2012-09-11 30 views
59

我有一個OHLC價格的數據集,我已經從CSV解析成熊貓數據幀和重採樣爲15名分鐘巴的數據幀:添加計算的列(S)到在熊貓

<class 'pandas.core.frame.DataFrame'> 
DatetimeIndex: 500047 entries, 1998-05-04 04:45:00 to 2012-08-07 00:15:00 
Freq: 15T 
Data columns: 
Close 363152 non-null values 
High  363152 non-null values 
Low  363152 non-null values 
Open  363152 non-null values 
dtypes: float64(4) 

我想添加各種計算列,從簡單的例如Range(HL)開始,然後用布爾值來表示我將要定義的價格模式的發生 - 例如錘子蠟燭圖案,其中一個樣品的定義:

def closed_in_top_half_of_range(h,l,c): 
    return c > l + (h-1)/2 

def lower_wick(o,l,c): 
    return min(o,c)-l 

def real_body(o,c): 
    return abs(c-o) 

def lower_wick_at_least_twice_real_body(o,l,c): 
    return lower_wick(o,l,c) >= 2 * real_body(o,c) 

def is_hammer(row): 
    return lower_wick_at_least_twice_real_body(row["Open"],row["Low"],row["Close"]) \ 
    and closed_in_top_half_of_range(row["High"],row["Low"],row["Close"]) 

基本問題:如何將功能映射到列,具體在哪裏,我想引用一個以上的其他列或整行或什麼?

This post涉及將單個來源列的兩個計算列關閉,但不是完全相同。

稍微更高級一點:對於參照多個單條(T)確定的價格模式,我如何從函數定義中引用不同的行(例如T-1,T-2等) ?

非常感謝提前。

回答

57

確切的代碼將每個你想要做的列的變化,但很可能您想要使用mapapply函數。在某些情況下,您可以直接使用現有列進行計算,因爲這些列是Pandas Series對象,它們也可以作爲Numpy數組工作,這些數組會自動爲通常的數學運算按元素進行工作。

>>> d 
    A B C 
0 11 13 5 
1 6 7 4 
2 8 3 6 
3 4 8 7 
4 0 1 7 
>>> (d.A + d.B)/d.C 
0 4.800000 
1 3.250000 
2 1.833333 
3 1.714286 
4 0.142857 
>>> d.A > d.C 
0  True 
1  True 
2  True 
3 False 
4 False 

如果你需要一個行內使用像最大值和最小值的操作,您可以使用applyaxis=1申請你喜歡的每一行的任何功能。下面是計算min(A, B)-C一個例子,這似乎是喜歡你的「下油繩」:即讓你的如何進行一些想法

>>> d.apply(lambda row: min([row['A'], row['B']])-row['C'], axis=1) 
0 6 
1 2 
2 -3 
3 -3 
4 -7 

希望。

編輯:要將行與相鄰行進行比較,最簡單的方法是對要比較的列進行切片,將開始/結束切掉,然後比較結果切片。舉例來說,這將告訴你哪些行A列元素小於C列的下一行的元素:

d['A'][:-1] < d['C'][1:] 

,這確實它的其他方式,告訴你哪些行具有比A少前行的C:

d['A'][1:] < d['C'][:-1] 

['A"][:-1]片斷列A的最後一個元素,並做['C'][1:]片關閉C列的第一個元素,所以你排隊的這兩個並比較它們,你要比較各A中的元素和下一行中的C。

35

你可以有is_hammerrow["Open"]等條款如下

def is_hammer(rOpen,rLow,rClose,rHigh): 
    return lower_wick_at_least_twice_real_body(rOpen,rLow,rClose) \ 
     and closed_in_top_half_of_range(rHigh,rLow,rClose) 

然後你可以使用地圖:

df["isHammer"] = map(is_hammer, df["Open"], df["Low"], df["Close"], df["High"]) 
+2

還有用,非常感謝。許多方法爲貓和所有皮膚。我會給你一個upvote,但這是我在StackOverflow上的第一個問題,我可惜沒有足夠的代表。 我不認爲你對第二部分有任何想法,即在map/apply函數中引用dataframe中的相鄰行嗎? 再次歡呼。 – ultra909

+0

很好的例子。非常可讀的代碼。 –

+0

出於某種原因,使用'map(f,col1,col2)'的方法比'df.apply(...,axis = 1)'快。映射需要0.35s,df.apply需要26s才能獲得1M行數據幀。任何想法爲什麼? (python 2.7和熊貓0.18.1) – MohamedEzz

1

你列出的載體也能發揮作用,與lower_wick需要適應的是,除了前四項功能。像這樣,

def lower_wick_vec(o, l, c): 
    min_oc = numpy.where(o > c, c, o) 
    return min_oc - l 

其中o,l和c是向量。 你可以做到這一點,而不是這樣這只是需要DF作爲輸入並避免使用numpy的,雖然會慢得多:

def lower_wick_df(df): 
    min_oc = df[['Open', 'Close']].min(axis=1) 
    return min_oc - l 

另外三個將在列或載體,就像他們的工作。然後,你可以用

def is_hammer(df): 
    lw = lower_wick_at_least_twice_real_body(df["Open"], df["Low"], df["Close"]) 
    cl = closed_in_top_half_of_range(df["High"], df["Low"], df["Close"]) 
    return cl & lw 

位運算符玩完可以在布爾向量執行一套邏輯,&and|or等,這是足以完全矢量化你給的樣本計算,應該是比較快的。在執行這些計算時,您可以通過臨時處理數據下面的numpy陣列來加速甚至更快。

對於第二部分,我會建議引入一個指示每行模式的列,並編寫處理每個模式的函數族。然後將模式分組並將適當的功能應用於每個組。