2017-07-24 43 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