Suivez cette question , en particulier ce commentaire .
Considérez le dataframe suivant:
Belonging Bike Car House Person Adam NaN [10.0] [300.0, 180.0] Cesar NaN [12.0] NaN Diana [2.0] [15.0, 21.0] [450.0] Erika NaN [11.0] [600.0]
À quoi ressemble comme ceci:
df_pivot = df.pivot_table( values='Value', index='Person', columns='Belonging', aggfunc=list, )
L'utilisation d'un pivot_table ()
est un bon moyen de remodeler ces données qui permettra de les interroger par personne et de voir toutes leurs effets personnels sur une seule ligne, ce qui permet de répondre très facilement à des requêtes telles que "Comment trouver la valeur de la voiture des personnes, si leur maison a une valeur supérieure à 400,0?"
A pivot_table ()
peut être facilement construit pour cet ensemble de données avec:
Belonging Bike Car House Person Adam NaN 10.0 240.0 Cesar NaN 12.0 NaN Diana 2.0 18.0 450.0 Erika NaN 11.0 600.0
Ce qui ressemblera à:
Person Belonging Value 0 Adam House 300.0 1 Adam Car 10.0 2 Cesar Car 12.0 3 Diana House 450.0 4 Diana Car 15.0 5 Diana Bike 2.0 6 Erika House 600.0 7 Erika Car 11.0 8 Diana Car 21.0 9 Adam House 180.0
Mais cela est limité lorsqu'une personne a plus d'un du même type d'appartenance, par exemple deux voitures, deux maisons ou deux vélos.
Tenez compte des données mises à jour:
df = pd.DataFrame({ 'Person': ['Adam', 'Adam', 'Cesar', 'Diana', 'Diana', 'Diana', 'Erika', 'Erika', 'Diana', 'Adam'], 'Belonging': ['House', 'Car', 'Car', 'House', 'Car', 'Bike', 'House', 'Car', 'Car', 'House'], 'Value': [300.0, 10.0, 12.0, 450.0, 15.0, 2.0, 600.0, 11.0, 21.0, 180.0], })
pivot_table ()
; J'ai pensé à mettre à jour les descriptions d'appartenance pour inclure un compteur, tel que "Maison 1", "Voiture 2", etc. Peut-être trier pour que le plus précieux vienne en premier (pour aider à répondre à des questions telles que "possède une maison valant plus de 400,0" en regardant uniquement "Maison 1".)
Ou peut-être en utilisant un pd.MultiIndex
pour pouvoir accéder à toutes les colonnes "Maison"
Mais je ne sais pas comment remodeler les données de cette manière.
Ou y a-t-il de meilleures suggestions sur la façon de les remodeler (autre que d'ajouter un décompte par appartenance) qui conserver les fonctionnalités décrites ci-dessus? Comment le remodeleriez-vous et comment répondriez-vous à toutes ces questions que j'ai mentionnées ci-dessus?
4 Réponses :
En utilisant groupby
, vous pourriez réaliser quelque chose comme ceci.
df.pivot('Person', 'Belonging') Value Belonging Bike_1 Car_1 Car_2 House_1 House_2 Person Adam NaN 10.0 NaN 300.0 180.0 Cesar NaN 12.0 NaN NaN NaN Diana 2.0 15.0 21.0 450.0 NaN Erika NaN 11.0 NaN 600.0 NaN
ce qui donnerait.
df['Belonging'] = df["Belonging"] + "_" + df.groupby(['Person','Belonging']).cumcount().add(1).astype(str) Person Belonging Value 0 Adam House_1 300.0 1 Adam Car_1 10.0 2 Cesar Car_1 12.0 3 Diana House_1 450.0 4 Diana Car_1 15.0 5 Diana Bike_1 2.0 6 Erika House_1 600.0 7 Erika Car_1 11.0 8 Diana Car_2 21.0 9 Adam House_2 180.0
Vous pouvez définir vos propres fonctions dans la méthode .agg
pour fournir des descriptions plus appropriées également.
Vous pouvez également essayer p>
Value sum count min max Person Belonging Adam Car 10.0 1 10.0 10.0 House 480.0 2 180.0 300.0 Cesar Car 12.0 1 12.0 12.0 Diana Bike 2.0 1 2.0 2.0 Car 36.0 2 15.0 21.0 House 450.0 1 450.0 450.0 Erika Car 11.0 1 11.0 11.0 House 600.0 1 600.0 600.0
Ensuite, vous pouvez simplement utiliser pivot
df_new = df.groupby(['Person', 'Belonging']).agg(('sum', 'count', 'min', 'max'))
Ce résumé est certainement utile, mais ne permet pas vraiment (ou même possible?) De répondre à des questions telles que "Comment trouver la valeur de la voiture des personnes, si leur maison a une valeur supérieure à 400,0?"
Ajout de quelques modifications pour répondre à cette question. Bien que je pense que @SpghttCd a une bonne solution
Peut-être comme ceci:
étant donné votre tableau croisé dynamique dans le cadre de données suivant:
new_pv.filter(like='House').sum().sum() # 1530.0
puis appliquez pd.Series
à toutes les colonnes .
Pour nommer correctement les colonnes, calculez la longueur maximale des listes dans chaque colonne, puis utilisez 'set_axis' pour renommer:
new_pv.filter(like='House').count(1) # Person # Adam 2 # Cesar 0 # Diana 1 # Erika 1 # dtype: int64
comptage des maisons:
XXX
somme de toutes les valeurs de la maison:
new_pv = pd.DataFrame(index=pv.index) for col in pv: n = int(pv[col].str.len().max()) new_pv = pd.concat([new_pv, pv[col].apply(pd.Series).set_axis([f'{col}_{i}' for i in range(n)], 1, inplace = False)], 1) # Bike_0 Car_0 Car_1 House_0 House_1 # Person # Adam NaN 10.0 NaN 300.0 180.0 # Cesar NaN 12.0 NaN NaN NaN # Diana 2.0 15.0 21.0 450.0 NaN # Erika NaN 11.0 NaN 600.0 NaN
Oui, c'est sympa! Bien que pour répondre à la valeur totale de toutes les maisons, je devrais parcourir les colonnes pour déterminer le nombre de maisons que l'on pourrait avoir ... Par exemple, pour trouver new_pv.House_0.sum () + new_pv.House_1.sum ()
qui devrait donner 1530.0
ou new_pv.filter (like = 'House'). sum (). sum ()
J'ai essayé de faire cela avec les listes du dataframe, afin qu'elles soient converties en ndarrays.
pd_df_pivot = df_pivot.copy(deep=True) for row in range(0,df_pivot.shape[0]): for col in range(0,df_pivot.shape[1]): if type(df_pivot.iloc[row,col]) is list: pd_df_pivot.iloc[row,col] = np.array(df_pivot.iloc[row,col]) else: pd_df_pivot.iloc[row,col] = df_pivot.iloc[row,col]
Idée intéressante! Mais un moyen plus simple d'accomplir cela est d'appeler directement pivot_table ()
avec aggfunc = np.array
. Cela fait, il est possible d'obtenir la valeur totale des maisons avec df_pivot ['House']. Apply (np.sum) .sum ()
. Prometteur, mais je pense que les colonnes Pandas sont toujours meilleures que les ndarrays dans les cellules ici.
Je pense que vous auriez pensé à aggfunc = pd.DataFrame, j'essaie de trouver comment vous pouvez répondre "Comment trouver la valeur de la voiture des personnes, si elles ont une maison évaluée à plus de 400,0"
J'ai fini par trouver une solution à celle-ci, inspirée des excellentes réponses de @SpghttCd et @ Josmoor98 , mais avec quelques différences:
Code pour le tableau croisé dynamique:
df_pivot.loc['Adam'].dropna()
DataFrame résultant:
df_pivot['House'].sum()
Les requêtes sont assez simples .
Par exemple, trouver la valeur de la voiture de la personne s , si sa maison a une valeur supérieure à 400,0:
df_pivot.loc[ df_pivot[('House', 1)] > 400.0, 'Car' ].stack().mean()
Résultat:
BelongingNo 1 2 Person Diana 21.0 15.0 Erika 11.0 NaN
Le prix moyen de la voiture pour eux:
df_pivot.loc[ df_pivot[('House', 1)] > 400.0, 'Car' ]
Résultat: 15,6666
Ici, utiliser stack ()
est un moyen puissant d'aplatir le deuxième niveau du MultiIndex, après avoir utilisé le niveau supérieur pour sélectionner une colonne Appartenance.
La même chose est utile pour obtenir la valeur totale de toutes les maisons:
Belonging Bike Car House BelongingNo 1 1 2 1 2 Person Adam NaN 10.0 NaN 300.0 180.0 Cesar NaN 12.0 NaN NaN NaN Diana 2.0 21.0 15.0 450.0 NaN Erika NaN 11.0 NaN 600.0 NaN
Résultats dans les 1530,0 attendus.
Enfin, en regardant tous les biens d'une seule personne: p >
df_pivot = (df .assign(BelongingNo=df .sort_values(by='Value', ascending=False) .groupby(['Person', 'Belonging']) .cumcount() + 1 ) .pivot_table( values='Value', index='Person', columns=['Belonging', 'BelongingNo'], ) )
Renvoie les deux maisons attendues et la voiture, avec leurs valeurs respectives.