A matrix problem. Please help!

C

Carl

I have the following matrix that I want to transform:

import random
import Numeric as N
ru = []
for i in range(25):
ru.append(int(random.uniform(0, 2)))
ru = N.reshape(ru, (5, 5))
array([[1, 0, 1, 1, 1],
[0, 1, 1, 1, 0],
[1, 1, 0, 0, 1],
[0, 1, 0, 0, 1],
[1, 1, 0, 1, 1]])

Trailing numbers (ie, from left to right) after the first encounter of a "1"
for all rows should equal "0".

Thus, I want this:
array([[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0]])

Does anyone have a suggestion of a fast and easy way to accomplish the
above?

Carl
 
P

Peter Otten

Carl said:
I have the following matrix that I want to transform:

import random
import Numeric as N
ru = []
for i in range(25):
ru.append(int(random.uniform(0, 2)))
ru = N.reshape(ru, (5, 5))
array([[1, 0, 1, 1, 1],
[0, 1, 1, 1, 0],
[1, 1, 0, 0, 1],
[0, 1, 0, 0, 1],
[1, 1, 0, 1, 1]])

Trailing numbers (ie, from left to right) after the first encounter of a
"1" for all rows should equal "0".

Thus, I want this:
array([[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0]])

Does anyone have a suggestion of a fast and easy way to accomplish the
above?

Carl

(Disclaimer: Numeric newbie code)
.... while 1:
.... r = int(random.uniform(0, 2))
.... yield r
.... if r: break
.... for r in itertools.repeat(0):
.... yield r
....
ru = Numeric.array([[x for x,y in itertools.izip(oneone(), range(5))] for z in range(5)])
ru
array([[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0]])
Or, more seriously, i. e. assuming that you have no influence on the initial
matrix:
array([[1, 1, 1],
[0, 1, 1],
[0, 0, 1]]).... for k in Numeric.nonzero(i)[1:]:
.... i[k] = 0
....array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])

Peter
 
C

Carl

Peter said:
Carl said:
I have the following matrix that I want to transform:

import random
import Numeric as N
ru = []
for i in range(25):
ru.append(int(random.uniform(0, 2)))
ru = N.reshape(ru, (5, 5))
array([[1, 0, 1, 1, 1],
[0, 1, 1, 1, 0],
[1, 1, 0, 0, 1],
[0, 1, 0, 0, 1],
[1, 1, 0, 1, 1]])

Trailing numbers (ie, from left to right) after the first encounter of a
"1" for all rows should equal "0".

Thus, I want this:
array([[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0]])

Does anyone have a suggestion of a fast and easy way to accomplish the
above?

Carl

(Disclaimer: Numeric newbie code)
... while 1:
... r = int(random.uniform(0, 2))
... yield r
... if r: break
... for r in itertools.repeat(0):
... yield r
...
ru = Numeric.array([[x for x,y in itertools.izip(oneone(), range(5))] for z in range(5)])
ru
array([[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0]])
Or, more seriously, i. e. assuming that you have no influence on the
initial matrix:
array([[1, 1, 1],
[0, 1, 1],
[0, 0, 1]])... for k in Numeric.nonzero(i)[1:]:
... i[k] = 0
...array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])

Peter


Thanks Peter,

This:

for i in ru:
for k in N.nonzero(i)[1:]:
i[k] = 0

works very nice, but I'm a little worried about performance problem, since
the matrix ru is typically of size 10,000 to 100,000 rows by 10 to 60
columns.

I have tried to figure out how to do it without loops, but have not managed
to do that yet.

Carl
 
J

Jeff Epler

Well, my strategy is to get a new array with 1 in the spots where you
want a 1 in the output, and other values elsewhere. Then I can use
comparison to get a (boolean) array with 1s in the right place

I didn't find a satisfactory way to do that, but here's one that seemed
to work:array([[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[0, 0, 0, 1, 1],
[1, 1, 1, 0, 0],
[1, 1, 0, 1, 0]])array([[ 0, 0, 1, 2, 4],
[ 1, 2, 3, 5, 8],
[ 0, 0, 0, 1, 3],
[ 1, 3, 6, 9, 12],
[ 1, 3, 5, 8, 11]])array([[0, 0, 1, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[1, 0, 0, 0, 0],
[1, 0, 0, 0, 0]], type=Bool)

The first accumulate makes everything to the left of a 1 >0, and the
second accumulate makes it >1.

Jeff
 
C

Carl

Jeff said:
Well, my strategy is to get a new array with 1 in the spots where you
want a 1 in the output, and other values elsewhere. Then I can use
comparison to get a (boolean) array with 1s in the right place

I didn't find a satisfactory way to do that, but here's one that seemed
to work:array([[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[0, 0, 0, 1, 1],
[1, 1, 1, 0, 0],
[1, 1, 0, 1, 0]])array([[ 0, 0, 1, 2, 4],
[ 1, 2, 3, 5, 8],
[ 0, 0, 0, 1, 3],
[ 1, 3, 6, 9, 12],
[ 1, 3, 5, 8, 11]])array([[0, 0, 1, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[1, 0, 0, 0, 0],
[1, 0, 0, 0, 0]], type=Bool)

The first accumulate makes everything to the left of a 1 >0, and the
second accumulate makes it >1.

Jeff

Jeff,

Your solution works very well. I tried to do something similar, but with
N.cumsum instead of N.add.accumuluate. However, I never did the second
step, so I ended up with two "1:s" in each row and was, therefore, never
able to do the booelan comparison.

Thanks for yopur help!

Carl
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,950
Members
47,503
Latest member
supremedee

Latest Threads

Top