列上の複数のデータフレームを結合するパンダ


191

3つのCSVファイルがあります。各列の最初の列は(文字列)人の名前ですが、各データフレームの他のすべての列はその人の属性です。

3つのCSVドキュメントすべてを「結合」して、各行に人物の文字列名の一意の値ごとにすべての属性を持つ単一のCSVを作成するにはどうすればよいですか?

join()パンダの関数は、マルチインデックスが必要であることを指定していますが、階層インデックススキーマが単一のインデックスに基づいて結合を行うこととどのように関係しているのか混乱しています。


2
マルチインデックスは必要ありません。結合ドキュメントには、結合する複数の列を渡すときにマルチインデックスがないと記載されているため、それが処理されます。
cwharland 2014年

1
私の裁判でdf1.join([df2, df3], on=[df2_col1, df3_col1])は、うまくいきませんでした。
Lollercoaster 2014年

あなたは与えられた答えのようにそれらを一緒にチェーンする必要があります。df1とdf2をマージしてから、結果をdf3とマージします
cwharland

回答:


472

想定される輸入:

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)

このようにして、マージするデータフレームの数に関係なくコードを機能させる必要があります。

2016年8月1日編集:Python 3を使用しreduceている場合:に移動しましたfunctools。したがって、この関数を使用するには、まずそのモジュールをインポートする必要があります。

from functools import reduce

11
これを使ってみたところreducefunctools.reduceSo に置き換えられたため失敗しましたimport functools functools.reduce(.......)
MattR

3
結合するフィールドの名前が異なる場合、このソリューションはどのように機能しますか?たとえば、3つのデータフレームでname1name2とをname3それぞれ持つことができます。
ps0604 2018

2
これはn-1、merge関数の呼び出しがあることを意味しませんか?この場合、データフレームの数が少ない場合は問題ないと思いますが、もっとスケーラブルなソリューションがあるかどうか疑問に思います。
eapolinario

1
これは非常に私のために動作しませんでしたdf代わりに、私はで動作するようにそれを得た、列マルチインデックスとS(それは最初のマージのために働いたが、その後のマージが失敗した列としての「上」を注入した):df = reduce(lambda left, right: left.join(right, how='outer', on='Date'), dfs)
エイドリアン・トリー

+ 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
結合するフィールドの名前が異なる場合、このソリューションはどのように機能しますか?たとえば、3つのデータフレームname1name2name3それぞれと
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'がインデックスであり、列名ではない場合は機能しないようです。
ブライアンD

85

これはjoinメソッドにとって理想的な状況です

joinこの方法は、正確な状況のこれらのタイプのために構築されています。データフレームはいくつでも結合できます。呼び出し側のDataFrameは、渡されたDataFrameのコレクションのインデックスと結合します。複数のデータフレームを使用するには、結合列をインデックスに配置する必要があります。

コードは次のようになります。

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
すべてのdfを空のデータフレームに結合することも機能しますpd.DataFrame().join(dfs, how="outer")。これは、状況によってはよりクリーンになる場合があります。
ドミニク

4
これはまともなアドバイスであり、101をマージするパンダに組み込まれました(複数のデータフレームのマージに関するセクションを参照してください)。結合キーが一意である場合、を使用pd.concatすると構文が単純になることに注意してくださいpd.concat([df.set_index('name') for df in dfs], axis=1, join='inner').reset_index()concat複数のdf間で重複する列名を処理する場合(これjoinはあまり得意ではありませんが)もより汎用性がありますが、内部結合または外部結合しか実行できません。
cs95

dfs[0].join(dfs[1:])dfs[0].join(dfs[1:], sort=False) そうしないFutureWarningとポップアップするため、編集する必要があります。良い例をありがとう。
gies0r

試行するとエラーが発生しますValueError: Indexes have overlapping values。ただし、リスト内の個々のデータフレームを調べたところ、値が重複していないようです。
ソムジュラ

17

これは、データフレームのリストについて次のように行うこともできますdf_list

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

または、データフレームがジェネレータオブジェクト内にある場合(メモリ消費を削減するためなど):

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およびdf3John 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.

4

結合操作を実行するためにマルチインデックスは必要ありません。結合操作を実行するインデックス列を正しく設定する必要があります(どのコマンド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)

OK、データを生成してこれをテストしましょう:

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ソースいずれかで利用可能な次のインデックスに置き換える、添付データフレームのインデックスを無視するために使用されます。

異なる列名がある場合Nanは、導入されます。


「結合」という言葉を使って2つのデータフレームをまとめるという意味では、これはセマンティックです。(SQL結合操作として必ずしも必要ではありません)
Sylhare、2018年

1

3つのデータフレームは

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ネストされたpd.mergeを使用してこれらのフレームをマージしましょう

ここに画像の説明を入力してください

さて、マージされたデータフレームがあります。

ハッピー分析!!!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.