Trying to modify np array diagonal - python

I am trying to modify the diagonal values of a 6 x 5 2D numpy array (It's an exercise in this scipy tutorial: http://scipy-lectures.org/intro/numpy/array_object.html#basic-visualization). I'm supposed to change the values of a diagonal from zeroes to 2,3,4,5,6. Since it's a 6 x 5 matrix, there's not really a "main" diagonal, and so I need to change the diagonal starting from the second row ([1][0]) to [5][4]. They suggest reading the docstring for diag. I did, and I still can't figure out how to do this. Any suggestions?

You can just slice an array, and fill_diagonal of that:
In [13]: import numpy as np
In [14]: a = np.zeros((6,5), int)
In [15]: np.fill_diagonal(a[1:], [2,3,4,5,6])
In [16]: a
Out[16]:
array([[0, 0, 0, 0, 0],
[2, 0, 0, 0, 0],
[0, 3, 0, 0, 0],
[0, 0, 4, 0, 0],
[0, 0, 0, 5, 0],
[0, 0, 0, 0, 6]])

Related

How can I add a 1D array to a segment of a 2D array?

I have a 2D NumPy array filled with zeroes (placeholder values). I would like to add a 1D array filled with ones and zeroes to a part of it. eg.
2D array:
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
1D array:
array([1, 0, 1])
Desired end product: I want the array starting in position [2, 1]
array([[0, 0, 0, 0, 0],
[0, 0, 1, 0, 1],
[0, 0, 0, 0, 0]])
Or an insertion in any other position it could reasonably fit in. I have tried to do it with boolean masks but have not had any luck creating one in the correct shape. I have also tried flattening the 2D array, but couldn't figure out how to replace the values in the correct space.
You can indeed flatten the array and create a sequence of positions where you will insert your 1D array segment:
>>> pos = [1, 2]
>>> start = x.shape[1]*pos[0] + pos[1]
>>> seq = start + np.arange(len(segment))
>>> seq
array([7, 8, 9])
Then, you can either index the flattened array:
>>> x_f = x.flatten()
>>> x_f[seq] = segment
>>> x_f.reshape(x.shape)
array([[0, 0, 0, 0, 0],
[0, 0, 1, 0, 1],
[0, 0, 0, 0, 0]])
Alternatively, you can np.ravel_multi_index to get seq and apply np.unravel_index on it.
>>> seq = np.arange(len(segment)) + np.ravel_multi_index(pos, x.shape)
array([7, 8, 9])
>>> indices = np.unravel_index(seq, x.shape)
(array([1, 1, 1]), array([2, 3, 4]))
>>> x[indices] = segment
>>> x
array([[0, 0, 0, 0, 0],
[0, 0, 1, 0, 1],
[0, 0, 0, 0, 0]])

How do I extract elements from a 2D array using a 2D array of indices?

I am trying to extract elements from a 2 dimensional array, a, and I am using a 2 dimensional array of indices, b , representing x/y coordinates. I have found something similar for a 1D array but I was unable to successfully apply it to a 2D array: Python - How to extract elements from an array based on an array of indices?
a = np.random.randn(10,7)
a = a.astype(int)
b = np.array([[1, 2], [2,3], [3,5], [2,7], [5,6]])
I have been using the bit of code below, however it returns a 3D matrix with values from the rows of each of the indices:
result2 = np.array(a)[b]
result2
Out[101]:
array([[[ 0, -1, 0, 0, 0, 1, 0],
[ 0, -1, 0, 0, 0, 0, 0]],
[[ 0, -1, 0, 0, 0, 0, 0],
[-1, 0, 0, 1, 0, 0, 0]],
[[-1, 0, 0, 1, 0, 0, 0],
[ 0, 0, -1, -2, 1, 0, 0]],
[[ 0, -1, 0, 0, 0, 0, 0],
[-1, 0, 0, 0, 0, 0, 1]],
[[ 0, 0, -1, -2, 1, 0, 0],
[ 1, 0, 0, 1, 0, -1, 0]]])
How can I modify b in order to index (column 1,row 2) ... (column 2, row 3)... (column 3, row 5) ... etc?
...
This is a minimal reproducible example and my actual data involves me indexing 500 cells in a 100x100 matrix (using an array of x/y coordinates/indices, size (500x2), similar to the above b). Would it be best to use a for loop in this case? Something along the lines of ...
for i in b:
for j in b:
result2 = np.array(a)[i,j]
I've encountered the same issue not long ago, and the answer is actually quite simple :
result = a[b[:,0], b[:,1]]

Multiply all pairs of rows in a Numpy array [duplicate]

This question already has an answer here:
How to compute the outer product of two matrices in numpy?
(1 answer)
Closed 4 years ago.
I have an MxN Numpy array. I'd like to take each row of the array and multiply it element-wise by each row of the array, resulting in an MxMxN numpy array of the products.
le_input = np.array([
[0, 0, 1],
[0, 1, 0]
])
le_expected_output = np.array([
[
[0, 0, 1],
[0, 0, 0]
],
[
[0, 0, 0],
[0, 1, 0]
]
])
I can of course do this with a for loop, and I've tried that, but I'm assuming there's a way faster way to do this within Numpy. Does anyone have any ideas?
You can use np.einsum:
np.einsum('ik,jk->ijk', le_input, le_input)
# array([[[0, 0, 1],
# [0, 0, 0]],
# [[0, 0, 0],
# [0, 1, 0]]])
Or create a new axis and use array's broadcasting property to calculate the outer product on the first dimension:
le_input[:,None] * le_input
# array([[[0, 0, 1],
# [0, 0, 0]],
# [[0, 0, 0],
# [0, 1, 0]]])

numpy roll along a single axis

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]])

Initializing an n-dimensional matrix elegantly in Python

There have been a couple questions on SO about how to initialize a 2-dimensional matrix, with the answer being something like this:
matrix = [[0 for x in range(10)] for x in range(10)]
Is there any way to generalize this to n dimensions without using for blocks or writing out a really long nested list comprehension?
As integers are immutable you can reduce your code to:
matrix = [[0] * 10 for x in range(10)]
As #iCodez mentioned in comments if NumPy is an option you can simply do:
import numpy as np
matrix = np.zeros((10, 10))
If you really want a matrix, np.zeros and np.ones can quickly create such a 2 dimensional array for instantiating a matrix:
import numpy as np
my_matrix = np.matrix(np.zeros((10,10)))
To generalize to n dimensions, you can't use a matrix, which by definition is 2 dimensional:
n_dimensions = 3
width = 10
n_dimensional_array = np.ones((width,) * n_dimensions)
#brian-putman was faster and better... anyway, this is my solution:
init = lambda x, y: [init(x, y-1) if y>1 else 0 for _ in xrange(x)]
that generates only square matrices of size x filled with zeroes in y dimensions. called like this
init(5, 3)
[[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]]
I agree that if numpy is an option, it's a much easier way to work with matrices. I highly recommend it.
That being said, this recursive function is a reasonable way to generalize your code to n dimensions. The first parameter is a list or tuple specifying how large each dimension should be (and, indirectly, how many dimensions). The second parameter is the constant value to fill the matrix with (in your example, 0):
def init(sizes, value=0):
if (len(sizes) == 1):
return [value] * sizes[0]
else:
# old code - fixed per comment. This method does not create
# sizes[0] *new* lists, it just repeats the same list
# sizes[0] times. This causes unexpected behavior when you
# try to set an item in a list and all of its siblings get
# the same change
# return [init(sizes[1:], value)] * sizes[0]
# this method works better; it creates a new list each time through
return [init(sizes[1:], value) for i in xrange(sizes[0])]
matrix = init((2,3,4), 5)
matrix[0][0][0] = 100 # setting value per request in comment
print matrix
>>> [[[100, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]], [[5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]]]
N-dimensional arrays are a little hard to print on a 2D screen, but you can see the structure of matrix a little more easily in the snippet below which I manually indented. It's an array of length 2, containing arrays of length 3, containing arrays of length 4, where every value is set to 5:
[
[
[100, 5, 5, 5],
[5, 5, 5, 5],
[5, 5, 5, 5]
],
[
[5, 5, 5, 5],
[5, 5, 5, 5],
[5, 5, 5, 5]
]
]

Categories

Resources