Python: panda’s voegen meerdere dataframes samen

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/3en 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 mergeof 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)

Other episodes