Что такое чистый метод pythonic для поиска набора последовательных постоянных значений в pd.dataframe?

#python #pandas #datetime

#python #панды #дата и время

Вопрос:

Я ищу метод для обозначения последовательных постоянных значений (например, n), которые последовательно являются постоянными, в pd.dataframe (например, df).

Я написал некоторый код, с помощью которого значение будет помечено, если его различия с n / 2 следующей и n / 2 предыдущей точкой данных равны нулю.

 n = 5         # the minimum number of sequential constant values  

#to create a adatframe example
df=pd.DataFrame(np.random.randn(25), index=pd.date_range(start='2010-1-1',end='2010-1-2',freq='H'), columns=['value'])

#to modify the dataframe to have several sets of constant values
df[1:10]=23
df[20:26]=10
df[15:17]=15
for i in np.arange(1, int(n/2)):
    # to calcualte the difference between value and ith previous values
    df_diff['delta_'   str(i)] = (df['value'].diff(periods=i)).abs()
    # to calcualte the difference between value and ith next values
    df_diff['delta_'   str(-i)] = (df['value'].diff(periods=-i)).abs()

# to filter the results (e.g. as a boolean)
result_1 = (df_diff[:] <= 0).all(axis=1)
result_2 = (df_diff[:] <= 0).any(axis=1)
 

Result_1 и results_2 в этом примере не дают правильного ответа.

Чего я ожидаю, так это:

 2010-01-01 00:00:00    False
2010-01-01 01:00:00     True
2010-01-01 02:00:00     True
2010-01-01 03:00:00     True
2010-01-01 04:00:00     True
2010-01-01 05:00:00     True
2010-01-01 06:00:00     True
2010-01-01 07:00:00     True
2010-01-01 08:00:00     True
2010-01-01 09:00:00     True
2010-01-01 10:00:00    False
2010-01-01 11:00:00    False
2010-01-01 12:00:00    False
2010-01-01 13:00:00    False
2010-01-01 14:00:00    False
2010-01-01 15:00:00    False
2010-01-01 16:00:00    False
2010-01-01 17:00:00    False
2010-01-01 18:00:00    False
2010-01-01 19:00:00    False
2010-01-01 20:00:00     True
2010-01-01 21:00:00     True
2010-01-01 22:00:00     True
2010-01-01 23:00:00     True
2010-01-02 00:00:00     True
 

Ответ №1:

IIUC, используйте DataFrame.groupby с группировкой Series.diff , .ne(0) тогда .cumsum :

 df.groupby(df.value.diff().ne(0).cumsum())['value'].transform('size').ge(n)
 

[out]

 2010-01-01 00:00:00    False
2010-01-01 01:00:00     True
2010-01-01 02:00:00     True
2010-01-01 03:00:00     True
2010-01-01 04:00:00     True
2010-01-01 05:00:00     True
2010-01-01 06:00:00     True
2010-01-01 07:00:00     True
2010-01-01 08:00:00     True
2010-01-01 09:00:00     True
2010-01-01 10:00:00    False
2010-01-01 11:00:00    False
2010-01-01 12:00:00    False
2010-01-01 13:00:00    False
2010-01-01 14:00:00    False
2010-01-01 15:00:00    False
2010-01-01 16:00:00    False
2010-01-01 17:00:00    False
2010-01-01 18:00:00    False
2010-01-01 19:00:00    False
2010-01-01 20:00:00     True
2010-01-01 21:00:00     True
2010-01-01 22:00:00     True
2010-01-01 23:00:00     True
2010-01-02 00:00:00     True
Freq: H, Name: value, dtype: bool
 

Объяснение

Серия, по которой мы группируем, будет представлять собой непрерывные группы равных значений:

 s = df.value.diff().ne(0).cumsum()

2010-01-01 00:00:00     1
2010-01-01 01:00:00     2
2010-01-01 02:00:00     2
2010-01-01 03:00:00     2
2010-01-01 04:00:00     2
2010-01-01 05:00:00     2
2010-01-01 06:00:00     2
2010-01-01 07:00:00     2
2010-01-01 08:00:00     2
2010-01-01 09:00:00     2
2010-01-01 10:00:00     3
2010-01-01 11:00:00     4
2010-01-01 12:00:00     5
2010-01-01 13:00:00     6
2010-01-01 14:00:00     7
2010-01-01 15:00:00     8
2010-01-01 16:00:00     8
2010-01-01 17:00:00     9
2010-01-01 18:00:00    10
2010-01-01 19:00:00    11
2010-01-01 20:00:00    12
2010-01-01 21:00:00    12
2010-01-01 22:00:00    12
2010-01-01 23:00:00    12
2010-01-02 00:00:00    12
Freq: H, Name: value, dtype: int32
 

Когда вы группируете по этим «идентификаторам групп», используя transform для возврата объекта той же формы, что и оригинал DataFrame , агрегируя до «размера», вы получаете:

 s.groupby(s).transform('size')

2010-01-01 00:00:00    1
2010-01-01 01:00:00    9
2010-01-01 02:00:00    9
2010-01-01 03:00:00    9
2010-01-01 04:00:00    9
2010-01-01 05:00:00    9
2010-01-01 06:00:00    9
2010-01-01 07:00:00    9
2010-01-01 08:00:00    9
2010-01-01 09:00:00    9
2010-01-01 10:00:00    1
2010-01-01 11:00:00    1
2010-01-01 12:00:00    1
2010-01-01 13:00:00    1
2010-01-01 14:00:00    1
2010-01-01 15:00:00    2
2010-01-01 16:00:00    2
2010-01-01 17:00:00    1
2010-01-01 18:00:00    1
2010-01-01 19:00:00    1
2010-01-01 20:00:00    5
2010-01-01 21:00:00    5
2010-01-01 22:00:00    5
2010-01-01 23:00:00    5
2010-01-02 00:00:00    5
Freq: H, Name: value, dtype: int64
 

Отсюда это простое Series.ge >= сравнение () с вашим значением n