How to assign an if statement's result into an equation? - python

I'm new to python and I have to run a program to get the correct interest rate based on user input and use the interest rate obtained to compute monthly interest earned.
For the computation of interest earned, I'm trying to use the print result to create a formula for calculating monthly interest earned. However, I've tried so many things and I'm not sure how to correct this.
transaction_category = [2000, 2500, 5000, 15000, 30000]
first_50k_1_category_rates = [0.05, 1.55, 1.85, 1.90, 2.00, 2.08]
if (count == 1) and (account_balance <= 50000) and (total_eligible_monthly_transactions < transaction_category[0]):
print(f'Interest rate applicable is: {first_50k_1_category_rates[0]: .2f}%')
if (count == 1) and (account_balance <= 50000) and (transaction_category[0] <= total_eligible_monthly_transactions < transaction_category[1]):
print(f'Interest rate applicable is: {first_50k_1_category_rates[1]: .2f}%')

Your question is rather unclear, but I guess you are looking for something like
if (count == 1) and (account_balance <= 50000) and (transaction_category[3] <= total_eligible_monthly_transactions < transaction_category[4]):
applicable_interest_rate = first_50k_1_category_rates[4]
elif (count == 1) and (account_balance <= 50000) and (total_eligible_monthly_transactions >= transaction_category[4]):
applicable_interest_rate = first_50k_1_category_rates[5]
print(f'Interest rate applicable is: {applicable_interest_rate: .2f}%')
This is just a sketch; you will have to make sure the new variable is always defined, then use that in your final equation instead.
Probably the repeated conditions should be refactored, too, so you don't compare the same things over and over.
if (count == 1) and (account_balance <= 50000):
if transaction_category[3] <= total_eligible_monthly_transactions < transaction_category[4]:
applicable_interest_rate = first_50k_1_category_rates[4]
elif total_eligible_monthly_transactions >= transaction_category[4]:
applicable_interest_rate = first_50k_1_category_rates[5]
but again, without seeing the complete script, it's not clear exactly how to refactor. This is just one example to illustrate the idea.

So you could do if/else in one code block, or turn those print statements into variables and return them. Both would say result as var name.
def foo(condition1, condition2):
if condition1 < condition2:
result = (1 + 1)
if 1 == False:
result = (1 - 1)
return result
print(foo(1, 2))
there’s better ways to do this in a more functional programming aspect like this: (lambda :f"b:{b}",lambda :f"a:{a}")[a>b](), but it seems this code style is imperative so stick w that.

If you are having trouble with scope, you can try this (safe) hack:
_scope = {
"applicable_interest_rate1": first_50k_1_category_rates[4],
"applicable_interest_rate2": first_50k_1_category_rates[5],
}
def foo(condition1, condition2):
if condition1 < condition2:
result = _scope["applicable_interest_rate1"]
if 1 == False:
result = _scope["applicable_interest_rate2"]
return result
print(foo(1, 2))

Related

is there a way to make a value non-negative in dataframe

I'm new to coding and I'm using python pandas to practice making an algo-trading bot. This is my code.
for date in BTCtest.index:
if BTCtest.loc[date,'Shares'] == 0:
BTCtest.loc[date,'Shares'] = max(0,-5)
if BTCtest.loc[date, 'MA10'] > BTCtest.loc[date, 'MA50']:
BTCtest.loc[date, 'Shares'] = 1
elif BTCtest.loc[date, 'MA10'] < BTCtest.loc[date, 'MA50']:
BTCtest.loc[date, 'Shares'] = -1
BTCtest['Position'] = BTCtest['Shares'].cumsum()
BTCtest['Close1'] = BTCtest['Close'].shift(-1)
BTCtest['Profit'] = [BTCtest.loc[date, 'Close1'] - BTCtest.loc[date, 'Close'] if BTCtest.loc[date, 'Shares']==1 else 0 for date in BTCtest.index]
BTCtest['Profit'].plot()
print (BTCtest)
plt.axhline(y=0, color='red')
This is my code and I'm trying to not add shares when the position is 0.
I tried
if BTCtest.loc[date,'Shares'] == 0:
BTCtest.loc[date,'Shares'] = 0
if BTCtest.loc[date,'Shares'] == 0:
max(BTCtest.loc[date,'Shares'],-1)
Below is the result so far.
enter image description here
I don't want my position to go below 0.
I don't understand your code, but I understand your title.
To convert negative values into positive, we can multiply it by '-1' if it is less than 0. So, write
numberr=int(input("Enter a number: "))
if numberr<0:
numberr*=-1
print(numberr)
Hope this helps.
You should use .apply function instead of iterating over index. It will really simplify your code and it is the best practice.
Additionally, if you want to operate only with no zero rows do this:
BTCtest[BTCtest['Position'] == 0].apply(myfunction, axis=1)

Loop code with: {x_(n+1) = x_n * r * (1- x_n)}

Little new here and any help would be appreciated.
I have been tooling around with this code for a while now and I cant seem to wrap my head around it. Im fairly new to python so I dont quite know or remember all the tricks yet/skills.
So the question at hand:
Equation: {x_(n+1) = x_n * r * (1- x_n)}
With x_n between (0,1) and r between (0,4).
The goal here is to make a loop function that will gather a value for 'x_n' and 'r' and spit out the iteration 'n' and the current 'x_n+1'; i.e. print(n , x_n+1), at each 'n' step while checking to see if the new value is within 0.0000001 of the old value.
If it settles on a fixed point within 20,000 (0.0000001), print the final 'n' + message. If not then and goes to 20,000 then print another message.
All i have so far is:
import math
x_o=float(input("Enter a 'seed' value: "))
r=float(input("Enter an 'r' value: "))
x_a=((x_o + 0) * r * (1-(x_o + 0)))
while x_a != (0.0000001, x_o , 0.0000001):
for n in range(0,99):
x_a=((x_o + n) * r * (1-(x_o + n)))
print(n , x_a)
I'm pretty sure this is no where close so any help would be awesome; if you need any more info let me know.
Much appreciated,
Genosphere
You could write a generator function and use it directly in your for loop. If you need to keep track of the rank of intermediate values you can use enumerate on the generator.
def fnIter(fn,x,delta=0.000001):
while True:
yield x
prev,x = x,fn(x)
if abs(x-prev)<delta:break
output:
r = 2
seed = 0.1
for i,Xn in enumerate(fnIter(lambda x:x*r*(1-x),seed)):
print(i,Xn)
0 0.1
1 0.18000000000000002
2 0.2952
3 0.41611392
4 0.4859262511644672
5 0.49960385918742867
6 0.49999968614491325
7 0.49999999999980305
To implement the maximum iteration check you can either add a conditional break in the loop or use zip with a range:
maxCount = 20000
n,Xn = max(zip(range(maxCount+1),fnIter(lambda x:x*r*(1-x),seed)))
if n < maxCount:
print(n,Xn)
else:
print(Xn,"not converging")
This is an exponentially-weighted moving average. Pandas has a function for this: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html
You have a good start so far. You might be overthinking it, though.
The following approach just tries to generate this sequence for 20,000 terms. Each time, it checks whether the new value is within 0.0000001 from the previous value. If so, it breaks out of the loop and prints that. If not, it uses python's for/else construct to print a different value. Note the different levels of indentation.
x_0 = float(input("enter a 'seed' value: "))
r = float(input("enter an 'r' value: "))
x_m = x_0 # placeholder for 'previous value'
delta = 0.0000001
# Try to calculate 20 thousand terms of this sequence
# We will break out of the loop early if our x_n converges
for _ in range(20000):
x_n = x_m * r * (1 - x_m)
if abs(x_n - x_m) < delta:
print("Settled on value for x_n: ", x_n)
break
else:
x_m = x_n # move forward to the next value
else:
print("x_n did not converge in 20000 terms")

Optimized way to find in which range does a number lie

I have multiple ranges lets say 1-1000, 1000-2000, 2000-3000, 3000-4000, 4000-5000. I get a number from the user and now i need to find in which range it lies. One way to do this would be to create multiple if statement and check from there like so:
if num>=1 and num < 1000:
print "1"
elif num >=1000 and num < 2000:
print "2"
....
This method would create a lot of branches.
Is there an optimized way to do this without so many branches and in the least complexity?
PS: I just wrote the code in python since its shorter to write but this can be case in any language. Also the range and output can be very different.
The range and output are examples and can be anything like 1-100, 100-1000, 1000-1500 etc and output like "Very Low, low, medium" something like that.
Store the starting or ending of the range in the list and sort it along with number to find its exact range.
import numpy as np
start = [1,1000,2000,3000,4000]
print(list(np.sort(start+[num])).index(num))
If your ranges don't follow any particular logic, there's not much you can do except testing them one by one, but you can still simplify the code by using a loop:
ranges = [[0,1000],[1500,1600],[1200,1220]]
def find_range(num, ranges)
for low, high in ranges:
if low <= num < high:
return low, high # or any other formating using a dict for example
Of course you can optimize a bit by sorting your ranges and then doing a binary search instead of linear...
my_range=(1,1000), (1000,2000), (2000,3000), (3000,4000), (4000,5000)
my_output='Very Low, Low, Medium, High, Very High'.split(', ')
num=3565
for k,i in enumerate(my_range):
if i[0]<=num<i[1]:print(my_output[k]);break
else:
print('Out of range')
How about something like this:
ranges = {
0: 'undefined range',
1000: '1',
1500: '2',
2500: '3'
}
num = 500
print(ranges[max(ranges, key=lambda x: num < x)])
Output: 1
Suspect that you have many breaks and require an optimized search, you can go with bisection on an ordered list of breakpoints resulting in a logarithmic time consumption:
import random
import time
def split_pivot(intervals, number):
"""Divide and conquer recursively."""
if len(intervals) == 1:
return intervals[0]
if len(intervals) == 2:
if number >= intervals[1][1][0]:
return intervals[1]
elif number < intervals[0][1][1]:
return intervals[0]
else:
raise
pivot = int(len(intervals) // 2.0)
if number < intervals[pivot][1][1]:
return split_pivot(intervals[:pivot + 1], number)
elif number >= intervals[pivot + 1][1][0]:
return split_pivot(intervals[pivot + 1:], number)
else:
raise
if __name__ == '__main__':
UPPER_BOUND = 10000000
newbreak = 0
manybreaks = []
while newbreak < UPPER_BOUND:
step = int(random.random() * 10) + 1
manybreaks.append(newbreak + step)
newbreak = manybreaks[-1]
print('Breaks: {:d}'.format(len(manybreaks)))
intervals = [
(idx, (manybreaks[idx], manybreaks[idx + 1]))
for idx in range(len(manybreaks) - 1)
]
print('Intervals: {:d}'.format(len(intervals)))
print(
' Example: idx {tpl[0]:d}, lower {tpl[1][0]:d}, upper {tpl[1][1]:d}'
.format(tpl=random.choice(intervals)))
thenumber = int(random.random() * UPPER_BOUND)
print('Number: {:d}'.format(thenumber))
t0 = time.time()
result = split_pivot(intervals, thenumber)
t1 = time.time()
print('Result: {e[0]:d} ({e[1][0]:d}, {e[1][1]:d})'.format(e=result))
print(' Done in {:.4f}s'.format(t1 - t0))
The result of the search itself is (on my machine) below 0.05 seconds. The generation of breakpoints and corresponding intervals runs for roughly 4.5 seconds:
Breaks: 1818199
Intervals: 1818198
Example: idx 605849, lower 3330441, upper 3330446
Number: 6951844
Result: 1263944 (6951843, 6951847)
Done in 0.0436s
maybe just divide by 1000 and take the entire part :
here example in python :
>>> x=3608
>>> int(x/1000+1)
4
Following your comment/edit in your post, if you need a different output (a string for example) you can (in python) use a dict :
>>> Output={'1': 'very low', '2': 'low', '3': 'medium','4':'high' }
>>> x=2954
>>> Output[str(int(x/1000+1))]
'medium'

When calling an array only the first element is used?

When calling QuarterlySales into the DetermineRate procedure it only uses the first number in the array every time the loop goes around. I think I have it indexed properly. Also it only prints out 9 numbers when it should print out 10.
def FillQuarterlySales(QuarterlySales):
#declare local variables
Index = 0
QuarterlySales = [0] * 10
#Loading the array
QuarterlySales = [21487, 22450, 7814, 12458, 4325, 9247, 18125, 5878, 16875, 10985]
#Determine the quarterly sales based on the index
return QuarterlySales
def DetermineRate(QuarterlySales):
#declare local variables
Rate = float()
Index = 0
Counter = 0
Rates = [Index] * 9
for Index in range (9):
if QuarterlySales[Counter] < 5000:
Rate = 0
elif QuarterlySales[Counter] < 10000:
Rate = 0.04
elif QuarterlySales[Counter] < 15000:
Rate = 0.08
elif QuarterlySales[Counter] < 20000:
Rate = 0.12
else:
Rate = 0.15
#end if
Rates[Index] = Rate
#end for
return Rates
There is no error code but when I print out rates to make sure they are correct the array is filled with the same number. This is happening anywhere I call QuarterlySales throughout the program as well.
It's because you use Counter to index QuarterlySales instead of Index.
But your question shows some inexperience with python, so let's try to address some other issues, too.
Rates = [Index] * 9
...
QuarterlySales = [0] * 10
This looks like you're trying to do allocation in advance, which is almost always unnecessary in python. Certainly for lists of only ten elements, it hurts more than it helps.
Instead do this:
Rates = []
...
QuarterlySales = []
and then just use the .append() method to add sequential data elements to the list.
For example:
def DetermineRate(QuarterlySales):
Rates = []
for sales in QuarterlySales:
if sales < 5000:
Rates.append(0.)
elif sales < 10000:
Rates.append(0.04)
elif sales < 15000:
Rates.append(0.08)
elif sales < 20000:
Rates.append(0.12)
else:
Rates.append(0.15)
return Rates

Summing the number of instances a string is generated in iteration

Working in python 2.7.
I'm trying to work my way up to plotting a random walk. But first I'm having some trouble summing the number of results I get from a random generator.
The first piece of code:
def random_pick(some_list, probabilities):
x = random.uniform(0,1)
cumulative_probability = 0.0
for item, item_probability in zip(some_list, probabilities):
cumulative_probability += item_probability
if x < cumulative_probability: break
return item
In this case, the list is a = ['Hit', 'Out'] and the respective probabilities are given by b = [.3, .7]. This code returns 'Hit' with probability .3 and 'Out' with probability .7.
I then have code to create a rough sim of a player's batting average based on those probabilities:
def battingAverage(atBats, i, some_list=a, probabilities=b):
for i in range(1,atBats):
if random_pick(a, b) == 'Hit':
hit = random_pick(a, b)
print '%.0f: %s' % (1, 'Hit')
elif random_pick(a, b) == 'Out':
out = random_pick(a, b)
print '%.0f: %s' % (2, 'Out')
When I run this, I get a random generation of as many at-bats as a I choose. But I would like to be able to then sum the number of instances or both hit and out, but I have not been able to figure out how. I've tried to use code similar to below after changing the random_pick to return the probability instead of the item, but to no avail.
def battingAverage(atBats, i, some_list=a, probabilities=b):
num_hits = 0
num_outs = 0
for i in range(1,atBats):
if random_pick(a, b) == 'Hit':
hit = (random_pick(a, b))/.3
num_hits += hit
elif random_pick(a, b) == 'Out':
out = (random_pick(a, b))/7
num_outs += out
print num_hits, num_outs
Any help would be greatly appreciated. Also, does anyone know of a good resource to learn Monte Carlo simulations?
num_hits = 0
num_outs = 0
for i in range(1, atBats):
if random_pick(a,b) == 'Hit':
num_hits += 1
else:
num_outs += 1
print num_hits, num_outs
To be honest, I am struggling to follow the logic of your code (it's been a long day), but here are a couple of pointers:
1) When you do things like:
if random_pick(a, b) == 'Hit':
...
elif random_pick(a, b) == 'Out':
...
you're calling random_pick() twice, so you're conducting two independent simulations instead of one. As a result, it could be that neither of the two branches get executed. To fix, call random_pick() once, store the result, and then branch on that result.
2) As to your other problem, Python allows you to return multiple values from a function. This might be useful here:
def random_pick(some_list, probabilities):
... decide on the item and probability ...
return item, probability
You can then call it like so:
item, prob = random_pick(a, b)
and use item or prob (or both).

Categories

Resources