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.

Josh
la source

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().

Jeff
la source
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
dezzan
la source
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.).

OrangeSorbet
la source
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
utilisateur2015487
la source
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
jpp
la source
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).

Ismail Hachimi
la source
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.

Rohan Chandratre
la source
-3

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

john joy
la source
pas si les tableaux dans le dict sont de longueur différente
baxx