2
votes

Remplir une trame de données pandas à partir d'un dictionnaire étrange

J'ai un dictionnaire comme suit:

for header_name, body_list in all_unique.items():
    for body_name in body_list:
        metadata.loc[metadata.index[-1]] = [header_name, body_name]

Je voudrais créer un dataframe comme celui-ci:

+----+----------+--------+
| ID | header   | body   |
+----+----------+--------+
| 1  | header_1 | body_1 |
+----+----------+--------+
| 2  | header_1 | body_3 |
+----+----------+--------+
| 3  | header_1 | body_2 |
+----+----------+--------+
| 4  | header_2 | body_6 |
+----+----------+--------+
| 5  | header_2 | body_4 |
+----+----------+--------+
| 6  | header_2 | body_5 |
+----+----------+--------+
| 7  | header_4 | body_7 |
+----+----------+--------+

Où vide les éléments (comme pour la clé header_10 dans le dict ci-dessus) recevraient la valeur None . J'ai essayé un certain nombre de variétés pour df.loc telles que:

{'header_1': ['body_1', 'body_3', 'body_2'],
 'header_2': ['body_6', 'body_4', 'body_5'],
 'header_4': ['body_7', 'body_8'],
 'header_3': ['body_9'],
 'header_9': ['body_10'],
 'header_10': []}

En vain. Il doit sûrement y avoir un moyen rapide dans panadas d'ajouter des lignes et d'auto-incrémenter l'index? Quelque chose de similaire à l'instruction SQL INSERT INTO utilisant uniquement du code pythonique?

Merci.


5 commentaires

Et si vous transformiez simplement votre dictionnaire en quelque chose que les pandas pourraient gérer avant la main?


Ce serait inefficace, vous ne pensez pas? Cela introduirait du code supplémentaire ...


Plus inefficace que de tenter de réallouer la totalité du dataframe à chaque étape? Parce que c'est ce que cela fera.


À titre de comparaison, vous avez le dictionnaire, qui est une structure de données spécialement conçue pour être mutée efficacement. Plus de code ne signifie pas un code moins efficace.


@ W-B Je publierais à nouveau cette réponse. C'est précisément ce dont j'avais besoin


3 Réponses :


2
votes

Ceci est un autre problème de désemboîtement

Empruntez la configuration de Jez pour votre d

def unnesting(df, explode):
    idx=df.index.repeat(df[explode[0]].str.len())
    df1=pd.concat([pd.DataFrame({x:np.concatenate(df[x].values)} )for x in explode],axis=1)
    df1.index=idx
    return df1.join(df.drop(explode,1),how='left')

Commencez par convertir votre dict en dataframe

yourdf=unnesting(df,[0])
yourdf
Out[208]: 
         0      index
0   body_1   header_1
0   body_3   header_1
0   body_2   header_1
1   body_6   header_2
1   body_4   header_2
1   body_5   header_2
2   body_7   header_4
2   body_8   header_4
3   body_9   header_3
4  body_10   header_9
5     None  header_10

Puis en utilisant cette fonction dans ici

df=pd.Series(d).reset_index()
df.columns
Out[204]: Index(['index', 0], dtype='object')

d = {k: v if bool(v) else [None] for k, v in d.items()}


3 commentaires

@jezrael ok laissez-moi supprimer ma réponse


Je pense que cette réponse est toujours valable car elle montre une approche alternative. Mais je préfère la méthode de @ jezrael car elle nécessite moins de lignes de code


@ user32882 pas de souci, sa réponse est meilleure à coup sûr



2
votes

Si l'ensemble de données est trop volumineux, cette solution serait lente, mais elle devrait quand même fonctionner.

for key in data.keys():
    vals= data[key]
    # Create temp df with data from a single key
    t_df = pd.DataFrame({'header':[key]*len(vals),'body':vals})

    # Append it to your full dataframe.
    df = df.append(t_df)


0 commentaires

6
votes

Utilisez la compréhension de dict pour ajouter Aucun s pour les listes vides, puis aplatir pour la liste des tuples:

data = []
for k, v in d.items():
    if bool(v):
        for y in v:
            data.append((k, y))
    else:
        data.append((k, None))


df = pd.DataFrame(data, columns= ['a','b'])
print (df)
            a        b
0    header_1   body_1
1    header_1   body_3
2    header_1   body_2
3    header_2   body_6
4    header_2   body_4
5    header_2   body_5
6    header_4   body_7
7    header_4   body_8
8    header_3   body_9
9    header_9  body_10
10  header_10     None

Une autre solution:

d = {'header_1': ['body_1', 'body_3', 'body_2'],
 'header_2': ['body_6', 'body_4', 'body_5'],
 'header_4': ['body_7', 'body_8'],
 'header_3': ['body_9'],
 'header_9': ['body_10'],
 'header_10': []}

d = {k: v if bool(v) else [None] for k, v in d.items()}
data = [(k, y) for k, v in d.items() for y in v]
df = pd.DataFrame(data, columns= ['a','b'])
print (df)
            a        b
0    header_1   body_1
1    header_1   body_3
2    header_1   body_2
3    header_2   body_6
4    header_2   body_4
5    header_2   body_5
6    header_4   body_7
7    header_4   body_8
8    header_3   body_9
9    header_9  body_10
10  header_10     None


2 commentaires

Puis-je emprunter votre configuration pour d ?


Réponse très agréable / créative. Vous pouvez également utiliser if v au lieu de if bool (v) .