2
votes

Quelle est la meilleure façon de créer un Pandas MultiIndex à partir d'une liste de dictionnaires?

J'ai un processus itératif qui s'exécute avec différentes valeurs de paramètres à chaque itération et je souhaite collecter les valeurs de paramètres et les résultats et les placer dans un dataframe Pandas avec un multi-index construit à partir des ensembles de valeurs de paramètres (qui sont uniques) .

À chaque itération, les valeurs des paramètres sont dans un dictionnaire comme celui-ci:

index = pd.MultiIndex.from_tuples([tuple(i.values()) for i in results_index], 
                                  names=results_index[0].keys())
df = pd.DataFrame(results_data, index=index)

        A     B
p q            
2 7  0.18  0.18
  5  0.67  0.21
1 4  0.96  0.45
2 4  0.58  0.66

Il est donc facile de les rassembler dans une liste avec les résultats: p>

df = pd.concat([pd.DataFrame(results_index), pd.DataFrame(results_data)], axis=1).set_index(['p', 'q'])

Mais je ne trouve pas de moyen simple de produire le multi-index souhaité à partir de results_index.

J'ai essayé ceci:

        A     B
p q            
2 7  0.18  0.18
  5  0.67  0.21
1 4  0.96  0.45
2 4  0.58  0.66

Mais cela produit ceci:

                     A     B
{'p': 2, 'q': 7}  0.18  0.18
{'p': 2, 'q': 5}  0.67  0.21
{'p': 1, 'q': 4}  0.96  0.45
{'p': 2, 'q': 4}  0.58  0.66

(L'index ne s'est pas converti en MultiIndex)

Ce que je veux, c'est ceci:

df = pd.DataFrame(results_data, index=results_index)

Cela fonctionne, mais il doit y avoir un moyen plus simple:

results_index = [
    {'p': 2, 'q': 7},
    {'p': 2, 'q': 5},
    {'p': 1, 'q': 4},
    {'p': 2, 'q': 4}
]
results_data = [
    {'A': 0.18, 'B': 0.18},
    {'A': 0.67, 'B': 0.21},
    {'A': 0.96, 'B': 0.45},
    {'A': 0.58, 'B': 0.66}
]

UPDATE:

De plus, cela fonctionne mais me rend nerveux car comment puis-je être sûr que les valeurs des paramètres sont alignées avec les noms de niveau?

params = {'p': 2, 'q': 7}


1 commentaires

pd.DataFrame ({** x, ** y} pour x, y dans zip (results_index, results_data)). set_index (['p', 'q']) fonctionne, mais honnêtement pas trop différent de votre solution concat .


4 Réponses :


1
votes

J'ai essayé avec .join ()

df1 = pd.DataFrame(results_index)
df2 = pd.DataFrame(results_data)
result = df1.join(df2, how='outer').set_index(['p','q'])

J'ai obtenu les mêmes résultats et j'ai trouvé cela plus facile. J'espère que cela vous aide.


0 commentaires

2
votes

Créez un dictionnaire de listes et passez à MultiIndex.from_arrays :

#https://stackoverflow.com/a/33046935
d = {k: [dic[k] for dic in results_index] for k in results_index[0]}
print(d)
{'p': [2, 2, 1, 2], 'q': [7, 5, 4, 4]}

mux = pd.MultiIndex.from_arrays(list(d.values()), names=list(d))

df = pd.DataFrame(results_data, index=mux)
print (df)
        A     B
p q            
2 7  0.18  0.18
  5  0.67  0.21
1 4  0.96  0.45
2 4  0.58  0.66


4 commentaires

Oui, je pense qu'il ne semble pas y avoir d'autre moyen, la meilleure chose à faire est de collecter toutes les valeurs de paramètres dans les listes en premier lieu (en vérifiant à chaque itération que les paramètres sont les mêmes et sont ajoutés à la bonne liste), puis en utilisant le pd.MultiIndex.from_arrays à la fin. Il ne semble pas qu'il existe un moyen facile de créer un multi-index à partir d'une liste de dictionnaires. Merci.


Voir la nouvelle réponse de @santon en utilisant pd.MultiIndex.from_frame .


@Bill Oui, je le vois.


Alternative avec pd.MultiIndex.from_tuples : tuples = [tuple (d.values ​​()) pour d dans results_index]; index = pd.MultiIndex.from_tuples (tuples, noms = liste (result_index.keys ())); df = pd.DataFrame (données_résultats, index = index)



0
votes

Ceci est une variante de la réponse de @ jezrael. Légèrement plus concis et a l'avantage de pouvoir gérer les incohérences potentielles dans les dictionnaires de paramètres. Mais pas aussi vite.

        A     B
p q            
2 7  0.18  0.18
  5  0.67  0.21
1 4  0.96  0.45
2 4  0.58  0.66

Résultat:

index_df = pd.DataFrame(results_index)
index = pd.MultiIndex.from_arrays(index_df.values.transpose(),
                                  names=index_df.columns)
pd.DataFrame(results_data, index=index)


0 commentaires

2
votes

Je suis tombé dessus récemment et il semble qu'il y ait un moyen un peu plus propre que la réponse acceptée:

        A     B
p q            
2 7  0.18  0.18
  5  0.67  0.21
1 4  0.96  0.45
2 4  0.58  0.66

Résultats:

results_index = [
    {'p': 2, 'q': 7},
    {'p': 2, 'q': 5},
    {'p': 1, 'q': 4},
    {'p': 2, 'q': 4}
]

results_data = [
    {'A': 0.18, 'B': 0.18},
    {'A': 0.67, 'B': 0.21},
    {'A': 0.96, 'B': 0.45},
    {'A': 0.58, 'B': 0.66}
]

index = pd.MultiIndex.from_frame(pd.DataFrame(results_index))

pd.DataFrame(results_data, index=index)


0 commentaires