Iterating over an numpy.ndarray along an axis - python-3.x

Suppose I have a 3D array arr. I want to iterate over arr in such a way that each iteration yields a vector along z-axis. This can be done but the solution is not generalized. If the arr.shape and the axis along which the vectors have to be obtained are not known or variable then there seems no straight forward way to do this. Can anyone provide a solution to this?
for line in np.nditer(arr, axis=2):
# Perform operation on line
arr = array(
[[[2, 2, 8, 8],
[6, 2, 1, 5],
[4, 5, 1, 4]],
[[7, 4, 7, 4],
[0, 0, 3, 3],
[7, 6, 8, 0]]]
)
Expected output:
[2 2 8 8]
[6 2 1 5]
[4 5 1 4]
[7 4 7 4]
[0 0 3 3]
[7 6 8 0]

In numpy arrays the shape provides you information about # dimensions and # elements in each of the dimensions. with your code we get,
print(arr.shape)
# (2,3,4)
# 3-D array
# along x-axis = 2 elements each
# along y-axis = 3 elements each
# along z-axis = 4 elements each
So, If i want to look at elements along z-axis for all x-axis and y-axis it will look like
for xid in range(arr.shape[0]): # for each x-axis
for yid in range(arr.shape[1]): # for each y-axis
print(arr[xid, yid, :]) # All elements in z-axis

Writing the suggestions of #hpaulj into an answer.
moveaxis seems to be right answer. However apply_along_axis is intuitive and also very easy to use.

Related

I am having trouble multiplying two matrices with numpy

I am trying to use numpy to multiply two matrices:
import numpy as np
A = np.array([[1, 3, 2], [4, 0, 1]])
B = np.array([[1, 0, 5], [3, 1, 2]])
I tested the process and ran the calculations manually, utilizing the formula for matrix multiplications. So, in this case, I would first multiply [1, 0, 5] x A, which resulted in [11, 9] and then multiply [3, 1, 2] x B, which resulted in [10, 14]. Finally, the product of this multiplication is [[11, 9], [10, 14]]
nevertheless, when I use numpy to multiply these matrices, I am getting an error:
ValueError: shapes (2,3) and (2,3) not aligned: 3 (dim 1) != 2 (dim 0)
Is there a way to do this with python, successfully?
Read the docs on matrix multiplication in numpy, specifically on behaviours.
The behavior depends on the arguments in the following way.
If both arguments are 2-D they are multiplied like conventional
matrices. If either argument is N-D, N > 2, it is treated as a stack
of matrices residing in the last two indexes and broadcast
accordingly. If the first argument is 1-D, it is promoted to a matrix
by prepending a 1 to its dimensions. After matrix multiplication the
prepended 1 is removed. If the second argument is 1-D, it is promoted
to a matrix by appending a 1 to its dimensions. After matrix
multiplication the appended 1 is removed.
to get your output, try transposing one before multiplying?
c=np.matmul(A,B.transpose())
array([[11, 10],
[ 9, 14]])

numpy 1D array: identify pairs of elements that sum to 0

My code generates numpy 1D arrays of integers. Here's an example.
arr = np.array([-8, 7, -5, 2, -7, 8, -6, 3, 5])
There are two steps I need to take with this array, but I'm new enough at Python that I'm at a loss how do this efficiently. The two steps are:
a) Identify the 1st element of pairs having sum == 0. For arr, we have (-8, 7, -5).
b) Now I need to find the difference in indices for each of the pairs identified in a).
The difference in indices for (-8,8) is 5, for (7,-7) is 3,
and for (-5,5) is 6.
Ideally, the output could be a 2D array, something like:
[[-8, 5],
[ 7, 3],
[-5, 6]]
Thank you for any assistance.
Here is my solution:
arr = np.array([-8, 7, -5, 2, -7, 8, -6, 3, 5])
output = list()
for i in range(len(arr)):
for j in range(len(arr)-i):
if arr[i] + arr[i+j] == 0:
output.append([arr[i],j])
print(output)
[[-8, 5], [7, 3], [-5, 6]]
I have two comments also:
1) You can transfer the list to the numpy array by np.asarray(output)
2) Imagine you have list [8, -8, -8]. If you want to calculate distance of the first pair only, you can simply add break after the appending procedure.

Returning the N largest values' indices in a multidimensional array (can find solutions for one dimension but not multi-dimension)

I have a numpy array X, and I'd like to return another array Y whose entries are the indices of the n largest values of X i.e. suppose I have:
a =np.array[[1, 3, 5], [4, 5 ,6], [9, 1, 7]]
then say, if I want the first 5 "maxs"'s indices-here 9, 7 , 6 , 5, 5 are the maxs, and their indices are:
b=np.array[[2, 0], [2 2], [ 2 1], [1 1], [0 , 2])
I've been able to find some solutions and make this work for a one dimensional array like
c=np.array[1, 2, 3, 4, 5, 6]:
def f(a,N):
return np.argsort(a)[::-1][:N]
But have not been able to generate something that works in more than one dimension. Thanks!
Approach #1
Get the argsort indices on its flattened version and select the last N indices. Then, get the corresponding row and column indices -
N = 5
idx = np.argsort(a.ravel())[-N:][::-1] #single slicing: `[:N-2:-1]`
topN_val = a.ravel()[idx]
row_col = np.c_[np.unravel_index(idx, a.shape)]
Sample run -
# Input array
In [39]: a = np.array([[1,3,5],[4,5,6],[9,1,7]])
In [40]: N = 5
...: idx = np.argsort(a.ravel())[-N:][::-1]
...: topN_val = a.ravel()[idx]
...: row_col = np.c_[np.unravel_index(idx, a.shape)]
...:
In [41]: topN_val
Out[41]: array([9, 7, 6, 5, 5])
In [42]: row_col
Out[42]:
array([[2, 0],
[2, 2],
[1, 2],
[1, 1],
[0, 2]])
Approach #2
For performance, we can use np.argpartition to get top N indices without keeping sorted order, like so -
idx0 = np.argpartition(a.ravel(), -N)[-N:]
To get the sorted order, we need one more round of argsort -
idx = idx0[a.ravel()[idx0].argsort()][::-1]

Splitting integers 8 --> [1,7],[2,6]

I'm looking to make a function where I take an integer greater than 3 and show different ways you can add the number. For example 6 would turn into [[1,5],[2,4]] and not including [3,3]. 3 would turn into [[1,2]]. 8 would turn into [[1,7],[2,6],[3,5]] and not including [4,4]
My attempt thus far.
def split(k):
values = []
for i in range(k//2):
values.append([i+1,k-1-i])
print(values)
Running into issues where it is showing the [3,3] and [4,4]. Not sure about the logic behind this one.
You want to use math.ceil to account for odd numbers and just round up after float division.
from math import ceil
def split(k):
return [[i, k-i] for i in range(1, ceil(k/2))]
So in the case of 9, range will generate values 1 - 5 excluding 5, 1, 2, 3, 4 and then just subtract those from 9 to form the pairs.
You can also provide range a start value of 1 to ignore zeros.
# Output
>>> split(3)
[[1, 2]]
>>> split(8)
[[1, 7], [2, 6], [3, 5]]
>>> split(9)
[[1, 8], [2, 7], [3, 6], [4, 5]]

python numpy stack matrices and add specific corner/column entries

Say we have two matrices A and B with a size of 2 by 2. Is there a command that can stack them horizontally and add A[:,1] to B[:,0] so that the resulting matrix C is 2 by 3, with C[:,0] = A[:,0], C[:,1] = A[:,1] + B[:,0], C[:,2] = B[:,1]. One step further, stacking them on diagonal so that C[0:2,0:2] = A, C[1:2,1:2] = B, C[1,1] = A[1,1] + B[0,0]. C is 3 by 3 in this case. Hard coding this routine is not hard, but I'm just curious since MATLAB has a similar function if my memory serves me well.
A straight forward approach is to copy or add the two arrays to a target:
In [882]: A=np.arange(4).reshape(2,2)
In [883]: C=np.zeros((2,3),int)
In [884]: C[:,:-1]=A
In [885]: C[:,1:]+=A # or B
In [886]: C
Out[886]:
array([[0, 1, 1],
[2, 5, 3]])
Another approach is to to pad A at the end, pad B at the start, and sum; while there is a convenient pad function, it won't be any faster.
And for the diagonal
In [887]: C=np.zeros((3,3),int)
In [888]: C[:-1,:-1]=A
In [889]: C[1:,1:]+=A
In [890]: C
Out[890]:
array([[0, 1, 0],
[2, 3, 1],
[0, 2, 3]])
Again the 2 arrays could be pad and added.
I'm not aware of any specialized function to do this; even if there were, it probably would do the same thing. This isn't a common enough operation to justify a compiled version.
I have built up finite element sparse matrices by adding over lapping element matrices. The sparse formats for both MATLAB and scipy facilitate this (duplicate coordinates are summed).
============
In [896]: np.pad(A,[[0,0],[0,1]],mode='constant')+np.pad(A,[[0,0],[1,0]],mode='
...: constant')
Out[896]:
array([[0, 1, 1],
[2, 5, 3]])
In [897]: np.pad(A,[[0,1],[0,1]],mode='constant')+np.pad(A,[[1,0],[1,0]],mode='
...: constant')
Out[897]:
array([[0, 1, 0],
[2, 3, 1],
[0, 2, 3]])
What's the special MATLAB code for doing this?
in Octave I found:
prepad(A,3,0,axis=2)+postpad(A,3,0,axis=2)

Resources