Je vais suivre le cours de statistique de la Khan Academy sur les statistiques pour me rafraîchir la mémoire et pour me mettre au courant de pandas et autres scientifiques Python.
J'ai une table qui ressemble à ceci de Khan Academy:
| Undergraduate | Graduate | Total
-------------+---------------+----------+------
Straight A's | 240 | 60 | 300
-------------+---------------+----------+------
Not | 3,760 | 440 | 4,200
-------------+---------------+----------+------
Total | 4,000 | 500 | 4,500
Je voudrais recréer cette table en utilisant des pandas. Bien sûr, je pourrais créer un DataFrame en utilisant quelque chose comme
"Graduate": {...},
"Undergraduate": {...},
"Total": {...},
Mais cela semble être une approche naïve qui tomberait à la fois rapidement et ne serait tout simplement pas extensible.
J'ai les parties non totales du tableau comme ceci:
df = pd.DataFrame(
{
"Undergraduate": {"Straight A's": 240, "Not": 3_760},
"Graduate": {"Straight A's": 60, "Not": 440},
}
)
df
J'ai cherché et trouvé quelques choses prometteuses, comme:
df['Total'] = df.sum(axis=1)
Mais je n'ai rien trouvé terriblement élégant.
J'ai trouvé la fonction crosstab
qui semble devoir faire ce que je veux, mais pour ce faire, il me faudrait créer un cadre de données constitué de 1/0 pour toutes ces valeurs, ce qui semble idiot parce que j'ai déjà un agrégat.
J'ai trouvé quelques approches qui semblent construire manuellement une nouvelle ligne de totaux, mais il semble qu'il devrait y avoir une meilleure façon, quelque chose comme:
totals(df, rows=True, columns=True)
ou quelque chose.
Cela existe-t-il dans les pandas ou dois-je simplement bricoler ma propre approche?
Ou en deux étapes, en utilisant la fonction .sum()
comme vous l'avez suggéré (qui pourrait également être un peu plus lisible):
import pandas as pd
df = pd.DataFrame( {"Undergraduate": {"Straight A's": 240, "Not": 3_760},"Graduate": {"Straight A's": 60, "Not": 440},})
#Total sum per column:
df.loc['Total',:]= df.sum(axis=0)
#Total sum per row:
df.loc[:,'Total'] = df.sum(axis=1)
Sortie:
Graduate Undergraduate Total
Not 440 3760 4200
Straight A's 60 240 300
Total 500 4000 4500
append
et assign
Le but de cette réponse est de fournir une solution en ligne et non une solution en place.
append
J'utilise append
pour empiler Series
ou DataFrame
verticalement. Cela crée également un copy
pour que je puisse continuer à chaîner.
assign
J'utilise assign
pour ajouter une colonne. Cependant, le DataFrame
sur lequel je travaille se situe entre les deux. J'utilise donc lambda
dans l'argument assign
qui indique à Pandas
de l'appliquer à l'appelant DataFrame
.
df.append(df.sum().rename('Total')).assign(Total=lambda d: d.sum(1))
Graduate Undergraduate Total
Not 440 3760 4200
Straight A's 60 240 300
Total 500 4000 4500
Utilise drop
avec errors='ignore'
pour supprimer les lignes et colonnes Total
potentiellement préexistantes.
Aussi, toujours en ligne.
def tc(d):
return d.assign(Total=d.drop('Total', errors='ignore', axis=1).sum(1))
df.pipe(tc).T.pipe(tc).T
Graduate Undergraduate Total
Not 440 3760 4200
Straight A's 60 240 300
Total 500 4000 4500
À partir des données d'origine en utilisant crosstab
, si vous vous basez simplement sur votre entrée, vous avez simplement besoin de melt
avant crosstab
s=df.reset_index().melt('index')
pd.crosstab(index=s['index'],columns=s.variable,values=s.value,aggfunc='sum',margins=True)
Out[33]:
variable Graduate Undergraduate All
index
Not 440 3760 4200
Straight A's 60 240 300
All 500 4000 4500
Données de jouets
df=pd.DataFrame({'c1':[1,2,2,3,4],'c2':[2,2,3,3,3],'c3':[1,2,3,4,5]})
# before `agg`, I think your input is the result after `groupby`
df
Out[37]:
c1 c2 c3
0 1 2 1
1 2 2 2
2 2 3 3
3 3 3 4
4 4 3 5
pd.crosstab(df.c1,df.c2,df.c3,aggfunc='sum',margins
=True)
Out[38]:
c2 2 3 All
c1
1 1.0 NaN 1
2 2.0 3.0 5
3 NaN 4.0 4
4 NaN 5.0 5
All 3.0 12.0 15
Les données d'origine sont:
>>> df = pd.DataFrame(dict(Undergraduate=[240, 3760], Graduate=[60, 440]), index=["Straight A's", "Not"])
>>> df
Out:
Graduate Undergraduate
Straight A's 60 240
Not 440 3760
Vous pouvez uniquement utiliser df.T
pour reconstituer ce tableau:
>>> df_new = df.T
>>> df_new
Out:
Straight A's Not
Graduate 60 440
Undergraduate 240 3760
Après avoir calculé la Total
par rangée et par colonne:
>>> df_new.loc['Total',:]= df_new.sum(axis=0)
>>> df_new.loc[:,'Total'] = df_new.sum(axis=1)
>>> df_new
Out:
Straight A's Not Total
Graduate 60.0 440.0 500.0
Undergraduate 240.0 3760.0 4000.0
Total 300.0 4200.0 4500.0