gấu trúc ba chiều tham gia nhiều datafram trên cột


191

Tôi có 3 tệp CSV. Mỗi cột có cột đầu tiên là tên (chuỗi) của mọi người, trong khi tất cả các cột khác trong mỗi khung dữ liệu là thuộc tính của người đó.

Làm cách nào tôi có thể "tham gia" cùng nhau cả ba tài liệu CSV để tạo một CSV duy nhất với mỗi hàng có tất cả các thuộc tính cho mỗi giá trị duy nhất của tên chuỗi của người đó?

Các join()chức năng trong gấu trúc quy định cụ thể mà tôi cần một multiindex, nhưng tôi đang bối rối về những gì một chương trình lập chỉ mục thứ bậc đã làm với thực hiện một tham gia dựa trên một chỉ số duy nhất.


2
Bạn không cần một multindex. Nó tuyên bố trong các tài liệu tham gia rằng bạn không có multiindex khi truyền nhiều cột để tham gia thì nó sẽ xử lý việc đó.
cwharland

1
Trong các thử nghiệm của tôi, df1.join([df2, df3], on=[df2_col1, df3_col1])đã không làm việc.
lollercoaster

Bạn cần xâu chuỗi chúng lại với nhau như trong câu trả lời đã cho. Hợp nhất df1 và df2 sau đó hợp nhất kết quả với df3
cwharland

Câu trả lời:


472

Nhập khẩu giả định:

import pandas as pd

Câu trả lời của John Galt về cơ bản là một reducehoạt động. Nếu tôi có nhiều hơn một số datafram, tôi sẽ đặt chúng vào một danh sách như thế này (được tạo thông qua việc hiểu danh sách hoặc vòng lặp hoặc không có gì):

dfs = [df0, df1, df2, dfN]

Giả sử họ có một số cột chung, như nametrong ví dụ của bạn, tôi sẽ làm như sau:

df_final = reduce(lambda left,right: pd.merge(left,right,on='name'), dfs)

Theo cách đó, mã của bạn sẽ hoạt động với bất kỳ số lượng dữ liệu nào bạn muốn hợp nhất.

Chỉnh sửa ngày 1 tháng 8 năm 2016 : Đối với những người sử dụng Python 3: reduceđã được chuyển vào functools. Vì vậy, để sử dụng chức năng này, trước tiên bạn cần nhập mô-đun đó:

from functools import reduce

11
Tôi mới thử sử dụng cái này và nó đã thất bại vì reduceđược thay thế bằng functools.reduceSoimport functools functools.reduce(.......)
MattR

3
Giải pháp này sẽ hoạt động như thế nào nếu tên của các trường tham gia khác nhau? Ví dụ, trong ba khung dữ liệu tôi có thể có name1, name2name3tương ứng.
ps0604

2
Điều này không có nghĩa là chúng ta có n-1các lệnh gọi đến hàm hợp nhất sao? Tôi đoán trong trường hợp này số lượng datafram nhỏ không thành vấn đề, nhưng tôi tự hỏi liệu có giải pháp nào có thể mở rộng hơn không.
eapolinario

1
Điều này đã không hoàn toàn làm việc cho tôi dfs với cột chỉ số đa (nó đã được tiêm 'bật' như một cột mà làm việc cho việc hợp nhất đầu tiên, nhưng hòa trộn tiếp theo thất bại), thay vào đó tôi đã nhận nó để làm việc với:df = reduce(lambda left, right: left.join(right, how='outer', on='Date'), dfs)
Adrian Torrie

+1 đến ps0604. Điều gì xảy ra nếu các cột tham gia khác nhau, điều này có hoạt động không? chúng ta có nên đi với pd.merge trong trường hợp các cột tham gia có khác không? cảm ơn
steve

106

Bạn có thể thử điều này nếu bạn có 3 dataframes

# Merge multiple dataframes
df1 = pd.DataFrame(np.array([
    ['a', 5, 9],
    ['b', 4, 61],
    ['c', 24, 9]]),
    columns=['name', 'attr11', 'attr12'])
df2 = pd.DataFrame(np.array([
    ['a', 5, 19],
    ['b', 14, 16],
    ['c', 4, 9]]),
    columns=['name', 'attr21', 'attr22'])
df3 = pd.DataFrame(np.array([
    ['a', 15, 49],
    ['b', 4, 36],
    ['c', 14, 9]]),
    columns=['name', 'attr31', 'attr32'])

pd.merge(pd.merge(df1,df2,on='name'),df3,on='name')

cách khác, như được đề cập bởi cwharland

df1.merge(df2,on='name').merge(df3,on='name')

34
Để trông gọn gàng hơn, bạn có thể xâu chuỗi chúng df1.merge(df2,on='name').merge(df3,on='name')
cwharland

1
Giải pháp này sẽ hoạt động như thế nào nếu tên của các trường tham gia khác nhau? Ví dụ: trong ba khung dữ liệu tôi có thể có name1, name2name3tương ứng
ps0604

4
@ ps0604df1.merge(df2,left_on='name1', right_on='name2').merge(df3,left_on='name1', right_on='name3').drop(columns=['name2', 'name3']).rename(columns={'name1':'name'})
Michael H.

và hơn nữa, làm thế nào để làm điều này bằng cách sử dụng chỉ mục. Dường như không hoạt động nếu 'name' là chỉ mục và không phải là tên cột.
Brian D

85

Đây là một tình huống lý tưởng cho join phương pháp

Các join phương pháp được xây dựng chính xác cho các loại tình huống. Bạn có thể tham gia bất kỳ số lượng DataFrames nào cùng với nó. DataFrame gọi tham gia với chỉ mục của bộ sưu tập DataFrames đã truyền. Để làm việc với nhiều DataFrames, bạn phải đặt các cột tham gia trong chỉ mục.

Mã sẽ trông giống như thế này:

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

Với dữ liệu của @ zero, bạn có thể làm điều này:

df1 = pd.DataFrame(np.array([
    ['a', 5, 9],
    ['b', 4, 61],
    ['c', 24, 9]]),
    columns=['name', 'attr11', 'attr12'])
df2 = pd.DataFrame(np.array([
    ['a', 5, 19],
    ['b', 14, 16],
    ['c', 4, 9]]),
    columns=['name', 'attr21', 'attr22'])
df3 = pd.DataFrame(np.array([
    ['a', 15, 49],
    ['b', 4, 36],
    ['c', 14, 9]]),
    columns=['name', 'attr31', 'attr32'])

dfs = [df1, df2, df3]
dfs = [df.set_index('name') for df in dfs]
dfs[0].join(dfs[1:])

     attr11 attr12 attr21 attr22 attr31 attr32
name                                          
a         5      9      5     19     15     49
b         4     61     14     16      4     36
c        24      9      4      9     14      9

4
Tham gia tất cả các dfs vào một khung dữ liệu trống cũng hoạt động : pd.DataFrame().join(dfs, how="outer"). Điều này có thể được sạch hơn trong một số tình huống.
Dominik

4
Đây là lời khuyên đúng đắn và hiện đã được tích hợp vào gấu trúc hợp nhất 101 (xem phần về hợp nhất nhiều dataframes). Điều đáng chú ý là nếu các khóa tham gia của bạn là duy nhất, việc sử dụng pd.concatsẽ dẫn đến cú pháp đơn giản hơn : pd.concat([df.set_index('name') for df in dfs], axis=1, join='inner').reset_index(). concatcũng linh hoạt hơn khi xử lý các tên cột trùng lặp trên nhiều dfs (điều joinnày không tốt lắm) mặc dù bạn chỉ có thể thực hiện các phép nối bên trong hoặc bên ngoài với nó.
cs95

dfs[0].join(dfs[1:])nên được chỉnh sửa dfs[0].join(dfs[1:], sort=False) bởi vì nếu không FutureWarningsẽ xuất hiện. Cảm ơn ví dụ tốt đẹp.
gies0r

Tôi gặp lỗi khi thử rằng: ValueError: Indexes have overlapping valuesmặc dù, bằng cách kiểm tra các tệp dữ liệu riêng lẻ trong danh sách, chúng dường như không có các giá trị chồng chéo.
SomJura

17

Điều này cũng có thể được thực hiện như sau cho một danh sách các dataframes df_list:

df = df_list[0]
for df_ in df_list[1:]:
    df = df.merge(df_, on='join_col_name')

hoặc nếu các dataframes nằm trong một đối tượng trình tạo (ví dụ để giảm mức tiêu thụ bộ nhớ):

df = next(df_list)
for df_ in df_list:
    df = df.merge(df_, on='join_col_name')

11

Trong python3.6.3 với pandas0.22.0, bạn cũng có thể sử dụng concatmiễn là bạn đặt làm chỉ mục cho các cột bạn muốn sử dụng để tham gia

pd.concat(
    (iDF.set_index('name') for iDF in [df1, df2, df3]),
    axis=1, join='inner'
).reset_index()

ở đâu df1, df2df3được định nghĩa như trong câu trả lời của John Galt

import pandas as pd
df1 = pd.DataFrame(np.array([
    ['a', 5, 9],
    ['b', 4, 61],
    ['c', 24, 9]]),
    columns=['name', 'attr11', 'attr12']
)
df2 = pd.DataFrame(np.array([
    ['a', 5, 19],
    ['b', 14, 16],
    ['c', 4, 9]]),
    columns=['name', 'attr21', 'attr22']
)
df3 = pd.DataFrame(np.array([
    ['a', 15, 49],
    ['b', 4, 36],
    ['c', 14, 9]]),
    columns=['name', 'attr31', 'attr32']
)

2
Đây phải là câu trả lời được chấp nhận. Đó là cách nhanh nhất.
R. Zhu

4

Người ta không cần multiindex để thực hiện các hoạt động tham gia . Người ta chỉ cần đặt chính xác cột chỉ mục để thực hiện các hoạt động nối (lệnh nàodf.set_index('Name') ví dụ )

Các joinhoạt động theo mặc định được thực hiện trên chỉ mục. Trong trường hợp của bạn, bạn chỉ cần xác định rằngName cột tương ứng với chỉ mục của bạn. Dưới đây là một ví dụ

Một hướng dẫn có thể hữu ích.

# Simple example where dataframes index are the name on which to perform the join operations
import pandas as pd
import numpy as np
name = ['Sophia' ,'Emma' ,'Isabella' ,'Olivia' ,'Ava' ,'Emily' ,'Abigail' ,'Mia']
df1 = pd.DataFrame(np.random.randn(8, 3), columns=['A','B','C'], index=name)
df2 = pd.DataFrame(np.random.randn(8, 1), columns=['D'],         index=name)
df3 = pd.DataFrame(np.random.randn(8, 2), columns=['E','F'],     index=name)
df = df1.join(df2)
df = df.join(df3)

# If you a 'Name' column that is not the index of your dataframe, one can set this column to be the index
# 1) Create a column 'Name' based on the previous index
df1['Name']=df1.index
# 1) Select the index from column 'Name'
df1=df1.set_index('Name')

# If indexes are different, one may have to play with parameter how
gf1 = pd.DataFrame(np.random.randn(8, 3), columns=['A','B','C'], index=range(8))
gf2 = pd.DataFrame(np.random.randn(8, 1), columns=['D'], index=range(2,10))
gf3 = pd.DataFrame(np.random.randn(8, 2), columns=['E','F'], index=range(4,12))

gf = gf1.join(gf2, how='outer')
gf = gf.join(gf3, how='outer')

4

Đây là một phương pháp để hợp nhất một từ điển các khung dữ liệu trong khi giữ cho các tên cột được đồng bộ hóa với từ điển. Ngoài ra, nó sẽ điền vào các giá trị còn thiếu nếu cần:

Đây là chức năng hợp nhất một khung dữ liệu

def MergeDfDict(dfDict, onCols, how='outer', naFill=None):
  keys = dfDict.keys()
  for i in range(len(keys)):
    key = keys[i]
    df0 = dfDict[key]
    cols = list(df0.columns)
    valueCols = list(filter(lambda x: x not in (onCols), cols))
    df0 = df0[onCols + valueCols]
    df0.columns = onCols + [(s + '_' + key) for s in valueCols] 

    if (i == 0):
      outDf = df0
    else:
      outDf = pd.merge(outDf, df0, how=how, on=onCols)   

  if (naFill != None):
    outDf = outDf.fillna(naFill)

  return(outDf)

OK, cho phép tạo dữ liệu và kiểm tra điều này:

def GenDf(size):
  df = pd.DataFrame({'categ1':np.random.choice(a=['a', 'b', 'c', 'd', 'e'], size=size, replace=True),
                      'categ2':np.random.choice(a=['A', 'B'], size=size, replace=True), 
                      'col1':np.random.uniform(low=0.0, high=100.0, size=size), 
                      'col2':np.random.uniform(low=0.0, high=100.0, size=size)
                      })
  df = df.sort_values(['categ2', 'categ1', 'col1', 'col2'])
  return(df)


size = 5
dfDict = {'US':GenDf(size), 'IN':GenDf(size), 'GER':GenDf(size)}   
MergeDfDict(dfDict=dfDict, onCols=['categ1', 'categ2'], how='outer', naFill=0)

3

Giải pháp đơn giản:

Nếu tên cột tương tự nhau:

 df1.merge(df2,on='col_name').merge(df3,on='col_name')

Nếu tên cột khác nhau:

df1.merge(df2,left_on='col_name1', right_on='col_name2').merge(df3,left_on='col_name1', right_on='col_name3').drop(columns=['col_name2', 'col_name3']).rename(columns={'col_name1':'col_name'})

2

Có một giải pháp khác từ tài liệu về gấu trúc (mà tôi không thấy ở đây),

sử dụng .append

>>> df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
   A  B
0  1  2
1  3  4
>>> df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
   A  B
0  5  6
1  7  8
>>> df.append(df2, ignore_index=True)
   A  B
0  1  2
1  3  4
2  5  6
3  7  8

Các ignore_index=True này được sử dụng để bỏ qua chỉ mục của khung dữ liệu được nối thêm, thay thế nó bằng chỉ mục tiếp theo có sẵn trong nguồn.

Nếu có tên cột khác nhau, Nansẽ được giới thiệu.


đó là ngữ nghĩa, đối với ai đó sử dụng từ "tham gia" để nói kết hợp hai khung dữ liệu. (không nhất thiết phải là hoạt động tham gia SQL)
Sylhare

1

Ba datafram là

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Hãy hợp nhất các khung này bằng cách sử dụng pd.merge lồng nhau

nhập mô tả hình ảnh ở đây

Ở đây chúng tôi đi, chúng tôi có khung dữ liệu hợp nhất của chúng tôi.

Phân tích hạnh phúc !!!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.