Я продолжаю сталкиваться с одной и той же ошибкой, пытаясь подогнать распределение к данным с помощью fitdistrplus. МВЕ ниже. Короче говоря, я хочу подогнать биномиальное распределение Пуассона к некоторым данным. Я использую пакет poibin R для биномиальных функций Пуассона p, d, q, r (я также пробовал poisbinom с той же ошибкой). В MWE я создаю dd, вектор успеха. Я пытаюсь использовать fitdist, чтобы соответствовать распределению с учетом начальных значений в списке start. Ошибка говорит (я думаю), что я даю ему начальные значения с именами, которых нет в функции dpoibin, где я застрял.
library(fitdistrplus)
library(poibin)
set.seed(123)
dd <- rpoibin(10, pp=seq(0.1, 0.5, length.out=10))
ppp <- runif (10)
ret <- try(fitdistrplus::fitdist(dd, distr=dpoibin,
start=list(pp = ppp)))
Сообщение об ошибке:
Ошибка в списке контрольных параметров (arg_startfix$start.arg, arg_startfix$fix.arg, : 'start' должен указывать имена, которые являются аргументами 'distr'.





Ошибка возникает из-за функции fitdistrplus:::checkparamlist, которая вызывается fitdist, чтобы убедиться, что имена в списке, переданном start, совпадают с именами параметров в функции, переданной distr. Когда вы передаете вектор вроде ppp в качестве параметра в start, checkparamlist переименовывает каждый элемент вектора, добавляя целое число. Это означает, что имена аргументов становятся "pp1", "pp2", "pp3" и так далее до "pp10". Поскольку аргумент pp не передается, выдается ошибка.
Я не уверен, есть ли способ оценить векторизованные параметры в fitdist из-за этой проблемы, но, к счастью, в этом случае мы можем легко подобрать распределение самостоятельно.
Поскольку мы знаем, что среднее значение распределения равно
и дисперсия
Тогда мы знаем, что если у нас есть образец dd, следующая функция вернет 0, если pp идеально соответствует распределению:
objective <- function(pp) {
abs(mean(dd) - sum(pp)) + abs(sum(pp * (1 - pp)) - var(dd))
}
Чтобы продемонстрировать, как это работает, давайте возьмем гораздо большую выборку из rpoibin.
set.seed(123)
dd <- poibin::rpoibin(100000, pp=seq(0.1, 0.5, length.out=10))
ppp <- runif (10)
Теперь найдем набор значений, который оптимизирует нашу целевую функцию:
pp_opt <- optim(par = ppp, objective)$par
pp_opt
#> [1] 0.45594175 0.08754997 0.54250499 0.28056432 0.30363457 0.28354584
#> [7] 0.17861750 0.21109410 0.41562763 0.23920435
Мы можем подтвердить, что это хорошее соответствие, построив гистограмму и наложив результат dpoibin на наши расчетные значения для параметра pp:
hist(dd, freq = FALSE, breaks = 0:11 - 0.5)
points(0:10, poibin::dpoibin(0:10, pp = pp_opt), col = "red")

Обратите внимание, что может быть много решений для оптимального значения pp, и мы не должны ожидать, что получим seq(0.1, 0.5, length.out = 10). Для начала порядок не имеет значения. Мы видим, что наше pp_opt имеет очень похожее среднее значение и дисперсию с seq(0.1, 0.5, length.out = 10), и это все, что имеет значение с точки зрения подбора распределения.
mean(seq(0.1, 0.5, length.out = 10))
#> [1] 0.3
mean(pp_opt)
#> [1] 0.2998285
sum((1 - pp_opt) * pp_opt)
#> [1] 1.930687
sum((1 - seq(0.1, 0.5, length.out = 10)) * seq(0.1, 0.5, length.out = 10))
#> [1] 1.937037
В общем, невозможно точно восстановить pp из данной выборки из-за упорядочения и того факта, что бесконечное количество наборов имеют одинаковое распределение и расчетную дисперсию.
Created on 2023-07-18 with reprex v2.0.2
... хотя дальнейшее тестирование, похоже, показывает, что оптимизация логарифмического сходства немного странная на нижнем пределе для небольших выборок.
@ user20650 хорошая мысль. Вызов optim должен быть ограничен между 0 и 1. Изменено.
Кажется, это не работает, если вы меняете
set.seed(123); n=100; rpoibin(n, ...и дает отрицательные вероятности. Вы можете заставить параметры быть больше 0 с помощьюlower=0, method = "L-BFGS-B"вoptim(хотя, возможно, вы можете перепарметрировать свою функцию, о чем мне лень думать). В качестве альтернативы вашей цели, я думаю, вы могли бы использовать логарифмическую вероятность:ll = function(par, x) -sum(log(dpoibin(x, par)))