J'ai un dataframe comme celui-ci:
ordernum ordernum_index key value 222 1 a 1 222 2 b 3 222 3 c 2 222 4 d 1 333 1 a 1 333 2 d 1
ordernum dict_of item_counts
0 222 {'a': 1, 'b': 3, 'c': 2, 'd': 1}
1 333 {'a': 1, 'b': 0, 'c': 0, 'd': 1}
et j'aimerais créer un dataframe dans lequel chaque ordernum est répété pour chaque clé de dictionnaire dans dict_of_item_counts qui n'est pas 0. Je voudrais également créer une colonne key qui montre la clé de dictionnaire correspondante pour cette ligne ainsi qu'un valeur qui contient les valeurs du dictionnaire. Enfin, je voudrais également un ordernum_index qui compte les différentes lignes du dataframe pour chaque ordernum .
Le dataframe final devrait ressembler à ceci:
matrix = [(222, {'a': 1, 'b':3, 'c':2, 'd':1}),
(333, {'a': 1, 'b':0, 'c':0, 'd':1})]
df = pd.DataFrame(matrix, columns=['ordernum', 'dict_of item_counts'])
Toute aide serait très appréciée :)
4 Réponses :
Développez le dictionnaire en utilisant postulez avec pd.Series et utilisez concat pour concaténer cela à votre autre colonne (ordernum). Voir ci-dessous pour votre résultat intermédiaire de df2 .
Maintenant, pour transformer chaque colonne en ligne, utilisez fondre , puis utilisez query pour supprimer toutes les lignes 0 et enfin attribuer le cumcount pour obtenir l'index (après la commande) et ajoutez 1 pour commencer à compter à partir de 1, pas 0.
# ordernum a b c d #0 222 1 3 2 1 #1 333 1 0 0 1
Maintenant, df2 ressemble à:
df2 = pd.concat([df[['ordernum']], df['dict_of item_counts'].apply(pd.Series)], axis=1)
(df2.melt(id_vars='ordernum', var_name='key')
.query('value != 0')
.sort_values(['ordernum', 'key'])
.assign(ordernum_index = lambda df: df.groupby('ordernum').cumcount().add(1)))
# ordernum key value ordernum_index
#0 222 a 1 1
#2 222 b 3 2
#4 222 c 2 3
#6 222 d 1 4
#1 333 a 1 1
#7 333 d 1 2
Vous pouvez le faire en décompressant vos dictionnaires tout en y accédant avec iterrows et en créant un tuple à partir de ordernum, clé, valeur .
Enfin pour créer votre ordernum_index nous nous groupons sur ordernum et faisons un cumcount :
ordernum key value ordernum_index 0 222 a 1 1.0 1 222 b 3 2.0 2 222 c 2 3.0 3 222 d 1 4.0 4 333 a 1 1.0 7 333 d 1 2.0
data = [(r['ordernum'], k, v) for _, r in df.iterrows() for k, v in r['dict_of item_counts'].items() ]
new = pd.DataFrame(data, columns=['ordernum', 'key', 'value']).sort_values('ordernum').reset_index(drop=True)
new['ordernum_index'] = new[new['value'].ne(0)].groupby('ordernum').cumcount().add(1)
new.dropna(inplace=True)
La clé qui a la valeur 0 doit être exclue selon OP.
Essayez toujours de structurer vos données, peut être fait facilement comme ci-dessous:
>>> matrix
[(222, {'a': 1, 'b': 3, 'c': 2, 'd': 1}), (333, {'a': 1, 'b': 0, 'c': 0, 'd': 1})]
>>> data = [[item[0]]+[i+1]+list(value) for item in matrix for i,value in enumerate(item[1].items()) if value[-1]!=0]
>>> data
[[222, 1, 'a', 1], [222, 2, 'b', 3], [222, 3, 'c', 2], [222, 4, 'd', 1], [333, 1, 'a', 1], [333, 4, 'd', 1]]
>>> pd.DataFrame(data, columns=['ordernum', 'ordernum_index', 'key', 'value'])
ordernum ordernum_index key value
0 222 1 a 1
1 222 2 b 3
2 222 3 c 2
3 222 4 d 1
4 333 1 a 1
5 333 4 d 1
Construisez le dataframe df1 en utilisant df ['dict_of item_counts']. tolist () pour les valeurs et df.ordernum pour l'index. remplacez 0 par np.nan et stack par dropna = True pour ignorer 0 valeurs. reset_index pour obtenir toutes les colonnes.
Ensuite, créez la colonne ordernum_index en utilisant groupby et cumcount .
Enfin, remplacez les noms de colonnes par des noms appropriés.
df1 = pd.DataFrame(df['dict_of item_counts'].tolist(), index=df.ordernum).replace(0, np.nan).stack(dropna=True).reset_index(name='value')
df1['ordernum_index'] = df1.groupby('ordernum')['value'].cumcount() + 1
df1 = df1.rename(columns={'level_1': 'key'})
Out[732]:
ordernum key value ordernum_index
0 222 a 1.0 1
1 222 b 3.0 2
2 222 c 2.0 3
3 222 d 1.0 4
4 333 a 1.0 1
5 333 d 1.0 2
Avez-vous essayé quelque chose?