Próbuję wygenerować próbkę x i ich etykiet - y, dla klasyfikatora binarnego.

Wiem, że moje x są równomiernie rozmieszczone w [0,1]. Ale rozkład mojego y uzyskany przez moje x: if x in [0.2, 0.4] or in [0.6, 0.8] - P[Y=1] = 0.1. Jeśli x jest poza tymi granicami, to P[Y=1] = 0.8.

Myślę, że najlepszym sposobem na to jest użycie NumPy (a nie używanie pętli for i warunku-if), ale do tej pory mi się to nie udało.

To jest moja próba:

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?

Próbuję bez powodzenia znaleźć sposób na losowe generowanie wartości y zgodnie z warunkami na próbce wartości x. Chciałbym zrozumieć, czego mi brakuje.

2
Yanirmr 3 kwiecień 2020, 13:23

3 odpowiedzi

Najlepsza odpowiedź

Aby znaleźć rozwiązanie wykorzystujące twoje podejście, zobacz odpowiedź @adnanmuttaleb.

Moim podejściem do tego byłoby użycie zaawansowanego indeksowania 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
idow09 3 kwiecień 2020, 12:34

Jednym ze sposobów mogłoby być wygenerowanie dwóch losowych sekwencji wypełnionych 1 lub 0 zgodnie z obydwoma wymienionymi przypadkami. Następnie użyj np.where, aby wybrać jedną lub drugą w zależności od 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)
1
yatu 3 kwiecień 2020, 10:35

Rozwiązaniem wykorzystującym to samo podejście, którego używasz, byłoby:

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)

Wynik:

[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]

Jednak rozwiązanie zapewniające większą oszczędność czasu i miejsca to:

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))

Wynik:

[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 wymaga listy tego samego rozmiaru z s jako listą wyboru dla każdego warunku (w twoim przypadku dwa), można tego oczywiście uniknąć w swoim problemie.

1
adnanmuttaleb 3 kwiecień 2020, 12:18