0

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 Ts 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 
7
  • I edited my post. I hope it is clearer now. Commented Jul 17, 2018 at 6:52
  • Is this function supposed to be a generator that counts T up in 0.5 steps or is the range for T a given at the start (e.g., 0.5<=T<=1234.5)? Commented Jul 17, 2018 at 7:00
  • The T range could be anything, it doesn't matter. I mean, we don't really need to take T into account really, I just want to generate the values based on T. You can generate T as a list pretty easily. Commented Jul 17, 2018 at 7:02
  • what do you mean by "I want to pick a random year and..."? Commented Jul 17, 2018 at 8:32
  • 1
    Do you want exactly one "special" T in the first batch of 100, another in the second batch of 100, etc., or should the probability for each T to spe "special" be 1%? Commented Jul 17, 2018 at 8:54

3 Answers 3

1

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.

EDIT (based on the comments)

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) 
Sign up to request clarification or add additional context in comments.

7 Comments

´T´ is predefined. The solution you have proposed will pick a value between 15 and 16 when ´T´ is a multiple of 100. I want to be able to randomly select one ´T´ from 1 to 100 where the ´Value´ is between 15 and 16.
If I understood correctly, you want that a for a single random number T in the (1, 100) range, the offset must be set to 15, and similarly for T in the (1, 10) range with offset of 5.
If you need the random "magic number" to be update for every group of 10 (or 100) number of T, you must write in the form of a generator, but then it cannot be a "function", or you update it a posteriori.
I hope the last edits have given you enough information to move forward. I believe this gives you the data the way you described them so far. I am not quite sure what do you mean by "change in randomness". This was not mentioned in the original question.
Yes, thank you for your help! You have given me more than enough to move forward. By 'change in randomness', I mean that I generate a random number between 5 and 6 instead of the usual 2 and 3.
|
0

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.

Comments

0

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 Nth number, with an offset of K.

4 Comments

Nope. This would generate a value between 15 & 16 when T=100. I want a random function to pick the T value where the value should lie between 15 and 16.
So instead of 0, 100, 200... being mapped to (15,16), you want something arbitrary like 27, 193, 254... ?
Yes. The same thing with the mapping between (5,6). I would like something like 4,17,29,33... to be mapped to (5,6).
You could generate two random numbers r1 and r2 between 0 and 10 or 100 respectively, and then check if T % 100 == r2 and generate a new value for r2 afterwards (and same for r1)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.