GOOGLE ADS

viernes, 29 de abril de 2022

Pandas fusiona múltiples marcos de datos en un índice temporal, con el valor más reciente de todos los demás

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:

producción objetivo

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)

combinación eficiente pero mala

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

Regla de Firestore para acceder a la generación de subcolección Permisos faltantes o insuficientes

Tengo problemas con las reglas de Firestore para permitir el acceso a algunos recursos en una subcolección. Tengo algunos requests document...