Python Pandas NumPy Conversion: DataFrame to Array
python pandas numpy conversion: Learn how to convert between pandas DataFrames/Series and NumPy arrays, handle data types, and avoid common pitfalls in Python.
When working with data in Python, you often need to move between pandas and NumPy structures. A pandas DataFrame or Series provides labeled, tabular data with rich indexing, while a NumPy array offers a compact, homogeneous container optimized for numerical operations. The python pandas numpy conversion is a routine step in data pipelines, especially before feeding data into machine learning models or performing vectorized computations. This article covers the primary conversion methods, their behavior, and the tradeoffs you should consider.
Converting a DataFrame to a NumPy Array
The most direct way to convert a DataFrame to a NumPy array is the .to_numpy() method, which was introduced in pandas 0.24 and is the recommended approach. It returns a NumPy array that shares the data with the DataFrame when possible, avoiding an unnecessary copy.
import pandas as pd df = pd.DataFrame({ 'A': [1, 2, 3], 'B': [4.5, 5.5, 6.5] }) arr = df.to_numpy() print(arr) # [[1. 4.5] # [2. 5.5] # [3. 6.5]]
In this example, the resulting array has dtype float64 because pandas promotes the integer column to float to accommodate the mixed types. If all columns have the same dtype, the array preserves that dtype. For instance, a DataFrame with only integers yields an int64 array.
Before .to_numpy(), the common approach was the .values attribute. While .values still works, it has subtle differences. For a DataFrame with mixed dtypes, .values may return an object array, whereas .to_numpy() attempts to find a common dtype. The pandas documentation recommends .to_numpy() for new code because it is more explicit and avoids the ambiguity of .values.
# Older approach arr_old = df.values
If you need to preserve the index or column labels, you must handle them separately because a NumPy array has no such metadata. The conversion discards labels, so only the underlying data is retained.
Converting a Series to a NumPy Array
A pandas Series converts to a NumPy array in the same way. The .to_numpy() method works on Series as well, returning a one-dimensional array.
s = pd.Series([10, 20, 30], name='values') arr = s.to_numpy() print(arr) # [10 20 30] print(arr.dtype) # int64
For a Series with a datetime64 dtype, .to_numpy() returns an array of datetime64[ns] values. If you need a plain Python datetime object, you can convert using astype(object) or pd.to_datetime() depending on your goal.
Converting a NumPy Array to a DataFrame
Creating a pandas DataFrame from a NumPy array is straightforward using the pd.DataFrame() constructor. You can pass the array directly, and optionally specify column names and an index.
import numpy as np import pandas as pd arr = np.array([[1, 2], [3, 4]]) df = pd.DataFrame(arr, columns=['col1', 'col2']) print(df) # col1 col2 # 0 1 2 # 1 3 4
If you omit columns, pandas assigns integer labels starting from 0. For a one-dimensional array, you can create a Series instead:
arr_1d = np.array([1, 2, 3]) s = pd.Series(arr_1d)
When the array has a structured dtype (i.e., a record array), pandas can map the field names to columns automatically. This is useful when reading data from sources that produce structured arrays.
Handling Data Types During Conversion
Data type behavior is the most common source of confusion in pandas–NumPy conversion. pandas and NumPy have different type promotion rules. When a DataFrame contains columns of different dtypes, .to_numpy() must find a common dtype that can represent all values. This often results in upcasting to float64 or object.
Consider a DataFrame with an integer column and a string column:
df = pd.DataFrame({'num': [1, 2], 'txt': ['a', 'b']}) arr = df.to_numpy() print(arr.dtype) # object
The resulting array is object because there is no numeric type that can hold strings. This is often undesirable for numerical operations. If you need a numeric array, you must either drop the non-numeric columns or convert them separately.
For datetime columns, the conversion preserves the datetime64 dtype. However, if you mix timezone-aware and timezone-naive datetimes, pandas will raise an error or produce an object array depending on the version. Always check the dtype of the resulting array to ensure it matches your expectations.
Performance and Memory Considerations
The to_numpy() method may return a view or a copy depending on the data layout. For a DataFrame with a single dtype and a contiguous block of memory, the array shares memory with the DataFrame. Modifying the array will affect the DataFrame, and vice versa. For mixed dtypes, pandas must create a new array, which is a copy.
# View case: single dtype df = pd.DataFrame({'a': [1, 2, 3]}) arr = df.to_numpy() arr[0] = 99 print(df) # a # 0 99 # 1 2 # 2 3
This behavior is important when you want to avoid unintended side effects. If you need a copy, use .to_numpy(copy=True) explicitly. The copy parameter was added in pandas 1.0 and defaults to False, meaning it may return a view when possible.
For large datasets, the memory footprint matters. Converting a DataFrame to a NumPy array that requires upcasting can double memory usage temporarily. If you are working with a DataFrame that already has a homogeneous dtype, the conversion is cheap because no copy is made.
Common Pitfalls and How to Avoid Them
Missing Values and NaN
NumPy arrays do not have a native representation for missing values in integer columns. When a DataFrame contains NaN in an integer column, pandas automatically converts that column to float64 to represent the missing value as np.nan. This can surprise developers who expect integer dtypes.
df = pd.DataFrame({'id': [1, None, 3]}) arr = df.to_numpy() print(arr.dtype) # float64
If you need to preserve integer semantics with missing values, consider using pd.NA and the nullable integer dtype Int64, but note that .to_numpy() will still convert to object or float depending on the context.
Index and Column Labels
As mentioned earlier, conversion discards labels. If you need to keep the index, you must store it separately. This is often necessary when converting back to a DataFrame after a NumPy operation.
Structured Arrays and Record Arrays
When converting a NumPy structured array to a DataFrame, pandas maps the field names to columns. However, if the structured array has nested fields or multi-dimensional fields, the conversion may produce columns with array values. In such cases, you may need to flatten the structure manually.
Converting with Mixed Types: When to Use Object Arrays
Sometimes you intentionally want an object array, for example when you need to store heterogeneous data in a single array for a specific algorithm. The to_numpy(dtype=object) parameter forces an object array, but this defeats the performance benefits of homogeneous numeric arrays. Use it only when necessary.
arr_obj = df.to_numpy(dtype=object)
For most numerical work, you should aim for a homogeneous numeric array. If your DataFrame contains mixed numeric types, you can select the numeric columns first using df.select_dtypes(include='number') and then convert.
Working with Categorical Data
Pandas categorical columns store data as integer codes plus a mapping of categories. When you convert a categorical column to a NumPy array, .to_numpy() returns the actual values (the category labels), not the integer codes. If you need the codes, use the .cat.codes attribute first.
s = pd.Series(['a', 'b', 'a'], dtype='category') print(s.to_numpy()) # ['a' 'b' 'a'] print(s.cat.codes.to_numpy()) # [0 1 0]
This distinction matters when you are preparing data for machine learning models that expect numeric inputs.
Choosing the Right Conversion Method for Your Pipeline
The decision between .to_numpy() and .values is straightforward: use .to_numpy() for new code. It is more predictable and supports the copy parameter. For converting back to pandas, the constructor is the only way, but you must be aware of dtype promotion and index handling.
In performance-critical paths, avoid unnecessary copies by checking whether the array shares memory with the DataFrame. You can use np.shares_memory() to verify. If you need to modify the array without affecting the original DataFrame, pass copy=True.
For large-scale data processing, consider whether you actually need to convert at all. Many pandas operations can be vectorized without leaving the DataFrame abstraction. Converting to NumPy only when required—such as for a specific library function that expects a NumPy array—reduces overhead and keeps the data structure consistent.