Yann POURCENOUX
Yann POURCENOUX

Reputation: 677

Computation difference between function and manual computation

I am facing a mystery right now. I get strange results in some program and I think it may be related to the computation since I got different results with my functions compared to manual computation.

This is from my program, I am printing the values pre-computation :

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

I got the following output:

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]

The thing is when I compute the following code:

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

The values in use are exactly the same as they should be in the computation before but I get the following result:

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

This result is then obviously different than the previous one and is the true one (I computed the dot product by hand).

I have been facing this problem the whole day and I did not find anything useful online. If any of you have any even tiny idea where it can come from I'd be really happy :D

Thank's in advance Yann

PS: I can show more of the code if needed. PS2: I don't know if it is relevant but this is used in a dynamic programming algorithm.

Upvotes: 0

Views: 116

Answers (2)

Seb
Seb

Reputation: 4586

To recap our discussion in the comments, in the first part ("pre-computation"), the following is true about the matrix object:

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

And as you say, this is due to matrix being a slice of a larger, non-uniform array. Let's recreate this situation:

>>> 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:]

It is now not a matrix with scalars in rows and columns, but a column vector of column vectors. Technically, matrix @ tmp is an operation between two 1-D arrays and hence NumPy should, according to the documentation, calculate the inner product of the two. This is true in this case, with the convention that the sum be over the first axis:

>>> 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])

This is essentially the same as taking the transpose of the proper 2-D matrix before the multiplication:

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

Equivalently, as noted by @jirasssimok:

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

Hence the erroneous or unexpected result.

As you have already resolved to do in the comments, this can be avoided in the future by ensuring all matrices are proper 2-D arrays.

Upvotes: 2

jirassimok
jirassimok

Reputation: 4263

It looks like you got the operands switched in one of your matrix multiplications.

Using the same values of matrix and tmp that you provided, matrix @ tmp and tmp @ matrix provide the two results you showed.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]

To make it a little more obvious what your code is doing, you might also consider using np.dot instead of @. If you pass matrix as the first argument and tmp as the second, it will have the result you want, and make it more clear that you're conceptually calculating dot products rather than multiplying matrices.


As an additional note, if you're performing matrix operations on matrix, it might be better if it was a single two-dimensional array instead of a list of 1-dimensional arrays. this will prevent errors of the sort you'll see right now if you try to run matrix @ matrix. This would also let you say matrix.dot(tmp) instead of np.dot(matrix, tmp) if you wanted to.

(I'd guess that you can use np.stack or a similar function to create matrix, or you can call np.stack on matrix after creating it.)


1 Because tmp has only one dimension and matrix has two, NumPy can and will treat tmp as whichever type of vector makes the multiplication work (using broadcasting). So tmp is treated as a column vector in matrix @ tmp and a row vector in tmp @ matrix.

Upvotes: 2

Related Questions