Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 具有相同索引的两个数据帧的外积_Python_Pandas_Numpy - Fatal编程技术网

Python 具有相同索引的两个数据帧的外积

Python 具有相同索引的两个数据帧的外积,python,pandas,numpy,Python,Pandas,Numpy,考虑以下数据帧d1和d1 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和d2 到目前为止我已经做到了 from itertools imp

考虑以下数据帧
d1
d1

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
d2


到目前为止我已经做到了

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

这种方法没有错。但我正在寻找替代方案进行评估


灵感来自雅克姆·皮罗琴科

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可以更好地覆盖它

定时
所有的答案都是很好的答案,并展示了熊猫和裸体的不同方面。如果你觉得它们有用和信息丰富,请考虑投票。

%%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

这是一个有点矢量化的版本。还有更好的办法

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

你可以先得到多重索引,用它来获得形状,然后直接相乘

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
这里有一种方法-

样本运行-

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

这是一个使用熊猫和方法的单行线。 “诀窍”是使用
堆栈
,以便
应用
中的每个计算结果都是一个时间序列。然后使用
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

与我的示例数据相比,这无疑是一个改进。
ix
已被弃用,但我喜欢这个概念。改用
loc
。我正在对此进行改进这实际上是我在生产代码中实现的。。。你上钩了(-)@piRSquared似乎是个诱饵。很容易获得值,而不是设置列。
broadcasting
的想法是避免使用
repeat/tile
进行复制,因为这样可以创建中间数组,
broadcasting
可以避免这些值,从而带来性能。因此,人们会看到明显的效果使用适当大小的输入时的好处:)
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
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