pandas สามทางเข้าร่วมหลาย dataframes ในคอลัมน์


191

ฉันมีไฟล์ CSV 3 ไฟล์ แต่ละคนมีคอลัมน์แรกเป็นชื่อ (สตริง) ของคนในขณะที่คอลัมน์อื่น ๆ ทั้งหมดในแต่ละ dataframe เป็นคุณลักษณะของบุคคลนั้น

ฉันจะ "เข้าร่วม" ร่วมกันทั้งสามเอกสาร CSV เพื่อสร้าง CSV เดียวกับแต่ละแถวที่มีแอตทริบิวต์ทั้งหมดสำหรับแต่ละค่าที่ไม่ซ้ำกันของชื่อสตริงของบุคคลได้อย่างไร

join()ฟังก์ชั่นในหมีแพนด้าระบุว่าฉันต้อง multiindex แต่ฉันสับสนเกี่ยวกับสิ่งที่เป็นโครงการที่จัดทำดัชนีลำดับชั้นจะทำอย่างไรกับการทำเข้าร่วมอยู่บนพื้นฐานของดัชนีเดียว


2
คุณไม่จำเป็นต้องมีหลายดัชนี มันระบุในเอกสารการเข้าร่วมที่คุณไม่มี multiindex เมื่อผ่านหลายคอลัมน์เพื่อเข้าร่วมแล้วมันจะจัดการกับมัน
cwharland

1
ในการทดลองของฉันdf1.join([df2, df3], on=[df2_col1, df3_col1])ไม่ทำงาน
lollercoaster

คุณต้องโยงมันเข้าด้วยกันเหมือนในคำตอบที่ให้ ผสาน df1 และ df2 แล้วรวมผลลัพธ์กับ df3
cwharland

คำตอบ:


475

สันนิษฐานการนำเข้า:

import pandas as pd

คำตอบของ John Galtนั้นเป็นการreduceผ่าตัด หากฉันมีมากกว่าหนึ่งดาต้าเฟรมเราจะใส่ไว้ในรายการเช่นนี้ (สร้างจากความเข้าใจในรายการหรือลูปหรืออะไรก็ตาม):

dfs = [df0, df1, df2, dfN]

สมมติว่าพวกเขามีคอลัมน์ทั่วไปบางอย่างเช่นnameในตัวอย่างของคุณฉันจะทำต่อไปนี้:

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

ด้วยวิธีนี้รหัสของคุณควรทำงานกับดาต้าเบสจำนวนเท่าใดก็ได้ที่คุณต้องการผสาน

แก้ไข 1 สิงหาคม 2559 : สำหรับผู้ที่ใช้ Python 3: reduceถูกย้ายไปfunctoolsแล้ว ดังนั้นในการใช้ฟังก์ชั่นนี้คุณจะต้องนำเข้าโมดูลนั้นก่อน:

from functools import reduce

11
ฉันเพิ่งลองใช้สิ่งนี้และมันล้มเหลวเพราะreduceถูกแทนที่ด้วยfunctools.reduceSoimport functools functools.reduce(.......)
MattR

3
โซลูชันนี้จะทำงานอย่างไรถ้าฉันชื่อของเขตข้อมูลที่จะเข้าร่วมแตกต่างกันอย่างไร ยกตัวอย่างเช่นในสามเฟรมข้อมูลฉันสามารถมีname1, name2และname3ตามลำดับ
ps0604

2
นี่ไม่ได้หมายความว่าเรามีการn-1เรียกไปยังฟังก์ชั่นการผสานหรือไม่? ฉันเดาว่าในกรณีนี้ที่จำนวนของ dataframes มีขนาดเล็กมันก็ไม่สำคัญ แต่ฉันสงสัยว่ามีวิธีแก้ปัญหาที่ปรับขนาดได้มากกว่านี้หรือไม่
eapolinario

1
สิ่งนี้ไม่ได้ผลสำหรับdfคอลัมน์ดัชนีหลายคอลัมน์ของฉัน(มันเป็นการฉีด 'on' เป็นคอลัมน์ที่ทำงานในการผสานแรก แต่การรวมที่ตามมาล้มเหลว) แทนที่จะให้ทำงานกับ:df = reduce(lambda left, right: left.join(right, how='outer', on='Date'), dfs)
Adrian Torrie

+1 ถึง ps0604 จะเกิดอะไรขึ้นถ้าคอลัมน์การรวมแตกต่างกันทำงานได้ไหม เราควรไปด้วย pd.merge กรณีคอลัมน์รวมแตกต่างกันหรือไม่ ขอบคุณ
สตีฟ

106

คุณสามารถลองใช้สิ่งนี้หากคุณมี 3 ดาต้าเฟรม

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

อีกวิธีหนึ่งดังกล่าวโดย cwharland

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

34
เพื่อรูปลักษณ์ที่สะอาดกว่าคุณสามารถdf1.merge(df2,on='name').merge(df3,on='name')
โยง

1
โซลูชันนี้จะทำงานอย่างไรถ้าฉันชื่อของเขตข้อมูลที่จะเข้าร่วมแตกต่างกันอย่างไร ยกตัวอย่างเช่นในสามเฟรมข้อมูลฉันสามารถมีname1, name2และname3ตามลำดับ
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.

และเพิ่มเติมวิธีการทำเช่นนี้โดยใช้ดัชนี ดูเหมือนจะไม่ทำงานหาก 'name' เป็นดัชนีและไม่ใช่ชื่อคอลัมน์
Brian D

85

นี่เป็นสถานการณ์ที่เหมาะสำหรับjoinวิธีการ

joinวิธีการที่ถูกสร้างขึ้นว่าสำหรับประเภทนี้สถานการณ์ คุณสามารถเข้าร่วม DataFrames ได้ไม่ จำกัด จำนวน การเรียก DataFrame รวมกับดัชนีของการรวบรวม DataFrames ที่ผ่านไปแล้ว ในการทำงานกับ DataFrames หลายตัวคุณต้องใส่คอลัมน์การเข้าร่วมในดัชนี

รหัสจะมีลักษณะดังนี้:

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

ด้วยข้อมูลของ @ zero คุณสามารถทำได้:

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
เข้าร่วมทั้งหมดของ DFS ไปยัง dataframe pd.DataFrame().join(dfs, how="outer")ที่ว่างเปล่ายังทำงาน: สิ่งนี้อาจสะอาดกว่าในบางสถานการณ์
Dominik

4
นี่เป็นคำแนะนำที่ดีและตอนนี้ได้รวมอยู่ในการรวมของ pandas 101 (ดูหัวข้อการรวมหลาย dataframes) มันเป็นมูลค่า noting ว่าถ้าปุ่มเข้าร่วมของคุณจะไม่ซ้ำกันใช้จะมีผลในไวยากรณ์ง่าย:pd.concat มีความหลากหลายมากขึ้นเมื่อจัดการกับชื่อคอลัมน์ที่ซ้ำกันในหลาย ๆ dfs ( ไม่ดีเท่านี้) แม้ว่าคุณจะสามารถทำการรวมภายในหรือภายนอกได้เท่านั้น pd.concat([df.set_index('name') for df in dfs], axis=1, join='inner').reset_index()concatjoin
cs95

dfs[0].join(dfs[1:])ควรได้รับการแก้ไขdfs[0].join(dfs[1:], sort=False) เพราะมิฉะนั้นFutureWarningจะปรากฏขึ้น ขอบคุณสำหรับตัวอย่างที่ดี
gies0r

ฉันได้รับข้อผิดพลาดในการลองใช้: ValueError: Indexes have overlapping valuesแม้ว่าโดยการตรวจสอบแต่ละ dataframes ในรายการพวกเขาดูเหมือนจะไม่มีค่าที่ทับซ้อนกัน
SomJura

17

สิ่งนี้สามารถทำได้ดังต่อไปนี้สำหรับรายการของ dataframes df_list:

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

หรือถ้า dataframes อยู่ในวัตถุ generator (เช่นเพื่อลดการใช้หน่วยความจำ):

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

11

ในpython3.6.3 ด้วยpandas0.22.0 คุณสามารถใช้concatตราบใดที่คุณกำหนดเป็นดัชนีคอลัมน์ที่คุณต้องการใช้สำหรับการเข้าร่วม

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

ที่df1, df2และdf3มีการกำหนดในคำตอบของจอห์น 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
นี่ควรเป็นคำตอบที่ยอมรับได้ มันเร็วที่สุด
R. Zhu

4

ไม่จำเป็นต้อง multiindex เพื่อดำเนินการเข้าร่วมการดำเนินงาน คุณเพียงแค่ต้องตั้งค่าคอลัมน์ดัชนีอย่างถูกต้องเพื่อดำเนินการเข้าร่วม ( df.set_index('Name')เช่นคำสั่งใด)

การjoinดำเนินการโดยค่าเริ่มต้นดำเนินการกับดัชนี ในกรณีของคุณคุณต้องระบุว่าNameคอลัมน์นั้นตรงกับดัชนีของคุณ ด้านล่างเป็นตัวอย่าง

กวดวิชาอาจจะมีประโยชน์

# 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

นี่คือวิธีการรวมพจนานุกรมของเฟรมข้อมูลในขณะที่รักษาชื่อคอลัมน์ให้สอดคล้องกับพจนานุกรม นอกจากนี้ยังเติมเต็มค่าที่ขาดหายไปหากต้องการ:

นี่คือฟังก์ชั่นในการรวมชุดข้อมูลต่างๆ

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)

ตกลงให้สร้างข้อมูลและทดสอบสิ่งนี้:

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

วิธีแก้ปัญหาง่าย ๆ :

หากชื่อคอลัมน์คล้ายกัน:

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

หากชื่อคอลัมน์แตกต่าง:

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

มีวิธีแก้ไขปัญหาอื่นจากเอกสารแพนด้า (ที่ฉันไม่เห็นที่นี่)

ใช้ .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

ignore_index=Trueจะใช้ในการละเว้นดัชนีของ dataframe ท้ายแทนที่มันด้วยดัชนีถัดไปที่มีอยู่ในแหล่งหนึ่ง

หากมีชื่อคอลัมน์ที่แตกต่างกันNanจะมีการแนะนำ


มันมีความหมายสำหรับคนที่ใช้คำว่า "เข้าร่วม" เพื่อบอกว่ารวบรวม dataframe ทั้งสองไว้ด้วยกัน (ไม่จำเป็นเหมือนการดำเนินการเข้าร่วม SQL)
Sylhare

1

สาม dataframes คือ

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

มารวมเฟรมเหล่านี้โดยใช้ pd.merge ที่ซ้อนกัน

ป้อนคำอธิบายรูปภาพที่นี่

ที่นี่เราไปเรามี dataframe ที่ผสานของเรา

การวิเคราะห์ที่มีความสุข !!!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.