簡體   English   中英

如何合並多個數據框

[英]How to merge multiple dataframes

我有不同的數據框,需要根據日期列將它們合並在一起。 如果我只有兩個數據幀,我可以使用df1.merge(df2, on='date') ,要用三個數據幀來做,我使用df1.merge(df2.merge(df3, on='date'), on='date') ,但是使用多個數據幀來完成它變得非常復雜且不可讀。

所有數據框都有一個共同的列 - date ,但它們沒有相同的行數和列數,我只需要那些行,其中每個日期對於每個 dataframe 都是共同的。

所以,我正在嘗試編寫一個遞歸 function,它返回一個包含所有數據的 dataframe,但它沒有用。 那我應該如何合並多個數據框呢?

我嘗試了不同的方法,但遇到了錯誤,例如out of rangekeyerror 0/1/2/3並且can 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)))

一個例子: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%

預期合並結果:

May 15, 2017;  1,901.00;0.1%;  2,902.00;1000000;0.2%;   3,903.00;2000000;0.3%   

如果不涉及復雜查詢,下面是合並多個數據幀的最干凈、最易理解的方法。

只需簡單地將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 ....

看起來數據具有相同的列,因此您可以:

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

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

functools.reducepd.concat是很好的解決方案,但就執行時間而言 pd.concat 是最好的。

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)

有兩種解決方案,但它分別返回所有列:

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%

另一種組合方式: functools.reduce

從文檔:

例如, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])計算 ((((1+2)+3)+4)+5)。 左邊的參數 x 是累積值,右邊的參數 y 是迭代的更新值。

所以:

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)

@dannyeuu 的回答是正確的。 如果將軸選項設置為 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)

看看這個pandas 三向連接列上的多個數據框

filenames = ['fn1', 'fn2', 'fn3', 'fn4',....]
dfs = [pd.read_csv(filename, index_col=index_col) for filename in filenames)]
dfs[0].join(dfs[1:])

@everestial007 的解決方案對我有用。 這就是我為我的用例改進它的方式,即讓每個不同 df 的列具有不同的后綴,以便我可以更輕松地區分最終合並數據幀中的 dfs。

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)

如果您按公共日期過濾,這將返回它:

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

感謝您對@ jezrael 、@ zipa@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

對我來說,在沒有明確指示的情況下會忽略索引。 例子:

    > 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

(盡管索引不同,但刪除了重復的行)

我有一個類似的用例並在下面解決了。 基本上捕獲了列表中的第一個df,然后循環通過提醒並將它們合並到合並結果將替換前一個的位置。

編輯:我正在處理非常小的數據框 - 不確定這種方法如何擴展到更大的數據集。 #買者自負

import pandas as pd
df_list = [df1,df2,df3, ...dfn]
# grab first dataframe
all_merged = df_list[0]
# loop through all but first data frame
for to_merge in df_list[1:]:
    # result of merge replaces first or previously
    # merged data frame w/ all previous fields
    all_merged = pd.merge(
        left=all_merged
        ,right=to_merge
        ,how='inner'
        ,on=['some_fld_across_all']
        )

# can easily have this logic live in a function
def merge_mult_dfs(df_list):
    all_merged = df_list[0]
    for to_merge in df_list[1:]:
        all_merged = pd.merge(
            left=all_merged
            ,right=to_merge
            ,how='inner'
            ,on=['some_fld_across_all']
            )
    return all_merged

您也可以像這樣使用dataframe.merge

df = df1.merge(df2).merge(df3)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM