Adding up formatted indexes with Numpy arrays Python - python

How can I write code that adds up all the numbers in between the indices? The arrays numbers and indices are correlated. The first two index values are 0-3 so the numbers between indices 0-3 are being added up 1 + 5 + 6 = 12. The expected value is what I am trying to find. I am trying to get the results without using a for loop.
numbers = np.array([1, 5, 6, 7, 4, 3, 6, 7, 11, 3, 4, 6, 2, 20]
indices = np.array([0, 3 , 7, 11])
Expected output:
[12, 41, 22]

I'm not sure how you got the expected output - from my calculation, the sum between the indices should be [12, 20, 25]. The following code calculates this:
numbers = np.array([1, 5, 6, 7, 4, 3, 6, 7, 11, 3, 4, 6, 2, 20])
indexes = np.array([0, 3, 7, 11])
tmp = np.zeros(len(numbers) + 1)
np.cumsum(numbers, out=tmp[1:])
result = np.diff(tmp[indexes])
The output of this is [12, 20, 25]
How does this work? It creates an array that is just one size larger than the numbers array (in order to have the first element be zero). Then it calculates the cumulative sum of the elements, starting at index 1 of the tmp array. Then, it takes the diff of the tmp array at the indices provided. As an example, it takes the different of the cumulative sum of the array from index 3 (value = 12) to index 7 (value = 32), 32-12 = 20.

You are likely looking for np.add.reduceat:
>>> np.add.reduceat(numbers, indices)
array([12, 20, 25, 28], dtype=int32)

Related

Find min value and index of the value in a matrix column after column

I have a problem, which seems to be easy but it is causing me a lot of headache.
The problem is that I'm programming in python (I'm relative new to it) and I'm looking for an aquivalent of the function max (min) of a matrix in matlab but using numpy.
What I want to do is to get the minimum value and its index in a matrix
Just to keep it as easiest as possible with an example, let's say this is the matrix:
arr2D = np.array([[11, 12, 13, 34],
[14, 15, 16, 3],
[17, 15, 11, 1],
[7, 5, 11, 4],
[1, 12, 4, 4],
[12, 14, 15,-3]])
in matlab I would do:
[local_max, index] = min(arr2D)
and I would get the min value and its index for every column in the matrix.
Trying to repeat the same in python (after looking here and here) with the following code:
print(np.where(arr2D == np.amin(arr2D, axis = 0))) # axis 0 is for columns
I get the following output:
(array([3, 4, 4, 5]), array([1, 0, 2, 3]))
which is not really what I want to get!
The expected output should be:
[1, 4] # Meaning the minimum value is 1 and it is in row 4 for the first column
[5, 3] # Meaning the minimum value is 5 and it is in row 3 for the second column
[4, 4] # Meaning the minimum value is 4 and it is in row 4 for the third column
[-3, 5] # Meaning the minimum value is -3 and it is in row 5 for the last column
I cannot use the output I get by:
print(np.where(arr2D == np.amin(arr2D, axis = 0)))
Or I don't understand the output or that's not the right way to get the aquivalent function max (min) of matlab.
Could you help me?
UPDATE:
I forgot to say that the matrix is float and not integer. I used integer just for the example
np.amin or np.min returns the min values along an axis
np.amin(arr2D, axis=0)
Out:
array([ 1, 5, 4, -3])
np.argmin returns the indices
np.argmin(arr2D, axis=0)
Out:
array([4, 3, 4, 5])
To get the desired output you can use np.vstack and transpose the array
np.vstack([np.amin(arr2D, axis=0), np.argmin(arr2D, axis=0)]).T
Out:
array([[ 1, 4],
[ 5, 3],
[ 4, 4],
[-3, 5]])
Use this code (you can simply make a function out of it):
import numpy as np
arr2D = np.array([[11, 12, 13, 34],
[14, 15, 16, 3],
[17, 15, 11, 1],
[7, 5, 11, 4],
[1, 12, 4, 4],
[12, 14, 15,-3]])
flat = arr2D.flatten()
arrayIndex = flat.tolist().index(min(flat))
// results
rowIndex = int(minIndex/arr2D.shape[0])
columnIndex = minIndex % arr2D.shape[1]

Fill matrix with random numbers within range?

I am new to programming and python. I am trying to create a matrix(6, 6) with random numbers within a certain range. Each number must be twice. Should I use matrix, multi dimensional array or list of lists? I'd like to know what is the easiest way to achieve this.
This is what I have right now:
rows = 6
columns = 6
range(0, 18)
matrix = [[0 for x in range(rows)] for y in range(columns)]
# Loop into matrix to fill with random numbers withing the range property.
# Matrix should have the same number twice.
for row in matrix:
print(row)
You could:
Generate a list of 36 numbers having each value of 0-17 twice as 2 * list(range(18))
Shuffle the list of numbers
Slice the list to equal chunks of 6
The result will be a matrix that meets your requirements, using only the standard library.
Something like this:
import random
nums = 2 * list(range(18))
random.shuffle(nums)
matrix = [nums[i:i+6] for i in range(0, 36, 6)]
Assuming you're looking for integers, it's as easy as this:
import numpy as np
import random
number_sample = list(range(18))*2 #Get two times numbers from 0 to 17
random.shuffle(number_sample) #Shuffle said numbers
np.array(number_sample).reshape(6,6) #Reshape into matrix
Output:
array([[ 1, 0, 5, 1, 8, 15],
[ 9, 3, 15, 17, 0, 14],
[ 7, 9, 11, 7, 16, 13],
[ 4, 10, 8, 12, 5, 6],
[ 6, 11, 4, 14, 3, 13],
[10, 16, 2, 17, 2, 12]])
Edit: Changed answer to reflect changes in your question

Slicing lists for getting just quarter of them in the same length

I have a list with lengths of A. Is there a way using slicing to take just every fourth value but maintaining it's length? For example, If this is my list:
A = [0,1,2,3,4,5,6,7,8....]
I want to use slicing to receive:
A = [0,0,0,0,4,4,...]
Using the [::4] is doing the job for the taking every fourth value, but without the other values I want.
If you have:
A = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Then you can do:
>>> [v for v in A[::4] for _ in range(4)]
[0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12]
>>>
I should mention that this rounds the result list length up to a multiple of 4, so you always get 4 of each value included in the result. If you want to drop the extra values at the end, you can append [:len(A)] to the end.
you could do :
A = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
repeatedA = [ A[(i//4) * 4 ] for i in range(len(A))]
the i//4 here allows to get the quotient of the division of the index by 4, then (i//4) * 4 allows us to find the closest multiple of 4 to i smaller than i, so here 1,2,3 are not dividors of 4 but 0 is , which is the closest multiple to them, it's the same with 5,6, and 7, 4 is the closest multiple ( given that it should always be smaller than either of them ), it's equivalent to i - i%4, which allows us to round i down to the closest dividor of 4 given that i = 4* (i//4 ) + 4%i
This code prints elements of A if their index residual from division by 4 equals 0.
Instead of i%4==0 you may enter i%4==1 or 2 or 3 if you need different offset.
A = [0,1,2,3,4,5,6,7,8,9,10,11,12]
print ([A[i] if i%4==0 else 0 for i in range (len(A))])
[0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 12]
If you want to repeat each fourth value 4 times, try this:
print ( [A[i//4*4] for i in range (len(A))])
[0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12]

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

Choosing and iterating specific sub-arrays in multidimensional arrays in Python

This is a question that comes from the post here Iterating and selecting a specific array from a multidimensional array in Python
In that post, user #Cleb solved what it was my original problem: how to perform a sum through columns in a 3d array:
import numpy as np
arra = np.arange(16).reshape(2, 2, 4)
which gives
array([[[0, 1, 2, 3],
[4, 5, 6, 7]],
[[8, 9, 10, 11],
[12, 13, 14, 15]]])
and the problem was how to perform the sum of columns in each matrix, i. e., 0 + 4, 1 + 5, ... , 8 + 12, ..., 11 + 15. It was solved by #Cleb.
Then I wondered how to do it in the case of a sum of 0 + 8, 1 + 9, ..., 4 + 12, ..., 7 + 15, (odd and even columns) which was also solved by #Cleb.
But then I wondered if there are a general idea (which can be modified in each specific case). Imagine you can add the first and the last rows and the center rows, in columns, separately, i. e., 0 + 12, 1 + 13, ..., 3 + 15, 4 + 8, 5 + 9, ..., 7 + 11.
Is there a general way? Thank you.
Depending on the how exactly arra is defined, you can shift your values appropriately using np.roll:
arra_mod = np.roll(arra, arra.shape[2])
arra_mod then looks as follows:
array([[[12, 13, 14, 15],
[ 0, 1, 2, 3]],
[[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]])
Now you can simply use the command from your previous question to get your desired output:
map(sum, arra_mod)
which gives you the desired output:
[array([12, 14, 16, 18]), array([12, 14, 16, 18])]
You can also use a list comprehension
[sum(ai) for ai in arra_mod]
which gives you the same output.
If you prefer one-liner, you can therefore simply do:
map(sum, np.roll(arra, arra.shape[2]))

Categories

Resources