2017-09-18 96 views
2

我有兩個DataFrames dfevol如下(簡化的例子):的Python大熊貓:如何向量化這個功能

In[6]: df 
Out[6]: 
    data year_final year_init 
0 12  2023  2012 
1 34  2034  2015 
2  9  2019  2013 
... 

In[7]: evol 
Out[7]: 
     evolution 
year   
2000 1.474946 
2001 1.473874 
2002 1.079157 
... 
2037 1.463840 
2038 1.980807 
2039 1.726468 

我想在一個矢量方式操作以下操作(電流for循環實現實在太長了,當我有GB的數據):

for index, row in df.iterrows(): 
    for year in range(row['year_init'], row['year_final']): 
     factor = evol.at[year, 'evolution'] 
     df.at[index, 'data'] += df.at[index, 'data'] * factor 

複雜性來自於一個事實,即當年的範圍不是各行上一樣... 在上面的例子中輸出繼電器將是:

 data year_final year_init 
0  163673  2023  2012 
1 594596046  2034  2015 
2  1277  2019  2013 

(全evol數據幀進行測試的目的:)只使用熊貓

 evolution 
year   
2000 1.474946 
2001 1.473874 
2002 1.079157 
2003 1.876762 
2004 1.541348 
2005 1.581923 
2006 1.869508 
2007 1.289033 
2008 1.924791 
2009 1.527834 
2010 1.762448 
2011 1.554491 
2012 1.927348 
2013 1.058588 
2014 1.729124 
2015 1.025824 
2016 1.117728 
2017 1.261009 
2018 1.705705 
2019 1.178354 
2020 1.158688 
2021 1.904780 
2022 1.332230 
2023 1.807508 
2024 1.779713 
2025 1.558423 
2026 1.234135 
2027 1.574954 
2028 1.170016 
2029 1.767164 
2030 1.995633 
2031 1.222417 
2032 1.165851 
2033 1.136498 
2034 1.745103 
2035 1.018893 
2036 1.813705 
2037 1.463840 
2038 1.980807 
2039 1.726468 
+1

您可以添加樣品輸出? – Dark

+0

我剛纔編輯的問題 – Prikers

+0

這是真的很複雜,從熊貓社區矢量化如此添加numpy標記。速度的numba。 – Dark

回答

2

一個量化的方法是做一個笛卡爾的兩幀之間的子集加入。將開始出像:

df['dummy'] = 1 
evol['dummy'] = 1 
combined = df.merge(evol, on='dummy') 
# filter date ranges, multiply etc 

這可能會比你在做什麼更快,但是內存是效率低下,可能會炸燬你的真實數據。

如果你可以承擔倫巴依賴,這樣的事情應該是非常快 - 基本上是你現在正在做的事情的編譯版本。在cython中也可能有類似的東西。請注意,這要求evol數據框按年分類並連續排列,這可以通過修改來放鬆。

import numba 

@numba.njit 
def f(data, year_final, year_init, evol_year, evol_factor): 
    data = data.copy() 
    for i in range(len(data)): 
     year_pos = np.searchsorted(evol_year, year_init[i]) 
     n_years = year_final[i] - year_init[i] 
     for offset in range(n_years): 
      data[i] += data[i] * evol_factor[year_pos + offset]    
    return data 

f(df['data'].values, df['year_final'].values, df['year_init'].values, evol.index.values, evol['evolution'].values) 
Out[24]: array([ 163673, 594596044,  1277], dtype=int64) 

編輯: 一些與你的測試數據的時序

In [25]: %timeit f(df['data'].values, df['year_final'].values, df['year_init'].values, evol.index.values, evol['evolution'].values) 
15.6 µs ± 338 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 


In [26]: %%time 
    ...: for index, row in df.iterrows(): 
    ...:  for year in range(row['year_init'], row['year_final']): 
    ...:   factor = evol.at[year, 'evolution'] 
    ...:   df.at[index, 'data'] += df.at[index, 'data'] * factor 
Wall time: 3 ms 
+0

你會介意添加時間,這將有助於找到差異。 – Dark

+0

確實,對於這種情況來說,使用numba好得多!感謝你,我無法找到任何有效的方式來矢量化否則... – Prikers