Création d'une trame de données à partir d'un dictionnaire où les entrées ont des longueurs différentes


114

Disons que j'ai un dictionnaire avec 10 paires clé-valeur. Chaque entrée contient un tableau numpy. Cependant, la longueur du tableau n'est pas la même pour tous.

Comment créer un dataframe dans lequel chaque colonne contient une entrée différente?

Quand j'essaye:

pd.DataFrame(my_dict)

Je reçois:

ValueError: arrays must all be the same length

Un moyen de surmonter cela? Je suis heureux que Pandas utilise NaNpour remplir ces colonnes pour les entrées plus courtes.

Réponses:


132

Dans Python 3.x:

In [6]: d = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )

In [7]: pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in d.items() ]))
Out[7]: 
    A  B
0   1  1
1   2  2
2 NaN  3
3 NaN  4

Dans Python 2.x:

remplacer d.items()par d.iteritems().


Je travaillais sur ce même problème récemment, et c'est mieux que ce que j'avais! Une chose à noter, le remplissage avec NaNs contraindra la série dtype à float64, ce qui peut être problématique si vous devez faire des calculs entiers.
mattexx

vous pouvez toujours poser une question - beaucoup de gens y répondent
Jeff

vous devez fournir MVCE comme le suggèrent les commentaires
Jeff

3
@germ, vous voudrez peut-être importer la série en premier ou faire quelque chose comme pd.Series(...) (en supposant import pandas as pddans la section d'importation)
Nima Mousavi

5
Version plus compacte de cette réponse:pd.DataFrame({k: pd.Series(l) for k, l in d.items()})
user553965

82

Voici un moyen simple de le faire:

In[20]: my_dict = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )
In[21]: df = pd.DataFrame.from_dict(my_dict, orient='index')
In[22]: df
Out[22]: 
   0  1   2   3
A  1  2 NaN NaN
B  1  2   3   4
In[23]: df.transpose()
Out[23]: 
    A  B
0   1  1
1   2  2
2 NaN  3
3 NaN  4

existe-t-il d'autres options pour «indexer»?
sAguinaga

@sAguinaga Oui:, columnsmais c'est déjà la valeur par défaut. Voir la documentation des pandas - pandas.DataFrame.from_dict
Murmel

15

Vous trouverez ci-dessous un moyen de ranger votre syntaxe, tout en faisant essentiellement la même chose que ces autres réponses:

>>> mydict = {'one': [1,2,3], 2: [4,5,6,7], 3: 8}

>>> dict_df = pd.DataFrame({ key:pd.Series(value) for key, value in mydict.items() })

>>> dict_df

   one  2    3
0  1.0  4  8.0
1  2.0  5  NaN
2  3.0  6  NaN
3  NaN  7  NaN

Une syntaxe similaire existe également pour les listes:

>>> mylist = [ [1,2,3], [4,5], 6 ]

>>> list_df = pd.DataFrame([ pd.Series(value) for value in mylist ])

>>> list_df

     0    1    2
0  1.0  2.0  3.0
1  4.0  5.0  NaN
2  6.0  NaN  NaN

Une autre syntaxe pour les listes est:

>>> mylist = [ [1,2,3], [4,5], 6 ]

>>> list_df = pd.DataFrame({ i:pd.Series(value) for i, value in enumerate(mylist) })

>>> list_df

   0    1    2
0  1  4.0  6.0
1  2  5.0  NaN
2  3  NaN  NaN

Vous devrez peut-être en outre transposer le résultat et / ou modifier les types de données de la colonne (flottant, entier, etc.).


3

Bien que cela ne réponde pas directement à la question du PO. J'ai trouvé que c'était une excellente solution pour mon cas lorsque j'avais des tableaux inégaux et que j'aimerais partager:

de la documentation pandas

In [31]: d = {'one' : Series([1., 2., 3.], index=['a', 'b', 'c']),
   ....:      'two' : Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
   ....: 

In [32]: df = DataFrame(d)

In [33]: df
Out[33]: 
   one  two
a    1    1
b    2    2
c    3    3
d  NaN    4

3

Vous pouvez également utiliser pd.concatainsi axis=1une liste d' pd.Seriesobjets:

import pandas as pd, numpy as np

d = {'A': np.array([1,2]), 'B': np.array([1,2,3,4])}

res = pd.concat([pd.Series(v, name=k) for k, v in d.items()], axis=1)

print(res)

     A  B
0  1.0  1
1  2.0  2
2  NaN  3
3  NaN  4

2

Les deux lignes suivantes fonctionnent parfaitement:

pd.DataFrame.from_dict(df, orient='index').transpose() #A

pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in df.items() ])) #B (Better)

Mais avec% timeit sur Jupyter, j'ai un rapport de vitesse 4x pour B vs A, ce qui est assez impressionnant, surtout lorsque vous travaillez avec un énorme ensemble de données (principalement avec un grand nombre de colonnes / fonctionnalités).


1

Si vous ne voulez pas qu'il s'affiche NaNet que vous avez deux longueurs particulières, l'ajout d'un «espace» dans chaque cellule restante fonctionnera également.

import pandas

long = [6, 4, 7, 3]
short = [5, 6]

for n in range(len(long) - len(short)):
    short.append(' ')

df = pd.DataFrame({'A':long, 'B':short}]
# Make sure Excel file exists in the working directory
datatoexcel = pd.ExcelWriter('example1.xlsx',engine = 'xlsxwriter')
df.to_excel(datatoexcel,sheet_name = 'Sheet1')
datatoexcel.save()

   A  B
0  6  5
1  4  6
2  7   
3  3   

Si vous avez plus de 2 longueurs d'entrées, il est conseillé de créer une fonction qui utilise une méthode similaire.


-3

pd.DataFrame ([my_dict]) fera l'affaire!


pas si les tableaux dans le dict sont de longueur différente
baxx
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.