我想添加两个我可以通过添加功能实现的数据帧。 现在,我想根据初始数据帧(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列。
答案 0 :(得分:5)
我们可以在一个步骤中水平连接所有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
或者我们可以一步完成(感谢{{3}}):
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
) - 恭喜!
答案 1 :(得分:4)
看起来你正试图计算一个平均值。如果您可以提供帮助,请不要使用数据框方法和单个列进行太多操作,因为它很慢。
df = pd.concat([df1,df2]) # concatenate all your dataframes together
df.mean(level = 0)
第二行计算沿垂直轴的平均值(默认为axis = 0
),level = 0
告诉pandas获取每个唯一索引的平均值。
答案 2 :(得分:4)
更快的解决方案除以列的大小:
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
计时(提到的100列像OP一样):
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)