У меня есть следующие данные
data = {
'Subject': ['3','3','3','3','3','3','3','3','3','10','10','10','10','10','10','10','10','10'],
'Day': [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9],
'Value': [19.0959, 19.2321, 19.3088, 19.2589, 19.3085, 19.0455, 19.3491, NaN, 19.1823, 25.7506, 25.8287, NaN, 26.2913, NaN, 26.1501, 25.9447, 25.9493, 25.9629]
}
который становится этим фреймом данных после pd.DataFrame(data):
Subject Day Value
0 3 1 19.0959
1 3 2 19.2321
2 3 3 19.3088
3 3 4 19.2589
4 3 5 19.3085
5 3 6 19.0455
6 3 7 19.3491
7 3 8 NaN
8 3 9 19.1823
9 10 1 25.7506
10 10 2 25.8287
11 10 3 NaN
12 10 4 26.2913
13 10 5 NaN
14 10 6 26.1501
15 10 7 25.9447
16 10 8 25.9493
17 10 9 25.9629
Я попытался интерполировать недостающие данные в столбце «Значение», но этот фрейм данных, состоящий из 3 столбцов, похоже, вызывает проблемы, связанные с тем, что данные не интерполируются должным образом внутри групп, когда задействован НАМНОГО БОЛЬШОЙ фрейм данных со многими другими субъектами.
Например:
df['Value'] = df.groupby('Subject')['Value'].transform(lambda group: group.interpolate())
работает для небольших наборов данных, подобных показанному, но всякий раз, когда я применяю один и тот же код для замены NaN интерполяцией, когда имеется 1000 разных субъектов, каждый из которых имеет значения данных по 9 дней, есть случаи для субъекта 10, когда день 5 все еще остается NaN после интерполяции. Есть какие-нибудь советы по этому поводу? Спасибо!






По умолчанию для параметра limit_direction установлено значение вперед. Это означает, что если первый элемент в серии — nan, он не будет интерполирован.
Учитывая слегка измененный фрейм данных:
>>> df
Subject Day Value
0 3 1 19.0959
1 3 2 19.2321
2 3 3 19.3088
3 3 4 19.2589
4 3 5 19.3085
5 3 6 19.0455
6 3 7 19.3491
7 3 8 NaN
8 3 9 19.1823
9 10 1 NaN
10 10 2 25.8287
11 10 3 NaN
12 10 4 26.2913
13 10 5 NaN
14 10 6 26.1501
15 10 7 25.9447
16 10 8 25.9493
17 10 9 25.9629
>>> df['Value'] = df.groupby('Subject')['Value'].transform(lambda group: group.interpolate())
>>> df
Subject Day Value
0 3 1 19.0959
1 3 2 19.2321
2 3 3 19.3088
3 3 4 19.2589
4 3 5 19.3085
5 3 6 19.0455
6 3 7 19.3491
7 3 8 19.2657
8 3 9 19.1823
9 10 1 NaN
10 10 2 25.8287
11 10 3 26.0600
12 10 4 26.2913
13 10 5 26.2207
14 10 6 26.1501
15 10 7 25.9447
16 10 8 25.9493
17 10 9 25.9629
Если мы повторим упражнение с приведенным выше фреймом данных и воспользуемся limit_direction='both', мы получим:
[...dataframe omitted...]
>>> df['Value'] = df.groupby('Subject')['Value'].transform(lambda group: group.interpolate(limit_direction='both'))
>>> df
Subject Day Value
0 3 1 19.0959
1 3 2 19.2321
2 3 3 19.3088
3 3 4 19.2589
4 3 5 19.3085
5 3 6 19.0455
6 3 7 19.3491
7 3 8 19.2657
8 3 9 19.1823
9 10 1 25.8287
10 10 2 25.8287
11 10 3 26.0600
12 10 4 26.2913
13 10 5 26.2207
14 10 6 26.1501
15 10 7 25.9447
16 10 8 25.9493
17 10 9 25.9629
Подробности см. в документации по интерполяции Pandas.
---- Дополнение ----
Был дополнительный вопрос, который намекнул на тот факт, что данные не всегда могут быть отсортированы по дням. В этом случае просто отсортируйте его перед группировкой, как показано в следующем примере (см. обратный порядок для Субъекта 10):
>>> data2 = {
... 'Subject': ['3','3','3','3','3','3','3','3','3','10','10','10','10','10','10','10','10','10'],
... 'Day': [1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 1, 3, 4, 5, 6, 7, 8, 9],
... 'Value': [19.0959, 19.2321, 19.3088, 19.2589, 19.3085, 19.0455, 19.3491, NaN, 19.1823, NaN,
25.8287, 26.0, 26.2913, NaN, 26.1501, 25.9447, 25.9493, 25.9629]
... }
>>> df2['Value'] = df2.sort_values(axis=0, by=['Subject', 'Day']).groupby('Subject')['Value'].transform(lambda group: group.interpolate(limit_direction='both'))
>>> df2
Subject Day Value
0 3 1 19.09590
1 3 2 19.23210
2 3 3 19.30880
3 3 4 19.25890
4 3 5 19.30850
5 3 6 19.04550
6 3 7 19.34910
7 3 8 19.26570
8 3 9 19.18230
9 10 2 25.91435
10 10 1 25.82870
11 10 3 26.00000
12 10 4 26.29130
13 10 5 26.22070
14 10 6 26.15010
15 10 7 25.94470
16 10 8 25.94930
17 10 9 25.96290
Почему это работает? Давайте посмотрим на следующий образец:
>>> list(df2.sort_values(axis=0, by=['Subject', 'Day']).groupby('Subject')['Value'])
[('10', 10 25.82870
9 25.91435
11 26.00000
12 26.29130
13 26.22070
14 26.15010
15 25.94470
16 25.94930
17 25.96290
Name: Value, dtype: float64), ('3', 0 19.0959
1 19.2321
2 19.3088
3 19.2589
4 19.3085
5 19.0455
6 19.3491
7 19.2657
8 19.1823
Name: Value, dtype: float64)]
Здесь мы получили приведенный выше фрейм данных, отсортированный по теме и дню. Вы видите группу по, '10' и '3', а также перед столбцом Values видите индекс исходного фрейма данных (25,82870 соответствует индексу 10 исходного фрейма данных и т. д.), который затем используется для присвоения значений обратно в исходный фрейм данных в задании df2['Value'] = выше.
Другой вопрос: поскольку вы уже сортируете большую таблицу, хотите ли вы сохранить новый отсортированный порядок и, следовательно, реализовать это немного по-другому, но это зависит от вашего конкретного варианта использования...
Это как если бы интерполяция различалась всякий раз, когда набор данных больше, несмотря на то, что интерполяция происходит через pandas.groupby. Разве в этом случае он не распознает столбец «День» как ориентир между двумя точками для интерполяции?
Это немного сложно, не видя большего набора данных. Я сомневаюсь, что здесь учитывается столбец Day, и я думаю, что ваш набор данных не так хорошо отсортирован по дням, как в образце, который вы предоставили в своем вопросе. Я также добавил этот случай в свой ответ.
Вы можете установить аргумент limit_direction на 'both' (см. документацию), чтобы гарантировать, что в столбце не останется значений NaN.
df.interpolate(method='linear', limit_direction='both', axis=0)
Когда этот фрейм данных является частью более крупного фрейма данных с тысячами других субъектов со столбцами одного и того же дня (1-9, как в примере), и я следую этому методу, это работает, но интерполируемые значения не совпадают. Например, Субъект 10, день 3 не возвращается в 26.0600. Вместо этого я получаю что-то вроде 25,8322. Почему возникает такая разница?