Merge equally sized arrays into tiled big array - python

I'm having a hard time phrasing what I want, which is why I didn't find it on Google. Let me start with an example before formulating the general case.
Say we have 7 arrays a1, ..., a7, each of shape (4, 5). I want a new array where the 7 arrays are arranged like this:
a1 a2 a3
a4 a5 a6
a7 0 0
This array is of shape (3*4, 3*5) == (12, 15), 0 is np.zeros((4, 5)).
In general, I have C arrays a1, ..., aC, of shape (H, W), and I want to put them into an array of shape (h*H, w*W), where h = ceil(sqrt(C)) and w = ceil(C/h). The C arrays are stored as one (C, H, W) dimensional array.
What's the most elegant way to do this? I was hacking something together by iterating over the necessary indices but it's not nice so I stopped.
Speed is not top priority and the arrays are fairly small.

Approach #1
Some permuting of axes and reshaping should do the job -
C,m,n = a.shape
h = int(np.ceil(np.sqrt(C)))
w = int(np.ceil(C/h))
out = np.zeros((h,w,m,n),dtype=a.dtype)
out.reshape(-1,m,n)[:C] = a
out = out.swapaxes(1,2).reshape(-1,w*n)
Sample input, output -
In [340]: a
Out[340]:
array([[[55, 58],
[75, 78]],
[[78, 20],
[94, 32]],
[[47, 98],
[81, 23]],
[[69, 76],
[50, 98]],
[[57, 92],
[48, 36]],
[[88, 83],
[20, 31]],
[[91, 80],
[90, 58]]])
In [341]: out
Out[341]:
array([[55, 58, 78, 20, 47, 98],
[75, 78, 94, 32, 81, 23],
[69, 76, 57, 92, 88, 83],
[50, 98, 48, 36, 20, 31],
[91, 80, 0, 0, 0, 0],
[90, 58, 0, 0, 0, 0]])
Approach #2
Simpler one with zeros-concatenation -
z = np.zeros((h*w-C,m,n),dtype=a.dtype)
out = np.concatenate((a,z)).reshape(h,w,m,n).swapaxes(1,2).reshape(-1,w*n)
That could be modified/simplified a bit by using zeros-padding with np.pad -
zp = np.pad(a,((0,h*w-C),(0,0),(0,0)),'constant')
out = zp.reshape(h,w,m,n).swapaxes(1,2).reshape(-1,w*n)

Related

How to find the smallest value of element in matrix with size (9,2,2)

Supposing I have a matrix A with the np.shape(A) = (9,2,2).
Then, I would like to find the smallest element value for the inner matrix (2,2) of total 9 outer matrix. Let's call it B.
Could anyone let me know what is the numpy code, please?
Thank you in advance.
import numpy as np
A =np.array([[[24, 73],
[35, 67]],
[[35, 68],
[21, 5]],
[[29, 69],
[60, 46]],
[[98, 25],
[50, 92]],
[[63, 27],
[55, 28]],
[[60, 89],
[61, 66]],
[[87, 38],
[44, 33]],
[[64, 76],
[76, 70]],
[[90, 91],
[71, 58]]])
np.shape(A)
Expected Result
B = [24,5,29,25,27,60,38,64,58]
np.shape(B) = (9,)
Solution
import numpy as np
A =np.array([[[24, 73],
[35, 67]],
[[35, 68],
[21, 5]],
[[29, 69],
[60, 46]],
[[98, 25],
[50, 92]],
[[63, 27],
[55, 28]],
[[60, 89],
[61, 66]],
[[87, 38],
[44, 33]],
[[64, 76],
[76, 70]],
[[90, 91],
[71, 58]]])
B1 = A.min(axis=(1, 2))
B2 = np.min(A, axis=(1, 2))
print("B1 =", B1)
print("B2 =", B2)
print("np.shape(B1) =", np.shape(B1))
Find minimum value with 2 menthods
1.
B1 = A.min(axis=(1, 2))
2.
B2 = np.min(A, axis=(1, 2))
Find shape of array in numpy
shape = np.shape(B1)
Output
B1 = [24 5 29 25 27 60 33 64 58]
B2 = [24 5 29 25 27 60 33 64 58]
np.shape(B1) = (9,)
Use min aggregating on the last two axes:
A.min((1, 2))
Alternatively, if you want a generic code to handle any number of dimensions, reshape then aggregate the min on the last dimension:
A.reshape(A.shape[0], -1).min(-1)
Output: array([24, 5, 29, 25, 27, 60, 33, 64, 58])
Since you wish only the get the code, there you go:
np.min(A, axis=(1,2))

How do I convert a matrix of integers to a matrix of lists of integers in numpy?

I'm quite new to numpy, I tried with vstack but it seems really wrong since it creates a copy in memory everytime.
The initial structure is:
[[1,2,3],
[1,2,3],
[1,2,3]]
and it will be mapped to:
[[[3,2,1,2], [4,5,2,7], [7,4,1,3]],
[[3,2,1,2], [4,5,2,7], [7,4,1,3]],
[[3,2,1,2], [4,5,2,7], [7,4,1,3]]]
The numbers here don't have any meaning, it's just to show the structure, basically each integer is decoded to a list of integers N -> [N_1, N_2, N_3, N_4]
For context I have pixels encoded in 32bits and I have to decode them to argb
Create uint8 view:
>>> ar = np.random.randint(0, 2 ** 31, (3, 3))
>>> ar
array([[ 437217537, 524850213, 771706759],
[ 467263015, 219221544, 1712453711],
[1444860139, 625411292, 1224272631]])
>>> ar[1:] = ar[0] # make the layout the same as the example of OP
>>> ar
array([[437217537, 524850213, 771706759],
[437217537, 524850213, 771706759],
[437217537, 524850213, 771706759]])
>>> ar.view(np.uint8).reshape(3, 3, -1)
array([[[ 1, 105, 15, 26],
[ 37, 148, 72, 31],
[135, 79, 255, 45]],
[[ 1, 105, 15, 26],
[ 37, 148, 72, 31],
[135, 79, 255, 45]],
[[ 1, 105, 15, 26],
[ 37, 148, 72, 31],
[135, 79, 255, 45]]], dtype=uint8)
>>> int.from_bytes(bytes(_[0, 0]), 'little') == ar[0, 0]
True

How to reshape numpy array keeping each nth element

I have a numpy array of shape, say, (1000, 80) and I want to convert it to (100, 40, 2). You can think of it as having 1000 observations where the first 40 columns refer to a specific feature across 40 days and the next 40 columns to a 2nd feature across the same 40 days.
So, I want to the 2nd dimension to be the 40 days while the 3rd should be the values of these two features for each day.
Here's a simple example with what I tried:
import numpy as np
data = [[11, 22, 33, 44],
[55, 66, 77 ,88],
[99, 100, 101, 102]]
data = np.array(data)
# This works but I have to manually do it for every day
np.c_[data[:, ::2], data[:, 1::2]].reshape((3, 2, 2))
# This does not work
np.c_[data[:, i::2] for i in range(2)].reshape((3, 2, 2))
Desired output:
array([[[ 11, 33],
[ 22, 44]],
[[ 55, 77],
[ 66, 88]],
[[ 99, 101],
[100, 102]]])
You can reshape first and then transpose the second and third axis:
data.reshape(-1, 2, data.shape[1] / 2).transpose(0,2,1)
#array([[[ 11, 33],
# [ 22, 44]],
# [[ 55, 77],
# [ 66, 88]],
# [[ 99, 101],
# [100, 102]]])
Or swapaxes:
data.reshape(-1, 2, data.shape[1] / 2).swapaxes(1,2)
#array([[[ 11, 33],
# [ 22, 44]],
# [[ 55, 77],
# [ 66, 88]],
# [[ 99, 101],
# [100, 102]]])
Or as #wwii commented, reshape with column-major order:
data.reshape(-1, data.shape[1] / 2, 2, order='F')

Multiply each row of one array with each element of another array in numpy

I have two arrays A and B in numpy. A holds cartesian coordinates, each row is one point in 3D space and has the shape (r, 3). B has the shape (r, n) and holds integers.
What I would like to do is multiply each element of B with each row in A, so that the resulting array has the shape (r, n, 3). So for example:
# r = 3
A = np.array([1,1,1, 2,2,2, 3,3,3]).reshape(3,3)
# n = 2
B = np.array([10, 20, 30, 40, 50, 60]).reshape(3,2)
# Result with shape (3, 2, 3):
# [[[10,10,10], [20,20,20]],
# [[60,60,60], [80,80,80]]
# [[150,150,150], [180,180,180]]]
I'm pretty sure this can be done with np.einsum, but I've been trying this for quite a while now and can't get it to work.
Use broadcasting -
A[:,None,:]*B[:,:,None]
Since np.einsum also supports broadcasting, you can use that as well (thanks to #ajcr for suggesting this concise version) -
np.einsum('ij,ik->ikj',A,B)
Sample run -
In [22]: A
Out[22]:
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
In [23]: B
Out[23]:
array([[10, 20],
[30, 40],
[50, 60]])
In [24]: A[:,None,:]*B[:,:,None]
Out[24]:
array([[[ 10, 10, 10],
[ 20, 20, 20]],
[[ 60, 60, 60],
[ 80, 80, 80]],
[[150, 150, 150],
[180, 180, 180]]])
In [25]: np.einsum('ijk,ij->ijk',A[:,None,:],B)
Out[25]:
array([[[ 10, 10, 10],
[ 20, 20, 20]],
[[ 60, 60, 60],
[ 80, 80, 80]],
[[150, 150, 150],
[180, 180, 180]]])

Python: conversion of a iterated assignment with an atomic assignment using numpy is not working when matrix height > 256

I'm working using numpy 1.6.2 and python 2.7.
Given an N x M x D matrix A and a matrix I that contains a list of indices.
I have to fill a zeros matrix ACopy with the sum of element of A according to the indeces found in I (see code).
Here is my code:
ACopy = zeros(A.shape)
for j in xrange(0, size(A, 0)):
i = I[j]
ACopy[j, i, :] = A[j, i, :] + A[j, i + 1, :]
Indices matrix:
I = array([2, 0, 3, 2, 1])
A matrix:
A = array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]],
[[15, 16, 17],
[18, 19, 20],
[21, 22, 23],
[24, 25, 26],
[27, 28, 29]],
[[30, 31, 32],
[33, 34, 35],
[36, 37, 38],
[39, 40, 41],
[42, 43, 44]],
[[45, 46, 47],
[48, 49, 50],
[51, 52, 53],
[54, 55, 56],
[57, 58, 59]],
[[60, 61, 62],
[63, 64, 65],
[66, 67, 68],
[69, 70, 71],
[72, 73, 74]]])
I try to improve my code avoiding the for loop in this way:
r = r_[0:len(I)]
ACopy[r, I, :] = A[r, I, :] + A[r, I + 1, :]
I noticed that the output matrices ACopy are different and I can't understand why. Any idea?
Thank you all!
EDIT: I'm computing a lot of matrices and I try with np.array_equals(ACopy1,ACopy2), where ACopy1 is the output of the first method and ACopy2 the output of the second method. Sometimes the matrices are the same, but not everytime. The two methods output should be the same or are there any bordeline case?
EDIT2: I noticed that this strange behaviour happens only when matrix height is bigger than 256.
Here is my test suite:
from numpy import *
w = 5
h = 257
for i in xrange(1000):
Z = random.rand(w, h, 5)
I = (random.rand(w) * h - 1).astype(uint8)
r = r_[0:w]
ZCopy = zeros(Z.shape)
ZCopy2 = zeros(Z.shape)
for j in xrange(0, size(Z, 0)):
i = I[j]
ZCopy[j, i, :] = Z[j, i, :] + Z[j, i + 1, :]
ZCopy2[r, I, :] = Z[r, I, :] + Z[r, I + 1, :]
if (ZCopy - ZCopy2).any() > 0:
print(ZCopy, ZCopy2, I)
raise ValueError
I get the problem!
I cast the matrix I to uint8 and so matrix I elements are between 0 and 255.
I resolved using I = (random.rand(w) * h - 1).astype(uint32)

Categories

Resources