Function over each value in Python Array (without using def) - python

The input array is x with dimensions (1 x 3) and the output array is 3 x 3 (column of input x column of input). The output array's diagonals are the values^2. If row != column, then the formula is x(row)+x(col) for each value. Currently for 1 x 3 but should assume a variety of dimensions as input. Cannot use 'def'. The current code does not work, what would you recommend?
x = np.array([[0, 5, 10]])
output array formulas =
[[i^2, x(row)+x(col), x(row)+x(col)]
[x(row)+x(col), i^2, x(row)+x(col)]
[x(row)+x(col), x(row)+x(col), i^2]]
# where row and column refer to the output matrix row, column. For example, the value in (1,2) is x(1)+x(2)= 5
ideal output =
[[0 5 10]
[5 25 15]
[10 15 100]]
Code Attempted:
x = np.array([[0, 5, 10]])
r, c = np.shape(x)
results = np.zeros((c, c))
g[range(c), range(c)] = x**2
for i in x:
for j in i:
results[i,j] = x[i]+x[j]

Learn to use numpy methods and broadcasting:
>>> x
array([[ 0, 5, 10]])
>>> x.T
array([[ 0],
[ 5],
[10]])
>>> x.T + x
array([[ 0, 5, 10],
[ 5, 10, 15],
[10, 15, 20]])
>>> result = x.T + x
>>> result
array([[ 0, 5, 10],
[ 5, 10, 15],
[10, 15, 20]])
Then this handy built-in:
>>> np.fill_diagonal(result, x**2)
>>> result
array([[ 0, 5, 10],
[ 5, 25, 15],
[ 10, 15, 100]])
Can replace the results[range(c), range(c)] = x**2

Try this:
x.repeat(x.shape[1], axis=0)
x = x+x.T
x[np.arange(len(x)),np.arange(len(x))] = (np.diag(x)/2)**2

Related

python : numpy n-array : arranged values

i would like to get an multidimentional array in arr1.shape = (x,y)
which would be filled with values like from np.arange(z), where z is number of spaces in arr1.
it is known that, that i could make
arr2 = np.random.randn(x,y)
but then the values would be random...
Is there any straight way, which allows me not to iterate through the array?
You could use numpy.reshape to take the result of numpy.arange and reshape into (x,y) dimensions
>>> import numpy as np
>>> x = 5
>>> y = 3
>>> np.reshape(np.arange(x*y), (x,y))
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])

how to understand such shuffling data code in Numpy

I am learning at Numpy and I want to understand such shuffling data code as following:
# x is a m*n np.array
# return a shuffled-rows array
def shuffle_col_vals(x):
rand_x = np.array([np.random.choice(x.shape[0], size=x.shape[0], replace=False) for i in range(x.shape[1])]).T
grid = np.indices(x.shape)
rand_y = grid[1]
return x[(rand_x, rand_y)]
So I input an np.array object as following:
x1 = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]], dtype=int)
And I get a output of shuffle_col_vals(x1) like comments as following:
array([[ 1, 5, 11, 15],
[ 3, 8, 9, 14],
[ 4, 6, 12, 16],
[ 2, 7, 10, 13]], dtype=int64)
I get confused about the initial way of rand_x and I didn't get such way in numpy.array
And I have been thinking it a long time, but I still don't understand why return x[(rand_x, rand_y)] will get a shuffled-rows array.
If not mind, could anyone explain the code to me?
Thanks in advance.
In indexing Numpy arrays, you can take single elements. Let's use a 3x4 array to be able to differentiate between the axes:
In [1]: x1 = np.array([[1, 2, 3, 4],
...: [5, 6, 7, 8],
...: [9, 10, 11, 12]], dtype=int)
In [2]: x1[0, 0]
Out[2]: 1
If you review Numpy Advanced indexing, you will find that you can do more in indexing, by providing lists for each dimension. Consider indexing with x1[rows..., cols...], let's take two elements.
Pick from the first and second row, but always from the first column:
In [3]: x1[[0, 1], [0, 0]]
Out[3]: array([1, 5])
You can even index with arrays:
In [4]: x1[[[0, 0], [1, 1]], [[0, 1], [0, 1]]]
Out[4]:
array([[1, 2],
[5, 6]])
np.indices creates a row and col array, that if used for indexing, give back the original array:
In [5]: grid = np.indices(x1.shape)
In [6]: np.alltrue(x1[grid[0], grid[1]] == x1)
Out[6]: True
Now if you shuffle the values of grid[0] col-wise, but keep grid[1] as-is, and then use these for indexing, you get an array with the values of the columns shuffled.
Each column index vector is [0, 1, 2]. The code now shuffles these column index vectors for each column individually, and stacks them together into rand_x into the same shape as x1.
Create a single shuffled column index vector:
In [7]: np.random.seed(0)
In [8]: np.random.choice(x1.shape[0], size=x1.shape[0], replace=False)
Out[8]: array([2, 1, 0])
The stacking works by (pseudo-code) stacking with [random-index-col-vec for cols in range(x1.shape[1])] and then transposing (.T).
To make it a little clearer we can rewrite i as col and use column_stack instead of np.array([... for col]).T:
In [9]: np.random.seed(0)
In [10]: col_list = [np.random.choice(x1.shape[0], size=x1.shape[0], replace=False)
for col in range(x1.shape[1])]
In [11]: col_list
Out[11]: [array([2, 1, 0]), array([2, 0, 1]), array([0, 2, 1]), array([2, 0, 1])]
In [12]: rand_x = np.column_stack(col_list)
In [13]: rand_x
Out[13]:
array([[2, 2, 0, 2],
[1, 0, 2, 0],
[0, 1, 1, 1]])
In [14]: x1[rand_x, grid[1]]
Out[14]:
array([[ 9, 10, 3, 12],
[ 5, 2, 11, 4],
[ 1, 6, 7, 8]])
Details to note:
the example output you give is different from what the function you provide does. It seems to be transposed.
the use of rand_x and rand_y in the sample code can be confusing when being used to the convention of x=column index, y=row index
See output:
import numpy as np
def shuffle_col_val(x):
print("----------------------------\n A rand_x\n")
f = np.random.choice(x.shape[0], size=x.shape[0], replace=False)
print(f, "\nNow I transpose an array.")
rand_x = np.array([f]).T
print(rand_x)
print("----------------------------\n B rand_y\n")
print("Grid gives you two possibilities\n you choose second:")
grid = np.indices(x.shape)
print(format(grid))
rand_y = grid[1]
print("\n----------------------------\n C Our rand_x, rand_y:")
print("\nThe order of values in the column CHANGE:\n has random order\n{}".format(rand_x))
print("\nThe order of values in the row NO CHANGE:\n has normal order 0, 1, 2, 3\n{}".format(rand_y))
return x[(rand_x, rand_y)]
x1 = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]], dtype=int)
print("\n----------------------------\n D Our shuffled-rows: \n{}\n".format(shuffle_col_val(x1)))
Output:
A rand_x
[2 3 0 1]
Now I transpose an array.
[[2]
[3]
[0]
[1]]
----------------------------
B rand_y
Grid gives you two possibilities, you choose second:
[[[0 0 0 0]
[1 1 1 1]
[2 2 2 2]
[3 3 3 3]]
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]]
----------------------------
C Our rand_x, rand_y:
The order of values in the column CHANGE: has random order
[[2]
[3]
[0]
[1]]
The order of values in the row NO CHANGE: has normal order 0, 1, 2, 3
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
----------------------------
D Our shuffled-rows:
[[ 9 10 11 12]
[13 14 15 16]
[ 1 2 3 4]
[ 5 6 7 8]]

Indexing numpy 2D array that wraps around

How do you index a numpy array that wraps around when its out of bounds?
For example, I have 3x3 array:
import numpy as np
matrix = np.array([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]])
##
[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]]
Say I would like to index the values around index (2,4) where value 15 is located. I would like to get back the array with values:
[[9, 10, 6]
[14, 15, 11]
[4, 5, 1]]
Basically all the values around 15 was returned, assuming it wraps around
A fairly standard idiom to find the neighboring elements in a numpy array is arr[x-1:x+2, y-1:y+2]. However, since you want to wrap, you can pad your array using wrap mode, and offset your x and y coordinates to account for this padding.
This answer assumes that you want the neighbors of the first occurence of your desired element.
First, find the indices of your element, and offset to account for padding:
x, y = np.unravel_index((m==15).argmax(), m.shape)
x += 1; y += 1
Now pad, and index your array to get your neighbors:
t = np.pad(m, 1, mode='wrap')
out = t[x-1:x+2, y-1:y+2]
array([[ 9, 10, 6],
[14, 15, 11],
[ 4, 5, 1]])
Here's how you can do it without padding. This can generalize easily to when you want more than just one neighbor and without the overhead of padding the array.
def get_wrapped(matrix, i, j):
m, n = matrix.shape
rows = [(i-1) % m, i, (i+1) % m]
cols = [(j-1) % n, j, (j+1) % n]
return matrix[rows][:, cols]
res = get_wrapped(matrix, 2, 4)
Let me explain what's happening here return matrix[rows][:, cols]. This is really two operations.
The first is matrix[rows] which is short hand for matrix[rows, :] which means give me the selected rows, and all columns for those rows.
Then next we do [:, cols] which means give me all the rows and the selected cols.
The take function works in-place.
>>> a = np.arange(1, 16).reshape(3,5)
array([[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15]])
>>> b = np.take(a, [3,4,5], axis=1, mode='wrap')
array([[ 4, 5, 1],
[ 9, 10, 6],
[14, 15, 11]])
>>> np.take(b, [1,2,3], mode='wrap', axis=0)
array([[ 9, 10, 6],
[14, 15, 11],
[ 4, 5, 1]])

Change values in array (condition) with values from another list

I have the following list:
indices
>>> [21, 43, 58, 64, 88, 104, 113, 115, 120]
I want every occurrence of these values in this list -1 (so 20, 42, 57, etc.) to be zeroed out from a 3D array 'q' I have.
I have tried list comprehensions, for and if loops (see below), but I always get the following error:
ValueError: The truth value of an array with more than one element is
ambiguous. Use a.any() or a.all()
I haven't been able to resolve this.
Any help would be amazing!
>>> for b in q:
... for u in indices:
... if b==u:
... b==0
>>> for u in indices:
... q = [0 if x==u else x for x in q]
I think this is a short and efficient way:
b= b*np.logical_not(np.reshape(np.in1d(b,indices),b.shape))
with np.in1d() we have a boolean array with True where the element in b is in indices. We reshape it to be the as b and then negate, so that we have False (or, if you want, 0) where we want to zero b. Just multiply this matrix element wise with b and you got it
It has the advantage that it works for 1D, 2D, 3D, ... arrays
How about this?
indices = range(1, 10)
>>[1, 2, 3, 4, 5, 6, 7, 8, 9]
q = np.arange(12).reshape(2,2,3)
array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]]])
def zeroed(row):
new_indices = map(lambda x: x-1, indices)
nrow = [0 if elem in new_indices else elem for elem in row]
return now
np.apply_along_axis(zeroed, 1, q)
array([[[ 0, 0, 0],
[ 0, 0, 0]],
[[ 0, 0, 0],
[ 9, 10, 11]]])
I tried this and it worked for me:
>>> arr_2D = [3,4,5,6]
>>> arr_3D = [[3,4,5,6],[2,3,4,5],[4,5,6,7,8,8]]
>>> for el in arr_2D:
... for x in arr_3D:
... for y in x:
... if y == el - 1:
... x.remove(y)
...
>>> arr_3D
[[6], [], [6, 7, 8, 8]]
Doing it with list comprehensions seams like it might be overkill in this situation.
Or to zero out instead of remove
>>> for el in arr_2D:
... for x in range(len(arr_3D)):
... for y in range(len(arr_3D[x])):
... if arr_3D[x][y] == el - 1:
... arr_3D[x][y] = 0
...
>>> arr_3D
[[0, 0, 0, 6], [0, 0, 0, 0], [0, 0, 6, 7, 8, 8]]
Here is the list comprehension:
zero_out = lambda arr_2D, arr_3D: [[0 if x in [el-1 for el in arr_2D] else x for x in y] for y in arr_3D]

numpy, different slices for different layers of array

I have 3d array m*n*k and for every 2d-layer I want to take a subarray of size i*j. I have an array c with size 2*k of coordinates of starts of slices for every layer. Is there nice and easy way to get what I need without any loops?
Example:
test = np.arange(18).reshape((3,3,2))
c = np.array([[0,1], [0, 1]])
test[:,:,0] = array([[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
test[:,:,1] = array([[ 1, 3, 5],
[ 7, 9, 11],
[13, 15, 17]])
I want to get an array
[[[ 0, 9],
[ 2, 11]],
[[ 6, 15],
[ 8, 17]]]
Solution with loop:
h=2
w=2
layers = 2
F = np.zeros((h,w,layers))
for k in range(layers):
F[:,:,k] = test[c[0,k]:c[0,k]+h, c[1,k]:c[1,k]+w, k]
Here's a vectorized approach making use of broadcasting and advanced-indexing -
d0,d1,d2 = np.ogrid[:h,:w,:layers]
out = test[d0+c[0],d1+c[1],d2]
Sample run -
In [112]: test = np.arange(200).reshape((10,10,2))
...: c = np.array([[0,1], [0, 1]])
...:
In [113]: h=4
...: w=5
...: layers = 2
...: F = np.zeros((h,w,layers))
...: for k in range(layers):
...: F[:,:,k] = test[c[0,k]:c[0,k]+h, c[1,k]:c[1,k]+w, k]
...:
In [114]: d0,d1,d2 = np.ogrid[:h,:w,:layers]
...: out = test[d0+c[0],d1+c[1],d2]
...:
In [115]: np.allclose(F, out)
Out[115]: True

Categories

Resources