Cómo fusionar múltiples marcos de datos
Tengo diferentes marcos de datos y necesito fusionarlos según la columna de fecha. Si solo tuviera dos marcos de datos, podría usar df1.merge(df2, on='date')
, para hacerlo con tres marcos de datos, uso df1.merge(df2.merge(df3, on='date'), on='date')
, sin embargo, se vuelve realmente complejo e ilegible hacerlo con múltiples marcos de datos.
Todos los marcos de datos tienen una columna en común date
, pero no tienen la misma cantidad de filas ni columnas y solo necesito aquellas filas en las que cada fecha es común a cada marco de datos.
Entonces, estoy intentando escribir una función recursiva que devuelva un marco de datos con todos los datos, pero no funcionó. Entonces, ¿cómo debería fusionar varios marcos de datos?
Probé de diferentes maneras y obtuve errores out of range
como keyerror 0/1/2/3
y can not merge DataFrame with instance of type <class 'NoneType'>
.
Este es el guión que escribí:
dfs = [df1, df2, df3] # list of dataframes
def mergefiles(dfs, countfiles, i=0):
if i == (countfiles - 2): # it gets to the second to last and merges it with the last
return
dfm = dfs[i].merge(mergefiles(dfs[i+1], countfiles, i=i+1), on='date')
return dfm
print(mergefiles(dfs, len(dfs)))
Un ejemplo: df_1:
May 19, 2017;1,200.00;0.1%
May 18, 2017;1,100.00;0.1%
May 17, 2017;1,000.00;0.1%
May 15, 2017;1,901.00;0.1%
df_2:
May 20, 2017;2,200.00;1000000;0.2%
May 18, 2017;2,100.00;1590000;0.2%
May 16, 2017;2,000.00;1230000;0.2%
May 15, 2017;2,902.00;1000000;0.2%
df_3:
May 21, 2017;3,200.00;2000000;0.3%
May 17, 2017;3,100.00;2590000;0.3%
May 16, 2017;3,000.00;2230000;0.3%
May 15, 2017;3,903.00;2000000;0.3%
Resultado de fusión esperado:
May 15, 2017; 1,901.00;0.1%; 2,902.00;1000000;0.2%; 3,903.00;2000000;0.3%
Respuesta corta
df_merged = reduce(lambda left,right: pd.merge(left,right,on=['DATE'],
how='outer'), data_frames)
Respuesta larga
A continuación, se muestra la forma más clara y comprensible de fusionar múltiples marcos de datos si no se trata de consultas complejas.
Simplemente combine con DATE como índice y combine usando el método OUTER (para obtener todos los datos).
import pandas as pd
from functools import reduce
df1 = pd.read_table('file1.csv', sep=',')
df2 = pd.read_table('file2.csv', sep=',')
df3 = pd.read_table('file3.csv', sep=',')
Ahora, básicamente carga todos los archivos que tienes como marco de datos en una lista. Y luego combine los archivos usando merge
o reduce
función.
# compile the list of dataframes you want to merge
data_frames = [df1, df2, df3]
Nota: puede agregar tantos marcos de datos dentro de la lista anterior. Esta es la parte buena de este método. No hay consultas complejas involucradas.
Para mantener los valores que pertenecen a la misma fecha, debe fusionarlos en elDATE
df_merged = reduce(lambda left,right: pd.merge(left,right,on=['DATE'],
how='outer'), data_frames)
# if you want to fill the values that don't exist in the lines of merged dataframe simply fill with required strings as
df_merged = reduce(lambda left,right: pd.merge(left,right,on=['DATE'],
how='outer'), data_frames).fillna('void')
- Ahora, el resultado serán los valores de la misma fecha en las mismas líneas.
- Puede completar los datos no existentes de diferentes marcos para diferentes columnas usando fillna().
Luego escriba los datos combinados en el archivo csv si lo desea.
pd.DataFrame.to_csv(df_merged, 'merged.txt', sep=',', na_rep='.', index=False)
Esto debería darte
DATE VALUE1 VALUE2 VALUE3 ....
Parece que los datos tienen las mismas columnas, por lo que puedes:
df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)
merged_df = pd.concat([df1, df2])
functools.reduce y pd.concat son buenas soluciones, pero en términos de tiempo de ejecución, pd.concat es la mejor.
from functools import reduce
import pandas as pd
dfs = [df1, df2, df3, ...]
nan_value = 0
# solution 1 (fast)
result_1 = pd.concat(dfs, join='outer', axis=1).fillna(nan_value)
# solution 2
result_2 = reduce(lambda df_left,df_right: pd.merge(df_left, df_right,
left_index=True, right_index=True,
how='outer'),
dfs).fillna(nan_value)