Convertir la trame de données pandas en tableau NumPy

467

Je suis intéressé à savoir comment convertir une trame de données pandas en un tableau NumPy.

trame de données:

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

donne

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

Je voudrais convertir cela en un tableau NumPy, comme suit:

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

Comment puis-je faire ceci?


En bonus, est-il possible de conserver les dtypes, comme ça?

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

ou similaire?

mister.nobody.nz
la source
5
Pourquoi en avez-vous besoin? Les cadres de données ne sont-ils pas de toute façon basés sur des tableaux numpy? Vous devriez pouvoir utiliser une trame de données où vous avez besoin d'un tableau numpy. C'est pourquoi vous pouvez utiliser des dataframes avec scikit-learn où les fonctions demandent des tableaux numpy.
chrisfs
Voici quelques liens potentiellement pertinents sur les dtypes et recarrays (alias tableaux d'enregistrements ou tableaux structurés): (1) stackoverflow.com/questions/9949427/… (2) stackoverflow.com/questions/52579601/…
JohnE
REMARQUE: Devoir convertir Pandas DataFrame en un tableau (ou une liste) comme celui-ci peut indiquer d'autres problèmes. Je recommande fortement de vous assurer qu'un DataFrame est la structure de données appropriée pour votre cas d'utilisation particulier et que Pandas n'inclut aucun moyen d'effectuer les opérations qui vous intéressent.
AMC

Réponses:

391

Pour convertir une trame de données pandas (df) en un ndarray numpy, utilisez ce code:

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]])
User456898
la source
239

Dépréciez votre utilisation de valueset as_matrix()!

pandas v0.24.0 a introduit deux nouvelles méthodes pour obtenir des tableaux NumPy à partir d'objets pandas:

  1. to_numpy(), qui est défini sur Index, Series,et les DataFrameobjets, et
  2. array, qui est défini sur Indexet Seriesuniquement sur les objets.

Si vous visitez la documentation de v0.24 pour .values, vous verrez un gros avertissement rouge qui dit:

Avertissement: nous vous recommandons d'utiliser à la DataFrame.to_numpy()place.

Consultez cette section des notes de mise à jour v0.24.0 et cette réponse pour plus d'informations.


Vers une meilleure cohérence: to_numpy()

Dans un esprit de meilleure cohérence à travers l'API, une nouvelle méthode to_numpya été introduite pour extraire le tableau NumPy sous-jacent des 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]])

Comme mentionné ci-dessus, cette méthode est également définie sur les objets Indexet Series(voir ici ).

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

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

Par défaut, une vue est retournée, donc toutes les modifications apportées affecteront l'original.

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

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

Si vous avez plutôt besoin d'une copie, utilisez to_numpy(copy=True).

pandas> = 1.0 mise à jour pour ExtensionTypes

Si vous utilisez pandas 1.x, il y a de fortes chances que vous ayez beaucoup plus à faire avec les types d'extension. Vous devrez faire un peu plus attention à ce que ces types d'extensions soient correctement convertis.

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

Ceci est mentionné dans les documents .

Si vous avez besoin du dtypes...

Comme indiqué dans une autre réponse, DataFrame.to_recordsest un bon moyen de le faire.

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

Cela ne peut to_numpymalheureusement pas être fait avec . Cependant, comme alternative, vous pouvez utiliser 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')])

En termes de performances, c'est presque la même chose (en fait, l'utilisation rec.fromrecordsest un peu plus rapide).

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)

Justification de l'ajout d'une nouvelle méthode

to_numpy()(en plus de array) a été ajouté à la suite de discussions sur deux problèmes GitHub GH19954 et GH23623 .

Plus précisément, les documents mentionnent la justification:

[...] avec .valuesil n'était pas clair si la valeur retournée serait le tableau réel, une transformation de celui-ci, ou l'un des tableaux personnalisés pandas (comme Categorical). Par exemple, avec PeriodIndex, .values génère à ndarraychaque fois un nouvel objet période. [...]

to_numpyvisent à améliorer la cohérence de l'API, ce qui constitue une étape importante dans la bonne direction. .valuesne sera pas déconseillé dans la version actuelle, mais je m'attends à ce que cela se produise à un moment donné dans le futur, donc j'exhorte les utilisateurs à migrer vers la nouvelle API, dès que possible.


Critique des autres solutions

DataFrame.values a un comportement incohérent, comme déjà noté.

DataFrame.get_values()est simplement un wrapper DataFrame.values, donc tout ce qui précède s'applique.

DataFrame.as_matrix()est obsolète maintenant, ne l' utilisez PAS !

cs95
la source
Je ne comprends pas comment il est possible de lire page après page après page des personnes hurlant du haut de leurs poumons pour passer d' as_matrixune autre solution, dans ce cas, to_numpysans expliquer comment récupérer la fonctionnalité de sélection de colonne de as_matrix! Je suis sûr qu'il existe d'autres façons de sélectionner des colonnes, mais as_matrixc'était au moins l'une d'entre elles!
Jérémie
@ Jérémie en plus de l'évidence df[[col1, col2']].to_numpy()? Je ne sais pas pourquoi vous pensez vouloir annoncer une alternative mise à jour à une fonction obsolète mérite un downvote sur la réponse.
cs95
Et si certaines colonnes sont de type liste. Comment puis-je créer un tableau cahoteux plat à partir de cela?
Moniba
@Moniba, vous voudrez peut-être faire exploser les éléments de la liste dans des colonnes / lignes distinctes en fonction de vos besoins.
cs95
Sauf erreur, obtenir plus d'une colonne dans le même appel obtient toutes les données fusionnées dans un grand tableau. Suis-je en train de manquer quelque chose?
Andrea Moro
128

Remarque : La .as_matrix()méthode utilisée dans cette réponse est obsolète. Pandas 0.23.4 prévient:

La méthode .as_matrixsera supprimée dans une future version. Utilisez plutôt des valeurs.


Pandas a quelque chose de intégré ...

numpy_matrix = df.as_matrix()

donne

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]])
ZJS
la source
30
Cela ne donne pas un tableau structuré, toutes les colonnes sont de type dtype object.
sebix
14
"Déconseillé depuis la version 0.23.0: utilisez plutôt DataFrame.values." / "Cette méthode est fournie pour la compatibilité descendante. En général, il est recommandé d'utiliser '.values'." - github.com/pandas-dev/pandas/blob/…
David J.
4
Ceci est désormais obsolète. À partir de la version 0.24, veuillez utiliser à la to_numpyplace (pas non .valuesplus). Plus ici .
cs95
1
"FutureWarning: La méthode .as_matrix sera supprimée dans une future version. Utilisez plutôt des valeurs."
Farhad Maleki
66

Je voudrais simplement enchaîner les fonctions DataFrame.reset_index () et DataFrame.values pour obtenir la représentation Numpy de la trame de données, y compris l'index:

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

Pour obtenir les dtypes, nous aurions besoin de transformer ce ndarray en un tableau structuré en utilisant 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')])
prl900
la source
3
la seule chose qui manque dans cette réponse est de savoir comment construire le dtype à partir du bloc de données afin que vous puissiez écrire une fonction générique
Joseph Garvin
32

Vous pouvez utiliser la to_recordsméthode, mais devez jouer un peu avec les dtypes s'ils ne sont pas ce que vous voulez dès le départ. Dans mon cas, après avoir copié votre DF à partir d'une chaîne, le type d'index est chaîne (représenté par un objectdtype dans pandas):

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 conversion du dtype recarray ne fonctionne pas pour moi, mais on peut déjà le faire dans Pandas:

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

Notez que Pandas ne définit pas le nom de l'index correctement (à ID) dans le tableau d'enregistrement exporté (un bug?), Nous profitons donc de la conversion de type pour corriger également cela.

Pour le moment, Pandas n'a que des entiers de 8 octets i8, et flotte, f8(voir ce numéro ).

météore
la source
2
Pour obtenir le tableau structuré recherché (qui a de meilleures performances qu'un recarray), il vous suffit de passer le recarray au np.arrayconstructeur.
météore
Nous venons de mettre un correctif pour définir le nom de l'index indiqué ci-dessus.
Chang She
26

Il semble que df.to_records()cela fonctionnera pour vous. La fonctionnalité exacte que vous recherchez a été demandée et to_recordsindiquée comme alternative.

J'ai essayé cela localement en utilisant votre exemple, et cet appel donne quelque chose de très similaire à la sortie que vous cherchiez:

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

Notez qu'il s'agit recarrayplutôt d'un array. Vous pouvez déplacer le résultat dans un tableau numpy normal en appelant son constructeur as np.array(df.to_records()).

Jamie Doyle
la source
3
Attendez, qu'est-ce que cette réponse ajoute par rapport à l'autre réponse de @meteore qui a mentionné to_records()plus de 5 ans plus tôt?
JohnE
13

Essaye ça:

a = numpy.asarray(df)
Dadu Khan
la source
Salut! Veuillez ajouter quelques explications à votre réponse. À l'heure actuelle, il est actuellement marqué comme de faible qualité par la révision en raison de la longueur et du contenu et risque d'être supprimé par le système. Merci!
d_kennetz
1
convertir essentiellement l'entrée en un tableau (comme son nom l'indique). Donc, avec le contexte de la question, cette réponse est valable. check docs.scipy.org/doc/numpy/reference/generated/…
Lautaro Parada Opazo
Merci, je pense que c'est assez explicite.
Dadu Khan
8

Voici mon approche pour créer un tableau de structure à partir d'un DataFrame pandas.

Créer le bloc de données

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

Définissez la fonction pour créer un tableau de structure numpy (pas un tableau d'enregistrement) à partir d'un DataFrame 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

Permet reset_indexde créer un nouveau bloc de données qui inclut l'index dans ses données. Convertissez ce bloc de données en un tableau de structure.

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: mise à jour de df_to_sarray pour éviter une erreur lors de l'appel de .encode () avec python 3. Merci à Joseph Garvin et halcyon pour leurs commentaires et leur solution.

Phil
la source
ne fonctionne pas pour moi, erreur: TypeError: type de données non compris
Joseph Garvin
Merci pour ton commentaire et à halcyon pour la correction. J'ai mis à jour ma réponse et j'espère que cela fonctionne pour vous maintenant.
Phil
5

Un moyen plus simple pour exemple 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

UTILISATION:

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

AVOIR:

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')]))
Yanni Papadakis
la source
4

Juste eu un problème similaire lors de l'exportation de la trame de données vers la table arcgis et suis tombé sur une solution des usgs ( https://my.usgs.gov/confluence/display/cdi/pandas.DataFrame+to+ArcGIS+Table ). Bref, votre problème a une solution similaire:

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')]))
lars
la source
4

J'ai parcouru les réponses ci-dessus. La méthode " as_matrix () " fonctionne mais est désormais obsolète. Pour moi, ce qui a fonctionné était " .to_numpy () ".

Cela renvoie un tableau multidimensionnel. Je préfère utiliser cette méthode si vous lisez des données à partir d'une feuille Excel et que vous devez accéder aux données de n'importe quel index. J'espère que cela t'aides :)

Arsam
la source
Qu'entendez-vous par et avez-vous besoin d'accéder aux données de n'importe quel index ? Selon la nature de vos données, un Pandas DataFrame peut même ne pas être le bon choix en premier lieu.
AMC
2

Suite à la réponse de météore, j'ai trouvé le code

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

ne fonctionne pas pour moi. J'ai donc mis mon code ici pour la commodité des autres coincés avec ce problème.

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))
James L
la source
1

Un moyen simple de convertir la trame de données en tableau 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'utilisation de to_numpy est encouragée pour préserver la cohérence.

Référence: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_numpy.html

user1460675
la source
quelle est la différence entre la solution fournie par Arsam et la vôtre ...
qaiser
J'ai juste essayé de le rendre plus complet et utilisable avec un exemple de code, ce que je préfère personnellement.
user1460675