[英]Python pandas rolling_apply two column input into function
繼這個問題Python 自定義函數 using rolling_apply for pandas 之后,關於使用rolling_apply
。 盡管我的函數取得了進展,但我仍在努力處理需要兩列或更多列作為輸入的函數:
創建與以前相同的設置
import pandas as pd
import numpy as np
import random
tmp = pd.DataFrame(np.random.randn(2000,2)/10000,
index=pd.date_range('2001-01-01',periods=2000),
columns=['A','B'])
但是稍微改變函數以取兩列。
def gm(df,p):
df = pd.DataFrame(df)
v =((((df['A']+df['B'])+1).cumprod())-1)*p
return v.iloc[-1]
它產生以下錯誤:
pd.rolling_apply(tmp,50,lambda x: gm(x,5))
KeyError: u'no item named A'
我認為這是因為 lambda 函數的輸入是長度為 50 且僅第一列的 ndarray,並且不以兩列作為輸入。 有沒有辦法將兩列都作為輸入並在rolling_apply
函數中使用它。
再次,任何幫助將不勝感激......
看起來rolling_apply會嘗試將用戶func的輸入轉換為ndarray( http://pandas.pydata.org/pandas-docs/stable/generated/pandas.stats.moments.rolling_apply.html?highlight=rolling_apply#pandas.stats。 moment.rolling_apply )。
基於使用輔助列ii 的解決方法,該列用於在操作函數 gm 中選擇窗口:
import pandas as pd
import numpy as np
import random
tmp = pd.DataFrame(np.random.randn(2000,2)/10000, columns=['A','B'])
tmp['date'] = pd.date_range('2001-01-01',periods=2000)
tmp['ii'] = range(len(tmp))
def gm(ii, df, p):
x_df = df.iloc[map(int, ii)]
#print x_df
v =((((x_df['A']+x_df['B'])+1).cumprod())-1)*p
#print v
return v.iloc[-1]
#print tmp.head()
res = pd.rolling_apply(tmp.ii, 50, lambda x: gm(x, tmp, 5))
print res
不確定這里是否仍然相關,對於 Pandas 上的新rolling
類,每當我們將raw=False
傳遞給apply
,我們實際上是將系列傳遞給包裝器,這意味着我們可以訪問每個觀察的索引,並且可以使用它進一步處理多列。
從文檔:
raw : bool, 默認無
False :將每一行或每一列作為系列傳遞給函數。
True 或 None :傳遞的函數將接收 ndarray 對象。 如果您只是應用 NumPy 縮減功能,這將獲得更好的性能。
在這種情況下,我們可以執行以下操作:
### create a func for multiple columns
def cust_func(s):
val_for_col2 = df.loc[s.index, col2] #.values
val_for_col3 = df.loc[s.index, col3] #.values
val_for_col4 = df.loc[s.index, col4] #.values
## apply over multiple column values
return np.max(s) *np.min(val_for_col2)*np.max(val_for_col3)*np.mean(val_for_col4)
### Apply to the dataframe
df.rolling('10s')['col1'].apply(cust_func, raw=False)
請注意,這里我們仍然可以使用pandas rolling
類的所有功能,這在處理與時間相關的窗口時特別有用。
我們傳遞一列並使用整個數據框的事實感覺像是一種黑客攻擊,但它在實踐中是有效的。
這是這個問題的另一個版本: 在 DataFrame 對象上使用滾動應用。 如果您的函數返回一個系列,請使用它。
由於您的返回標量,因此請執行此操作。
In [71]: df = pd.DataFrame(np.random.randn(2000,2)/10000,
index=pd.date_range('2001-01-01',periods=2000),
columns=['A','B'])
重新定義您的函數以返回一個包含您要使用的索引和計算的標量值的元組。 請注意,這略有不同,因為我們在這里返回第一個索引(而不是通常返回的最后一個,你也可以這樣做)。
In [72]: def gm(df,p):
v =((((df['A']+df['B'])+1).cumprod())-1)*p
return (df.index[0],v.iloc[-1])
In [73]: Series(dict([ gm(df.iloc[i:min((i+1)+50,len(df)-1)],5) for i in xrange(len(df)-50) ]))
Out[73]:
2001-01-01 0.000218
2001-01-02 -0.001048
2001-01-03 -0.002128
2001-01-04 -0.003590
2001-01-05 -0.004636
2001-01-06 -0.005377
2001-01-07 -0.004151
2001-01-08 -0.005155
2001-01-09 -0.004019
2001-01-10 -0.004912
2001-01-11 -0.005447
2001-01-12 -0.005258
2001-01-13 -0.004437
2001-01-14 -0.004207
2001-01-15 -0.004073
...
2006-04-20 -0.006612
2006-04-21 -0.006299
2006-04-22 -0.006320
2006-04-23 -0.005690
2006-04-24 -0.004316
2006-04-25 -0.003821
2006-04-26 -0.005102
2006-04-27 -0.004760
2006-04-28 -0.003832
2006-04-29 -0.004123
2006-04-30 -0.004241
2006-05-01 -0.004684
2006-05-02 -0.002993
2006-05-03 -0.003938
2006-05-04 -0.003528
Length: 1950
所有rolling_* 函數都適用於一維數組。 我相信有人可以發明一些傳遞二維數組的解決方法,但在您的情況下,您可以簡單地預先計算行值以進行滾動評估:
>>> def gm(x,p):
... return ((np.cumprod(x) - 1)*p)[-1]
...
>>> pd.rolling_apply(tmp['A']+tmp['B']+1, 50, lambda x: gm(x,5))
2001-01-01 NaN
2001-01-02 NaN
2001-01-03 NaN
2001-01-04 NaN
2001-01-05 NaN
2001-01-06 NaN
2001-01-07 NaN
2001-01-08 NaN
2001-01-09 NaN
2001-01-10 NaN
2001-01-11 NaN
2001-01-12 NaN
2001-01-13 NaN
2001-01-14 NaN
2001-01-15 NaN
...
2006-06-09 -0.000062
2006-06-10 -0.000128
2006-06-11 0.000185
2006-06-12 -0.000113
2006-06-13 -0.000962
2006-06-14 -0.001248
2006-06-15 -0.001962
2006-06-16 -0.003820
2006-06-17 -0.003412
2006-06-18 -0.002971
2006-06-19 -0.003882
2006-06-20 -0.003546
2006-06-21 -0.002226
2006-06-22 -0.002058
2006-06-23 -0.000553
Freq: D, Length: 2000
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.