It’s a little bit complicated and has to do with the concept of broadcasting and the fact that all numpy operations are element wise.
ais a 2D array with 1 row and 3 columns andbis a 2D array with 1 column and 3 rows.- If you try to multiply them element by element (which is what numpy tries to do if you do
a * bbecause every basic operation except thedotoperation is element wise), it must broadcast the arrays so that they match in all their dimensions. - Since the first array is 1×3 and the second is 3×1 they can be broadcasted to 3×3 matrix according to the broadcasting rules. They will look like:
a = [[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]
b = [[4, 4, 4],
[5, 5, 5],
[6, 6, 6]]
And now Numpy can multiply them element by element, giving you the result:
[[ 4, 8, 12],
[ 5, 10, 15],
[ 6, 12, 18]]
When you are doing a .dot operation it does the standard matrix multiplication. More in docs