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.
Related
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.
Example 1:
save([4,4,4,3,3], 12) -> 3
# 4+4+4 <= 12, but 4+4+4+3 > 12
Example 2:
save([4,4,4,3,3], 11) -> 2
# 4+4 <= 11, but 4+4+4 > 11
First of all I'm noob yet, but here is my "code" lol.
def save(sizes, hd):
sum = 0
for i in sizes:
sum = sum + i
if sum <= hd:
a = (str(sum))
print(a)
save([4,4,4,3,3], 12)
Output of this code is:
4
8
12
It would be correct if I could count length of those numbers, but I tried many ways and still couldnt found(
Thanks for helping!
You need the enumerate() function:
def save(sizes, hd):
summm = 0
for index,value in enumerate(sizes,1): # start counting at 1
summm += value
if summm <= hd:
print(summm, index) # or simply print index alone
save([4,4,4,3,3], 12)
Outputs:
12 3 # first number is the sum, second amount of numbers you added (aka 1-based index)
You can use for i in range(len(sizes)) . I think it's the fastest solution, but I'm sure it doesn't matter.
def save(sizes, hd):
sum = 0
for i in range(len(sizes)): # i values are 0,1,2,...,len(sizes)-1
sum += sizes[i] # add i-th sizes element to sum
if sum <= hd: # check if we can print answer
print(i + 1) # because i starts from 0
else: # if we can't print, we should exit cycle
break # we can use return instead
By the way, you don't need to do anything like this, because 'print()' function converts all arguments to str()
a = str(sum)
print(a)
I hope, you has learned something new!
Try this one:
def save(sizes, hd):
sum = 0
new_list = []
for i in sizes:
sum += i
new_list.append(i)
if sum >= hd:
print(new_list)
return len(new_list)
print(save([4,4,4,3,3], 12))
#print(new_list) => [4, 4, 4]
#return len(new_list) => 3
If you build a list with the cumulative sum of your sorted numbers, the position of the target value will correspond to the maximum count of numbers that will fit within your target:
from bisect import bisect_right
from itertools import accumulate
numbers = [4,4,4,3,3]
target = 12
maxCount = bisect_right(list(accumulate(sorted(numbers))),target)
print(maxCount) # 3
The bisect module provides efficient search for an index in a sorted list (bisect_right). The itertools module provides a function (accumulate) to obtain the cumulative sum of numbers in a list
I changed your code around a bit to keep it simple:
def save(sizes, hd):
size_list = [] #instead of an int, let's use a list object to hold values
for size in sizes:
size_list.append(i) # add the size to the list
if sum(size_list) <= hd: # check if sum of all values in list is <= hd
return len(size_list) # return the number of sizes inside of list
hope this helps!
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 .
Beginner here- trying to make a simple python program that will compute/answer this problem:
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
Currently this is what I have:
a = 0
b = 0
while a < 1000:
a = a + 3
print (a)
while b < 1000
b = b + 5
print (b)
This will print all the numbers being considered. I just need to add them together and that's my answer.
I would like one of two things to happen, instead of the code that I have written:
I would like all of this to happen internally, and therefore not have to use the "print" function. The just print the sum of all of those multiples.
I would like all of this stuff to print, but then I want to be able to print the sum of all of them too. Is there a way to make the computer take the value of everything it has printed?
Actually this problem can be solved in O(1) instead of O(N) without using any loops or lists:
The required sum is the sum of all multiples of 3 plus sum of all multiples of 5 minus the sum of multiples of (3*5=15) below the given number 1000 (LIMIT=999). The sums are calculated as a sum of arithmetic series.
It can be calculated in following way:
LIMIT=999
# Get the upper bounds for the arithmetic series
upper_for_three = LIMIT // 3
upper_for_five = LIMIT // 5
upper_for_fifteen = LIMIT // 15
# calculate sums
sum_three = 3*upper_for_three*(1 + upper_for_three) / 2
sum_five = 5*upper_for_five*(1 + upper_for_five) / 2
sum_fifteen = 15*upper_for_fifteen*(1 + upper_for_fifteen) / 2
# calculate total
total = sum_three + sum_five - sum_fifteen
# print result with Python 3
print(int(total))
The result is:
>>>
233168
It is possible to do this in one line in Python using a generator expression:
print(sum(x for x in range(1000) if x % 3 == 0 or x % 5 == 0))
The range(1000) produces all the integers from 0 to 999 inclusive. For each one of those integers, if it is divisible by 3 or divisible by 5, then it is included in the result. The sum(...) function adds up all those numbers, and finally print(...) prints the result.
I would use a for loop to iterate over each number in your selected range. Then you can check if the modulus % is equal to 0, meaning it has no remainder when divided by those values, if so, add it to the total.
total = 0
for num in range(1000):
if num % 3 == 0 or num % 5 == 0:
print(num)
total += num
>>> total
233168
While a for loop would work, you could also use a generator expression and sum:
sum(n for n in range(1000) if n % 3 == 0 or n % 5 == 0)
def sum_multiply (n):
data = []
for num in range (1, n):
if num % 3 == 0 or num % 5 == 0:
data.append(num)
return sum(data)
sum_multiply(1000)
total=0
i=0
while i<1000:
if i%3==0 or i%5==0:
print(num)
total+=i
i+=1
print("Total is: ")
**with python**
print(sum([i for i in range(1,1000) if i%3==0 or i%5==0 ]))
Here's the problem: I try to randomize n times a choice between two elements (let's say [0,1] -> 0 or 1), and my final list will have n/2 [0] + n/2 [1]. I tend to have this kind of result: [0 1 0 0 0 1 0 1 1 1 1 1 1 0 0, until n]: the problem is that I don't want to have serially 4 or 5 times the same number so often. I know that I could use a quasi randomisation procedure, but I don't know how to do so (I'm using Python).
To guarantee that there will be the same number of zeros and ones you can generate a list containing n/2 zeros and n/2 ones and shuffle it with random.shuffle.
For small n, if you aren't happy that the result passes your acceptance criteria (e.g. not too many consecutive equal numbers), shuffle again. Be aware that doing this reduces the randomness of the result, not increases it.
For larger n it will take too long to find a result that passes your criteria using this method (because most results will fail). Instead you could generate elements one at a time with these rules:
If you already generated 4 ones in a row the next number must be zero and vice versa.
Otherwise, if you need to generate x more ones and y more zeros, the chance of the next number being one is x/(x+y).
You can use random.shuffle to randomize a list.
import random
n = 100
seq = [0]*(n/2) + [1]*(n-n/2)
random.shuffle(seq)
Now you can run through the list and whenever you see a run that's too long, swap an element to break up the sequence. I don't have any code for that part yet.
Having 6 1's in a row isn't particularly improbable -- are you sure you're not getting what you want?
There's a simple Python interface for a uniformly distributed random number, is that what you're looking for?
Here's my take on it. The first two functions are the actual implementation and the last function is for testing it.
The key is the first function which looks at the last N elements of the list where N+1 is the limit of how many times you want a number to appear in a row. It counts the number of ones that occur and then returns 1 with (1 - N/n) probability where n is the amount of ones already present. Note that this probability is 0 in the case of N consecutive ones and 1 in the case of N consecutive zeros.
Like a true random selection, there is no guarantee that the ratio of ones and zeros will be the 1 but averaged out over thousands of runs, it does produce as many ones as zeros.
For longer lists, this will be better than repeatedly calling shuffle and checking that it satisfies your requirements.
import random
def next_value(selected):
# Mathematically, this isn't necessary but it accounts for
# potential problems with floating point numbers.
if selected.count(0) == 0:
return 0
elif selected.count(1) == 0:
return 1
N = len(selected)
selector = float(selected.count(1)) / N
if random.uniform(0, 1) > selector:
return 1
else:
return 0
def get_sequence(N, max_run):
lim = min(N, max_run - 1)
seq = [random.choice((1, 0)) for _ in xrange(lim)]
for _ in xrange(N - lim):
seq.append(next_value(seq[-max_run+1:]))
return seq
def test(N, max_run, test_count):
ones = 0.0
zeros = 0.0
for _ in xrange(test_count):
seq = get_sequence(N, max_run)
# Keep track of how many ones and zeros we're generating
zeros += seq.count(0)
ones += seq.count(1)
# Make sure that the max_run isn't violated.
counts = [0, 0]
for i in seq:
counts[i] += 1
counts[not i] = 0
if max_run in counts:
print seq
return
# Print the ratio of zeros to ones. This should be around 1.
print zeros/ones
test(200, 5, 10000)
Probably not the smartest way, but it works for "no sequential runs", while not generating the same number of 0s and 1s. See below for version that fits all requirements.
from random import choice
CHOICES = (1, 0)
def quasirandom(n, longest=3):
serial = 0
latest = 0
result = []
rappend = result.append
for i in xrange(n):
val = choice(CHOICES)
if latest == val:
serial += 1
else:
serial = 0
if serial >= longest:
val = CHOICES[val]
rappend(val)
latest = val
return result
print quasirandom(10)
print quasirandom(100)
This one below corrects the filtering shuffle idea and works correctly AFAICT, with the caveat that the very last numbers might form a run. Pass debug=True to check that the requirements are met.
from random import random
from itertools import groupby # For testing the result
try: xrange
except: xrange = range
def generate_quasirandom(values, n, longest=3, debug=False):
# Sanity check
if len(values) < 2 or longest < 1:
raise ValueError
# Create a list with n * [val]
source = []
sourcelen = len(values) * n
for val in values:
source += [val] * n
# For breaking runs
serial = 0
latest = None
for i in xrange(sourcelen):
# Pick something from source[:i]
j = int(random() * (sourcelen - i)) + i
if source[j] == latest:
serial += 1
if serial >= longest:
serial = 0
guard = 0
# We got a serial run, break it
while source[j] == latest:
j = int(random() * (sourcelen - i)) + i
guard += 1
# We just hit an infinit loop: there is no way to avoid a serial run
if guard > 10:
print("Unable to avoid serial run, disabling asserts.")
debug = False
break
else:
serial = 0
latest = source[j]
# Move the picked value to source[i:]
source[i], source[j] = source[j], source[i]
# More sanity checks
check_quasirandom(source, values, n, longest, debug)
return source
def check_quasirandom(shuffled, values, n, longest, debug):
counts = []
# We skip the last entries because breaking runs in them get too hairy
for val, count in groupby(shuffled):
counts.append(len(list(count)))
highest = max(counts)
print('Longest run: %d\nMax run lenght:%d' % (highest, longest))
# Invariants
assert len(shuffled) == len(values) * n
for val in values:
assert shuffled.count(val) == n
if debug:
# Only checked if we were able to avoid a sequential run >= longest
assert highest <= longest
for x in xrange(10, 1000):
generate_quasirandom((0, 1, 2, 3), 1000, x//10, debug=True)