Python pandas разница в заданных c строках в группе - PullRequest
3 голосов
/ 06 марта 2020

У меня есть pandas фрейм данных

df = pd.DataFrame({'Firm': ['Firm1','Firm1','Firm1','Firm1','Firm1','Firm1','Firm2','Firm2','Firm2','Firm2','Firm2','Firm2'],'Location' : ['Country1', 'Country1', 'Country1', 'Country2', 'Country2', 'Country2','Country1', 'Country1', 'Country1', 'Country2', 'Country2', 'Country2'], 'Currency' : ['Curr1', 'Curr2', 'Curr3', 'Curr1', 'Curr2', 'Curr3','Curr1', 'Curr2', 'Curr3', 'Curr1', 'Curr2', 'Curr3'], 'Value' : [100, 105, 110, 100, 95, 120, 95, 110, 115, 105, 120, 90] })

, который выглядит следующим образом:

df:

     Firm  Location Currency  Value
0   Firm1  Country1    Curr1    100
1   Firm1  Country1    Curr2    105
2   Firm1  Country1    Curr3    110
3   Firm1  Country2    Curr1    100
4   Firm1  Country2    Curr2     95
5   Firm1  Country2    Curr3    120
6   Firm2  Country1    Curr1     95
7   Firm2  Country1    Curr2    110
8   Firm2  Country1    Curr3    115
9   Firm2  Country2    Curr1    105
10  Firm2  Country2    Curr2    120
11  Firm2  Country2    Curr3     90

Теперь я хотел бы рассчитать разницу между Curr3 и Curr2 (столбца Value) для каждой группы фирм-местоположений и измените значение Curr3 в зависимости от результата. Полученный df должен выглядеть следующим образом:

     Firm  Location Currency  Value
0   Firm1  Country1    Curr1    100
1   Firm1  Country1    Curr2    105
2   Firm1  Country1    Curr3      5
3   Firm1  Country2    Curr1    100
4   Firm1  Country2    Curr2     95
5   Firm1  Country2    Curr3     25
6   Firm2  Country1    Curr1     95
7   Firm2  Country1    Curr2    110
8   Firm2  Country1    Curr3      5
9   Firm2  Country2    Curr1    105
10  Firm2  Country2    Curr2    120
11  Firm2  Country2    Curr3    -30

Я попытался использовать .groupby и .apply, что дает мне результаты, однако я хотел бы выполнить преобразование в исходном кадре данных.

df2 = df.groupby(['Firm','Location']).apply(lambda g: g[g.Currency == 'Curr3'].Value.values[0] - g[g.Currency == 'Curr2'].Value.values[0])

df2:

Firm    Location    0
Firm1   Country1    5
Firm1   Country2    25
Firm2   Country1    5
Firm2   Country2    -30

Я не могу понять, как сделать это на месте в оригинальном df. Я также попытался сделать то же самое, используя .transform, однако он создает ошибку:

df2 = df.groupby(['Firm','Location']).transform(lambda g: g[g.Currency == 'Curr3'].Value.values[0] - g[g.Currency == 'Curr2'].Value.values[0])

AttributeError: ("'Series' object has no attribute 'Currency'", 'occurred at index Currency')

---- Обновление на основе решения Эрфана:

newvals = (
    df.where(df['Currency'].isin(['Curr2', 'Curr3']))
      .groupby(['Firm', 'Location'])['Value'].diff()
)
df['Value'] = newvals.fillna(df['Value'])

Если df выглядит так (валюта не отсортирована), решение больше не работает (поскольку diff () только вычисляет разницу с предыдущим значением

    Firm    Location    Currency    Value
0   Firm1   Country1    Curr2   100
1   Firm1   Country1    Curr1   105
2   Firm1   Country1    Curr3   110
3   Firm1   Country2    Curr3   100
4   Firm1   Country2    Curr2   95
5   Firm1   Country2    Curr1   120
6   Firm2   Country1    Curr1   95
7   Firm2   Country1    Curr2   110
8   Firm2   Country1    Curr3   115
9   Firm2   Country2    Curr2   105
10  Firm2   Country2    Curr3   120
11  Firm2   Country2    Curr1   90

-> result:

    Firm    Location    Currency    Value
0   Firm1   Country1    Curr2   100.0
1   Firm1   Country1    Curr1   105.0
2   Firm1   Country1    Curr3   10.0
3   Firm1   Country2    Curr3   100.0
4   Firm1   Country2    Curr2   -5.0
5   Firm1   Country2    Curr1   120.0
6   Firm2   Country1    Curr1   95.0
7   Firm2   Country1    Curr2   110.0
8   Firm2   Country1    Curr3   5.0
9   Firm2   Country2    Curr2   105.0
10  Firm2   Country2    Curr3   15.0
11  Firm2   Country2    Curr1   90.0

Теперь уже не тот случай, когда каждый раз, когда вычисляется разница между Curr3 и Curr 2, и заменяется значение для Curr3.

1 Ответ

3 голосов
/ 06 марта 2020

Используя DataFrame.where, Series.isin, GroupBy.diff и Series.fillna:

Сначала мы конвертируем все Curr1 в NaN с where, затем группируем по Firm и Location и вычислим разницу в Value.

newvals = (
    df.where(df['Currency'].isin(['Curr2', 'Curr3']))
      .groupby(['Firm', 'Location'])['Value'].diff()
)
df['Value'] = newvals.fillna(df['Value'])
     Firm  Location Currency  Value
0   Firm1  Country1    Curr1  100.0
1   Firm1  Country1    Curr2  105.0
2   Firm1  Country1    Curr3    5.0
3   Firm1  Country2    Curr1  100.0
4   Firm1  Country2    Curr2   95.0
5   Firm1  Country2    Curr3   25.0
6   Firm2  Country1    Curr1   95.0
7   Firm2  Country1    Curr2  110.0
8   Firm2  Country1    Curr3    5.0
9   Firm2  Country2    Curr1  105.0
10  Firm2  Country2    Curr2  120.0
11  Firm2  Country2    Curr3  -30.0
...