2017-06-02 48 views
5

Tôi có các tệp dữ liệu khác nhau và cần hợp nhất chúng lại với nhau dựa trên cột ngày. Nếu tôi chỉ có hai tệp, tôi có thể sử dụng df1.merge(df2, on='date'), nếu tôi thử với ba tệp, tôi sử dụng df1.merge(df2.merge(df3, on='date'), on='date'), nhưng có nhiều tệp để hợp nhất.Python: gấu trúc hợp nhất nhiều dataframes

Các khung dữ liệu có một cột chung - "ngày", nhưng không có cùng số hàng và cột và tôi chỉ cần các ngày phổ biến cho mỗi khung dữ liệu.

Vì vậy, tôi đang cố gắng viết một hàm đệ quy trả về một khung dữ liệu với tất cả dữ liệu nhưng nó không hoạt động. Tôi nên hợp nhất nhiều datafram như thế nào?

Tôi đã thử các cách khác nhau và gặp lỗi như out of range, keyerror 0/1/2/3can not merge DataFrame with instance of type <class 'NoneType'>.

Đây là kịch bản:

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

Một ví dụ: 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% 

Dự kiến ​​hợp nhất kết quả:

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

Và kết quả mong đợi của bạn là gì? – zipa

+0

@zipa, chỉ cần chỉnh sửa bài đăng. Kết quả hợp nhất là kết quả mong đợi. –

+0

Kiểm tra câu trả lời. Dễ hiểu nhất và dễ dàng nhất. – everestial007

Trả lời

6

Dưới đây, là cách sạch nhất, dễ hiểu nhất khi hợp nhất nhiều khung dữ liệu nếu các truy vấn phức tạp không liên quan.

Chỉ cần hợp nhất với DATE làm chỉ mục và hợp nhất bằng phương thức OUTER (để nhận tất cả dữ liệu).

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

Vì vậy, về cơ bản tải tất cả các tệp bạn có làm khung dữ liệu. Sau đó hợp nhất các tệp bằng cách sử dụng chức năng merge hoặc reduce.

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

bạn có thể thêm nhiều khung dữ liệu trong mã trên. Đây là phần tốt về phương pháp này. Không có truy vấn phức tạp nào liên quan.

Để giữ các giá trị thuộc về cùng ngày bạn cần phải hợp nhất nó vào 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') 
  • Vì vậy, các giá trị kể từ ngày cùng đang trên đường cùng.
  • Bạn có thể điền dữ liệu không tồn tại từ các khung khác nhau cho các cột khác nhau bằng cách sử dụng fillna().

Sau đó ghi dữ liệu đã hợp nhất vào tệp csv nếu muốn.

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

này sẽ cho bạn

DATE VALUE1 VALUE2 VALUE3 ....

+0

cảm ơn sự giúp đỡ của bạn, thực tế là nó thực sự sạch sẽ và hoạt động như dự định. –

2

Có 2 giải pháp cho điều này, nhưng nó trở lại tất cả các cột riêng biệt:

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

Nếu bạn đang lọc theo ngày chung này sẽ trả lại nó:

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

nhưng theo cách này, nó chỉ có thể nhận được kết quả cho 3 tệp. Nếu tôi thử với 4 tệp thì sao? Tôi có cần phải làm: 'set (df1.loc [:, 0] .intectionection (set (df3.loc [:, 0]). Giao điểm (set (df2.loc [:, 0])). (df1.loc [:, 0]))) '? –

+0

@VascoFerreira Tôi đã chỉnh sửa mã để phù hợp với tình huống đó. – zipa

1

Hình như các dữ liệu có các cột tương tự, vì vậy bạn có thể:

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

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

tôi cảm ơn bạn đã giúp đỡ của bạn @jezrael , @zipa@ everestial007, cả hai câu trả lời là những gì tôi cần. Nếu tôi đã thực hiện đệ quy, điều này cũng sẽ hoạt động như dự định:

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

Câu trả lời của @ dannyeuu là chính xác. pd.concat tự nhiên tham gia vào các cột chỉ mục, nếu bạn đặt tùy chọn trục thành 1. Mặc định là một phép nối ngoài, nhưng bạn cũng có thể chỉ định tham gia bên trong. Dưới đây là ví dụ:

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) 
Các vấn đề liên quan