Finding more indices in a list close to zero - python-3.x

I have a list of values, which represents a damping function when this is plotted (so a form of a sinusoide). This function passes the y=0 thus several times until it levels out on y=0. I need to find the index at the moment when the function passes zero for the third time.
All values are floats, so I have a function that finds the index closest to zero:
def find_index(list_, value):
array = np.asarray(list_)
idx = (np.abs(array - value)).argmin()
return idx
Where 'list_' is the list and 'value' is zero.
This function does work, but it can only retrieve the index of the first moment the damping function (and thus the list) is closest to zero. Meaning that it will show an index of zero (because the damping function starts at zero). However, I need the index of the third time when it is closest to zero.
How can I obtain the index of the third time it will be closest to zero, instead of the first time?

You are looking for a change in the sign.
import numpy as np
x = np.array([10.0, 1.0, -1.0, -2.0, 1.0, 4.0])
y = np.sign(x) # -1 or 1
print(y)
>>> [ 1. 1. -1. -1. 1. 1.]
If you calculate the difference between consecutive elements using np.diff it will be either -2 or 2, both are boolean True.
>>> [ 0. -2. 0. 2. 0.]
Now get the indices of them using np.nonzero, which returns a tuple for each dimension. Pick the first one.
idx = np.nonzero(np.diff(y))[0]
print(idx)
>>> [1 3]

Related

The initializer parameter of reduce() on the sum of elements of an iterable

A query regarding this code:
from functools import reduce
def sum_even(it):
return reduce(lambda x, y: x + y if not y % 2 else x, it,0)
print(sum_even([1, 2, 3, 4]))
Why not adding the third parameter of reduce() adds the first odd element of the list?
If you don't pass an initial element explicitly, then the first two elements of the input become the arguments to the first call to the reducer, so x would be 1 and y would be 2. Since your test only excludes odd ys, not xs, the x gets preserved, and all future xs are sums based on that initial 1. Using 0 as an explicit initial value means only 0 and (later) the accumulated total of that 0 and other even numbers is ever passed as x, so an odd number is never passed as x.
Note that this is kind of a silly way to do this. It's much simpler to build this operation from parts, using one tool to filter to even, and another to sum the surviving elements from the filtering operation. For example:
def sum_even(it):
return sum(x for x in it if not x % 2)
is shorter, clearer, and (likely) faster than the reduce you wrote.

Output of a sum integer from a function that iteratively minimizes an arrary

I'm trying to build a function (minSum) to minimize the sum of an array, of various lengths and values over any number of iterations.
The function contains two arguments - the name of an array (num) and the number of steps of modification (k). For each k-step of modification, the function will retrieve an element/integer from the num array, divide it by 2, and update the array with the ceiling of the halved value in the same index position as it was retrieved. Once the k value has been reached, the function should output the sum of the array as a single integer.
For example - if my array (num) is [10. 20. 7] and I will run it over 2 steps (k) the input for the function would be minSum(num, 2).
It would divide 10 by half in kstep 0 resulting in an array of (5, 20, 7)
It would divide 10 by half in kstep 0 resulting in an array of (5, 10, 7)
It would divide 10 by half in kstep 0 resulting in an array of (5, 10, 4) (4 being the ceiling of 3.5).
The output of this would be the sum 0f 5, 10, 4 = 19. By increasing the k-value we should be able to reduce the output to a lower value. In any case, I'm able to use the below code to achieve my goal with the exception of the output being a single integer (our testing system system only receives the final array). Any pointers here? Thanks!
import array as ar
import math
import numpy as np
# 1. INTEGER_ARRAY num
# 2. INTEGER k (number of steps of element removal, transformation and update)
def minSum(num, k):
arr = np.array(num)
i = 0
idx = 0
while i < k:
for element in np.nditer(arr):
thereduced = math.ceil(element/2)
np.put(arr, [idx], thereduced)
if i < arr.size-1:
idx += 1
thesum = int((sum(arr)))
i = i+1
return thesum
The sum() method returns a single value, so you might create an empty array, put the "thesum" value into the array and at the end of the function return the new array with the values, right now your code is just returning a single integer

How to find max and min numbers in list within list

I am stuck at this question where I am required to update all largest and smallest numbers in the list with the average value as a way to remove the extreme values in the given list.
For example:
def remove_extreme( [ [0,4], [1,4], [-1,2] ] ) would return [ [0,1.5], [1,1.5], [1.5,2] ].
The function will need to use the average value to modify the elements in the lists, which, in this case the smallest and largest values are -1 and 4 respectively. Then, all the largest and smallest values present in the list need to be changed to the average(mean) of these two values, which is (4+-1)/2 = 1.5
Here's my code:
def remove_extreme(datalist):
for numlist in datalist:
for index, number in enumerate(numlist):
largest = max(number)
smallest = min(number)
average = (largest - smallest)/2
if number == largest or smallest:
num_list[index] = average
return datalist
May I know what went wrong? I keep getting 'int' object is not iterable.
What you asked about
To answer your immediate question, the built in functions max and min return for you the maximum and minimum number from an iterable.
https://docs.python.org/3/library/functions.html#max
So it throws a TypeError when you pass it an integer. Run it on a list/iterable instead.
But your code has more issues than just that.
Your if statement, though syntactically correct, is probably not what you want. More than likely you wanted to do this:
if number == largest or number == smallest:
Like Tomerikoo pointed out, you want to put your max and min outside the loop. As an aside, you do not need to return the list as lists are mutable and you are modifying it freely inside the function.
def remove_extreme(datalist):
for numlist in datalist:
largest = max(numlist)
smallest = min(numlist)
average = (largest - smallest)/2
for index, number in enumerate(numlist):
if number == largest or number == smallest:
numlist[index] = average
return datalist
What your problem is actually asking you
Looking at your original question I think you're a little off from the correct answer if your lists need to look like your given answer. The first hint is that your given answer shows only one of the values changed, and it's not always the average of the inner list. Take [0, 4] for instance. 1.5 is not the average of 0 and 4, yet that is what you say it should return. It seems that you are really desiring to change the most extreme number for each inner list based off the average of all the lists. Taking the average of the numbers of all the inner lists yields 1.66, so I'm not sure of this precisely, but I think one of your numbers might be off by 1 (I think so because 10/6 yields 1.66 while 9/6 yields 1.5).
If the above assumptions are all correct you will want to calculate the average (which is usually the sum/number of elements) and then find the most extreme element within each list.
Your function should look a bit more like this:
def remove_extreme(datalist):
# sum len of each list to get total number of elements
num_elements = sum([len(numlist) for numlist in datalist])
# sum the sum of each list to get total
sum_elements = sum([sum(numlist) for numlist in datalist])
# calculate average
average = sum_elements/num_elements
# find the most extreme element in each list and perform substitution
for numlist in datalist:
smallest = min(numlist)
largest = max(numlist)
large_diff = abs(largest - average)
small_diff = abs(average - smallest)
num_to_change = largest if large_diff > small_diff else smallest
for index, number in enumerate(numlist):
if number == num_to_change: # Just look at the most extreme number
numlist[index] = average
return datalist # list will be modified, but returning it doesn't hurt either
Running this function after changing your -1 to -2:
my_list = [
[0,4],
[1,4],
[-2,2]
]
print("Before: ", my_list)
remove_extreme(my_list)
print("After: ", my_list)
Output:
$ python remove_extreme.py
Before: [[0, 4], [1, 4], [-2, 2]]
After: [[0, 1.5], [1, 1.5], [1.5, 2]]
After further clarification
After clarifying what the question was really asking you, the answer is even simpler:
def remove_extreme(datalist):
flattened = [i for numlist in datalist for i in numlist] # flatten list for convenience
largest = max(flattened)
smallest = min(flattened)
average = (largest + smallest)/2
# find the most extreme element in each list and perform substitution
for numlist in datalist:
for index, number in enumerate(numlist):
if number == smallest or number == largest:
numlist[index] = average
return datalist # list will be modified, but returning it doesn't hurt either
Personally I feel like this makes less sense, but that seems to be what you're asking for.
Also, when writing a question, it's helpful to include the stack trace or point to the specific line where the issue is occurring. Just a helpful tip!
You are trying to get max and min of the element not of the list
>>> list = ( [ [0,4], [1,4], [-1,2] ] )
>>> max(list)
Output
[1, 4]
>>> min(list)
Output
[-1, 2]

kth-value per row in pytorch?

Given
import torch
A = torch.rand(9).view((3,3)) # tensor([[0.7455, 0.7736, 0.1772],\n[0.6646, 0.4191, 0.6602],\n[0.0818, 0.8079, 0.6424]])
k = torch.tensor([0,1,0])
A.kthvalue_vectoriezed(k) -> [0.1772,0.6602,0.0818]
Meaning I would like to operate on each column with a different k.
Not kthvalue nor topk offers such API.
Is there a vectorized way around that?
Remark - kth value is not the value in the kth index, but the kth smallest element. Pytorch docs
torch.kthvalue(input, k, dim=None, keepdim=False, out=None) -> (Tensor, LongTensor)
Returns a namedtuple (values, indices) where values is the k th smallest element of each row of the input tensor in the given dimension dim. And indices is the index location of each element found.
Assuming you don't need indices into original matrix (if you do, just use fancy indexing for the second return value as well) you could simply sort the values (by last index by default) and return appropriate values like so:
def kth_smallest(tensor, indices):
tensor_sorted, _ = torch.sort(tensor)
return tensor_sorted[torch.arange(len(indices)), indices]
And this test case gives you your desired values:
tensor = torch.tensor(
[[0.7455, 0.7736, 0.1772], [0.6646, 0.4191, 0.6602], [0.0818, 0.8079, 0.6424]]
)
print(kth_smallest(tensor, [0, 1, 0])) # -> [0.1772,0.6602,0.0818]

How to select a number from an array with given probability distribution

I want to select a number from a list with a given probability.
I use numpy and I have defined a list to choose from. I also have a probability distribution matching the entries of my list.
from numpy import random
a = [0, 1] # select one entry from this list
p = [0.0, 1.0] # probability distribution
print(random.choice(a, 1, p))
With the distribution p I should only receive 1. However, when I run my code, I receive 0 too often. I think my distribution doesn't really affect the selection.
From the documentation of numpy.random.choice:
choice(a, size=None, replace=True, p=None)
When you call choice(a, 1, p), the third positional argument p is used for the replace parameter1, not for the p parameter as you intend.
You either need to insert another positional argument for replace, so that p becomes the fourth positional argument:
choice(a, 1, True, p)
or explicitly pass p as a keyword argument:
choice(a, 1, p=p)
1 This works because a list can also be evaluated in a boolean context. In this case, [0.0, 1.0], as a non-empty list, would be evaluated as True.

Resources