78 votos

Añadir columna(s) calculada(s) a un marco de datos en los pandas

Tengo un conjunto de datos de precios de OHLC, que he analizado de CSV en un marco de datos de Pandas y remuestreado a barras de 15 minutos:

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

Me gustaría añadir varias columnas calculadas, empezando por las más sencillas como el período Rango (H-L) y luego las booleanas para indicar la ocurrencia de patrones de precios que definiré - por ejemplo, un patrón de vela de martillo, para el cual una definición de muestra:

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

Problema básico: ¿cómo mapeo la función a la columna, específicamente donde me gustaría referirme a más de otra columna o a toda la fila o lo que sea?

Este puesto se trata de añadir dos columnas calculadas de una sola columna de origen, que está cerca, pero no del todo.

Y algo más avanzado: en el caso de los patrones de precios que se determinan con referencia a más de una sola barra (T), ¿cómo puedo referirme a diferentes filas (por ejemplo, T-1, T-2, etc.) desde dentro de la definición de la función?

Muchas gracias de antemano.

75voto

BrenBarn Puntos 63718

El código exacto variará para cada una de las columnas que quieras hacer, pero es probable que quieras usar el map y apply funciones. En algunos casos se puede calcular directamente utilizando las columnas existentes, ya que las columnas son objetos de la serie de Pandas, que también funcionan como matrices de Numpy, que funcionan automáticamente en función de los elementos para las operaciones matemáticas habituales.

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

Si necesitas usar operaciones como máximo y mínimo en una fila, puedes usar apply con axis=1 para aplicar cualquier función que quieras a cada fila. Aquí hay un ejemplo que calcula min(A, B)-C que parece ser como tu "mecha inferior":

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

Espero que eso le dé alguna idea de cómo proceder.

Editar: para comparar filas con las filas vecinas, el enfoque más simple es rebanar las columnas que se quieren comparar, dejando fuera el principio/fin, y luego comparar los cortes resultantes. Por ejemplo, esto te dirá para qué filas el elemento de la columna A es menor que el elemento de la siguiente fila de la columna C:

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

y esto lo hace de la otra manera, diciéndote qué filas tienen A menos que la C de la fila anterior:

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

Haciendo ['A"][:-1] corta el último elemento de la columna A, y haciendo ['C'][1:] corta el primer elemento de la columna C, así que cuando alineas estos dos y los comparas, estás comparando cada elemento de la A con la C de la siguiente fila.

45voto

Andy Hayden Puntos 38010

Podrías haber is_hammer en términos de row["Open"] etc. de la siguiente manera

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)

Entonces puedes usar el mapa:

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

5voto

fantabolous Puntos 431

Para la segunda parte de tu pregunta, también puedes usar shift por ejemplo:

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

t-1 contendría entonces los valores de t una fila más arriba.

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

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X