2017-08-17 72 views
3

我想添加两个数据帧,我可以通过添加函数来实现。 现在我想根据初始数据框(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柱在两个dataframes发现,我除以2的那些值。 任何人都可以请提供一个通用的解决方案,假设我需要添加2个以上的数据框(因此划分因子也会发生变化),并且每个数据框中有100多列。

回答

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 

或我们可以一步完成(谢谢@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) - 恭喜你!

+1

代替'df.columns'是更好的'水平= 0' – jezrael

+0

@jezrael,是的,谢谢! – MaxU

4

看起来你正在试图计算一个均值。如果可以提供帮助,请不要对数据框方法和各个列执行太多操作,因为速度很慢。

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

第二行计算平均沿着垂直轴(默认axis = 0),和level = 0告诉大熊猫获得每个唯一索引的平均值。

+0

'pd.concat([df1,df2])。mean(0).to_dict()'不同于'pd.concat([df1,df2])。mean(level = 0).to_dict()' 。 '.mean()'的第一个位置参数是'axis'。 –

+0

哦,我的不好,道歉!你的解决方案比我的方法更好...... :-)我也会在一行中做到这一点...... – MaxU

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,有可能chaning如:

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)