Двоичный случайный массив с определенной долей единиц?

Каков эффективный (вероятно, векторизованный с использованием терминологии Matlab) способ генерации случайного числа нулей и единиц с определенной пропорцией? Специально с Numpy?

Поскольку мой случай особенный для 1/3, мой код:

import numpy as np 
a=np.mod(np.multiply(np.random.randomintegers(0,2,size)),3)

Но есть ли какая-нибудь встроенная функция, которая могла бы справиться с этим более эффективно, по крайней мере, для ситуации K/N, где K и N — натуральные числа?


person Cupitor    schedule 25.10.2013    source источник
comment
Вам нужно, чтобы пропорция была точно заданной, или это всего лишь ожидаемая пропорция выборки?   -  person Warren Weckesser    schedule 25.10.2013
comment
Кроме того, что должно произойти для случая 1/3, когда size не делится на 3? Исключение? Круглый/пол/корпус? Взвешенный случайный раунд (таким образом, 10 имеет шанс 2/3 на 3 и шанс 1/3 на 4)?   -  person abarnert    schedule 25.10.2013
comment
@WarrenWeckesser, в моем случае это ожидаемая пропорция. Я хотел бы, чтобы вы не удалили свой ответ, поэтому я бы принял его.   -  person Cupitor    schedule 25.10.2013
comment
@abarnert, это был ожидаемый случай!   -  person Cupitor    schedule 25.10.2013
comment
@Naji: я восстановил свой ответ. Если бы вам нужна была точная пропорция, этот метод не сработал бы.   -  person Warren Weckesser    schedule 25.10.2013
comment
@WarrenWeckesser, и я принял это! Ну, даже мой метод не был точным, так как я сначала делаю случайную последовательность!   -  person Cupitor    schedule 25.10.2013
comment
@Naji: Биномиальная или другая функция случайного распределения не даст вам шанс 2/3 на 3 и шанс 1/3 на 4; это даст вам высокий шанс 3, более низкий шанс 4, еще более низкий шанс 2, еще более низкий шанс 5 и т. д. Это то, что вы хотели?   -  person abarnert    schedule 25.10.2013
comment
@abarnert, биномиальная выборка с N = 2 и p = ratio будет генерировать все, что я хочу, я верю!   -  person Cupitor    schedule 26.10.2013
comment
@Naji: Спасибо, но я думаю, что ответ @Jaime мне нравится больше, чем мой. Это кажется еще более явным. Для произвольной пропорции frac просто используйте p=[1-frac, frac].   -  person Warren Weckesser    schedule 26.10.2013
comment
@Наджи: Что хочешь? Я хотел, чтобы он принес триллион долларов, и все, что он дал мне, — это массив. Наверное, я недостаточно сильно верю. ;)   -  person abarnert    schedule 26.10.2013
comment
@abarnert, ха-ха-ха! Неплохо! ну вы понимаете о чем я :)   -  person Cupitor    schedule 26.10.2013
comment
@WarrenWeckesser, тогда Оскар достается Хайме! :D   -  person Cupitor    schedule 26.10.2013


Ответы (6)


Если я правильно понимаю вашу проблему, вы можете получить помощь с numpy.random.shuffle

>>> def rand_bin_array(K, N):
    arr = np.zeros(N)
    arr[:K]  = 1
    np.random.shuffle(arr)
    return arr

>>> rand_bin_array(5,15)
array([ 0.,  1.,  0.,  1.,  1.,  1.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,
        0.,  0.])
person Abhijit    schedule 25.10.2013

Еще один подход с использованием np.random.choice:

>>> np.random.choice([0, 1], size=(10,), p=[1./3, 2./3])
array([0, 1, 1, 1, 1, 0, 0, 0, 0, 0])
person Jaime    schedule 25.10.2013
comment
обратите внимание, что этот подход не даст вам точную пропорцию нулей и единиц, которую вы запрашиваете. . . ответ @mdml ниже будет. - person dbliss; 14.08.2018
comment
верно, и поскольку это принято, я думаю, что Cupitor мог добавить ошибку в свою программу - person JFFIGK; 02.12.2019
comment
@JFFIGK, dbliss: это обсуждалось в комментариях к вопросу. Эти комментарии все еще там, так что посмотрите. - person Warren Weckesser; 03.12.2019

Простым способом сделать это было бы сначала сгенерировать ndarray с пропорцией нулей и единиц, которую вы хотите:

>>> import numpy as np
>>> N = 100
>>> K = 30 # K zeros, N-K ones
>>> arr = np.array([0] * K + [1] * (N-K))
>>> arr
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1])

Затем вы можете просто shuffle массив, сделав распределение случайным:

>>> np.random.shuffle(arr)
>>> arr
array([1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0,
       1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1,
       1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
       0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
       1, 1, 1, 0, 1, 1, 1, 1])

Обратите внимание, что этот подход даст вам точную пропорцию нулей/единиц, которые вы запрашиваете, в отличие, скажем, от биномиального подхода. Если вам не нужна точная пропорция, то подойдет биномиальный подход.

person mdml    schedule 25.10.2013
comment
Как глупо с моей стороны! Правильно, я забыл о бинарном распространении. На самом деле кто-то разместил бинарный файл прямо перед вами, но он удалил свой ответ (не знаю почему !!) - person Cupitor; 25.10.2013
comment
Это довольно умно - person mxmlnkn; 15.06.2019

Вы можете использовать numpy.random.binomial. Например. предположим, что frac - это доля единиц:

In [50]: frac = 0.15

In [51]: sample = np.random.binomial(1, frac, size=10000)

In [52]: sample.sum()
Out[52]: 1567
person Warren Weckesser    schedule 25.10.2013
comment
Это не гарантирует правильную пропорцию, как это делает ответ mdml. - person Epimetheus; 03.12.2019
comment
@Джон, это обсуждалось в комментариях к вопросу. Взглянем. - person Warren Weckesser; 03.12.2019
comment
Я вижу сейчас! Конечно, тогда вопрос нуждается в редактировании, поскольку он требует определенной пропорции. - person Epimetheus; 04.12.2019

Другой способ получить точное количество единиц и нулей — это выборка индексов без замены с использованием np.random.choice:

arr_len = 30
num_ones = 8

arr = np.zeros(arr_len, dtype=int)
idx = np.random.choice(range(arr_len), num_ones, replace=False)
arr[idx] = 1

Вне:

arr

array([0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1,
       0, 0, 0, 0, 0, 1, 0, 0])
person joelostblom    schedule 27.03.2019

Простой однострочник: вы можете избежать использования списков целых чисел и вероятностных распределений, которые, на мой взгляд, являются неинтуитивными и излишними для этой проблемы, просто работая сначала с bools, а затем при необходимости приводя к int (хотя оставляя его как массив bool следует работают в большинстве случаев).

>>> import numpy as np
>>> np.random.random(9) < 1/3.
array([False,  True,  True,  True,  True, False, False, False, False])   
>>> (np.random.random(9) < 1/3.).astype(int)
array([0, 0, 0, 0, 0, 1, 0, 0, 1])    
person Galactic Ketchup    schedule 01.08.2018
comment
Это не гарантирует правильную пропорцию, как это делает ответ mdml. - person Epimetheus; 03.12.2019
comment
ОП сказал, что они хотят, чтобы 1/3 была ожидаемой пропорцией единиц, а не точной пропорцией. - person Galactic Ketchup; 04.12.2019