How can I average multiple outputs independently in python - python

PYTHON 3: Hi, so I have this piece of code
for money in range(0, 2501, 500):
print("{} Euro".format(money), end='')
throws = 0
d = trump.possession(board)
while False in d.values():
prevLoc = piece.location
piece.move(trump.throw())
throws += 1
if piece.location < prevLoc:
money += 200
if board.names[piece.location] in d and d[board.names[piece.location]] == False and money >= board.values[piece.location]:
money -= board.values[piece.location]
d[board.names[piece.location]] = True
return throws
and this code takes 0 money to start with, runs the code, looks for amount of throws required to buy the entire board, does the same with 500 starting money, 1000 and so forth
my question is, how can i take the average of the throws to buy the entire board for each starting value? the way my code is now it returns the amount of throws for all the starting values, but simulated once, so it may not be accurate.
I searched a lot, and tried some things but i had problems with this one because I want to like run it, say for example, 2000 times, and get the average for each starting value for the money.
anyone got any tips for this? been struggling on it for a while..
i tried making a for loop from 0 to 2000 and then inside of that another for loop that prints 0-2500 and then uses the code below in a function, appends the return value of throws into a list and sums it up and devides it by 2000, it did not turn out so good...

I'm going to assume this is in a function, due to the return statement. You need to collect outputs into a list and then average that at the end.
def calc_throws(simulations):
throw_list = []
average = lambda x: sum(x)/len(x)
for i, money in enumerate(range(0, 2501, 500)):
print("{} Euro".format(money), end='')
throw_list.append([money, []])
for _ in range(simulations):
throws = 0
d = trump.possession(board)
while False in d.values():
prevLoc = piece.location
piece.move(trump.throw())
throws += 1
if piece.location < prevLoc:
money += 200
if board.names[piece.location] in d and d[board.names[piece.location]] == False and money >= board.values[piece.location]:
money -= board.values[piece.location]
d[board.names[piece.location]] = True
throw_list[i][1].append(throws)
throw_list[i][1] = average(throw_list[i][1])
return throw_list
Rather than a single number, this returns a list of lists like #[[0,20],[500,15],...[2500,3]] (or whatever reasonable numbers are) which gives you the average for each amount of starting money.

Related

Python if statement with multiple condition is messing up?

I'm a beginner with Python. I have a 2-d array called infected that stores values that correspond with the index. This bit of code is messy, but basically what I'm trying to do is simulate an infectious disease spreading over a number of days (T). The individual is infectious for infTime many days and then goes into recovery where they are immune for immTime days. There's also a probability value for whether a node will be infected and a value for how many nodes they will be connected to.
My problem is that I'm also trying to track the number of individuals currently susceptible, infected, or immune, but something is going wrong in the elif statement that is marked "# Messing up in this loop". Currently, the program is running through the statement more times than it should, which is throwing off the variables. If I switch the conditions in the elif statement, the program doesn't go through it and will stay at a very low number of infected individuals the entire time. I'm really stuck and I can't find any reason why it's not working how I want it to.
Code:
# Loop through T days, checking for infected individuals and connecting them to beta num of nodes, possibly infecting
infTime = 5 # Time spent infected before becoming immune
immTime = 20 # Time spent immune before becoming susceptible again
numSus = N - count
day = 0
while day < T:
for a in range(len(infected)):
nextnode = random.randint(0, N-1)
if((infected[a][0] == 1) and (infected[a][3] < infTime)):
num = infected[a][1]
for b in range(num-1):
if((a != nextnode) and (infected[nextnode][0] == 0)):
infected[a][3] += 1
chance = round((random.uniform(0, 1)), 2)
if(infected[nextnode][2] > chance):
infected[nextnode][0] = 1
G.add_edge(a, nextnode)
count += 1
numInf += 1
numSus -= 1
elif((a != nextnode) and (infected[nextnode][0] == 1)):
G.add_edge(a, nextnode)
elif((infected[a][0] == 1) and (infected[a][3] == infTime)): # Messing up in this loop
infected[a][3] = 0
infected[a][4] = 1
numImm += 1
numInf -= 1
G.add_edge(a, nextnode)
elif((infected[a][0] == 0) and (1 < infected[a][4] < immTime)):
infected[a][4] += 1
elif((infected[a][0] == 0) and (infected[a][4] == immTime)):
infected[a][4] = 0
numImm -= 1
numSus =+ 1
day += 1
print("Number of infected on day ", day, ": ", count)

is it possible to recheck an index in a list in the same loop again? python

What I'm trying to do is to make the loop goes to every index in the "investments" list then checks if it's equal to "aMoney" variable or not. if the statement is True then the same index of "investments" in "revenue" list data will be added to "totalMoney" variable and goes back again to do next.
My problem is that I want the loop to go back to the False statements to recheck if it's True again and add it to the "totalMoney" variable.
what's happening here is the loop will skip index[0] because 2040 >=/ 3000. but after many loops the condition will be True if we do it again with the new number.
note: Sorting won't work because index[] in first list must go with what same index[] in the second list, no changes.
here is my full code:
numOfProjects = int(7)
aMoney = int(2040)
investments = [3000,2040,3040,5000,3340,4000,7000]
revenue = [500,1000,300,450,2010,650,1500]
totalMoney = int()
totalMoney = aMoney
for j in range(len(investments)):
if(totalMoney >= investments[j]):
totalMoney += revenue[j]
investments[j] + 1
revenue[j] + 1
totalMoney -= aMoney
print("The profit is $", totalMoney)
the output of this code will be $3960
in papers, it should be $4910
because, first round should be
"2040 + 1000 + 300 + 2010 + 650" = 6000
then we go back at what we left
"6000 + 500 + 450" = 6950
6950 - 2040 = 4910
I tried my best explaining the idea, hope it's clear
In python, we don't need to initialise int variables as int(number), just declaring them with the corresponding value suffices. So instead of aMoney = int(2040), just aMoney = 2040 works.
You can use zip to sort the investments and revenue together. Here's a simplified code which does what you need -
initialMoney, currentMoney = 2040, 2040
investments = [3000,2040,3040,5000,3340,4000,7000]
revenue = [500,1000,300,450,2010,650,1500]
data = sorted(zip(investments, revenue))
print(data)
for investment, revenue in data:
if investment <= currentMoney:
currentMoney += revenue
netProfit = currentMoney - initialMoney
print("The profit is $", netProfit)
Output:
[(2040, 1000), (3000, 500), (3040, 300), (3340, 2010), (4000, 650), (5000, 450), (7000, 1500)]
The profit is $ 4910
What you see printed just before profit, is the (investment, revenue) sorted by investment.

Count the dice throws to get to file 5 100 times(board is 0-5)

I'm trying to find out how many times you have to throw the dice to get on file 5 100 times(board is played from 0 to 5). This is how I tried(I know the answer is 690 but I don't know what I'm doing wrong).
from random import *
seed(8)
five = 0
count = 0
add = 0
while five < 100:
count = count + 1
print(randint(1,6))
add = add + randint(1,6)
if add % 5 == 0 :
five = five + 1
else: add = add + randint(1,6)
print(count)
This is the code I think you were trying to write. This does average about 600. Is it possible your "answer" came from Python 2? The random seed algorithm is quite likely different.
from random import *
seed(8)
five = 0
count = 0
add = 0
while five < 100:
count += 1
r = randint(0,5)
if r == 5:
five += 1
else:
add += r
print(count, add)
You're adding a second dice throw every time you don't get on 5, this makes the probability distribution irregular (i.e. advancing by 7 will be more probable (1/6) than any other value, e.g. 1/9 for 5) so your result will not be the same as counting single throws.
BTW there is no fixed result for this, just a higher probability around a given number of throws. However, given that you seeded the random number generator with a constant, every run should give the same result. And it should be the right one if you don't double throw the dice.
Here is an example of the process that arrives at 690:
import random
random.seed(8)
fiveCount = 0
throwCount = 0
position = 0
while fiveCount < 100:
position = (position + random.randint(1,6)) % 6
throwCount += 1
fiveCount += position == 5
print(throwCount) # 690
Other observations:
Updating the position wraps around using modulo 6 (there are 6 positions from 0 to 5 inclusively)
Your check of add%5 == 0 does not reflect this. It should have been add%6 == 5 instead but it is always preferable to model the computation as close as possible to the real world process (so keep the position in the 0...5 range)

problem calculating minimum amount of coins in change using python

I have a homework assignment in which we have to write a program that outputs the change to be given by a vending machine using the lowest number of coins. E.g. £3.67 can be dispensed as 1x£2 + 1x£1 + 1x50p + 1x10p + 1x5p + 1x2p.
However, my program is outputting the wrong numbers. I know there will probably be rounding issues, but I think the current issue is to do with my method of coding this.
change=float(input("Input change"))
twocount=0
onecount=0
halfcount=0
pttwocount=0
ptonecount=0
while change!=0:
if change-2>-1:
change=change-2
twocount+=1
else:
if change-1>-1:
change=change-1
onecount+=1
else:
if change-0.5>-1:
change=change-0.5
halfcount+=1
else:
if change-0.2>-1:
change=change-0.2
pttwocount+=1
else:
if change-0.1>-1:
change=change-0.1
ptonecount+=1
else:
break
print(twocount,onecount,halfcount,pttwocount,ptonecount)
RESULTS:
Input: 2.3
Output: 11010
i.e. 3.2
Input: 3.2
Output:20010
i.e. 4.2
Input: 2
Output: 10001
i.e. 2.1
All your comparisons use >-1, so you give out change as long as you have more than -1 balance.
This would be correct if you were only dealing with integers, since there >-1 is equal to >=0.
For floating point numbers however, we have for example -0.5>-1, so we will give out change for negative balance (which we do not want).
So the correct way would be to replace all >-1 comparisons by >=0 (larger or equal to 0) comparisons.
The problem is how it calculates the change using your if/else statements. If you walk through the first example change-2>-1 will register true and then result will be .3 but on the next loop the if change - 1 > -1 you are expecting to be false but it's not it's actually -0.7. One of the best ways to do this would be with Python's floor // and mod % operators. You have to round some of the calculations because of the way Python handles floats
change=float(input("Input change"))
twocount=0
onecount=0
halfcount=0
pttwocount=0
ptonecount=0
twocount = int(change//2)
change = round(change%2,1)
if change//1 > 0:
onecount = int(change//1)
change = round(change%1,1)
if change//0.5 > 0:
halfcount = int(change//0.5)
change = round(change%0.5, 1)
if change//0.2 > 0:
pttwocount = int(change//0.2)
change = round(change%0.2, 1)
if change//0.1 > 0:
ptonecount = int(change//0.1)
change = round(change%0.1,1)
print(twocount,onecount,halfcount,pttwocount,ptonecount)
But given the inputs this produces
Input: 2.3
Output: 1 0 0 1 1
Input: 3.2
Output:1 1 0 1 0
Input: 2
Output: 1 0 0 0 0

Restart loop and add values in python?

The problem:
There are 3 paths where only one leads home.
The first path gets you lost for 3 days, then you're back to the beginning where you have to pick another path.
The second path gets you lost for 2 days, then you're back at the beginning and you have to pick another path.
The last door leads you home in 1 day.
Basically you keep going until you pick the last path. I'm trying to find the average time it takes to get home by simulating 1000 tries.
Here is what I have thus far:
days=0
for i in range(1000):
door=["a","b","c"]
numpy.random.choice(path)
if numpy.random.choice(path)=="a":
days=+2
if numpy.random.choice(path)=="b":
days=+3
if numpy.random.choice(path)=="c":
days=+1
print(steps)
As is, my code will just print out a value from 1-3 as the days.
I'm having trouble figuring out how to pick one and then accumulate it into the days and then restarting the loop until it picks path C.
I've done research and think a while loop might work but I don't know how to apply that.
You can use a while loop that keeps iterating while you are stuck and then when door 'a' is selected it adds the 1 to get home but then the person is no longer stuck so it drops out of the while loop. Then before entering the while loop again, just set stuck = True and the process continues always adding to the total number of days, then at the end just take the average.
import numpy
days=0
door=["a","b","c"]
N = 1000
for i in range(N):
stuck = True
while stuck:
if numpy.random.choice(door)=="a":
days += 2
if numpy.random.choice(door)=="b":
days += 3
if numpy.random.choice(door)=="c":
days += 1
stuck = False
print('Average number of days taken to get home: ', days / N)
I hope this helps!
Here's the code you're looking for:
import numpy
def runOnce():
days = 0
door=["a","b","c"]
while(True):
path = numpy.random.choice(door)
if path=="a":
days+=2
if path=="b":
days+=3
if path=="c":
days+=1
return days
total = 0
for i in range(1000):
total += runOnce()
print(total / 1000.0)
This code must solve your problem:
import random
doors = ['a', 'b', 'c']
total_days = 0
runs = 1000
for i in range(runs):
days = 0
choice = None
while choice != 'c':
choice = random.choice(doors)
if choice == 'a':
days += 2
if choice == 'b':
days += 3
if choice == 'c':
days += 1
total_days += days
avg_days = total_days / runs
print(avg_days)
I'm not quite sure on your rules, but this is my attempt
import numpy as np
def choose_path():
p =np.random.randint(3)
#print("Path = {}".format(p))
return p
N = 100000
days=0.0
for i in range(N):
#make sure you don't take the wrong path twice
taken = [False, False, False]
path = choose_path()
while(path != 2):
if(path==0):
if(not(taken[path])):
taken[path] = True
days += 2.0
if(path==1):
if(not(taken[path])):
taken[path] = True
days += 3.0
path = choose_path()
days += 1.0
# print("Days = {}".format(days))
print("Average for {} iterations = {}".format(N, days/N))
In contrast to the some of the other codes my guy doesn't take the same route twice. I'm not sure how you problem is defined. My solution seems to be 3.5.
Some of the mistakes you made are:
=+ is an assignment of a positive number a = +3 or a = -3
+= is an increment a = a + 3 <=> a += 3
you define door, but never use it
you never define steps but you use it
I think you should come up with an algorithm first and then implement it.
There are a few problems with your code. For example, you define a door list of possible choices, but then you pass path to the choice function. At the end of your program you print steps, but that's not defined anywhere. Instead, you should be printing days, or days / 1000. You need to pay attention to things like that when you're programming!
As others have shown, you need to do this with two loops. Each iteration of the outer loop performs a trial. The inner loop chooses paths until you get home and adds the day counts to the current total.
In your code, each if test generates a fresh random choice on top of the one you make at the start of the loop. That's not right. Just make the choice at the top of the loop, determine how many days to add to the count, and if you're home, break out of the loop.
We can do this in a simpler way. Rather than choosing from 'a', 'b', or 'c', just choose from 1, 2, or 3, the number of days each path takes. And as I said earlier, there's no need to use Numpy for this, we can just call the random module functions directly instead of letting Numpy do it on our behalf.
Here's a short demo.
from random import randint
trials = 10000
days = 0
for n in range(trials):
while True:
path = randint(1, 3)
days += path
if path == 1:
break
print(days, days / trials)
typical output
59996 5.9996
We can get a more accurate estimate to the true expected time by performing multiple runs and averaging the results. We could do that by wrapping the previous code in an extra loop, but it makes the code more readable if instead we wrap the old code in a function, and call that function in a loop. Like this:
from random import randint
def sim(trials):
days = 0
for n in range(trials):
while True:
path = randint(1, 3)
days += path
if path == 1:
break
return days
num = 10
trials = 10000
total = 0
for i in range(num):
days = sim(trials)
x = days / trials
print(i, x)
total += x
print('Final', total / num)
typical output
0 5.9732
1 6.007
2 6.0555
3 5.9943
4 5.9964
5 5.9514
6 6.0689
7 6.0457
8 5.9859
9 5.9685
Final 6.00468
It looks like the true expected value is 6 days. Actually, it's not hard to show that mathematically.
Let d equal the expected number of days to get home. 1/3 of the time we get home in 1 day, 1/3 of the time we get back to the start in 2 days and so we still have d days before we get home, and 1/3 of the time we get back to the start in 3 days and so, once again we still have d days before we get home.
We can put that into an equation:
d = (1/3)*1 + (1/3)*(2 + d) + (1/3)*(3 + d)
3*d = 1 + 2 + d + 3 + d
3*d = 6 + 2*d
d = 6

Categories

Resources