【问题标题】:Python numpy matrix multiplication with one diagonal matrixPython numpy 矩阵乘法与一个对角矩阵
【发布时间】:2017-06-06 11:06:49
【问题描述】:

我有两个数组 A (4000,4000),其中只有对角线填充了数据,而 B (4000,5) 填充了数据。有没有比 numpy.dot(a,b) 函数更快的方法来乘(点)这些数组?

到目前为止,我发现(A * B.T).T 应该更快(其中 A 是一维 (4000),填充了对角线元素),但结果却大约慢了一倍。

在 A 是对角数组的情况下,是否有更快的方法来计算 B.dot(A)?

【问题讨论】:

  • 那些是数组还是矩阵?另外,你确定 (B * A.T).T 吗?
  • Numpy 矩阵,我对 (B*A.T).T 进行了测试,但仅针对小矩阵,因此我将尝试针对大矩阵并发布结果
  • 我的意思是对于 A (4000,5), B (4000,4000),B * A.T 会有错位错误。
  • 在编辑后,(A * B.T).T 再次因形状未对齐而无法工作。
  • 是的,但在这种情况下,A 将是一维(4000,)数组

标签: numpy matrix-multiplication


【解决方案1】:

您可以简单地提取对角元素,然后执行广播元素乘法。

因此,B*A 的替代品将是 -

np.multiply(np.diag(B)[:,None], A)

对于A.T*B -

np.multiply(A.T,np.diag(B))

运行时测试-

In [273]: # Setup
     ...: M,N = 4000,5
     ...: A = np.random.randint(0,9,(M,N)).astype(float)
     ...: B = np.zeros((M,M),dtype=float)
     ...: np.fill_diagonal(B, np.random.randint(11,99,(M)))
     ...: A = np.matrix(A)
     ...: B = np.matrix(B)
     ...: 

In [274]: np.allclose(B*A, np.multiply(np.diag(B)[:,None], A))
Out[274]: True

In [275]: %timeit B*A
10 loops, best of 3: 32.1 ms per loop

In [276]: %timeit np.multiply(np.diag(B)[:,None], A)
10000 loops, best of 3: 33 µs per loop

In [282]: np.allclose(A.T*B, np.multiply(A.T,np.diag(B)))
Out[282]: True

In [283]: %timeit A.T*B
10 loops, best of 3: 24.1 ms per loop

In [284]: %timeit np.multiply(A.T,np.diag(B))
10000 loops, best of 3: 36.2 µs per loop

【讨论】:

  • 不错。 np.multiply(np.diag(B)[:,None], A) 仅在 B 是对角矩阵时才有效,对吗?而A 可以是矩阵或向量。
【解决方案2】:

看来我最初声称 (A * B.T).T 变慢是不正确的。

from timeit import default_timer as timer
import numpy as np

##### Case 1
a = np.zeros((4000,4000))
np.fill_diagonal(a, 10)
b = np.ones((4000,5))

dot_list = []

def time_dot(a,b):
    start = timer()
    c = np.dot(a,b)
    end = timer()
    return end - start

for i in range(100):
    dot_list.append(time_dot(a,b))

print np.mean(np.asarray(dot_list))

##### Case 2
a = np.ones((4000,))
a = a * 10
b = np.ones((4000,5))

shortcut_list = []

def time_quicker(a,b):
    start = timer()
    c = (a*b.T).T
    end = timer()
    return end - start

for i in range(100):
    shortcut_list.append(time_quicker(a,b))

print np.mean(np.asarray(shortcut_list))


##### Case 3
a = np.zeros((4000,4000)) #diagonal matrix
np.fill_diagonal(a, 10)
b = np.ones((4000,5))

case3_list = []

def function(a,b):
    start = timer()
    np.multiply(b.T,np.diag(a))
    end = timer()
    return end - start

for i in range(100):
    case3_list.append(function(a,b))

print np.mean(np.asarray(case3_list))

结果:

0.119120892431

0.00010633951868

0.00214490709662

所以第二种方法最快

【讨论】:

  • 问题状态为A (4000,5), B (4000,4000),,在这里您正在使用它们翻转。认为您需要解决问题或这篇文章。
  • 再一次,在 cmets 中您说您使用的是 NumPy 矩阵,而您在这里使用的是 NumPy 数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-22
  • 2012-05-27
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
  • 2016-05-11
相关资源
最近更新 更多