【问题标题】:Adding dataframes and dividing resultant based on availability根据可用性添加数据框并划分结果
【发布时间】:2017-08-17 09:23:44
【问题描述】:

我想添加两个可以通过添加功能实现的数据框。 现在我想根据初始数据帧(df1,df2,df3)中是否存在相应的值来划分结果数据帧的每个值。例如。

df1 = pd.DataFrame([[1,2],[3,4]], index =['A','B'], columns = ['C','D'])
df2 = pd.DataFrame([[11,12], [13,14]], index = ['A','B'], columns = ['D','E'])
df3 = df1.add(df2, fill_value=0)

这将导致像 df 一样

     C   D     E
A  1.0  13  12.0
B  3.0  17  14.0

我需要一个像这样的df:

     C    D     E
A  1.0  6.5  12.0
B  3.0  8.5  14.0

因为在两个数据框中都找到了 D 列,所以我将这些值除以 2。 任何人都可以提供一个通用的解决方案,假设我需要添加超过 2 个数据帧(因此除法因子也会改变)并且每个数据帧中有超过 100 列。

【问题讨论】:

    标签: python pandas dataframe pandas-groupby


    【解决方案1】:

    我们可以一步水平连接所有 DF:

    In [13]: df = pd.concat([df1,df2], axis=1).fillna(0)
    

    这会产生:

    In [15]: df
    Out[15]:
       C  D   D   E
    A  1  2  11  12
    B  3  4  13  14
    

    现在我们可以按列分组,计算平均值 (mean):

    In [14]: df.groupby(df.columns, axis=1).mean()
    Out[14]:
         C    D     E
    A  1.0  6.5  12.0
    B  3.0  8.5  14.0
    

    或者我们可以一步完成(感谢@jezrael):

    In [60]: pd.concat([df1,df2], axis=1).fillna(0).groupby(level=0, axis=1).mean()
    Out[60]:
         C    D     E
    A  1.0  6.5  12.0
    B  3.0  8.5  14.0
    

    时间:

    In [38]: df1 = pd.concat([df1] * 10**5, ignore_index=True)
    
    In [39]: df2 = pd.concat([df2] * 10**5, ignore_index=True)
    
    In [40]: %%timeit
        ...: df = pd.concat([df1,df2], axis=1).fillna(0)
        ...: df.groupby(df.columns, axis=1).mean()
        ...:
    63.4 ms ± 2.39 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    In [41]: %%timeit
        ...: s = pd.Series(np.concatenate([df1.columns, df2.columns])).value_counts()
        ...: df1.add(df2, fill_value=0).div(s)
        ...:
    28.7 ms ± 712 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    In [42]: %%timeit
        ...: pd.concat([df1,df2]).mean(level = 0)
        ...:
    65.5 ms ± 555 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    In [43]: df1.shape
    Out[43]: (200000, 2)
    
    In [44]: df2.shape
    Out[44]: (200000, 2)
    

    当前获胜者: @jezrael (28.7 ms ± 712 µs) - 恭喜!

    【讨论】:

    • 而不是df.columns 更好level=0
    【解决方案2】:

    您似乎正在尝试计算平均值。如果可以的话,不要对数据框方法和单个列进行太多操作,因为它很慢。

    df = pd.concat([df1,df2]) # concatenate all your dataframes together
    df.mean(level = 0)
    

    第二行计算沿垂直轴的平均值(默认为axis = 0),level = 0 告诉 pandas 获取每个唯一索引的平均值。

    【讨论】:

    • pd.concat([df1,df2]).mean(0).to_dict()pd.concat([df1,df2]).mean(level=0).to_dict() 不同。 .mean() 的第一个位置参数是 axis
    • 哦,我的错,抱歉!你的解决方案比我的要好得多...... :-) 我也会在一行中完成......
    【解决方案3】:

    更快的解决方案是除以列的大小:

    s = pd.Series(np.concatenate([df1.columns, df2.columns])).value_counts()
    print (s)
    C    1
    D    2
    E    1
    dtype: int64
    
    df3 = df1.add(df2, fill_value=0).div(s)
    print (df3)
         C    D     E
    A  1.0  6.5  12.0
    B  3.0  8.5  14.0
    

    Timings(与 OP 一样有 100 列):

    np.random.seed(123)
    N = 100000
    df1 = pd.DataFrame(np.random.randint(10, size=(N, 100)))
    df1.columns = 'col' + df1.columns.astype(str)
    df2 = df1.mul(10)
    
    #MaxU solution 
    In [127]: %timeit (pd.concat([df1,df2], axis=1).fillna(0).groupby(level=0, axis=1).mean())
    1 loop, best of 3: 952 ms per loop
    
    #Ken Wei solution
    In [128]: %timeit (pd.concat([df1,df2]).mean(level = 0))
    1 loop, best of 3: 895 ms per loop
    
    #jez solution
    In [129]: %timeit (df1.add(df2, fill_value=0).div(pd.Series(np.concatenate([df1.columns, df2.columns])).value_counts()))
    10 loops, best of 3: 161 ms per loop
    

    更通用的解决方案:

    如果有DataFrames 的列表,可能会像这样:

    df = df1.add(df2, fill_value=0).add(df3, fill_value=0)
    

    但更好的是使用reduce:

    from functools import reduce
    
    dfs = [df1,df2, df3]
    s = pd.Series(np.concatenate([x.columns for x in dfs])).value_counts()
    df5 = reduce(lambda x, y: x.add(y, fill_value=0), dfs).div(s)
    

    【讨论】:

      猜你喜欢
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-25
      • 2016-03-28
      相关资源
      最近更新 更多