Наиболее общий способ генерации случайного числа после распределения заключается в следующем:
- Создание равномерного случайного числа, ограниченного 0 и 1 (например,
numpy.random.random()
). - Возьмите обратный CDF (обратная кумулятивная функция распределения) этого числа.
Результатом является число, которое следует за распределением.
В вашем случае обратный CDF (ICDF(x)
) определяется уже пятью вашими параметрами - минимальным, максимальным и тремя процентилями, а именно:
- ICDF (0) = минимум
- ICDF (0,25) = 25-й процентиль
- ICDF (0,5) = 50-й процентиль
- ICDF (0,75) = 75-й процентиль
- ICDF (1) = максимум
Таким образом, у вас уже есть представление о том, как выглядит обратный CDF. И все, что вам нужно сделать сейчас, это как-то оптимизировать обратный CDF для других параметров (среднее значение, стандартное отклонение, асимметрия и эксцесс). Например, вы можете «заполнить» обратный CDF на других процентилях и посмотреть, насколько хорошо они соответствуют параметрам, которые вы выбираете. В этом смысле хорошим начальным предположением является линейная интерполяция только что упомянутых процентилей.
Следующий код показывает решение. Он выполняет следующие шаги:
- Он вычисляет начальное предположение для обратного CDF с помощью линейной интерполяции. Первоначальное предположение состоит из значений этой функции в 101 равномерно распределенных точках, включая пять процентилей, упомянутых выше.
- Она устанавливает границы оптимизации. Оптимизация ограничена минимальными и максимальными значениями везде, кроме пяти процентилей.
- Она устанавливает остальные четыре параметра.
- Затем она передает целевую функцию (
_lossfunc
), первоначальное предположение, границы и другие параметры для метода SciPy scipy.optimize.minimize
для оптимизации. - После завершения оптимизации код проверяет успешность и выдает ошибку в случае неудачи.
- Если оптимизация успешно, код вычисляет обратный CDF для окончательного результата.
- Генерирует N равномерных случайных значений.
- Преобразует эти значения с обратным CDF и возвращает эти значения.
import scipy.stats.mstats as mst
from scipy.optimize import minimize
from scipy.interpolate import interp1d
import numpy
# Define the loss function, which is simply the
# sum of squared distances between the calculated
# and ideal parameters
def _lossfunc(x, *args):
mean, vari, skew, kurt=args
return (numpy.mean(x)-mean)**2 + \
(numpy.var(x)-vari)**2 + \
(mst.skew(x)-skew)**2 + \
(mst.kurtosis(x)-kurt)**2
# Calculates an inverse CDF for the given nine parameters.
def _get_inverse_cdf(mn, p25, p50, p75, mx, mean, stdev, skew, kurt):
# Calculate initial guess for the inverse CDF; an
# interpolation of the inverse CDF through the known
# percentiles
interp=interp1d([0,0.25,0.5, 0.75,1.0],[mn,p25,p50,p75,mx])
x=interp(numpy.linspace(0,1,101))
# Bounds
bounds=[(mn,mx) for i in range(101)]
# Percentiles must have fixed values
bounds[0]=(mn,mn)
bounds[25]=(p25,p25)
bounds[50]=(p50,p50)
bounds[75]=(p75,p75)
bounds[100]=(mx,mx)
# Other parameters
otherParams=(mean, stdev**2, skew, kurt)
# Optimize the result for the given parameters
# using the initial guess and the bounds
result=minimize(
_lossfunc, # Loss function
x, # Initial guess
otherParams, # Arguments
bounds=bounds)
# Check for success
if not result.success: raise ValueError
# Calculate interpolating function of result
ls=numpy.linspace(0,1,101)
return interp1d(ls,result.x,kind='cubic')
def random_10params(n, mn, p25, p50, p75, mx, mean, stdev, skew, kurt):
""" Note: Kurtosis as used here is Fisher's kurtosis,
or kurtosis excess. Stdev is square root of numpy.var(). """
# Calculate inverse CDF
icdf = _get_inverse_cdf(mn, p25, p50, p75, mx, mean, stdev, skew, kurt)
# Generate uniform random variables
npr=numpy.random.random(size=n)
# Transform them with the inverse CDF
return icdf(npr)
Пример:
print(random_10params(100,
-2.3263478740408408, -0.6744897501960817, 0.0, 0.6744897501960817, 2.0537489106318225,-0.023,0.875,-0.0806,-0.448))
Последнее замечание: если у вас есть доступ к базовым точкам данных, а не только к их статистике, есть другие методы Вы можете использовать для выборки из распределения эти точки данных формы. Примеры включают оценки плотности ядра , гистограммы или модели регрессии (особенно для данных временных рядов). См. Также Генерация случайных данных на основе существующих данных .