pandas three-way joining multiple dataframes on columns
我有3个CSV文件。 每个都有第一列作为人的(字符串)名称,而每个数据框中的所有其他列都是该人的属性。
如何将所有三个CSV文档"连接"在一起以创建单个CSV,每行具有该人员字符串名称的每个唯一值的所有属性?
pandas中的
假定进口:
1 | import pandas as pd |
John Galt的答案基本上是一个
1 | dfs = [df0, df1, df2, dfN] |
假设他们有一些共同的列,比如示例中的
1 | df_final = reduce(lambda left,right: pd.merge(left,right,on='name'), dfs) |
这样,您的代码应该与您要合并的任意数量的数据帧一起使用。
编辑2016年8月1日:对于使用Python 3的用户:
1 | from functools import reduce |
如果您有3个数据帧,可以试试这个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 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所述
1 | df1.merge(df2,on='name').merge(df3,on='name') |
这是
代码看起来像这样:
1 2 3 | filenames = ['fn1', 'fn2', 'fn3', 'fn4',....] dfs = [pd.read_csv(filename, index_col=index_col) for filename in filenames)] dfs[0].join(dfs[1:]) |
使用@ zero的数据,您可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 |
对于数据帧
1 2 3 | df = df_list[0] for df_ in df_list[1:]: df = df.merge(df_, on='join_col_name') |
或者如果数据帧在生成器对象中(例如,为了减少内存消耗):
1 2 3 | df = next(df_list) for df_ in df_list: df = df.merge(df_, on='join_col_name') |
在
1 2 3 4 | pd.concat( (iDF.set_index('name') for iDF in [df1, df2, df3]), axis=1, join='inner' ).reset_index() |
其中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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'] ) |
这是一种合并数据帧字典同时保持列名与字典同步的方法。如果需要,它还会填写缺失值:
这是合并数据帧的dict的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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) |
好的,让我们生成数据并测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) |
一个不需要多索引来执行连接操作。
只需要正确设置执行连接操作的索引列(例如,命令
默认情况下,对索引执行
在您的情况下,您只需指定
以下是一个例子
教程可能很有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 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') |
pandas文档还有另一个解决方案(我在这里看不到),
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> 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 |
如果有不同的列名,将引入
简单解决方案
如果列名相似:
1 | df1.merge(df2,on='col_name').merge(df3,on='col_name') |
如果列名不同:
1 | 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'}) |