Iterate over list of NumPy matrices

1k views Asked by At

I've got a list with row matrices:

rows = [ matrix([[1, 0, 0]]), matrix([[0, 1, 0]]), matrix([[0, 0, 1]]) ]

and I attempted to loop over these using for (a, b, c) in rows:, but instead of this working, I got an error:

ValueError: not enough values to unpack (expected 3, got 1)

The expected behaviour would be to unpack the three elements in the row to a, b, c:

for (a, b, c) in rows:
    print(f"{a} {b} {c}")
> 1 0 0
> 0 1 0
> 0 0 1

Unfortunately, this would work on [1, 0, 0], but not on [[1, 0, 0]].

I realized this is because they're [[doubly packed]], but I was wondering if there was a simple solution to this issue?

3

There are 3 answers

5
Divakar On BEST ANSWER

Since, we are using a,b,c to extract elements from each matrix's first row, it seems we are guaranteed to have 3 elements per row and it would be one per row for each of those matrices. So, one simple solution (as asked) would be to use the array constructor when using the loop and squeeze out the singleton nested level, like so -

for a,b,c in np.array(rows)[:,0]:

Or simpler np.squeeze() -

for a,b,c in np.squeeze(rows):

Note that this won't be the most memory efficient way but works as a simple way to extract those required scalar values.

Here's a sample run -

In [375]: for a,b,c in np.squeeze(rows):
     ...:     print(a,b,c)
     ...:     
(1, 0, 0)
(0, 1, 0)
(0, 0, 1)
1
MSeifert On

It seems like you want to unpack each matrix itself. In that case I would advise: Don't use matrix or NumPy. There is also no reason to use NumPy matrix at all. Even the NumPy documentation states that you should prefer arrays over matrices. But in this case you should use plain lists, they are faster if you iterate over them or unpack them.

So you first want to iterate over each matrix and then you want to unpack each one of these. But you have to do it in two steps:

for mat in rows:      # this iterates over the list and gives you each matrix
    # this unpacks the matrix
    # to make it work faster I converted it to a list first using "tolist"
    # note that I needed to index it because it's a 2D matrix!
    a, b, c = mat.tolist()[0]
    print(a, b, c)  

It's also possible to do the two steps in one line:

for a, b, c in (mat.tolist()[0] for mat in rows):
    print(a, b, c)
0
hpaulj On

A problem is that indexing a row of a matrix still gives a matrix. A way around that is to turn the matrix into a 1d array:

In [368]: for r in rows:
     ...:     a,b,c=r.A1
     ...:     print(a,b,c)
     ...:     
1 0 0
0 1 0
0 0 1

Numpy matrix to array


In [370]: for r in rows:
     ...:     print(r.shape,r[0].shape)
     ...:     
(1, 3) (1, 3)
(1, 3) (1, 3)
(1, 3) (1, 3)

I don't usually use or recommend unpacking values from an array. That works against the generality of arrays. unpacking (unless using '*' terms) fixes the dimensions. But in general array can have several dimensions, and large sizes.

Also np.matrix is discouraged. If these elements were np.array instead there wouldn't be this persistent 2d problem.