Pandas Dataframe: descarte ciertas horas del día de 20 años de datos históricos

8

Tengo datos del mercado de valores para un solo valor que se remonta a 20 años. Los datos se encuentran actualmente en un Pandas DataFrame, en el siguiente formato:

ingrese la descripción de la imagen aquí

El problema es que no quiero ningún dato comercial "fuera de horario" en mi DataFrame. El mercado en cuestión está abierto de 9:30 a.m. a 4 p.m. (09:30 a 16:00 en cada día de negociación). Me gustaría descartar todas las filas de datos que no están dentro de este período de tiempo.

Mi instinto es usar una máscara de pandas, que sé cómo hacer si quisiera ciertas horas en un solo día:

mask = (df['date'] > '2015-07-06 09:30:0') & (df['date'] <= '2015-07-06 16:00:0')
sub = df.loc[mask]

Sin embargo, no tengo idea de cómo usar uno de forma rotativa para eliminar los datos de ciertos momentos del día durante un período de 20 años.

HMLDude
fuente
¿Cuál es el tipo de datos de la columna date? ¿Podría ejecutar este comando print(df['date'].map(type)) y publicar su salida a la pregunta?
Andy L.

Respuestas:

8

El problema aquí es cómo está importando datos. ¿No hay un indicador de si las 04:00 son am o pm? pero basándonos en sus comentarios, debemos asumir que es PM. Sin embargo, la entrada lo muestra como AM.

Para resolver esto, necesitamos incluir dos condiciones con la cláusula OR.

  1. 9: 30-11: 59
  2. 0: 00-4: 00

Entrada:

df = pd.DataFrame({'date':   {880551: '2015-07-06 04:00:00', 880552: '2015-07-06 04:02:00',880553: '2015-07-06 04:03:00', 880554: '2015-07-06 04:04:00', 880555: '2015-07-06 04:05:00'},
                   'open':   {880551: 125.00, 880552: 125.36,880553: 125.34, 880554: 125.08, 880555: 125.12},
                   'high':   {880551: 125.00, 880552: 125.36,880553: 125.34, 880554: 125.11, 880555: 125.12},
                   'low':    {880551: 125.00, 880552: 125.32,880553: 125.21, 880554: 125.05, 880555: 125.12},
                   'close':  {880551: 125.00, 880552: 125.32,880553: 125.21, 880554: 125.05, 880555: 125.12},
                   'volume': {880551: 141, 880552: 200,880553: 750, 880554: 17451, 880555: 1000},
                   },
                   )


df.head()

    date    open    high    low close   volume
880551  2015-07-06 04:00:00 125.00  125.00  125.00  125.00  141
880552  2015-07-06 04:02:00 125.36  125.36  125.32  125.32  200
880553  2015-07-06 04:03:00 125.34  125.34  125.21  125.21  750
880554  2015-07-06 04:04:00 125.08  125.11  125.05  125.05  17451
880555  2015-07-06 04:05:00 125.12  125.12  125.12  125.12  1000

from datetime import time

start_first = time(9, 30)
end_first = time(11, 59)
start_second = time(0, 00)
end_second = time(4,00)
df['date'] = pd.to_datetime(df['date'])
df= df[(df['date'].dt.time.between(start_first, end_first)) | (df['date'].dt.time.between(start_second, end_second))]
df
date    open    high    low close   volume
880551  2015-07-06 04:00:00 125.0   125.0   125.0   125.0   141

Lo anterior no es una buena práctica, y desaconsejo usar este tipo de datos ambiguos. La solución a largo plazo es llenar correctamente los datos con am / pm.

Podemos lograrlo de dos maneras en caso de formato de datos correcto:

1) usando datetime

from datetime import time

start = time(9, 30)
end = time(16)
df['date'] = pd.to_datetime(df['date'])
df= df[df['date'].dt.time.between(start, end)]

2) uso entre tiempo, que solo funciona con índice de fecha y hora

df['date'] = pd.to_datetime(df['date'])

df = (df.set_index('date')
          .between_time('09:30', '16:00')
          .reset_index())

Si aún enfrenta un error, edite su pregunta con el enfoque línea por línea y el error exacto.

Bhavesh Ghodasara
fuente
Eso da como resultado el siguiente errorTypeError: Index must be DatetimeIndex
HMLDude
edité mi respuesta, df ['date'] = pd.to_datetime (df ['date'])
Bhavesh Ghodasara
Desde esta publicación SO , parece que between_timeel marco de datos debe ser un índice de fecha y hora. OP se puede tratar a nivel de trama de datos: day_df = df.set_index('date').between_time('9:30', '16:00').
Parfait
BhaveshGhodasara Intenté lo que sugeriste en tus últimas ediciones y el resultado es el mismo TypeError: Index must be DatetimeIndex.
HMLDude
@Parfait Probé su sugerencia, así y una vez más el mensaje de error fue: TypeError: Index must be DatetimeIndex.
HMLDude
3

Creo que la respuesta ya está en los comentarios (@ Parfait's .between_time ) pero que se perdió en problemas de depuración. Parece que su df['date']columna Datetimeaún no es de tipo .

Esto debería ser suficiente para arreglar eso y obtener el resultado requerido:

df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date')
df = df.between_time('9:30', '16:00')
jorijnsmit
fuente
0

Este código de ejemplo consolida las respuestas proporcionadas por Bhavesh Ghodasara, Parfait y jorijnsmit en un ejemplo completo y comentado:

import pandas as pd

# example dataframe containing 6 records: 2 days of 3 records each in which all cases are covered:
# each day has one record before trading hours, one record during trading hours and one recrod after trading hours
df = pd.DataFrame({'date':   {0: '2015-07-06 08:00:00', 1: '2015-07-06 13:00:00', 2: '2015-07-06 18:00:00', 
                              3: '2015-07-07 08:00:00', 4: '2015-07-07 13:00:00', 5: '2015-07-07 18:00:00'},
                   'open':   {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'high':   {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'low':    {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'close':  {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'volume': {0: 141, 1: 200, 2: 750, 3: 17451, 4: 1000, 5: 38234},
                   },
                   )

# inspect the example data set
df.head(6)

# first, ensure that the 'date' column is of the correct data type: MAKE IT SO!
df['date'] = pd.to_datetime(df['date'])

# inspect the data types: date column should be of type 'datetime64[ns]'
print(df.dtypes)

# set the index of the dataframe to the datetime-type column 'data'
df = df.set_index('date')

# inspect the index: it should be a DatetimeIndex of dtype 'datetime64[ns]'
print(df.index)

# filter the data set
df_filtered = df.between_time('9:30', '16:00')

# inspect the filtered data set: Voilà! No more outside trading hours records.
df_filtered.head()
Steve
fuente