#python #pandas #dataframe
Вопрос:
Предположим, у меня есть следующий фрейм данных:
df = pd.DataFrame({'city': ['a', 'a', 'a', 'b', 'b', 'c', 'd', 'd', 'd'],
'year': [2013, 2014, 2016, 2015, 2016, 2013, 2016, 2017, 2018],
'value': [10, 12, 16, 20, 21, 11, 15, 13, 16]})
И я хочу найти для каждого города и года, каково было процентное изменение стоимости по сравнению с предыдущим годом. Мой окончательный кадр данных будет:
city year value
a 2013 NaN
a 2014 0.20
a 2016 NaN
b 2015 NaN
b 2016 0.05
c 2013 NaN
d 2016 NaN
d 2017 -0.14
d 2018 0.23
Я попытался использовать группу в городе, а затем использовать apply, но это не сработало:
df.groupby('city').apply(lambda x: x.sort_values('year')['value'].pct_change()).reset_index()
Это не сработало, потому что я не мог получить год, а также потому, что таким образом я считал, что у меня есть все годы для всех городов, но это неправда.
ПРАВКА: Я не очень озабочен эффективностью, поэтому любое решение, которое решает проблему, действительно для меня.
Ответ №1:
Давайте попробуем лениво groupby()
, использовать pct_change
для изменений и diff
для обнаружения скачка года:
groups = df.sort_values('year').groupby(['city'])
df['pct_chg'] = (groups['value'].pct_change()
.where(groups['year'].diff()==1)
)
Выход:
city year value pct_chg
0 a 2013 10 NaN
1 a 2014 12 0.200000
2 a 2016 16 NaN
3 b 2015 20 NaN
4 b 2016 21 0.050000
5 c 2013 11 NaN
6 d 2016 15 NaN
7 d 2017 13 -0.133333
8 d 2018 16 0.230769
Комментарии:
1. Боже, как я люблю
pandas
.
Ответ №2:
Хотя ответ @Quang написан гораздо более элегантно и лаконично, я просто добавляю другой подход, использующий индексацию.
sorted_df = df.sort_values(by=['city', 'year'])
sorted_df.loc[((sorted_df.year.diff() == 1) amp;
(sorted_df.city == sorted_df.city.shift(1))), 'pct_chg'] = sorted_df.value.pct_change()
мой подход быстрее, как вы можете видеть ниже, выполняется на вашем df, но синтаксис не такой красивый.
%timeit #mine
1.44 ms ± 2.91 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit #@Quang's
2.23 ms ± 40.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)