Converti frame di dati Panda in array NumPy


467

Sono interessato a sapere come convertire un frame di dati Panda in un array 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')

label   A    B    C
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

Vorrei convertirlo in un array NumPy, in questo modo:

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]])

Come posso fare questo?


Come bonus, è possibile preservare i tipi, come questo?

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 simili?


5
Perchè ti serve ? I frame di dati non sono comunque basati su array intorpiditi? Dovresti essere in grado di utilizzare un frame di dati in cui hai bisogno di una matrice numpy. Ecco perché è possibile utilizzare i frame di dati con scikit-learn in cui le funzioni richiedono array intorpiditi.
chrisfs,

Qui ci sono un paio di link eventualmente rilevanti circa dtypes & recarrays (array di dischi o array aka strutturati): (1) stackoverflow.com/questions/9949427/... (2) stackoverflow.com/questions/52579601/...
JohnE

NOTA: Dover convertire Pandas DataFrame in un array (o elenco) come questo può essere indicativo di altri problemi. Consiglio vivamente di assicurare che un DataFrame sia la struttura dati appropriata per il tuo caso d'uso specifico e che Pandas non includa alcun modo di eseguire le operazioni che ti interessano.
AMC

Risposte:


391

Per convertire un frame di dati panda (df) in un ndarray numpy, utilizzare questo codice:

df.values

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]])

239

Deprecare l'utilizzo di valuese as_matrix()!

pandas v0.24.0 ha introdotto due nuovi metodi per ottenere matrici NumPy dagli oggetti pandas:

  1. to_numpy(), che è definito su Index, Series,e DataFrameoggetti e
  2. array, che è definito su Indexe Seriessolo oggetti.

Se visiti i documenti v0.24 per .values, vedrai un grande avviso rosso che dice:

Avvertenza: si consiglia DataFrame.to_numpy()invece di utilizzare .

Vedere questa sezione delle note sulla versione v0.24.0 e questa risposta per ulteriori informazioni.


Verso una migliore coerenza: to_numpy()

Nello spirito di una migliore coerenza in tutta l'API, to_numpyè stato introdotto un nuovo metodo per estrarre l'array NumPy sottostante da DataFrames.

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

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

Come accennato in precedenza, questo metodo è anche definito su Indexe Seriesoggetti (vedi qui ).

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

df['A'].to_numpy()
#  array([1, 2, 3])

Per impostazione predefinita, viene restituita una vista, quindi eventuali modifiche apportate influiranno sull'originale.

v = df.to_numpy()
v[0, 0] = -1

df
   A  B
a -1  4
b  2  5
c  3  6

Se invece hai bisogno di una copia, usa to_numpy(copy=True).

panda> = 1.0 aggiornamento per ExtensionTypes

Se stai usando Panda 1.x, è probabile che avrai a che fare con tipi di estensione molto di più. Dovrai stare un po 'più attento che questi tipi di estensione vengano convertiti correttamente.

a = pd.array([1, 2, None], dtype="Int64")                                  
a                                                                          

<IntegerArray>
[1, 2, <NA>]
Length: 3, dtype: Int64 

# Wrong
a.to_numpy()                                                               
# array([1, 2, <NA>], dtype=object)  # yuck, objects

# Right
a.to_numpy(dtype='float', na_value=np.nan)                                 
# array([ 1.,  2., nan])

Questo è richiamato nei documenti .

Se hai bisogno del dtypes...

Come mostrato in un'altra risposta, DataFrame.to_recordsè un buon modo per farlo.

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

to_numpyPurtroppo non è possibile farlo . Tuttavia, in alternativa, è possibile utilizzare 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', '<U1'), ('A', '<i8'), ('B', '<i8')])

Per quanto riguarda le prestazioni, è quasi lo stesso (in realtà, l'utilizzo rec.fromrecordsè un po 'più veloce).

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)

Razionale per l'aggiunta di un nuovo metodo

to_numpy()(oltre a array) è stato aggiunto a seguito di discussioni nell'ambito di due numeri GitHub GH19954 e GH23623 .

In particolare, i documenti menzionano la logica:

[...] con .valuesesso non era chiaro se il valore restituito sarebbe l'array effettivo, una sua trasformazione o uno degli array personalizzati di panda (come Categorical). Ad esempio, con PeriodIndex, .values genera ndarrayogni volta un nuovo oggetto periodico. [...]

to_numpymirare a migliorare la coerenza dell'API, che rappresenta un passo importante nella giusta direzione. .valuesnon sarà deprecato nella versione corrente, ma mi aspetto che ciò possa accadere ad un certo punto in futuro, quindi esorto gli utenti a migrare verso l'API più recente, appena possibile.


Critica di altre soluzioni

DataFrame.values ha un comportamento incoerente, come già notato.

DataFrame.get_values()è semplicemente un involucro in giro DataFrame.values, quindi si applica tutto quanto detto sopra.

DataFrame.as_matrix()è obsoleto ora, NON utilizzare!


Non capisco come sia possibile leggere pagina dopo pagina di persone che urlano nella parte superiore dei polmoni per passare da as_matrixun'altra soluzione, in questo caso, to_numpysenza spiegare come recuperare la colonna selezionando la funzionalità di as_matrix! Sono sicuro che ci sono altri modi per selezionare le colonne, ma as_matrixera almeno uno di questi!
Jérémie,

@ Jérémie oltre all'ovvio df[[col1, col2']].to_numpy()? Non sei sicuro del motivo per cui pensi che voler pubblicizzare un'alternativa aggiornata a una funzione deprecata meriti un voto negativo sulla risposta.
cs95

che cosa succede se alcune delle colonne sono di tipo elenco. Come posso creare un array irregolare piatto da questo?
Moniba,

@Moniba potresti voler esplodere le voci dell'elenco in colonne / righe separate secondo il tuo requisito prima.
cs95,

A meno che non mi sbagli, ottenere più di una colonna nella stessa chiamata ottiene tutti i dati uniti in un array di grandi dimensioni. Mi sto perdendo qualcosa?
Andrea Moro,

128

Nota : il .as_matrix()metodo utilizzato in questa risposta è obsoleto. Panda 0.23.4 avverte:

Il metodo .as_matrixverrà rimosso in una versione futura. Utilizzare invece .values.


Panda ha qualcosa di costruito in ...

numpy_matrix = df.as_matrix()

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]])

30
Questo non fornisce un array strutturato, tutte le colonne sono di tipo object.
sebix,

14
"Obsoleto dalla versione 0.23.0: utilizzare invece DataFrame.values." / "Questo metodo viene fornito per la compatibilità con le versioni precedenti. In genere, si consiglia di utilizzare '.values'." - github.com/pandas-dev/pandas/blob/…
David J.

4
Questo è ora deprecato. Da v0.24 in poi, utilizzare to_numpyinvece (non .valuesuno dei due). Più qui .
cs95,

1
"FutureWarning: il metodo .as_matrix verrà rimosso in una versione futura. Utilizzare invece .values."
Farhad Maleki,

66

Vorrei solo concatenare le funzioni DataFrame.reset_index () e DataFrame.values per ottenere la rappresentazione Numpy del frame di dati, incluso l'indice:

In [8]: df
Out[8]: 
          A         B         C
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]])

Per ottenere i dtypes avremmo bisogno di trasformare questo ndarray in un array strutturato usando view :

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', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

3
l'unica cosa che manca in questa risposta è come costruire il tipo dal frame di dati in modo da poter scrivere una funzione generica
Joseph Garvin

32

Puoi usare il to_recordsmetodo, ma devi giocare un po 'con i dtypes se non sono quello che vuoi fin dall'inizio. Nel mio caso, dopo aver copiato il tuo DF da una stringa, il tipo di indice è stringa (rappresentato da un objecttipo in panda):

In [102]: df
Out[102]: 
label    A    B    C
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', '<f8'), ('B', '<f8'), ('C', '<f8')])
In [106]: df.to_records().dtype
Out[106]: dtype([('index', '|O8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

La conversione del dtype di ricomposizione non funziona per me, ma uno può già farlo in Panda:

In [109]: df.index = df.index.astype('i8')
In [111]: df.to_records().view([('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])
Out[111]:
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=[('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

Nota che Pandas non imposta correttamente il nome dell'indice (su ID) nell'array di record esportato (un bug?), Quindi approfittiamo della conversione del tipo per correggere anche quello.

Al momento Pandas ha solo numeri interi da 8 byte i8e float f8(vedi questo numero ).


2
Per ottenere l'array strutturato ricercato (che ha prestazioni migliori rispetto a un ricarray) è sufficiente passare il ricarray al np.arraycostruttore.
meteore,

Abbiamo appena inserito una correzione per l'impostazione del nome dell'indice mostrato sopra.
Chang She,

26

Sembra df.to_records()che funzionerà per te. La funzione esatta che stai cercando è stata richiesta e to_recordsindicata come alternativa.

L'ho provato localmente usando il tuo esempio e quella chiamata produce qualcosa di molto simile all'output che stavi cercando:

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', '<i8'), (u'A', '<f8'), (u'B', '<f8'), (u'C', '<f8')])

Si noti che questo è un recarrayanziché un array. È possibile spostare il risultato in un normale array numpy chiamando il suo costruttore come np.array(df.to_records()).


3
Aspetta, cosa aggiunge questa risposta rispetto all'altra risposta di @meteore menzionata to_records()più di 5 anni prima?
Giovanni,

13

Prova questo:

a = numpy.asarray(df)

Ciao! Aggiungi una spiegazione alla tua risposta. In questo momento, è attualmente contrassegnato come di bassa qualità dalla revisione a causa della lunghezza e del contenuto ed è a rischio di essere eliminato dal sistema. Grazie!
d_kennetz,

1
fondamentalmente convertire l'input in un array (come suggerisce il nome). Quindi, insieme al contesto della domanda, questa risposta è valida. check docs.scipy.org/doc/numpy/reference/generated/…
Lautaro Parada Opazo

Grazie, penso che sia un po 'esplicativo.
Dadu Khan,

8

Ecco il mio approccio alla creazione di un array di strutture da un DataFrame Panda.

Crea il frame di dati

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)

      A    B    C
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

Definire la funzione per creare un array di struttura numpy (non un array di record) da un DataFrame di Panda.

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

Utilizzare reset_indexper creare un nuovo frame di dati che includa l'indice come parte dei suoi dati. Converti quel frame di dati in un array di strutture.

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', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

EDIT: Aggiornato df_to_sarray per evitare errori nella chiamata a .encode () con python 3. Grazie a Joseph Garvin e halcyon per il loro commento e la loro soluzione.


non funziona per me, errore: TypeError: tipo di dati non compreso
Joseph Garvin

Grazie per il tuo commento e per halcyon per la correzione. Ho aggiornato la mia risposta, quindi spero che funzioni per te adesso.
Phil


5

Un modo più semplice per esempio 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

USO:

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

OTTENERE:

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', '<i8'), ('gbm', '<f8'), ('nnet', '<f4'),
       ('reg', '<f8')]))

4

Ho appena avuto un problema simile durante l'esportazione da dataframe alla tabella arcgis e sono incappato in una soluzione da usgs ( https://my.usgs.gov/confluence/display/cdi/pandas.DataFrame+to+ArcGIS+Table ). In breve, il tuo problema ha una soluzione simile:

df

      A    B    C
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', '<f8'), ('B', '<f8'), ('C', '<f8')]))

4

Ho esaminato le risposte sopra. Il metodo " as_matrix () " funziona ma ora è obsoleto. Per me, ciò che ha funzionato è stato " .to_numpy () ".

Ciò restituisce un array multidimensionale. Preferirò utilizzare questo metodo se stai leggendo i dati dal foglio Excel e devi accedere ai dati da qualsiasi indice. Spero che sia di aiuto :)


Cosa intendi con e devi accedere ai dati da qualsiasi indice ? A seconda della natura dei tuoi dati, un Pandas DataFrame potrebbe non essere nemmeno la scelta giusta in primo luogo.
AMC

2

Oltre alla risposta di meteore, ho trovato il codice

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

non funziona per me. Quindi ho inserito il mio codice qui per la comodità degli altri bloccato con questo 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))

1

Un modo semplice per convertire i frame di dati in array numpy:

import pandas as pd
df = pd.DataFrame({"A": [1, 2], "B": [3, 4]})
df_to_array = df.to_numpy()
array([[1, 3],
   [2, 4]])

L'uso di to_numpy è incoraggiato a preservare la coerenza.

Riferimento: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_numpy.html


qual è la differenza tra la soluzione fornita da Arsam e la tua ...
qaiser

Ho appena provato a renderlo più completo e utilizzabile con un esempio di codice, che è ciò che preferisco personalmente.
user1460675

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.