Как создать скользящее окно в pandas с другим условием - PullRequest
3 голосов
/ 20 марта 2020

У меня есть фрейм данных с 2 столбцами

df = pd.DataFrame(np.random.randint(0,100,size=(100, 2)), columns=list('AB'))


    A   B
0   11  10
1   61  30
2   24  54
3   47  52
4   72  42
... ... ...
95  61  2
96  67  41
97  95  30
98  29  66
99  49  22
100 rows × 2 columns

Теперь я хочу создать третий столбец, который является скользящим окном max столбца 'A', НО максимум должен быть ниже, чем соответствующий значение в col 'B'. Другими словами, я хочу, чтобы значение 4 (с использованием размера окна 4) в столбце «A» было ближе к значению в столбце «B», но меньше, чем B

Так, например, в строке 3 47 52 новое значение, которое я ищу, это не 61, а 47, потому что это самое высокое значение 4, которое не превышает 52

псевдокод

df['C'] = df['A'].rolling(window=4).max()  where < df['B']

Ответы [ 3 ]

2 голосов
/ 20 марта 2020

Вы можете использовать concat + shift, чтобы создать широкий DataFrame с предыдущими значениями, что немного упрощает сложные расчеты.

Пример данных

np.random.seed(42)
df = pd.DataFrame(np.random.randint(0, 100, size=(100, 2)), columns=list('AB'))

Код

N = 4
# End slice ensures same default min_periods behavior to `.rolling`
df1 = pd.concat([df['A'].shift(i).rename(i) for i in range(N)], axis=1).iloc[N-1:]

# Remove values larger than B, then find the max of remaining.
df['C'] = df1.where(df1.lt(df.B, axis=0)).max(1)

print(df.head(15))

     A   B     C
0   51  92   NaN  # Missing b/c min_periods
1   14  71   NaN  # Missing b/c min_periods
2   60  20   NaN  # Missing b/c min_periods
3   82  86  82.0
4   74  74  60.0
5   87  99  87.0
6   23   2   NaN  # Missing b/c 82, 74, 87, 23 all > 2
7   21  52  23.0  # Max of 21, 23, 87, 74 which is < 52
8    1  87  23.0
9   29  37  29.0
10   1  63  29.0
11  59  20   1.0
12  32  75  59.0
13  57  21   1.0
14  88  48  32.0
1 голос
/ 20 марта 2020

Вы можете использовать пользовательскую функцию, чтобы .apply открывать окно. В этом случае вы можете использовать аргумент по умолчанию для передачи в столбец B.

df = pd.DataFrame(np.random.randint(0,100,size=(100, 2)), columns=('AB'))

def rollup(a, B=df.B):
    ix = a.index.max()
    b = B[ix]
    return a[a<b].max()

df['C'] = df.A.rolling(4).apply(rollup)

df
# returns:
     A   B     C
0    8  17   NaN
1   23  84   NaN
2   75  84   NaN
3   86  24  23.0
4   52  83  75.0
..  ..  ..   ...
95  38  22   NaN
96  53  48  38.0
97  45   4   NaN
98   3  92  53.0
99  91  86  53.0

Значения NaN появляются, когда в окне A нет ни одного числа меньше B или в начале серии, когда окно слишком велико для первых нескольких строк.

0 голосов
/ 20 марта 2020

Вы можете использовать where для замены значений, которые не удовлетворяют условию, на np.nan, а затем использовать rolling(window=4, min_periods=1):

In [37]: df['C'] = df['A'].where(df['A'] < df['B'], np.nan).rolling(window=4, min_periods=1).max()                                                                                            

In [38]: df                                                                                                                                                                                   
Out[38]: 
    A   B    C
0   0   1  0.0
1   1   2  1.0
2   2   3  2.0
3  10   4  2.0
4   4   5  4.0
5   5   6  5.0
6  10   7  5.0
7  10   8  5.0
8  10   9  5.0
9  10  10  NaN
...