#python #pandas #dataframe #pandas-groupby
#python #pandas #фрейм данных #pandas-groupby
Вопрос:
Я довольно новичок в Pandas, и это также мой первый актуальный вопрос Stackoverflow, поэтому, пожалуйста, потерпите меня.
Я преобразую фрейм данных с помощью мультииндекса. Я должен вычислить движущуюся сумму из пяти наблюдений в каждом и выполнить ее по центру. Я сделал это при использовании groupby, так что скользящая сумма вычисляется внутри каждой группы, которая сгруппирована по полу, возрасту и типу. Однако это означает, что первая и последние две строки в каждой группе равны NaN . Я хочу, чтобы первые два значения NaN были равны третьему, а последние два были равны третьему последнему.
Это исходный фрейм данных
Gender Type Age Value
1 'f' A 1 654
2 'f' A 2 665
3 'f' A 3 684
4 'f' A 4 688
5 'f' A 5 651
6 'f' A 6 650
7 'f' A 7 698
8 'f' A 8 689
9 'f' A 9 648
10 'f' A 10 654
11 'f' B 1 623
12 'f' B 2 620
13 'f' B 3 623
14 'f' B 4 653
15 'f' B 5 653
16 'f' B 6 642
17 'f' B 7 632
18 'f' B 8 632
19 'f' B 9 644
20 'f' B 10 654
21 'm' A 1 623
22 'm' A 2 624
23 'm' A 3 600
24 'm' A 4 642
25 'm' A 5 622
26 'm' A 6 623
27 'm' A 7 633
28 'm' A 8 635
29 'm' A 9 653
30 'm' A 10 623
31 'm' B 1 623
32 'm' B 2 632
33 'm' B 3 632
34 'm' B 4 683
35 'm' B 5 652
36 'm' B 6 655
37 'm' B 7 691
38 'm' B 8 684
39 'm' B 9 645
40 'm' B 10 624
Это код, который я использую для вычисления скользящей суммы.
df=df.reset_index().set_index(['Age'])
df=df.groupby(['Gender','Type'])['Value'].rolling(window=5,center=True).sum().reset_index()
Это вычисляет это:
Gender Type Age Value
1 'f' A 1 NaN
2 'f' A 2 NaN
3 'f' A 3 3342
4 'f' A 4 3338
5 'f' A 5 3371
6 'f' A 6 3376
7 'f' A 7 3336
8 'f' A 8 3339
9 'f' A 9 NaN
10 'f' A 10 NaN
11 'f' B 1 NaN
12 'f' B 2 NaN
13 'f' B 3 3172
14 'f' B 4 3191
15 'f' B 5 3203
16 'f' B 6 3212
17 'f' B 7 3203
18 'f' B 8 3204
19 'f' B 9 NaN
20 'f' B 10 NaN
21 'm' A 1 NaN
22 'm' A 2 NaN
23 'm' A 3 x1
24 'm' A 4 x2
25 'm' A 5 x3
26 'm' A 6 x4
27 'm' A 7 x5
28 'm' A 8 x7
29 'm' A 9 NaN
30 'm' A 10 NaN
31 'm' B 1 NaN
32 'm' B 2 NaN
33 'm' B 3 x8
34 'm' B 4 x9
35 'm' B 5 x10
36 'm' B 6 x11
37 'm' B 7 x12
38 'm' B 8 x13
39 'm' B 9 NaN
40 'm' B 10 NaN
X — это просто замена скользящих сумм.
Теперь моя проблема. Я хочу заменить значения NaN определенными ячейками в каждой группе. В частности, скользящая сумма за 1 и 2 года в каждой группе должна быть равна сумме за 3 года. Поскольку строка за 3 года также может быть NaN из-за отсутствия возможности вычисления, я не могу использовать код, который просто экстраполирует вперед и назад bfill или hfill . Если 3-летняя строка равна NaN, я хочу, чтобы в течение 1 года и 2 года также входили в группу.
Итак, следующий результат: хочу, я хочу:
Gender Type Age Value
1 'f' A 1 3342
2 'f' A 2 3342
3 'f' A 3 3342
4 'f' A 4 3338
5 'f' A 5 3371
6 'f' A 6 3376
7 'f' A 7 3336
8 'f' A 8 3339
9 'f' A 9 3339
10 'f' A 10 3339
11 'f' B 1 3172
12 'f' B 2 3172
13 'f' B 3 3172
14 'f' B 4 3191
15 'f' B 5 3203
16 'f' B 6 3212
17 'f' B 7 3203
18 'f' B 8 3204
19 'f' B 9 3204
20 'f' B 10 3204
21 'm' A 1 x1
22 'm' A 2 x1
23 'm' A 3 x1
24 'm' A 4 x2
25 'm' A 5 x3
26 'm' A 6 x4
27 'm' A 7 x5
28 'm' A 8 x7
29 'm' A 9 x7
30 'm' A 10 x7
31 'm' B 1 x8
32 'm' B 2 x8
33 'm' B 3 x8
34 'm' B 4 x9
35 'm' B 5 x10
36 'm' B 6 x11
37 'm' B 7 x12
38 'm' B 8 x13
39 'm' B 9 x13
40 'm' B 10 x13
Я действительно надеюсь, что один из вас мог бы мне помочь. Заранее спасибо.
Комментарии:
1. не уверен, что я понимаю, какого результата вы ожидаете, если 3-й год равен NaN .. можете ли вы объяснить немного больше?
2. Извините, я понимаю, почему мое письмо вас смутило. Но скажите, что исходные данные NaN до 6 года в группе, зависящей от типа и пола. Следовательно, год 3 после скользящей суммы также будет NaN в этой группе. Но 4-й год этого не сделал. Если я просто использую bfill, то год 1-3 будет равен году 4. Я этого не хочу. Я хочу, чтобы год 1 и 2 были равны году 3. Таким образом, в этом случае год 1 2 также должен быть NaN, как и год 3.
Ответ №1:
После первоначального groupby
rolling.sum
groupby.transform
использования попробуйте с клиентом def
:
Настройка
Сделайте год 3 NaN
для первой группы для тестирования
df.loc[2, 'Value'] = np.nan
print(df)
Gender Type Age Value
0 'f' A 1 NaN
1 'f' A 2 NaN
2 'f' A 3 NaN
3 'f' A 4 3338.0
4 'f' A 5 3371.0
5 'f' A 6 3376.0
6 'f' A 7 3336.0
7 'f' A 8 3339.0
8 'f' A 9 NaN
9 'f' A 10 NaN
10 'f' B 1 NaN
...
Решение
def custom_rolling_fillna(arr):
arr.iloc[:2] = arr.iloc[2]
arr.iloc[-2:] = arr.iloc[-3]
return arr
df['Value'] = df.groupby(['Gender', 'Type'])['Value'].transform(custom_rolling_fillna)
print(df)
Gender Type Age Value
0 'f' A 1 NaN
1 'f' A 2 NaN
2 'f' A 3 NaN
3 'f' A 4 3338.0
4 'f' A 5 3371.0
5 'f' A 6 3376.0
6 'f' A 7 3336.0
7 'f' A 8 3339.0
8 'f' A 9 3339.0
9 'f' A 10 3339.0
10 'f' B 1 3172.0
...
Альтернативно, вы могли бы сделать это за один шаг, используя:
def custom_rolling_fillna(arr):
rolling = arr.rolling(window=5,center=True).sum()
rolling.iloc[:2] = arr.iloc[2]
rolling.iloc[-2:] = arr.iloc[-3]
return rolling
df['Value'] = df.groupby(['Gender', 'Type'])['Value'].transform(custom_rolling_fillna)
Комментарии:
1.
As 3 year row might also be NaN due to not meing computable, I can't use a code that just extrapolates forward and backwards a bfil
2. Спасибо за вашу помощь. Но это работает не совсем так, как хотелось, поскольку диапазон возраста может варьироваться в пределах каждой группы. В моем точном случае мне нужно 3-летнее значение для 1 и 2 года в каждой группе, и я хочу 108-летнее значение для 109 и 110 лет в каждой группе. Я предполагаю, что вы все еще можете использовать вариант функции custom_rolling_fillna, но используя loc вместо iloc . Но как именно?