Unpack items and add a new one - python

I need to create a new list merging two lists where one of them is a list of lists. Here's what I need to do:
a = [[2, 1, 4, 5, 0], [3, 6, 5, 4, 8], [2, 1, 4, 7, 8], [3, 4, 9, 5, 6], [7, 5, 2, 1, 1]]
b = [2, 3, 5, 0, 8]
c = []
for indx, item in enumerate(a):
c.append([item, b[indx]])
This generates c as:
[[[2, 1, 4, 5, 0], 2], [[3, 6, 5, 4, 8], 3], [[2, 1, 4, 7, 8], 5], [[3, 4, 9, 5, 6], 0], [[7, 5, 2, 1, 1], 8]]
but I would need it to look like:
[[2, 1, 4, 5, 0, 2], [3, 6, 5, 4, 8, 3], [2, 1, 4, 7, 8, 5], [3, 4, 9, 5, 6, 0], [7, 5, 2, 1, 1], 8]
I've tried adding a * in front of item to unpack the elements but that doesn't work.

Just concatenate the items to create a new list from item and the element from b:
for indx, item in enumerate(a):
c.append(item + [b[indx]])
You can simplify your loop using the zip() function:
for a_item, b_item in zip(a, b):
c.append(a_item + [b_item])
Then move the whole definition of c to a list comprehension:
c = [a_item + [b_item] for a_item, b_item in zip(a, b)]
Demo:
>>> a = [[2, 1, 4, 5, 0], [3, 6, 5, 4, 8], [2, 1, 4, 7, 8], [3, 4, 9, 5, 6], [7, 5, 2, 1, 1]]
>>> b = [2, 3, 5, 0, 8]
>>> [a_item + [b_item] for a_item, b_item in zip(a, b)]
[[2, 1, 4, 5, 0, 2], [3, 6, 5, 4, 8, 3], [2, 1, 4, 7, 8, 5], [3, 4, 9, 5, 6, 0], [7, 5, 2, 1, 1, 8]]

You can make use of zip() function and list comprehension:
>>> a = [[2, 1, 4, 5, 0], [3, 6, 5, 4, 8], [2, 1, 4, 7, 8], [3, 4, 9, 5, 6], [7, 5, 2, 1, 1]]
>>> b = [2, 3, 5, 0, 8]
>>> [elem1 + [elem2] for elem1, elem2 in zip(a, b)]
[[2, 1, 4, 5, 0, 2], [3, 6, 5, 4, 8, 3], [2, 1, 4, 7, 8, 5], [3, 4, 9, 5, 6, 0], [7, 5, 2, 1, 1, 8]]

Related

Is there an alternate way to do the same without for loop?

I have two numpy arrays A and l. The dimension of A is (n, x, y) and the dimension of l is (n,1). I get the result as follows:
res = []
for i in range(n):
res.append(A[i, x, l[i])
This way of getting the result is very time consuming for a larger value of n. Is there an alternative to get the same result quickly?
If 0<=l[i]<y for all values of i:
>>> n,x,y = 4,5,6
>>> A = np.random.randint(0,10,(n,x,y))
array([[[3, 3, 3, 8, 7, 0],
[8, 1, 1, 5, 3, 8],
[0, 1, 0, 4, 1, 3],
[2, 2, 1, 8, 6, 5],
[2, 5, 9, 2, 6, 3]],
[[9, 7, 4, 6, 7, 7],
[1, 7, 0, 4, 9, 6],
[8, 0, 8, 6, 7, 8],
[1, 9, 7, 8, 7, 6],
[2, 4, 6, 3, 6, 8]],
[[2, 8, 5, 7, 9, 4],
[7, 2, 2, 5, 2, 1],
[0, 8, 6, 4, 1, 2],
[6, 9, 9, 0, 2, 4],
[9, 9, 1, 6, 7, 0]],
[[3, 8, 4, 3, 5, 6],
[5, 3, 7, 7, 4, 6],
[9, 0, 7, 9, 2, 1],
[1, 6, 2, 2, 9, 5],
[5, 0, 9, 0, 5, 2]]])
>>> l = np.random.randint(low=0, high=y-1, size=(n,1))
array([[0],
[1],
[3],
[1]])
>>> x0 = 2
>>> res = []
>>> for i in range(n):
res.append(A[i, x0, l[i])
>>> res
[array([0]), array([0]), array([4]), array([0])]
numpy:
>>> A[range(n), 2, l.flatten()]
array([0, 0, 4, 0])
what about list comprehension?
res=[A[i, x, l[i] for i in range(n)]

How to get data out of an array

I have an array as such from a txt file:
[[1, 4, 6, 2, 5]
[3, 4, 3, 5, 4]
[5, 3, 6, 7, 1]]
[[3, 4, 2, 5, 8]
[5, 2, 7, 5, 4]
[4, 2, 4, 4, 0]]
[[2, 5, 3, 1, 4]
[3, 8, 5, 6, 2]
[2, 6, 7, 4, 2]]
I want to take the mean of the 3rd row for each group of results. so each group is in a double bracket [[1, 4, 6, 2, 5]
[3, 4, 3, 5, 4]
[5, 3, 6, 7, 1]] is one group,
[[3, 4, 2, 5, 8]
[5, 2, 7, 5, 4]
[4, 2, 4, 4, 0]] is the second group etc.)
How do I access each group individually?
If you want to take the mean of the third row of each group with:
>>> data[:,2].mean(axis=1)
array([4.4, 2.8, 4.2])
If data is for example:
>>> data
array([[[1, 4, 6, 2, 5],
[3, 4, 3, 5, 4],
[5, 3, 6, 7, 1]],
[[3, 4, 2, 5, 8],
[5, 2, 7, 5, 4],
[4, 2, 4, 4, 0]],
[[2, 5, 3, 1, 4],
[3, 8, 5, 6, 2],
[2, 6, 7, 4, 2]]])
then by slicing, we obtain the third row of each group:
>>> data[:,2]
array([[5, 3, 6, 7, 1],
[4, 2, 4, 4, 0],
[2, 6, 7, 4, 2]])
Then for each row we can calculate the mean with .mean(axis=1)
If your data is like this, This code will work fine
lst =[
[[1, 4, 6, 2, 5],[3, 4, 3, 5, 4],[5, 3, 6, 7, 1]],
[[3, 4, 2, 5, 8],[5, 2, 7, 5, 4],[4, 2, 4, 4, 0]],
[[2, 5, 3, 1, 4],[3, 8, 5, 6, 2],[2, 6, 7, 4, 2]]
]
import numpy as np
means = []
for i in lst:
means.append(np.mean(i[2]))
print(means)
>> [4.4, 2.8, 4.2]

Adding a n extra colum from another matrix

I have these two matrices:
A = [[2, 7, 3, 6], [3, 3, 4, 4], [6, 9, 5, 3], [4, 2, 1, 7]]
B = [[2, 6, 3, 5], [-1, 2, -3, 1], [2, -5, 7, 3]]
I need to create three matrices A+1st column of B, and so on
So I need this final result:
A1 = [[2, 7, 3, 6, 2], [3, 3, 4, 4, 6], [6, 9, 5, 3, 3], [4, 2, 1, 7, 5]]
A2 = [[2, 7, 3, 6, -1], [3, 3, 4, 4, 2], [6, 9, 5, 3, -3], [4, 2, 1, 7, 7]]
A3 = [[2, 7, 3, 6, 2], [3, 3, 4, 4, -5], [6, 9, 5, 3, 7], [4, 2, 1, 7, 3]]
I start doing the following code, but I only got one of those
for j in range(len(B)):
for i in range(j):
b = B[j][i]
A = [x + [b] for x in A]
print(A)
Output:
[[2, 7, 3, 6], [3, 3, 4, 4], [6, 9, 5, 3], [4, 2, 1, 7]]
[[2, 7, 3, 6, -1], [3, 3, 4, 4, -1], [6, 9, 5, 3, -1], [4, 2, 1, 7, -1]]
[[2, 7, 3, 6, -1, 2, -5], [3, 3, 4, 4, -1, 2, -5], [6, 9, 5, 3, -1, 2, -5], [4, 2, 1, 7, -1, 2, -5]]
Process finished with exit code 0
You can leverage enumerate() to get your output:
A = [[2, 7, 3, 6], [3, 3, 4, 4], [6, 9, 5, 3], [4, 2, 1, 7]]
B = [[2, 6, 3, 5], [-1, 2, -3, 1], [2, -5, 7, 3]]
AA ={}
for idx,inner in enumerate(B):
# add to each a from A the k-th elem of your inner
AA[f"A{idx}"] = [a +[inner[k]] for k,a in enumerate(A)]
print(AA) # stored the lists into a dict
{'A0': [[2, 7, 3, 6, 2], [3, 3, 4, 4, 6], [6, 9, 5, 3, 3], [4, 2, 1, 7, 5]],
'A1': [[2, 7, 3, 6, -1], [3, 3, 4, 4, 2], [6, 9, 5, 3, -3], [4, 2, 1, 7, 1]],
'A2': [[2, 7, 3, 6, 2], [3, 3, 4, 4, -5], [6, 9, 5, 3, 7], [4, 2, 1, 7, 3]]}
As a personal preference I avoid using range(len(...)) where I can - enumerate is cleaner.
If string literals do not work for you, use "A{}".format(idx) instead.
Your code does not work because you coupled the range of i to j
for j in range(len(B)): # j starts as 0,1,2
for i in range(j): # i is doing nothing, 0, 0+1 <-- wrong
This is a possible solution that you can certainly start with:
k = len(A)
D = []
for i in range(len(B)):
D.append([])
for j in range(len(A)):
C = A[j][:k]
C.append(B[i][j])
D[i].append(C)
Make sure to use deepcopy so that they are not all referring to the same object.
A = [[2, 7, 3, 6], [3, 3, 4, 4], [6, 9, 5, 3], [4, 2, 1, 7]]
B = [[2, 6, 3, 5], [-1, 2, -3, 1], [2, -5, 7, 3]]
from copy import deepcopy
A_list = [deepcopy(A) for i in range(3)]
for outer_idx, list_in_b in enumerate(B):
for inner_idx, value in enumerate(list_in_b):
A_list[outer_idx][inner_idx].append(value)
print(A_list)
# Output:
#[[[2, 7, 3, 6, 2], [3, 3, 4, 4, 6], [6, 9, 5, 3, 3], [4, 2, 1, 7, 5]],
# [[2, 7, 3, 6, -1], [3, 3, 4, 4, 2], [6, 9, 5, 3, -3], [4, 2, 1, 7, 1]],
# [[2, 7, 3, 6, 2], [3, 3, 4, 4, -5], [6, 9, 5, 3, 7], [4, 2, 1, 7, 3]]]

How to get k top elements of multidimensional array along a axis instead of one that argmax gives

I have a prediction in the format of np.argmax(model.predict(X),axis=2) which returns one element.How to predict top k elements using numpy
The link provided by #desertnaut covers the 1D case. It is, however, not entirely trivial to generalize the good answer to "ND along axis".
Here is an example where we find the top 2 along axis 1:
>>> a = np.random.randint(0, 9, (3, 5, 6))
>>> b = a.argpartition(-2, axis=1)[:, -2:]
>>> i, j, k = a.shape
>>> i, j, k = np.ogrid[:i, :j, :k]
>>> b = b[i, a[i, b, k].argsort(axis=1), k]
>>> a
array([[[8, 4, 1, 2, 4, 8],
[0, 1, 3, 4, 2, 7],
[4, 2, 7, 8, 1, 4],
[1, 6, 2, 0, 3, 7],
[1, 0, 0, 2, 8, 1]],
[[1, 6, 3, 3, 0, 6],
[7, 2, 0, 3, 8, 5],
[5, 0, 1, 1, 7, 4],
[2, 2, 4, 2, 6, 2],
[5, 5, 7, 6, 8, 1]],
[[4, 4, 4, 6, 2, 5],
[2, 7, 8, 2, 6, 0],
[5, 6, 7, 5, 1, 6],
[6, 5, 3, 2, 2, 3],
[5, 1, 8, 1, 6, 8]]])
>>> a[i, b, k]
array([[[4, 4, 3, 4, 4, 7],
[8, 6, 7, 8, 8, 8]],
[[5, 5, 4, 3, 8, 5],
[7, 6, 7, 6, 8, 6]],
[[5, 6, 8, 5, 6, 6],
[6, 7, 8, 6, 6, 8]]])
A general function could look like
def argtopk(A, k, axis=0):
tk = A.argpartition(-k, axis=axis)[(*axis*(slice(None),), slice(-k, None))]
I = np.ogrid[(*map(slice, A.shape),)]
I[axis] = tk
I[axis] = A[I].argsort(axis=axis)
return tk[I]

How to get all submatrices of given size in numpy?

For example, x = np.random.randint(low=0, high=10, shape=(6,6)) gives me a 6x6 numpy array:
array([[3, 1, 0, 1, 5, 4],
[2, 9, 9, 4, 8, 8],
[2, 3, 4, 3, 2, 9],
[5, 8, 4, 5, 7, 6],
[3, 0, 8, 1, 8, 0],
[6, 7, 1, 9, 0, 5]])
How can I get a list of, say, all 2x3 submatrices? What about non-overlapping ones?
I could code this in myself, but I'm sure this is a common enough operation that it already exists in numpy, I just can't find it.
Listed in this post is a generic approach to get a list of submatrices with given shape. Based on the order of submatrices being row (C-style) or column major (fortran-way), you would have two choices. Here's the implementation with np.reshape , np.transpose and np.array_split -
def split_submatrix(x,submat_shape,order='C'):
p,q = submat_shape # Store submatrix shape
m,n = x.shape
if np.any(np.mod(x.shape,np.array(submat_shape))!=0):
raise Exception('Input array shape is not divisible by submatrix shape!')
if order == 'C':
x4D = x.reshape(-1,p,n/q,q).transpose(0,2,1,3).reshape(-1,p,q)
return np.array_split(x4D,x.size/(p*q),axis=0)
elif order == 'F':
x2D = x.reshape(-1,n/q,q).transpose(1,0,2).reshape(-1,q)
return np.array_split(x2D,x.size/(p*q),axis=0)
else:
print "Invalid output order."
return x
Sample run with a modified sample input -
In [201]: x
Out[201]:
array([[5, 2, 5, 6, 5, 6, 1, 5],
[1, 1, 8, 4, 4, 5, 2, 5],
[4, 1, 6, 5, 6, 4, 6, 1],
[5, 3, 7, 0, 5, 8, 6, 5],
[7, 7, 0, 6, 5, 2, 5, 4],
[3, 4, 2, 5, 0, 7, 5, 0]])
In [202]: split_submatrix(x,(3,4))
Out[202]:
[array([[[5, 2, 5, 6],
[1, 1, 8, 4],
[4, 1, 6, 5]]]), array([[[5, 6, 1, 5],
[4, 5, 2, 5],
[6, 4, 6, 1]]]), array([[[5, 3, 7, 0],
[7, 7, 0, 6],
[3, 4, 2, 5]]]), array([[[5, 8, 6, 5],
[5, 2, 5, 4],
[0, 7, 5, 0]]])]
In [203]: split_submatrix(x,(3,4),order='F')
Out[203]:
[array([[5, 2, 5, 6],
[1, 1, 8, 4],
[4, 1, 6, 5]]), array([[5, 3, 7, 0],
[7, 7, 0, 6],
[3, 4, 2, 5]]), array([[5, 6, 1, 5],
[4, 5, 2, 5],
[6, 4, 6, 1]]), array([[5, 8, 6, 5],
[5, 2, 5, 4],
[0, 7, 5, 0]])]

Categories