Python repeating a function using the result of the previous function - python

I am a bit new to python and have been searching and trying different solutions to this issue.
I need to create a function that not only counts down within the function but also adds the previous results.
To help put this in context:
I have a formula for a weekly cost where Time corresponds to the current time within the model. It looks like the following:
week1 = 5000**((Time-1))
week2 = 5000**((Time-2))
...
(where the number next to time is increasing by one over a specific range)
Now the end result needs to be (for example)
if Time > 5:
return week1+ week2+ week3+ week4+ week5
elif Time == 5:
return week1+ week2+ week3+ week4
This would continue to time <=1. So I need a formula where not only is the function repeated a specific number of times adding the previous result, but one of the variables in the formula also changes based on the count. I know there must be an efficient way to do this with a loop but I can not seem to figure it out.
Any help would be amazing!
Thanks!

One way of solving this problem is using recursion. Put simply, it is a function that will continue to call itself until a specific condition is met (time <=1 in this example).
The downside of doing this is that it uses more memory than a simple loop.
An example of this would be:
def funcName(time):
sum = 0
if (time > 1):
sum = funcName(time-1)
sum += 5000**(time-1)
return sum

I think, your formula is wrong, it should be:
week1 = 5000 * (Time-1)
With simple loop:
result = 0
for i in range(Time):
result += 5000 * (Time - i)
print result
You can achieve it in one line using both sum and generator expression.
result = sum(5000 *(Time - i) for i in range(Time))

Related

How to revise Monte Carlo Simulation code for Coupon Collector problem

The question I'm solving is if I receive 1/5 coupons at random a day, how many days will it take to collect 2 copies of each of the 5 coupons?
My code is only checking for 1 of each coupon instead of two but I'm not sure where I can make revisions. I edited the while True statement to include a list to my cards_own statement like this cards_own != [1,1,2,2,3,3,4,4,5,5] but then my output didn't print at all. I think maybe using the random.choice function would be a better option. Any recommendations?
import numpy as np
# number of simulations
n =10000
# defining function to check if we got all 5 cards indexed from 0 to 4
def all_cards(arr2,arr1=np.array(range(5))):
return np.array_equal(arr1,arr2)
days_taken = 0
# performing simulation
for i in range(n):
# initializing empty list to store card obtained in each day
cards_own =[]
# days taken in each simulation
days =1
# looping until i get 5 cards and count the days taken for finding average
while True:
value = np.random.randint(0,5)
cards_own.append(value)
if len(cards_own)>=5:
if all_cards(arr2=np.array(list(set(cards_own)))):
days_taken+=days
break
days+=1
average = days_taken/n
# recording the result in result with given precision
result = round(average,2)
print("Average days taken = ",result," days")
So there are a few things that I think you could change here. First off you can change your if statement to read if len(cards_own) >= 10 since you need at least ten coupons to have 2 of everything. Additionally, in your cards_all function, you can loop through all of the possible coupons (in this case [0, 4] and check if there are at least two occurences for each of them in the array (so you don't need arr2). Something like:
for i in range(5):
if np.sum(arr1 == i) < 2:
return False
return True
the if statement is just counting how many times the element i appears in the array. Also you should not be converting arr1 to a set in the function call since sets cannot have duplicate values so checking for 2 of each coupon would never work like that. Hopefully this helps!

Python/Numpy: Is there an efficient way to calculate moving averages with multiple windows?

Part of a program I'm writing has code that calculates the following:
data = np.array(..........)
param = np.array(range(100)+1)
result = np.array([data[-x:].mean() for x in param])
This code is used in a giant loop so performance is crucial. It shows that the 3rd line (result = ...) takes the most time of all - I wonder if there are better ways to do this operation?
Any suggestions are appreciated!
If you add 0 to the beginning of the array, and then create its cumulative sum using np.cumsum, then finding the average between indices i and j and just
(my_cumsum[j] - my_cumsum[i]) / (j - i).
This should let you vastly simplify your code.
I think you are looking for this:
data[::-1].cumsum()[:100]/np.arange(1,101)

Fast running average during data acquisition

I have a piece of code which iterates through a vector several times, performs some calculation, and averages the result into existing data. This calculation is based on other variables (eg time) as well as the input, so the same input has a different output and the total results cannot be pre-computed. This looks like this:
output = np.zeros(50)
while loop_count < max_loops:
for idx, dat in enumerate(vec):
val = calculate(dat)
averaged = (val + output[idx] * loop_count) / (1 + loop_count)
output[idx] = averaged
loop_count += 1
This works fine but appears to be quite slow (taking around 9s). Is there a better solution, ideally using numpy, scipy or pandas? The length of vec can be quite long so avoiding a copy is also ideal
You could just compute the sum and divide by max_loops in the end, right? This would make it one bit faster as you also could do the summation in-place:
output = np.zeros(50)
for idx, dat in enumerate(vec):
for count in range(max_loop):
output[idx] += calculate(dat)
output[idx] /= max_loop
As you provided a more abstract example (which is helpful), I am not sure whether this restructured version works for your application. If the computation in calculate is truly independent for the various repetitions, I don't see further simplification.

How can select samples with apply method without replacing in a loop

I would like to select "dmin" numbers of samples in each group(group by) in a dataframe and add them to another empty dataframe.
If total number of samples which we need is not enough, again select new "dmin" numbers of samples and add to the dataframe. This loop needs to be repeated until total number of samples we need is covered.
I am new in coding and can not understand the problem, but samples are selected just one time in my code and can not be repeated time by time in a group.
Another problem is that in each group of that dataframe, the number of records might go to be less than value of "dmin" in the loop and the code might face this problem "number of samples in the group is less than "dmin".
I was wondering if you could help me. This is part of my code:
while V > 0:
x6 = result_sort[result_sort['K'] > p_ratio].groupby('position').apply(lambda x:x.sample(dmin).reset_index(drop=True))
A = x6.append(A)
S = len(A)
V = V_total - S
I solved my problem with adding another condition in while loop.

Sensitivity Analysis solver python

I am solving for the sensitivity of a cashflow at a certain time period and to do that I want to take my code:
while count < (len(netcf)):
cpv = float(netcf[count]/((1+MARR)**(time[count])))
sum = round((sum+cpv),2)
count=count+1
print "Net Present Value = $", sum
This calculates the cashflow w/o sensitivity analysis and what I want to do is take certain time periods, say time 0 for simplicity's sake, and multiply the value times (1+x) and solve for the value of "x" so that when you add the new value to the sum of the other looped values, instead of the previous value (w/o 1+x) it brings the present worth as close to 0 as possible.
So far I have tried to utilize "while True" loops to solve for x but I have had no luck.. I am also having trouble keeping the loop from calculating the value w/o (1+x) and only using the value with (1+x) when added to the sum. Any suggestions at this point would be helpful as I've never solved for an unknown in python.
If you have a sum and you'd like to know which value to add to it in order to get zero, that's just -sum. Now, if you want the value of x for which (1 + x) == -sum, the solution is just x = -sum - 1.
EDIT: I get the feeling that isn't what you're trying to solve, though...
EDIT2: With regard to stopping the loop and then doing a second calculation, just use the break statement, e.g.:
stop_at = random.choice(range(len(netcf)))
while count < (len(netcf)):
cpv = float(netcf[count]/((1+MARR)**(time[count])))
sum = round((sum+cpv),2)
if count == stop_at:
break
count=count+1
print "Net Present Value = $", sum
# now do the second calculation ...

Categories

Resources