Apply a function to each element of an array in Python - python

I am trying to do two things in Python:
Simulate 100 random draws from a Poisson distribution. I have done this by:
sample100 = poisson.rvs(mu=5,size=100)
Take the above sample, and apply an UMP test I've generated to each individual observation (e.g., test the hypothesis against each individual observation). The test should accept the null hypothesis if the observation has a value < 8; reject with probability ~50% if observation has value = 8; reject if observation has value > 8
I cannot figure out how to do the second part of this. The function code I've made is:
def optionaltest(y,k,g):
if (y > k):
return 1
if (y == k):
if rand(uniform(0,1)) >= 0.4885: return 1
else: return 0
if (y < k):
return 0
But there are two issues - apparently if (y==k) is invalid syntax. Second, even if I remove that part, I can't actually apply the function to sample100 since it is an array.
How can I modify this to make it work? Clearly, I'm very new to Python but I have been scouring the internet for hours. Perhaps I should change how I'm generating my sample data so I can apply a function to it? Maybe there's a way to apply a function to each element of an array? How do I make the test logic work when the output = k (which I will set to 8 in this case)?
EDIT/UPDATE:
Here's how I ended up doing it:
def optionaltest(y):
if (y > 8):
return 1
if (y == 8):
if np.random.uniform(0,1) >= 0.4885: return 1
else: return 0
if (y < 8):
return 0
I was able to apply that test to my array data via:
results_sample100 = list(map(optimaltest, sample100))
cl.Counter(results_sample100)

This is invalid python syntax
if rand(uniform(0,1)) >= 0.4885 then 1
else 0
Instead, you could do this:
return 1 if rand(uniform(0,1)) >= 0.4885 else 0
You could also do something more verbose but potentially more straightforward (this is often a matter of taste), like this:
def optionaltest(y,k,g):
if (y > k):
return 1
if (y == k):
if rand(uniform(0,1)) >= 0.4885:
return 1
else:
return 0
if (y < k):
return 0
Or even like this:
def optionaltest(y,k,g):
if (y > k):
return 1
if (y == k) and rand(uniform(0,1)) >= 0.4885:
return 1
else:
return 0
For this question:
Maybe there's a way to apply a function to each element of an array?
You can use a for-loop or map a function over a list:
results = []
for elem in somelist:
results.append(my_function(elem))
Alternately:
results = list(map(my_function, somelist))
Your function takes three arguments, though, and it's not clear to me where those are coming from. Is your list a list of tuples?

syntax error is
in Python if condition then..else becomes
if condition:
pass
else:
pass

For applying function on your list's elements you can convert your list to a pandas dataframe. Then use apply function. For example if your list name is " data " and your function is "func" do this:
import pandas as pd
data = ['item_1', 'item_2', 'item_3']
df = pd.DataFrame (data, columns = ['column_name'])
result = df.apply(func)

Related

How to make this greedy function faster?

I am trying to solve a problem and my code fails at one test case where the list is of length 25000. Is there any way I can make this faster. I tried using functools.lru_cache and I still can not run within the time required to complete.
This is the problem from the site
Given an array of non-negative integers nums, you are initially
positioned at the first index of the array.
Each element in the array represents your maximum jump length at that
position.
Determine if you are able to reach the last index.
This is what I have tried
def can_jump(input_list):
#lru_cache
def helper(idx = 0):
if idx == len(input_list) - 1:
return True
return any(helper(new_idx) for x in range(input_list[idx]) \
if (new_idx := idx + x + 1) < len(input_list)) # increasing order of jumps
return helper()
Sample test cases work
input_list = [2,3,1,1,4]
print(can_jump(input_list)) # True
input_list = [3,2,1,0,4]
print(can_jump(input_list)) # False
I have also tried going from the other direction,
return any(helper(new_idx) for x in range(input_list[idx], 0, -1) \
if (new_idx := idx + x) < len(input_list)) # decreasing order of jumps
But I still can not make this run fast enough to clear the last test case of 25000 element list, what is it that I am doing wrong here?
Ok, I think I get it. Can you try this? Please note, this is taken straight from: https://codereview.stackexchange.com/questions/223612/jump-game-leetcode
def canjump(nums):
maximum_reachable_index = 0
for index, max_jump in enumerate(nums):
if index > maximum_reachable_index:
return False
maximum_reachable_index = max(index + max_jump, maximum_reachable_index)
return True

My python recursive function won't return and exceeds maximum recursive depth

I simply do not understand why this is not returning the value and stopping the recursion. I have tried everything but it seems to just keep on going no matter what I do. I am trying to get the program to get the loop to compare the first two values of the list if they are the same return that it was the first value. If they were not, add the first and second values of each list and compare, etc etc until it reaches the end of the list. If the sum of the values in each list never equal each other at any point then return 0.
It is supposed to take three inputs:
A single integer defining the length of the next two inputs
First set of input data
Second set of input data
Ex input
3
1 3 3
2 2 2
It should output a single number. In the case of the example data, it should output 2 because the sum of the lists equalled at the second value.
N = int(input())
s1 = input().split()
s2 = input().split()
count = 0
def func1(x,y):
if x == y:
return(count)
elif (N - 1) == count:
return(0)
else:
count + 1
return(func1(x + int(s1[count]), y + int(s2[count])))
days = func1(int(s1[0]),int(s2[0]))
print(days)
I am sorry in advance if I really messed up the formatting or made some dumb mistake, I am pretty new to programming and I have never posted on here before. Thanks in advance :)
The problem is that you never actually update the variable count. However, just writing:
count += 1
is not going to work either without declaring the variable global:
def func1(x, y):
global count
....
That said, global variables increase code complexity and break re-enterability, i.e. the same function can no longer be called twice, not to mention about concurrency. A much cleaner way is to make count a function argument, it will look like this (the code not tested and is here for illustration only):
N = int(input())
s1 = [int(c) for c in input().split()]
s2 = [int(c) for c in input().split()]
def func1(x, y, count=0):
if x == y:
return count
elif count == N - 1:
return 0
else:
return(func1(x + s1[count], y + s2[count]), count + 1)
days = func1(int(s1[0]),int(s2[0]))
print(days)
To answer "How would you go about solving this problem then" – If I understood the problem correctly, the aim is to find the index where the "running total" of the two lists is the same. If so,
def func1(s1, s2):
total_a = 0
total_b = 0
for i, (a, b) in enumerate(zip(s1, s2)):
total_a += a
total_b += b
if total_a == total_b:
return i
return 0
print(func1([1, 3, 3], [2, 2, 2]))
does the trick. (I've elided the input bits here – this function just works with two lists of integers.)

Adding every other integer from 0 to n (recursive func)

The function I am writing is meant to add every other integer from 0 to n. For example, if you inputted 6, you would get 12 because 6 + 4 + 2 + 0 = 12.
I was working with a list at first but realized I have to be working with integers instead. Below is my attempt, but I get TypeError: object of type 'int' has no len().
I'm confused as to how to fix this problem and make it a proper recursive function.
def addNum(n):
if len(n) == 0:
return 0
else:
return n[0] + addNum(n[::2])
print(addNum(6)) #example of how you would call the function
If you are looking to add just the alternating integers, it should be like
def addNum(n):
if n < 1 :
return 0
else:
return n + addNum(n-2)
print(addNum(6))
You pass an Integer to your function addnum, but you need a list. So you have to write addnum([6]) to create a list with the 6 as a single entry.
You have to call the function with the argument, reduced by 2 if you want to work without a list.
def addnum(n):
if n == 0:
return 0
else:
return n + addnum(n - 2)
print(addnum(6))
This gives the output 12.
so first of all the func len() is for lengths and you actually don't need that, what you need is a list comprehension. I assume that you don't know them so go and learn about them because they can help with these kinds of functions because they aren't that hard to write and are highly flexible.
The code below here does exactly what you want!
def addnum(n):
if n == 0:
return 0
else:
return sum([list for list in range(0,n+1,2)])
print(addnum(10))
first I create a function named addnum which has one parameter called n.
secondly I created the if else clauses, if the number is equal to 0 it returns 0. Else it returns the sum of every odd integer from 0 the the range. n+1 is here just to get the number you put in because the func range doesn't include the last value.

Logical expression in key of dictionary in Python

As a simplified example, say I have the following if statement
if x > 5:
score = 1
else if x <= 5
score = 2
How can I replace this with a dictionary? I want something like
score = {x > 5: 1, x <= 5: 2}[x]
My actual if statement is quite long, so I'd like to use this condensed construct.
Instead of a dictionary, you can use a list of tuples, where one item is a function and the other is a value. You loop through the list, calling each function; when the function returns a truthy value you return the corresponding value.
def greater_than_5(x):
return x > 5
def less_or_equal_5(x):
return x <= 5
scores = [(greater_than_5, 1), (less_or_equal_5, 2)]
for f, val in scores:
if f(x):
score = val
break
Using if-else will be the most readable solution. Also it avoids the problem that you would need an infinite amount of values to express something like x > 5 with a dictionary (as it will map all number starting from 6).
Only if you know that the domain is limited (e.g., x is always less than 1000), it will work. The simple if statement will most likely be faster.
To express ranges, you can use this short notation:
if 4 <= x <= 10:
...
If you have a very complicate formula (lots of if-else statements), and a limited number of values, using a precomputed table makes sense, though. This is what compilers also do if they have to translate complicated switch-case statements in C like languages when the values are dense. They implement it as a lookup table.
I would still recommend to start with writing the formula as if-else statements, and then use a function that computes the dictionary based on the if-else code and the range of possible values. To fill the dictionary, iterate over the range of possible values:
def score(x):
if x > 5:
return 1
elif x <= 5:
return 2
...
d = dict((i,foo(i)) for i in range(1,100))
d[x]

Why do I get a 'valueError' despite explicitly returning the expected number of values?

This is merge sort tweaked to count inversions. My code throws an odd error
(I'm implementing algos to learn python 3.x).
In line 11,
in merge_sort first_sorted_half, x = merge_sort(arr[:half])
[Previous line repeated 12 more times] ValueError: not enough values
to unpack (expected 2, got 1)
Even though I explicitly return two values? I'm new to python 3 so I'd like to understand exactly what's going on here, I can't seem to find a similar issue anywhere. A link to python docs for more on this would also be appreciated!
def merge_sort(arr):
if len(arr) <= 1:
return arr
half = int(len(arr)/2)
first_sorted_half, x = merge_sort(arr[:half])
second_sorted_half, y = merge_sort(arr[half:])
merged_halves, z = merge(first_sorted_half, second_sorted_half)
return merged_halves, x + y + z
def merge(first_half, second_half):
n = len(first_half) + len(second_half)
i = 0
j = 0
split_inversions = 0
ans = []
for k in range(n):
if i >= len(first_half):
ans.append(second_half[j])
j += 1
continue
if j >= len(second_half):
ans.append(first_half[i])
i += 1
continue
if first_half[i] > second_half[j]:
ans.append(second_half[j])
j += 1
split_inversions += len(first_half) - i
elif first_half[i] < second_half[j]:
ans.append(first_half[i])
i += 1
return ans, split_inversions
numbers = [3,2,1,4,5,6,8,10,9]
print(merge_sort(numbers))
The error you are getting says that your program executed that recursive call 12 times, and at the end it couldn't unpack the result.
What that means is, python expects you to return two values from merge_sort, because you unpack the result into first_sorted_half and x. However, when you return only arr from the condition len(arr) <=1, there is no value to unpack, only there exists the array.
So how you fix that is returning a value for the base case, like return arr, len(arr).
Whilst ilke444 is right - a bit more clarification is needed. To start: returning data variables is what you need but I do not know much about the len(arr) <=1 , and I am quite new to stackflow, I do not know this feature of Python 3. I specialize in Pygame/ standard packages.
First thing - arr in this "Code Snippet" (If it is) is not defined; and/or will need to be defined. Len stands for length as you know - and uses a quote (' ') to use it.
Like so:
len('arr')
would print:
3
because there are 3 Characters in this set. You are obviously new to python 3 as you said because the syntax is slightly different.
As this probably only solves the first bit - with this info I will leave you with 1 thing more.
Call to print requires a quote (' '),
Lists have [ ] Brackets instead of (),
Dictionaries have {} brackets and variables now require definition either by variable definition or function unless put in quote marks.
Thanks,
Jerry

Categories