Convertir pandas dataframe a NumPy array

Estoy interesado en saber cómo convertir un dataframe pandas en una matriz NumPy.

dataframe:

import numpy as np import pandas as pd index = [1, 2, 3, 4, 5, 6, 7] a = [np.nan, np.nan, np.nan, 0.1, 0.1, 0.1, 0.1] b = [0.2, np.nan, 0.2, 0.2, 0.2, np.nan, np.nan] c = [np.nan, 0.5, 0.5, np.nan, 0.5, 0.5, np.nan] df = pd.DataFrame({'A': a, 'B': b, 'C': c}, index=index) df = df.rename_axis('ID') 

da

 label ABC ID 1 NaN 0.2 NaN 2 NaN NaN 0.5 3 NaN 0.2 0.5 4 0.1 0.2 NaN 5 0.1 0.2 0.5 6 0.1 NaN 0.5 7 0.1 NaN NaN 

Me gustaría convertir esto en una matriz NumPy, así:

 array([[ nan, 0.2, nan], [ nan, nan, 0.5], [ nan, 0.2, 0.5], [ 0.1, 0.2, nan], [ 0.1, 0.2, 0.5], [ 0.1, nan, 0.5], [ 0.1, nan, nan]]) 

¿Cómo puedo hacer esto?


Como beneficio adicional, ¿es posible preservar los tipos de datos, de esta manera?

 array([[ 1, nan, 0.2, nan], [ 2, nan, nan, 0.5], [ 3, nan, 0.2, 0.5], [ 4, 0.1, 0.2, nan], [ 5, 0.1, 0.2, 0.5], [ 6, 0.1, nan, 0.5], [ 7, 0.1, nan, nan]], dtype=[('ID', '<i4'), ('A', '<f8'), ('B', '<f8'), ('B', '<f8')]) 

o similar.

¿Alguna sugerencia sobre cómo lograr esto?

Para convertir un dataframe de pandas (df) en un ndarray numpy, use este código:

df = df.values

df ahora se convierte en el ndarray numpy:

 array([[nan, 0.2, nan], [nan, nan, 0.5], [nan, 0.2, 0.5], [0.1, 0.2, nan], [0.1, 0.2, 0.5], [0.1, nan, 0.5], [0.1, nan, nan]]) 

Nota : el método .as_matrix() utilizado en esta respuesta está en desuso. Pandas 0.23.4 advierte:

El método .as_matrix se eliminará en una versión futura. Utilice .values ​​en su lugar.


Pandas tiene algo construido en …

 numpy_matrix = df.as_matrix() 

da

 array([[nan, 0.2, nan], [nan, nan, 0.5], [nan, 0.2, 0.5], [0.1, 0.2, nan], [0.1, 0.2, 0.5], [0.1, nan, 0.5], [0.1, nan, nan]]) 

Simplemente encadenaría las funciones DataFrame.reset_index () y DataFrame.values para obtener la representación de Numpy del dataframe, incluido el índice:

 In [8]: df Out[8]: ABC 0 -0.982726 0.150726 0.691625 1 0.617297 -0.471879 0.505547 2 0.417123 -1.356803 -1.013499 3 -0.166363 -0.957758 1.178659 4 -0.164103 0.074516 -0.674325 5 -0.340169 -0.293698 1.231791 6 -1.062825 0.556273 1.508058 7 0.959610 0.247539 0.091333 [8 rows x 3 columns] In [9]: df.reset_index().values Out[9]: array([[ 0. , -0.98272574, 0.150726 , 0.69162512], [ 1. , 0.61729734, -0.47187926, 0.50554728], [ 2. , 0.4171228 , -1.35680324, -1.01349922], [ 3. , -0.16636303, -0.95775849, 1.17865945], [ 4. , -0.16410334, 0.0745164 , -0.67432474], [ 5. , -0.34016865, -0.29369841, 1.23179064], [ 6. , -1.06282542, 0.55627285, 1.50805754], [ 7. , 0.95961001, 0.24753911, 0.09133339]]) 

Para obtener los dtypes necesitaríamos transformar esta ndarray en una matriz estructurada usando la vista :

 In [10]: df.reset_index().values.ravel().view(dtype=[('index', int), ('A', float), ('B', float), ('C', float)]) Out[10]: array([( 0, -0.98272574, 0.150726 , 0.69162512), ( 1, 0.61729734, -0.47187926, 0.50554728), ( 2, 0.4171228 , -1.35680324, -1.01349922), ( 3, -0.16636303, -0.95775849, 1.17865945), ( 4, -0.16410334, 0.0745164 , -0.67432474), ( 5, -0.34016865, -0.29369841, 1.23179064), ( 6, -1.06282542, 0.55627285, 1.50805754), ( 7, 0.95961001, 0.24753911, 0.09133339), dtype=[('index', ' 

Puedes usar el método to_records , pero to_records jugar un poco con los dtypes si no son lo que quieres desde el principio. En mi caso, habiendo copiado su DF de una cadena, el tipo de índice es una cadena (representada por un tipo de object en pandas):

 In [102]: df Out[102]: label ABC ID 1 NaN 0.2 NaN 2 NaN NaN 0.5 3 NaN 0.2 0.5 4 0.1 0.2 NaN 5 0.1 0.2 0.5 6 0.1 NaN 0.5 7 0.1 NaN NaN In [103]: df.index.dtype Out[103]: dtype('object') In [104]: df.to_records() Out[104]: rec.array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5), (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5), (7, 0.1, nan, nan)], dtype=[('index', '|O8'), ('A', ' 

La conversión del tipo de recarray no funciona para mí, pero ya se puede hacer esto en Pandas:

 In [109]: df.index = df.index.astype('i8') In [111]: df.to_records().view([('ID', ' 

Tenga en cuenta que Pandas no establece correctamente el nombre del índice (a ID ) en la matriz de registros exportados (¿un error?), Por lo que nos beneficiamos de la conversión de tipos para corregir eso también.

En este momento, Pandas solo tiene enteros de 8 bytes, i8 , y flota, f8 (ver este problema ).

Parece que df.to_records() funcionará para usted. Se solicitó la característica exacta que está buscando y to_records señaló como una alternativa.

Intenté esto localmente usando su ejemplo, y esa llamada produce algo muy similar a la salida que estaba buscando:

 rec.array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5), (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5), (7, 0.1, nan, nan)], dtype=[(u'ID', ' 

Tenga en cuenta que esto es un recarray lugar de una array . Puede mover el resultado a una matriz numpy normal llamando a su constructor como np.array(df.to_records()) .

Deprate tu uso de los values y as_matrix() !

Desde v0.24.0, se nos presentan dos nuevos métodos preferidos para obtener matrices NumPy a partir de objetos pandas:

  1. to_numpy() , que se define en los objetos Index , Series, y DataFrame , y
  2. array , que se define solo en los objetos Index y Series .

Si visita los documentos v0.24 para .values , verá una gran advertencia roja que dice:

Advertencia: Recomendamos usar DataFrame.to_numpy() lugar.

Consulte esta sección de las notas de la versión v0.24.0 y esta respuesta para obtener más información.


Hacia una mejor consistencia: to_numpy()

En el espíritu de una mejor coherencia en toda la API, se ha introducido un nuevo método to_numpy para extraer la matriz NumPy subyacente de DataFrames.

 # Setup. df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}, index=['a', 'b', 'c']) df AB a 1 4 b 2 5 c 3 6 

 df.to_numpy() array([[1, 4], [2, 5], [3, 6]]) 

Como se mencionó anteriormente, este método también se define en los objetos de Index y Series (consulte aquí ).

 df.index.to_numpy() # array(['a', 'b', 'c'], dtype=object) df['A'].to_numpy() # array([1, 2, 3]) 

De forma predeterminada, se devuelve una vista, por lo que cualquier modificación que se realice afectará al original.

 v = df.to_numpy() v[0, 0] = -1 df AB a -1 4 b 2 5 c 3 6 

Si necesita una copia en su lugar, use to_numpy(copy=True );

 v = df.to_numpy(copy=True) v[0, 0] = -123 df AB a 1 4 b 2 5 c 3 6 

Si necesitas preservar los dtypes
Como se muestra en otra respuesta, DataFrame.to_records es una buena manera de hacer esto.

 df.to_records() # rec.array([('a', -1, 4), ('b', 2, 5), ('c', 3, 6)], # dtype=[('index', 'O'), ('A', ' 

Esto no se puede hacer con to_numpy , desafortunadamente. Sin embargo, como alternativa, puede usar np.rec.fromrecords :

 v = df.reset_index() np.rec.fromrecords(v, names=v.columns.tolist()) # rec.array([('a', -1, 4), ('b', 2, 5), ('c', 3, 6)], # dtype=[('index', ' 

En cuanto al rendimiento, es casi el mismo (en realidad, usar rec.fromrecords es un poco más rápido).

 df2 = pd.concat([df] * 10000) %timeit df2.to_records() %%timeit v = df2.reset_index() np.rec.fromrecords(v, names=v.columns.tolist()) 11.1 ms ± 557 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 9.67 ms ± 126 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 

Razón para agregar un nuevo método

to_numpy() (además de la array ) se agregó como resultado de las discusiones bajo dos números G19204 y GH23623 de GitHub .

Específicamente, los documentos mencionan el razonamiento:

[...] con .values no estaba claro si el valor devuelto sería la matriz real, alguna transformación de la misma o una de las matrices personalizadas de pandas (como Categorical ). Por ejemplo, con PeriodIndex , .values genera una nueva ndarray de objetos de período cada vez. [...]

to_numpy objective de to_numpy es mejorar la consistencia de la API, que es un paso importante en la dirección correcta. .values no será obsoleto en la versión actual, pero espero que esto ocurra en algún momento en el futuro, por lo que insto a los usuarios a migrar hacia la API más nueva, tan pronto como sea posible.


Crítica de otras soluciones

DataFrame.values tiene un comportamiento inconsistente, como ya se mencionó.

DataFrame.get_values() es simplemente una envoltura alrededor de DataFrame.values , por lo que todo lo dicho anteriormente se aplica.

DataFrame.as_matrix() está en desuso ahora, ¡ NO lo use!

Aquí está mi enfoque para hacer una matriz de estructura de un dataframe de pandas.

Crear el dataframe

 import pandas as pd import numpy as np import six NaN = float('nan') ID = [1, 2, 3, 4, 5, 6, 7] A = [NaN, NaN, NaN, 0.1, 0.1, 0.1, 0.1] B = [0.2, NaN, 0.2, 0.2, 0.2, NaN, NaN] C = [NaN, 0.5, 0.5, NaN, 0.5, 0.5, NaN] columns = {'A':A, 'B':B, 'C':C} df = pd.DataFrame(columns, index=ID) df.index.name = 'ID' print(df) ABC ID 1 NaN 0.2 NaN 2 NaN NaN 0.5 3 NaN 0.2 0.5 4 0.1 0.2 NaN 5 0.1 0.2 0.5 6 0.1 NaN 0.5 7 0.1 NaN NaN 

Defina la función para crear una matriz de estructura numpy (no una matriz de registro) a partir de un dataframe de pandas.

 def df_to_sarray(df): """ Convert a pandas DataFrame object to a numpy structured array. This is functionally equivalent to but more efficient than np.array(df.to_array()) :param df: the data frame to convert :return: a numpy structured array representation of df """ v = df.values cols = df.columns if six.PY2: # python 2 needs .encode() but 3 does not types = [(cols[i].encode(), df[k].dtype.type) for (i, k) in enumerate(cols)] else: types = [(cols[i], df[k].dtype.type) for (i, k) in enumerate(cols)] dtype = np.dtype(types) z = np.zeros(v.shape[0], dtype) for (i, k) in enumerate(z.dtype.names): z[k] = v[:, i] return z 

Use reset_index para crear un nuevo dataframe que incluya el índice como parte de sus datos. Convertir ese dataframe en una matriz de estructura.

 sa = df_to_sarray(df.reset_index()) sa array([(1L, nan, 0.2, nan), (2L, nan, nan, 0.5), (3L, nan, 0.2, 0.5), (4L, 0.1, 0.2, nan), (5L, 0.1, 0.2, 0.5), (6L, 0.1, nan, 0.5), (7L, 0.1, nan, nan)], dtype=[('ID', ' 

EDITAR: Se actualizó df_to_sarray para evitar errores al llamar a .encode () con python 3. Gracias a Joseph Garvin y halcyon por su comentario y solución.

Dos formas de convertir el dataframe a su representación Numpy-array.

  • mah_np_array = df.as_matrix(columns=None)

  • mah_np_array = df.values

Doc: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.as_matrix.html

Una forma más simple de ejemplo de dataframe:

 df gbm nnet reg 0 12.097439 12.047437 12.100953 1 12.109811 12.070209 12.095288 2 11.720734 11.622139 11.740523 3 11.824557 11.926414 11.926527 4 11.800868 11.727730 11.729737 5 12.490984 12.502440 12.530894 

UTILIZAR:

 np.array(df.to_records().view(type=np.matrix)) 

OBTENER:

 array([[(0, 12.097439 , 12.047437, 12.10095324), (1, 12.10981081, 12.070209, 12.09528824), (2, 11.72073428, 11.622139, 11.74052253), (3, 11.82455653, 11.926414, 11.92652727), (4, 11.80086775, 11.72773 , 11.72973699), (5, 12.49098389, 12.50244 , 12.53089367)]], dtype=(numpy.record, [('index', ' 

Solo tuve un problema similar al exportar desde la tabla de dataframe a arcgis y tropezé con una solución de usgs ( https://my.usgs.gov/confluence/display/cdi/pandas.DataFrame+to+ArcGIS+Table ). En resumen su problema tiene una solución similar:

 df ABC ID 1 NaN 0.2 NaN 2 NaN NaN 0.5 3 NaN 0.2 0.5 4 0.1 0.2 NaN 5 0.1 0.2 0.5 6 0.1 NaN 0.5 7 0.1 NaN NaN np_data = np.array(np.rec.fromrecords(df.values)) np_names = df.dtypes.index.tolist() np_data.dtype.names = tuple([name.encode('UTF8') for name in np_names]) np_data array([( nan, 0.2, nan), ( nan, nan, 0.5), ( nan, 0.2, 0.5), ( 0.1, 0.2, nan), ( 0.1, 0.2, 0.5), ( 0.1, nan, 0.5), ( 0.1, nan, nan)], dtype=(numpy.record, [('A', ' 

En respuesta a la respuesta de Meteore, encontré el código.

 df.index = df.index.astype('i8') 

no funciona para mi Así que puse mi código aquí para la conveniencia de otros atrapados con este problema.

 city_cluster_df = pd.read_csv(text_filepath, encoding='utf-8') # the field 'city_en' is a string, when converted to Numpy array, it will be an object city_cluster_arr = city_cluster_df[['city_en','lat','lon','cluster','cluster_filtered']].to_records() descr=city_cluster_arr.dtype.descr # change the field 'city_en' to string type (the index for 'city_en' here is 1 because before the field is the row index of dataframe) descr[1]=(descr[1][0], "S20") newArr=city_cluster_arr.astype(np.dtype(descr)) 

Escriba to_numpy lugar de to_numpy() para conservar los tipos.