Как сгенерировать выборку x и y с условной вероятностью с NumPy - PullRequest
2 голосов
/ 03 апреля 2020

Я пытаюсь сгенерировать образец x и их меток - y для двоичного классификатора.

Я знаю, что мои x равномерно распределены в [0,1]. Но распределение моего y получено по моим x: if x in [0.2, 0.4] or in [0.6, 0.8] - P[Y=1] = 0.1. Если x находится вне этих границ, то P[Y=1] = 0.8.

Я думаю, что лучший способ сделать это - использовать NumPy (а не использовать for-loop и if-условие), но до сих пор я не делал не удалось.

Это моя попытка:

s = np.random.uniform(0,1,100) # 100 x samples in [0,1] uniformly distributed
condition  = (np.logical_or((s>0.2)&(s < 0.4), (s>0.6)&(s < 0.8))) # attempt to mark with True the places of x in bounds.
x_in_bounds = np.select(condlist, s) # this line doesn't work
... # how to generate the y values?

Я безуспешно пытаюсь найти способ случайного генерирования значений y в соответствии с условиями в выборке значений x. Я бы хотел понять, чего мне не хватает.

Ответы [ 3 ]

1 голос
/ 03 апреля 2020

Решение, использующее тот же подход, который вы используете, будет выглядеть следующим образом:

generate = lambda prob: 1 if np.random.rand() < prob else 0

s = np.random.uniform(0, 1, 100)
low_prob_condition = ((s > 0.2) & (s < 0.4)) | ((s > 0.6) & (s < 0.8))
condlist = [low_prob_condition, np.logical_not(low_prob_condition)] 
labels = np.select(condlist, [[generate(0.1) for _ in range(s.size)], [generate(0.8) for _ in range(s.size)]])

print(labels)

Вывод:

[1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0
 1 1 0 0 1 0 1 1 1 0 0 1 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 1 1 0 1 0 0 0 1 0 0
 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 1 1 1 0 1 0 0 1 1]

Но более эффективное по времени и пространству решение будет:

s = np.random.uniform(0, 1, 100)
low_prob_cond = lambda x: ((x > 0.2) and (x < 0.4)) or ((x > 0.6) and (x < 0.8))
gen = lambda prob: 1 if np.random.rand() < prob else 0
labels = (gen(0.1) if low_prob_cond(x) else gen(0.8) for x in s)

print(list(labels))

Вывод:

[0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1]

np.select запрашивает список того же размера с s в качестве списка выбора для каждого условия (в вашем случае два), этого, очевидно, можно избежать в вашем проблема.

1 голос
/ 03 апреля 2020

Для решения, использующего ваш подход, см. Ответ @adnanmuttaleb.

Мой подход для этого будет использовать расширенную индексацию numpy:

x = np.random.uniform(0, 1, 100)

cond = ((x > 0.2) & (x < 0.4)) | ((x > 0.6) & (x < 0.8))
not_cond = np.logical_not(cond)

y = np.random.rand(*x.shape)
y[cond] = y[cond] < 0.1
y[not_cond] = y[not_cond] < 0.8
y = y.astype(int)
1 голос
/ 03 апреля 2020

Одним из способов может быть генерирование двух случайных последовательностей, заполненных либо 1, либо 0 в соответствии с обоими упомянутыми случаями. Затем используйте np.where для выбора одного или другого в зависимости от condition:

s = np.random.uniform(0,1,100)
condition  = np.logical_or((s>0.2)&(s < 0.4), (s>0.6)&(s < 0.8))

repl_a = (np.random.random(len(s))>0.9).view('i1')
repl_b = (np.random.random(len(s))>0.2).view('i1')

np.where(condition, repl_a, repl_b)

array([1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1,
       0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0,
       1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1,
       0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0], dtype=int8)
...