Summing the number of instances a string is generated in iteration - python

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

Related

If, else return else value even when the condition is true, inside a for loop

Here is the function i defined:
def count_longest(field, data):
l = len(field)
count = 0
final = 0
n = len(data)
for i in range(n):
count = 0
if data[i:i + l] is field:
while data[i - l: i] == data[i:i + l]:
count = count + 1
i = i + 1
else:
print("OK")
if final == 0 or count >= final:
final = count
return final
a = input("Enter the field - ")
b = input("Enter the data - ")
print(count_longest(a, b))
It works in some cases and gives incorrect output in most cases. I checked by printing the strings being compared, and even after matching the requirement, the loop results in "OK" which is to be printed when the condition is not true! I don't get it! Taking the simplest example, if i enter 'as', when prompted for field, and 'asdf', when prompted for data, i should get count = 1, as the longest iteration of the substring 'as' is once in the string 'asdf'. But i still get final as 0 at the end of the program. I added the else statement just to check the if the condition was being satisfied, but the program printed 'OK', therefore informing that the if condition has not been satisfied. While in the beginning itself, data[0 : 0 + 2] is equal to 'as', 2 being length of the "field".
There are a few things I notice when looking at your code.
First, use == rather than is to test for equality. The is operator checks if the left and right are referring to the very same object, whereas you want to properly compare them.
The following code shows that even numerical results that are equal might not be one and the same Python object:
print(2 ** 31 is 2 ** 30 + 2 ** 30) # <- False
print(2 ** 31 == 2 ** 30 + 2 ** 30) # <- True
(note: the first expression could either be False or True—depending on your Python interpreter).
Second, the while-loop looks rather suspicious. If you know you have found your sequence "as" at position i, you are repeating the while-loop as long as it is the same as in position i-1—which is probably something else, though. So, a better way to do the while-loop might be like so:
while data[i: i + l] == field:
count = count + 1
i = i + l # <- increase by l (length of field) !
Finally, something that might be surprising: changing the variable i inside the while-loop has no effect on the for-loop. That is, in the following example, the output will still be 0, 1, 2, 3, ..., 9, although it looks like it should skip every other element.
for i in range(10):
print(i)
i += 1
It does not effect the outcome of the function, but when debugging you might observe that the function seems to go backward after having found a run and go through parts of it again, resulting in additional "OK"s printed out.
UPDATE: Here is the complete function according to my remarks above:
def count_longest(field, data):
l = len(field)
count = 0
final = 0
n = len(data)
for i in range(n):
count = 0
while data[i: i + l] == field:
count = count + 1
i = i + l
if count >= final:
final = count
return final
Note that I made two additional simplifications. With my changes, you end up with an if and while that share the same condition, i.e:
if data[i:i+1] == field:
while data[i:i+1] == field:
...
In that case, the if is superfluous since it is already included in the condition of while.
Secondly, the condition if final == 0 or count >= final: can be simplified to just if count >= final:.

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

Tower of Hanoi Representation

I'm having trouble implementing the problem in python as follows. I understand the original Tower of Hanoi problem which is that one can move $N$ disks to say the 3rd disk, and there are algorithms to do so but I am unable to figure out how to list out each of the individual disks at each stage. The problem is as follows:
I figured that I could use a binomial tree representation shown as follows:
So far the rough skeleton code I thought of would look something along the lines of
def recursion(m,n,T):
pos = list(range(1,m))
index = 0
values = list(range(1,n))
tree = []
if pos[index+1] > pos[index]:
pos[index + 1] -= pos[index+1]
pos[index + 2] += pos[index+1]
tree.append(pos)
if pos[index+1] < pos[index]:
pos[index+1] += pos[index]
pos[index] -= pos[index]
tree.append(pos)
else:
recursion()
return tree
I would greatly appreciate some help with this
You didn't pass no. of disks to your function, and this number must be decreased at every next call you make to the function. And there is a condition to break further recursion. Here is the modified form
# n = no. of rods
def recurse(n , from_rod, to_rod, aux_rod):
if n == 1:
print "Move disk 1 from rod", from_rod, "to rod",to_rod
return
recurse(n-1, from_rod, aux_rod, to_rod)
print "Move disk", n, "from rod", from, "to rod", to
recurse(n-1, aux_rod, to_rod, from_rod)
n = 5
recurse(n, 'A', 'B', 'C')
This is very similar to ksai solution except this is for python 3 and I removed the extra print and return statement
def move(disk , from_rod, to_rod, aux_rod):
if disk >= 1:
move(disk-1, from_rod, aux_rod, to_rod)
print ("Move disk", disk, "from rod", from_rod, "to rod", to_rod)
move(disk-1, aux_rod, to_rod, from_rod)
n = 3
move(n, 'A', 'B', 'C')
output:

How do you use a string to solve a math equation using python?

I'm trying to make a python program which takes in a user equation, for example: "168/24+8=11*3-16", and tries to make both sides of the equation equal to each other by removing any 2 characters from the user input. This is what I have so far:
def compute(side):
val = int(side[0])
x= val
y=0
z=None
for i in range(1, len(side)-1):
if side[i].isdigit():
x= (x*10)+ int(side[i])
if x == side[i].isdigit():
x= int(side[i])
else:
op = side[i]
if op=="+":
val += x
elif op == "-":
val -= x
elif op == "*":
val *= x
else:
val /= x
return print(val)
I have edited my compute function.
def evaluate(e):
side1 = ""
side2 = ""
equalsign = e.index("=")
side1= e[:equalsign - 1]
side2= e[:equalsign + 1]
if compute (side1) == compute(side2):
return True
else:
return False
def solve():
# use a for loop with in a for loop to compare all possible pairs
pass
def main():
e= input("Enter an equation: ")
evaluate(e)
main()
For the actual solve function I want to test all possible pairs for each side of the equation and with every pair removed check if the equation is equal to the other side. I was thinking of using a for loop that said:
for i in side1:
j= [:x]+[x+1:y]+[y+1:]
if compute(j)==compute(side2):
val= compute(j)
return val
How should I go about doing this? I'm getting a little confused on how to really approach this program.
Let's get to the preliminary issues.
e = raw_input("Enter an equation: ") # input is fine if you are using Python3.x
side1 = e[:equalsign] #note that a[start:end] does not include a[end]
side2 = e[equalsign + 1:] # not e[:equalsign + 1].
val = int(side[0]) # not val = side[0] which will make val a string
In the operations part, you are doing val += side # or -= / *= / /= .. remember side is a string
Edits:
Yeah, I'm still stuck up with Python 2.7 (use input if Python 3)
To solve for the value of each side, you could simply use eval(side1) # or eval(side2). There could be alternatives to using eval. (I am a novice myself). eval will also take care of PEMDAS.
Added edit to side1 expression.
Updated with code written so far.
def compute(side):
return eval(side)
def evaluate(e):
side1, side2 = e.split('=')
if compute(side1) == compute(side2):
return (True, e)
else:
return (False, 'Not Possible')
def solve(e):
for i in range(len(e)): # loop through user input
if e[i] in '=': # you dont want to remove the equal sign
continue
for j in range(i+1, len(e)): # loop from the next index, you dont want
if e[j] in '=': # to remove the same char
continue # you dont want to remove '=' or operators
new_exp = e[:i] + e[i+1:j] + e[j+1:] # e[i] and e[j] are the removed chars
#print e[i], e[j], new_exp # this is the new expression
s1, s2 = new_exp.split('=')
try:
if compute(s1) == compute(s2):
return (True, new_exp)
except:
continue
return (False, 'not possible')
def main():
e= raw_input("Enter an equation: ")
print evaluate(e.replace(' ', ''))
main()
This is what I have come up with so far (works for your example at least).
It assumes that operators are not to be removed
Final edit: Updated code taking into account #Chronical 's suggestions
Removed the try-except block in each loop and instead just use it after calculating each side
Here is code that does exactly what you want:
from itertools import combinations
def calc(term):
try:
return eval(term)
except SyntaxError:
return None
def check(e):
sides = e.split("=")
if len(sides) != 2:
return False
return calc(sides[0]) == calc(sides[1])
equation = "168/24+8 = 11*3-16".replace(" ", "")
for (a, b) in combinations(range(len(equation)), 2):
equ = equation[:a] + equation[a+1:b] + equation[b+1:]
if check(equ):
print equ
Core tricks:
use eval() for evaluation. If you use this for anything, please be aware of the security implications of this trick.
use itertools.combinations to create all possible pairs of characters to remove
Do not try to handle = too specially – just catch it in check()

Assign new values to an array based on a function ran on other 3 dimensional array

I have a multiband raster where I want to apply a function to the values that each pixel has across all the bands. Depending on the result, a new value is assigned, and a new single-band raster is generated from these new values. For example if a pixel has increasing values across the bands, the value "1" will be assigned to that pixel in the resulting raster. I am doing some tests on an three dimensional array using numpy but I am not able to resolve the last part, where the new values are assigned.
The function to be applied to the 3 dimensional array is Trend(List). I have defined it in the begining. To be easier to iterate through the array values on the z (or 0) axis I have used np.swapaxes (thank you #Fabricator for this). The problem comes now when assinging new values to the new_band[i,j] array so that the result of Trend(List) over the list:
[myArraySw[0,0]] will be assigned to new_band[0,0]
[myArraySw[0,1]] will be assigned to new_band[0,1]
[myArraySw[0,2]] will be assigned to new_band[0,2]
[myArraySw[0,3]] will be assigned to new_band[0,3]
................................................
[myArraySw[3,3]] will be assigned to new_band[3,3]
Some values are assigned, but some not. For example new_band[0,1] should be "2" but is "0". The same with new_band[3,0], new_band[3,1], new_band[3,2], new_band[3,3] that should be "5" but they are "0". Other values look alright. Where could be the problem?
Thank you
Here is the code:
import os
import numpy as np
def decrease(A):
return all(A[i] >= A[i+1]for i in range(len(A)-1))
def increase(A):
return all(A[i] <= A[i+1] for i in range(len(A)-1))
def Trend(List):
if all(List[i] == List[i+1] for i in range(len(List)-1))==1:
return "Trend: Stable"
else:
a=[value for value in List if value !=0]
MaxList = a.index(max(a)) #max of the list
MinList=a.index(min(a)) #min of the list
SliceInc=a[:MaxList] #slice until max
SliceDec=a[MaxList:] #slice after max value
SliceDec2=a[:MinList] #slice until min value
SliceInc2=a[MinList:] #slice after min value
if all(a[i] <= a[i+1] for i in range(len(a)-1))==1:
return "Trend: increasing"
elif all(a[i] >= a[i+1] for i in range(len(a)-1))==1:
print "Trend: decreasing"
elif increase(SliceInc)==1 and decrease(SliceDec)==1:
return "Trend: Increasing and then Decreasing"
elif decrease(SliceDec2)==1 and increase(SliceInc2)==1:
return "Trend: Decreasing and then Increasing"
else:
return "Trend: mixed"
myArray = np.zeros((4,4,4)) # generating an example array to try the above functions on
myArray[1,0,0] = 2
myArray[3,0,0] = 4
myArray[1,0,1] = 10
myArray[3,0,1] = 8
myArray[0,1,2] = 5
myArray[1,1,2] = 7
myArray[2,1,2] = 4
print "\n"
print "This is the original: "
print "\n"
print myArray
print "\n"
print "\n"
myArraySw = np.swapaxes(np.swapaxes(myArray,0,2),0,1) # swaping axes so that I can iterate through the lists
print "\n"
print "This is the swapped: "
print "\n"
print myArraySw
print "\n"
new_band = np.zeros_like(myArray[0]) # create a new array to store the results of the functions
for j in range(3):
for i in range(3):
if Trend(myArraySw[i,j]) == "Trend: increasing":
new_band[i,j] = 1
elif Trend(myArraySw[i,j]) == "Trend: decreasing":
new_band[i,j] = 2
elif Trend(myArraySw[i,j]) == "Trend: Increasing and then Decreasing":
new_band[i,j] = 3
elif Trend(myArraySw[i,j]) == "Trend: Decreasing and then Increasing":
new_band[i,j] = 4
elif Trend(myArraySw[i,j]) == "Trend: Stable":
new_band[i,j] = 5
elif Trend(myArraySw[i,j]) == "Trend: mixed":
new_band[i,j] = 6
print "\n"
print "The new array is: "
print "\n"
print new_band
At least part of the problem is that when you typed:
elif all(a[i] >= a[i+1] for i in range(len(a)-1))==1:
print "Trend: decreasing"
you probably meant to type this:
elif all(a[i] >= a[i+1] for i in range(len(a)-1))==1:
return "Trend: decreasing"
^^^^^^
Also, if you don't mind a little unsolicited advice, the code you've posted has a pretty strong "code smell" - you're doing a lot of things in unnecessarily complicated ways. Good on you for getting it done anyways, but I think you'll find this sort of thing easier if you work through some python tutorial problem sets, and read over the given solutions to see how more experienced programmers handle common tasks. You'll discover easier ways to implement many of the elements of this and future projects.

Categories

Resources