Slicing an [m, n] array by a variable [m] array in numpy - python

Let there be a numpy array of shape [M], dtype int32 and (random) values in range [0, N), e.g.:
M = 8
N = 5
a = np.random.randint(0, N, [M]) # a = [1, 1, 2, 4, 0, 1, 1, 3]
From this array I need to create a matrix m of shape [M, N], dtype int32 and values 0 or 1, where m[i,j] = 0 if j < a[i], otherwise 1. Following the example:
m = some_magic(a) # m = [[0, 1, 1, 1, 1],
# [0, 1, 1, 1, 1],
# [0, 0, 1, 1, 1],
# [0, 0, 0, 0, 1],
# [1, 1, 1, 1, 1],
# [0, 1, 1, 1, 1],
# [0, 1, 1, 1, 1],
# [0, 0, 0, 1, 1]]
My dysfunctional version of some_magic starts with initializing the matrix to zeros (using np.zeros), and then proceeding to set the appropriate members to 1.
m = np.zeros([M, N])
This next part though I cannot properly figure out. Accessing single members, for example, every second member, or a fixed slice, is easy, and achievable by
m[np.arange(M), C1:C2]
where C1 and C2 are integer constants,
m[np.arange(M), a:]
which, as far as I've thought, should yield the correct result, fails with the error being
Only integer scalar arrays can be converted to a scalar index.
Can you please point me to the right direction? Thank you very much.

Here's a solution using broadcasting.
(a[:, None] <= np.arange(N)).view('i1')
# np.less_equal.outer(a, np.arange(N)).view('i1')
array([[0, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 1],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 0, 0, 1, 1]], dtype=int8)

I'm not sure if slicing like that is possible. I suggest you create indices instead and then operate on those:
M = 8
N = 5
#a = np.random.randint(0, N, [M])
a = np.array([1, 1, 2, 4, 0, 1, 1, 3])
from0toN = np.expand_dims(np.arange(N),0) # [[0,1,2,3,4]]
m = np.repeat(from0toN, M, axis=0)
#array([[0, 1, 2, 3, 4],
# ...,
# [0, 1, 2, 3, 4]])
boolean = m >= np.expand_dims(a,1)
onesAndZeroes = boolean.astype(int)
"""
array([[0, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 1],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 0, 0, 1, 1]])
"""

Related

Python, Numpy. Find values in 2d array and replace neighbors with 1

I have a 10x10 array with zeros and ones.
I would like to:
find the position of each cell with a value of 1.
replace all the neighbors with 1. neighbors= any cell to a n=1 distance (also diagonal).
Example:
array([[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 1, 1]])
output:
array([[1, 1, 1, 1, 0],
[1, 1, 1, 1, 0],
[1, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
I am trying finding indexes but It does not work:
a=np.where(a==1)+1
From other post I also try getting the neighbors with this function:
def n_closest(x,n,d=1):
return x[n[0]-d:n[0]+d+1,n[1]-d:n[1]+d+1]
But this does not work for the edges
Thanks
If you don't mind using scipy, a 2D convolution will solve the problem quickly:
import numpy as np
from scipy import signal
# Input array
X = np.array([[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 1, 1]])
# We apply a 2D convolution with a 3x3 kernel and we check which value are bigger than 0.
R = (signal.convolve2d(X,np.ones((3,3)),mode='same')>0).astype(int)
# R = array([[1, 1, 1, 0, 0],
# [1, 1, 1, 1, 0],
# [1, 1, 1, 1, 0],
# [1, 1, 1, 1, 1],
# [1, 1, 1, 1, 1]])
# Finally we extract the index
x,y = np.where(R)

How to define an array with all possible combinations of numbers

I want to define an array with a given number of columns (let's say n=5) and in each cell of the array, the value can be either 0 or 1. And I would like to create all possibilities of ones and zeros, which means, that each row would represent one possible vector with n elements.
In other words, I want the table to look like this:
I know that create the vector of ones and zeros is quite easy but how can I ensure that the vectors would not repeat in the table and that there will be all possible combinations included (If my math is correct the table should have 2**5 = 32 rows)
How can I do it in Python? Thank you very much
Easy with itertools:
itertools.product(*[[0, 1]] * 3)
results in
[(0, 0, 0),
(0, 0, 1),
(0, 1, 0),
(0, 1, 1),
(1, 0, 0),
(1, 0, 1),
(1, 1, 0),
(1, 1, 1)]
You could generate all the numbers up to 32, and convert each to binary representation using bit shifts.
combs = [[(n >> p) & 1 for p in range(4, -1, -1)] for n in range(32)]
which gives combs as:
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 1],
[0, 0, 1, 1, 0],
[0, 0, 1, 1, 1],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 1],
[0, 1, 1, 0, 0],
[0, 1, 1, 0, 1],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 1],
[1, 0, 0, 0, 0],
[1, 0, 0, 0, 1],
[1, 0, 0, 1, 0],
[1, 0, 0, 1, 1],
[1, 0, 1, 0, 0],
[1, 0, 1, 0, 1],
[1, 0, 1, 1, 0],
[1, 0, 1, 1, 1],
[1, 1, 0, 0, 0],
[1, 1, 0, 0, 1],
[1, 1, 0, 1, 0],
[1, 1, 0, 1, 1],
[1, 1, 1, 0, 0],
[1, 1, 1, 0, 1],
[1, 1, 1, 1, 0],
[1, 1, 1, 1, 1]
]
Alternatively, you could use a recursive generation function:
def gimme_combs(n):
if n == 1: return [[0], [1]]
lower_combs = gimme_combs(n - 1)
return [[0] + c for c in lower_combs] + \
[[1] + c for c in lower_combs]
which would give the same result when called with:
combs = gimme_combs(5)

moving around values around in a list using map plus function

I have a nested list that I want to do some data restructuring on. The nested list look like this:
[
[1, 2, 1, 0, 0],
[0, 1, 1, 0],
[1, 1, 0, 0, 0],
[0, 1, 1, 0],
[1, 1, 0, 0, 0],
[0, 1, 1, 1],
[1, 1, 0, 0, 0],
[0, 1, 1, 1],
[1, 1, 0, 0, 0],
[0, 1, 1, 1],
[0, 1, 2, 1],
[0, 1, 1, 1],
[1, 2, 1, 0, 0],
[2, 2, 1, 0, 0],
[0, 1, 2, 1],
[1, 2, 4, 2],
[0, 1, 2, 1]
]
I wrote a function to move that is supposed to either move the last element of the list to the front or add a 0 to the end of the list, depending on whether the length of the list is odd or even. This is the function I wrote:
def zero_move (list_obj):
if len(list_obj) % 2 != 0:
list_obj.insert(0, list_obj.pop())
else:
list_obj.append(0)
When I try to map the function to my nested lists it returns none values instead of new lists.
size_list = list(map(zero_move, sizes))
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
This is my desired outcome:
[0, 1, 2, 1, 0]
[0, 1, 1, 0, 0]
[0, 1, 1, 0, 0]
[0, 1, 1, 0, 0]
[0, 1, 1, 0, 0]
[0, 1, 1, 1, 0]
[0, 1, 1, 0, 0]
[0, 1, 1, 1, 0]
[0, 1, 1, 0, 0]
[0, 1, 1, 1, 0]
[0, 1, 2, 1, 0]
[0, 1, 1, 1, 0]
[0, 1, 2, 1, 0]
[0, 2, 2, 1, 0]
[0, 1, 2, 1, 0]
[1, 2, 4, 2, 0]
[0, 1, 2, 1, 0]
I don't understand why I am getting None back instead of my desired outcome.
This is because you are not returning anything. Both the insert and the append operations are modifying the original nested lists in-place. If we inspected the value of the original list after the map:
>>> list(map(zero_move, sizes)
[None, None, ...]
>>> sizes
[[0, 1, 2, 1, 0], [0, 1, 1, 0, 0], ...]
However, since the operation we are performing modifies the original list, it is more idiomatic to use a for loop instead of mapping over the list:
for s in sizes:
zero_move(s)
If however, you don't wish to modify the original list but rather return a new list reflecting the modifications, you will need to change your zero_move method to reflect that:
def zero_move_return(list_obj):
if len(list_obj) % 2 != 0:
return [list_obj[-1]] + list_obj[:-1]
else:
return [0] + list_obj
Now, if you apply your map, you will get the result you originally expected:
>>> list(map(zero_move_return, sizes))
[[0, 1, 2, 1, 0], [0, 1, 1, 0, 0], ...]

Replace some elements of numpy.ndarray with zero given another numpy array

I'd need to know the most efficient way for the following case. There is a numpy.ndarray of shape 11k*11k for which I need to force all elements of some rows to be zero given a binary numpy array of shape 11k. A toy example could be described as follows:
Inputs:
x = np.array([[2, 1, 1, 2],
[0, 2, 1, 0],
[1, 0, 1, 1],
[2, 2, 1, 0]])
ref = np.array([0, 1, 1, 0])
Output:
y = ([[0, 0, 0, 0],
[0, 2, 1, 0],
[1, 0, 1, 1],
[0, 0, 0, 0]])
Use this -
y = np.multiply(x.T,ref).T
array([[0, 0, 0, 0],
[0, 2, 1, 0],
[1, 0, 1, 1],
[0, 0, 0, 0]])

Searching numpy array for for pattern

I'd like to find a value in a numpy array given a search pattern. For instance for the given array a, I want to retrieve a result of 1 when using the search pattern s because 1 is the element at index 0 of a[:,1] (=array([1, 0, 0, 1])) and the elements of a[1:,1] match s (i.e. (a[1:,1] == s).all() == True => return a[0,1]).
Another example would be s=[1, 0, 1] for which I would expect a search result of 2 (match at 4th column starting (1-based)). 2 would also be the search result for s=[2, 0, 0], etc.
>>> import numpy as np
>>> a = np.asarray([[0, 1, 2, 2, 2, 2, 2, 2], [0, 0, 1, 1, 2, 2, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0, 1]])
>>> a
array([[0, 1, 2, 2, 2, 2, 2, 2],
[0, 0, 1, 1, 2, 2, 3, 3],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 1, 0, 1]])
>>> s = np.asarray([0, 0, 1])
I came up with a[0, np.where((a[1:,:].transpose() == s).all(axis=-1))[0][0]], but thought there must be something more elegant...
Additionally, it would be great if I could do this operation with one call on multiple search patters, so that I retrieve the 0-element for which the values of index 1 to index 3 match.
Single search pattern
Here's one approach with help from broadcasting and slicing -
a[0,(a[1:] == s[:,None]).all(0)]
Multiple search patterns
For multiple search patterns (stored as 2D array), we just need to broadcast as before and look for ANY match at the end -
a[0,((a[1:] == s[...,None]).all(1)).any(0)]
Here's a sample run -
In [327]: a
Out[327]:
array([[0, 1, 2, 2, 2, 2, 2, 2],
[0, 0, 1, 1, 2, 2, 3, 3],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 1, 0, 1]])
In [328]: s
Out[328]:
array([[1, 0, 1],
[2, 0, 0]])
In [329]: a[0,((a[1:] == s[...,None]).all(1)).any(0)]
Out[329]: array([2, 2])

Categories

Resources