2012-09-11 11 views
59

mam zestaw danych dotyczących cen OHLC, że są analizowane z CSV w dataframe PANDAS i próbkowane 15 min barów:dodania obliczonej kolumnę (-y) do dataframe w pand

<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) 

POLUBIŁEM dodawać różne kolumny obliczeniowe, zaczynając od prostych, takich jak przedział okresu (HL), a następnie wartości logiczne, aby wskazać występowanie wzorów cen, które zdefiniuję - np. młotek świeca wzór, dla którego definicja próbki:

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"]) 

podstawowy problem: w jaki sposób mapować funkcję do kolumny, a konkretnie gdzie chciałbym odwołać więcej niż jedną inną kolumnę lub cały wiersz lub cokolwiek?

This post dotyczy dodania dwóch wyliczonych kolumn z pojedynczej kolumny źródłowej, która jest bliska, ale nie do końca.

I nieco bardziej zaawansowany: w przypadku wzorów cen, które są określone w odniesieniu do więcej niż jednego paska (T), jak mogę odwoływać się do różnych wierszy (np. T-1, T-2 itp.) Z definicji funkcji ?

Wielkie dzięki z góry.

Odpowiedz

57

Dokładny kod będzie różny dla każdej z kolumn, które chcesz zrobić , ale prawdopodobnie będziesz chciał użyć funkcji map i apply. W niektórych przypadkach możesz po prostu obliczyć bezpośrednio z istniejących kolumn, ponieważ kolumny są obiektami serii Pandas, które również działają jako tablice Numpy, które automatycznie działają w sposób elementarny dla zwykłych operacji matematycznych.

>>> 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 

Jeśli trzeba użyć operacji jak max i min w rzędzie, można użyć apply z axis=1 zastosować dowolną funkcję chcesz każdego wiersza. Oto przykład, który oblicza min(A, B)-C, który wydaje się być jak twój „dolnym knotem”:

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

Mam nadzieję, że daje pewne wyobrażenie o tym, jak postępować.

Edytuj: aby porównać wiersze z sąsiednimi wierszami, najprostszym sposobem jest wycięcie kolumn, które chcesz porównać, pozostawiając poza początkiem/końcem, a następnie porównać otrzymane plasterki. Na przykład, to ci, dla których wiersze element w kolumnie A jest mniejsza niż elementu następnego wiersza w kolumnie C:

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

i to robi to w inny sposób, z informacją, które wiersze mają mniej niż rzędu poprzedniego użytkownika C:

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

Doing ['A"][:-1] plastry off ostatniego elementu kolumny a, i robi ['C'][1:] plasterki od pierwszego elementu kolumny C, więc po linii tych dwóch się i porównać je, jesteś porównując każdy element w A z C z poniższego rzędu.

35

Można mieć is_hammer pod względem row["Open"] itp następująco

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) 

Następnie można użyć mapę:

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

Również przydatne, wielkie dzięki. Wiele sposobów na skórze kota i wszystkich. Dałbym ci uprowadzenie, ale jest to moje pierwsze pytanie dotyczące StackOverflow i niestety nie mam wystarczającej liczby przedstawicieli. Nie sądzę, że masz nny pomysł na drugą część, mianowicie odsyłając do sąsiednich wierszy w ramce danych z funkcji map/apply? Znów na zdrowie. – ultra909

+0

Świetny przykład. Bardzo czytelny kod. –

+0

Z jakiegoś powodu metoda używająca 'map (f, col1, col2)' jest znacznie szybsza niż 'df.apply (..., axis = 1)'. mapowanie zajmuje 0,35s vs df.apply, co daje 26s dla ramki danych rzędu 1M. Każdy pomysł, dlaczego? (python 2.7 i pandy 0.18.1) – MohamedEzz

1

Pierwsze cztery funkcje wymienione Państwo będzie działać na wektorach, a także, z tym wyjątkiem, że lower_wick musi zostać dostosowany. Coś w tym stylu:

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

gdzie o, l oraz c są wektorami. Można zrobić to w ten sposób zamiast który właśnie zaczyna DF jako wejście i unikać numpy, chociaż to będzie dużo wolniej:

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

Pozostała trójka będzie działać na kolumnach lub wektorów tak jak są. Następnie można dobić z

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 

operatorów bitowych można wykonać zestaw logicznych logiki na wektorach & dla and, | dla or itp To wystarczy, aby całkowicie wektoryzacji obliczeń przykładowych Ci dał i powinien być stosunkowo szybko. Prawdopodobnie można przyspieszyć jeszcze bardziej, tymczasowo pracując z numpy tablicami leżącymi u podstaw danych podczas wykonywania tych obliczeń.

Dla drugiej części, chciałbym polecić wprowadzenie kolumny wskazującej wzór dla każdego rzędu i napisanie rodziny funkcji, które dotyczą każdego wzoru. Następnie zgrupuj wzór i zastosuj odpowiednią funkcję do każdej grupy.

Powiązane problemy