Estoy fusionando algunos marcos de datos que tienen un índice de tiempo.
import pandas as pd
df1 = pd.DataFrame(['a', 'b', 'c'],
columns=pd.MultiIndex.from_product([['target'], ['key']]),
index = [
'2022-04-15 20:20:20.000000',
'2022-04-15 20:20:21.000000',
'2022-04-15 20:20:22.000000'],)
df2 = pd.DataFrame(['a2', 'b2', 'c2', 'd2', 'e2'],
columns=pd.MultiIndex.from_product([['feature2'], ['keys']]),
index = [
'2022-04-15 20:20:20.100000',
'2022-04-15 20:20:20.500000',
'2022-04-15 20:20:20.900000',
'2022-04-15 20:20:21.000000',
'2022-04-15 20:20:21.100000',],)
df3 = pd.DataFrame(['a3', 'b3', 'c3', 'd3', 'e3'],
columns=pd.MultiIndex.from_product([['feature3'], ['keys']]),
index = [
'2022-04-15 20:20:19.000000',
'2022-04-15 20:20:19.200000',
'2022-04-15 20:20:20.000000',
'2022-04-15 20:20:20.200000',
'2022-04-15 20:20:23.100000',],)
entonces uso este procedimiento de combinación:
def merge(dfs:list[pd.DataFrame], targetColumn:'str|tuple[str]'):
from functools import reduce
if len(dfs) == 0:
return None
if len(dfs) == 1:
return dfs[0]
for df in dfs:
df.index = pd.to_datetime(df.index)
merged = reduce(
lambda left, right: pd.merge(
left,
right,
how='outer',
left_index=True,
right_index=True),
dfs)
for col in merged.columns:
if col!= targetColumn:
merged[col] = merged[col].fillna(method='ffill')
return merged[merged[targetColumn].notna()]
Me gusta esto:
merged = merge([df1, df2, df3], targetColumn=('target', 'key'))
que produce esto:
Y todo funciona muy bien. El problema es la eficiencia: observe que en el procedimiento de combinación () utilizo reducir y una combinación externa para unir los marcos de datos, esto puede hacer un marco de datos provisional ENORME que luego se filtra. Pero, ¿qué pasa si mi PC no tiene suficiente RAM para manejar ese enorme marco de datos en la memoria? Bueno, ese es el problema que estoy tratando de evitar.
Me pregunto si hay una manera de evitar expandir los datos en un gran marco de datos durante la fusión.
Por supuesto, una combinación anterior regular no es suficiente porque solo se combina con índices que coinciden exactamente en lugar del índice temporal más reciente antes de la observación de la variable de destino:
df1.merge(df2, how='left', left_index=True, right_index=True)
¿Este tipo de cosas se han resuelto de manera eficiente? Parece un problema común de ciencia de datos, ya que nadie quiere filtrar información futura en sus modelos, y todos tienen varias entradas para fusionar...
Solución del problema
Estás de suerte: ¡ pandas.merge_asof
hace exactamente lo que necesitas!
Usamos el direction='backward'
argumento por defecto:
Una búsqueda "hacia atrás" selecciona la última fila en el DataFrame derecho cuya tecla 'on' es menor o igual que la tecla de la izquierda.
Usando sus tres marcos de datos de ejemplo:
import pandas as pd
from functools import reduce
# Convert all indexes to datetime
for df in [df1, df2, df3]:
df.index = pd.to_datetime(df.index)
# Perform as-of merges
res = reduce(lambda left, right:
pd.merge_asof(left, right, left_index=True, right_index=True),
[df1, df2, df3])
print(res)
target feature2 feature3
key keys keys
2022-04-15 20:20:20 a NaN c3
2022-04-15 20:20:21 b d2 d3
2022-04-15 20:20:22 c e2 d3
No hay comentarios:
Publicar un comentario