【问题标题】:Python: Merging many dataframes in most efficient way possible [duplicate]Python:以最有效的方式合并许多数据帧[重复]
【发布时间】:2018-01-22 17:52:01
【问题描述】:

现在我有许多不同的统计数据,它们的名称都附加在单独的数据框中。为了合并,我是否必须继续重写到新的数据框?有没有更有效的方法来做到这一点?

如果合并时列的名称相同,pd.merge 是否更容易?

一定要递归写吗

pd.merge(left=something, right=somethingelse, left_on='name', right_on='site')

【问题讨论】:

  • 所有数据框是否都连接在同一列上?
  • 是的,但我很想双向学习
  • 在这里查看各种选项:stackoverflow.com/questions/23668427/…
  • 看看使用 pd.concat,你和 concat 一个具有适当索引的数据框列表。

标签: python pandas dataframe merge


【解决方案1】:

首先,我们定义如何合并 2 个数据帧

def merge_two(a,b, col):
    if b is None:
        return a
    return pd.merge(a,b,on=col)

接下来,我们要合并尽可能小的部分

from multiprocessing import Pool
from itertools import izip_longest as izip
from functools import partial

def merge_many(dfs, col):
    p = Pool(8) # number of cores
    merge = partial(merge_two, col=col)
    while len(dfs)>1:
        dfs = p.map(merge, izip(islice(dfs,0,None,2),islice(dfs,1,None,2)))
    return dfs[0]

由于数据帧是独立的,因此使用multiprocessing 模块使其并行运行是没有害处的

【讨论】:

    【解决方案2】:

    您可以先创建所有数据帧的列表,然后使用reduce 函数获取结果

    # create some data
    columns = ['v1','v2','v3']
    df1 = pd.DataFrame(np.random.randint(10, size=(3,3)),columns=columns)
    df2 = pd.DataFrame(np.random.randint(10, size=(3,3)),columns=columns)
    df3 = pd.DataFrame(np.random.randint(10, size=(3,3)),columns=columns)
    
    dfs = [df1,df2,df3] # store in one list
    df_merge = reduce(lambda  left,right: pd.merge(left,right,on=['v1'], how='outer'), dfs)
    

    【讨论】:

    • reduce(+1)的经典应用
    【解决方案3】:

    如果您希望合并的列具有唯一值,则 有一种更快的方法:将要合并的列设置为索引,然后将所有数据框与pd.concat 连接起来:

    import itertools as IT
    import numpy as np
    import functools
    
    count = IT.count()
    M, N, P = 100, 10, 4
    dfs = [pd.DataFrame({
        next(count): np.random.randint(4, size=(N)) for j in range(P)}) for i in range(M)]
    
    for i in range(M):
        dfs[i]['foo'] = np.random.choice(N, size=N, replace=False)
    
    def using_merge(dfs):
        result = dfs[0]
        for df in dfs[1:]:
            result = pd.merge(result, df, on='foo')
        return result
    
    def using_reduce(dfs):
        return functools.reduce(lambda  left,right: 
                                pd.merge(left, right, on=['foo']), dfs)
    
    def using_concat(dfs):
        return pd.concat([df.set_index('foo') for df in dfs], axis=1)    
    

    在循环中调用merge 的问题在于它返回一个中间数据帧,该数据帧需要从leftright 数据帧复制值。在循环中完成时,这会导致quadraticly increasing amounts of copying

    当索引唯一时,pd.concat 可用于避免二次复制——dfs 中所有 DataFrames 的值只需复制一次到结果中。


    这是上面示例的微基准测试。

    In [160]: %timeit using_concat(dfs)
    10 loops, best of 3: 81.2 ms per loop
    
    In [161]: %timeit using_merge(dfs)
    1 loop, best of 3: 660 ms per loop
    
    In [162]: %timeit using_reduce(dfs)
    1 loop, best of 3: 659 ms per loop
    

    速度优势是可变的——它取决于 DataFrame 的数量,M, 被合并。随着M 的增加,速度也会增加 using_concat 优于 using_mergeusing_reduce。但是让我 再次强调pd.concat只能作为pd.merge的替代品 当列值是 unique 时——也就是说,合并是 1 对 1,而不是 多对一或一对多。

    如果要合并的列对于每个 DataFrame 没有唯一值,则 我没有看到比调用pd.merge 更快的方法来计算所需结果 在一个循环中。

    【讨论】:

      猜你喜欢
      • 2020-09-28
      • 1970-01-01
      • 2017-01-06
      • 2019-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多