Reputation: 596
I have a column T
, which decides the range of the value in the value column.
T
is incremented in steps of 0.5 and always has 4 occurrences.
If T=0.5,1.5,2.5
etc., I want to generate a random number between 1 and 2.
If T=1,2,3,4
etc., I want to generate a random number between 2 and 3.
^This is the easy bit, switching the random generator or generating the random numbers separately and ordering them should do the trick.
However, once in every 10 integer T
s i.e. 1,2,3,4...10
, I want a random function to pick a random T
and set the value between 5 and 6, instead of 2 and 3.
Similarly, once in every 100 integer values of T
, I want to pick a random T
and make the Value
column to be between 15 and 16.
T Value
0.5 1.01
0.5 1.05
0.5 1.85
0.5 1.49
1 2.45
1 2.52
1 2.48
1 2.95
1.5 1.78
1.5 1.45
1.5 1.65
1.5 1.77
2 2.96
2 2.75
2 2.74
2 2.95
2.5 1.75
2.5 7.89
2.5 1.33
2.5 1.58
3 5.78
3 5.44
3 5.36
3 5.24
Upvotes: 0
Views: 276
Reputation: 26886
I would do it this way:
(EDIT: I changed the last two conditions as they were actually redundant.)
(EDIT2: I updated so that the 10/100 offset change happen randomly - but set once at the definition of the function.)
import random
def rand_gen_t(
t,
n0=random.randint(1, 100),
n1=random.randint(1, 10)):
if t % n0 == 0:
offset = 15
elif t % n1 == 0:
offset = 5
elif t % 1 == 0:
offset = 1
elif t % 0.5 == 0:
offset = 2
return offset + random.random()
Compared to the solution proposed by @DillonDavis it would work for arbitrary t
as long as it is a half-integer value, and it is assuming that the range you are interested in is always of size 1, and all is changing is the offset (which is true based on the content of your question).
I'll leave to you to define what should be done for other input values.
And if you want this to be able to cope with numpy.ndarray
as your tagging suggests, I would just use the np.vectorize
function decorator, e.g.:
import numpy as np
rand_gen_t_arr = np.vectorize(rand_gen_t)
Time-wise, the proposed Numpy's solution would not really shine here, but is not that bad either:
%timeit [rand_gen_t(x / 2) for x in range(1000)]
# 1000 loops, best of 3: 490 µs per loop
%timeit rand_gen_t_arr(np.arange(1000) / 2)
# 1000 loops, best of 3: 523 µs per loop
Perhaps using np.where()
is faster, but I would not expect that, since you would probably have (hidden) a loop for each condition in that way.
If you want this to be be more flexible, you could try something like (assuming you have a predefined array t_arr
, containing the value of T
):
import numpy as np
# I assume that you have it somehow, but I generate one for completeness
t_arr = np.arange(1, 1000) / 2
# first generate random numbers between 0 and 1
val_arr = np.random.random(t_arr.shape)
# update for values of `T`
int_mask = np.where(t_arr % 1 == 0)[0]
half_int_mask = np.where(t_arr % 0.5 == 0)[0]
int_offset = 1
half_int_offset = 2
val_arr[int_mask] += int_offset
val_arr[half_int_mask] += half_int_offset
# update `Value` for exceptional cases
def gen_special_mask(n_special, n_max):
return np.random.randint(1, n_special, int(n_max / n_special)) + np.arange(0, n_max, n_special)
def mask_intersect(mask1, mask2):
return np.array(list(set(mask1).intersection(set(mask2))))
special_mask10 = gen_special_mask(10, val_arr.size)
special10_offset = 5
special_mask100 = gen_special_mask(100, val_arr.size)
special100_offset = 10
special_mask10_int = mask_intersect(int_mask, special_mask10)
val_arr[special_mask10_int] += (special10_offset - int_offset)
special_mask10_half_int = mask_intersect(half_int_mask, special_mask10)
val_arr[special_mask10_half_int] += (special10_offset - half_int_offset)
special_mask100_int = mask_intersect(int_mask, special_mask10)
val_arr[special_mask100_int] += (special100_offset - int_offset)
special_mask100_half_int = mask_intersect(half_int_mask, special_mask10)
val_arr[special_mask100_half_int] += (special100_offset - half_int_offset)
Upvotes: 1
Reputation: 7740
I believe you are looking for something like the following:
from random import random
def rand(T):
bounds = None
if T % 100 == 0:
bounds = (15, 16)
elif T % 10 == 0:
bounds = (5, 6)
elif T in [1, 2, 3]:
bounds = (2, 3)
elif T in [0.5, 1.5, 2.5]:
bounds = (1, 2)
lower, upper = bounds
return random() * (upper - lower) + lower
You can use the T in [...]
syntax to support arbitrary lists of numbers, and T % N == K
to support every N
th number, with an offset of K
.
Upvotes: 0
Reputation: 51
If I'm understanding you right, I think it sounds like you want to use a switch case. Just run the first random function, and then setup a switch that runs another random function (and this second random function varies based on the first result).
As you're working in Python, this switch might be better suited to being just a series of if statements, or you can see documentation about other example implementations in this article. Just make your functions that it maps to include the second random function inside them.
Upvotes: 0