Скользящая средняя для нескольких непостоянных условий - PullRequest
0 голосов
/ 19 мая 2019

Я надеюсь найти экспертов, которые могут помочь)

Есть такая таблица

X2         X3   X4  Y   Y1
01.02.2019  1   1   1   
02.02.2019  2   2   0   
02.02.2019  2   3   0   
02.02.2019  2   1   1   
03.02.2019  1   2   1   
04.02.2019  2   3   0   
05.02.2019  1   1   1   
06.02.2019  2   2   0   
07.02.2019  1   3   1   
08.02.2019  2   1   1   
09.02.2019  1   2   0   
10.02.2019  2   3   1   
11.02.2019  1   1   0   
12.02.2019  2   2   1   
13.02.2019  1   3   0   
14.02.2019  2   1   1   
15.02.2019  1   2   1   
16.02.2019  2   3   0   
17.02.2019  1   1   1   
18.02.2019  2   2   0

А в столбце Y1 необходимо рассчитать скользящее среднее столбца Y за последние 5 дней, но только с фильтрацией по условиям X3 и X4. Фильтр равен текущему значению столбцов для текущей строки. Например, для строки 02/04/2019 2 3 0 среднее будет равно 0, потому что для него только строка соответствует условию 02.02.2019 2 3 0

Как это сделать я не понимаю, я знаю, что это будет что-то вроде

filtered_X4 = df ['X4']. where (condition_1 & condition_2 & condition_3)

Но как самим установить условия условие_1,2,3 Я не понимаю.

Видел много примеров, когда фильтр известен, например condition_1 = df ['X2']. isin ([2, 3, 5]) но это не то, что мне нужно, потому что мои значения условий меняются со строкой

Как рассчитать среднее значение, которое я знаю

df ['Y1'] = filtered_X4.shift (1) .rolling (window = 999999, min_periods = 1) .mean ()

, но не могу настроить фильтрацию.

add1: вот результат, который я пытаюсь получить:

X2          X3  X4  Y   Y1
01.02.2019  1   1   1   NAN
02.02.2019  2   2   0   NAN
02.02.2019  2   3   0   NAN
02.02.2019  2   1   1   NAN
03.02.2019  1   2   1   NAN
04.02.2019  2   3   0   0
05.02.2019  1   1   1   1
06.02.2019  2   2   0   0
07.02.2019  1   3   1   NAN
08.02.2019  2   1   1   NAN
09.02.2019  1   2   0   NAN
10.02.2019  2   3   1   NAN
11.02.2019  1   3   0   1
12.02.2019  2   2   1   NAN
13.02.2019  1   3   0   0
14.02.2019  2   1   1   NAN
15.02.2019  2   2   1   1
16.02.2019  2   3   0   NAN
17.02.2019  1   1   1   NAN
18.02.2019  2   2   0   1

Например, чтобы вычислить среднее (Y1) этой строки:

    X2          X3  X4  Y   Y1
    04.02.2019  2   3   0   

Мне нужно взять только строки с даты с X3 = 2 и X4 = 3 и X2 с 30.01.2019 по 03.02.2019

1 Ответ

1 голос
/ 19 мая 2019

Для этого используйте .apply ()

Конвертировать дату в дату и время.

df['X2'] = pd.to_datetime(df['X2'], format='%d.%m.%Y')

print(df)

           X2 X3 X4  Y
0  2019-02-01  1  1  1
1  2019-02-02  2  2  0
2  2019-02-02  2  3  0
3  2019-02-02  2  1  1
4  2019-02-03  1  2  1
5  2019-02-04  2  3  0
6  2019-02-05  1  1  1
7  2019-02-06  2  2  0
8  2019-02-07  1  3  1
9  2019-02-08  2  1  1
10 2019-02-09  1  2  0
11 2019-02-10  2  3  1
12 2019-02-11  1  3  0
13 2019-02-12  2  2  1
14 2019-02-13  1  3  0
15 2019-02-14  2  1  1
16 2019-02-15  2  2  1
17 2019-02-16  2  3  0
18 2019-02-17  1  1  1
19 2019-02-18  2  2  0

Используя apply и lambda, создайте фильтр df.loc длязатем в каждой строке, ограничиваясь датой до предыдущих 5 дней, а также для равенства в столбцах X2 и X3, вычисляется среднее значение 'Y'.

df['Y1'] = df.apply(
    lambda x: df.loc[
        (
            (df.X2 < x.X2)
            & (df.X2 >= (x.X2 + pd.DateOffset(days=-4)))
            & (df.X3 == x.X3)
            & (df.X4 == x.X4)
        ),
        "Y",
    ].mean(),
    axis=1,
)


print(df)

           X2 X3 X4  Y   Y1
0  2019-02-01  1  1  1  NaN
1  2019-02-02  2  2  0  NaN
2  2019-02-02  2  3  0  NaN
3  2019-02-02  2  1  1  NaN
4  2019-02-03  1  2  1  NaN
5  2019-02-04  2  3  0  0.0
6  2019-02-05  1  1  1  1.0
7  2019-02-06  2  2  0  0.0
8  2019-02-07  1  3  1  NaN
9  2019-02-08  2  1  1  NaN
10 2019-02-09  1  2  0  NaN
11 2019-02-10  2  3  1  NaN
12 2019-02-11  1  3  0  1.0
13 2019-02-12  2  2  1  NaN
14 2019-02-13  1  3  0  0.0
15 2019-02-14  2  1  1  NaN
16 2019-02-15  2  2  1  1.0
17 2019-02-16  2  3  0  NaN
18 2019-02-17  1  1  1  NaN
19 2019-02-18  2  2  0  1.0

Y1 результат находится в типе float, так как np.NaNне совместим с целочисленными рядами.Если вам нужны целые числа, используйте следующий обходной путь .

col = 'Y1'

​

df[col] = df[col].fillna(-1)

df[col] = df[col].astype(int)

df[col] = df[col].astype(str)

df[col] = df[col].replace('-1', np.nan)

​

print(df)

           X2 X3 X4  Y   Y1
0  2019-02-01  1  1  1  NaN
1  2019-02-02  2  2  0  NaN
2  2019-02-02  2  3  0  NaN
3  2019-02-02  2  1  1  NaN
4  2019-02-03  1  2  1  NaN
5  2019-02-04  2  3  0    0
6  2019-02-05  1  1  1    1
7  2019-02-06  2  2  0    0
8  2019-02-07  1  3  1  NaN
9  2019-02-08  2  1  1  NaN
10 2019-02-09  1  2  0  NaN
11 2019-02-10  2  3  1  NaN
12 2019-02-11  1  3  0    1
13 2019-02-12  2  2  1  NaN
14 2019-02-13  1  3  0    0
15 2019-02-14  2  1  1  NaN
16 2019-02-15  2  2  1    1
17 2019-02-16  2  3  0  NaN
18 2019-02-17  1  1  1  NaN
19 2019-02-18  2  2  0    1

РЕДАКТИРОВАТЬ

Последующий вопрос, как применять вышеуказанное ежедневно с новыми данными, не включая старые данные:

Вам просто нужночтобы отфильтровать ваши данные по диапазону данных, который вы хотите включить.

Создать начальную дату в datetime

startdate = pd.to_datetime('2019-02-13')

Изменить функцию применения, добавив условие if:

df['Y1'] = df.apply(
    lambda x: (df.loc[
        (
            (df.X2 < x.X2)
            & (df.X2 >= (x.X2 + pd.DateOffset(days=-4)))
            & (df.X3 == x.X3)
            & (df.X4 == x.X4)
        ),
        "Y",
    ].mean()) if x[0] >= startdate else x[3]
    , axis=1
)

** Это будет работать только после первогозапустите инструкцию apply, в противном случае вы получите ошибку выхода из индекса.**

Итак, сначала запустите его без условия if, а затем запустите с условием if.

...