Можно ли использовать функцию применения или векторизацию в этой логике кода? - PullRequest
0 голосов
/ 27 ноября 2018

Я пытаюсь рассчитать итоговое сальдо

Входной фрейм данных:

    open   inOut    close
0   3      100      0
1   0      300      0
2   0      200      0
3   0      230      0
4   0      150      0

Выходной фрейм данных

    open    inOut   close
0   3       100     103
1   103     300     403
2   403     200     603
3   603     230     833
4   833     150     983  

Я могу добиться этого, используя raw for-loop и для ее оптимизации я использовал iterrow ()

For-Loop

%%timeit
for i in range(len(df.index)):
    if i>0:
        df.iloc[i]['open'] = df.iloc[i-1]['close']
        df.iloc[i]['close'] = df.iloc[i]['open']+df.iloc[i]['inOut']
    else:
        df.iloc[i]['close'] = df.iloc[i]['open']+df.iloc[i]['inOut'] 

1.64 ms ± 51.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

iterrows

%%timeit
for index,row in dfOg.iterrows():
    if index>0:
        row['open'] = dfOg.iloc[index-1]['close']
        row['close'] = row['open']+row['inOut']
    else:
        row['close'] = row['open']+row['inOut']

627 µs ± 28.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

производительность оптимизирована с 1,64 мс -> 627 мкс

Согласно этому блогу , я изо всех сил пытаюсь выяснить, какчтобы написать вышеупомянутую логику, используя apply () и векторизацию.
для векторизации, я попытался сместить столбцы, но не смог достичь желаемого результата.

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Вы можете использовать np.where

%%timeit
df['open'] = np.where(df.index==0, df['open'], df['inOut'].shift())
df['close'] = df['open'] + df['inOut']
# 1.07 ms ± 16.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Выход:

    open    inOut   close
0   3.0     100     103.0
1   100.0   300     300.0
2   300.0   200     200.0
3   200.0   230     230.0
4   230.0   150     150.0
0 голосов
/ 27 ноября 2018

Редактировать: Я изменил все вокруг, чтобы сопоставить изменения, внесенные ОП с вопросом

Вы можете делать то, что хотите, в векторизованном виде без каких-либо циклов, таких как:

import pandas as pd

d = {'open': [3] + [0]*4, 'inOut': [100, 300, 200, 230, 150], 'close': [0]*5}
df = pd.DataFrame(d)

df['close'].values[:] = df['open'].values[0] + df['inOut'].values.cumsum()
df['open'].values[1:] = df['close'].values[:-1]

Синхронизация с %%timeit:

529 µs ± 5.39 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Вывод:

   close  inOut  open
0    103    100     3
1    403    300   103
2    603    200   403
3    833    230   603
4    983    150   833

Так что векторизация вашего кода таким способом действительно несколько быстрее.На самом деле, это, вероятно, как можно быстрее.Вы можете увидеть это, синхронизировав только код создания фрейма данных:

%%timeit
d = {'open': [3] + [0]*4, 'inOut': [100, 300, 200, 230, 150], 'close': [0]*5}
df = pd.DataFrame(d)

Результат:

367 µs ± 5.67 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Вычитая время, необходимое для создания фрейма данных, векторизованной версии заполнения вашегодатафрейм занимает всего ~ 160 мкс.

...