2017-07-24 44 views
4

考慮以下dataframes d1d1熊貓2個dataframes與同一指數的產品外

d1 = pd.DataFrame([ 
    [1, 2, 3], 
    [2, 3, 4], 
    [3, 4, 5], 
    [1, 2, 3], 
    [2, 3, 4], 
    [3, 4, 5] 
], columns=list('ABC')) 

d2 = pd.get_dummies(list('XYZZXY')) 

d1 

    A B C 
0 1 2 3 
1 2 3 4 
2 3 4 5 
3 1 2 3 
4 2 3 4 
5 3 4 5 

d2 

    X Y Z 
0 1 0 0 
1 0 1 0 
2 0 0 1 
3 0 0 1 
4 1 0 0 
5 0 1 0 

我需要得到一個新的數據幀具有產品的多索引列對象從d1d2


到目前爲止,我已經做到了這一點列的每個組合...的

from itertools import product 
pd.concat({(x, y): d1[x] * d2[y] for x, y in product(d1, d2)}, axis=1) 

    A  B  C  
    X Y Z X Y Z X Y Z 
0 1 0 0 2 0 0 3 0 0 
1 0 2 0 0 3 0 0 4 0 
2 0 0 3 0 0 4 0 0 5 
3 0 0 1 0 0 2 0 0 3 
4 2 0 0 3 0 0 4 0 0 
5 0 3 0 0 4 0 0 5 0 

沒有什麼錯用這種方法。但我正在尋找替代品來評估。


通過Yakym Pirozhenko啓發

m, n = len(d1.columns), len(d2.columns) 
lvl0 = np.repeat(np.arange(m), n) 
lvl1 = np.tile(np.arange(n), m) 
v1, v2 = d1.values, d2.values 

pd.DataFrame(
    v1[:, lvl0] * v2[:, lvl1], 
    d1.index, 
    pd.MultiIndex.from_tuples(list(zip(d1.columns[lvl0], d2.columns[lvl1]))) 
) 

然而,這是一個比較笨拙實現numpy的廣播中的哪一個更好地Divakar覆蓋。

定時
所有答案都是很好的答案,並證明熊貓和numpy的不同方面。如果您發現它們有用且信息豐富,請考慮對它們進行投票。

%%timeit 
m, n = len(d1.columns), len(d2.columns) 
lvl0 = np.repeat(np.arange(m), n) 
lvl1 = np.tile(np.arange(n), m) 
v1, v2 = d1.values, d2.values 

pd.DataFrame(
    v1[:, lvl0] * v2[:, lvl1], 
    d1.index, 
    pd.MultiIndex.from_tuples(list(zip(d1.columns[lvl0], d2.columns[lvl1]))) 
) 

%%timeit 
vals = (d2.values[:,None,:] * d1.values[:,:,None]).reshape(d1.shape[0],-1) 
cols = pd.MultiIndex.from_product([d1.columns, d2.columns]) 
pd.DataFrame(vals, columns=cols, index=d1.index) 

%timeit d1.apply(lambda x: d2.mul(x, axis=0).stack()).unstack() 
%timeit pd.concat({x : d2.mul(d1[x], axis=0) for x in d1.columns}, axis=1) 
%timeit pd.concat({(x, y): d1[x] * d2[y] for x, y in product(d1, d2)}, axis=1) 

1000 loops, best of 3: 663 µs per loop 
1000 loops, best of 3: 624 µs per loop 
100 loops, best of 3: 3.38 ms per loop 
1000 loops, best of 3: 860 µs per loop 
100 loops, best of 3: 2.01 ms per loop 
+0

用'broadcasting'這樣做是爲了避免重複與'重複/ tile'那些會造成中間陣列和'broadcasting'避免那些而且會帶來性能它。所以,當處理體面大小的輸入時,人們會看到明顯的好處:) – Divakar

回答

3

這裏有一個方法與NumPy broadcasting -

vals = (d2.values[:,None,:] * d1.values[:,:,None]).reshape(d1.shape[0],-1) 
cols = pd.MultiIndex.from_product([d1.columns, d2.columns]) 
df_out = pd.DataFrame(vals, columns=cols, index=d1.index) 

採樣運行 -

In [92]: d1 
Out[92]: 
    A B C 
0 1 2 3 
1 2 3 4 
2 3 4 5 
3 1 2 3 
4 2 3 4 
5 3 4 5 

In [93]: d2 
Out[93]: 
    X Y Z 
0 1 0 0 
1 0 1 0 
2 0 0 1 
3 0 0 1 
4 1 0 0 
5 0 1 0 

In [110]: vals = (d2.values[:,None,:] * d1.values[:,:,None]).reshape(d1.shape[0],-1) 
    ...: cols = pd.MultiIndex.from_product([d1.columns, d2.columns]) 
    ...: df_out = pd.DataFrame(vals, columns=cols, index=d1.index) 
    ...: 

In [111]: df_out 
Out[111]: 
    A  B  C  
    X Y Z X Y Z X Y Z 
0 1 0 0 2 0 0 3 0 0 
1 0 2 0 0 3 0 0 4 0 
2 0 0 3 0 0 4 0 0 5 
3 0 0 1 0 0 2 0 0 3 
4 2 0 0 3 0 0 4 0 0 
5 0 3 0 0 4 0 0 5 0 
+0

這實際上是我在生產代碼中實現的...您使用誘餌( - : – piRSquared

+0

@piRSquared看起來像一個誘餌,很容易獲取值,而不是設置在列上。 – Divakar

3

這是一個位矢量化版本。可能有更好的方法。

In [846]: pd.concat({x : d2.mul(d1[x], axis=0) for x in d1.columns}, axis=1) 
Out[846]: 
    A  B  C 
    X Y Z X Y Z X Y Z 
0 1 0 0 2 0 0 3 0 0 
1 0 2 0 0 3 0 0 4 0 
2 0 0 3 0 0 4 0 0 5 
3 0 0 1 0 0 2 0 0 3 
4 2 0 0 3 0 0 4 0 0 
5 0 3 0 0 4 0 0 5 0 
+0

在我的示例數據中,這絕對是一種改進。 – piRSquared

2

你可以先得到多指標,用它來獲得形狀並直接乘。

cols = pd.MultiIndex.from_tuples(
     [(c1, c2) for c1 in d1.columns for c2 in d2.columns]) 

a = d1.loc[:,cols.get_level_values(0)] 
b = d2.loc[:,cols.get_level_values(1)] 
a.columns = b.columns = cols 

res = a * b 
+0

'ix'已被棄用,但我喜歡這個概念。改用'loc'。我正在改進這個 – piRSquared

3

這裏是一個班輪使用熊貓stackunstack方法。 「訣竅」是使用stack,以便apply內的每個計算結果都是時間序列。然後使用unstack獲取Multiindex表單。

d1.apply(lambda x: d2.mul(x, axis=0).stack()).unstack() 

其中給出:

 A    B    C   
    X Y Z X Y Z X Y Z 
0 1.0 0.0 0.0 2.0 0.0 0.0 3.0 0.0 0.0 
1 0.0 2.0 0.0 0.0 3.0 0.0 0.0 4.0 0.0 
2 0.0 0.0 3.0 0.0 0.0 4.0 0.0 0.0 5.0 
3 0.0 0.0 1.0 0.0 0.0 2.0 0.0 0.0 3.0 
4 2.0 0.0 0.0 3.0 0.0 0.0 4.0 0.0 0.0 
5 0.0 3.0 0.0 0.0 4.0 0.0 0.0 5.0 0.0 
+0

對我來說很可讀。 – piRSquared