Related
I have an array for an example:
import numpy as np
data=np.array([[4,4,4,0,1,1,1,0,0,0,0,1,0,0,1],
[3,0,0,1,1,1,1,1,1,1,1,0,0,1,0],
[6,0,0,1,1,1,1,1,0,0,0,0,1,0,0]])
Requirement :
In the data array, if element 1's are consecutive as the square size
of ((3,3)) and more than square size no changes. Otherwise, replace
element value 1 with zero except the square size.
Expected output :
[[4 4 4 0 1 1 1 0 0 0 0 0 0 0 0]
[3 0 0 0 1 1 1 0 0 0 0 0 0 0 0]
[6 0 0 0 1 1 1 0 0 0 0 0 0 0 0]]
I will provide here as solutions two different approaches. One which doesn't and one which is using Python loops. Let's start with the common header:
import numpy as np
from skimage.util import view_as_windows as winview
data=np.array([[4,4,4,0,1,1,1,0,0,0,0,1,0,0,1],
[3,0,0,1,1,1,1,1,1,1,1,0,0,1,0],
[6,0,0,1,1,1,1,1,0,0,0,0,1,0,0]])
Below an approach without using Python loops resulting in shortest code, but requiring import of an additional module skimage:
clmn = np.where(np.all(winview(data,(3,3))[0],axis=(1,2)))[0][0]
data[data == 1] = 0 # set all ONEs to zero
data[0:3,clmn+3:] = 0 # set after match to zero
data[0:3,clmn:clmn+3] = 1 # restore ONEs
Another one is using Python loops and only two lines longer:
for clmn in range(0,data.shape[1]):
if np.all(data[0:3,clmn:clmn+3]):
data[data==1] = 0
data[0:3,clmn+3:] = 0
data[0:3,clmn:clmn+3] = 1
break
Instead of explaining how the above code using loops works I have put the 'explanations' into the names of the used variables so the code becomes hopefully self-explaining. With this explanations and some redundant code you can use the code below for another shaped haystack to search for in another array of same kind. For an array with more rows as the shape of the sub-array there will be necessary to loop also over the rows and optimize the code skipping some unnecessary checks.
import numpy as np
data=np.array([[4,4,4,0,1,1,1,0,0,0,0,1,0,0,1],
[3,0,0,1,1,1,1,1,1,1,1,0,0,1,0],
[6,0,0,1,1,1,1,1,0,0,0,0,1,0,0]])
indx_of_clmns_in_shape = 1
indx_of_rows_in_shape = 0
subarr_shape = (3, 3)
first_row = 0
first_clmn = 0
for clmn in range(first_clmn,data.shape[indx_of_clmns_in_shape],1):
sub_data = data[
first_row:first_row+subarr_shape[indx_of_rows_in_shape],
clmn:clmn+subarr_shape[indx_of_clmns_in_shape]]
if np.all(sub_data):
data[data == 1] = 0
data[first_row : subarr_shape[indx_of_rows_in_shape],
clmn+subarr_shape[indx_of_clmns_in_shape] : ] = 0
data[first_row : subarr_shape[indx_of_rows_in_shape],
clmn : clmn+subarr_shape[indx_of_clmns_in_shape]] = 1
break
# print(sub_data)
print(data)
all three versions of the code give the same result:
[[4 4 4 0 1 1 1 0 0 0 0 0 0 0 0]
[3 0 0 0 1 1 1 0 0 0 0 0 0 0 0]
[6 0 0 0 1 1 1 0 0 0 0 0 0 0 0]]
Should be easy to do with a double for loop and a second array
rows = len(source_array)
columns = len(source_array[0])
# Create a result array of same size
result_array = [[0 for _ in range(rows)] for _ in range(columns)]
for i in range(rows):
for j in range(columns):
# Copy non 1s
if source_array[i][j] != 1:
result_array[i][j] = source_array[i][j]
# if enough rows left to check then check
if i < rows - 3:
if j < columns - 3:
# Create set on the selected partition
elements = set(source_array[i][j:j+3] + source_array[i+1][j:j+3] + source_array[i+2][j:j+3])
# Copy 1s to new array
if len(elements) == 1 and 1 in elements:
for sq_i in range(i,i+3):
for sq_j in range(j,j+3):
result_array[sq_i][sq_j] = 1
I want to create a 64 components array showing all the squares in which the two rooks of an empty chessboard could move from their current position. So far I am doing it with for and while loops.
I first create a function just to better visualize the board:
import numpy as np
def from_array_to_matrix(v):
m=np.zeros((8,8)).astype('int')
for row in range(8):
for column in range(8):
m[row,column]=v[row*8+column]
return m
and here I show how I actually build the array:
# positions of the two rooks
a=np.zeros(64).astype('int')
a[15] = 1
a[25] = 1
print from_array_to_matrix(a)
# attack_a will be all the squares where they could move in the empty board
attack_a=np.zeros(64).astype('int')
for piece in np.where(a)[0]:
j=0
square=piece+j*8
while square<64:
attack_a[square]=1
j+=1
square=piece+j*8
j=0
square=piece-j*8
while square>=0:
attack_a[square]=1
j+=1
square=piece-j*8
j=0
square=piece+j
while square<8*(1+piece//8):
attack_a[square]=1
j+=1
square=piece+j
j=0
square=piece-j
while square>=8*(piece//8):
attack_a[square]=1
j+=1
square=piece-j
print attack_a
print from_array_to_matrix(attack_a)
I have been advised to avoid for and while loops whenever it is possible to use other ways, because they tend to be time consuming. Is there any way to achieve the same result without iterating the process with for and while loops ?
Perhaps using the fact that the indices to which I want to assign the value 1 can be determined by a function.
There are a couple of different ways to do this. The simplest thing is of course to work with matrices.
But you can vectorize operations on the raveled array as well. For example, say you had a rook at position 0 <= n < 64 in the linear array. To set the row to one, use integer division:
array[8 * (n // 8):8 * (n // 8 + 1)] = True
To set the column, use modulo:
array[n % 8::8] = True
You can convert to a matrix using reshape:
matrix = array.reshape(8, 8)
And back using ravel:
array = martix.ravel()
Or reshape:
array = matrix.reshape(-1)
Setting ones in a matrix is even simpler, given a specific row 0 <= m < 8 and column 0 <= n < 8:
matrix[m, :] = matrix[:, n] = True
Now the only question is how to vectorize multiple indices simultaneously. As it happens, you can use a fancy index in one axis. I.e, the expression above can be used with an m and n containing multiple elements:
m, n = np.nonzero(matrix)
matrix[m, :] = matrix[:, n] = True
You could even play games and do this with the array, also using fancy indexing:
n = np.nonzero(array)[0]
r = np.linspace(8 * (n // 8), 8 * (n // 8 + 1), 8, False).T.ravel()
c = np.linspace(n % 8, n % 8 + 64, 8, False)
array[r] = array[c] = True
Using linspace allows you to generate multiple sequences of the same size simultaneously. Each sequence is a column, so we transpose before raveling, although this is not required.
Use reshaping to convert 1-D array to 8x8 2-D matrix and then numpy advance indexing to select rows and columns to set to 1:
import numpy as np
def from_array_to_matrix(v):
return v.reshape(8,8)
# positions of the two rooks
a=np.zeros(64).astype('int')
a[15] = 1
a[25] = 1
a = from_array_to_matrix(a)
# attack_a will be all the squares where they could move in the empty board
attack_a=np.zeros(64).astype('int')
attack_a = from_array_to_matrix(attack_a)
#these two lines replace your for and while loops
attack_a[np.where(a)[0],:] = 1
attack_a[:,np.where(a)[1]] = 1
output:
a:
[[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 1 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]]
attack_a:
[[0 1 0 0 0 0 0 1]
[1 1 1 1 1 1 1 1]
[0 1 0 0 0 0 0 1]
[1 1 1 1 1 1 1 1]
[0 1 0 0 0 0 0 1]
[0 1 0 0 0 0 0 1]
[0 1 0 0 0 0 0 1]
[0 1 0 0 0 0 0 1]]
I wanted to construct a 6 x 9 matrix with entries zeros and ones in a specific way as follows. In the zeroth row column, 0 to 2 should be 1 and in the first-row column,3 to 5 should be one and in the second-row column, 6 to 8 should be one, with all the other entries to be zeros. In the third row, element 0,3,6 should be one and the other should be zeros. In the fourth row, element 1,4,7 should be one and the other elements should be zeros. In the fifth row,2,5,8 should be one and the remaining should be zeros. Half of the rows follow one way enter the value 1 and the other half of the row follows different procedures to enter the value one. How do extend this some 20 x 100 case where the first 10 rows follow one procedure as mentioned above and the second half follows different procedures
The 6x9 by matrix looks as follows
[[1,1,1,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,1,1,1],
[1,0,0,1,0,0,1,0,0],
[0,1,0,0,1,0,0,1,0],
[0,0,1,0,0,1,0,0,1]]
EDIT: Code I used to create this matrix:
import numpy as np
m=int(input("Enter the value of m, no. of points = "))
pimatrix=np.zeros((2*m +1)*(m**2)).reshape((2*m+1),(m**2))
for i in range(2*m + 1):
for j in range(m**2):
if((i<m) and ((j<((i+1)*m) and j>=(i*m)))):
pimatrix[i][j]=1
if (i>(m-1)):
for k in range(-1,m-1,1):
if(j == i+(k*m)):
pimatrix[i][j]=1
if i==2*m:
pimatrix[i][j]=1
print(pimatrix)
Try to use numpy.put function numpy.put
The best approach depends on the rules you plan to follow, but an easy approach would be to initialise the array as an array of zeroes:
import numpy as np
a = np.zeros([3, 4], dtype = int)
You can then write the logic to loop over the appropriate rows and set 1's as needed. You can simply access any element of the array by its coordinates:
a[2,1] = 1
print(a)
Result:
[[0 0 0 0]
[0 0 0 0]
[0 1 0 0]]
Without a general rule, it's hard to say what your intended logic is exactly, but assuming these rules: the top half of the array has runs of three ones on each consecutive row, starting in the upper left and moving down a row at the end of every run, until it reaches the bottom of the top half, where it wraps around to the top; the bottom half has runs of single ones, following the same pattern.
Implementing that, with your given example:
import numpy as np
a = np.zeros([6, 9], dtype=int)
def set_ones(a, run_length, start, end):
for n in range(a.shape[1]):
a[start + ((n // run_length) % (end - start)), n] = 1
set_ones(a, 3, 0, a.shape[0] // 2)
set_ones(a, 1, a.shape[0] // 2, a.shape[0])
print(a)
Result:
[[1 1 1 0 0 0 0 0 0]
[0 0 0 1 1 1 0 0 0]
[0 0 0 0 0 0 1 1 1]
[1 0 0 1 0 0 1 0 0]
[0 1 0 0 1 0 0 1 0]
[0 0 1 0 0 1 0 0 1]]
This question already has answers here:
Index a 2D Numpy array with 2 lists of indices
(5 answers)
Closed 4 years ago.
for example,I have a matrix like this
mat = np.diag((1,1,1,1,1,1))
print(mat)
out:[[1 0 0 0 0 0]
[0 1 0 0 0 0]
[0 0 1 0 0 0]
[0 0 0 1 0 0]
[0 0 0 0 1 0]
[0 0 0 0 0 1]]
I may need some slices that can be combination of any lines and columns.
if it is lines=[0,1,2] columns=[0,1,2],I could use:
mat[0:3,0:3]
If I need lines=[0,1,2,5] columns=[0,1,2,5],I write:
mat[[0,1,2,5],[0,1,2,5]]
I can only get:
out:[1 1 1 1]
But I wanna get a matrix of 4×4.By the way,the columns always equal lines.
For non-contiguous indices you can do:
mat[[0,1,2,5],:][:,[0,1,2,5]]
i.e. first get the specified rows (gets a 4x6 matrix out of it) then get the specified columns from that.
I need to get a new matrix generated by selecting a subset of columns from another matrix, given a list (or tuple) of column indices.
The following is the code I am working on (there is a bit more than just the attempt to create a new matrix, but might be interesting for you to have some context).
A = matrix(QQ,[
[2,1,4,-1,2],
[1,-1,5,1,1],
[-1,2,-7,0,1],
[2,-1,8,-1,2]
])
print "A\n",A
print "A rref\n",A.rref()
p = A.pivots()
print "A pivots",p
with the following output:
A
[ 2 1 4 -1 2]
[ 1 -1 5 1 1]
[-1 2 -7 0 1]
[ 2 -1 8 -1 2]
A rref
[ 1 0 3 0 0]
[ 0 1 -2 0 0]
[ 0 0 0 1 0]
[ 0 0 0 0 1]
A pivots (0, 1, 3, 4)
Now I expected to find easily a method from matrix objects which allowed to construct a new matrix with a subset of columns by just giving the tuple p as parameter, but could not find anything like that.
Any ideas on how to solve this elegantly in a sage-friendly way? (avoiding for loops and excess code)
thanks!
You can use the matrix_from_columns method: A.matrix_from_columns(p).
Just found how to do this in the easiest and most concise way:
A[:,p]