Добавление вычисляемого столбца(ов) в таблицу данных в панд


у меня есть набор цен OHLC, который я проанализировал из CSV в фрейм данных Pandas и пересчитал до 15 мин баров:

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

Я хотел бы добавить различные вычисляемые столбцы, начиная с простых, таких как диапазон периодов (H-L), а затем булевы, чтобы указать на появление ценовых моделей, которые я определю, например, шаблон свечи молотка, для которого определение образца:

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

основная проблема: как мне сопоставить функцию со столбцом, в частности где я хотел бы ссылаться на более чем один столбец или всю строку или что?

этот пост имеет дело с добавлением двух вычисляемых столбцов из одного исходного столбца, который близок, но не совсем.

и немного более продвинутый: для ценовых моделей, которые определяются со ссылкой на более чем один бар (T), как я могу ссылаться на разные строки (например, T-1, T-2 и т. д.) из определения функции?

большое спасибо продвижение.

4 68

4 ответа:

точный код будет отличаться для каждого из столбцов, которые вы хотите сделать, но, вероятно, вы хотите использовать map и apply функции. В некоторых случаях вы можете просто вычислить, используя существующие столбцы напрямую, так как столбцы являются объектами серии Pandas, которые также работают как массивы 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

Если вам нужно использовать такие операции, как Max и min в строке, вы можете использовать apply С axis=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

надеюсь, это дает вам некоторое представление о том, как действовать.

Edit: чтобы сравнить строки с соседними строками, самый простой подход-разрезать столбцы, которые вы хотите сравнить, оставив начало/конец, а затем сравнить полученные срезы. Например, это скажет вам, для каких строк элемент в столбце A меньше чем элемент следующей строки в столбце C:

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

и это делает это по-другому, говоря вам, какие строки имеют меньше, чем c предыдущей строки:

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

делаешь ['A"][:-1] отрезает последний элемент столбца A и делает ['C'][1:] отрезает первый элемент столбца C, поэтому, когда вы выстраиваете эти два и сравниваете их, вы сравниваете каждый элемент в A с C из следующей строки.

вы могли бы is_hammer С точки зрения row["Open"] etc. следующим образом

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

для второй части вашего вопроса, Вы также можете использовать shift, например:

df['t-1'] = df['t'].shift(1)

t-1 будет содержать значения из t одной строки выше.

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.shift.html

первые четыре функции, которые вы перечисляете, также будут работать с векторами, за исключением того, что 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 etc. Этого достаточно, чтобы полностью векторизовать примеры вычислений, которые вы дали, и должны быть относительно быстрыми. Вероятно, вы могли бы ускорить еще больше, временно работая с массивами numpy, лежащими в основе данных при выполнении этих вычислений.

для второй части я бы рекомендовал ввести столбец с указанием шаблона для каждой строки и написать семейство функций, которые имеют дело с каждый шаблон. Затем сгруппируйте шаблон и примените соответствующую функцию к каждой группе.