Pandas:合并多个数据框并控制列名?

6
我可以帮你将九个Pandas数据框合并成一个数据框,通过两列进行连接,并控制列名。这个可行吗?
我有九个数据集,它们都有以下列:
org, name, items,spend

我希望将它们合并成一个单独的数据框,包含以下列:

org, name, items_df1, spend_df1, items_df2, spend_df2, items_df3...

我一直在阅读关于合并和连接的文档。我目前可以像这样合并两个数据集:

ad = pd.DataFrame.merge(df_presents, df_trees,
                        on=['practice', 'name'],
                        suffixes=['_presents', '_trees'])

这很好用,执行 print list(aggregate_data.columns.values) 后会显示以下列:

[org', u'name', u'spend_presents', u'items_presents', u'spend_trees', u'items_trees'...]

但是如果我有九列要这样做怎么办? merge只能一次合并两列,如果我按顺序合并,我的列名会变得非常凌乱。


刚刚发现了这个网址http://stackoverflow.com/questions/24853762/pandas-merging-multiple-dataframes,但我不确定它是否适用于我的例子——我猜我需要先连接,然后再进行合并?我想将输出写入BigQuery表中,所以我不知道分层数据框是否适用于我。 - Richard
发现了这个链接 https://dev59.com/Z2Ag5IYBdhLWcg3wYaC6?rq=1 ,看起来更有希望,但是没有解释如何控制列名。 - Richard
3个回答

7
你可以使用 functools.reduce来迭代地将pd.merge应用于每个DataFrame:
result = functools.reduce(merge, dfs)

这相当于

result = dfs[0]
for df in dfs[1:]:
    result = merge(result, df)

为了传递on = ['org', 'name']参数,您可以使用functools.partial定义合并函数:
merge = functools.partial(pd.merge, on=['org', 'name'])

由于在 functools.partial 中指定 suffixes 参数只允许选择一个固定的后缀,而且由于在这里我们需要每个 pd.merge 调用都有不同的后缀,我认为在调用 pd.merge 之前准备好DataFrame列名可能是最容易的:

for i, df in enumerate(dfs, start=1):
    df.rename(columns={col:'{}_df{}'.format(col, i) for col in ('items', 'spend')}, 
              inplace=True)

例如,
import pandas as pd
import numpy as np
import functools
np.random.seed(2015)

N = 50
dfs = [pd.DataFrame(np.random.randint(5, size=(N,4)), 
                    columns=['org', 'name', 'items', 'spend']) for i in range(9)]
for i, df in enumerate(dfs, start=1):
    df.rename(columns={col:'{}_df{}'.format(col, i) for col in ('items', 'spend')}, 
              inplace=True)
merge = functools.partial(pd.merge, on=['org', 'name'])
result = functools.reduce(merge, dfs)
print(result.head())

产出率
   org  name  items_df1  spend_df1  items_df2  spend_df2  items_df3  \
0    2     4          4          2          3          0          1   
1    2     4          4          2          3          0          1   
2    2     4          4          2          3          0          1   
3    2     4          4          2          3          0          1   
4    2     4          4          2          3          0          1   

   spend_df3  items_df4  spend_df4  items_df5  spend_df5  items_df6  \
0          3          1          0          1          0          4   
1          3          1          0          1          0          4   
2          3          1          0          1          0          4   
3          3          1          0          1          0          4   
4          3          1          0          1          0          4   

   spend_df6  items_df7  spend_df7  items_df8  spend_df8  items_df9  spend_df9  
0          3          4          1          3          0          1          2  
1          3          4          1          3          0          0          3  
2          3          4          1          3          0          0          0  
3          3          3          1          3          0          1          2  
4          3          3          1          3          0          0          3  

太棒了!非常感谢!不过很遗憾,这只是内连接,那么你如何处理外连接? - jeangelj
@jeangelj:您可以在functools.partial调用中添加how='outer':例如merge = functools.partial(pd.merge, on=['org', 'name'], how='outer') - unutbu

0

你觉得通过使用大型的 pd.concat() 函数,再将所有列重命名,可以解决这个问题吗?像下面这样:

desired_columns = ['items', 'spend']
big_df = pd.concat([df1, df2[desired_columns], ..., dfN[desired_columns]], axis=1)


new_columns = ['org', 'name']
for i in range(num_dataframes):
    new_columns.extend(['spend_df%i' % i, 'items_df%i' % i])

bid_df.columns = new_columns

这应该给你类似于以下的列:

org, name, spend_df0, items_df0, spend_df1, items_df1, ..., spend_df8, items_df8


0

我有时也想要这样做,但找不到内置的pandas方法。以下是我的建议(以及下次需要它时的计划):

  1. 创建一个空字典merge_dict
  2. 循环遍历您想要的每个数据帧的索引,并将所需值添加到字典中,以索引作为键。
  3. 生成一个新的索引sorted(merge_dict)
  4. 通过循环遍历merge_dict.items()生成每列的新数据列表。
  5. 使用前面步骤中创建的列,创建一个新的数据帧,其中index=sorted(merge_dict)

基本上,这有点像SQL中的哈希连接。这似乎是我能想到的最有效的方法,编码起来也不会太长时间。

祝你好运。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接