Панды, берущие накопительную сумму с сбросом
проблема
Я пытаюсь сохранить общее количество последовательных меток времени (минутная частота). В настоящее время у меня есть способ взять накопленную сумму и сбросить ее при условии, что два столбца не совпадают, но это сделано с помощью цикла for. Мне было интересно, если есть способ сделать это без цикла.
Код
cb_arbitrage['shift'] = cb_arbitrage.index.shift(1, freq='T')
Возвращает:
cccccccc bbbbbbbb cb_spread shift
timestamp
2017-07-07 18:23:00 2535.002000 2524.678462 10.323538 2017-07-07 18:24:00
2017-07-07 18:24:00 2535.007826 2523.297619 11.710207 2017-07-07 18:25:00
2017-07-07 18:25:00 2535.004167 2524.391000 10.613167 2017-07-07 18:26:00
2017-07-07 18:26:00 2534.300000 2521.838667 12.461333 2017-07-07 18:27:00
2017-07-07 18:27:00 2530.231429 2520.195625 10.035804 2017-07-07 18:28:00
2017-07-07 18:28:00 2529.444667 2518.782143 10.662524 2017-07-07 18:29:00
2017-07-07 18:29:00 2528.988000 2518.802963 10.185037 2017-07-07 18:30:00
2017-07-07 18:59:00 2514.403367 2526.473333 12.069966 2017-07-07 19:00:00
2017-07-07 19:01:00 2516.410000 2528.980000 12.570000 2017-07-07 19:02:00
Затем я делаю следующее:
cb_arbitrage['shift'] = cb_arbitrage['shift'].shift(1)
cb_arbitrage['shift'][0] = cb_arbitrage.index[0]
cb_arbitrage['count'] = 0
Который возвращает:
cccccccc bbbbbbbb cb_spread shift count
timestamp
2017-07-07 18:23:00 2535.002000 2524.678462 10.323538 2017-07-07 18:23:00 0
2017-07-07 18:24:00 2535.007826 2523.297619 11.710207 2017-07-07 18:24:00 0
2017-07-07 18:25:00 2535.004167 2524.391000 10.613167 2017-07-07 18:25:00 0
2017-07-07 18:26:00 2534.300000 2521.838667 12.461333 2017-07-07 18:26:00 0
2017-07-07 18:27:00 2530.231429 2520.195625 10.035804 2017-07-07 18:27:00 0
2017-07-07 18:28:00 2529.444667 2518.782143 10.662524 2017-07-07 18:28:00 0
2017-07-07 18:29:00 2528.988000 2518.802963 10.185037 2017-07-07 18:29:00 0
2017-07-07 18:59:00 2514.403367 2526.473333 12.069966 2017-07-07 18:30:00 0
2017-07-07 19:01:00 2516.410000 2528.980000 12.570000 2017-07-07 19:00:00 0
Затем цикл для расчета накопленной суммы со сбросом:
count = 0
for i, row in cb_arbitrage.iterrows():
if i == cb_arbitrage.loc[i]['shift']:
count += 1
cb_arbitrage.set_value(i, 'count', count)
else:
count = 1
cb_arbitrage.set_value(i, 'count', count)
Что дает мне мой ожидаемый результат:
cccccccc bbbbbbbb cb_spread shift count
timestamp
2017-07-07 18:23:00 2535.002000 2524.678462 10.323538 2017-07-07 18:23:00 1
2017-07-07 18:24:00 2535.007826 2523.297619 11.710207 2017-07-07 18:24:00 2
2017-07-07 18:25:00 2535.004167 2524.391000 10.613167 2017-07-07 18:25:00 3
2017-07-07 18:26:00 2534.300000 2521.838667 12.461333 2017-07-07 18:26:00 4
2017-07-07 18:27:00 2530.231429 2520.195625 10.035804 2017-07-07 18:27:00 5
2017-07-07 18:28:00 2529.444667 2518.782143 10.662524 2017-07-07 18:28:00 6
2017-07-07 18:29:00 2528.988000 2518.802963 10.185037 2017-07-07 18:29:00 7
2017-07-07 18:59:00 2514.403367 2526.473333 12.069966 2017-07-07 18:30:00 1
2017-07-07 19:01:00 2516.410000 2528.980000 12.570000 2017-07-07 19:00:00 1
2017-07-07 21:55:00 2499.904560 2510.814000 10.909440 2017-07-07 19:02:00 1
2017-07-07 21:56:00 2500.134615 2510.812857 10.678242 2017-07-07 21:56:00 2
1 ответ
Вы можете использовать diff
метод, который находит разницу между текущей строкой и предыдущей строкой. Затем вы можете проверить и посмотреть, равна ли эта разница одной минуте. Отсюда есть множество хитростей, чтобы сбросить полосы в данных.
Сначала мы берем совокупную сумму логической Серии, которая приближает нас к тому, что мы хотим. Для сброса ряда мы умножаем этот ряд накопленной суммы на исходное логическое значение, поскольку False оценивается как 0.
s = cb_arbitrage.timestamp.diff() == pd.Timedelta('1 minute')
s1 = s.cumsum()
s.mul(s1).diff().where(lambda x: x < 0).ffill().add(s1, fill_value=0) + 1
0 1.0
1 2.0
2 3.0
3 4.0
4 5.0
5 6.0
6 7.0
7 1.0
8 1.0
9 1.0
10 2.0