Essayer de créer une nouvelle colonne à partir du calcul groupby
. Dans le code ci-dessous, j'obtiens les valeurs calculées correctes pour chaque date (voir groupe ci-dessous), mais lorsque j'essaie de créer une nouvelle colonne (df['Data4']
) avec cela je reçois NaN. J'essaie donc de créer une nouvelle colonne dans le cadre de données avec la somme de Data3
pour toutes les dates et l’appliquer à chaque rangée de dates. Par exemple, 2015-05-08 est sur 2 lignes (le total est 50 + 5 = 55) et dans cette nouvelle colonne, j'aimerais avoir 55 dans les deux lignes.
import pandas as pd
import numpy as np
from pandas import DataFrame
df = pd.DataFrame({'Date': ['2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05', '2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05'], 'Sym': ['aapl', 'aapl', 'aapl', 'aapl', 'aaww', 'aaww', 'aaww', 'aaww'], 'Data2': [11, 8, 10, 15, 110, 60, 100, 40],'Data3': [5, 8, 6, 1, 50, 100, 60, 120]})
group = df['Data3'].groupby(df['Date']).sum()
df['Data4'] = group
Vous voulez utiliser transform
Cela retournera une série avec l'index aligné sur le df afin que vous puissiez ensuite l'ajouter comme une nouvelle colonne:
In [74]:
df = pd.DataFrame({'Date': ['2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05', '2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05'], 'Sym': ['aapl', 'aapl', 'aapl', 'aapl', 'aaww', 'aaww', 'aaww', 'aaww'], 'Data2': [11, 8, 10, 15, 110, 60, 100, 40],'Data3': [5, 8, 6, 1, 50, 100, 60, 120]})
df['Data4'] = df['Data3'].groupby(df['Date']).transform('sum')
df
Out[74]:
Data2 Data3 Date Sym Data4
0 11 5 2015-05-08 aapl 55
1 8 8 2015-05-07 aapl 108
2 10 6 2015-05-06 aapl 66
3 15 1 2015-05-05 aapl 121
4 110 50 2015-05-08 aaww 55
5 60 100 2015-05-07 aaww 108
6 100 60 2015-05-06 aaww 66
7 40 120 2015-05-05 aaww 121
Comment créer une nouvelle colonne avec Groupby (). Sum ()?
Il y a deux manières - l'une directe et l'autre légèrement plus intéressante.
GroupBy.transform()
avec 'sum'
La réponse de @Ed Chum peut être un peu simplifiée. Appelez DataFrame.groupby
Plutôt que Series.groupby
. Cela se traduit par une syntaxe plus simple.
# The setup.
df[['Date', 'Data3']]
Date Data3
0 2015-05-08 5
1 2015-05-07 8
2 2015-05-06 6
3 2015-05-05 1
4 2015-05-08 50
5 2015-05-07 100
6 2015-05-06 60
7 2015-05-05 120
df.groupby('Date')['Data3'].transform('sum')
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Data3, dtype: int64
C'est un peu rapide,
df2 = pd.concat([df] * 12345)
%timeit df2['Data3'].groupby(df['Date']).transform('sum')
%timeit df2.groupby('Date')['Data3'].transform('sum')
10.4 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
8.58 ms ± 559 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
GroupBy.sum()
+ Series.map()
Je suis tombé sur une idiosyncrasie intéressante dans l'API. D'après ce que je dis, vous pouvez reproduire cela sur toutes les versions majeures supérieures à 0.20 (j'ai testé cela sur 0.23 et 0.24). Il semble que vous puissiez constamment gagner quelques millisecondes du temps pris par transform
si vous utilisez plutôt une fonction directe de GroupBy
et que vous la diffusez à l'aide de map
:
df.Date.map(df.groupby('Date')['Data3'].sum())
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Date, dtype: int64
Comparer avec
df.groupby('Date')['Data3'].transform('sum')
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Data3, dtype: int64
Mes tests montrent que map
est un peu plus rapide si vous pouvez vous permettre d’utiliser la fonction directe GroupBy
(telle que mean
, min
, max
, first
, etc). Il est plus ou moins rapide dans la plupart des situations d’environ 200 000 enregistrements. Après cela, la performance dépend vraiment des données.
(Gauche: v0.23, Droite: v0.24)
Belle alternative à connaître, et mieux si vous avez des cadres plus petits avec un plus petit nombre de groupes. . . mais je recommanderais transform
comme premier choix. Pensé que cela valait la peine de partager de toute façon.
Code de référence, pour référence:
import perfplot
perfplot.show(
setup=lambda n: pd.DataFrame({'A': np.random.choice(n//10, n), 'B': np.ones(n)}),
kernels=[
lambda df: df.groupby('A')['B'].transform('sum'),
lambda df: df.A.map(df.groupby('A')['B'].sum()),
],
labels=['GroupBy.transform', 'GroupBy.sum + map'],
n_range=[2**k for k in range(5, 20)],
xlabel='N',
logy=True,
logx=True
)