Как Python может использовать n, min, max, среднее значение, стандартное отклонение, 25%, 50%, 75%, Skew, Kurtosis для определения псевдослучайной оценки / функции плотности вероятности? - PullRequest
0 голосов
/ 26 апреля 2020

Читая и экспериментируя с numpy .random, я не могу найти или создать то, что мне нужно; генератор с 10 параметрами Python псевдослучайных значений, включая счетчик, мин, макс, среднее значение, сд, 25-й процент ила, 50-й процент (медиана), 75-й процент иль, перекос и эксцесс.

с https://docs.python.org/3/library/random.html Я вижу эти распределения равномерное, нормальное (гауссово), логнормальное, отрицательное экспоненциальное, гамма и бета-распределения, хотя мне нужно генерировать значения непосредственно для распределения, определенного только моими 10 параметрами, без ссылки в семейство рассылки.

Есть ли документация или автор (ы) numpy .random.xxxxxx (n, min, max, mean, sd, 25%, 50%, 75% , перекос, куртозис), или какой, пожалуйста, самый близкий существующий исходный код, который я мог бы изменить для достижения этой цели?

Это было бы противоположно описанию (), включая перекос и куртоз в некотором смысле. Я мог бы сделать все oop или оптимизировать до тех пор, пока критерий не будет удовлетворен случайными сгенерированными числами, хотя это может занять бесконечное количество времени для удовлетворения моих 10 параметров.

Я нашел optim в R, который генерирует данные установлен, но до сих пор был в состоянии увеличить параметры в исходном коде R optim или продублировать его с помощью Python scipy.optimize или аналогичного, хотя они все еще зависят от методов, а не от прямого псевдослучайного создания набора данных в соответствии с моим 10 параметров, сколько мне нужно;

m0 <- 20
sd0 <- 5
min <- 1
max <- 45
n <- 15
set.seed(1)
mm <- min:max
x0 <- sample(mm, size=n, replace=TRUE)
objfun <- function(x) {(mean(x)-m0)^2+(sd(x)-sd0)^2}
candfun <- function(x) {x[sample(n, size=1)] <- sample(mm, size=1)
    return(x)}
objfun(x0) ##INITIAL RESULT:83.93495
o1 <- optim(par=x0, fn=objfun, gr=candfun, method="SANN", control=list(maxit=1e6))
mean(o1$par) ##INITIAL RESULT:20
sd(o1$par) ##INITIAL RESULT:5
plot(table(o1$par))

1 Ответ

0 голосов
/ 26 апреля 2020

Наиболее общий способ генерации случайного числа после распределения заключается в следующем:

  • Создание равномерного случайного числа, ограниченного 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))

Последнее замечание: если у вас есть доступ к базовым точкам данных, а не только к их статистике, есть другие методы Вы можете использовать для выборки из распределения эти точки данных формы. Примеры включают оценки плотности ядра , гистограммы или модели регрессии (особенно для данных временных рядов). См. Также Генерация случайных данных на основе существующих данных .

...