Найдите, является ли значение максимальным для предыдущих строк

#python #pandas

#python #панды

Вопрос:

Это мой фрейм данных:

 num val
0   77
1   78
2   78
3   79
4   80
5   81
6   79
7   83
8   85
9   86
10  87
11  88
12  89
13  90
14  91
15  90
16  92
 

Я хочу создать новый столбец bool со значениями True или False. Это зависит от того, является ли текущее значение максимальным для предыдущих 4 строк (больше, чем значения в 4 предыдущих строках).
Ожидаемый результат:

 num val is_max
0   77  NaN
1   78  NaN
2   78  NaN
3   79  NaN
4   80  True
5   81  True
6   79  False
7   83  True
8   85  True
9   86  True
10  87  True
11  88  True
12  89  True
13  90  True
14  91  True
15  90  False
16  92  True
 

Комментарии:

1. Где ваш код? Трудно помочь вам исправить ваш код без кода.

2. @L.Скоттджонсон, о дорогой друг, у меня нет решения, чтобы сделать это. Я могу сделать это некрасиво с помощью итераций (каждый может это запрограммировать, это просто), но я ожидаю элегантного способа с pandas.

3. панды. DataFrame.rolling — ваш друг.

4. @IgorK, я отредактировал свой ответ. Взгляните на него, когда получите сдачу. Смешивание типов данных в Pandas вернет object dtype или автоматически преобразует данные в float .

Ответ №1:

Я считаю, что это можно решить, оценив условие с .rolling() помощью функции для окна, над которым вы вычисляете. В целом код будет выглядеть следующим образом:

 df['is_max'] = df['val'].rolling(4).max() > df['val']
 

Поскольку ваш ожидаемый результат, по-видимому, является отрицанием того, которого я достигаю, сохраняя при этом первые 3 строки как np.nan, нам нужно сначала пропустить строки, а затем приступить к сравнению:

 df['is_max'] = np.where(df['val'].rolling(4).max().isna(),np.nan,(df['val'].rolling(4).max() > df['val']))
 

Учитывая, что в столбце с утверждением True или False есть NaN, pandas принудительно преобразует это логическое значение True / False в значения с плавающей запятой 1 и 0 (что представляет одно и то же). Независимо от выбранного вами подхода, как только вы добавите NaN s в столбец, значения True и False будут принудительно преобразованы в 1 и 0 соответственно

Комментарии:

1. Согласен, так лучше, спасибо за комментарий

2. Я бы рекомендовал проверить вывод. Я думаю, что это работает не так, как ожидалось.

3. Пожалуйста, проверьте комментарий вместе с примечанием True / False

4. @CeliusStingher Дорогой друг, спасибо тебе за помощь! Последнее, что я спрашиваю, это где использовать символ «~»? Результат требует инверсии, как и в предыдущем случае. Теперь True и False поменялись местами. Я попытался поставить ~ перед np.where, но он возвращает ошибку

5. Извините за отложенный ответ, ~ символ может использоваться для логического ряда, и в этом случае нам нужно будет определить ряд из возвращаемого массива np.where . Вам понадобится что — то вроде ~(pd.Series(np.where(...))) . Или, если вы хотите принудительно True/False , вы можете превратить их в строки с map({0:'True',1:'False'}) помощью, но это было бы нелогично, и я бы не рекомендовал это.

Ответ №2:

Используйте groupby каждые 4 строки и найдите расширяющийся максимум.

 df.val.eq(df.groupby(df.index//4).val.transform(lambda x: x.expanding().max()))
 

Комментарии:

1. умммм расширяется?, расширение займет первичное число n (номер строки), а не первичное число 4. вы можете попробовать изменить первые 77 на 999

2. Это зависит от того, является ли текущее значение максимальным для предыдущих 4 строк (больше, чем значения в 4 предыдущих строках) , и логика здесь заключается в том, чтобы использовать все 4 не все строки

3. @BENY в каких случаях это приведет к сбою, чтобы мы могли обойти это?

4. как я уже сказал, измените 77 на 999, вы увидите все False

5. @BENY спасибо за указание. Отредактировано, чтобы сгруппировать по перед приравниванием

Ответ №3:

Поскольку rolling также используется текущая строка, вам может потребоваться использовать shift или увеличить окно на единицу. Взгляните на соответствующие коды ниже:

 df['is_max'] = df.val[n:] > df.val.shift(1).rolling(n).max().dropna()
 

или

 df['is_max'] = df.val.iloc[n:].eq(df.val.rolling(n 1).max().dropna())
 

где n стоит у последних n рядов.


Выходной сигнал:

     num  val is_max
0     0   77    NaN
1     1   78    NaN
2     2   78    NaN
3     3   79    NaN
4     4   80   True
5     5   81   True
6     6   79  False
7     7   83   True
8     8   85   True
9     9   86   True
10   10   87   True
11   11   88   True
12   12   89   True
13   13   90   True
14   14   91   True
15   15   90  False
16   16   92   True
 

Обратите внимание, что выходной dtype для столбца «is_max» object вызван тем, что он имеет смешанные типы данных ( NaN и bool ), и pandas его не принимает. Панды либо преобразуют столбец dtype в object или float . Однако он также предоставляет обнуляемый боллеанский тип данных, так что вы можете принудительно использовать столбец «is_max» boolean с помощью: df.is_max.astype('boolean') .