1
votes

I have a 1-D array in numpy v. I'd like to copy it to make a matrix with each row being a copy of v. That's easy: np.broadcast_to(v, desired_shape).

However, if I'd like to treat v as a column vector, and copy it to make a matrix with each column being a copy of v, I can't find a simple way to do it. Through trial and error, I'm able to do this:

 np.broadcast_to(v.reshape(v.shape[0], 1), desired_shape)

While that works, I can't claim to understand it (even though I wrote it!).

Part of the problem is that numpy doesn't seem to have a concept of a column vector (hence the reshape hack instead of what in math would just be .T).

But, a deeper part of the problem seems to be that broadcasting only works vertically, not horizontally. Or perhaps a more correct way to say it would be: broadcasting only works on the higher dimensions, not the lower dimensions. I'm not even sure if that's correct.

In short, while I understand the concept of broadcasting in general, when I try to use it for particular applications, like copying the col vector to make a matrix, I get lost.

Can you help me understand or improve the readability of this code?

2
NumPy isn't matrix-oriented. You can think of it as tensor-oriented, if you want. A 1D array doesn't have two dimensions to swap for a transpose.user2357112 supports Monica

2 Answers

2
votes

https://en.wikipedia.org/wiki/Transpose - this article on Transpose talks only of transposing a matrix.

https://en.wikipedia.org/wiki/Row_and_column_vectors -

a column vector or column matrix is an m × 1 matrix a row vector or row matrix is a 1 × m matrix

You can easily create row or column vectors(matrix):

In [464]: np.array([[1],[2],[3]])   # column vector
Out[464]: 
array([[1],
       [2],
       [3]])
In [465]: _.shape
Out[465]: (3, 1)

In [466]: np.array([[1,2,3]])  # row vector
Out[466]: array([[1, 2, 3]])
In [467]: _.shape
Out[467]: (1, 3)

But in numpy the basic structure is an array, not a vector or matrix.

[Array in Computer Science] - Generally, a collection of data items that can be selected by indices computed at run-time

A numpy array can have 0 or more dimensions. In contrast in MATLAB matrix has 2 or more dimensions. Originally a 2d matrix was all that MATLAB had.

To talk meaningfully about a transpose you have to have at least 2 dimensions. One may have size one, and map onto a 1d vector, but it still a matrix, a 2d object.

So adding a dimension to a 1d array, whether done with reshape or [:,None] is NOT a hack. It is a perfect valid and normal numpy operation.

The basic broadcasting rules are:

  • a dimension of size 1 can be changed to match the corresponding dimension of the other array

  • a dimension of size 1 can be added automatically on the left (front) to match the number of dimensions.

In this example, both steps apply: (5,)=>(1,5)=>(3,5)

In [458]: np.broadcast_to(np.arange(5), (3,5))
Out[458]: 
array([[0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4]])

In this, we have to explicitly add the size one dimension on the right (end):

In [459]: np.broadcast_to(np.arange(5)[:,None], (5,3))
Out[459]: 
array([[0, 0, 0],
       [1, 1, 1],
       [2, 2, 2],
       [3, 3, 3],
       [4, 4, 4]])

np.broadcast_arrays(np.arange(5)[:,None], np.arange(3)) produces two (5,3) arrays.

np.broadcast_arrays(np.arange(5), np.arange(3)[:,None]) makes (3,5).

np.broadcast_arrays(np.arange(5), np.arange(3)) produces an error because it has no way of determining whether you want (5,3) or (3,5) or something else.

0
votes

Broadcasting always adds new dimensions to the left because it'd be ambiguous and bug-prone to try to guess when you want new dimensions on the right. You can make a function to broadcast to the right by reversing the axes, broadcasting, and reversing back:

def broadcast_rightward(arr, shape):
    return np.broadcast_to(arr.T, shape[::-1]).T