Как выполнить прокрутку цикла в кадре данных Pandas?

У меня есть pandas df с 3 столбцами:

        Close   Top_Barrier Bottom_Barrier
0       441.86  441.964112  426.369888
1       448.95  444.162225  425.227108
2       449.99  446.222271  424.285063
3       449.74  447.947051  423.678282
4       451.97  449.879254  423.029413
...
996     436.97  446.468790  426.600543
997     438.16  446.461401  426.599265
998     437.00  446.093899  426.641434
999     437.52  446.024365  426.631635
1000    437.75  446.114093  426.715907

Цель: Для каждой строки мне нужно проверить, касается ли какая-либо из следующих 30 строк цены закрытия верхнего или нижнего барьера (из строки 0), например, начать с индекса строки 0, проверить, не касается ли цена закрытия (441,86) больше, чем Верхний_барьер (441,96) или ниже, чем Нижний_барьер (426,36), если он больше, чем Верхний_барьер, вернуть 1, если он ниже, чем Нижний_барьер, вернуть -1. В противном случае перейдите к следующей строке, например, по индексу 1 цена закрытия равна 448,95, но она все еще тестируется относительно цены барьера с индексом 0, т. е. верхний_барьер равен 441,96, нижний_барьер равен 426,36. Этот цикл продолжается до индекса 29, если цена закрытия никогда не касается барьеров - в этом случае возвращается 0. Следующий скользящий цикл начинается с индекса 1 до 30 и т. д.

Попытки: я пытался использовать .rolling.apply со следующей функцией, но не смог устранить ошибки. С удовольствием изучу любые другие методы, если они достигают моей цели, указанной выше. Спасибо!

def tbl_rolling(x):
    start_i = x.index[0]
    for i in range(len(x)):
        # the barrier freeze at index 0
        if x.loc[i, 'Close'] > x.loc[start_i, 'Top_Barrier']:
            return 1
        elif x.loc[i, 'Close'] < x.loc[start_i, 'Bottom_Barrier']:
            return -1
    return 0

Затем следующее выдает IndexingError: слишком много индексаторов.

test = df.rolling(30).apply(tbl_rolling, raw=False)

person Kok Wei Hoo    schedule 13.11.2018    source источник
comment
Что произойдет, если цена закрытия выше верхнего барьера для одной записи и ниже нижнего барьера для другой записи в течение тридцати дней? Что вы хотите вернуть?   -  person Scott Boston    schedule 13.11.2018
comment
Извините, я должен был упомянуть об этом - цикл for завершается, когда он касается любого верхнего или нижнего барьера.   -  person Kok Wei Hoo    schedule 13.11.2018
comment
В конечном итоге ожидаемый результат состоит в том, чтобы иметь столбец с метками (1, -1 или 0), указывающий, что для каждой строки, касается ли цена закрытия в следующих 30 строках сначала верхней (1) или нижней (-1) ), либо остается внутри барьеров на всем протяжении (0).   -  person Kok Wei Hoo    schedule 13.11.2018


Ответы (1)


Вы можете попробовать что-то вроде этого, если ваш набор данных не очень большой:

df = df.reset_index().assign(key=1)

def f(x):
    cond1 = x['Close_x'] > x['Top_Barrier_y'].max()
    cond2 = x['Close_x'] < x['Bottom_Barrier_y'].min()
    return np.select([cond1,cond2],[1,-1], default=0)[0]

df.merge(df, on='key').query('index_y <= index_x').groupby('index_x').apply(f)

Выход:

index_x
0       0
1       1
2       1
3       1
4       1
996     0
997     0
998     0
999     0
1000    0
dtype: int64
person Scott Boston    schedule 13.11.2018
comment
Полный df имеет около 24 тыс. строк. Пока я все еще пытаюсь понять, как работает ваш метод, могу ли я узнать, имеет ли ваш метод эффект роллинга? т.е. .rolling(30)... - person Kok Wei Hoo; 13.11.2018