pandas三向连接列上的多个数据帧

时间:2014-05-15 02:51:41

标签: python pandas join merge

我有3个CSV文件。每个都有第一列作为人的(字符串)名称,而每个数据框中的所有其他列都是该人的属性。

我怎样才能加入"将所有三个CSV文档组合在一起创建一个CSV,每行包含该人的字符串名称的每个唯一值的所有属性?

pandas中的join()函数指定我需要一个多索引,但我对层次索引方案与基于单个索引进行连接有什么关系感到困惑。

11 个答案:

答案 0 :(得分:357)

假定进口:

import pandas as pd

John Galt's answer基本上是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

答案 1 :(得分:78)

如果你有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')

答案 2 :(得分:27)

这是join方法

的理想情况

join方法专为这些类型的情况而构建。您可以与它一起加入任意数量的DataFrame。调用DataFrame与传递的DataFrames集合的索引相连接。要使用多个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

答案 3 :(得分:15)

对于数据框列表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')

答案 4 :(得分:5)

python 3.6.3和pandas 0.22.0中,只要将要用于联接的列设置为索引,您也可以使用concat

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

其中df1df2df3的定义如John Galt's answer

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

答案 5 :(得分:3)

一个不需要多索引来执行join操作。 只需要正确设置执行连接操作的索引列(例如,命令df.set_index('Name')

默认情况下,对{s}}操作执行索引。 在您的情况下,您只需指定join列对应于您的索引。 以下是一个例子

tutorial可能有用。

Name

答案 6 :(得分:3)

这是一种合并数据帧字典同时保持列名与字典同步的方法。如果需要,它还会填写缺失值:

这是合并数据帧dict的函数

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)

答案 7 :(得分:2)

pandas documentation还有另一个解决方案(我不会在这里看到),

使用.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

答案 8 :(得分:2)

三个数据帧是

enter image description here

enter image description here

让我们使用嵌套的pd.merge合并这些框架

enter image description here

在这里,我们有合并的数据框。

快乐分析!

答案 9 :(得分:0)

简单解决方案:

如果列名相似:

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

答案 10 :(得分:0)

我调整了可接受的答案以使用suffix在不同的reduce参数上对多个数据帧执行操作,我想它也可以扩展到不同的on参数。

from functools import reduce 

dfs_with_suffixes = [(df2,suffix2), (df3,suffix3), 
                     (df4,suffix4)]

merge_one = lambda x,y,sfx:pd.merge(x,y,on=['col1','col2'..], suffixes=sfx)

merged = reduce(lambda left,right:merge_one(left,*right), dfs_with_suffixes, df1)