Reputation: 1847
I need to generate an nX3 array of zeros but one of the columns has the value (1.0) staggered in each row.
Desired Output:
n = 10
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.]])
I tried to slice and reshape an array but some rows contain all zeros.
My Attemtp:
n = 10
verts_color = np.zeros(3 * n)
verts_color[::4] = 1
verts_color.reshape((n,3))
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 0., 0., 0.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 0., 0., 0.],
[ 1., 0., 0.],
[ 0., 1., 0.]])
I couldn't find an example or figure out how to solve this myself and was hoping someone here might be able to help me accomplish this?
Upvotes: 1
Views: 527
Reputation: 221564
Approach #1
def broadcasting_based(n, m): # n :number of cols, m : number of rows
return (np.mod(np.arange(m),n)[:,None] == np.arange(n)).astype(float)
Approach #2
def tile_based(n, m): # n :number of cols, m : number of rows
M = 1+((m-1)//n)
return np.tile(np.eye(n),M).T[:m]
Approach #3
def initialization_based(n, m): # n :number of cols, m : number of rows
M = 1+((m-1)//n)
r = np.arange(n)
out = np.zeros((M,n,n))
out[:,r,r] = 1
out.shape = (-1,n)
return out[:m]
One more initialization based, a shorter one and making use of stepsize to slice -
def initialization_based_v2(n, m): # n :number of cols, m : number of rows
out = np.zeros((m,n))
for i in range(n):
out[i::n,i] = 1
return out
Sample runs -
In [93]: broadcasting_based(n=3, m = 10)
Out[93]:
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.]])
In [94]: np.allclose(broadcasting_based(3,10), tile_based(3,10))
Out[94]: True
In [95]: np.allclose(broadcasting_based(3,10), initialization_based(3,10))
Out[95]: True
In [162]: np.allclose(broadcasting_based(3,10), initialization_based_v2(3,10))
Out[162]: True
Runtime test
Other approaches -
# @kmario23's soln
def using_concatenate(m, n):
return np.concatenate([np.identity(m)]* (n//m + 1), axis=0 )[:n, :]
# @Michael's soln
def initialization_modassign(m, n):
x = np.zeros((n,m))
i = np.arange(n)
x[i, i%m] = 1
return x
Timings -
In [188]: %timeit broadcasting_based(3,10000)
...: %timeit tile_based(3,10000)
...: %timeit initialization_based(3,10000)
...: %timeit initialization_based_v2(3,10000)
...: %timeit using_concatenate(3,10000)
...: %timeit initialization_modassign(3,10000)
...:
1000 loops, best of 3: 225 µs per loop
10000 loops, best of 3: 40.9 µs per loop
10000 loops, best of 3: 23.6 µs per loop
10000 loops, best of 3: 20.7 µs per loop
1000 loops, best of 3: 480 µs per loop
10000 loops, best of 3: 177 µs per loop
In [189]: %timeit broadcasting_based(5,10000)
...: %timeit tile_based(5,10000)
...: %timeit initialization_based(5,10000)
...: %timeit initialization_based_v2(5,10000)
...: %timeit using_concatenate(5,10000)
...: %timeit initialization_modassign(5,10000)
...:
1000 loops, best of 3: 238 µs per loop
10000 loops, best of 3: 63.6 µs per loop
10000 loops, best of 3: 33.3 µs per loop
10000 loops, best of 3: 33.3 µs per loop
1000 loops, best of 3: 275 µs per loop
10000 loops, best of 3: 176 µs per loop
So, on performance initialization_based_v2
seems to be working quite well.
Upvotes: 1
Reputation: 3483
import numpy as np
n = 10
x = np.zeros((n,3))
i = np.arange(n)
x[i, i%3] = 1
Upvotes: 1
Reputation: 61355
It's a bit quirky but it works by realizing the fact that you've (vertically) stacked identity arrays but you need to adjust the rows based on n
n = 10
np.vstack([np.identity(3)]* (n//3 + 1))[:n, :]
Alternatively, you can use np.concatenate
if you want improved performance:
np.concatenate([np.identity(3)]* (n//3 + 1), axis=0 )[:n, :]
For a general use case & improved performance use the following where (n, m)
are the rows and columns respectively.
np.concatenate([np.identity(m)]* (n//m + 1), axis=0 )[:n, :]
Example:
In [151]: n = 10
In [152]: np.vstack([np.identity(3)]* (n//3 + 1))[:n, :]
Out[152]:
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.]])
# number of columns
In [170]: m = 3
# number of rows
In [171]: n = 10
In [172]: np.concatenate([np.identity(m)]* (n//m + 1), axis=0 )[:n, :]
Out[172]:
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.]])
Performance:
In [176]: def using_concatenate(n, m):
...: return np.concatenate([np.identity(m)]* (n//m + 1), axis=0 )[:n, :]
...:
In [177]: %timeit using_concatenate(n, m)
10000 loops, best of 3: 22.8 µs per loop
Upvotes: 1