Ik heb verschillende dataframes en moet ze samenvoegen op basis van de datumkolom. Als ik maar twee dataframes had, zou ik df1.merge(df2, on='date')
kunnen gebruiken, om het met drie dataframes te doen, gebruik ik df1.merge(df2.merge(df3, on='date'), on='date')
, maar het wordt erg complex en onleesbaar om het met meerdere dataframes te doen.
Alle dataframes hebben één kolom gemeen –DATE
, maar ze hebben niet hetzelfde aantal rijen of kolommen en ik heb alleen die rijen nodig waarin elke datum gemeenschappelijk is voor elk dataframe.
Dus ik probeer een recursiefunctie te schrijven die een dataframe met alle gegevens retourneert, maar het werkte niet. Hoe moet ik dan meerdere dataframes samenvoegen?
Ik heb verschillende manieren geprobeerd en kreeg fouten zoals out of range
, keyerror 0/1/2/3
en can not merge DataFrame with instance of type <class 'NoneType'>
.
Dit is het script dat ik heb geschreven:
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)))
Een voorbeeld:
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%
Verwacht resultaat samenvoegen:
May 15, 2017; 1,901.00;0.1%; 2,902.00;1000000;0.2%; 3,903.00;2000000;0.3%
Antwoord 1, autoriteit 100%
Hieronder staat de meest duidelijke, begrijpelijke manier om meerdere dataframes samen te voegen als er geen complexe zoekopdrachten bij betrokken zijn.
Gewoon samenvoegen met DATEals index en samenvoegen met behulp van de OUTERmethode (om alle gegevens te krijgen).
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=',')
Laad nu in principe alle bestanden die u als dataframe hebt in een lijst. En voeg vervolgens de bestanden samen met de functie merge
of reduce
.
# compile the list of dataframes you want to merge
data_frames = [df1, df2, df3]
Opmerking: u kunt zoveel dataframes toevoegen aan de bovenstaande lijst.Dit is het goede aan deze methode. Geen ingewikkelde vragen.
Om de waarden die bij dezelfde datum horen te behouden, moet u deze samenvoegen op de DATE
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')
- Nu, de uitgang zal de waarden uit dezelfde datum op dezelfde lijn.
- U kunt de niet-bestaande gegevens uit verschillende frames voor verschillende kolommen te vullen met behulp van fillna ().
Schrijf dan de samengevoegde gegevens naar het CSV-bestand, indien gewenst.
pd.DataFrame.to_csv(df_merged, 'merged.txt', sep=',', na_rep='.', index=False)
Dit moet geven u
DATE VALUE1 VALUE2 VALUE3 ....
Antwoord 2, Autoriteit 17%
Het lijkt erop dat de gegevens heeft dezelfde kolommen, zodat u:
df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)
merged_df = pd.concat([df1, df2])
Antwoord 3, Autoriteit 14%
functools.reduce en pd.concat zijn goede oplossingen, maar in termen van uitvoeringstijd pd.concat is het beste.
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)
Antwoord 4, Autoriteit 7%
Er zijn 2 oplossingen voor dit, maar het geeft alle kolommen afzonderlijk:
import functools
dfs = [df1, df2, df3]
df_final = functools.reduce(lambda left,right: pd.merge(left,right,on='date'), dfs)
print (df_final)
date a_x b_x a_y b_y c_x a b c_y
0 May 15,2017 900.00 0.2% 1,900.00 1000000 0.2% 2,900.00 2000000 0.2%
k = np.arange(len(dfs)).astype(str)
df = pd.concat([x.set_index('date') for x in dfs], axis=1, join='inner', keys=k)
df.columns = df.columns.map('_'.join)
print (df)
0_a 0_b 1_a 1_b 1_c 2_a 2_b 2_c
date
May 15,2017 900.00 0.2% 1,900.00 1000000 0.2% 2,900.00 2000000 0.2%
Antwoord 5, Autoriteit 2%
Het antwoord van @ Dannyeuu is correct. PD.CONCAT Natuurlijk doet een lid van indexkolommen, als u de Axis-optie instelt op 1. De standaard is een buitenste join, maar u kunt ook innerlijke join opgeven. Hier is een voorbeeld:
x = pd.DataFrame({'a': [2,4,3,4,5,2,3,4,2,5], 'b':[2,3,4,1,6,6,5,2,4,2], 'val': [1,4,4,3,6,4,3,6,5,7], 'val2': [2,4,1,6,4,2,8,6,3,9]})
x.set_index(['a','b'], inplace=True)
x.sort_index(inplace=True)
y = x.__deepcopy__()
y.loc[(14,14),:] = [3,1]
y['other']=range(0,11)
y.sort_values('val', inplace=True)
z = x.__deepcopy__()
z.loc[(15,15),:] = [3,4]
z['another']=range(0,22,2)
z.sort_values('val2',inplace=True)
pd.concat([x,y,z],axis=1)
Antwoord 6
Bekijk dit Panda’s Drie-weg Drie-rendement verbinden met meerdere dataframes op kolommen
filenames = ['fn1', 'fn2', 'fn3', 'fn4',....]
dfs = [pd.read_csv(filename, index_col=index_col) for filename in filenames)]
dfs[0].join(dfs[1:])
Antwoord 7
Nog een manier om te combineren: functools.reduce
Van documentatie:
Bijvoorbeeld,
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
berekent ((((1 + 2) +3) +4 ) +5). Het linker argument, x, is de geaccumuleerde waarde en het juiste argument, Y, is de update-waarde van de tisaber.
Dus:
from functools import reduce
dfs = [df1, df2, df3, df4, df5, df6]
df_final = reduce(lambda left,right: pd.merge(left,right,on='some_common_column_name'), dfs)
Antwoord 8
@ Everestial007’s oplossing werkte voor mij. Dit is hoe ik het ben verbeterde voor mijn gebruikscase, dat de kolommen van elke verschillende DF met een ander achtervoegsel is, zodat ik gemakkelijker kan differentiëren tussen de DFS in het uiteindelijke samengevoegde dataframe.
from functools import reduce
import pandas as pd
dfs = [df1, df2, df3, df4]
suffixes = [f"_{i}" for i in range(len(dfs))]
# add suffixes to each df
dfs = [dfs[i].add_suffix(suffixes[i]) for i in range(len(dfs))]
# remove suffix from the merging column
dfs = [dfs[i].rename(columns={f"date{suffixes[i]}":"date"}) for i in range(len(dfs))]
# merge
dfs = reduce(lambda left,right: pd.merge(left,right,how='outer', on='date'), dfs)
Antwoord 9
Als u filteren per gemeenschappelijke datum, retourneert dit het:
dfs = [df1, df2, df3]
checker = dfs[-1]
check = set(checker.loc[:, 0])
for df in dfs[:-1]:
check = check.intersection(set(df.loc[:, 0]))
print(checker[checker.loc[:, 0].isin(check)])
Antwoord 10
Bedankt voor uw hulp @jezrael , @zipa en @ everestial007 , beide antwoorden zijn wat ik nodig heb. Als ik een recursief wilde maken, zou dit ook werken zoals bedoeld:
def mergefiles(dfs=[], on=''):
"""Merge a list of files based on one column"""
if len(dfs) == 1:
return "List only have one element."
elif len(dfs) == 2:
df1 = dfs[0]
df2 = dfs[1]
df = df1.merge(df2, on=on)
return df
# Merge the first and second datafranes into new dataframe
df1 = dfs[0]
df2 = dfs[1]
df = dfs[0].merge(dfs[1], on=on)
# Create new list with merged dataframe
dfl = []
dfl.append(df)
# Join lists
dfl = dfl + dfs[2:]
dfm = mergefiles(dfl, on)
return dfm
Antwoord 11
Voor mij wordt de index genegeerd zonder expliciete instructie. Voorbeeld:
> x = pandas.DataFrame({'a': [1,2,2], 'b':[4,5,5]})
> x
a b
0 1 4
1 2 5
2 2 5
> x.drop_duplicates()
a b
0 1 4
1 2 5
(gedupliceerde lijnen verwijderd ondanks verschillende index)