Как построить окно через положительные и отрицательные диапазоны чисел в столбце фрейма данных? - PullRequest
1 голос
/ 26 мая 2020

Я хотел бы иметь среднее значение и максимальное значение в каждом положительном и отрицательном диапазоне. Из примеров данных ниже:

import pandas as pd
test_list = [-1, -2, -3, -2, -1, 1, 2, 3, 2, 1, -1, -4, -5, 2 ,4 ,7  ]
df_test = pd.DataFrame(test_list, columns=['value'])

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

    value
0      -1
1      -2
2      -3
3      -2
4      -1
5       1
6       2
7       3
8       2
9       1
10     -1
11     -4
12     -5
13      2
14      4
15      7

Я хотел бы иметь что-то вроде этого:

AVG1 = [-1, -2, -3, -2, -1] / 5 = - 1.8
Max1 = -3
AVG2 = [1, 2, 3, 2, 1] / 5 = 1.8 
Max2 = 3
AVG3 = [2 ,4 ,7] / 3 =  4.3
Max3 = 7

Если решение нужен новый столбец или новый фрейм данных, это нормально для меня.

Я знаю, что могу использовать .mean, как здесь pandas получить среднее / среднее значение столбца с круглым значением Но это решение дает среднее значение от всех положительных и всех отрицательных значений.

Как построить какое-то окно, в котором я могу вычислять среднее значение из первой отрицательной группы, затем из второй положительной группы и т.д. С уважением

1 Ответ

2 голосов
/ 26 мая 2020

Вы можете создать серию по np.sign для различий guish положительных и отрицательных групп со сравнением сдвинутых значений с кумулятивной суммой для групп, а затем агрегировать mean и max:

s = np.sign(df_test['value'])
g = s.ne(s.shift()).cumsum()
df = df_test.groupby(g)['value'].agg(['mean','max'])
print (df)
           mean  max
value               
1     -1.800000   -1
2      1.800000    3
3     -3.333333   -1
4      4.333333    7

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

Для поиска крайностей локали используется решение из этот ответ :

test_list = [-1, -2, -3, -2, -1, 1, 2, 3, 2, 1, -1, -4, -5, 2 ,4 ,7  ]
df_test = pd.DataFrame(test_list, columns=['value'])

from scipy.signal import argrelextrema

#https://stackoverflow.com/a/50836425
n=2 # number of points to be checked before and after 
# Find local peaks
df_test['min'] = df_test.iloc[argrelextrema(df_test.value.values, np.less_equal, order=n)[0]]['value']
df_test['max'] = df_test.iloc[argrelextrema(df_test.value.values, np.greater_equal, order=n)[0]]['value']

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

s = np.sign(df_test['value'])
g = s.ne(s.shift()).cumsum()

df_test[['min1','max1']] = df_test[['min','max']].notna().astype(int).iloc[::-1].groupby(g[::-1]).cumsum()
df_test['min1'] = df_test['min1'].where(s.eq(-1) & df_test['min1'].ne(0))
df_test['max1'] = df_test['max1'].where(s.eq(1) & df_test['max1'].ne(0))

df_test['g'] = g
print (df_test)
    value  min  max  min1  max1  g
0      -1  NaN -1.0   1.0   NaN  1
1      -2  NaN  NaN   1.0   NaN  1
2      -3 -3.0  NaN   1.0   NaN  1
3      -2  NaN  NaN   NaN   NaN  1
4      -1  NaN  NaN   NaN   NaN  1
5       1  NaN  NaN   NaN   1.0  2
6       2  NaN  NaN   NaN   1.0  2
7       3  NaN  3.0   NaN   1.0  2
8       2  NaN  NaN   NaN   NaN  2
9       1  NaN  NaN   NaN   NaN  2
10     -1  NaN  NaN   1.0   NaN  3
11     -4  NaN  NaN   1.0   NaN  3
12     -5 -5.0  NaN   1.0   NaN  3
13      2  NaN  NaN   NaN   1.0  4
14      4  NaN  NaN   NaN   1.0  4
15      7  NaN  7.0   NaN   1.0  4

Таким образом, можно отдельно агрегировать последние 3 значения для каждой группы с помощью лямбда-функции и mean, строки с пропущенными значениями в min1 или max1 удаляются по умолчанию в groupby :

df1 = df_test.groupby(['g','min1'])['value'].agg(lambda x: x.tail(3).mean())
print (df1)
g  min1
1  1.0    -2.000000
3  1.0    -3.333333
Name: value, dtype: float64

df2 = df_test.groupby(['g','max1'])['value'].agg(lambda x: x.tail(3).mean())
print (df2)
g  max1
2  1.0     2.000000
4  1.0     4.333333
Name: value, dtype: float64
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...