A record array (or recarray) in NumPy is a specialized array that stores structured, tabular data with named columns and mixed data types. Unlike regular NumPy arrays that hold a single data type, record arrays let you store integers, floats, and strings in different columns - similar to a spreadsheet or database table - while accessing fields conveniently as attributes.
In this guide, you'll learn three methods to read CSV data into a NumPy record array, understand the differences between each approach, and know when to use which one.
What Is a Record Array?
A record array extends NumPy's structured arrays by providing attribute-style access to named fields:
import numpy as np
data = np.rec.array(
[(1, 'Alice', 50000.0), (2, 'Bob', 60000.0)],
dtype=[('ID', 'i4'), ('Name', 'U10'), ('Salary', 'f8')]
)
print(data.Name) # ['Alice' 'Bob']
print(data.Salary) # [50000. 60000.]
print(data[0]) # (1, 'Alice', 50000.0)Key features:
- Named fields: Access columns by name (e.g.,
data.Name) instead of index. - Mixed data types: Different columns can hold integers, floats, strings, etc.
- NumPy performance: Operates at NumPy speed, faster than Python lists of dictionaries.
Sample CSV File
All examples below use this CSV file (employees.csv):
ID,Name,Salary
1,Alice,50000
2,Bob,60000
3,Charlie,55000You can create it programmatically:
csv_content = """ID,Name,Salary
1,Alice,50000
2,Bob,60000
3,Charlie,55000
"""
with open('employees.csv', 'w') as f:
f.write(csv_content)Method 1: Using numpy.genfromtxt()
The numpy.genfromtxt() function is the most versatile option for reading CSV data into a structured array. It automatically infers data types and handles missing values:
import numpy as np
data = np.genfromtxt(
'employees.csv',
delimiter=',',
dtype=None,
names=True,
encoding=None
)
print("Type:", type(data))
print("Data:")
print(data)
print("\nField names:", data.dtype.names)
print("Names:", data['Name'])
print("Salaries:", data['Salary'])Output:
Type: <class 'numpy.ndarray'>
Data:
[(1, 'Alice', 50000) (2, 'Bob', 60000) (3, 'Charlie', 55000)]
Field names: ('ID', 'Name', 'Salary')
Names: ['Alice' 'Bob' 'Charlie']
Salaries: [50000 60000 55000]Parameter explanation:
| Parameter | Value | Purpose |
|---|---|---|
delimiter |
',' |
Specifies the column separator |
dtype |
None |
Lets NumPy automatically infer data types |
names |
True |
Uses the first row as column names |
encoding |
None |
Uses the system default encoding |
Method 2: Using numpy.recfromcsv() (ONLY in NumPy <v2.0)
The numpy.recfromcsv() function is a convenience wrapper specifically designed for reading CSV files into record arrays. It sets sensible defaults automatically:
import numpy as np
data = np.recfromcsv('employees.csv', encoding=None)
print("Type:", type(data))
print("Data:")
print(data)
print("\nAccess by attribute:")
print("Names:", data.name)
print("Salaries:", data.salary)Output:
Type: <class 'numpy.recarray'>
Data:
[(1, 'Alice', 50000) (2, 'Bob', 60000) (3, 'Charlie', 55000)]
Access by attribute:
Names: ['Alice' 'Bob' 'Charlie']
Salaries: [50000 60000 55000]Notice that recfromcsv() returns a numpy.recarray directly (not just a structured ndarray), so you can access fields as attributes without any additional conversion.
Method 3: Using Pandas and Converting to a Record Array
If you're already using Pandas in your project, you can read the CSV into a DataFrame first and then convert it to a NumPy record array using to_records():
import pandas as pd
df = pd.read_csv('employees.csv')
print("DataFrame:")
print(df)
data = df.to_records(index=False)
print("\nRecord array:")
print(data)
print("\nNames:", data.Name)
print("Salaries:", data.Salary)Output:
DataFrame:
ID Name Salary
0 1 Alice 50000
1 2 Bob 60000
2 3 Charlie 55000
Record array:
[(1, 'Alice', 50000) (2, 'Bob', 60000) (3, 'Charlie', 55000)]
Names: ['Alice' 'Bob' 'Charlie']
Salaries: [50000 60000 55000]This approach is especially useful when you want to preprocess data with Pandas (filtering, cleaning, merging) before converting to a NumPy record array for numerical computation.
Comparison of Methods
| Feature | genfromtxt() |
recfromcsv() |
Pandas + to_records() |
|---|---|---|---|
| Returns type | Structured ndarray |
recarray |
recarray |
| Attribute access | Via field names only (data['Name']) |
✅ (data.name) |
✅ (data.Name) |
| Auto-detects types | ✅ (with dtype=None) |
✅ | ✅ |
| Preserves column case | ✅ | ❌ (lowercased) | ✅ |
| Handles missing values | ✅ (filling_values) |
✅ | ✅ (more options) |
| Requires Pandas | ❌ | ❌ | ✅ |
| Data preprocessing | Limited | Limited | ✅ (full Pandas power) |
| Best for | Fine-grained control | Quick CSV to recarray | Preprocessing + conversion |
Converting a Structured Array to a Record Array
If you use genfromtxt() and want attribute-style access, convert the result to a record array with view():
import numpy as np
structured = np.genfromtxt(
'employees.csv', delimiter=',', dtype=None, names=True, encoding=None
)
record = structured.view(np.recarray)
print("Access as attribute:", record.Name)
print("Access as field: ", record['Name'])Output:
Access as attribute: ['Alice' 'Bob' 'Charlie']
Access as field: ['Alice' 'Bob' 'Charlie']Common Mistake: Encoding Issues
When reading CSV files, you may encounter UnicodeDecodeError if the file uses a non-UTF-8 encoding:
import numpy as np
try:
data = np.genfromtxt('data_latin1.csv', delimiter=',', dtype=None, names=True)
except UnicodeDecodeError as e:
print(f"Error: {e}")Fix: Specify the correct encoding:
data = np.genfromtxt(
'data_latin1.csv', delimiter=',', dtype=None, names=True, encoding='latin-1'
)With Pandas, use pd.read_csv('file.csv', encoding='latin-1').
Summary
To read CSV data into a NumPy record array:
- Use
numpy.genfromtxt()for the most control over parsing - specify delimiters, handle missing values, and choose data types. Convert to arecarraywith.view(np.recarray)if you need attribute access. - Use
numpy.recfromcsv()for the quickest, simplest approach - it returns arecarraydirectly with sensible defaults. Be aware that it lowercases column names. - Use Pandas with
to_records()when you need to preprocess data (filter, clean, merge) before converting - it offers the most flexibility but requires an additional dependency.
All three methods produce functionally equivalent record arrays. Choose based on whether you need preprocessing capabilities, attribute-style access, or minimal dependencies.