numpy roll along a single axis - python

I have a numpy array with binary values that I need to change in the following way: The value of every element must be shifted one column to the left but only within the same row. As an example, I have the following array:
>>> arr = np.array([[0,0,1,0],[1,0,0,0],[0,0,1,1]])
>>> arr
array([[0, 0, 1, 0],
[1, 0, 0, 0],
[0, 0, 1, 1]])
And it needs to be transformed to:
>>> arr
array([[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 1, 1, 0]])
I know that np.roll(arr,-1) would roll the values one cell to the left, but it doesn't seem to be able to roll them within the rows they belong to (i.e. the element on cell [1,0] goes to [0,3] instead of the desired [1,3]. Is there a way of doing this?
Thanks in advance.

roll accepts an axis parameter:
np.roll(arr,-1, axis=1)
array([[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 1, 1, 0]])

Related

Merge three numpy arrays, keep largest value

I want to merge three numpy arrays, for example:
a = np.array([[0,0,1],[0,1,0],[1,0,0]])
b = np.array([[1,0,0],[0,1,0],[0,0,1]])
c = np.array([[0,1,0],[0,2,0],[0,1,0]])
a = array([[0, 0, 1],
[0, 1, 0],
[1, 0, 0]])
b = array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
c = array([[0, 1, 0],
[0, 2, 0],
[0, 1, 0]])
Desired result would be to overlay them but keep the largest value where multiple elements are not 0, like in the middle.
array([[1, 1, 1],
[0, 2, 0],
[1, 1, 1]])
I solved this by iterating over all elements with multiple if-conditions. Is there a more compact and more beautiful way to do this?
You can try of stacking arrays together in extra dimension with Numpy np.dstack method
and extract the maximum value specific to added dimension
# Stacking arrays together
d = np.dstack([a,b,c])
d.max(axis=2)
Out:
array([[1, 1, 1],
[0, 2, 0],
[1, 1, 1]])
NumPy's np.ufunc.reduce allows to apply a function cumulatively along a given axis. We can just concatenate the arrays and reduce with numpy.maximum to keep the accumulated elementwise maximum:
np.maximum.reduce([a,b,c])
array([[1, 1, 1],
[0, 2, 0],
[1, 1, 1]])

Changing the order of a matrix in numpy

I have a matrix
test = np.array([[0,1,0,0],[1,0,1,1],[0,1,0,1],[0,1,1,0]])
How do I reorder the columns so that they are like this matrix? (Basically the last row becomes the first row in reverse order and so on...)
np.array([[0,1,1,0],[1,0,1,0],[1,1,0,1],[0,0,1,0]])
Just reverse both axis
test[::-1,::-1]
array([[0, 1, 1, 0],
[1, 0, 1, 0],
[1, 1, 0, 1],
[0, 0, 1, 0]])
Update (ahh... Okay, I think I understand now.)
You can use negative steps for both the inner and outer steps.
test[::-1, ::-1]
Output:
array([[0, 1, 1, 0],
[1, 0, 1, 0],
[1, 1, 0, 1],
[0, 0, 1, 0]])
To reverse both the row and column you can use the np.flip, in your case:
test = np.array([[0,1,0,0],[1,0,1,1],[0,1,0,1],[0,1,1,0]])
reversed = np.flip(test, axis=[0,1])

create a 3d numpy array from a 2d numpy array

I have a 2d numpy array as : arr= np.array([[2,5,10],[6,2,9]]). Now I want to convert this into 3d numpy array as I will place same number of 1's towards z-axis or the 3rd dimension, at that place replacing the element. For example, in place of 2, we will place two 1's and all other elements will be zero. So I place of two 1 and eight 0, since the matrix will be of size 2*3*10.
Is it possible? If yes, How can we achieve this?
you can try something like this :
arr3d= np.zeros((arr.shape[0] , arr.shape[1], max(map(max, arr))))
for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
print(i,j,arr[i][j])
for k in range(arr[i][j]):
arr3d[i,j,k]=1
I know 3 loops :\
edited after suggestions from #hpaulj
This may be what you're asking...
Use numpy.reshape. This takes the array and reshapes it like so:
array = numpy.array([[1,4,1], [3, 1, 4]])
numpy.reshape(array, (array.shape[0], array.shape[1], 1).
array is now numpy.array([[[1,4,1], [3, 1, 4]]])
The 1 at the end is basically adding an extra dimension to the array. Shape just means the length of an X-Y-Z-whatever dimensional thing...
See the numpy docs for reshape at https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html.
Hope I helped!
Use broadcasting like so:
>>> x = np.array([[2,5,10],[6,2,9]])
>>>
>>> (x[..., None] > np.arange(10)).view('i1')
array([[[1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]],
[[1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0]]], dtype=int8)

How to merge 4 columns based on user-defined criterion

I need to merge 4 columns of an array into a single column
array([[0, 0, 0, 1],
[1, 0, 0, 0],
...,
[0, 1, 0, 0]])
The result should be:
array([3, 0, ..., 1])
In particular, I want to get column indices (starting from 0 and ending with 3) for those columns that have a value 1.
Based on each row containing only one '1' value, and only with zeros and ones.
EDIT: For some reason I lost the connection with numpy while trying to clarify question. This will not work if using numpy, but I'll leave it in case you were looking for something with just lists.
a = [[0, 0, 0, 1],
[1, 0, 0, 0],
[1, 0, 0, 0],
[0, 1, 0, 0]]
# One way
single_list = []
for x in a:
single_list.append(x.index(1))
# or
using_list_comprehension = [x.index(1) for x in a]
If every row has a unique one then the following will work:
np.where(a == 1)[1]
For example:
>>> a = np.array([[0, 0, 0, 1], [1, 0, 0, 0], [0, 1, 0, 0]])
>>> np.where(a == 1)[1]
array([3, 0, 1])
We can see it from the following:
>>> np.where(a == 1)
(array([0, 1, 2]), array([3, 0, 1]))
array([0, 1, 2]) are the row indexes having one values, and array([3, 0, 1] are the column indexes. This means that we have one values at coordinates (0, 3), (1, 0), (2, 1). Because each row will have one unique value of one, then there will be one column index for each row.

NumPy: sort matrix rows by number of non-zero entries

import numpy as np
def calc_size(matrix, index):
return np.nonzero(matrix[index,:])[1].size
def swap_rows(matrix, frm, to):
matrix[[frm, to],:] = matrix[[to, frm],:]
Numpy - Python 2.7
How can I achieve that matrix's rows are sorted after the size of the nonzero entries? I already wrote these two methods for doing the work but I need to give it to a sorting engine? The fullest rows should be at the beginning!
If you have an array arr:
array([[0, 0, 0, 0, 0],
[1, 0, 1, 1, 1],
[0, 1, 0, 1, 1],
[1, 1, 1, 1, 1]])
You could sort the array's rows according to the number of zero entries by writing:
>>> arr[(arr == 0).sum(axis=1).argsort()]
array([[1, 1, 1, 1, 1],
[1, 0, 1, 1, 1],
[0, 1, 0, 1, 1],
[0, 0, 0, 0, 0]])
This first counts the number of zero entries in each row with (arr == 0).sum(axis=1): this produces the array [5, 1, 2, 0].
Next, argsort sorts the indices of this array by their corresponding value, giving [3, 1, 2, 0].
Lastly, this argsorted array is used to rearrange the rows of arr.
P.S. If you have a matrix m (and not an array), you may need to ravel before using argsort:
m[(m == 0).sum(axis=1).ravel().argsort()]

Categories

Resources