Multiple Numpy random shuffles does not add up - python

I'm trying to generate an array of neighbors, each neighbor differing from the previous neighbor in one random shuffle, either a row or column shuffle. The neighbors should only be generated if a certain row or column has more than K 1's, and if so, a neighbor should be generated with this row or column shuffled. The shuffles should be additive, meaning that if first a row is shuffled and then a column; two neighbors should be generated, one with a shuffled row and one with both a row and a column shuffled.
However, it seems that the array is only shuffled two times, one for the column loop and one for the row loop, and the shuffles don't add up.
In this example, column index 1 and 2 should be shuffled, and row index 3 and 4. Here is an example output, showing the generated neighbors:.
[[0 0 0 1 1]
[0 0 1 0 0]
[1 1 0 0 0]
[0 1 1 1 0]
[1 1 1 0 1]]
[[0 0 0 1 1]
[0 0 1 0 0]
[0 0 1 0 1]
[0 1 1 1 0]
[1 1 1 0 1]]
[[0 0 0 1 1]
[0 0 1 0 0]
[0 0 1 0 1]
[0 1 1 1 0]
[1 1 1 0 1]]
[[0 0 0 1 1]
[0 0 1 0 0]
[0 0 1 0 1]
[0 1 1 1 0]
Here is the code:
k=2
tmp = np.array([
[0, 0, 0, 1, 1]
,[0, 0, 1, 0, 0]
,[1, 1, 0, 0, 0]
,[0, 1, 1, 1, 0]
,[1, 1, 1, 0, 1]
])
board = np.copy(tmp)
column = np.sum(board, axis=0)-k
columns = len(column)
row = np.sum(board, axis=1)-k
rows = len(row)
neighbors = []
for i in range(columns):
if column[i] > 0:
np.random.shuffle(board[:,i])
neighbors.append(np.copy(board))
for i in range(rows):
if row[i] > 0:
np.random.shuffle(board[i,:])
neighbors.append(np.copy(board))
print tmp
print column
print row
for i in neighbors:
print i
Thanks

Your code works :)
It's just that sometimes a row or column is shuffled but stays in the same configuration. Compare with:
ar = np.array([0, 1])
for _ in range(10):
print ar
np.random.shuffle(ar)
In addition, it's not unlikely that the elements of a row or column are indeed shuffled, but you'll end up with ones and zeros in the exact same place anyway (because there's only a limited number of unique permutations).

Related

finding neighbors in np.array at predefined start points

in an array i have 2 randomly defind start points for 2 agents that will fill the grid with "1" & "2" (that will get data from a pandas df)
#starting points:
start_point = []
cellMAP_0 = np.full((11,7), 0)
for i in range(2):
start_points = random.randint(0,cellMAP_0.size)
start_point.append(start_points)
further i assign each number to one agent:
for i in range(len(df[0:77])):
if df.loc[i]['side'] == 'MOVE' and df.loc[i]['symbol'] == 'FIGHTER_1':
cellMAP_0[np.unravel_index(random.choices(list(start_point)), cellMAP_0.shape)] = 1
elif df.loc[i]['side'] == 'MOVE' and df.loc[i]['symbol'] == 'FIGHTER_2':
cellMAP_0[np.unravel_index(random.choices(list(start_point)), cellMAP_0.shape)] = 2
this is my outcome:
[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 2 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 1]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]]
so far so good. now i want to find horizontal & vertical neighbors for "1" and "2"
therefore i found this code, but somehow i don't get it to work with both instances (1&2) at once in the same array:
edit: sorry was a bit on the run here the code that i edited:
def find_horizontal_and_vertical_neighbours(cellMAP_0, start_point):
"""
This method takes 2d array and return list of all elements
with all horizontal and vertical neighbours
:param arr: 2d array
:return: list of array elements with neighbours
"""
neighbors = []
for start_point in range(len(cellMAP_0)):
for j, value in enumerate(cellMAP_0[start_point]):
if start_point == 0 or start_point == len(cellMAP_0) - 1 or j == 0 or j == len(cellMAP_0[start_point]) - 1:
# corners
new_neighbors = []
if start_point != 0:
new_neighbors.append(cellMAP_0[start_point - 1][j]) # top neighbor
if j != len(cellMAP_0[start_point]) - 1:
new_neighbors.append(cellMAP_0[start_point][j + 1]) # right neighbor
if start_point != len(cellMAP_0) - 1:
new_neighbors.append(cellMAP_0[start_point + 1][j]) # bottom neighbor
if j != 0:
new_neighbors.append(cellMAP_0[start_point][j - 1]) # left neighbor
else:
# add neighbors
new_neighbors = [
cellMAP_0[start_point - 1][j], # top neighbor
cellMAP_0[start_point][j + 1], # right neighbor
cellMAP_0[start_point + 1][j], # bottom neighbor
cellMAP_0[start_point][j - 1] # left neighbor
]
neighbors.append({
"index": start_point * len(cellMAP_0[start_point]) + j,
"value": value,
"neighbors": new_neighbors})
return neighbors
find_horizontal_and_vertical_neighbours(cellMAP_0,start_point)
this gives me inedex values and neighbors
[{'index': 0, 'value': 0, 'neighbors': [0, 0]},
{'index': 1, 'value': 0, 'neighbors': [0, 0, 0]},
{'index': 2, 'value': 0, 'neighbors': [0, 0, 0]},
{'index': 3, 'value': 0, 'neighbors': [0, 0, 0]},
{'index': 4, 'value': 0, 'neighbors': [0, 0, 0]},
but what i actually seek is a list of the cells next to the starting points (here the fat numbers in the array):
[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 **2** 0 0 0]
[0 0 **2** 2 **2** 0 0]
[0 0 0 **2** 0 0 0]
[0 0 0 0 0 0 **1**]
[0 0 0 0 0 **1** 1]
[0 0 0 0 0 0 **1**]
afterwards i want that the fighter can fill one field of the neighbours in each round, as well as that each new acquired field can act as a new starting field. the first seems kind of obvious for me to pick random positions from the list of neighbours i would get from the outcome above.
hope this is now a bit more clear :) thank you very much!
Since you want only the cells next to the starting points, you can use np.where() to find the indices of the starting points and then apply a function that finds all cells next to them:
oneIndex = np.where(cellMAP_0 == 1) #in your example it will return [8][6]
twoIndex = np.where(cellMAP_0 == 2) #in your example it will return [5][4]
def allInRange(num1,num2):
inRange = []
if num1< cellMAP_0.shape[0]-1:
inRange.append((num1+1,num2))
if num1>0:
inRange.append((num1-1,num2))
if num2< cellMAP_0.shape[1]-1:
inRange.append((num1,num2+1))
if num2>0:
inRange.append((num1,num2-1))
return inRange
firstNeighbours = allInRange(oneIndex[0],oneIndex[1])
secondNeighbours = allInRange(twoIndex[0],twoIndex[1])

How to resize a Numpy array to add/replace rows with combinations determined by the values in each row of the array

So I have a program that at some point creates random arrays and I have perform an operation which is to add rows while replacing other rows based on the values found in the rows. One of the random arrays will look something like this but keep in mind that it could randomly vary in size ranging from 3x3 up to 10x10:
0 2 0 1
1 0 0 1
1 0 2 1
2 0 1 2
For every row that has at least one value equal to 2 I need to remove/replace the row and add some more rows. The number of rows added will depend on the number of combinations possible of 0s and 1s where the number of digits is equal to the number of 2s counted in each row. Each added row will introduce one of these combinations in the positions where the 2s are located. The result that I'm looking for will look like this:
0 1 0 1 # First combination to replace 0 2 0 1
0 0 0 1 # Second combination to replace 0 2 0 1 (Only 2 combinations, only one 2)
1 0 0 1 # Stays the same
1 0 1 1 # First combination to replace 1 0 2 1
1 0 0 1 # Second combination to replace 1 0 2 1 (Only 2 combinations, only one 2)
0 0 1 0 # First combination to replace 2 0 1 2
0 0 1 1 # Second combination to replace 2 0 1 2
1 0 1 1 # Third combination to replace 2 0 1 2
1 0 1 0 # Fourth combination to replace 2 0 1 2 (4 combinations, there are two 2s)
If you know a Numpy way of accomplishing this I will be grateful.
You can try the following. Create a sample array:
import numpy as np
np.random.seed(5)
a = np.random.randint(0, 3, (4, 4))
print(a)
This gives:
[[2 1 2 2]
[0 1 0 0]
[2 0 2 0]
[0 1 1 0]]
Compute the output array:
ts = (a == 2).sum(axis=1)
r = np.hstack([np.array(np.meshgrid(*[[0, 1]] * t)).reshape(t, -1).T.ravel() for t in ts if t])
out = np.repeat(a, 2**ts, axis=0)
out[out == 2] = r
print(out)
Result:
[[0 1 0 0]
[0 1 0 1]
[1 1 0 0]
[1 1 0 1]
[0 1 1 0]
[0 1 1 1]
[1 1 1 0]
[1 1 1 1]
[0 1 0 0]
[0 0 0 0]
[1 0 0 0]
[0 0 1 0]
[1 0 1 0]
[0 1 1 0]]
Not the prettiest code but it does the job. You could clean up the itertools calls but this lets you see how it works.
import numpy as np
import itertools
X = np.array([[0, 2, 0, 1],
[1, 0, 0, 1],
[1, 0, 2, 1],
[2, 0, 1, 2]])
def add(X_,Y):
if Y.size == 0:
Y = X_
else:
Y = np.vstack((Y, X_))
return(Y)
Y = np.array([])
for i in range(len(X)):
if 2 not in X[i,:]:
Y = add(X[i,:], Y)
else:
a = np.where(X[i,:]==2)[0]
n = [[i for i in itertools.chain([1, 0])] for _ in range(len(a))]
m = list(itertools.product(*n))
for j in range(len(m)):
M = 1 * X[i,:]
u = list(m[j])
for k in range(len(a)):
M[a[k]] = u[k]
Y = add(M, Y)
print(Y)
#[[0 1 0 1]
# [0 0 0 1]
# [1 0 0 1]
# [1 0 1 1]
# [1 0 0 1]
# [1 0 1 1]
# [1 0 1 0]
# [0 0 1 1]
# [0 0 1 0]]

Sum n values of n-lists with the same index in Python

For example, I have 5 lists with 10 elements each one generated with random values simulating a coin toss.
I get my 5 lists with 10 elements in the following way:
result = [0,1] #0 is tail #1 is head
probability = [1/2,1/2]
N = 10
list = []
def list_generator(number): #this number would be 5 in this case
for i in range(number):
n_round = np.array(rnd.choices(result, probability, k=N))
print(n_round)
list_generator(5)
And for example I would get this
[1 1 0 0 0 1 0 1 1 0]
[0 1 0 0 0 1 1 1 0 1]
[1 1 0 0 1 1 1 0 1 1]
[0 0 0 1 0 0 0 1 0 0]
[0 0 1 1 0 0 0 0 1 1]
How can I sum only the numbers of the same column, I mean, I would like to get a list that appends the value of 1+0+1+0+0 (the first column), then, that list appends the sum of each second coin toss of each round i.e. 1+1+1+0+0 (the second column), and so on with the ten coin tosses
(I need it in a list because I will use this to plot a graph)
I have thought about making a matrix with each array and summing only the nth column and append that value in the list but I do not know how to do that, I do not have much knowledge about using arrays.
Have your function return a 2d numpy array and then sum along the required axis. Separately, you don't need to pass probability to random.choices as equal probabilities are the default.
import random
import numpy as np
def list_generator(number):
return np.array([np.array(random.choices([0,1], k=10)) for i in range(number)])
a = list_generator(5)
>>> a
array([[0, 1, 1, 1, 0, 1, 1, 0, 0, 0],
[1, 0, 1, 0, 1, 1, 1, 1, 1, 0],
[1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
[1, 1, 0, 0, 1, 1, 1, 1, 0, 0],
[0, 1, 1, 0, 0, 1, 1, 1, 0, 0]])
>>> a.sum(axis=0)
array([3, 4, 3, 2, 3, 5, 4, 3, 2, 1])
You can use numpy.random.randint to generate your randomized data. Then use sum to get the sum of the columns:
import numpy as np
N = 10
data = np.random.randint(2, size=(N, N))
print(data)
print(data.sum(axis=0))
[[1 0 1 1 1 1 0 0 1 1]
[0 0 1 1 0 0 1 1 1 0]
[1 1 0 1 1 1 0 0 1 1]
[1 1 0 0 0 0 1 1 1 1]
[1 0 0 1 1 1 0 1 1 1]
[1 0 1 1 0 1 0 1 1 1]
[0 0 0 1 0 1 0 1 1 0]
[0 0 0 1 0 1 0 1 0 1]
[1 0 0 0 1 0 1 0 1 1]
[1 0 1 1 0 1 0 0 0 1]]
[7 2 4 8 4 7 3 6 8 8]

How to replace values in a np 2d array based on condition for every row

I have a numpy 2d array (named lda_fit) with probabilities, where I want to replace the probabilities with 0 or 1, based on the max value in each line.
array([[0.06478282, 0.80609092, 0.06511851, 0.06400775],
[0.50386571, 0.02621445, 0.44400621, 0.02591363],
[0.259538 , 0.04266385, 0.65470484, 0.04309331],
...,
[0.01415491, 0.01527508, 0.22211579, 0.74845422],
[0.01419367, 0.01537099, 0.01521318, 0.95522216],
[0.25 , 0.25 , 0.25 , 0.25 ]])
So after all the first line should look like [0,1,0,0], the second like [1,0,0,0] and so on. I have tried, and this works, but only for a given threshold (0.5):
np.where(lda_fit < 0.5,0,1)
But as I might not have the largest value being greater than 0.5, I want to specify a new threshold for each line. Unfortunately this gives me the max value of the whole array.
np.where(lda_fit < np.max(lda_fit),0,1)
You can use np.max with specifying axis:
(lda_fit.max(1,keepdims=True)==lda_fit)+0
Note: if there is more than one max in a row, it will return 1 for all of them. For alternative solution follow the next method.
output for example input in question:
[[0 1 0 0]
[1 0 0 0]
[0 0 1 0]
[0 0 0 1]
[0 0 0 1]
[1 1 1 1]]
In case of multiple max in a row, if you want to have only first one as 1 and the rest of max as 0, you can use argmax:
(lda_fit.argmax(axis=1)[:,None] == range(lda_fit.shape[1]))+0
or equally:
lda_fit_max = np.zeros(lda_fit.shape, dtype=int)
lda_fit_max[np.arange(len(lda_fit)),lda_fit.argmax(axis=1)]=1
output:
[[0 1 0 0]
[1 0 0 0]
[0 0 1 0]
[0 0 0 1]
[0 0 0 1]
[1 0 0 0]]

using 1's in the arrays to make a shape like '+' using numpy in python

Numpy Three Four Five Dimensional Array in Python
Input 1: 3
Output 1:
[[0 1 0]
[1 1 1]
[0 1 0]]
Input 2:5
Output 1:
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
Notice that the 1s in the arrays make a shape like +.
My logic is shown below
a=np.zeros((n,n),dtype='int')
a[-3,:] = 1
a[:,-3] = 1 print(a)
This logic is only working for five dimensional array but not for three dimensional array.
can someone assist me to get the expected output for both three and five dimensional array using np.zeros & integer division //
As you can see, n//2 = 3 when n=5. So, that's the solution to your question as see here:
import numpy as np
def create_plus_matrix(n):
a = np.zeros((n,n),dtype='int')
a[-n//2,:] = 1
a[:,-n//2] = 1
return a
So, let's try it out:
>>> create_plus_matrix(3)
[[0 1 0]
[1 1 1]
[0 1 0]]
>> create_plus_matrix(5)
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
Do this
import numpy as np
def plus(size):
a = np.zeros([size,size], dtype = int)
a[int(size/2)] = np.ones(size)
for i in a:
i[int(size/2)] = 1
return a
print(plus(3)) //3 is the size
//Output
[[0 1 0]
[1 1 1]
[0 1 0]]

Categories