заполнение массива numpy случайным элементом из другого массива

Я не уверен, если это возможно, но здесь идет. Предположим у меня есть массив:

array1 = [0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1]

и теперь я хотел бы создать массив numpy 1D, состоящий из 5 элементов, которые случайным образом извлекаются из array1 и с условием, что сумма равна 1. Пример-что-то вроде массива numpy, который выглядит как [.2,.2,.2,.1,.1].

  • в настоящее время я использую случайный модуль и функцию выбора, которая выглядит так: range1= np.array([choice(array1),choice(array1),choice(array1),choice(array1),choice(array1)]) затем проверьте range1, чтобы узнать, соответствует критериям; мне интересно, есть ли более быстрый способ, что - то похожее на .

  • было бы еще лучше, если бы я мог хранить этот массив в некоторой библиотеке, так что если я попытаюсь создать 100 такого массива, то нет повторения, но это не обязательно.

3 ответов


можно использовать numpy.random.choice если вы используете numpy 1.7.0+:

>>> import numpy as np
>>> array1 = np.array([0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1])
>>> np.random.choice(array1, 5)
array([ 0. ,  0. ,  0.3,  1. ,  0.3])
>>> np.random.choice(array1, 5, replace=False)
array([ 0.6,  0.8,  0.1,  0. ,  0.4])

чтобы получить 5 элементов, сумма которых равна 1,

  • сгенерировать 4 случайных чисел.
  • вычесть сумму 4 чисел из 1 - > x
  • если x включен в array1, используйте это как окончательное число; или повторите

>>> import numpy as np
>>> 
>>> def solve(arr, total, n):
...     while True:
...         xs = np.random.choice(arr, n-1)
...         remain = total - xs.sum()
...         if remain in arr:
...             return np.append(xs, remain)
... 
>>> array1 = np.array([0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1])
>>> print solve(array1, 1, 5)
[ 0.1  0.3  0.4  0.2  0. ]

другая версия (предположим, что данный массив отсортирован):

EPS = 0.0000001
def solve(arr, total, n):
    while True:
        xs = np.random.choice(arr, n-1)
        t = xs.sum()
        i = arr.searchsorted(total - t)
        if abs(t + arr[i] - total) < EPS:
            return np.append(xs, arr[i])

Я должен был сделать что-то подобное некоторое время назад.

def getRandomList(n, source):
    '''
    Returns a list of n elements randomly selected from source.
    Selection is done without replacement.

    '''

    list = source
    indices = range(len(source))
    randIndices = []
    for i in range(n):
        randIndex = indices.pop(np.random.randint(0, high=len(indices)))
        randIndices += [randIndex]

    return [source[index] for index in randIndices]


data = [1,2,3,4,5,6,7,8,9]
randomData = getRandomList(4, data)
print randomData

если вы не заботитесь о порядке значений в выходных последовательностях, количество 5-значных комбинаций значений из вашего списка, которые складываются в 1, довольно мало. В конкретном случае, который вы предложили, это немного сложно вычислить, так как значения с плавающей запятой имеют проблемы округления. Вы можете легко решить проблему, если используете набор целых чисел (например,range(11))и найти комбинации, которые добавляют до 10. Затем, если вам нужны дробные значения, просто разделите значения в результаты по 10.

в любом случае, вот генератор, который дает все возможные наборы, которые складываются в заданное значение:

def picks(values, n, target):
    if n == 1:
        if target in values:
            yield (target,)
        return
    for i, v in enumerate(values):
        if v <= target:
            for r in picks(values[i:], n-1, target-v):
                yield (v,)+r

здесь результаты для чисел от нуля до десяти:

>>> for r in picks(range(11), 5, 10):
    print(r)

(0, 0, 0, 0, 10)
(0, 0, 0, 1, 9)
(0, 0, 0, 2, 8)
(0, 0, 0, 3, 7)
(0, 0, 0, 4, 6)
(0, 0, 0, 5, 5)
(0, 0, 1, 1, 8)
(0, 0, 1, 2, 7)
(0, 0, 1, 3, 6)
(0, 0, 1, 4, 5)
(0, 0, 2, 2, 6)
(0, 0, 2, 3, 5)
(0, 0, 2, 4, 4)
(0, 0, 3, 3, 4)
(0, 1, 1, 1, 7)
(0, 1, 1, 2, 6)
(0, 1, 1, 3, 5)
(0, 1, 1, 4, 4)
(0, 1, 2, 2, 5)
(0, 1, 2, 3, 4)
(0, 1, 3, 3, 3)
(0, 2, 2, 2, 4)
(0, 2, 2, 3, 3)
(1, 1, 1, 1, 6)
(1, 1, 1, 2, 5)
(1, 1, 1, 3, 4)
(1, 1, 2, 2, 4)
(1, 1, 2, 3, 3)
(1, 2, 2, 2, 3)
(2, 2, 2, 2, 2)

вы можете выбрать один из них наугад (с random.choice), или если вы планируете использовать многие из них, и вы не хотите повторяться, вы можете использовать random.shuffle, потом перебирать.

results = list(picks(range(11), 5, 10))
random.shuffle(results)

for r in results:
    # do whatever you want with r