2017-01-15 2 views
4

Я хотел бы иметь возможность генерировать случайные числа с функцией плотности вероятности, которая исходит из рисованной кривой. Эти два ниже имеют одну и ту же площадь под кривой, но должны создавать списки случайных чисел с различными характеристиками.Генерация случайных чисел из произвольной функции плотности вероятности

enter image description here

Моя интуиция является то, что один из способов будет сделать это, чтобы попробовать кривую, а затем использовать участки этих прямоугольников кормить np.random.choice, чтобы выбрать диапазон, чтобы сделать обычный случайный в диапазоне диапазона этого прямоугольника.

enter image description here

Это не чувствует, как очень эффективный способ сделать это. Есть ли более «правильный» способ сделать это?

я имел трещины на самом деле делать это:

import matplotlib.pyplot as plt 
import numpy as np 

areas = [4.397498, 4.417111, 4.538467, 4.735034, 4.990129, 5.292455, 5.633938, 
     6.008574, 6.41175, 5.888393, 2.861898, 2.347887, 2.459234, 2.494357, 
     2.502986, 2.511614, 2.520243, 2.528872, 2.537501, 2.546129, 7.223747, 
     7.223747, 2.448148, 1.978746, 1.750221, 1.659351, 1.669999] 
divisons = [0.0, 0.037037, 0.074074, 0.111111, 0.148148, 0.185185, 0.222222, 
      0.259259, 0.296296, 0.333333, 0.37037, 0.407407, 0.444444, 0.481481, 
      0.518519, 0.555556, 0.592593, 0.62963, 0.666667, 0.703704, 0.740741, 
      0.777778, 0.814815, 0.851852, 0.888889, 0.925926, 0.962963, 1.0] 
weights = [a/sum(areas) for a in areas] 
indexes = np.random.choice(range(len(areas)), 50000, p=weights) 
samples = [] 
for i in indexes: 
    samples.append(np.random.uniform(divisons[i], divisons[i+1])) 

binwidth = 0.02 
binSize = np.arange(min(samples), max(samples) + binwidth, binwidth) 
plt.hist(samples, bins=binSize) 
plt.xlim(xmax=1) 
plt.show() 

enter image description here

метод, кажется, работает, но немного тяжеловат!

+0

Вы говорите, что у вас есть файл изображения с этой кривой? Или у вас на самом деле есть числа, представляющие координаты точек на кривой? – BrenBarn

+0

Это может быть и то.Это может быть файл изображения, но, скорее, рисованная кривая. Либо svg, либо какая-то чернильная вещь на сенсорном экране. – Ben

+0

SVG - файл изображения. Если он нарисован на экране, то как ваша программа обращается к нему? Я спрашиваю, какой формат * данных * будет использовать ваша программа, а не как создать эту вещь ». – BrenBarn

ответ

2

Один из способов сделать это является использование rv_continuous из scipy.stats. Прямым способом начать было бы приблизиться к одному из этих pdf-файлов с набором сплайнов с rv_continuous. Фактически, вы можете генерировать псевдослучайные отклонения, определяя либо PDF, либо cdf с этой вещью.

3

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

Но поскольку вы просто пытаетесь генерировать случайные числа из этого дистрибутива, вы можете использовать нормализованные значения y (суммировать y-позицию всех пикселей и делить на общее число) в качестве вероятности_распределения непосредственно в функции ниже и просто возьмите массивы размером количества пикселей, которые пользователь нарисовал.

from numpy.random import choice 
pde = choice(list_of_candidates, number_of_items_to_pick, p=probability_distribution) 

probability_distribution (нормированная пиксельные у-значения) представляет собой последовательность в том же порядке list_of_candidates (соответствующие рентгеновские значения). Вы также можете использовать ключевое слово replace = False, чтобы изменить поведение, чтобы нарисованные элементы не были заменены.

see numpy docs here

Это должен быть намного быстрее, так как вы на самом деле не генерируя весь PDE, просто рисунка случайных чисел, которые соответствуют ОЫМ.

EDIT: ваше обновление выглядит как надежный подход. Если вы хотите сгенерировать pde, вы можете рассмотреть возможность использования numba (http://numba.pydata.org) для векторизации цикла for.

Смежные вопросы