Converting list to array and reshaping? - python

Attempting to make an array of 2d points.
import random
import numpy as np
world_x=500
world_y=500
num_points = 7
points_list = []
def fill_points():
for i in range(num_points):
points_list.append(random.randrange(-1*world_x,world_x+1))
points_list.append(random.randrange(-1*world_y,world_y+1))
points_array = np.array(points_list)
points_array.reshape((num_points,2))
print(points_array)
print (points_array[0,])
print (points_array[2,])
print (points_array[4,])
fill_points()
Returns
[ -70 -491 -326 -35 -408 407 94 -330 -493 499 -61 -12 62 -357]
-70
-326
-408
I was expecting [-70,-491],[-408,-407], and [-493,499]. I've also tried to do this just using shape instead of reshape, and got similar results. Am I converting the list incorrectly, or using reshape incorrectly?

The .reshape method returns a new array object, that is, it doesn't work in-place. You can either reassign the results of reshape back to the same variable, or modify the .shape attribute directly, which does work in-place:
In [1]: import numpy as np
In [2]: arr = np.arange(10)
In [3]: arr
Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [4]: arr.reshape(2, 5)
Out[4]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
In [5]: arr
Out[5]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
On the other hand:
In [6]: arr.shape = 2, 5
In [7]: arr
Out[7]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
Or use the .resize method for in-place modifications:
In [8]: arr = np.arange(4)
In [9]: arr
Out[9]: array([0, 1, 2, 3])
In [10]: arr.resize(2, 2)
In [11]: arr
Out[11]:
array([[0, 1],
[2, 3]])
Note: the different array objects can share the same underlying buffer, so be aware that this happens:
In [12]: arr = np.arange(10)
In [13]: arr
Out[13]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [14]: arr2 = arr.reshape(2, 5)
In [15]: arr
Out[15]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [16]: arr2
Out[16]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
In [17]: arr[0] = 99
In [18]: arr
Out[18]: array([99, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [19]: arr2
Out[19]:
array([[99, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]])
So, this makes the re-assigning approach relatively cheap:
In [20]: arr = arr.reshape(2, 5)
In [21]: arr
Out[21]:
array([[99, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]])
Note, I tend to avoid .resize, because you can accidentally do:
In [33]: arr = np.arange(4)
In [34]: arr.resize(4,4)
In [35]: arr
Out[35]:
array([[0, 1, 2, 3],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]])
But it will at least warn you... if other arrays are referenced:
In [36]: arr = np.arange(4)
In [37]: arr2 = arr.reshape(2,2)
In [38]: arr
Out[38]: array([0, 1, 2, 3])
In [39]: arr2
Out[39]:
array([[0, 1],
[2, 3]])
In [40]: arr.resize(4,4)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-40-c4464d98ed0e> in <module>()
----> 1 arr.resize(4,4)
ValueError: cannot resize an array that references or is referenced
by another array in this way. Use the resize function
However, you can override that behavior at your own peril:
In [41]: arr.resize(4,4, refcheck=False)
In [42]: arr
Out[42]:
array([[0, 1, 2, 3],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]])
In [43]: arr2
Out[43]:
array([[4611686018427387904, 4611686018427387904],
[ 6, 0]])

It looks like you want to keep the x and y cords together, try adding them as a list. E.g.:
import random
import numpy as np
world_x=500
world_y=500
num_points = 7
points_list = []
def fill_points():
for i in range(num_points):
points_list.append([random.randrange(-1*world_x,world_x+1),
random.randrange(-1*world_y,world_y+1)])
points_array = np.array(points_list)
print(points_array)
print (points_array[0,0])
print (points_array[2,0])
print (points_array[4,0])
fill_points()
Outputs:
[[ 354 -147]
[ 193 288]
[ 157 -319]
[ 133 426]
[-109 -54]
[ -61 224]
[-251 -411]]
354
157
-109
Or if you want to use reshape. Remember reshape returns a new list, it doesnt change the list you input:
def fill_points():
for i in range(num_points):
points_list.append(random.randrange(-1*world_x,world_x+1))
points_list.append(random.randrange(-1*world_y,world_y+1))
points_array = np.array(points_list).reshape((num_points,2))
print(points_array)
print (points_array[0,0])
print (points_array[2,0])
print (points_array[4,0])
fill_points()

Related

How i can get the indexes of numpy array that contain one's

How I can get the indexes of element that contain 1 in numpy array, in an elegant way?
I tried to do a loop:
indexes = []
for i in range(len(array)):
if array[i] == 1:
indexes += [i]
Use np.where:
a = np.array([0, 0, 1, 1, 0, 1, 1, 1, 0])
np.where(a)
Output:
(array([2, 3, 5, 6, 7], dtype=int64),)
Or np.nonzero:
a.nonzero()
Output:
(array([2, 3, 5, 6, 7], dtype=int64),)
You can also index into np.arange:
np.arange(len(a))[a.astype(bool)]
Output:
array([2, 3, 5, 6, 7])
numpy.argwhere() could be a perfect worker API for doing this. Additionally, we also have to remove the singleton dimension using arr.squeeze(). Below are two cases:
If your input is a 0-1 array, then:
In [101]: a = np.array([0, 0, 1, 1, 0, 1, 1, 1, 0])
In [102]: np.argwhere(a).squeeze()
Out[102]: array([2, 3, 5, 6, 7])
On the other hand, if you have a generic array, then:
In [98]: np.random.seed(23)
In [99]: arr = np.random.randint(0, 5, 10)
In [100]: arr
Out[100]: array([3, 0, 1, 0, 4, 3, 2, 1, 3, 3])
In [106]: np.argwhere(arr == 1).squeeze()
Out[106]: array([2, 7])

Numpy add (append) value to each row of 2-d array

I have numpy array of floats with shape (x,14) and I would like to add to the end of each "row" one more value (to each row different value), so that end result has shape (x,15).
We can suppose that I have those values in some list, so that part of the question is also defined.
How to do it with numpy functions?
Define a 2d array and a list:
In [73]: arr = np.arange(12).reshape(4,3)
In [74]: arr
Out[74]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
In [75]: alist = [10,11,12,13]
Note their shapes:
In [76]: arr.shape
Out[76]: (4, 3)
In [77]: np.array(alist).shape
Out[77]: (4,)
To join alist to arr it needs to have the same number of dimensions, and same number of 'rows'. We can do that by adding a dimension with the None idiom:
In [78]: np.array(alist)[:,None].shape
Out[78]: (4, 1)
Now we can concatenate on the 2nd axis:
In [79]: np.concatenate((arr, np.array(alist)[:,None]),axis=1)
Out[79]:
array([[ 0, 1, 2, 10],
[ 3, 4, 5, 11],
[ 6, 7, 8, 12],
[ 9, 10, 11, 13]])
column_stack does the same thing, taking care that each input is at least 2d (I'd suggest reading its code.) In the long run you should be familiar enough with dimensions and shapes to do this with plain concatenate.
In [81]: np.column_stack((arr, alist))
Out[81]:
array([[ 0, 1, 2, 10],
[ 3, 4, 5, 11],
[ 6, 7, 8, 12],
[ 9, 10, 11, 13]])
np.c_ also does this - but note the use of [] instead of (). It's a clever use of indexing notation, convenient, but potentially confusing.
np.c_[arr, alist]
np.r_['-1,2,0', arr, alist] # for more clever obscurity
You can use numpy.insert function (https://numpy.org/doc/stable/reference/generated/numpy.insert.html)
a = np.array([[1, 1], [2, 2], [3, 3]])
np.insert(a, 2, 0, axis=1)
Output:
array([[1, 1, 0],
[2, 2, 0],
[3, 3, 0]])

How to re-index 3d numpy array

Lets say we have a 3D array like:
array = np.arange(8).reshape(2,2, 2)
new_array = np.zeros((2, 2, 2))
and lets assume we have some new random x,y,z indices for our array
x,y,z = np.meshgrid(array, array, array)
What is the fastest way to re-index our array?
A simple solution given here:
for x in range(0, 3):
for y in range(0, 3):
for z in range(0, 3):
new_x = x_coord[x,y,z]
new_y = y_coord[x,y,z]
new_z = z_coord[x,y,z]
new_array[x,y,z] = array[new_x, new_y, new_z]
Is there a one-liner for this that I am not aware of?
EDIT
Yes, there is... very easy:
vol = np.arange(8).reshape(2,2, 2)
arr = np.arange(2)
x,y,z = np.meshgrid(arr, arr, arr)
print(vol)
print(vol[y, x, z]) ### ---> You have to swap the axes here tho. Does anyone know why?
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
Also, it is very slow. Any ideas how to improve the performance?
Setup:
In [54]: arr = np.arange(9).reshape(3,3)
In [55]: x = np.random.randint(0,3,(3,3))
In [56]: y = np.random.randint(0,3,(3,3))
In [57]: x
Out[57]:
array([[2, 0, 1],
[0, 2, 1],
[0, 0, 1]])
In [58]: y
Out[58]:
array([[0, 0, 0],
[0, 1, 1],
[0, 1, 0]])
The simplest application of these indexing arrays:
In [59]: arr[x,y]
Out[59]:
array([[6, 0, 3],
[0, 7, 4],
[0, 1, 3]])
The iterative equivalent:
In [60]: out = np.empty_like(arr)
In [61]: for i in range(3):
...: for j in range(3):
...: out[i,j] = arr[x[i,j], y[i,j]]
...:
In [62]: out
Out[62]:
array([[6, 0, 3],
[0, 7, 4],
[0, 1, 3]])
Your code isn't the same, because it is modifying the source array as it iterates:
In [63]: arr1 = arr.copy()
In [64]: for i in range(3):
...: for j in range(3):
...: arr1[i,j] = arr1[x[i,j], y[i,j]]
...:
In [65]: arr1
Out[65]:
array([[6, 6, 3],
[6, 7, 7],
[6, 6, 6]])
There isn't a simple equivalent.
You can index with arr[x_coord,y_coord,z_coord] as long a indexing arrays broadcast together. Where they all have the same shape that is trivial.
In [68]: x1 = np.random.randint(0,3,(2,4))
In [69]: x1
Out[69]:
array([[2, 0, 2, 0],
[0, 0, 0, 2]])
In [70]: arr[x1,x1]
Out[70]:
array([[8, 0, 8, 0],
[0, 0, 0, 8]])
A simpler way of picking random values from an array is to create random row and column selectors, and use ix_ to create arrays that broadcast together:
In [71]: x1 = np.random.randint(0,3,(3))
In [72]: y1 = np.random.randint(0,3,(3))
In [75]: np.ix_(x1,y1)
Out[75]:
(array([[2],
[1],
[1]]), array([[2, 2, 1]]))
In [76]: arr[np.ix_(x1,y1)]
Out[76]:
array([[8, 8, 7],
[5, 5, 4],
[5, 5, 4]])
Almost sounds like you just want to shuffle the values of the array, like:
In [95]: arr
Out[95]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [96]: np.random.shuffle(arr.ravel())
In [97]: arr
Out[97]:
array([[0, 1, 2],
[7, 4, 3],
[6, 5, 8]])

function to find minimum number greater than zero from rows of a array and store into a list

I want to find out minimum number from the rows of 9x9 array A and store in a list m. But I want to exclude zero. The program that I made is returning zero as minimum.
m = []
def find (L):
for i in range(len(L)):
m.append(A[L[i]].min())
c = [2,3,4,5,6];
find(c)
print m
Here's a NumPy solution -
np.where(a>0,a,a.max()).min(1)
Sample run -
In [45]: a
Out[45]:
array([[0, 4, 6, 6, 1],
[3, 1, 5, 0, 0],
[6, 3, 6, 0, 0],
[0, 6, 3, 5, 2]])
In [46]: np.where(a>0,a,a.max()).min(1)
Out[46]: array([1, 1, 3, 2])
If you want to perform this operation along selected rows only specified by row indices in L -
def find(a,L):
return np.where(a[L]>0,a[L],a.max()).min(1)
Sample run -
In [62]: a
Out[62]:
array([[0, 4, 6, 6, 1],
[3, 1, 5, 0, 0],
[6, 3, 6, 0, 0],
[0, 6, 3, 5, 2]])
In [63]: L = [2,3]
In [64]: find(a,L)
Out[64]: array([3, 2])

Extract rows from python array in python

I have a numpy array X with shape (768, 8).
The last value for each row can either be 0 or 1, I only want rows with value 1, and call this T.
I did:
T = [x for x in X if x[7]==1]
This is correct, however, this is now a list, not a numpy array (in fact I cannot print T.shape).
What should I do instead to keep this a numpy array?
NumPy's boolean indexing gets the job done in a fully vectorized manner. This approach is generally more efficient (and arguably more elegant) than using list comprehensions and type conversions.
T = X[X[:, -1] == 1]
Demo:
In [232]: first_columns = np.random.randint(0, 10, size=(10, 7))
In [233]: last_column = np.random.randint(0, 2, size=(10, 1))
In [234]: X = np.hstack((first_columns, last_column))
In [235]: X
Out[235]:
array([[4, 3, 3, 2, 6, 2, 2, 0],
[2, 7, 9, 4, 7, 1, 8, 0],
[9, 8, 2, 1, 2, 0, 5, 1],
[4, 4, 4, 9, 6, 4, 9, 1],
[9, 8, 7, 6, 4, 4, 9, 0],
[8, 3, 3, 2, 9, 5, 5, 1],
[7, 1, 4, 5, 2, 4, 7, 0],
[8, 0, 0, 1, 5, 2, 6, 0],
[7, 9, 9, 3, 9, 3, 9, 1],
[3, 1, 8, 7, 3, 2, 9, 0]])
In [236]: mask = X[:, -1] == 1
In [237]: mask
Out[237]: array([False, False, True, True, False, True, False, False, True, False], dtype=bool)
In [238]: T = X[mask]
In [239]: T
Out[239]:
array([[9, 8, 2, 1, 2, 0, 5, 1],
[4, 4, 4, 9, 6, 4, 9, 1],
[8, 3, 3, 2, 9, 5, 5, 1],
[7, 9, 9, 3, 9, 3, 9, 1]])
By calling
T = [x for x in X if x[8]==1]
you are making T as a list. To convert it any list to a numpy array, just use:
T = numpy.array([x for x in X if x[8]==1])
Here is what happens:
In [1]: import numpy as np
In [2]: a = [1,2,3,4]
In [3]: a.T
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-9f69ed463660> in <module>()
----> 1 a.T
AttributeError: 'list' object has no attribute 'T'
In [4]: a = np.array(a)
In [5]: a.T
Out[5]: array([1, 2, 3, 4])
In [6]:

Categories

Resources