函数计算与人工计算的区别

Computation difference between function and manual computation

我现在正面临一个谜。我在某些程序中得到了奇怪的结果,我认为这可能与计算有关,因为与手动计算相比,我的函数得到了不同的结果。

这是我的程序,我正在打印预先计算的值:

print("\nPrecomputation:\nmatrix\n:", matrix)
tmp = likelihood_left * likelihood_right
print("\nconditional_dep:", tmp)
print("\nfinal result:", matrix @ tmp)

我得到以下输出:

Precomputation:
matrix: 
[array([0.08078721, 0.5802404 , 0.16957052, 0.09629893, 0.07310294])
 array([0.14633129, 0.45458744, 0.20096238, 0.02142105, 0.17669784])
 array([0.41198731, 0.06197812, 0.05934063, 0.23325626, 0.23343768])
 array([0.15686545, 0.29516415, 0.20095091, 0.14720275, 0.19981674])
 array([0.15965914, 0.18383683, 0.10606946, 0.14234812, 0.40808645])]

conditional_dep: [0.01391123 0.01388155 0.17221067 0.02675524 0.01033257]
final result: [0.07995043 0.03485223 0.02184015 0.04721548 0.05323298]

问题是当我计算以下代码时:

matrix = [np.array([0.08078721, 0.5802404 , 0.16957052, 0.09629893, 0.07310294]),
          np.array([0.14633129, 0.45458744, 0.20096238, 0.02142105, 0.17669784]), 
          np.array([0.41198731, 0.06197812, 0.05934063, 0.23325626, 0.23343768]), 
          np.array([0.15686545, 0.29516415, 0.20095091, 0.14720275, 0.19981674]), 
          np.array([0.15965914, 0.18383683, 0.10606946, 0.14234812, 0.40808645])]

tmp = np.asarray([0.01391123, 0.01388155, 0.17221067, 0.02675524, 0.01033257])

matrix @ tmp

使用的值与之前计算中的值完全相同,但我得到以下结果:

array([0.04171218, 0.04535276, 0.02546353, 0.04688848, 0.03106443])

这个结果明显不同于上一个,是真实的(我手工计算了点积)。

我整天都在面对这个问题,我在网上没有找到任何有用的东西。如果你们中的任何人有任何一点点想法,我会很高兴 :D

提前致谢 雅恩

PS:如果需要,我可以展示更多代码。 PS2: 不知​​道有没有关系,但是这个在动态规划算法中用到了

看起来您在矩阵乘法之一中切换了操作数。

使用您提供的 matrixtmp 的相同值,matrix @ tmptmp @ matrix 提供您显示的两个结果。1

matrix = [np.array([0.08078721, 0.5802404 , 0.16957052, 0.09629893, 0.07310294]),
          np.array([0.14633129, 0.45458744, 0.20096238, 0.02142105, 0.17669784]), 
          np.array([0.41198731, 0.06197812, 0.05934063, 0.23325626, 0.23343768]), 
          np.array([0.15686545, 0.29516415, 0.20095091, 0.14720275, 0.19981674]), 
          np.array([0.15965914, 0.18383683, 0.10606946, 0.14234812, 0.40808645])]
tmp = np.asarray([0.01391123, 0.01388155, 0.17221067, 0.02675524, 0.01033257])

print(matrix @ tmp)  # [0.04171218 0.04535276 0.02546353 0.04688848 0.03106443]
print(tmp @ matrix)  # [0.07995043 0.03485222 0.02184015 0.04721548 0.05323298]

为了让您的代码在做什么更加明显,您还可以考虑使用 np.dot 而不是 @。如果您将 matrix 作为第一个参数传递,将 tmp 作为第二个参数传递,它将得到您想要的结果,并更清楚地表明您是在概念上计算点积而不是矩阵相乘。


另外请注意,如果您要对 matrix 执行矩阵运算,最好是单个二维数组而不是一维数组列表。如果您尝试 运行 matrix @ matrix,这将防止您现在看到的那种错误。如果你愿意,这也可以让你说 matrix.dot(tmp) 而不是 np.dot(matrix, tmp)

(我猜你可以使用 np.stack 或类似的函数来创建 matrix,或者你可以在创建后在 matrix 上调用 np.stack。 )


1 因为 tmp 只有一维而 matrix 有两个,NumPy 可以并将 tmp 视为任何一种向量使乘法工作(使用 broadcasting)。因此 tmpmatrix @ tmp 中被视为列向量,在 tmp @ matrix 中被视为行向量。

回顾一下我们在评论中的讨论,在第一部分 ("pre-computation") 中,以下关于 matrix 对象的说法是正确的:

>>> matrix.shape
(5,)
>>> matrix.dtype
dtype('O') # aka object

正如您所说,这是因为 matrix 是更大的非均匀数组的一部分。让我们重现这种情况:

>>> matrix = np.array([[], np.array([0.08078721, 0.5802404 , 0.16957052, 0.09629893, 0.07310294]), np.array([0.14633129, 0.45458744, 0.20096238, 0.02142105, 0.17669784]), np.array([0.41198731, 0.06197812, 0.05934063, 0.23325626, 0.23343768]), np.array([0.15686545, 0.29516415, 0.20095091, 0.14720275, 0.19981674]), np.array([0.15965914, 0.18383683, 0.10606946, 0.14234812, 0.40808645])])[1:]

它现在不再是行列标量矩阵,而是列向量的列向量。从技术上讲,matrix @ tmp 是两个一维数组之间的运算,因此 NumPy 应该根据 documentation 计算两者的内积。在这种情况下是这样,约定总和在第一个轴上:

>>> np.array([matrix[i] * tmp[i] for i in range(5)]).sum(axis=0)
array([0.07995043, 0.03485222, 0.02184015, 0.04721548, 0.05323298])
>>> matrix @ tmp
array([0.07995043, 0.03485222, 0.02184015, 0.04721548, 0.05323298])

这与在乘法之前对适当的二维矩阵进行转置基本相同:

>>> np.stack(matrix).T @ tmp
array([0.07995043, 0.03485222, 0.02184015, 0.04721548, 0.05323298])

等同于@jirasssimok 指出的:

>>> tmp @ np.stack(matrix)
array([0.07995043, 0.03485222, 0.02184015, 0.04721548, 0.05323298])

因此出现错误或意外的结果。

正如您在评论中已经解决的那样,将来可以通过确保所有矩阵都是正确的二维数组来避免这种情况。