panda tiga arah bergabung dengan banyak dataframe pada kolom

191

Saya memiliki 3 file CSV. Masing-masing memiliki kolom pertama sebagai nama (string) orang, sedangkan semua kolom lainnya di setiap bingkai data adalah atribut orang tersebut.

Bagaimana saya bisa "bergabung" bersama ketiga dokumen CSV untuk membuat CSV tunggal dengan setiap baris memiliki semua atribut untuk setiap nilai unik dari nama string seseorang?

The join()fungsi dalam panda menetapkan bahwa saya perlu multiindex, tapi aku bingung tentang apa skema pengindeksan hirarkis harus dilakukan dengan membuat bergabung berdasarkan indeks tunggal.

lollercoaster
sumber
2
Anda tidak perlu multiindex. Ini menyatakan dalam dokumen join bahwa Anda tidak memiliki multiindex ketika melewati beberapa kolom untuk bergabung maka itu akan menangani itu.
cwharland
1
Dalam cobaan saya, df1.join([df2, df3], on=[df2_col1, df3_col1])tidak berhasil.
lollercoaster
Anda perlu merantai mereka seperti dalam jawaban yang diberikan. Gabungkan df1 dan df2 lalu gabungkan hasilnya dengan df3
cwharland

Jawaban:

475

Impor yang diasumsikan:

import pandas as pd

Jawaban John Galt pada dasarnya adalah reduceoperasi. Jika saya memiliki lebih dari beberapa dataframe, saya akan meletakkannya dalam daftar seperti ini (dihasilkan melalui pemahaman daftar atau loop atau yang lainnya):

dfs = [df0, df1, df2, dfN]

Dengan asumsi mereka memiliki beberapa kolom umum, seperti namepada contoh Anda, saya akan melakukan hal berikut:

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

Dengan begitu, kode Anda harus bekerja dengan jumlah bingkai data berapa pun yang ingin Anda gabungkan.

Edit 1 Agustus 2016 : Bagi mereka yang menggunakan Python 3: reducetelah dipindahkan ke functools. Jadi untuk menggunakan fungsi ini, pertama-tama Anda harus mengimpor modul itu:

from functools import reduce
Kit
sumber
11
Saya hanya mencoba menggunakan ini dan gagal karena reducediganti dengan functools.reduceSoimport functools functools.reduce(.......)
MattR
3
Bagaimana solusi ini bekerja jika saya nama-nama bidang untuk bergabung berbeda? Misalnya, dalam tiga kerangka data yang saya bisa miliki name1, name2dan name3masing - masing.
ps0604
2
Tidakkah ini berarti bahwa kita memiliki n-1panggilan ke fungsi penggabungan? Saya kira dalam hal ini di mana jumlah dataframe kecil itu tidak masalah, tapi saya ingin tahu apakah ada solusi yang lebih scalable.
eapolinario
1
Ini tidak cukup untuk saya dfdengan kolom multi indeks (itu menyuntikkan 'on' sebagai kolom yang bekerja untuk penggabungan pertama, tetapi penggabungan berikutnya gagal), alih-alih saya membuatnya bekerja dengan:df = reduce(lambda left, right: left.join(right, how='outer', on='Date'), dfs)
Adrian Torrie
+1 ke ps0604. bagaimana jika kolom gabungan berbeda, apakah ini berfungsi? kita harus pergi dengan pd.merge memetikan kolom bergabung berbeda? terima kasih
steve
106

Anda dapat mencoba ini jika Anda memiliki 3 kerangka data

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

alternatifnya, seperti yang disebutkan oleh cwharland

df1.merge(df2,on='name').merge(df3,on='name')
Nol
sumber
34
Untuk penampilan yang lebih bersih, Anda dapat df1.merge(df2,on='name').merge(df3,on='name')
mengaitkannya
1
Bagaimana solusi ini bekerja jika saya nama-nama bidang untuk bergabung berbeda? Misalnya, dalam tiga kerangka data yang saya bisa miliki name1, name2dan name3masing
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.
dan selanjutnya, bagaimana melakukan ini menggunakan indeks. Tampaknya tidak berfungsi jika 'nama' adalah indeks dan bukan nama kolom.
Brian D
85

Ini adalah situasi yang ideal untuk joinmetode ini

The joinMetode ini dibangun tepat untuk jenis situasi. Anda dapat bergabung dengan sejumlah DataFrames bersama dengannya. DataFrame panggilan bergabung dengan indeks koleksi DataFrames yang disahkan. Untuk bekerja dengan beberapa DataFrames, Anda harus meletakkan kolom yang bergabung dalam indeks.

Kode akan terlihat seperti ini:

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

Dengan data nol, Anda dapat melakukan ini:

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
Ted Petrou
sumber
4
Bergabung semua DFS ke dataframe kosong juga bekerja: pd.DataFrame().join(dfs, how="outer"). Ini bisa lebih bersih dalam beberapa situasi.
Dominik
4
Ini adalah saran yang layak dan sekarang telah dimasukkan ke dalam panda yang menggabungkan 101 (lihat bagian tentang menggabungkan beberapa kerangka data). Itu perlu dicatat bahwa jika kunci bergabung Anda yang unik, menggunakan pd.concatakan menghasilkan sintaks sederhana: pd.concat([df.set_index('name') for df in dfs], axis=1, join='inner').reset_index(). concatjuga lebih fleksibel ketika berhadapan dengan nama kolom duplikat di beberapa dfs ( jointidak sebagus ini) meskipun Anda hanya dapat melakukan bergabung dalam atau luar dengan itu.
cs95
dfs[0].join(dfs[1:])harus diedit dfs[0].join(dfs[1:], sort=False) karena jika tidak FutureWarningkehendak muncul. Terima kasih untuk contoh yang bagus.
gies0r
Saya mendapatkan kesalahan saat mencoba itu ValueError: Indexes have overlapping values:, meskipun, dengan memeriksa masing-masing kerangka data dalam daftar, mereka tampaknya tidak memiliki nilai yang tumpang tindih.
SomJura
17

Ini juga dapat dilakukan sebagai berikut untuk daftar kerangka data df_list:

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

atau jika kerangka data berada dalam objek generator (mis. untuk mengurangi konsumsi memori):

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

Di python3.6.3 dengan pandas0.22.0 Anda juga dapat menggunakan concatselama Anda menetapkan indeks kolom yang ingin Anda gunakan untuk bergabung

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

dimana df1,, df2dan df3didefinisikan seperti dalam jawaban 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']
)
Igor Fobia
sumber
2
Ini harus menjadi jawaban yang diterima. Ini yang tercepat.
R. Zhu
4

Seseorang tidak memerlukan multiindex untuk melakukan operasi gabungan . Satu hanya perlu mengatur dengan benar kolom indeks untuk melakukan operasi gabungan (perintah yang df.set_index('Name')misalnya)

The joinoperasi secara default dilakukan pada indeks. Dalam kasus Anda, Anda hanya perlu menentukan bahwa Namekolom tersebut sesuai dengan indeks Anda. Di bawah ini adalah contohnya

Sebuah tutorial mungkin berguna.

# 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')
Guillaume Jacquenot
sumber
4

Berikut adalah metode untuk menggabungkan kamus bingkai data sambil tetap menyinkronkan nama kolom dengan kamus. Juga mengisi nilai yang hilang jika diperlukan:

Ini adalah fungsi untuk menggabungkan dict dari frame data

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)

Oke, mari kita hasilkan data dan uji ini:

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)
rz1317
sumber
3

Solusi sederhana:

Jika nama kolom serupa:

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

Jika nama kolom berbeda:

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'})
Gil Baggio
sumber
2

Ada solusi lain dari dokumentasi panda (yang tidak saya lihat di sini),

menggunakan .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

Yang ignore_index=Truedigunakan untuk mengabaikan indeks dari dataframe ditambahkan, menggantinya dengan indeks yang tersedia berikutnya dalam satu sumber.

Jika ada nama kolom yang berbeda, Nanakan diperkenalkan.

Sylhare
sumber
itu semantik, bagi seseorang yang menggunakan kata "gabung" untuk mengatakan menyusun dua kerangka data. (tidak perlu sebagai SQL bergabung operasi)
Sylhare
1

Tiga kerangka data adalah

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Mari kita gabungkan frame ini menggunakan pd.merge bersarang

masukkan deskripsi gambar di sini

Di sini kita pergi, kita memiliki kerangka data gabungan kami.

Analisis Selamat !!!

decision_scientist_noah
sumber