Python - How to add n zeros randomly in an existing matrix? - python

i have this array that i generated using the default_rng:
import numpy as np
from numpy.random import default_rng
rng = default_rng(seed=10)
rng = rng.integers(1,20,(5,10))
rng
>>>array([[15, 19, 6, 4, 16, 16, 10, 3, 16, 10],
[ 3, 3, 8, 14, 8, 16, 1, 9, 10, 19],
[ 5, 16, 2, 7, 15, 11, 18, 15, 18, 16],
[ 3, 18, 17, 3, 19, 15, 6, 3, 8, 18],
[15, 5, 10, 17, 13, 6, 3, 19, 5, 10]], dtype=int64)
I want to add 10 zeros in this matrix using the generator with seed=5.
I thought to create a new array with dimessions [5,10] and to put 10 zeros inside and the rest to be one and then mutliply the two arrays but i have to use the generator so i can't do this.

Try with np.random.choice to choose the index, then set the values at those indexes to 0:
np.random.seed(10)
idx = np.random.choice(np.arange(5*10), size=5, replace=False)
rng.ravel()[idx] = 0
Output:
array([[15, 19, 6, 4, 16, 16, 10, 3, 16, 10],
[ 3, 3, 8, 14, 8, 16, 1, 9, 10, 19],
[ 5, 16, 2, 0, 15, 11, 18, 15, 18, 16],
[ 3, 18, 17, 3, 19, 15, 6, 0, 8, 18],
[15, 5, 0, 17, 0, 6, 3, 0, 5, 10]])

Of course
idx = np.random.choice(rng.ravel(), 10, replace= False)
print(idx)
rng.ravel()[idx] = 0
rng
Output
[10 17 3 6 15 15 15 16 15 15]
array([[15, 19, 6, 0, 16, 16, 0, 3, 16, 10],
[ 0, 3, 8, 14, 8, 0, 0, 0, 10, 19],
[ 5, 16, 2, 7, 15, 11, 18, 15, 18, 16],
[ 3, 18, 17, 3, 19, 15, 6, 3, 8, 18],
[15, 5, 10, 17, 13, 6, 3, 19, 5, 10]], dtype=int64)
So instead of take 10 zeros i take only 6 becaus of 15 appears five times in my idx.

Related

Filtering nested lists with python conditions

how are you?
I have a distance matrix and need to perform a filter based on another list before applying some functions.
The matrix has 10 elements that represent machines and the distances between them, I need to filter this list by getting only the distances between some chosen machines.
matrix = [[0, 1, 3, 17, 24, 12, 18, 16, 17, 15],
[1, 0, 2, 2, 5, 6, 13, 11, 12, 10],
[3, 2, 0, 1, 6, 12, 18, 12, 17, 15],
[17, 2, 1, 0, 3, 12, 17, 15, 16, 14],
[24, 5, 6, 3, 0, 1, 24, 22, 23, 21],
[12, 6, 12, 12, 1, 0, 12, 10, 11, 9],
[18, 13, 18, 17, 24, 12, 0, 3, 4, 5],
[16, 11, 12, 15, 22, 10, 3, 0, 1, 2],
[17, 12, 17, 16, 23, 11, 4, 1, 0, 1],
[15, 10, 15, 14, 21, 9, 5, 2, 1, 0]]
The list used for filtering, for example, is:
filter_list = [1, 2, 7, 10]
The idea is to use this list to filter the rows and the indices of the sublists to get the final matrix:
final_matrix = [[0, 1, 18, 15],
[1, 0, 13, 10],
[18, 13, 0, 5],
[15, 10, 5, 0]]
It is worth noting that the filter list elements vary. Can someone please help me?
That's what I tried:
final_matrix = []
for i in range(0, len(filter_list)):
for j in range(0,len(filter_list[i])):
a = filter_list[i][j]
final_matrix .append(matrix[a-1])
print(final_matrix)
This is because the filter_list can have sublists. I get it:
final_matrix = [[0, 1, 3, 17, 24, 12, 18, 16, 17, 15],
[1, 0, 2, 2, 5, 6, 13, 11, 12, 10],
[18, 13, 18, 17, 24, 12, 0, 3, 4, 5],
[15, 10, 15, 14, 21, 9, 5, 2, 1, 0]]
I could not remove the spare elements.
You forgot to filter by column ids. You can do this using nested list comprehensions.
final_matrix = [[matrix[row-1][col-1] for col in filter_list] for row in filter_list]
final_matrix = []
for i in filter_list:
to_append = []
for j in filter_list:
to_append.append(matrix[i-1][j-1])
final_matrix.append(to_append)
or with list comprehension
final_matrix = [[matrix[i-1][j-1] for j in filter_list] for i in filter_list]

Prevent IPython from displaying long lists one element per line

In Jupyter notebooks, or in IPython, long lists are displayed one element per line. How do I display them on a single line? I don't mind if the line wraps.
In the following example, I'd like the 3rd list to be shown as a "row", not as a "column".
In [1]: [list(range(n)) for n in range(10,40,10)]
Out[1]:
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[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]]
The output I am looking for is the following or similar:
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[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]]
My goal is to make the output easier to read for humans.
I would simply use
A = [list(range(n)) for n in range(10,40,10)]
for i in A:
print(i)

Swaping columns of numpy array in all rows but the first one

Given a numpy array
import numpy as np
a = np.arange(4*7).reshape([4, 7])
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]])
I can apply slicing to swap the second and third columns by:
a[:, [0, 2, 1, 3, 4, 5, 6]]
array([[ 0, 2, 1, 3, 4, 5, 6],
[ 7, 9, 8, 10, 11, 12, 13],
[14, 16, 15, 17, 18, 19, 20],
[21, 23, 22, 24, 25, 26, 27]])
But, can I use slices to swap the second and third columns for all rows but the first one? The expected output would be:
array([[ 0, 1, 2, 3, 4, 5, 6],
[ 7, 9, 8, 10, 11, 12, 13],
[14, 16, 15, 17, 18, 19, 20],
[21, 23, 22, 24, 25, 26, 27]])
For in-situ edit, we can use flipping after slicing out the two columns -
a[1:,1:3] = a[1:,2:0:-1]
Sample run -
In [556]: a = np.arange(4*7).reshape([4, 7])
In [557]: a
Out[557]:
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]])
In [559]: a[1:,1:3] = a[1:,2:0:-1]
In [560]: a
Out[560]:
array([[ 0, 1, 2, 3, 4, 5, 6],
[ 7, 9, 8, 10, 11, 12, 13],
[14, 16, 15, 17, 18, 19, 20],
[21, 23, 22, 24, 25, 26, 27]])
For columns that are two-step apart, use a stepsize of 2 to assign (LHS) and -2 to select (RHS). Hence, for column IDs 1 & 3 -
In [577]: a = np.arange(4*7).reshape([4, 7])
In [578]: a
Out[578]:
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]])
In [579]: a[1:,1:4:2] = a[1:,3:0:-2]
In [580]: a
Out[580]:
array([[ 0, 1, 2, 3, 4, 5, 6],
[ 7, 10, 9, 8, 11, 12, 13],
[14, 17, 16, 15, 18, 19, 20],
[21, 24, 23, 22, 25, 26, 27]])
Another method would be with explicit column numbered indexing -
a[1:,[1,2]] = a[1:,[2,1]]
Note that this creates a copy with a[1:,[2,1]] and as such would be less memory efficient than the first method.

swap elements of list in recursive call python

I want to make simple function swap random element in list.
but it doesn't work in recursive call.
in first recursive call, element swapping work,
but nested recursive call(or nested recursive call in first recursive call) doesn't work.
I don't know why only swap in first recursive call works.
below are result.
Thank you all.
def change(lst):
if len(lst)>4:
a, b = np.random.randint(0, len(lst)), np.random.randint(0, len(lst))
print(lst)
lst[a], lst[b] = lst[b], lst[a]
print(lst)
mid = int(len(lst)/2)
change(lst[:mid])
change(lst[mid:])
k = list(range(0, 20))
change(k)
print(k)
`
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[0, 19, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1]
[0, 19, 2, 3, 4, 5, 6, 7, 8, 9]
[3, 19, 2, 0, 4, 5, 6, 7, 8, 9]
[3, 19, 2, 0, 4]
[3, 0, 2, 19, 4]
[5, 6, 7, 8, 9]
[5, 6, 8, 7, 9]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 1]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 1]
[10, 11, 12, 13, 14]
[10, 14, 12, 13, 11]
[15, 16, 17, 18, 1]
[15, 16, 17, 18, 1]
[0, 19, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1] <= result.
The problem is that in your recursive calls:
change(lst[:mid])
change(lst[mid:])
you use a slicing operator. The slicing operator constructs a new list, so your changes are made on a new list and are not reflected on the original list (since it is a copy).
What you can do is use indices instead:
def change(lst,frm=0,to=None):
if to is None: # set the default to the end of the list
to = len(lst)
if to-frm > 4:
a, b = np.random.randint(frm,to), np.random.randint(frm,to)
print(lst)
lst[a], lst[b] = lst[b], lst[a]
print(lst)
mid = (frm+to)//2
change(lst,frm,mid)
change(lst,mid,to)
Then we obtain:
>>> k = list(range(0, 20))
>>> change(k)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 2, 3, 4, 12, 6, 7, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 2, 3, 4, 12, 6, 7, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 2, 3, 4, 12, 6, 7, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 2, 3, 4, 12, 6, 7, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 12, 6, 7, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 12, 6, 7, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 10, 11, 5, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 5, 11, 10, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 5, 11, 10, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 5, 11, 10, 13, 14, 15, 16, 17, 18, 19]
>>> print(k)
[0, 1, 4, 3, 2, 7, 6, 12, 8, 9, 5, 11, 10, 13, 14, 15, 16, 17, 18, 19]
That's because you create copies of the original list by lst[:mid], lst[mid:]. A solution is to pass to change() the same list and (separately) the range to process.

Creating an overlap array with conditions - Python

Data = [day(1) day(2)...day(N)...day(2N)..day(K-N)...day(K)]
I am looking to create a numpy array with two arrays, N and K with shapes (120,) and (300,). The array needs to be of the form:
x1 = [day(1) day(2) day (3)...day(N)]
x2 = [day(2) day(3)...day(N) day(N+1)]
xN = [day(N) day(N+1) day(N+2)...day(2N)]
xK-N = [day(K-N) day(K-N+1)...day(K)]
X is basically of shape (K-N)xN, with the above x1,x2,...xK-N as rows. I have tried using iloc for getting two arrays N and K with the same shapes. Good till then. But, when I try to merge the arrays using X = np.array([np.concatenate((N[i:], K[:i] )) for i in range(len(N)]), I am getting an NxN array in the form of an overlap array only, and not in the desired format.
Is this what you are trying to produce (with simpler data)?
In [253]: N,K=10,15
In [254]: data = np.arange(K)+10
In [255]: data
Out[255]: array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])
In [256]: np.array([data[np.arange(N)+i] for i in range(K-N+1)])
Out[256]:
array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21],
[13, 14, 15, 16, 17, 18, 19, 20, 21, 22],
[14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
[15, 16, 17, 18, 19, 20, 21, 22, 23, 24]])
There's another way of generating this, using advanced ideas about strides:
np.lib.stride_tricks.as_strided(data, shape=(K-N+1,N), strides=(4,4))
In the first case, all values in the new array are copies of the original. The strided case is actually a view. So any changes to data appear in the 2d array. And without data copying, the 2nd is also faster. I can try to explain it if you are interested.
Warren suggests using hankel. That's a short function, which in our case does essentially:
a, b = np.ogrid[0:K-N+1, 0:N]
data[a+b]
a+b is an array like:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
[ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]])
In this example case it is just a bit better than the list comprehension solution, but I expect it will be a lot better for much larger cases.
It is probably not worth adding a dependence on scipy for the following, but if you are already using scipy in your code, you could use the function scipy.linalg.hankel:
In [75]: from scipy.linalg import hankel
In [76]: K = 16
In [77]: x = np.arange(K)
In [78]: x
Out[78]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
In [79]: N = 8
In [80]: hankel(x[:K-N+1], x[K-N:])
Out[80]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 1, 2, 3, 4, 5, 6, 7, 8],
[ 2, 3, 4, 5, 6, 7, 8, 9],
[ 3, 4, 5, 6, 7, 8, 9, 10],
[ 4, 5, 6, 7, 8, 9, 10, 11],
[ 5, 6, 7, 8, 9, 10, 11, 12],
[ 6, 7, 8, 9, 10, 11, 12, 13],
[ 7, 8, 9, 10, 11, 12, 13, 14],
[ 8, 9, 10, 11, 12, 13, 14, 15]])

Categories