#python #pandas
Вопрос:
У меня есть фрейм данных, на котором я хочу вычислить максимальное значение за предыдущие 3 месяца. Ниже приведен фрейм данных:
VIN Year_Month Amount
V1 2012-01 196
V2 2012-01 113
V3 2012-01 177
V1 2012-02 154
V2 2012-02 129
V4 2012-02 156
V2 2012-03 100
V3 2012-03 174
V4 2012-03 127
V1 2012-04 139
V3 2012-04 194
V4 2012-04 178
Используя следующий фрагмент кода, я пытаюсь вычислить максимальное значение для каждого VIN за последние 3 месяца
df['Max_3M_Value'] = df.groupby(['VIN','Year_Month'])['Amount'].rolling(3).max().fillna(0)
Но приведенный выше код выдает ошибку:
TypeError: incompatible index of inserted column with frame index
Результирующий кадр данных, который я ищу, выглядит так :
VIN Year_Month Amount Max_3M_Value
V1 2012-01 196 196
V2 2012-01 113 129
V3 2012-01 177 194
V1 2012-02 154 196
V2 2012-02 129 129
V4 2012-02 156 178
V2 2012-03 100 129
V3 2012-03 174 194
V4 2012-03 127 178
V1 2012-04 139 196
V3 2012-04 194 194
V4 2012-04 178 178
Я должен вычислить максимальное значение, используя rolling
только .Я знаю , что мы можем решить эту проблему с помощью pd.pivot_table()
, но в этом нет необходимости.
Чего мне здесь не хватает.
Ответ №1:
Вы можете избежать ошибки, используя только возвращаемые значения, но вы должны убедиться, что порядок строк не меняется во время операции:
df['Max_3M_Value'] = df.groupby(['VIN','Year_Month'])['Amount'].rolling(3).max().fillna(0).values
В приведенном вами примере ваши группы слишком малы (по 1 элементу в каждой), чтобы можно было применить прокрутку с окном 3:
>>> df.groupby(['VIN','Year_Month'])['Amount'].count()
VIN Year_Month
V1 2012-01 1
2012-02 1
2012-04 1
V2 2012-01 1
2012-02 1
2012-03 1
V3 2012-01 1
2012-03 1
2012-04 1
V4 2012-02 1
2012-03 1
2012-04 1
Я считаю, что на самом деле вы хотите группироваться только по «VIN»:
df['Max_3M_Value'] = df.groupby('VIN')['Amount'].transform(lambda s: s.rolling(3, min_periods=1).max())
выход:
VIN Year_Month Amount Max_3M_Value
0 V1 2012-01 196 196
1 V2 2012-01 113 113
2 V3 2012-01 177 177
3 V1 2012-02 154 196
4 V2 2012-02 129 129
5 V4 2012-02 156 156
6 V2 2012-03 100 129
7 V3 2012-03 174 177
8 V4 2012-03 127 156
9 V1 2012-04 139 196
10 V3 2012-04 194 194
11 V4 2012-04 178 178
выход для скользящего окна 2:
VIN Year_Month Amount Max_3M_Value
0 V1 2012-01 196 196
1 V2 2012-01 113 113
2 V3 2012-01 177 177
3 V1 2012-02 154 196
4 V2 2012-02 129 129
5 V4 2012-02 156 156
6 V2 2012-03 100 129
7 V3 2012-03 174 177
8 V4 2012-03 127 156
9 V1 2012-04 139 154
10 V3 2012-04 194 194
11 V4 2012-04 178 178
Если на самом деле вам нужно простое максимальное значение для каждой группы, вы можете просто сделать:
>>> df['Max_3M_Value'] = df.groupby('VIN')['Amount'].transform('max')
>>> df
VIN Year_Month Amount Max_3M_Value
0 V1 2012-01 196 196
1 V2 2012-01 113 129
2 V3 2012-01 177 194
3 V1 2012-02 154 196
4 V2 2012-02 129 129
5 V4 2012-02 156 178
6 V2 2012-03 100 129
7 V3 2012-03 174 194
8 V4 2012-03 127 178
9 V1 2012-04 139 196
10 V3 2012-04 194 194
11 V4 2012-04 178 178
Комментарии:
1. Хорошее объяснение. 1
2. @mozway: Что, если мы воспользуемся
rolling(2,min_periods=1)
? Все еще ваш код будет работать? Кстати, я получаюV1
и т.V2
Д. В Max_3M_Value.3. Я заменил свой ответ альтернативой, которая должна сработать в любом случае. Дайте мне знать…
4. @mozway. Ваши результаты не соответствуют ожиданиям операции.
5. @Corralien Я думаю, что вывод OP неверен. То, что описывает текущий выход, — это простой максимум для каждой группы ( не скользящий максимум), что не представляет никакой проблемы. Я добавляю эту возможность в свой ответ.
Ответ №2:
Попробуй:
>>> df['Max_3M_Value'] = df.groupby('VIN')['Amount']
.rolling(3).max().bfill().astype(int)
.reset_index(level=0, drop=True)
>>> df
VIN Year_Month Amount Max_3M_Value
0 V1 2012-01 196 196
1 V2 2012-01 113 129
2 V3 2012-01 177 194
3 V1 2012-02 154 196
4 V2 2012-02 129 129
5 V4 2012-02 156 178
6 V2 2012-03 100 129
7 V3 2012-03 174 194
8 V4 2012-03 127 178
9 V1 2012-04 139 196
10 V3 2012-04 194 194
11 V4 2012-04 178 178
Комментарии:
1. Это не сработает, если вы попытаетесь снова назначить исходный df (NB. Я не стал понижать голос)
2. @pythondumb, я обновил свой ответ. Не могли бы вы проверить, что это то, чего вы ожидаете, пожалуйста?