Условное суммарное / минимальное значение в пандах

#python #pandas #multi-index

Вопрос:

Я пытаюсь использовать значения пола и потолка в cumsum. Всякий раз, когда uniqueEntry имеет положительное значение, Позиции увеличиваются, а всякий раз, когда uniqueExit положительный, Позиции уменьшаются. Тем не менее, позиции должны иметь значение пола 0 и потолок 3.

Во-вторых, для каждого Символа, если uniqueEntry запускается, когда Позиции находятся на предельном значении, как uniqueEntry, так и uniqueExit (для каждого символа) игнорируются при расчете Позиций до тех пор, пока uniqueEntry не будет запущен, когда Позиции находятся ниже предельного значения. Желаемые результаты в последнем примере.

На практике я рассматриваю позиции по акциям, ограничивая количество позиций значением и исключая остальные. Возможно ли это без зацикливания?

Данные испытаний:

 import pandas as pd
import numpy as np
from datetime import datetime, timedelta

np.random.seed(56)
symbols, symlen = 2, 3

times =             np.arange(datetime(2021, 1, 5), datetime(2021, 1, 12), timedelta(days=1)).astype(np.datetime64)
tlen =              len(times)
A, Z =              np.array(['A', 'Z']).view('int32')
symbol_names =      np.random.randint(low=A, high=Z, size=symbols * symlen, dtype='int32').view(f'U{symlen}')
limit =             np.random.randint(low=0, high=5, size=symbols*tlen, dtype='int32')
reset =             np.random.randint(low=-1, high=1, size=symbols*tlen, dtype='int32')
times =             np.concatenate([times] * symbols)
names =             np.array([y for x in [[s] * tlen for s in symbol_names] for y in x])
value_col =         np.random.randint(low=30, high=60, size=len(times), dtype='uint32')

df = pd.DataFrame({'Values': value_col}, index=[times, names])
df.index = df.index.set_names(['Date', 'Symbol'])
 

Создайте столбцы, определяющие условия:

 df['uniqueEntry'] = np.where(df.Values > 45, 1, 0)
df['uniqueExit'] = np.where(df.Values < 40, 1, 0)
 

Сортировка и окончание:

 df = df.sort_index(level='Date')
df['Positions'] = (df.uniqueEntry - df.uniqueExit).cumsum()
 

Текущий результат:

 df

                    Values  uniqueEntry     uniqueExit  Positions
Date        Symbol              
2021-01-05  ACL     42      0               0           0
            VEP     40      0               0           0
2021-01-06  ACL     30      0               1           -1
            VEP     31      0               1           -2
2021-01-07  ACL     38      0               1           -3
            VEP     46      1               0           -2
2021-01-08  ACL     59      1               0           -1
            VEP     43      0               0           -1
2021-01-09  ACL     52      1               0           0
            VEP     50      1               0           1
2021-01-10  ACL     34      0               1           0
            VEP     36      0               1           -1
2021-01-11  ACL     44      0               0           -1
            VEP     48      1               0           0
 

Желаемые результаты:

                     Values  uniqueEntry     uniqueExit  Positions
Date        Symbol              
2021-01-05  ACL     42      0               0           0
            VEP     40      0               0           0
2021-01-06  ACL     30      0               1           0
            VEP     31      0               1           0
2021-01-07  ACL     38      0               1           0
            VEP     46      1               0           1
2021-01-08  ACL     59      1               0           2
            VEP     43      0               0           2
2021-01-09  ACL     52      1               0           3
            VEP     50      1               0           3 <- should be excluded
2021-01-10  ACL     34      0               1           2
            VEP     36      0               1           2 <- should be ignored as uniqueEntry triggered while Positions = 3
2021-01-11  ACL     44      0               0           1
            VEP     48      1               0           2
 

Комментарии:

1. Я не думаю, что это возможно без использования цикла for, так как значение позиций зависит от предыдущего значения. Возможно, вы сможете найти какой-то способ, выполнив некоторые причудливые манипуляции/вызовы функций, но что плохого в том, чтобы просто делать df.iterrows() ?

2. Скорость. Но я рассматриваю зацикливание, но с использованием итераций (), так как это значительно быстрее или с использованием numba. Очевидно, что зацикливание-это экспоненциально более простое решение здесь.