Numpy swap the values of nested columns - python

Given the following data structure is there some way I can swap the first and last column such that each row is [3, 2, 1] (I don't wish to sort them) without looping through each row?
[[[1 2 3]
[1 2 3]
[1 2 3]
...
[1 2 3]
[1 2 3]
[1 2 3]]
[[1 2 3]
[1 2 3]
[1 2 3]
...
[1 2 3]
[1 2 3]
[1 2 3]]]

Related

Is it possible to define function that creates an N-dimensional list of lists easily?

I have searched and found these questions: How to create a multi-dimensional list and N dimensional array in python which hint toward what I am looking for, but they seem to only make 2D arrays and not ND arrays.
Problem:
My problem is that I am able to create an n-dimensional list of lists for a known n, but I am not sure how it can be generalized to work with all values of n.
Consider this example:
def makeList(n):
return [[[n for _ in range(n)]
for _ in range(n)]
for _ in range(n)]
print(makeList(3))
Output:
[[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]]]
This will create a list of lists that is a 3x3x3 array of 3's which is the intended result, but if we use a different n:
print(makeList(2))
Output:
[[[2, 2],
[2, 2]],
[[2, 2],
[2, 2]]]
This will create a list of lists that is a 2x2x0 array of 2's and this is not the intended result. Instead the results should be a list of lists that is a 2x2 array of 2's.
Likewise if we set n = 4:
print(makeList(4))
This will give a list of lists that is 4x4x4 when it should give a 4x4x4x4 list of lists.
The main issue is that the number of for loops must change depending on the input, but obviously the code can't "come to life" and recode itself magically, hence my issue.
I am looking for a way to get this result that is simple. I am sure I could continue developing ideas for solutions, but I have not been able to think of anything that is concise.
What I have tried:
The first idea I thought of was to use recursion, and this my simple approach:
def makeList(n, output = []):
if not output:
output = [n for _ in range(n)]
else:
output = [output for _ in range(n)]
if len(output) == n:
return output
else:
return makeList(n, output)
This obviously will not work because if len(output) == n: will execute the first iteration since the length of the inner loops is equal to the length of the outermost loop. However, even if there was a condition that properly terminated the function, this solution would still not be ideal because I could run into maximum recursion errors with large values of n. Furthermore, even if these issues were resolved this code is still quite long as well as time consuming.
The other potential perspective I considered (and the solution that I found that works) is using a dict. My solution saves the intermediate lists of lists in a dict so it can be used for the next iteration:
def makeList(n):
d = {str(i): None for i in range(n)}
for i in range(n):
if i == 0:
d[str(i)] = [n for _ in range(n)]
else:
d[str(i)] = [d[str(i-1)] for _ in range(n)]
return d[str(n-1)]
But again, this is very long and doesn't seem very pythonic.
Solution requirements:
The ideal solution would be much more concise than mine with an efficient time complexity that only uses built-in functions.
Other options that are close to these requirements would also be helpful as long as the spirit of the answer is trying to best meet the requirements.
Being concise is the most important aspect, however, which is why I am not fully happy with my current attempts.
Using tuple(n for _ in range(n)) to get the dimension that you want, and numpy to generate a multidimensional array:
import numpy as np
def make_array(n):
return np.full(tuple(n for _ in range(n)), n)
for n in range(1,5):
print(make_array(n))
Output:
[1]
[[2 2]
[2 2]]
[[[3 3 3]
[3 3 3]
[3 3 3]]
[[3 3 3]
[3 3 3]
[3 3 3]]
[[3 3 3]
[3 3 3]
[3 3 3]]]
[[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]]
Your BEST plan is to use numpy for this. You can create an arbitrary array of all zeros with np.zeros( (4,4,4) ), or an array of 1s with np.ones( (4,4,4) ). If you're going to be working with arrays very much at all, you will certainly want to use numpy.
I've sketched out a recursive function that might suit:
def nd_list(n, x=None):
if x is None:
x = n
if x == 1:
return [n] * n
return [nd_list(n, x-1)] * n
In two lines using no external libraries!
def nd_list(x, z):
return [z] * z if x == 1 else [nd_list(x-1, z)] * z
In two lines (just) and without the list of lists surprising behaviour:
def nd_list(x, z):
return [0 for _ in range(z)] if x == 1 else [nd_list(x-1, z) for _ in range(z)]
I mean, I like numpy and all, but if I want to do general dynamic programming I don't want to have to pip install a massive library. Would also suck hard for technical interviews requiring complex DP.
Here's a simple, readable function that takes advantage of the built-in itertools module in Python (it uses repeat) and the copy module for making deep copies of lists (otherwise, you get that "surprising" list behavior where modifying one entry modifies many). It's also pretty sane in terms of the API: you can call it with a tuple of dimensions (like numpy's array's shape field):
from itertools import repeat
from copy import deepcopy
def ndarray(shape, val=None):
base = val
for dim in reversed(shape):
base = list(map(deepcopy, repeat(base, times=dim)))
return base
This is what is made:
>>> import pprint
>>> pprint.pprint(ndarray((2, 3, 4), val=1))
[[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]],
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]]
For your original question, you could easily wrap makeList(n) around this:
def makeList(n, val=None):
return ndarray([n]*n, val=val)
Using python support for pattern matching
def nlist(shape: tuple[int, ...], fill_with=None):
match shape:
case (n,):
return [fill_with] * n
case (n, *rest):
return [nlist(rest, fill_with) for _ in range(n)]
case _:
raise ValueError(f'Invalid value shape={shape}')
def makeList(n):
return nlist((n,)*n, n)

Unique symmetrical elements Numpy Array

I have a Numpy array as this:
[1 4]
[2 3]
[3 0]
[4 1]
[5 6]
[6 5]
[7 6]]
This is output of NearestNeighbors algorithm of scikit-learn. I want to remove duplicated values. To have something like this:
[[0 3]
[1 4]
[2 3]
[6 5]
[7 6]]
I searched a lot, but not found any solution.
One way with sorting and np.unique -
np.unique(np.sort(a, axis=1), axis=0)

Remove row from a numpy array according to some condition and concatenate result

I have a list of numpy arrays and I wanted to remove a row according to some condition.
Lets suppose I have the following list of numpy arrays and I want to delete the rows which contain an item that is > 8.
test = [np.array([[2,2,4],[10,3,5],[1,2,4,],[1,2,4]]),
np.array([[1,2,3],[1,3,5],[6,3,1],[9,1,2]])]
for i in test:
z = np.argwhere(i>8)
print(z)#[[1 0]] and [[3 0]]
a1 = np.delete(i,z,axis=0)
print(a1)
This for loop skips the numpy array of index[0]. How can Ifix this?
Returns:
[[1 2 4]
[1 2 4]]
[[1 3 5]
[6 3 1]]
Desirable Return:
[[2,2,4]
[1 2 4]
[1 2 4]]
[[1,2,3]
[1 3 5]
[6 3 1]]
From your example, you want to remove row with index 1 from the first array,
and row with index 3 from the second array.
So use those indices when executing np.delete:
a1 = np.delete(i, z[0][0], axis=0)
np.argwhere will return both indices, but we're only interested in the rows:
np.argwhere(i > 8)[:, 0]
But really, we're only interested in unique rows, so we can take care of that too:
np.unique(np.argwhere(i > 8)[:, 0])
Altogether we get:
test = [np.array([[2,2,4],[10,3,5],[1,2,4,],[1,2,4]]),np.array([[1,2,3],[1,3,5],[6,3,1],[9,1,2]])]
for i in test:
z = np.unique(np.argwhere(i>8)[:, 0])
a1 = np.delete(i,z,axis=0)
print(a1)
#[[2 2 4]
# [1 2 4]
# [1 2 4]]
#[[1 2 3]
# [1 3 5]
# [6 3 1]]

add field to memmaped numpy record array

With normal memmapped numpy arrays, you can "add" a new column by opening the memmap file with an additional column in the shape.
k = np.memmap('input', dtype='int32', shape=(10, 2), mode='r+', order='F')
k[:] = 1
l = np.memmap('input', dtype='int32', shape=(10, 3), mode='r+', order='F')
print(k)
print(l)
[[1 1]
[1 1]
[1 1]
[1 1]
[1 1]
[1 1]
[1 1]
[1 1]
[1 1]
[1 1]]
[[1 1 0]
[1 1 0]
[1 1 0]
[1 1 0]
[1 1 0]
[1 1 0]
[1 1 0]
[1 1 0]
[1 1 0]
[1 1 0]]
Is it possible to make a similar move with record arrays? Seems possible with rows, but can't find a way to do so with a new field, if the dtype has heterogeneous types.

Permutation of symmetric array in Python

I want to have the permutation for this symmetric matrix, if we move the the second column to the third the second row also should go to the third row.
array([[ 0. , 0.06377803, 0.1157737 , 0.19542195],
[ 0.06377803, 0. , 0.14754803, 0.23185761],
[ 0.1157737 , 0.14754803, 0. , 0.0843134 ],
[ 0.19542195, 0.23185761, 0.0843134 , 0. ]])
This is code for permutation on a list:
import numpy as np
x=[]
def perm(a, k=0):
if k == len(a):
x.extend(a)
# print (a )
else:
for i in range(k, len(a)):
a[k], a[i] = a[i] ,a[k]
perm(a, k+1)
a[k], a[i] = a[i], a[k]
perm([0,1,2,3])
a=np.asarray(x).reshape((24,4))
print(a)
Output:
[[0 1 2 3]
[0 1 3 2]
[0 2 1 3]
[0 2 3 1]
[0 3 2 1]
[0 3 1 2]
[1 0 2 3]
[1 0 3 2]
[1 2 0 3]
[1 2 3 0]
[1 3 2 0]
[1 3 0 2]
[2 1 0 3]
[2 1 3 0]
[2 0 1 3]
[2 0 3 1]
[2 3 0 1]
[2 3 1 0]
[3 1 2 0]
[3 1 0 2]
[3 2 1 0]
[3 2 0 1]
[3 0 2 1]
[3 0 1 2]]
But I want to have the permutation for the above array which is 4*4. For simplicity if we have a 3*3 array, we want something like below which is K!=6 but when k=4 then we have to get k! which is 24 permutations
import numpy as np
from itertools import permutations
n = 3
a = np.arange(n**2).reshape(n, n)
for perm in permutations(range(a.shape[0])):
b = np.zeros_like(a)
b[:, :] = a[perm, :]
b[:, :] = b[:, perm]
print(b)
gives the 6 following matrices:
[[0 1 2]
[3 4 5]
[6 7 8]]
[[0 2 1]
[6 8 7]
[3 5 4]]
[[4 3 5]
[1 0 2]
[7 6 8]]
[[4 5 3]
[7 8 6]
[1 2 0]]
[[8 6 7]
[2 0 1]
[5 3 4]]
[[8 7 6]
[5 4 3]
[2 1 0]]
Is this the question?

Categories