2017-06-02 132 views
5

我有不同的數據文件,需要根據日期列將它們合併在一起。如果我只有兩個文件,我可以使用df1.merge(df2, on='date'),如果我嘗試使用三個文件,我使用df1.merge(df2.merge(df3, on='date'), on='date'),但有多個文件要合併。Python:大熊貓合併多個數據框

數據幀有一個共同的列 - 「日期」,但沒有相同數量的行和列,我只需要每個數據幀通用的日期。

所以,我試圖編寫一個遞歸函數,返回一個數據幀與所有數據,但它沒有奏效。我應該如何合併多個數據框?

我嘗試過不同的方式,並得到像out of rangekeyerror 0/1/2/3can not merge DataFrame with instance of type <class 'NoneType'>錯誤。

這是腳本:

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))) 

一個例子: file_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;900.00;0.2% 

file_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;1,900.00;1000000;0.2% 

file_3:

May 21, 2017;3,200.00;2000000;0.2% 
May 17, 2017;3,100.00;2590000;0.2% 
May 16, 2017;3,000.00;2230000;0.2% 
May 15,2017;2,900.00;2000000;0.2% 

預期的合併結果:

May 15,2017;2,900.00;2000000;0.2% 
+0

你的預期結果是什麼? – zipa

+0

@zipa,剛剛編輯帖子。合併結果是預期的結果。 –

+0

查看答案。最容易理解和容易的一個。 – everestial007

回答

6

下面是在不涉及複雜查詢的情況下合併多個數據幀的最簡潔,最易理解的方法。

只需簡單地用DATE作爲索引合併和使用OUTER法合併(獲得的所有數據)。

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=',') 

因此,基本上加載所有文件作爲數據框。然後使用mergereduce函數合併文件。

# compile the list of dataframes you want to merge 
data_frames = [df1, df2, df3] 

你可以在上面的代碼添加儘可能多的數據幀。這是關於這種方法的好處。不涉及複雜的查詢。

爲了保持屬於同一日期,你需要這樣合併它的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') 
  • 值,從在同一日期的值在同一行。
  • 您可以使用fillna()填充不同框架的不存在的數據。

然後,如果需要,將合併的數據寫入csv文件。

pd.DataFrame.to_csv(df_merged, 'merged.txt', sep=',', na_rep='.', index=False) 

這應該給你

DATE VALUE1 VALUE2 VALUE3 ....

+0

感謝您的幫助,它實際上非常乾淨並且按預期工作。 –

2

這有2個解決方案,但它單獨返回所有列:

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% 
1

如果你是普通的日期過濾,這將返回它:

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)]) 
+0

但以這種方式,它只能得到3個文件的結果。如果我嘗試使用4個文件怎麼辦?我需要做:set(df1.loc [:, 0] .intersection(set(df3.loc [:, 0])。intersection(set(df2.loc [:, 0]))。intersection(set (df1.loc [:, 0])))'? –

+0

@VascoFerreira我編輯了代碼以匹配這種情況。 – zipa

1

貌似數據具有相同的列,所以您可以:

df1 = pd.DataFrame(data1) 
df2 = pd.DataFrame(data2) 

merged_df = pd.concat([df1, df2]) 
0

我感謝你的幫助@jezrael@zipa and @ everestial007,這兩個答案都是我需要的。如果我要遞歸,這也將按預期工作:

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 
1

@ dannyeuu的回答是正確的。如果將axis選項設置爲1,pd.concat自然會在索引列上進行連接。缺省值是外連接,但也可以指定內連接。這裏是一個例子:

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)