Найти неперекрывающиеся экземпляры (5-дневные складские запасы) продукта скользящего окна, которые соответствуют условию - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть временной ряд цены закрытия Amazon с 31 декабря 2009 года по настоящее время.

Я пытаюсь найти количество случаев, когда 5-дневная доходность Amzn падает более чем на 15%

Date          Open         High        Low        Close      Adj Close  Volume
2009-12-30  138.399994  138.399994  135.279999  136.490005  136.490005  6913200
2009-12-31  137.089996  137.279999  134.520004  134.520004  134.520004  4523000



## to get the 1-day returns 
df['returns'] =  df['Close'] / df['Close'].shift(1) 

## to get the rolling 5-day performance 
df['roll']= pd.rolling_apply(df.returns,5,lambda x : x.prod()) 


## filter returns -15% or more 
df2 = df[df['roll']<.85] 

Хотя приведенное выше выводит таблицу строк, где 5-дневная доходность составляет -15% или более, выходные данные df2 имеют перекрывающиеся 5-дневные окна.

1) Как вывести в список скользящее 5-дневное окно в виде столбца во фрейме данных => например: ['2009-12-30', 2009-12-31 ',' 2010-1 -1 ',' 2010-1-2 ',' 2010-1-3 ']

2) Как я могу удалить перекрывающиеся периоды в df2. Если в 5-дневном окне есть какие-либо дни, перекрывающиеся с другим рядом, оставьте только 1 ряд.

1 Ответ

0 голосов
/ 09 ноября 2018

Я не уверен на 100%, что вы имеете в виду в вопросе 1, но если вы хотите извлечь все даты из индекса фрейма данных и поместить их в список, вы можете использовать list(df.index). Если вы имели в виду, что вы хотели бы иметь столбец, содержащий даты, используемые в каждом 5-дневном скользящем окне, то это, скорее всего, будет нетривиально и немного странно. Панды не позволят вам просто посчитать это с помощью броска. Однако вот рабочее решение

def find_dates(df, center=False):

    dates = df.index.values
    dates_list = np.zeros((dates.shape[0],5), dtype=object)
    if center:
        for i,r in enumerate([2,1,0,-1,-2]):
            dates_list[:,i]=np.roll(dates,r)
            nul_dates_numbers = [0,1,len(dates)-1,len(dates)-2]

    else:
        for i,r in enumerate([4,3,2,1,0]):
            dates_list[:,i]=np.roll(dates,r)
            nul_dates_numbers = [0,1,2,3]

    dates_list = [list(d) if j not in nul_dates_numbers else None for j,d in enumerate(dates_list)]
    return dates_list


# make a quick dataframe
index_leters = 'a b c d e f g h i j'
indexes = index_leters.split(' ')
df = pd.DataFrame({'B': list(np.arange(len(indexes)))}, index=indexes)

center = False # can set to False
#apply rolling function    
df['roll']= pd.rolling_apply(df.B,5,lambda x : x.prod(), center=center) 

# extract index windows (will work on dates)
df['dates'] = find_dates(df, center=center)

2) Предполагая, что у вас есть данные для каждой даты, тогда простой способ удаления перекрывающихся периодов состоит в том, чтобы просто разрезать фрейм данных, чтобы сохранить только каждые 5 строк

## to get the rolling 5-day performance 
df['roll']= pd.rolling_apply(df.returns,5,lambda x : x.prod())
df_nonoverlapping = df[::5]

Также, если вы хотите, чтобы дата была назначена каждому окну в качестве среднего элемента в вашем окне. т.е. в окне ['2009-12-30',2009-12-31','2010-1-1','2010-1-2','2010-1-3'] вы хотите, чтобы дата была '2010-1-1', тогда вы должны использовать

df['roll']= pd.rolling_apply(df.returns,5,lambda x : x.prod(), center=True) 

Как у вас сейчас, тогда индекс даты для каждого 5-дневного окна будет установлен как последний, то есть '2010-1-3' в этом случае.

Наконец, вы должны заметить, что у вас будет несколько значений NaN в вашем столбце 'roll', потому что вы не можете вычислить скользящее среднее за 5 дней как в начале, так и в конце вашего фрейма данных. ТАК ожидаем, что в вашем столбце 'roll' будет 4 значения NaN.

...