#pandas
Вопрос:
Это должно быть просто, но для завершения мне потребовалось слишком много строк:
У меня есть фрейм данных pandas, индексированный по идентификатору и году.
Для групп A и B я хочу заполнить только значения с 2022 по 2021 год (значения 2019 года следует оставить нетронутыми). См.таблицу ниже.
В конце концов это сработало, но было громоздко:
df = df.swaplevel()
# create a frame with backfilled values
dfbf = df.loc[[2021,2022]].groupby('id')['value'].bfill(limit=1).to_frame()
df = df.join(dfbf, rsuffix = '_fill')
df = df.reset_index(level = "id")
df['value'].loc[2021] = df.loc[2021][['value', 'value_fill']].sum(axis = 1)
df = df.set_index(['id'], append=True).swaplevel()
Пример:
ценность | ценность | |||||
---|---|---|---|---|---|---|
ID | год | ID | год | |||
A | 2019 | A | 2019 | |||
A | 2020 | 1 | A | 2020 | 1 | |
A | 2021 | A | 2021 | 3 | ||
A | 2022 | 3 | A | 2022 | 3 | |
B | 2019 | B | 2019 | |||
B | 2020 | 12 | B | 2020 | 12 | |
B | 2021 | B | 2021 | 11 | ||
B | 2022 | 11 | B | 2022 | 11 |
Ответ №1:
Выберите строки сначала DataFrame.loc
с помощью GroupBy.bfill
с DataFrame.update
:
df.update(df.loc[:, [2021,2022], :].groupby('id')['value'].bfill(limit=1))
print (df)
value
id year
A 2019 NaN
2020 1.0
2021 3.0
2022 3.0
B 2019 NaN
2020 12.0
2021 11.0
2022 11.0
Или используйте маску для ожидаемых строк (фильтруется с обеих сторон для повышения производительности — обрабатываются только выбранные строки, а не все строки):
#include
m = df.index.get_level_values('year').isin([2021,2022])
#exclude
#m = df.index.get_level_values('year') != 2019
df.loc[m, 'value'] = df[m].groupby('id')['value'].bfill(limit=1)
print (df)
value
id year
A 2019 NaN
2020 1.0
2021 3.0
2022 3.0
B 2019 NaN
2020 12.0
2021 11.0
2022 11.0
Ответ №2:
Вы можете просто подмножествовать значения для замены, используя loc
и условие на уровне «год», чтобы избежать 2019 года:
df.loc[df.index.get_level_values('year')!=2019] = df.groupby(level=0).bfill()
выход:
value
id year
A 2019 NaN
2020 1.0
2021 3.0
2022 3.0
B 2019 NaN
2020 12.0
2021 11.0
2022 11.0
Комментарии:
1. да, с точки зрения производительности необходим фильтр с обеих сторон, как в моем ответе.
2. @jezrael Вы имеете в виду, чтобы избежать вычисления заполнения, ненужного для 2019 года?
3. Я думаю в целом.
4. Если это действительно не нужно, я обычно предпочитаю удобочитаемость для первого кадра. Но я всегда ценю ваши проницательные ответы и комментарии, вы, кажется, освоили аспекты производительности панд 🙂
5. хммм, читаемость для add
df[m]
vsdf
менее читабельна? Я думаю, что нет. Только если передать 2 маски для 2 сторон, то согласитесь, читается хуже.