2016-11-11 3 views
9

У меня есть панд ряд вида [0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1].Панды: флаг последовательных значений

0: indicates economic increase. 
1: indicates economic decline. 

Спад сигнализируется двумя последовательными снижается (1).

Конец рецессии сигнализируется двумя последовательными увеличениями (0).

В приведенных выше наборе данных у меня есть два спадов, начинается с индексом 3, конца с индексом 5 и начать на индекс 8 конца с индексом 11.

Я нахожусь в потерянном для того, как подойти к этому с пандами. Я хотел бы определить индекс начала и окончания рецессии. Любая помощь будет оценена.

Вот моя попытка python в soln.

np_decline = np.array([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1]) 
recession_start_flag = 0 
recession_end_flag = 0 
recession_start = [] 
recession_end = [] 

for i in range(len(np_decline) - 1): 
    if recession_start_flag == 0 and np_decline[i] == 1 and np_decline[i + 1] == 1: 
     recession_start.append(i) 
     recession_start_flag = 1 
    if recession_start_flag == 1 and np_decline[i] == 0 and np_decline[i + 1] == 0: 
     recession_end.append(i - 1) 
     recession_start_flag = 0 

print(recession_start) 
print(recession_end) 

Является ли более ориентированный на панд подход? Leon

ответ

3

Начало бега 1 удовлетворяет условию

x_prev = x.shift(1) 
x_next = x.shift(-1) 
((x_prev != 1) & (x == 1) & (x_next == 1)) 

То есть, значение в начале запуска равен 1, а предыдущее значение не равно 1, а следующее значение равно 1. Аналогично, конец пробега удовлетворяет условию

((x == 1) & (x_next == 0) & (x_next2 == 0)) 

Поскольку значение в конце прогона равно 1, а следующие два значения равны 0. Мы можем найти индексы, где эти условия будут выполнятся с помощью np.flatnonzero:

import numpy as np 
import pandas as pd 

x = pd.Series([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1]) 
x_prev = x.shift(1) 
x_next = x.shift(-1) 
x_next2 = x.shift(-2) 
df = pd.DataFrame(
    dict(start = np.flatnonzero((x_prev != 1) & (x == 1) & (x_next == 1)), 
     end = np.flatnonzero((x == 1) & (x_next == 0) & (x_next2 == 0)))) 
print(df[['start', 'end']]) 

дает

start end 
0  3 5 
1  8 11 
4

Вы можете использовать shift:

df = pd.DataFrame([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1], columns=['signal']) 
df_prev = df.shift(1)['signal'] 
df_next = df.shift(-1)['signal'] 
df_next2 = df.shift(-2)['signal'] 
df.loc[(df_prev != 1) & (df['signal'] == 1) & (df_next == 1), 'start'] = 1 
df.loc[(df['signal'] != 0) & (df_next == 0) & (df_next2 == 0), 'end'] = 1 
df.fillna(0, inplace=True) 
df = df.astype(int) 

    signal start end 
0  0  0 0 
1  1  0 0 
2  0  0 0 
3  1  1 0 
4  1  0 0 
5  1  0 1 
6  0  0 0 
7  0  0 0 
8  1  1 0 
9  1  0 0 
10  0  0 0 
11  1  0 1 
12  0  0 0 
13  0  0 0 
14  1  0 0 
+1

возможно только '.fillna' с 0, чтобы сделать его аккуратным и опрятным. –

+0

@ juanpa.arrivillaga спасибо, обновлено –

4

использование rolling(2)

s = pd.Series([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1]) 

Я вычитать .5 так rolling сумма 1 когда спад начинается и -1, когда он останавливается.

s2 = s.sub(.5).rolling(2).sum() 

поскольку оба 1 и -1 оценки для True я могу замаскировать качению сигнал, чтобы просто начать и остановки и ffill. Получите значения истинности, когда они положительны или отрицательны с gt(0).

pd.concat([s, s2.mask(~s2.astype(bool)).ffill().gt(0)], axis=1, keys=['signal', 'isRec']) 

enter image description here

+0

Привет @piRSquared. Как я могу внести поправки в то, что вы сделали за два столбца «Начало рецессии и конец рецессии». Если старт рецессии будет истинным, если его рецессия начнется еще недействительно и, конечно же, конец рецессии, если рецессия закончила True else False. –

4

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

# Boolean indexers for recession start and stops. 
rec_start = (df['signal'] == 1) & (df['signal'].shift(-1) == 1) 
rec_end = (df['signal'] == 0) & (df['signal'].shift(-1) == 0) 

# Mark the recession start/stops as True/False. 
df.loc[rec_start, 'recession'] = True 
df.loc[rec_end, 'recession'] = False 

# Forward fill the recession column with the last known Boolean. 
# Fill any NaN's as False (i.e. locations before the first start/stop). 
df['recession'] = df['recession'].ffill().fillna(False) 

Полученный выход:

signal recession 
0  0  False 
1  1  False 
2  0  False 
3  1  True 
4  1  True 
5  1  True 
6  0  False 
7  0  False 
8  1  True 
9  1  True 
10  0  True 
11  1  True 
12  0  False 
13  0  False 
14  1  False 
Смежные вопросы