How to "scale" a numpy array? - python

I would like to scale an array of shape (h, w) by a factor of n, resulting in an array of shape (h*n, w*n), with the.
Say that I have a 2x2 array:
array([[1, 1],
[0, 1]])
I would like to scale the array to become 4x4:
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]])
That is, the value of each cell in the original array is copied into 4 corresponding cells in the resulting array. Assuming arbitrary array size and scaling factor, what's the most efficient way to do this?

You should use the Kronecker product, numpy.kron:
Computes the Kronecker product, a composite array made of blocks of the second array scaled by the first
import numpy as np
a = np.array([[1, 1],
[0, 1]])
n = 2
np.kron(a, np.ones((n,n)))
which gives what you want:
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]])

You could use repeat:
In [6]: a.repeat(2,axis=0).repeat(2,axis=1)
Out[6]:
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]])
I am not sure if there's a neat way to combine the two operations into one.

scipy.misc.imresize can scale images. It can be used to scale numpy arrays, too:
#!/usr/bin/env python
import numpy as np
import scipy.misc
def scale_array(x, new_size):
min_el = np.min(x)
max_el = np.max(x)
y = scipy.misc.imresize(x, new_size, mode='L', interp='nearest')
y = y / 255 * (max_el - min_el) + min_el
return y
x = np.array([[1, 1],
[0, 1]])
n = 2
new_size = n * np.array(x.shape)
y = scale_array(x, new_size)
print(y)

To scale effectively I use following approach. Works 5 times faster than repeat and 10 times faster that kron. First, initialise target array, to fill scaled array in-place. And predefine slices to win few cycles:
K = 2 # scale factor
a_x = numpy.zeros((h * K, w *K), dtype = a.dtype) # upscaled array
Y = a_x.shape[0]
X = a_x.shape[1]
myslices = []
for y in range(0, K) :
for x in range(0, K) :
s = slice(y,Y,K), slice(x,X,K)
myslices.append(s)
Now this function will do the scale:
def scale(A, B, slices): # fill A with B through slices
for s in slices: A[s] = B
Or the same thing simply in one function:
def scale(A, B, k): # fill A with B scaled by k
Y = A.shape[0]
X = A.shape[1]
for y in range(0, k):
for x in range(0, k):
A[y:Y:k, x:X:k] = B

Related

Split a matrix in N chunks

Given a matrix, I want to split it in equally smaller matrices of m x n size. If the matrix is not divisible by the given size, we just put the remainder into a different matrix.
For example, given the matrix below and m=2 and n=2:
[[1, 0, 1],
[0, 0, 0],
[0, 1, 1]]
Result:
[[1, 0],
[0, 0]],
[[1],
[0]],
[[0, 1]],
[[1]],
I was using np.reshape but it fails to split when the numbers don't match, as in the example above.
matrix_size = matrix.shape[0] * matrix.shape[1]
n_matrix = math.ceil(matrix_size / (m * n))
matrix.reshape(n_matrix, m, n)
One way you could do this is using multiple calls to numpy.array_split
import numpy as np
matrix = [
[1, 0, 1],
[0, 0, 0],
[0, 1, 1],
]
sub_matrices = np.array_split(matrix, 2, axis=0)
sub_matrices = [m for sub_matrix in sub_matrices for m in np.array_split(sub_matrix, 2, axis=1)]
Where the first call to array_split splits it vertically, and the second call splits it horizontally.

How to transform a vector in matrix according to following rules

I have a column vector y of length N containing a set of integers (1,2,3....K).
I want a matrix of size N x K of ones and zeros, as follows:
If the number in the vector y corresponds to the column index, the matrix has a one.
Otherwise, a zero.
Better with an example
y = [0,1,2,1]
Expected output
M = [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
[0, 1, 0]]
How can I implement this in python?
y = [0,1,2,1]
k = 3
arr = np.zeros((len(y),k))
for row, i in zip(arr, y):
row[i]=1
print(arr)
Without Using Numpy
y = [0,1,2,1]
k = 3
arr = [([0]*k).copy() for _ in range(len(y))]
for row, i in zip(arr, y):
row[i]=1
print(arr)
In [108]: M = np.zeros((4,3),int)
In [109]: M[np.arange(4), y] = 1
In [110]: M
Out[110]:
array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[0, 1, 0]])
This assigns 1 to elements specified by (i, y(i)).
In [111]: list(zip(np.arange(4), y))
Out[111]: [(0, 0), (1, 1), (2, 2), (3, 1)]

numpy indexing: add vector to parts of rows, starting at varying position

I have this 2d array of zeros z and this 1d array of starting points starts. In addition, I have an 1d array of offsets
z = z = np.zeros(35, dtype='i').reshape(5, 7)
starts = np.array([1, 5, 3, 0, 3])
offsets = np.arange(5) + 1
I would like to vectorize this little for loop here, but I seem to be unable to do it.
for i in range(z.shape[0]):
z[i, starts[i]:] += offsets[i]
The result in this example should look like this:
z
array([[0, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 2, 2],
[0, 0, 0, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4],
[0, 0, 0, 5, 5, 5, 5]])
We could use some masking and NumPy broadcasting -
mask = starts[:,None] <= np.arange(z.shape[1])
z[mask] = np.repeat(offsets, mask.sum(1))
We could play a trick of broadcasted multiplication to get the final output -
z = offsets[:,None] * mask
Other way would be to assign values into z from offsets and then mask out the rest of mask, like so -
z[:] = offsets[:,None]
z[~mask] = 0
And other way would be have a replicated version from offsets as the starting z and then mask out -
z = np.repeat(offsets,z.shape[1]).reshape(z.shape[0],-1)
z[~mask] = 0
Of course, we would need the shape parameters before-hand.
If z is not initialized as zeros array, then only one of the solutions mentioned earlier would be applicable and that would need to be updated with +=, like so -
z[mask] += np.repeat(offsets, mask.sum(1))

Python subtract first element from each respective row of matrix

I want to subtract the first value of a row from the rest of the elements of that row, so for
import numpy as np
z = np.array([[1,2,3,4],[4,5,6,7],[7,8,9,9]])
for n in range(0,3):
znew = z[n,:]-z[n,0]
znew should be np.array([[0,1,2,3],[0,1,2,3],[0,1,2,2]]). How can I do this? It kind of seems trivial.
You can do this by taking advantage of broadcasting:
>>> z - z[:,0][:, None] # or z - z[:,0][:, np.newaxis]
array([[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 2]])

Python: Sampling from a discrete distribution defined in an n-dimensional array

Is there a function in Python that samples from an n-dimensional numpy array and returns the indices of each draw. If not how would one go about defining such a function?
E.g.:
>>> probabilities = np.array([[.1, .2, .1], [.05, .5, .05]])
>>> print function(probabilities, draws = 10)
([1,1],[0,2],[1,1],[1,0],[0,1],[0,1],[1,1],[0,0],[1,1],[0,1])
I know this problem can be solved in many ways with 1-D arrays. However, I will be dealing with large n-dimensional arrays and can not afford to reshape them just to do a single draw.
You can use np.unravel_index:
a = np.random.rand(3, 4, 5)
a /= a.sum()
def sample(a, n=1):
a = np.asarray(a)
choices = np.prod(a.shape)
index = np.random.choice(choices, size=n, p=a.ravel())
return np.unravel_index(index, dims=a.shape)
>>> sample(a, 4)
(array([2, 2, 0, 2]), array([0, 1, 3, 2]), array([2, 4, 2, 1]))
This returns a tuple of arrays, one per dimension of a, each of length the number of samples requested. If you would rather have an array of shape (samples, dimensions), change the return statement to:
return np.column_stack(np.unravel_index(index, dims=a.shape))
And now:
>>> sample(a, 4)
array([[2, 0, 0],
[2, 2, 4],
[2, 0, 0],
[1, 0, 4]])
If your array is contiguous in memory, you can change the shape of your array in place:
probabilities = np.array([[.1, .2, .1], [.05, .5, .05]])
nrow, ncol = probabilities.shape
idx = np.arange( nrow * ncol ) # create 1D index
probabilities.shape = ( 6, ) # this is OK because your array is contiguous in memory
samples = np.random.choice( idx, 10, p=probabilities ) # sample in 1D
rowIndex = samples / nrow # convert to 2D
colIndex = samples % ncol
array([2, 0, 1, 0, 2, 2, 2, 2, 2, 0])
array([1, 1, 2, 0, 1, 1, 1, 1, 1, 1])
Note that since your array is contiguous in memory, reshape returns a view as well:
In [53]:
view = probabilities.reshape( 6, -1 )
view[ 0 ] = 9
probabilities[ 0, 0 ]
Out[53]:
9.0

Categories

Resources