#python #pandas #filter #pandas-groupby
Вопрос:
У меня есть приведенный ниже фрейм данных:
ID Start End Variance
1 100000 120000 20000
1 1 0 -1
1 7815.58 7815.58 0
1 5261 5261 0
1 138783.2 89969.37 -48813.83
1 2459.92 2459.92 0
2 101421.99 93387.45 -8034.54
2 940.04 940.04 0
2 63.06 63.06 0
2 2454.86 2454.86 0
2 830 830 0
2 299 299 0
2 14000 12000 2000
2 1500 500 1000
Я хочу создать новый столбец, Overspend Total
. Но я хочу суммировать только те значения, которые больше 0. Результирующий фрейм данных будет выглядеть следующим образом:
ID Start End Variance Overspend Total
1 100000 120000 20000 20000
1 1 0 -1 20000
1 7815.58 7815.58 0 20000
1 5261 5261 0 20000
1 138783.2 89969.37 -48813.83 20000
1 2459.92 2459.92 0 20000
2 101421.99 93387.45 -8034.54 3000
2 940.04 940.04 0 3000
2 63.06 63.06 0 3000
2 2454.86 2454.86 0 3000
2 830 830 0 3000
2 299 299 0 3000
2 14000 12000 2000 3000
2 1500 500 1000 3000
Я попробовал следующее
df['Overspend Variance'] = df[df['Variance'] > 0].groupby(df['ID']).transform('sum')
Но я получаю следующую ошибку:
ValueError: Wrong number of items passed 8, placement implies 1
Я знаю df['Overspend Variance'] = df['Variance'].groupby(df['ID']).transform('sum')
, что будет работать без условия, но я не могу понять, как включить его в дополнительное условие.
Ответ №1:
Мы можем использовать Series.where
для замены значений, которые не соответствуют условию, на NaN
, затем просто groupby transform
«сумма», поскольку NaN
значения по умолчанию игнорируются «суммой»:
df['Overspend Total'] = (
df['Variance'].where(df['Variance'] > 0).groupby(df['ID']).transform('sum')
)
Или явно заменить аддитивным идентификатором (0), который не повлияет на сумму:
df['Overspend Total'] = (
df['Variance'].where(df['Variance'] > 0, 0)
.groupby(df['ID']).transform('sum')
)
Или с lambda
внутренним groupby transform
:
df['Overspend Total'] = df.groupby('ID')['Variance'].transform(
lambda s: s[s > 0].sum()
)
В любом случае df
:
ID Start End Variance Overspend Total
0 1 100000.00 120000.00 20000.00 20000.0
1 1 1.00 0.00 -1.00 20000.0
2 1 7815.58 7815.58 0.00 20000.0
3 1 5261.00 5261.00 0.00 20000.0
4 1 138783.20 89969.37 -48813.83 20000.0
5 1 2459.92 2459.92 0.00 20000.0
6 2 101421.99 93387.45 -8034.54 3000.0
7 2 940.04 940.04 0.00 3000.0
8 2 63.06 63.06 0.00 3000.0
9 2 2454.86 2454.86 0.00 3000.0
10 2 830.00 830.00 0.00 3000.0
11 2 299.00 299.00 0.00 3000.0
12 2 14000.00 12000.00 2000.00 3000.0
13 2 1500.00 500.00 1000.00 3000.0
Ответ №2:
это можно сделать, отфильтровав значение меньше 0, чем group by, и переназначив
df = df.join(df[df.Variance>=0].groupby("ID")["Variance"].agg(sum), on="ID", rsuffix="total")
df.columns = ["ID", "Start", "End", "Variance", "Overspend Total"]
ID Start End Variance Overspend Total
0 1 100000.00 120000.00 20000.00 20000.0
1 1 1.00 0.00 -1.00 20000.0
2 1 7815.58 7815.58 0.00 20000.0
3 1 5261.00 5261.00 0.00 20000.0
4 1 138783.20 89969.37 -48813.83 20000.0
5 1 2459.92 2459.92 0.00 20000.0
6 2 101421.99 93387.45 -8034.54 3000.0
7 2 940.04 940.04 0.00 3000.0
8 2 63.06 63.06 0.00 3000.0
9 2 2454.86 2454.86 0.00 3000.0
10 2 830.00 830.00 0.00 3000.0
11 2 299.00 299.00 0.00 3000.0
12 2 14000.00 12000.00 2000.00 3000.0
13 2 1500.00 500.00 1000.00 3000.0