Using Numpy.where() with a function on each element - numpy

I have a rather complicated function, say:
def func(elem):
// blah blah blah
return True
// blah blah blah
return False
I wish to use the numpy.where() function along the lines of
arr2 = np.where(func(arr1), arr1, 0)
But when I try this syntax and debug, I see that in func, that the entire array is passed rather than individual elements. The typical use cases I see in the documentation/examples only rely on simple comparators like arr < 5, but I need something quite a bit fancier that I don't want to try and write in a single line.
If this is possible, or if there is some vectorized substitute (emphasis on efficiency), any insights appreciated.

I figured out how to do it by using np.vectorize, followed by a list comprehension, not np.where. Maybe from this, one can find out a way to use numpy rather than of a list comprehension.
func_vec = np.vectorize(func)
[arr1 if cond else 0 for cond in func_vec(arr1)]
Anyways, by using func_vec(arr1) you get the True/False values per element.
Note: If you want a new array like arr1, replacing by 0 the elements that return False in your function, then this should work:
arr2 = np.where(func_vec(arr1), arr1, 0)
Edit:
Indeed, np.vectorize is not optimized to performance (by bad), is essentially a for loop under the hood. So I would recommend trying to write your function in a vectorized way rather than trying to vectorize it thereafter.
For example, try converting a function like this:
def func(elem):
if elem > 5:
return True
else:
return False
to something like this:
def func(elem):
return elem > 5
so that you can easily apply func(arr1) without error.
If you really have a function that returns just True or False, I'm pretty sure you can do it, regardless of its complexity. Anyways we're here to help you out!

It seems like you try to get the elements of arr1 you want using func function, but judging from the definition func works for a single element. You need a True/False array of the same shape as arr1 to do so.
If I get it right, a potential solution would be to modify func to operate on the whole array and not only on one element and return the True/False array of shape arr1.shape you need for np.where, since you want to do it in a single line that way.

Related

Can anyone tell me what's wrong with my code (I am a newbie in programming, pls do cooperate )

I am trying to write a code which calculates the HCF of two numbers but I am either getting a error or an empty list as my answer
I was expecting the HCF, My idea was to get the factors of the 2 given numbers and then find the common amongst them then take the max out of that
For future reference, do not attach screenshots. Instead, copy your code and put it into a code block because stack overflow supports code blocks. To start a code block, write three tildes like ``` and to end it write three more tildes to close. If you add a language name like python, or javascript after the first three tildes, syntax highlighting will be enabled. I would also create a more descriptive title that more accurately describes the problem at hand. It would look like so:
Title: How to print from 1-99 in python?
for i in range(1,100):
print(i)
To answer your question, it seems that your HCF list is empty, and the python max function expects the argument to the function to not to be empty (the 'arg' is the HCF list). From inspection of your code, this is because the two if conditions that need to be satisfied before anything is added to HCF is never satisfied.
So it could be that hcf2[x] is not in hcf and hcf[x] is not in hcf[x] 2.
What I would do is extract the logic for the finding of the factors of each number to a function, then use built in python functions to find the common elements between the lists. Like so:
num1 = int(input("Num 1:")) # inputs
num2 = int(input("Num 2:")) # inputs
numberOneFactors = []
numberTwoFactors = []
commonFactors = []
# defining a function that finds the factors and returns it as a list
def findFactors(number):
temp = []
for i in range(1, number+1):
if number%i==0:
temp.append(i)
return temp
numberOneFactors = findFactors(num1) # populating factors 1 list
numberTwoFactors = findFactors(num2) # populating factors 2 list
# to find common factors we can use the inbuilt python set functions.
commonFactors = list(set(numberOneFactors).intersection(numberTwoFactors))
# the intersection method finds the common elements in a set.

Finding smallest dtype to safely cast an array to

Let's say I want to find the smallest data type I can safely cast this array to, to save it as efficiently as possible. (The expected output is int8.)
arr = np.array([-101,125,6], dtype=np.int64)
The most logical solution seems something like
np.min_scalar_type(arr) # dtype('int64')
but that function doesn't work as expected for arrays. It just returns their original data type.
The next thing I tried is this:
np.promote_types(np.min_scalar_type(arr.min()), np.min_scalar_type(arr.max())) # dtype('int16')
but that still doesn't output the smallest possible data type.
What's a good way to achieve this?
Here's a working solution I wrote. It will only work for integers.
def smallest_dtype(arr):
arr_min = arr.min()
arr_max = arr.max()
for dtype_str in ["u1", "i1", "u2", "i2", "u4", "i4", "u8", "i8"]:
if (arr_min >= np.iinfo(np.dtype(dtype_str)).min) and (arr_max <= np.iinfo(np.dtype(dtype_str)).max):
return np.dtype(dtype_str)
This is close to your initial idea:
np.result_type(np.min_scalar_type(arr.min()), arr.max())
It will take the signed int8 from arr.min() if arr.max() fits inside of it.

What is the syntax to instantiate a structured dtype in numpy?

If I have a dtype like
foo = dtype([('chrom1', '<f4', (100,)), ('chrom2', '<f4', (13,))])
How can I create an instance of that dtype, as a scalar.
Background, in case There's A Better Way:
I want to efficiently represent arrays of scalars mapping directly to the bases in a genome, chromosome by chromosome. I don't want arrays of these genomic arrays, each one is simply a structured set of scalars that I want to reference by name/position, and be able to add/subtract/etc.
It appears that dtype.type() is maybe the path forward, but I haven't found useful documentation for correctly calling this function yet.
So suppose I have:
chrom1_array = numpy.arange(100)
chrom2_array = numpy.arange(13)
genomic_array = foo.type([chrom1_array, chrom2_array])
That last line isn't right, but hopefully it conveys what I'm currently attempting.
Is this a horrible idea? If so, what's the right idea? If not, what's the correct way to implement it?
This sort of works, but is terrible:
bar = np.zeros(1, dtype=[('chrom1', 'f4', 100), ('chrom2', 'f4', 13)])[0]
try this:
foo = np.dtype([('chrom1', '<f4', (100,)), ('chrom2', '<f4', (13,))])
t = np.zeros((), dtype=foo)

When does = perform comparison instead of assignment?

In VB.NET, there's no == operator for comparison, so the = operator serves that purpose as well as assignment. I have a function, and I want it to return the boolean result of a comparison, without storing that result in a variable:
Private Function foo() As Boolean
Dim bar As Integer = 1
Return bar = 2
End Function
Returns: False
OK, but what's the value of bar?
Private Function foo() As KeyValuePair(Of Boolean, Integer)
Dim bar As Integer = 1
Return New KeyValuePair(Of Boolean, Integer)(bar = 2, bar)
End Function
Returns: False, 1
It looks like = will perform a comparison when the statement context demands it, but is this guaranteed? That is, can I be sure that bar will never be set to 2 in this situation?
Also, I know that VB.NET doesn't allow chained inline assignments, which may be for the best. Does this odd = behavior cause any other quirks I should be aware of?
You cannot do in-line assignments in VB, Assignment is an explicit statement:
[Let] <<target-reference>> = <<value-expression>>
The Let is optional and implicit, and hardly ever used anymore. The general rule that you can use to distinguish the [Let] command from equality testing is that for Let, no other keyword may come before the target-reference in the statement. AFAIK, in all cases of = as equality testing, there is one or more other keywords that precede it in the statement.
In your first example, the keyword Return precedes your =, so it's an equality test, and not an assignment.
In your first example you can do either:
Return 2
or
bar = 2
Return bar
As for your question "OK, but what's the value of bar?", bar still equals one.
= in VB cause no quirks. It works exactly as documented, and it always has (including its predecessor, BASIC back to 1968).
If you are starting to code in VB (coming from a language like C#), you should start getting used to the peculiar VB way of doing things; which is based on the idea: as simple and intuitive for the programmer as possible. "If assignation and comparison happen always in different contexts, why not using the same operator and let the context define its exact meaning?" -> VB-way of seeing things. "No, different realities have to be accounted for by different operators. End of the discussion" -> C#-way. :)
Is this reliable? Can you blindly trust on these not-always-clear-for-a-programmer bits? Sure, VB.NET peculiarities are highly-reliable and trustworthy. You can always use = (or Is on some contexts, but VS would tell you) and be completely sure that the code will do what is expected. But the question is: are you sure that you write exactly what you want?
This last question is what, perhaps, is more criticable of VB and what might give some problems to programmers from other languages: the higher the flexibility, the more likely is that you make an error; mainly if you are used to a different format.
Regarding the chained inline assignments, I honestly don't see its true utility (and never use them in C#). Regarding other differences with respect to C#, there are plenty of them; in some cases, I think that the C# approach is better; other times, the VB.NET one. On readability/length of code, I can refer to the With Statement I have always found somehow useful which is not present in C#.
One way to have 100% sure that the expression will be evaluated as an boolean expression is to use ()
e.g
Dim a = 2
Return (a = 1)
Since you cannot set a value to a variable wihtin the parenthesis.
What i want to say is: on an return statament for example you cant assing a value to a variable so, even if you use
a = 1
The compilator knows that this expression only can be an boolean expression.
The same to the if statament and so on..
Heh back in QB45 days we used to exploit the fact that "True" was the numeric value -1. So you would see code like x = 1 - x * (x < 6) (translation: increment x, but reset to 1 when it gets to 6)

Passing values from function to function in JES/Jython

I am learning Jython using a program called JES, and I am having trouble understanding how to return values from a function that can be used in another function.
For example:
def driver():
picture = makePicture(pickAFile())
input(picture)
changeRed(picture, reduceRedAmount)
def input(picture):
redReduceAmount = requestInteger("How much should I reduce red by?")
return redReduceAmount
def changeRed(picture, reduceRedAmount):
for p in getPixels(picture):
value=getRed(p)
setRed(p,value*0.9)
I want to be able to just run the driver function in the command area, and have that function include the other functions. I understand that results in functions are local and don't pass through, but I though that if you use 'return' then it stores that value for later use. Am I on the wrong track here? Surely there is a way to pass information between functions?
Try this:
Any "-" just disregard them that is not part of the code, they are just there for spacing to help so that you don't get any syntax errors.
def driver():
picture = makePicture(pickAFile())
input(picture)
changeRed(picture, reduceRedAmount)
repaint(picture)`
or
def changeRed(picture, reduceRedAmount):
for p in getPixels(picture):
value=getRed(p)
setRed(p,value*0.9)
repaint(picture)
or
def changeRed(picture, reduceRedAmount):
for p in getPixels(picture):
value=getRed(p)
setRed(p,value*0.9)
show(picture)
or
def changeRed(picture, reduceRedAmount):
for p in getPixels(picture):
value=getRed(p)
setRed(p,value*0.9)
return(picture)`
One of those repaint, return, show should work to display the new image.
To display other values in command area just use "print something here" for example print 1+1 or print value.
the way I do it is declare it as a global variable the line after the def functionName() and at the LAST line of the functionName() code before you reduce the indent, type return variableNameYouWant.
check this:
def functionName()
global variableNameYouWant
..
..
return variableNameYouWant
What we are doing by following this is declaring the function you want to be a global variable (which must be done before it is delcared with a value, so best to do at the start of the def.) and then before you close the def by decreasing indentation, return the variable outside of the def.
I know it's an old question but I'm striving for upvotes as a newbie. :)
Edit: Thanks for the downvote, anon.