web-dev-qa-db-fra.com

Convertissez pandas dataframe en tableau NumPy

Je suis intéressé à savoir comment convertir un pandas dataframe en 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 ceci en tableau NumPy, ainsi:

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 prime, est-il possible de préserver les types, comme ceci?

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?

349
mister.nobody.nz

Pour convertir un pandas dataframe (df) en un Numpy ndarray, 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]])
308
User456898

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

La méthode .as_matrix sera supprimée dans une version ultérieure. Utilisez .values ​​à la place.


Pandas a quelque chose construit dans ...

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

Obsolète ton utilisation de values et as_matrix()!

À partir de la v0.24.0, nous avons découvert deux nouvelles méthodes préférées pour obtenir des matrices NumPy à partir de pandas objets:

  1. to_numpy(), défini sur les objets Index, _Series,_ et DataFrame, et
  2. array, défini uniquement sur les objets Index et Series.

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

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

Voir cette section des notes de version v0.24. , et cette réponse pour plus d'informations.


Vers une meilleure cohérence: to_numpy()

Dans l’esprit d’une meilleure cohérence dans l’API, une nouvelle méthode _to_numpy_ a été introduite pour extraire le tableau NumPy sous-jacent à partir de DataFrames.

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

   A  B
a  1  4
b  2  5
c  3  6
_
_df.to_numpy()
array([[1, 4],
       [2, 5],
       [3, 6]])
_

Comme mentionné ci-dessus, cette méthode est également définie sur les objets Index et 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 renvoyée, ainsi toute modification apportée affectera 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_);

_v = df.to_numpy(copy=True)
v[0, 0] = -123

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

Si vous devez conserver le dtypes...
Comme indiqué dans une autre réponse, DataFrame.to_records est un bon moyen de procéder.

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

Cela ne peut pas être fait avec _to_numpy_, malheureusement. Toutefois, vous pouvez également 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 ce qui concerne les performances, c'est presque la même chose (en fait, utiliser _rec.fromrecords_ est 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 sous deux problèmes GitHub GH19954 et GH2362 .

Plus précisément, les docs mentionnent le raisonnement suivant:

[...] avec _.values_ il n'était pas clair si la valeur renvoyée serait le tableau réel, une transformation de celui-ci ou l'un des pandas tableaux personnalisés (comme Categorical). Par exemple, avec PeriodIndex, _.values_ génère chaque fois un nouvel objet ndarray of period. [...]

_to_numpy_ vise à améliorer la cohérence de l'API, ce qui constitue un pas important dans la bonne direction. _.values_ ne sera pas obsolète dans la version actuelle, mais je suppose que cela pourrait se produire à l'avenir. J'invite donc les utilisateurs à migrer vers la nouvelle API dès que possible.


Critique d'autres solutions

_DataFrame.values_ a un comportement incohérent, comme déjà noté.

DataFrame.get_values() est simplement un wrapper autour de _DataFrame.values_, donc tout ce qui est dit ci-dessus s'applique.

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

105
cs95

Je voudrais juste enchaîner les fonctions DataFrame.reset_index () et DataFrame.values pour obtenir la représentation Numpy du cadre 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 types, 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')])
64
prl900

Vous pouvez utiliser la méthode to_records, mais vous devez jouer un peu avec les types de données s'ils ne correspondent pas à vos souhaits. 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 object dtype dans les 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 type de recarray ne fonctionne pas pour moi, mais on peut déjà le faire dans Pandas déjà:

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 correctement le nom de l'index (sur ID) dans le tableau d'enregistrements exporté (un bogue?), 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 des flottants, f8 (voir this issue ).

31
meteore

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

J'ai essayé cela localement en utilisant votre exemple, et cet appel produit quelque chose de très similaire au résultat que vous recherchiez:

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 d'une recarray plutôt que d'un array. Vous pouvez déplacer le résultat dans un tableau numpy normal en appelant son constructeur sous la forme np.array(df.to_records()).

22
Jamie Doyle

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

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 (et non un tableau d’enregistrements) à partir d’un pandas DataFrame.

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

Utilisez reset_index pour créer un nouveau cadre de données incluant l’index dans ses données. Convertissez ce cadre 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 les erreurs lors de l’appel de .encode () avec python 3. Grâce à Joseph Garvin et halcyon pour leur commentaire et leur solution.

8
Phil

Deux façons de convertir le cadre de données en sa représentation 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

6
Priyanshu Chauhan

Un moyen plus simple pour l'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))

OBTENIR:

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
Yanni Papadakis

Vient juste d'avoir un problème similaire lors de l'exportation de dataframe vers la table arcgis et est tombé sur une solution de usgs ( https://my.usgs.gov/confluence/display/cdi/pandas.DataFrame+to++ArcGIS+Table ). En 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')]))
4
lars

Essaye ça:

a = numpy.asarray(df)
4
Dadu Khan

Suite à la réponse de meteore, j'ai trouvé le code

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

ça ne marche pas pour moi. Donc, je mets 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))
2
James L

Ecrivez to_numpy au lieu de to_numpy() pour conserver les types.

1
Shuang Li

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

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

0
Arsam