5

Let's say I have a 2d NumPy ndarray, like so:

[[ 0, 1, 2, 3 ],
 [ 4, 5, 6, 7 ],
 [ 8, 9, 10, 11 ]]

Conceptually speaking, what I want to do is this:

For each row:
    Transpose the row
    Multiply the transposed row by a transformation matrix
    Transpose the result
    Store the result in the original ndarray, overwriting the original row data

I have an extremely slow, brute-force method which functionally achieves this:

import numpy as np
transform_matrix = np.matrix( /* 4x4 matrix setup clipped for brevity */ )
for i, row in enumerate( data ):
    tr = row.reshape( ( 4, 1 ) )
    new_row = np.dot( transform_matrix, tr )
    data[i] = new_row.reshape( ( 1, 4 ) )

However, this seems like the sort of operation that NumPy should do well with. I assume that - as someone new to NumPy - I'm just missing something fundamental in the documentation. Any pointers?

Note that if it's faster to create a new ndarray rather than edit it in-place, that can work for what I'm doing, too; speed of the operation is the primary concern.

2 Answers 2

11

The lengthy series of operations you want to perform is equivalent to the following:

data[:] = data.dot(transform_matrix.T)

or using a new array instead of modifying the original, which should be a bit faster:

data.dot(transform_matrix.T)

Here's the explanation:

For each row:
    Transpose the row

Equivalent to transposing the matrix and then going over the columns.

    Multiply the transposed row by a transformation matrix

Left-multiplying each column of a matrix by a second matrix is equivalent to left-multiplying the whole thing by the second matrix. At this point, what you have is transform_matrix.dot(data.T)

    Transpose the result

One of the basic properties of matrix transposes is that transform_matrix.dot(data.T).T is equivalent to data.dot(transform_matrix.T).

    Store the result in the original ndarray, overwriting the original row data

The slice assignment does this.

Sign up to request clarification or add additional context in comments.

2 Comments

the slice is redundant here, I think
Perfect! Thank you for walking through the explanation as well - it was very helpful.
4

It seems you need transpose operator:

>>> np.random.seed(11)
>>> transform_matrix = np.random.randint(1, 10, (4,4))
>>> np.dot(transform_matrix, data.T).T
matrix([[ 24,  24,  17,  37],
        [ 76, 108,  61, 137],
        [128, 192, 105, 237]])

or equivalently, as (A*B).T = (B.T * A.T):

>>> np.dot(data, transform_matrix.T)

1 Comment

+1 for pointing to matrix algebra - this is not a programming issue but a lack of understanding of matrix algebra

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.