2017-08-17 69 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)