pandas временных рядов, разбивающихся на множество и принимающих среднее - PullRequest
0 голосов
/ 16 января 2020

У меня есть следующий pandas dataframe:

SEC POS DATA
1   1   4
2   1   4
3   1   5
4   1   5
5   2   2
6   3   4
7   3   2
8   4   2
9   4   2
10  1   8
11  1   6
12  2   5
13  2   5
14  2   4
15  2   6
16  3   2
17  4   1

Теперь я хочу узнать среднее значение DATA и первое значение SE C для каждого блока столбца POS. Вот так:

SEC POS DATA
1   1   4.5
5   2   2
6   3   3
8   4   2
10  1   7
12  2   5
16  3   2
17  4   1

Кроме того, я хочу вычесть значение DATA POS = 4 из его 3 предыдущих значений DATA, поэтому, где POS = [1,2,3].

Получив следующее:

SEC POS DATA
1   1   2.5
5   2   0
6   3   1
8   4   2
10  1   6
12  2   4
16  3   1
17  4   1

Я понял, как это сделать, разделив фрейм данных на множество разных фреймов, используя forl oop. взяв среднее, а затем вычесть для других кадров данных. Однако это очень медленно, поэтому мне интересно, есть ли более быстрый способ сделать это, кто-нибудь, кто может помочь?

Спасибо!

Ответы [ 2 ]

1 голос
/ 16 января 2020

Другое решение:

diff_to_previous = df.POS != df.POS.shift(1)
df = df.groupby(diff_to_previous.cumsum(), as_index=False).agg({'SEC': 'first', 'POS':'first', 'DATA':'mean'})
df['tmp'] = (df['POS'] == 4).astype(int).shift(fill_value=0).cumsum()
df['DATA'] = df.groupby('tmp')['DATA'].transform(lambda x: [*(x[x.index[:-1]] - x[x.index[-1]]), x[x.index[-1]]] )
df = df.drop(columns='tmp')

print(df)

Отпечатки:

   SEC  POS  DATA
0    1    1   2.5
1    5    2   0.0
2    6    3   1.0
3    8    4   2.0
4   10    1   6.0
5   12    2   4.0
6   16    3   1.0
7   17    4   1.0
1 голос
/ 16 января 2020

Для вашей первой проблемы мы можем использовать:

grps = df['POS'].ne(df['POS'].shift()).cumsum()

dfg = df.groupby(grps).agg(
    POS=('POS', 'min'),
    SEC=('SEC', 'min'),
    DATA=('DATA', 'mean')
).reset_index(drop=True)

   POS  SEC  DATA
0  1    1    4.5 
1  2    5    2.0 
2  3    6    3.0 
3  4    8    2.0 
4  1    10   7.0 
5  2    12   5.0 
6  3    16   2.0 
7  4    17   1.0 

Для вашей второй проблемы:

grps2 = dfg['POS'].lt(dfg['POS'].shift()).cumsum()

m = (
    dfg.groupby(grps2)
       .apply(lambda x: x.loc[x['POS'].isin([1,2,3]), 'DATA'] 
              - x.loc[x['POS'].eq(4), 'DATA'].iat[0])
       .droplevel(0)
)

dfg['DATA'].update(m)

   POS  SEC  DATA
0  1    1    2.5 
1  2    5    0.0 
2  3    6    1.0 
3  4    8    2.0 
4  1    10   6.0 
5  2    12   4.0 
6  3    16   1.0 
7  4    17   1.0 
...