Shannon Diversity Program: basic questions - python

I am a biology student trying to get into programming and have some issue with a basic index calculator I am trying to write for a research project. I need a program that will prompt the user to input data points one at a time, perform the proper calculation (-1*(x*ln(x))) on each data point, and enter that new calculated value into an array. Once the user inputs 'done', I would like the program to sum the array values and return that index value.
This is what I have. I am very new so apologies for any blaring mistakes. Any points in the right direction are very appreciated.
import math
print('This program calculates a Shannon Diversity '
'Index value for a set of data points entered by the user.'
' when prompted enter a species number value,then press enter. '
'COntinue until all data points have been entered. '
'Upon completion, enter the word done.')
def Shannonindex():
index = []
entries = 1,000,000
endKey = 'done'
for i in range(entries):
index = [input("Enter a value: ")]
if index != endKey:
entry = p
p = -1*(x*ln(x))
index.append(p)
else Sindex = sum(index)
return Sindex
print('Your Shannon Diversity Value is: ", Sindex)

There are a huge number of problms here.
You need to get your variables straight.
You're trying to use index to mean both the list of values, and the input string. It can't mean both things at once.
You're trying to use x without defining it anywhere. Presumably it's supposed to be the float value of the input string? If so, you have to say that.
You're trying to use p to define entry before p even exists. But it's not clear what entry is even useful for, since you never use it.
You also need to get your control flow straight.
What code is supposed to run in that else case? Either it has to include the return, or you need some other way to break out of the loop.
You also need to get your types straight. [input(…)] is going to give you a list with one element, the input string. It's hard to imagine what that would be useful for. You can't compare that list to 'done', or convert it to a float. What you want is just the input string itself.
You can't just guess at what functions might exist. There's no function named ln. Look at the docs for Built-in Functions, the math module, and anything else that looks like it might be relevant to find the function you need.
1,000,000 is not a number, but a tuple of three numbers.
You can write 1_000_000, or just 1000000.
But it's not clear why you need a limit in the first place. Why not just loop forever until the enter done?
You've defined a function, but you never call it, so it doesn't do any good.
So, let's sort out these problems:
import math
def Shannonindex():
index = []
endKey = 'done'
while True:
value = input("Enter a value: ")
if value != endKey:
x = float(value)
p = -1 * (x * math.log(x))
index.append(p)
else:
Sindex = sum(index)
return Sindex
Sindex = Shannonindex()
print('Your Shannon Diversity Value is: ", Sindex)
There are still many ways you could improve this:
Add some error handling, so if the user typos 13.2.4 or 1O, it tells them to try again instead of bailing out on the whole thing.
You don't actually need to build a list, just keep a running total.
If you reverse the sense of the if/else it will probably be more readable.
You're not actually calculating the Shannon diversity index. That's not the sum of -x ln x, it's the sum of -p ln p where each p is the proportion of x / sum(all x). To handle that, you need to keep all the raw x values in a list, so you can convert that to a list of p values, so you can sum those.

import math
index = []
for i in range(1,100000):
val = input("Enter a value: ")
if val =='done':
break
else:
x = int(val)
p = -1*(x*math.log(x))
index.append(p)
print ("The value of index is %s:"%index)
=================================================
This is the simplified form of your code, since you are new to python.
This might help you get the values stored in a list and calculate it until you type done.

Related

matrix couple input from a user

"so i just started to learn python, now am against a real problem abt matrix i want to create a matrix by using an input from the user something like that : [[x,y],[x,y],[x,y],[x,y]],the first obvious solution is that to insert an array with 1D to a matrix on axis=0 but something went wrong with the dimensions on the console and also idk which function i use (like i said am new so looping through functions without knowing one of them really frustrated me)
so if anyone know how to do, and a speciallly the rules to append and insert to an array or a matrix without geeting some dimensional error would be very helpfull and thnx for ur time "
You could use a while loop that asks for user input until enough inputs have been passed through.
x = input('Enter x and y values (Ex. x,y): ')
lis, val = [], []
while 'n' not in x:
val = x.split(',')
lis.append(val)
x = input('Enter x and y values (Ex. x,y): ') # stop loop by typing n
print(lis)
To end the loop just type 'n'.

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.

Changing or preventing the use of E in Python?

I'm currently trying to write a script that will create a unique ID for a user relying on a number of variables, like birthdate, name, hometown, etc. This creates a very long number that is completely unique to that user, however, to try to make the number even more unique, I want to change a random number in the string. This is what I have so far:
rand = randint(1,15)
tempid = id / 10**rand
if randint(1,2) == 1:
tempid = tempid + randint(2,10000)
else:
tempid = tempid - randint(5,7500)
print(id)
id = tempid * (10**rand)
print(str(id))
The code is fairly simple. It makes the number much smaller by dividing it by a large multiple of 10, adds or subtracts a random number, and multiplies it back to it's original length, with some changed numbers in the middle. The only problem is, because it must be an integer to be able to do any math with it, Python shortens it to 1.[something]e+[something]. This isn't helpful at all, becasue now it's not an ID. Is there anyway I can change it back to its original form, where it's just a long string, or perhaps change the code so it never becomes e? Thank you!
Unless this is a specific exercise, you do not want to generate unique IDs the way you do. It will fail. Use the uuid module instead.
Your problem is that id when you print it refers to a large float value, which is then printed in exponential notation. If it were an integer value, no e would be in the printout. The float value comes from your line
tempid = id / 10**rand
which, in Python 3.x, stores a float value in tempid. You later execute
id = tempid * (10**rand)
which multiplies a float by an integer, resulting in a float, and that float is what is printed in the next line
You can avoid this in several ways. You can keep all the calculations in integers by replacing your division line with
tempid = id // 10**rand
That extra slash mark means integer division, so tempid here and id later are integers. However, this may change the resulting values. So a better way is allow tempid to be a float but ensure that id is always an integer, using
id = int(tempid * (10**rand))
This should keep all your values the same and give you the print you want.
That answers your actual question. However, I agree with #user2722968 that if your purpose is to create a unique ID you should use module meant for that purpose, such as uuid. The history of computing shows that randomizing a part of a string to get a random value does poorly, and getting actual random or unique values is difficult to get right. You should do it the way others have shown to work well.
I also agree with the other answers; as far as best practice goes, you should not do it this way at all. You will almost certainly make a worse than optimal solution. However, to solve the actual problem you pose, I would want to approach it in a different manner.
The problem is, as stated, that your division will not leave you with an integer result, which makes Python automatically convert to a float. This is not what you want if you want to keep your value unique. You want to do all your calculations on integers only. To achieve that, the simplest way is to multiply your modifiers, instead of dividing your original number. That way you will never leave the integer domain, and there is no need to convert you value back to an integer:
print(id)
rand = randint(1,15)
multiplier = 10**rand
if randint(1,2) == 1:
id += multiplier * randint(2,10000)
else:
id -= multiplier * randint(5,7500)
print(id)
In addition I have used a bit of syntactic sugar, that I find rather nice, namely += and -=. They add and subtract a value from your variables respectively: a = a + 3 <=> a += 3.

Python - Table of Values Equation

I'm trying to make a program where you input the Slope, Y-Intercept, the minimum X and maximum X and then it will put a table of values that prints the "y" of each "x" essentially. I know I would have to use a for loop that uses the range function to take the range of the numbers they input so it will display that many items but I'm not sure what to do to make this work.
choice4=input("Slope (x): ")
choice5=input("Y-Intercept: ")
choice6=input("Minimum (x): ")
choice7=input("Maximum (x): ")
print("")
for items in range(int(choice6),int(choice7)):
print ((int(choice4) * x) + int(choice5))
You are almost there. The immediate issue is that you've called your loop variable items but then refer to it as x.
On a related note, you definitely want to give clearer names to your variables.
There are several smaller issues:
range() will exclude the final value, so you may need to account for that.
Instead of doing the same string-to-int conversions over and over again, you might want to do them just once.

Need help fixing/refining a while loop sum calculator in python [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Keep in mind that I am still very new to python coding as I am only just into chapter 5 of my python coding class. Keeping that in mind, I am attempting to create a sum calculator using a "while loop" to continue until the user enters a negative number instead of a positive number.
In case I am not entirely clear in my description of my question I will post the exact homework problem here:
Chapter 5, page 200, #8
Sum of Numbers
Write a program with a while loop that asks the user to enter a series of positive numbers. The user should enter a negative number to signal the end of the series. After all the positive numbers have been entered, the program should display their sum.
Now for the code that I have written so far:
def main():
number = float(input('Please enter in a positive number: '))
while number > 0:
positiveNumber()
while number < 0:
calculateTotal()
printTotal()
def positiveNumber():
number = float(input('If you are finished please enter a negative number.' + \ 'Otherwise, enter another positive number: '))
while number > 0:
positiveNumber()
while number < 0:
calculateTotal()
printTotal()
def calculateTotal():
total = 0 + number
def printTotal():
print('The sum of your numbers is: ', total)
main()
In line 11, I have the "+ \" sign there because I wanted to make an enter space there in order to have a cleaner looking text, but that does not seem to work.
I apologize if this question seems "nooby" but I need help making a cleaner/working sum calculator. I would greatly appreciate it if someone can take a look at this code and hopefully help me improve it. Thank you!
Final Edit:
Thank you all for the informative answers! I learned alot (for a "newbie" =]). I used Talon876's answer for my calculator. Thanks again everyone!
If you want a single string to be printed on multiple lines, put a \n in the string.
For example,
print "This is on the first line\nThis is on the second line"
would output
This is on the first line
This is on the second line
It looks like you're mixing a while loop with recursion (calling a method from within itself). I would suggest using a single while loop and an input variable to check for the breaking condition (the input is < 0)
It would look something like this:
sum = 0
number = float(input('Please enter in a positive number: '))
while number > 0:
sum = sum + number
number = float(input('If you are finished please enter a negative number.' + \ 'Otherwise, enter another positive number: ')) #fix this line using the information from the first part of the answer
This will loop until the user inputs a negative number, or 0. If you want to accept 0 as a positive number, change the while condition to number > -1
You can't update a global variable in a python function without explicitly declaring it as a global. Observe:
a = 1
def foo():
a = a + 6 #creates a new variable (a) that is confined to the "foo" namespace.
#Note that it still uses a from the global namespace on the Right hand side
#This is because python looks for a in the "foo" namespace first. When
#it isn't found there, it looks in the global namespace. However, python
#WON'T ASSIGN to something in the global namespace without being told
#to explicitly
print (a)
foo() # 7
print (a) # 1
def foo():
global a #Tell python that it is OK to assign to variable "a" in the global namespace.
a = a + 6
print (a)
foo() # 7
print (a) # 7
However, with this great power comes great responsibility. Many people will tell you to never use global variables. In a lot of ways, they're correct because just about anything you can accomplish with global variables can be accomplished more cleanly using some other method. My hope in writing this is not to convince you to use globals, but to help you understand one of the errors in your code.
One thing that you may want to try is to have your function accept the input number as an argument along with the total to this point and then return the new total.
Good luck!
the problem is 1.you have not declared the variables you are using in function as global,to note the changes being made to them
2.you dont need while loops if you are implementing it by calling a function recursively!you need checking condition lik "if & else"
here is an easy implementation of problem with while loop:
def main():
total=0
number = float(input('Please enter in a positive number: '))
while(number>0):
total=total+number
number = float(input('Please enter in a positive number to continue or a negative no. to stop: '))
print('The sum of your numbers is: %d'% total)
main()
I think you're looking for something like this? But I don't know what style constraints you are required to use.
number = float(input('Please enter in a positive number: '))
to_sum = []
while number > 0:
to_sum.append(number)
number = float(input('If you are finished please enter a negative number.\n' +
'Otherwise, enter another positive number: '))
print('The sume of your numbers is: ', sum(to_sum))
Please note that because the statement you are trying to break onto multiple lines is already within ()'s, you don't need the . You can just break the line.
Did the assignment require you to use so many crazy functions? Also, which version of Python are you using?
One thing you need to learn is how to break up a program into functions. Some problems are better handled by a single block of code than by being split up, and I think this is one of them.
You need to calculate a single sum. You can handle that with a single variable, to which you add more numbers as the user enters them. Your code should be designed around this variable. If you try to split the code up into functions, you either need to use a global variable (not recommended!), or you need to pass the variable around among the functions, or perhaps you could put the variable into an object and then make the functions be "method" functions on the object. But simplest is just to write some code that uses the variable, and make all that code be a single block of code (either one function, or even just the code in your Python program).
Here is a solution:
sum = 0.0 # initial value; we will add values to this
print('Welcome to this program')
while True:
s = input('User: enter data value or a negative number to stop')
x = float(s)
if x < 0:
break
sum += x # add this value to update the sum
print('Here is your sum: {}'.format(sum))
So, here is what is good about the above code. All the places that need to work with the variable sum are all close together, and we can see them. We don't need to declare sum global, because we don't have multiple functions trying to all use it.
Look at that code, and ask yourself: would it be simpler or cleaner if we carved it up into multiple functions? If not, then don't do it.
The only tricky thing here is that we used while True: for the loop. This is because we want to do something (get input), then based on the result, decide whether to break out of the loop or continue, and then finally do something else based on the decision (update the sum).
It's possible to rewrite this to use a "flag" variable, and make the loop while flag: but I don't think it is cleaner:
sum = 0.0 # initial value; we will add values to this
print('Welcome to this program')
continue_loop = True
while continue_loop:
s = input('User: enter data value or a negative number to stop')
x = float(s)
if x < 0:
continue_loop = False
else:
sum += x # add this value to update the sum
print('Here is your sum: {}'.format(sum))
Do you think it is clearer to have the continue_loop flag variable? Some textbooks say you should write your code this way, because they think it is a sin to use break to exit a loop in the middle; they think loops should only exit from the usual place (which, for a while loop, is the top).
What if you really wanted to use functions? Well, you could, but you still shouldn't use a global variable. In fact, if you are writing a "functional" solution, you don't need a sum variable at all!
Here is a functional solution.
def ask_and_sum():
s = input('Hey dude enter a value or a negative to stop')
x = float(s)
if x < 0:
return 0
else:
return x + ask_and_sum()
print('Welcome to this program')
print('Your sum is: {}'.format(ask_and_sum()))
Instead of an explicit loop, this uses "tail recursion", where a function ends with another call to itself. In this case, I personally prefer the explicit loop. What do you think?
P.S. This problem is so simple that it was hard to discuss it without giving you the full answer. I apologize for that. But even if you just copy the code, please look at it, and think about it, and make sure you understand it.

Categories

Resources