how do you specifically add elements to a 2 dimentional array? - python

With a 2 dimentional array, I only want specific elements to be a different number.
If the array was not fixed and changed dimentions, how could you loop over it with a for loop to impliment the pattern?
0 0 0 0 1
0 0 0 0 1
0 0 1 0 1
0 0 1 0 1
1 0 1 0 1
0 0 0 0 0 0 1
0 0 0 0 0 0 1
0 0 0 0 1 0 1
0 0 0 0 1 0 1
0 0 1 0 1 0 1
0 0 1 0 1 0 1
1 0 1 0 1 0 1
This is what i want to create but i cant find a way to only select those ones in a for loop.
Any help would be appreciated. Thanks in advance!
rows, cols = (5,5)
arr = [[0 for i in range(cols)] for j in range(rows)]
for row in arr:
if row == 0 or row == 1:
print("h")
arr[rows-1, row] = 1
if row == 2 or row == 3:
arr[rows-1, row] = 1
if row == 4 or row == 5:
arr[rows-1, row] = 1
if row == 6 or row == 7:
arr[rows-1, row] = 1
print(arr)
This is what I have so far.

A possible solution:
from pprint import pprint
n = 5
mat = [[0 for _ in range(n)] for _ in range(n)]
for i in range(n):
for j in range(n):
if i + j >= n - 1 and j % 2 == 0:
mat[i][j] = 1
pprint(mat)
Some minor notes (this is better off in the code review forum, in truth):
If the matrix is always square - you need only define a single value (n here) and not two rows and cols. Presuming that n is also odd, your ones pattern is well defined.
arr is not a very good name, seeing the name 'array' usually refers to a one-dimensional array. A 'matrix' would suit better in my views [mat for short, of course].
pprint is a module, which allows prints out to the screen in a 'prettier' way, with respect to some python data structure, such as a list of lists. It sometimes comes in handy. Check out the differences when compared to print.
The key here is to recognize the pattern of ones, and implement it clearly in code. There are many patterns that may fit - but here I went with 'look only at even columns' and 'look only at the bottom right triangle of the matrix'.
Changing n to 11 for example, yields:
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
[0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
[0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]]

Related

Generate a specific number of ones for each row, but only where x = zeroes

Suppose I have an array like
a = np.array([[0, 1, 1, 1, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 1, 0, 0, 1, 0]])
I want each row to have a specific number of ones- let's say, 5 ones per row.
So in the first row I need to add 1 one, second row needs 3 ones, and the third needs 2. I need to randomly generate those ones in places where x = 0.
How do I do this?
This was a bit tricky but here is a fully vectorized solution:
import numpy as np
def add_ones_up_to(data, n):
# Count number of ones to add to each row
c = np.maximum(n - np.count_nonzero(data, axis=-1), 0)
# Make row-shuffling indices
shuffle = np.argsort(np.random.random(data.shape), axis=-1)
# Row-shuffled data
data_shuffled = np.take_along_axis(data, shuffle, axis=-1)
# Sorting indices for shuffled data (indices of zeros will be first)
sorter = np.argsort(np.abs(data_shuffled), axis=-1)
# Sorted row-shuffled data
data_sort = np.take_along_axis(data_shuffled, sorter, axis=-1)
# Mask for number of ones to add
m = c[..., np.newaxis] > np.arange(data.shape[-1])
# Replace values with ones or previous value depending on mask
data_sort = np.where(m, 1, data_sort)
# Undo sorting and shuffling
reorderer = np.empty_like(sorter)
np.put_along_axis(reorderer, sorter, np.arange(reorderer.shape[-1]), axis=-1)
np.put_along_axis(reorderer, shuffle, reorderer.copy(), axis=-1)
return np.take_along_axis(data_sort, reorderer, axis=-1)
np.random.seed(100)
data = np.array([[0, 1, 1, 1, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 1, 0, 0, 1, 0]])
n = 5
print(add_ones_up_to(data, n))
# [[0 1 1 1 1 0 0 0 1 0]
# [0 1 1 1 0 1 0 1 0 0]
# [1 0 0 0 0 1 1 0 1 1]]
import numpy as np
a = np.array([[0, 1, 1, 1, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 1, 0, 0, 1, 0]])
ones = 5
to_add = ones - np.count_nonzero(a, axis=1)
for i in range(a.shape[0]):
idx = np.random.choice(np.flatnonzero(a[i, :] == 0), size=to_add[i], replace=False)
a[i, idx] = 1
For each row you count the numbers of non zeros to calculate how many ones to add.
You than chose that many indices out of the set of indices where a is zero and set those to 1.

How to generate random 1s and 0s in a matrix array?

I have a matrix and it's currently populated with just 1's. How do I make it so it populates with random 1's and 0's?
matrix5x5 = [[1 for row in range (5)] for col in range (5)]
for row in matrix5x5:
for item in row:
print(item,end=" ")
print()
print("")
Output:
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
I want something like:
1 0 0 1 0
0 1 1 1 1
1 0 1 0 1
1 1 0 0 1
0 1 1 1 1
I found something regarding using random.randint(0,1) but I don't know how to change my current code to include the above.
Modifying your code, using the random package (and not the numpy equivalent):
matrix5x5 = [[random.randint(0,1) for _ in range(5)] for _ in range(5)]
for row in matrix5x5:
for item in row:
print(item,end=" ")
print()
print("")
0 1 0 0 1
0 1 0 1 0
0 0 1 1 0
0 0 0 1 0
1 0 0 1 1
But honestly, numpy makes it a lot faster and easier!
If you don't mind using numpy:
>>> import numpy as np
>>> np.random.randint(2, size=(5, 5))
array([[1, 0, 1, 0, 1],
[1, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[1, 0, 0, 0, 1],
[0, 1, 0, 0, 1]])
Numpy arrays support most list operations that involve indexing and iteration, and if you really care, you can turn it back into a list:
>>> np.random.randint(2, size=(5, 5)).tolist()
[[1, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 1, 0, 0], [1, 0, 1, 1, 1], [1, 0, 1, 0, 0]]
And, if for some strange reason, you are 100% adamant on using vanilla Python, just use the random module and a list comprehension:
>>> import random
>>> [[random.randint(0,1) for j in range (5)] for i in range (5)]
[[0, 1, 0, 1, 1], [0, 1, 1, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]]
You probably want to use numpy. Do the following:
import numpy as np
my_matrix = np.random.randint(2,size=(5,5))
This will create a random 5 by 5 matrix with 0s and 1s.

In opencv how do I get a list of segemented regions

I'm working on a project where I want to evaluate certain parameters on regions of a segemented image. So I have the following code
col = cv2.imread("in.jpg",1)
col=cv2.resize(col,(width,height),interpolation=cv2.INTER_CUBIC)
res=cv2.pyrMeanShiftFiltering(col,20,45,3)
and would now like to somehow get a list of masks per region in res.
So for example if res was now something like this
1 1 0 2 1
1 0 0 2 1
0 0 2 2 1
I would like to get an output such as
1 1 0 0 0
1 0 0 0 0
0 0 0 0 0
,
0 0 1 0 0
0 1 1 0 0
1 1 0 0 0
,
0 0 0 1 0
0 0 0 1 0
0 0 1 1 0
,
0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
So that is a mask for each group of the same values that are connected. Maybe this could somehow involve the floodfill function? I can
see that maybe by looping over every pixel and then flood filling and comparing to see if that set of pixels was already set might work but that seems like a very expensive way so is there something faster?
Oh and here is an example image of res after the code has run
Here's one approach with cv2.connectedComponents -
def list_seg_regs(a): # a is array
out = []
for i in np.unique(a):
ret, l = cv2.connectedComponents((a==i).astype(np.uint8))
for j in range(1,ret):
out.append((l==j).astype(int)) #skip .astype(int) for bool
return out
Sample run -
In [53]: a = np.array([
...: [1, 1, 0, 2, 1],
...: [1, 0, 0, 2, 1],
...: [0, 0, 2, 2, 1]])
In [54]: out = list_seg_regs(a)
In [55]: out[0]
Out[55]:
array([[0, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[1, 1, 0, 0, 0]])
In [56]: out[1]
Out[56]:
array([[1, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
In [57]: out[2]
Out[57]:
array([[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1]])
In [58]: out[3]
Out[58]:
array([[0, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 1, 0]])

Flip bits in array using python

You are given an integer array with N elements: d[0], d[1], ... d[N - 1].
You can perform AT MOST one move on the array: choose any two integers [L, R], and flip all the elements between (and including) the L-th and R-th bits. L and R represent the left-most and right-most index of the bits marking the boundaries of the segment which you have decided to flip.
What is the maximum number of 1-bits (indicated by S) which you can obtain in the final bit-string?
'Flipping' a bit means, that a 0 is transformed to a 1 and a 1 is transformed to a 0 (0->1,1->0).
Input Format: An integer N, next line contains the N bits, separated by spaces: d[0] d[1] ... d[N - 1]
Output: S
Constraints:
1 <= N <= 100000,
d[i] can only be 0 or 1 ,
0 <= L <= R < n ,
Sample Input:
8
1 0 0 1 0 0 1 0
Sample Output: 6
Explanation:
We can get a maximum of 6 ones in the given binary array by performing either of the following operations:
Flip [1, 5] ==> 1 1 1 0 1 1 1 0
Cleaned up and made Pythonic
arr1 = [1, 0, 0, 1, 0, 0, 1, 0]
arr2 = [1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
arr3 = [0,0,0,1,1,0,1,0,1,1,0,0,1,1,1]
def maximum_ones(arr):
"""
Returns max possible number of ones after flipping a span of bit array
"""
total_one = 0
net = 0
maximum = 0
for bit in arr:
if bit:
total_one += 1
net -= 1
else:
net += 1
maximum = max(maximum, net)
if net < 0:
net = 0
return total_one + maximum
print(maximum_ones(arr1))
print(maximum_ones(arr2))
print(maximum_ones(arr3))
Output:
6
14
11
If we want the L and R indices
Not so sure about this one. It can probably be made cleaner.
arr1 = [1, 0, 0, 1, 0, 0, 1, 0]
arr2_0 = [1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
arr2_1 = [1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
arr2_2 = [1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
arr3 = [0,0,0,1,1,0,1,0,1,1,0,0,1,1,1]
def maximum_ones(arr):
"""
Returns max possible number of ones after flipping a span of bit array
and the (L,R) indices (inclusive) of such a flip
"""
total_one = 0
net = 0
maximum = 0
L = R = 0
started_flipping = False
for i, bit in enumerate(arr):
if bit:
total_one += 1
net -= 1
else:
net += 1
if not started_flipping:
started_flipping = True
L = i
if net > maximum:
maximum = net
R = i
if net < 0:
net = 0
if i < R:
L = i
return (total_one + maximum, (L,R))
print(maximum_ones(arr1))
print(maximum_ones(arr2_0))
print(maximum_ones(arr2_1))
print(maximum_ones(arr2_2))
print(maximum_ones(arr3))
Output:
(6, (1, 5))
(14, (1, 16))
(14, (2, 16))
(14, (3, 16))
(11, (0, 2))
First Iteration
Here is what I had originally, if you want to see the evolution of the thought processes. Here, I was essentially transliterating what I came up with on paper.
Essentially, we traverse the array and start flipping bits (ok, not really), keeping track of cumulative flipped zeros and cumulative flipped ones in two separate arrays along with the total flipped ones in an integer counter. If the difference between flipped ones and zeroes at a given index - the "net" - drops below zero, we 'reset' the cumulative counts back at zero at that index (but nothing else). Along the way, we also keep track of the maximum net we've achieved and the index at which that occurs. Thus, the total is simply the total 1's we've seen, plus the net at the maximum index.
arr = [1, 0, 0, 1, 0, 0, 1, 0]
total_one = 0
one_flip = [0 for _ in range(len(arr))]
zero_flip = [0 for _ in range(len(arr))]
# deal with first element of array
if arr[0]:
total_one += 1
else:
zero_flip[0] = 1
maximum = dict(index=0,value=0) #index, value
i = 1
# now deal with the rest
while i < len(arr):
# if element is 1 we definitely increment total_one, else, we definitely flip
if arr[i]:
total_one += 1
one_flip[i] = one_flip[i-1] + 1
zero_flip[i] = zero_flip[i-1]
else:
zero_flip[i] = zero_flip[i-1] + 1
one_flip[i] = one_flip[i-1]
net = zero_flip[i] - one_flip[i]
if net > 0:
if maximum['value'] < net:
maximum['value'] = net
maximum['index'] = i
else: # net == 0, we restart counting our "net"
one_flip[i] = 0
zero_flip[i] = 0
i += 1
maximum_flipped = total_one - one_flip[maximum['index']] + zero_flip[maximum['index']]
Results:
print(total_one, -one_flip[maximum['index']], zero_flip[maximum['index']] )
print(maximum_flipped)
print('________________________________________________')
print(zero_flip, arr, one_flip, sep='\n')
print('maximum index', maximum['index'])
Output:
3 -1 4
6
________________________________________________
[0, 1, 2, 2, 3, 4, 4, 5]
[1, 0, 0, 1, 0, 0, 1, 0]
[0, 0, 0, 1, 1, 1, 2, 2]
maximum index 5
if arr = [1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
6 -4 12
14
________________________________________________
[0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 9, 10, 10, 11, 12, 12]
[1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
[0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5]
maximum index 16
Finally, if arr = [0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1]
8 0 3
11
________________________________________________
[1, 2, 3, 3, 3, 4, 4, 5, 5, 0, 1, 2, 2, 0, 0]
[0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1]
[0, 0, 0, 1, 2, 2, 3, 3, 4, 0, 0, 0, 1, 0, 0]
maximum index 2
Great, now tear it apart, people!
Traverse the whole array. Keep a count in the following way:
Do +1 for every 0 bit encountered.
Do -1 for every 1.
If this count reaches -ve at any stage, reset it to 0. Keep track of max value of this count. Add this max_count to number of 1's in input array. This will be your answer.
Code:
arr = [1, 0, 0, 1, 0, 0, 1, 0]
# I'm taking your sample case. Take the input the way you want
count,count_max,ones = 0,0,0
for i in arr:
if i == 1:
ones += 1
count -= 1
if i == 0:
count += 1
if count_max < count:
count_max = count
if count < 0:
count = 0
print (ones + count_max)
Small and simple :)

Centralising data in numpy

I have matrices with rows that need to be centralised. In other words each row has trailing zeros at both ends, while the actual data is between the trailing zeros. However, I need the number of trailing zeros to be equal at both ends or in other words what I call the data (values between the trailing zeros) to be centred at the middle of the row. Here is an example:
array:
[[0, 1, 2, 0, 2, 1, 0, 0, 0],
[2, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 2, 0, 0, 0]]
centred_array:
[[0, 0, 1, 2, 0, 2, 1, 0, 0],
[0, 0, 0, 2, 1, 1, 0, 0, 0],
[0, 0, 1, 0, 0, 2, 0, 0, 0]]
I hope that explains it well enough so that you can see some of the issues I am having. One, I am not guaranteed a even value for the size of the "data" so the function needs to pick a centre for even values which is consistent; also this is the case for rows (rows might have an even size which means one placed needs to be chosen as the centre).
EDIT: I should probably note that I have a function that does this; its just that I can get 10^3 number of rows to centralise and my function is too slow, so efficiency would really help.
#HYRY
a = np.array([[0, 1, 2, 0, 2, 1, 0, 0, 0],
[2, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 2, 0, 0, 0]])
cd = []
(x, y) = np.shape(a)
for row in a:
trim = np.trim_zeros(row)
to_add = y - np.size(trim)
a = to_add / 2
b = to_add - a
cd.append(np.pad(trim, (a, b), 'constant', constant_values=(0, 0)).tolist())
result = np.array(cd)
print result
[[0 0 1 2 0 2 1 0 0]
[0 0 0 2 1 1 0 0 0]
[0 0 1 0 0 2 0 0 0]]
import numpy as np
def centralise(arr):
# Find the x and y indexes of the nonzero elements:
x, y = arr.nonzero()
# Find the index of the left-most and right-most elements for each row:
nonzeros = np.bincount(x)
nonzeros_idx = nonzeros.cumsum()
left = y[np.r_[0, nonzeros_idx[:-1]]]
right = y[nonzeros_idx-1]
# Calculate how much each y has to be shifted
shift = ((arr.shape[1] - (right-left) - 0.5)//2 - left).astype(int)
shift = np.repeat(shift, nonzeros)
new_y = y + shift
# Create centered_arr
centered_arr = np.zeros_like(arr)
centered_arr[x, new_y] = arr[x, y]
return centered_arr
arr = np.array([[0, 1, 2, 0, 2, 1, 0, 0, 0],
[2, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 2, 0, 0, 0]])
print(centralise(arr))
yields
[[0 0 1 2 0 2 1 0 0]
[0 0 0 2 1 1 0 0 0]
[0 0 1 0 0 2 0 0 0]]
A benchmark comparing the original code to centralise:
def orig(a):
cd = []
(x, y) = np.shape(a)
for row in a:
trim = np.trim_zeros(row)
to_add = y - np.size(trim)
a = to_add / 2
b = to_add - a
cd.append(np.pad(trim, (a, b), 'constant', constant_values=(0, 0)).tolist())
result = np.array(cd)
return result
In [481]: arr = np.tile(arr, (1000, 1))
In [482]: %timeit orig(arr)
10 loops, best of 3: 140 ms per loop
In [483]: %timeit centralise(arr)
1000 loops, best of 3: 537 µs per loop
In [486]: (orig(arr) == centralise(arr)).all()
Out[486]: True
If you only have 10^3 rows in your array, you can probably afford a python loop if you'd like a more explicit solution:
import numpy as np
a = np.array([[0, 1, 2, 0, 2, 1, 0, 0, 0],
[2, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 2, 0, 0, 0]])
for i, r in enumerate(a):
w = np.where(r!=0)[0]
nend = len(r) - w[-1] - 1
nstart = w[0]
shift = (nend - nstart)//2
a[i] = np.roll(r, shift)
print(a)
gives:
[[0 0 1 2 0 2 1 0 0]
[0 0 0 2 1 1 0 0 0]
[0 0 1 0 0 2 0 0 0]]
A solution using np.apply_along_axis:
import numpy as np
def centerRow(a):
i = np.nonzero(a <> 0)
ifirst = i[0][0]
ilast = i[0][-1]
count = ilast-ifirst+1
padleft = (np.size(a) - count) / 2
padright = np.size(a) - padleft - count
b = np.r_ [ np.repeat(0,padleft), a[ifirst:ilast+1], np.repeat(0,padright) ]
return b
arr = np.array(
[[0, 1, 2, 0, 2, 1, 0, 0, 0],
[2, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 2, 0, 0, 0]]
)
barr = np.apply_along_axis(centerRow, 1, arr)
print barr
Algorithm:
find positions of non-zero values on the row of length n
find the difference, d, between 1st and the last non-zero element
store meaningful vector, x, in the row given by length d
find the mid-point of d, d_m, if it is even, get the right element
find the mid-point of row length, n_m, if it is even, pick the right
subtract d_m-d from n_m and place x at this position in the row of zeros of length n
repeat for all rows
Quick Octave Prototype (Will Soon post Python version):
mat = [[0, 1, 2, 0, 2, 1, 0, 0, 0],
[2, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 2, 0, 0, 0]];
newMat = zeros(size(mat)); %new matrix to be filled
n = size(mat, 2);
for i = 1:size(mat,1)
newRow = newMat(i,:);
nonZeros = find(mat(i,:));
x = mat(i, nonZeros(1):nonZeros(end));
d = nonZeros(end)- nonZeros(1);
d_m = ceil(d/2);
n_m = ceil(n/2);
newRow(n_m-d_m:n_m-d_m+d) = x;
newMat(i,:) = newRow;
end
newMat
> [[0 0 1 2 0 2 1 0 0]
[0 0 0 2 1 1 0 0 0]
[0 0 1 0 0 2 0 0 0]]

Categories