0

I am quite new in this and I am trying to learn on my own. As I said in the title, I am trying to create a list of 100 numbers whose elements are either 50% chance of being 0's or 50% change being a number between 0 and 1. I made it like the one below. It works but it is a very tedious and not well coded program. Any hints of how to make to make it better?

import random
import numpy as np

#define a list of 100 random numbers between 0 and 1
randomlist = []
for i in range(0,100):
    n = random.uniform(0,1)
    randomlist.append(n)
print(randomlist)


#create a list of 100 numbers of 0's and 1's
def random_binary_string(length):
    
    sample_values = '01' # pool of strings
    result_str = ''.join((random.choice(sample_values) for i in range(length)))
    return (result_str)

l=100
x=random_binary_string(l)
x1=np.array(list(map(int, x)))
print(x1)


#combine both lists. Keep value if of the binary list if it is equal to zero. Else, substitute it by the value of randomlist
#corresponding to the index position
finalist=[]
for i in range(len(x1)):
    if x1[i]==0:
        finalist.append(x1[i])
    else:
        finalist.append(randomlist[i])
        
print(finalist)    

Thanks a lot!

5 Answers5

2

You can simplify your code by nesting the two conditions. This avoids the need to keep two separate lists in memory and then merge them at the end.

randomlist = []
for i in range(0,100):
    if random.choice((0, 1)) == 1:
        randomlist.append(random.uniform(0,1))
    else:
        randomlist.append(0)

This is simple and succinct enough that you can refactor it to a single list comprehension. This is more compact but somewhat less legible.

randomlist = [random.uniform(0,1) if random.choice((0, 1)) else 0 for i in range(0,100)]

Here, we also shorten the code slightly by exploiting the fact that 0 is falsey and 1 is truthy in Python; i.e. they evaluate to False and True, respectively, in a boolean context. So if random.choice((0, 1)) == 1 can be abbreviated to simply if random.choice((0, 1)).

Somewhat obscurely, you can further simplify this (in the sense, use less code) by observing that the expression B if not A else A can be short-circuited into the expression A and B. This is not very obvious if you are not very familiar with boolean logic, but I think you can work it out on paper.

randomlist = [random.choice((0, 1)) and random.uniform(0,1) for i in range(0,100)]

Demo: https://ideone.com/uGHS2Y

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • `[random.getrandbits(1) and random.uniform(0, 1) for i in range(100)]` should be significantly faster. – Olvin Roght Feb 23 '21 at 10:30
  • Thanks. I guess it won't matter much for 100 numbers, but it's certainly a useful optimization if you need several thousand. – tripleee Feb 23 '21 at 10:54
0

You could try doing something like this:

import random


def create_random_list():
    random_list = list()

    for _ in range(100):
        if random.choice((True, False)):
            random_list.append(0)
        else:
            random_list.append(random.uniform(0, 1))

    return random_list


randomly_generated_list = create_random_list()
print(len(randomly_generated_list), randomly_generated_list)
# 100 [x_0,...,x_99]
jån
  • 165
  • 1
  • 9
0

I propose this method:

  • first generate a random list of 'A', and 'B' with random.choice. 50% 'A' and 50% 'B'
  • then replace 'A' by random number between 0 and 1
  • and replace 'B' by 0

code here:

import random

ll = [ random.choice(['A', 'B'])  for x in range(200)]
print(ll, len(ll))

for i in range(len(ll)):
    if ll[i] == 'A':
        ll[i]=random.random()
    else:
        ll[i]=0

print(ll, len(ll))

Shorter code here:

import random
ll = [ random.choice([0, random.random()])  for x in range(200)]
print(ll, len(ll), ll.count(0))
Malo
  • 1,233
  • 1
  • 8
  • 25
0

Since you are using Numpy, I probably would do what follow:

  1. Create the array of num_el elements using random.uniform
    • Consider if the problem of the excluded upper bound: [low, high)
  2. Create a boolean matrix with probability p=0.5 between true and false: random.choice
  3. Use the matrix to set some elements of the array to zero, by

That's the code:

num_el = 10
p = 0.5

res = np.random.uniform(0., 1., size=(1, num_el))
bool_mat = np.random.choice(a=[False, True], size=(1, num_el), p=[p, 1-p])
res[bool_mat] = 0.

res  
# array([[0.        , 0.51213168, 0.        , 0.68230528, 0.5287728 ,
#         0.9072587 , 0.        , 0.43078057, 0.89735872, 0.        ]])
iGian
  • 11,023
  • 3
  • 21
  • 36
0

The approach to use depends on whether your objective is to get exactly half of the outcomes to be zeroes, or have the expected number of zeros be half the total. It wasn't clear from your question which way you viewed the problem, so I've implemented both approaches as functions.

If you want a deterministic fixed proportion of zeroes/non-zeroes, the first function in the code below will do the trick. It creates a list with the desired number of zeros and non-zeros, and then uses shuffling (which I timed to be faster than sampling). If you want exactly half, then obviously the argument n has to be even.

If your goal is a probabilistic 50% zeroes, use the second function.

import random

# Exactly floor(n / 2) outcomes are zeros, i.e., exactly half when n is even.
# This version is trivial to modify to give any desired proportion of zeros.
def make_rand_list_v1(n = 100):
    m = n // 2
    n -= m
    ary = [random.random() for _ in range(n)] + [0] * m
    random.shuffle(ary)
    return ary

# Each outcome has probability 0.5 of being zero
def make_rand_list_v2(n = 100):
    return [random.getrandbits(1) and random.uniform(0, 1) for _ in range(n)]
pjs
  • 18,696
  • 4
  • 27
  • 56