pandalar üç yönlü sütunlarda birden fazla veri karesini birleştirme


191

3 CSV dosyam var. Her biri, insanların (dize) adları olarak ilk sütuna sahipken, her veri çerçevesindeki diğer tüm sütunlar o kişinin nitelikleridir.

Her satır, kişinin dize adının her benzersiz değeri için tüm özniteliklere sahip tek bir CSV oluşturmak için üç CSV belgesinin tümünü birlikte nasıl birleştirebilirim?

join()Pandalar belirtiyorsa fonksiyonu bir multiindex gerektiğini, ancak bir hiyerarşik indeksleme şeması tek endeksine dayalı katılmak yapma ile ne ilgisi olduğunu hakkında karıştı.


2
Çoklu dizine ihtiyacınız yok. Birleştirme belgelerinde, katılmak için birden fazla sütun geçirirken çok endeksli olmadığınızı belirtir ve bunu halleder.
cwharland

1
Denemelerimde df1.join([df2, df3], on=[df2_col1, df3_col1])işe yaramadı.
lollercoaster

Verilen cevaptaki gibi onları birbirine zincirlemelisiniz. Df1 ve df2'yi birleştirin ve sonucu df3 ile birleştirin
cwharland

Yanıtlar:


475

Varsayılan ithalat:

import pandas as pd

John Galt'in cevabı temelde bir reduceoperasyon. Bir avuç birden fazla veri kareniz varsa, bunları (liste kavrayışları veya döngüler veya oluşturulan değil) tarafından oluşturulan bir listeye koyarım:

dfs = [df0, df1, df2, dfN]

Örneğinizde olduğu gibi bazı ortak sütunları olduğunu varsayarsak name, aşağıdakileri yaparım:

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

Bu şekilde, kodunuz birleştirmek istediğiniz sayıda veri çerçevesiyle çalışmalıdır.

1 Ağustos 2016'yı düzenleyin : Python 3'ü kullananlar için: reduceiçine taşındı functools. Bu işlevi kullanmak için, önce bu modülü içe aktarmanız gerekir:

from functools import reduce

11
Çünkü sadece bu kullanmayı denedim ve başarısız reduceile değiştirildi functools.reduceSoimport functools functools.reduce(.......)
MattR

3
Katılmak için alan adlarının farklı olması durumunda bu çözüm nasıl çalışır? Örneğin, üç veri çerçeveleri I olabilir name1, name2ve name3sırasıyla.
ps0604

2
Bu n-1, birleştirme işlevine çağrı yaptığımız anlamına gelmiyor mu? Bu durumda veri karelerinin sayısının az olduğu bu durumda önemli değil, ama daha ölçeklenebilir bir çözüm olup olmadığını merak ediyorum.
eapolinario

1
Bu dfsütun çok dizinleri ile benim için oldukça işe yaramadı (ilk birleştirme için çalışan bir sütun olarak 'on' enjekte edildi, ancak sonraki birleştirme başarısız oldu), bunun yerine ile çalıştım:df = reduce(lambda left, right: left.join(right, how='outer', on='Date'), dfs)
Adrian Torrie

+ 1'den ps0604'e. birleştirme sütunları farklıysa, bu işe yarar mı? birleştirme sütunları farklıysa pd.merge ile gitmeli miyiz? teşekkürler
steve

106

3 veri çerçeveniz varsa bunu deneyebilirsiniz

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

alternatif olarak, cwharland tarafından belirtildiği gibi

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

34
Daha temiz görünüm için onları zincirleyebilirsiniz df1.merge(df2,on='name').merge(df3,on='name')
cwharland

1
Katılmak için alan adlarının farklı olması durumunda bu çözüm nasıl çalışır? Örneğin, üç veri çerçeveleri I olabilir name1, name2ve name3sırasıyla
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.

ve ayrıca, endeksi kullanarak bunu nasıl yapacağınızı. 'Name', bir sütun adı değil, dizinse işe yaramıyor gibi görünüyor.
Brian D

85

Bu ideal bir durumdur joinyöntemle

joinYöntem aynen durumlarda bu tür için üretilmiştir. Bununla birlikte istediğiniz sayıda DataFrame'e katılabilirsiniz. Çağıran DataFrame, iletilen DataFrames koleksiyonunun diziniyle birleşir. Birden çok DataFrame ile çalışmak için birleştirme sütunlarını dizine koymanız gerekir.

Kod şöyle görünecektir:

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

@ Zero'nun verileriyle şunları yapabilirsiniz:

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
Ayrıca boş dataframe DFS tüm Katılma çalışır: pd.DataFrame().join(dfs, how="outer"). Bu bazı durumlarda daha temiz olabilir.
Dominik

4
Bu iyi bir tavsiyedir ve şimdi 101 birleştirme pandalarına dahil edilmiştir (birden fazla veri çerçevesinin birleştirilmesi bölümüne bakınız). Senin katılmak anahtarları benzersiz ise, kullanan belirterek It değerinde pd.concatdaha basit sözdizimi neden olacaktır: pd.concat([df.set_index('name') for df in dfs], axis=1, join='inner').reset_index(). concatbirden çok dfs'de yinelenen sütun adları ile uğraşırken daha çok yönlüdür ( joinbu kadar iyi değildir), ancak yalnızca iç veya dış birleşimleri gerçekleştirebilirsiniz.
cs95

dfs[0].join(dfs[1:])düzenlenmelidir dfs[0].join(dfs[1:], sort=False) çünkü aksi takdirde bir FutureWarningirade açılır. Güzel örnek için teşekkürler.
gies0r

Bunu denemede bir hata alıyorum: ValueError: Indexes have overlapping valuesancak, listedeki ayrı veri çerçevelerini inceleyerek çakışan değerlere sahip görünmüyorlar.
SomJura

17

Bu, veri çerçeveleri listesi için aşağıdaki gibi de yapılabilir df_list:

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

veya veri çerçeveleri bir jeneratör nesnesindeyse (örneğin bellek tüketimini azaltmak için):

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

11

In python3.6.3 ile pandas0.22.0 de kullanabilirsiniz concatdizine gibi katıldığınız için kullanmak istediğiniz sütunları set sürece

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

nerede df1, df2ve John Galt'ın cevabındakidf3 gibi tanımlanır

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
Bu kabul edilen cevap olmalı. En hızlısı.
R. Zhu

4

Bir gerçekleştirmek için bir multiindex gerekmez katılmak işlemleri. Birleştirme işlemlerinin gerçekleştirileceği dizin sütununu doğru bir şekilde ayarlamanız gerekir ( df.set_index('Name')örneğin, hangi komut )

İşlem joinvarsayılan olarak dizin üzerinde gerçekleştirilir. Sizin durumunuzda, Namesütunun dizininize karşılık geldiğini belirtmeniz yeterlidir. Aşağıda bir örnek var

Bir öğretici faydalı olabilir.

# 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

Sütun adlarını sözlükle senkronize tutarken veri çerçeveleri sözlüğünü birleştirmek için bir yöntem. Ayrıca gerekirse eksik değerleri de doldurur:

Bu, veri çerçevelerinin bir diksiyonunu birleştirme işlevidir

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)

Tamam, veri üretelim ve bunu test edelim:

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

Basit Çözüm:

Sütun adları benzerse:

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

Sütun adları farklıysa:

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

Panda belgelerinden başka bir çözüm daha var (burada göremiyorum),

kullanmak .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 , ekli veri çerçevesinin dizinini yok saymak ve onu kaynaktaki bir sonraki dizinle değiştirmek için kullanılır.

Farklı sütun adları varsa Nantanıtılacaktır.


anlamsaldır, "birleştirme" sözcüğünü kullanan birinin iki veri çerçevesini bir araya getirmesini söylemesi. (mutlaka SQL birleştirme işlemi olarak değil)
Sylhare

1

Üç veri çerçevesi

resim açıklamasını buraya girin

resim açıklamasını buraya girin

Bu çerçeveleri iç içe pd.merge kullanarak birleştirelim

resim açıklamasını buraya girin

İşte başlıyoruz, birleştirilmiş veri çerçevemiz var.

Mutlu Analizler !!!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.