pd.df найти строки попарно используя groupby и изменить фиктивные значения - PullRequest
0 голосов
/ 12 апреля 2020

Мой pd.DataFrame похож на этот пример, но содержит около 10 миллионов строк, поэтому я ищу эффективное решение.

import pandas as pd                                                                                                                   

df = pd.DataFrame({'timestamp':['2004-09-06', '2004-09-06', '2004-09-06', '2004-09-06', '2004-09-07', '2004-09-07'], 
                   'opt_expiry': ['2005-12-16', '2005-12-16', '2005-12-16', '2005-12-16', '2005-06-17', '2005-06-17'],  
                   'strike': [2, 2, 2.5, 2.5, 1.5, 1.5],  
                   'type': ['c', 'p', 'c', 'p', 'c', 'p'],  
                   'sigma': [0.25, 0.25, 0.001, 0.17, 0.195, 0.19],  
                   'delta': [0.7, -0.3, 1, -0.25, 0.6, -0.4]}).set_index('timestamp', drop=True) 
df.index = pd.to_datetime(df.index) 
df.opt_expiry = pd.to_datetime(df.opt_expiry) 

Out[2]: 
           opt_expiry  strike type  sigma  delta
timestamp                                       
2004-09-06 2005-12-16     2.0    c  0.250   0.70
2004-09-06 2005-12-16     2.0    p  0.250  -0.30
2004-09-06 2005-12-16     2.5    c  0.001   1.00
2004-09-06 2005-12-16     2.5    p  0.170  -0.25
2004-09-07 2005-06-17     1.5    c  0.195   0.60
2004-09-07 2005-06-17     1.5    p  0.190  -0.40

вот что я хочу достичь:

1) найти пары с одинаковой отметкой времени, opt_expiry и strike:

groups = df.groupby(['timestamp','opt_expiry','strike'])

2) для каждой группы проверить, равна ли сумма абсолютной дельты 1. Если true, найти максимум двух сигма-значений и назначить это в обе строки как новая, правильная сигма. псевдокод:

for group in groups:
    # if sum of absolute deltas != 1
    if (abs(group.delta[0]) + abs(group.delta[1])) != 1:
        correct_sigma = group.sigma.max()
        group.sigma = correct_sigma

Ожидаемый результат:

           opt_expiry  strike type  sigma  delta
timestamp                                       
2004-09-06 2005-12-16     2.0    c  0.250   0.70
2004-09-06 2005-12-16     2.0    p  0.250  -0.30
2004-09-06 2005-12-16     2.5    c  0.170   1.00
2004-09-06 2005-12-16     2.5    p  0.170  -0.25
2004-09-07 2005-06-17     1.5    c  0.195   0.60
2004-09-07 2005-06-17     1.5    p  0.190  -0.40

1 Ответ

1 голос
/ 12 апреля 2020

Пересмотренный ответ. Я считаю, что там может быть более короткий ответ. Может быть, поставить его в качестве данных за вознаграждение

df = pd.DataFrame({'timestamp':['2004-09-06', '2004-09-06', '2004-09-06', '2004-09-06', '2004-09-07', '2004-09-07'], 
                   'opt_expiry': ['2005-12-16', '2005-12-16', '2005-12-16', '2005-12-16', '2005-06-17', '2005-06-17'],  
                   'strike': [2, 2, 2.5, 2.5, 1.5, 1.5],  
                   'type': ['c', 'p', 'c', 'p', 'c', 'p'],  
                   'sigma': [0.25, 0.25, 0.001, 0.17, 0.195, 0.19],  
                   'delta': [0.7, -0.3, 1, -0.25, 0.6, -0.4]}).set_index('timestamp', drop=True) 
df

Рабочая

Абсолютная дельта-сумма для каждой группы для каждой строки

df['absdelta']=df['delta'].abs()

Абсолютная дельта-сумма и максимальная сигма для каждой группы в новый фрейм данных df2

df2=df.groupby(['timestamp','opt_expiry','strike']).agg({'absdelta':'sum','sigma':'max'})#.reset_index().drop(columns=['timestamp','opt_expiry'])
df2

Слияние df2 с df

df3=df.merge(df2, left_on='strike', right_on='strike',
          suffixes=('', '_right'))
df3

групп масок с абсолютной дельтой суммы, не равной 1

m=df3['absdelta_right']!=1
m

Используя маску, примените максимальную сигма к объектам в группах, замаскированных выше

df3.loc[m,'sigma']=df3.loc[m,'sigma_right']

Срез для возврата к исходному фрейму данных

df3.iloc[:,:-4]

Вывод

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...