Sensitivity Analysis solver python - 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 ...

Related

Python Function about Logistic Equation

The original logistic function that represents the change in population size per year is delta_N=r*(1-N/K)*N. I'm trying to write a new function that takes in r, K, N0 (The initial value of N, which stands for initial population size), and t (the number of years) and return the population N after t years. Below is my code. it does work but when I plug in t=0 (which is supposed to mean there is no change in time), it stills return some N that is different from N0 (which means my code is likely wrong?). Do people have any idea as to how I can fix my code?
def equation2(r,K,N0,t):
i=0
N=N0
while i<=t:
Nf=N+(r*(1-N/K)*N)
N=Nf
i=i+1
return Nf
I can see 2 potential problems with your code:
Plugging in t = 0 for your function will still go inside your while loop once because it will check for 0<=0 Which is true. You need to remove the = sign from your condition
After fixing this, Nf will be undefined when passing in t = 0. This also needs to be dealt with accordingly
def equation2(r,K,N0,t):
i=0
N=N0
while i<t:
N += (r*(1-N/K)*N)
i=i+1
return N

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!

create loop using values from an array

I have an array D of variable length,
I want to create a loop that performs a sum based on the value of D corresponding to the number of times looped
i.e. the 5th run through the loop would use the 5th value in my array.
My code is:
period = 63 # can be edited to an input() command for variable periods.
Mrgn_dec = .10 # decimal value of 10%, can be manipulated to produce a 10% increase/decrease
rtn_annual = np.arange(0.00,0.15,0.05) # creates an array ??? not sure if helpful
sig_annual = np.arange(0.01,0.31,0.01) #use .31 as python doesnt include the upper range value.
#functions for variables of daily return and risk.
rtn_daily = (1/252)*rtn_annual
sig_daily = (1/(np.sqrt(252)))*sig_annual
D=np.random.normal(size=period) # unsure of range to use for standard distribution
for i in range(period):
r=(rtn_daily+sig_daily*D)
I'm trying to make it so my for loop is multiplied by the value for D of each step.
So D has a random value for every value of period, where period represents a day.
So for the 8th day I want the loop value for r to be multiplied by the 8th value in my array, is there a way to select the specific value or not?
Does the numpy.cumprod command offer any help, I'm not sure how it works but it has been suggested to help the problem.
You can select element in an iterative object (such as D in your code) simply by choosing its index. Such as:
for i in range(period):
print D[i]
But in your code, rtn_daily and sig_daily are not in the same shape, I assume that you want to add sig_daily multiply by D[i] in each position of rtn. so try this:
# -*- coding:utf-8 -*-
import numpy as np
period = 63 # can be edited to an input() command for variable periods.
Mrgn_dec = .10 # decimal value of 10%, can be manipulated to produce a 10% increase/decrease
rtn_annual = np.repeat(np.arange(0.00,0.15,0.05), 31) # creates an array ??? not sure if helpful
sig_annual = np.repeat(np.arange(0.01,0.31,0.01), 3) #use .31 as python doesnt include the upper range value.
#functions for variables of daily return and risk.
rtn_daily = (float(1)/252)*rtn_annual
sig_daily = (1/(np.sqrt(252)))*sig_annual
D=np.random.normal(size=period) # unsure of range to use for standard distribution
print D
for i in range(period):
r=(rtn_daily[i]+sig_daily[i]*D[i])
print r
Last of all, if you are using python2, the division method is for integer, so that means 1/252 will give you zero as result.
a = 1/252 >-- 0
to solve this you may try to make it float:
rtn_daily = (float(1)/252)*rtn_annual
Right now, D is just a scalar.
I'd suggest reading https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.random.normal.html to learn about the parameters.
If you change it to:
D=np.random.normal(mean,stdev,period)
you will get a 1D array with period number of samples, where mean and stdev are your mean and standard deviation of the distribution. Then you change the loop to:
for i in range(period):
r=(rtn_daily+sig_daily*D[i])
EDIT: I don't know what I was thinking when I read the code the first time. It was a horribly bad read on my part.
Looking back at the code, a few things need to happen to make it work.
First:
rtn_annual = np.arange(0.00,0.15,0.05)
sig_annual = np.arange(0.01,0.31,0.01)
These two lines need to be fixed so that the dimensions of the resulting matricies are the same.
Then:
rtn_daily = (1/252)*rtn_annual
Needs to be changed so it doesn't zero everything out -- either change 1 to 1.0 or float(1)
Finally:
r=(rtn_daily+sig_daily*D)
needs to be changed to:
r=(rtn_daily+sig_daily*D[i])
I'm not really sure of the intent of the original code, but it appears as though the loop is unnecessary and you could just change the loop to:
r=(rtn_daily+sig_daily*D[day])
where day is the day you're trying to isolate.

Python repeating a function using the result of the previous function

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

PuLP: casting LpVariable or LpAffineExpression to integer

In my optimization problem, I have a conditional that the amount of items (LpInteger) in a particular group may not exceed a percentage of the total amount of items. To do that, I wrote the following code:
total = lpSum([num[i].varValue for i in ind])
for d in length:
# get list of items that satisfy the conditional
items_length_d = list(compress(items,[work[i]==work_group[d] for i in items]))
# use that list to calculate the amount of items in the group (an item can occur multiple times)
amount[d] = lpSum([num[dl] for dl in items_length_d])
max_d[d] = total*perc_max[d] + 1
min_d[d] = total*perc_min[d] - 1
prob += max_d[d] >= amount[d]
prob += min_d[d] <= amount[d]
The problem with this approach is that my maximum and minimum become floats (LpContinuous). This in turn makes the solution infeasible.
How can I make sure that each max_d and min_d values are integers? Preferably, I would also like to round up max_d, while truncating min_d.
Edit
I solved the problem of an infeasible solution by changing total = lpSum([num[i].varValue for i in ind]) to total = lpSum([num[i] for i in ind]). However, the minimum and maximum values are still floats. If someone knows how to convert these to ints, an answer would still be very appreciated.
You appear to misunderstand how constructing and solving an Linear Programming problem works.
The entire problem should be set up, then solved and the solution values extracted.
You can't get the LpVariable.varValue for a variable while setting up the problem.
So for a fractional constraint if we define an the group as i /in G and then define the total as i /in T
we get where f is the required fraction
if rearrange this equation.
so in your code
prob += perc_max[d] * lpSum([num[i] for i in ind]) <= lpSum([num[dl] for dl in items_length_d])

Categories

Resources