The dot product inclination is correct, and that includes the sum you need. So, to get the sum of the products of the elements of a target array and a set of weights:
>>> a = np.array([[0,1,2],[2,2,3]])
>>> a
array([[0, 1, 2],
[2, 2, 3]])
>>> weights = np.array([16,4,2])
>>> np.dot(a,weights)
array([ 8, 46])
Answer from Karmel on Stack OverflowSince intervals (-0.25, -0.20), (-0.20, -0.10) and (-0.10, 0.15) are actually subintervals of partition of an interval (-0.25, 0.15) you could find indices where elements should be inserted in A to maintain order. They specify slices of B to perform addition on. In short:
partition = np.array([-0.25, -0.20, -0.10, 0.15])
weights = np.array([1, 0.5, 2])
out = []
for n in A:
idx = np.searchsorted(A, n + partition)
results = np.add.reduceat(B[:idx[-1]], idx[:-1])
out.append(np.dot(results, weights))
>>> print(out)
[7.5, 7.5, 8.0, 10.5, 12.0, 11.0, 11.5, 11.5, 6.5, 13.5, 27.5, 27.5, 31.5, 35.5, 37.5, 37.0, 36.0, 35.0, 34.0, 34.5, 34.0, 36.5, 33.0, 34.0, 34.5, 34.5, 36.0, 39.0, 37.0, 36.0, 37.0, 36.5, 37.5, 39.0, 36.5, 37.5, 34.0, 31.0, 27.5, 23.0]
Note that results are wrong if there are empty slices of B
Credits to @mathfux for providing me enough guidance. Here's the final code solution that I developed based on conversations here:
partition = np.array([-0.25, -0.20, -0.10, 0.15])
weights = np.array([1, 0.5, 2])
idx = np.searchsorted(A, partition + A[:, None])
_idx = np.lib.stride_tricks.sliding_window_view(idx, 2, axis = 1)
values = np.apply_along_axis(lambda x: B[slice(*(x))].sum(), 2, _idx)
values @ weights
Even a 'technically' correct answer has been all ready given, I'll give my straightforward answer:
from numpy import array, dot
dot(array([0.5, -1]), array([[1, 2, 3], [4, 5, 6]]))
# array([-3.5 -4. -4.5])
This one is much more on with the spirit of linear algebra (and as well those three dotted requirements on top of the question).
Update: And this solution is really fast, not marginally, but easily some (10- 15)x faster than all ready proposed one!
It will be more convenient to use a two-dimensional numpy.array than a numpy.matrix in this case.
start_matrix = numpy.array([[1,2,3],[4,5,6]])
weights = numpy.array([0.5,-1])
final_vector = (start_matrix.T * weights).sum(axis=1)
# array([-3.5, -4. , -4.5])
The multiplication operator * does the right thing here due to NumPy's broadcasting rules.
The method numpy.einsum is convenient for this:
np.einsum('ij,kli->klj', A, B)
The notation says: multiply A[i, j] by B[k, l, i] and sum over i; place the result in the cell [k, l, j].
Example:
A = np.array([(255, 0, 0), (0, 255, 0), (0, 0, 255)])
B = np.array([[[0.2, 0.6, 0.20], [0.2, 0.2, 0.60]], [[0.4, 0.4, 0.2], [0.3, 0.3, 0.4]]])
Y = np.einsum('ij,kli->klj', A, B)
Then Y is
array([[[ 51. , 153. , 51. ],
[ 51. , 51. , 153. ]],
[[ 102. , 102. , 51. ],
[ 76.5, 76.5, 102. ]]])
You are sum-reducing the first axis from A against the third from B, while the rest of the axes are spread out. This is a perfect setup to leverage BLAS based matrix-multiplication for tensors - np.tensordot, like so -
C = np.tensordot(B,A,axes=((2),(0)))
Related post to understand tensordot.
We can also manually reshape to 2D and use the matrix-multiplication for 2D : np.dot, like so -
B.reshape(-1,n).dot(A).reshape(x,y,3)
Note that B.dot(A) works as well, but that would be slower, most probably as it would loop through the first axis of B, while performing 2D matrix-multiplications for each 2D slice off it against A.
Runtime test -
In [180]: np.random.seed(0)
...: x,y,n = 100,100,100
...: A = np.random.rand(n,3)
...: B = np.random.rand(x,y,n)
# @Crazy Ivan's soln
In [181]: %timeit np.einsum('ij,kli->klj', A, B)
100 loops, best of 3: 4.21 ms per loop
In [182]: %timeit np.tensordot(B,A,axes=((2),(0)))
1000 loops, best of 3: 1.72 ms per loop
In [183]: np.random.seed(0)
...: x,y,n = 200,200,200
...: A = np.random.rand(n,3)
...: B = np.random.rand(x,y,n)
# @Crazy Ivan's soln
In [184]: %timeit np.einsum('ij,kli->klj', A, B)
10 loops, best of 3: 33.2 ms per loop
In [185]: %timeit np.tensordot(B,A,axes=((2),(0)))
100 loops, best of 3: 15.3 ms per loop