Как улучшить групповую работу / применить эффективность - PullRequest
0 голосов
/ 08 мая 2018

У меня есть пандас DataFrame с годами в качестве индекса, один столбец с идентификатором запаса, второй столбец с возвратами. DataFrame имеет ~ 200 тыс. Строк. Я хочу добавить 3 дополнительных столбца с совокупной доходностью каждой акции в следующие 5, 10 и 20 лет соответственно. Для этого я группирую по столбцу ID и применяю функцию к сгруппированному объекту, что я покажу в простом примере ниже. Я знал, что это займет некоторое время, но на данный момент код выполнялся в течение 23 часов и все еще работает.

У меня есть 2 вопроса:

  1. Почему именно python занимает так много времени для выполнения кода? куда узкое место?
  2. Есть идеи, как изменить код, чтобы он стал быстрее?

Вот мой код, примененный к более простому примеру.

In [1]: import pandas as pd

In [2]: simple_df = pd.DataFrame([[1,1,1,2,2],[0.1,0.05,0.15,0.3,0.2]], columns=[2010,2011,2012,2011,2012], index=['ID','Return']).T

In [3]: simple_df
Out[3]: 
       ID  Return
2010  1.0    0.10
2011  1.0    0.05
2012  1.0    0.15
2011  2.0    0.30
2012  2.0    0.20

In [4]: grouped = simple_df.groupby('ID', sort=False)

In [5]: create_df = lambda x: pd.DataFrame({i: x.Return.shift(-i) for i in range(0,3)})

In [6]: df_1 = grouped.apply(create_df)

In [7]: df_1
Out[7]: 
         0     1     2
2010  0.10  0.05  0.15
2011  0.05  0.15   NaN
2012  0.15   NaN   NaN
2011  0.30  0.20   NaN
2012  0.20   NaN   NaN

In [8]: df_2 =(df_1+1).cumprod(axis=1)-1

In [9]: df_2
Out[9]: 
         0       1        2
2010  0.10  0.1550  0.32825
2011  0.05  0.2075      NaN
2012  0.15     NaN      NaN
2011  0.30  0.5600      NaN
2012  0.20     NaN      NaN

In [10]: simple_df['Return_3y'] = df_2.iloc[:,2]

In [11]: simple_df
Out[11]: 
       ID  Return  Return_3y
2010  1.0    0.10    0.32825
2011  1.0    0.05        NaN
2012  1.0    0.15        NaN
2011  2.0    0.30        NaN
2012  2.0    0.20        NaN

1 Ответ

0 голосов
/ 08 мая 2018

Вместо apply используйте DataFrameGroupBy.shift с concat:

np.random.seed(234)
N = 10000

idx = np.random.randint(1990, 2020, size=N)
simple_df = pd.DataFrame({'ID':np.random.randint(1000, size=N),
              'Return':np.random.rand(N)}, index=idx).sort_values('ID')

print (simple_df)

In [147]: %%timeit
     ...: grouped = simple_df.groupby('ID', sort=False)
     ...: create_df = lambda x: pd.DataFrame({i: x.Return.shift(-i) for i in range(0,3)})
     ...: df_1 = grouped.apply(create_df)
     ...: df_2 =(df_1+1).cumprod(axis=1)-1
     ...: 
1.01 s ± 6.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [148]: %%timeit
     ...: g = simple_df.groupby('ID', sort=False)
     ...: df2 = pd.concat([g['Return'].shift(-i) for i in range(3)], axis=1, keys=range(3))
     ...: df2 =(df2+1).cumprod(axis=1)-1
     ...: 
3.91 ms ± 53.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...