Monte Carlo Simulation giving 0 as output - python

I ran an experiment in which I got 6 different orders of size and now I'm trying to see if my observations are significant. I have to perform a MC simulation to get a p value to see if my observed values are unusually large or small compared to the null.
I need to:
Set up a scheme where Order 1 is 0 to 1/6, Order 2, is 1/6- to 2/6, order 3 is 2/6 to 3/6
Generate 20 random numbers between 0 and 1 and allocate them to these bins. If the number if < 1/6 put it in bin 1, if it is between 1/6 and 2/6 into bin 2 etc. -
I should have 6 new numbers, one for each bin, that add up to 20, but my output is saying 0. Im new to python so what am I doing wrong?
My code is here:
from random import randint
from random import seed
# seed random number generator
seed(1)
counter = 0
chi_sq_values = []
# want 10,000 simulations
while counter < 10000:
# will eventually mimic your real six orders of size
sim_orders = [0, 0, 0, 0, 0, 0]
# generating 20 random numbers
for i in range(20):
numbers = randint(0, 1)
if 0 <= numbers <= 1 / 6:
numbers += sim_orders[0]
if 1 / 6 <= numbers <= 2 / 6:
numbers += sim_orders[1]
if 2 / 6 <= numbers <= 3 / 6:
numbers += sim_orders[2]
if 3 / 6 <= numbers <= 4 / 6:
numbers += sim_orders[3]
if 4 / 6 <= numbers <= 5 / 6:
numbers += sim_orders[4]
if 5 / 6 <= numbers <= 6 / 6:
numbers += sim_orders[5]
print(sim_orders)

You're not incrementing the values in sim_orders. You're adding the value in sim_orders to numbers, which has no effect because the value is always 0. And then you're not doing anything with numbers after you add to it.
You should increment the appropriate counter in sim_orders.
You need to use random.random(), not random.randint(0, 1). The latter will just return 0 or 1, not a number between 0 and 1.
for i in range(20):
numbers = random.random()
if numbers <= 1 / 6:
sim_orders[0] += 1
elif numbers <= 2 / 6:
sim_orders[1] += 1
elif numbers <= 3 / 6:
sim_orders[2] += 1
elif numbers <= 4 / 6:
sim_orders[3] += 1
elif numbers <= 5 / 6:
sim_orders[4] += 1
else:
sim_orders[5] += 1
You should also use elif for a sequence of mutually exclusive conditions, to avoid unnecessary tests. And if you do this, you don't need to test both ends of the range, since the previous test precludes numbers lower than the bottom of the range.
Your conditions overlapped -- if numbers was an exact multiple of 1/6 it would be put into both bins.
You can also get rid of all the if statements entirely:
sim_orders[floor(numbers*6)] += 1

If you dont want to update your list sim_orders with zeros, then you should put it out of while cycle. Moreover I don't see where you update your list with generated numbers. And if you want your while cycle to be finite then you have to increment counter inside loop body.

Related

Loop while basics in python 3

I am reading a python basics book and there is one function which I don't understand how it works. How is is possible that output looks like pow function even there are not any ** or pow operation? Would be nice if anyone can help because I am getting more and more frustrated
loop while
summary = 1
number = 1
while number <= 6:
i = 1
p = number
while i < 5:
p *= number
i += 1
print(number, "to 5", p)
summary += p
number += 1
print("sum of fifth powers of numbers from 1 to 6 is", summary)
output
1 to 5 1
2 to 5 32
3 to 5 243
4 to 5 1024
5 to 5 3125
6 to 5 7776
sum of fifth powers of numbers from 1 to 6 is 12202
Let me explain this code briefly,
first we are defining,
> summary = 1
> number = 1
Here we are defining and initialising the two variables summary and number.
> while number <= 6:
> i = 1
> p = number
In above code we are starting a while loop which will run while the value of number variable is less than or equal to 6. So, the loop will run from 1 to 6. we are taking a variable i = 1 and p = number here.
> while i < 5:
> p *= number
> i += 1
> print(number, "to 5", p)
> summary += p
> number += 1
> print("sum of fifth powers of numbers from 1 to 6 is", summary)
Now, we are having an another nested while loop and this will run for the values 1 to 4 of i variable. As we can see in the loop, the variable p will be multiplied with itself for 4 times so we will get the 5th power of the particular number. then we are increasing value of number by 1 and adding the value of 5th power in variable summary and lastly we are printing that.
Let me explain with an example
when number=2 (i.e after finding fifth power of 1)
value of p=2 and i=1
then inner loop i.e
while i<5 :
p* = number //i.e p = p*number
i+= 1 //i.e i=i+1
goes like this,
iteration 1: p= 2*2 i.e p=4
i=1+1 i.e i=2 which is less than 5
iteration 2: p= 4*2 i.e p=8
i=2+1 i.e i=3 which is less than 5
iteration 3: p= 8*2 i.e p=16
i=3+1 i.e i=4 which is less than 5
iteration 4: p= 16*2 i.e p=32
i=4+1 i.e i=5 which is equal to 5, so it comes out of loop
therefore, 2 to 5=32
this is how we get fifth power of a number

Python Arithmetic Sequence Sum

How do I make a code that follows this? 1⋅2+2⋅3+3⋅4+…+(n−1)⋅n
For example, if n=5, the answer is 1⋅2+2⋅3+3⋅4+4⋅5=40.
n cannot be less than or equal to two or more or equal to 1000
This is my code for now but it doesn't work.
n = int(input())
if n>= 2 and n<=1000:
sum = 0;
numbers = range(1, n+1)
for amount in numbers:
if (amount % 2 == 1):
sum *= amount
else:
sum += amount
print(sum)
For every number between 1 and n-1 (inclusive), you need to multiply it by the following number, and then sum them all. The easiest way to represent this is with a comprehension expression over a range call:
result = sum(i * (i + 1) for i in range(1, n))
You need to reproduce exactly the scheme you give
for each number, mulitply it with itself-1, and sum that
def compute(n):
if 2 <= n <= 1000:
total = 0
for amount in range(1, n + 1):
total += amount * (amount - 1)
print(total)
But that's the same as multiplying each with itself+1, if you change the bound to get one step less
for amount in range(1,n):
total += amount * (amount + 1)
Then you can use builtin methos sum and a generator syntax
def compute(n):
if 2 <= n <= 1000:
total = sum(nb * (nb + 1) for nb in range(1,n))
print(total)
If you try to approach it mathematically, you can have the answer in a single expression.
Dry run your code. You will see that for n = 5, you are doing as follows:
Num of Iterations = 6 (1 -> 5+1)
Iteration 1
sum = 0 + 1 = 1
Iteration 2
sum = 1 * 2 = 2
Iteration 3
sum = 2 + 3 = 5
Iteration 4
sum = 5 * 4 = 20
Iteration 5
sum = 20 + 5 = 25
Iteration 6
sum = 25 * 6 = 150
In this, you are completely disregarding the BODMAS/PEMDAS rule of multiplication over addition in the process of regenerating and calculating the series
What you need to do is
Iteration 1:
sum = 0 + 2 * 1 = 2
Iteration 2:
sum = 2 + 3 * 2 = 8
Iteration 3:
Sum = 8 + 4*3 = 20
Iteration 4:
Sum = 20 + 5*4 = 40
Here, We have broken the step as follows:
For each iteration, take the product of (n) and (n-1) and add it to the previous value
Also note that in the process, we are first multiplying and then adding. ( respecting BODMAS/PEMDAS rule )
So, you need to go from n = 2 to n = 5 and on each iteration you need to do (n-1)*(n)
As mentioned earlier, the loop is as follows:
## Checks for n if any
sum = 0
for i in range(2, n):
sum = sum + (i-1)*i
print(sum)

How to find even sum

I need to find the sum of all even numbers below the inserted number. For example if I insert 8 then the sum would be 2+4+6+8=20. If I insert 9 then it also needs to be 20. And it needs to be based on recursion.
This is what I have so far:
def even(a):
if a == 0:
else:
even(a - 1)
even(8)
I cannot figure out what to change under the "if" part for it to give the right outcome
If the function is called with an odd number, n, then you can immediately call again with the number below (an even).
Then if the function is called with an even number return that even number plus the result of summing all the even numbers below this number by calling again with n - 2.
Finally, your base case occurs when n = 0. In this case just return 0.
So we have
def even_sum(n):
if n % 2 == 1: # n is odd
return even_sum(n - 1)
if n == 0:
return 0
return n + even_sum(n - 2)
which works as expected
>>> even_sum(8)
20
>>> even_sum(9)
20
>>> even_sum(0)
0
To design a recursive algorithm, the first thing to wonder is "In what cases can my algorithm return an answer trivially?". In your case, the answer is "If it is called with 0, the algorithm answers 0". Hence, you can write:
def even(n):
if n == 0:
return 0
Now the next question is "Given a particular input, how can I reduce the size of this input, so that it will eventually reach the trivial condition?"
If you have an even number, you want to have this even number + the sum of even numbers below it, which is the result of even(n-2). If you have an odd number, you want to return the sum of even numbers below it. Hence the final version of your function is:
def even(n):
if n == 0 or n == 1:
return 0
if n % 2 == 0:
return n + even(n - 2)
return even(n - 1)
Both with o(n) time complexity
With For loop
num = int(input("Enter a number: ")) # given number to find sum
my_sum = 0
for n in range(num + 1):
if n % 2 == 0:
my_sum += n
print(my_sum)
With recursion
def my_sum(num):
if num == 0:
return 0
if num % 2 == 1:
return my_sum(num - 1)
return num + my_sum(num - 2)
always avoid O(n^2) and greater time complexity
For a recursive solution:
def evenSum(N): return 0 if N < 2 else N - N%2 + evenSum(N-2)
If you were always given an even number as input, you could simply recurse using N + f(N-2).
For example: 8 + ( 6 + (4 + ( 2 + 0 ) ) )
But the odd numbers will require that you strip the odd bit in the calculation (e.g. subtracting 1 at each recursion)
For example: 9-1 + ( 7-1 + ( 5-1 + ( 3-1 + 0 ) ) )
You can achieve this stripping of odd bits by subtracting the modulo 2 of the input value. This subtracts zero for even numbers and one for odd numbers.
adjusting your code
Your approach is recursing by 1, so it will go through both the even and odd numbers down to zero (at which point it must stop recursing and simply return zero).
Here's how you can adjust it:
Return a value of zero when you are given zero as input
Make sure to return the computed value that comes from the next level of recursion (you are missing return in front of your call to even(a-1)
Add the parameter value when it is even but don't add it when it is odd
...
def even(a):
if a == 0 : return 0 # base case, no further recusion
if a%2 == 1 : return even(a-1) # odd number: skip to even number
return a + even(a-1) # even number: add with recursion
# a+even(a-2) would be better
A trick to create a recursive function
An easy way to come up with the structure of a recursive function is to be very optimistic and imagine that you already have one that works. Then determine how you would use the result of that imaginary function to produce the next result. That will be the recursive part of the function.
Finally, find a case where you would know the answer without using the function. That will be your exit condition.
In this case (sum of even numbers), imagine you already have a function magic(x) that gives you the answer for x. How would you use it to find a solution for n given the result of magic(n-1) ?
If n is even, add it to magic(n-1). If n is odd, use magic(n-1) directly.
Now, to find a smaller n where we know the answer without using magic(). Well if n is less than 2 (or zero) we know that magic(n) will return zero so we can give that result without calling it.
So our recursion is "n+magic(n-1) if n is even, else magic(n-1)"
and our stop condition is "zero if n < 2"
Now substitute magic with the name of your function and the magic is done.
For an O(1) solution:
Given that the sum of numbers from 1 to N can be calculated with N*(N+1)//2, you can get half of the sum of even numbers if you use N//2 in the formula. Then multiply the result by 2 to obtain the sum of even numbers.
so (N//2)*(N//2+1) will give the answer directly in O(1) time:
N = 8
print((N//2)*(N//2+1))
# 20
# other examples:
for N in range(10):
print(N,N//2*(N//2+1))
# 0 0
# 1 0
# 2 2
# 3 2
# 4 6
# 5 6
# 6 12
# 7 12
# 8 20
# 9 20
Visually, you can see the progression like this:
1..n : 1 2 3 4 5 6 7 8
∑n : 1 3 6 10 15 21 28 36 n(n+1)/2
n/2 : 0 1 1 2 2 3 3 4
1..n/2 : 1 2 3 4
∑n/2 : 1 3 5 10 half of the result
2∑n/2 : 2 6 10 20 sum of even numbers
So we simply replace N with N//2 in the formula and multiply the result by 2:
N*(N+1)//2 --> replace N with N//2 --> N//2*(N//2+1)//2
N//2*(N//2+1)//2 --> multiply by 2 --> N//2*(N//2+1)
Another way to see it is using Gauss's visualisation of the sum of numbers but using even numbers:
ascending 2 4 6 8 ... N-6 N-4 N-2 N (where N is even)
descending N N-2 N-4 N-6 ... 8 6 4 2
--- --- --- --- --- --- --- ---
totals N+2 N+2 N+2 N+2 ... N+2 N+2 N+2 N+2 (N/2 times N+2)
Because we added the even numbers twice, once in ascending order and once in descending order, the sum of all the totals will be twice the sum of even numbers (we need to divide that sum by 2 to get what we are looking for).
sum of evens: N/2*(N+2)/2 --> N/2*(N/2+1)
The N/2(N/2+1) formulation allows us to supply the formula with an odd number and get the right result by using integer division which absorbs the 'odd bit': N//2(N//2+1)
Recursive O(1) solution
Instead of using the integer division to absorb the odd bit, you could use recursion with the polynomial form of N/2*(N+2)/2: N^2/4 + N/2
def sumEven(n):
if n%2 == 0 : return n**2/4 + n/2 # exit condition
return sumEven(n-1) # recursion
Technically this is recursive although in practice it will never go deeper than 1 level
Try out this.
>>> n = 5
>>> sum(range(0, n+1, 2))
with minimum complexity
# include <stdio.h>
void main()
{
int num, sum, i;
printf("Number: ");
scanf("%d", &num);
i = num;
if (num % 2 != 0)
num = num -1;
sum = (num * (num + 2)) / 4;
printf("The sum of even numbers upto %d is %d\n\n", i, sum);
}
It is a C program and could be used in any language with respective syntax.
And it needs to be based on recursion.
Though you want a recursion one, I still want to share this dp solution with detailed steps to solve this problem.
Dynamic Programming
dp[i] represents the even sum among [0, i] which I denote as nums.
Case1: When i is 0, there is one number 0 in nums. dp[0] is 0.
Case2: When i is 1, there are two numbers 0 and 1 in nums. dp[1] is still 0.
Case3: When i is 2, there are three numbers 0, 1 and 2 in nums. dp[2] is 2.
Case4: When i is greater than 2, there are two more cases
If i is odd, dp[i] = dp[i-1]. Since i is odd, it is the same with [0, i-1].
If i is even, dp[i] = dp[i-2] + i by adding the current even number to the even sum among [0, i-2] (i-1 is odd, so won't be added).
PS. dp[i] = dp[i-1] + i is also ok. The difference is how you initialize dp.
Since we want the even sum among [0, n], we return dp[n]. You can conclude this from the first three cases.
def even_sum(n):
dp = []
# Init
dp.append(0) # dp[0] = 0
dp.append(0) # dp[1] = 0
# DP
for i in range(2, n+1): # n+1 because range(i, j) results [i, j) and you take n into account
if i % 2 == 1: # n is odd
dp.append(dp[i-1]) # dp[i] = dp[i-1]
else: # n is even
dp.append(dp[i-2] + i) # dp[i] = dp[i-2] + i
return dp[-1]

Python Poker hand single pair counter

I wrote the program below to iterate through every possible poker hand and count how many of these hands are a single pair
A hand is any 5 cards.
A single pair is when two cards of the same rank (number) and the other 3 cards of all different ranks e.g. (1,2,1,3,4)
I am representing the deck of cards as a list of numbers e.g.
- 1 = ACE
- 2 = Two
- 3 = Three
...
- 11 = Jack
- 12 = Queen...
The program seems to work find however,
the number of single pair hands it finds = 1101984
But according to multiple sources the correct answer is 1098240.
Can anyone see where the error in my code is?
from itertools import combinations
# Generating the deck
deck = []
for i in range(52):
deck.append(i%13 + 1)
def pairCount(hand):
paircount = 0
for i in hand:
count = 0
for x in hand:
if x == i:
count += 1
if count == 2:
paircount += .5 #Adding 0.5 because each pair is counted twice
return paircount
count = 0
for i in combinations(deck, 5): # loop through all combinations of 5
if pairCount(i) == 1:
count += 1
print(count)
The issue is that your hand can contain the following type of cards as well -
A Three of a kind and a single pair
You are actually calculating this as a single pair as well.
I modified the code to count just the number of hands such that it contains a three of a kind as well as a single pair together. Code -
deck = []
for i in range(52):
deck.append((i//13 + 1, i%13 + 1))
def pairCount(hand):
paircount = 0
threecount = 0
for i in hand:
count = 0
for x in hand:
if x[1] == i[1]:
count += 1
if count == 2:
paircount += .5 #Adding 0.5 because each pair is counted twice
if count == 3:
threecount += 0.33333333
return (round(paircount, 0) , round(threecount, 0))
count = 0
for i in combinations(deck, 5):
if pairCount(i) == (1.0, 1.0):
count += 1
This counted the number as - 3744.
Now, if we subtract this number from the number you got - 1101984 - We get the number you are expecting - 1098240 .

Randomly select 0 or 1 equal number of times?

I want to iterate over 100 values and select randomly 0 or 1, but end up with equal numbers of 0's and 1's,
The code below prints the counts:
import random
c_true = 0
c_false = 0
for i in range(100):
a = random.getrandbits(1)
if a == 1:
c_true += 1
else:
c_false += 1
print "true_count:",c_true
print "false_count:",c_false
The output is:
true_count: 56
false_count: 44
I want the counts to be equal
true_count: 50
false_count: 50
How can I change the code to obtain the desired result?
Create numbers with 50 0's and 50 1's,
>>> numbers = [0, 1] * 50
Import shuffle from random
>>> from random import shuffle
shuffle them
>>> shuffle(numbers)
Note: shuffle shuffles the list in-place. So, the numbers will be shuffled now.
Here is a generator-based solution that uses O(1) memory:
import random
def gen_boolean_seq(true_count, false_count):
while true_count or false_count:
val = (random.random() >= false_count / float(true_count + false_count))
if val:
true_count -= 1
else:
false_count -= 1
yield val
print sum(gen_boolean_seq(50, 50))
Well its not truely random then but if you want to end up with 50 1s and 50 0s then use a weighting based on how many available places are left. Eg. At 40 1s and 45 0s, the chance of 0 should be 5/15, and the chance of 1 should be 10/15.

Categories

Resources