Моделирование данных с помощью функции связи Вейбулла в R

Я пытаюсь моделировать некоторые данные, которые следует за отношением сигмовидной кривой. В моей области работы (психофизика) функция Вейбулла обычно используется для моделирования таких отношений, а не пробита.

Я пытаюсь создать модель, использующую R, и борюсь с синтаксисом. Я знаю, что мне нужно использовать функцию vglm() из пакета VGAM, но я не могу получить разумную модель. Здесь мои данные:

# Data frame example data
dframe1 <- structure(list(independent_variable = c(0.3, 0.24, 0.23, 0.16, 
0.14, 0.05, 0.01, -0.1, -0.2), dependent_variable = c(1, 1, 
1, 0.95, 0.93, 0.65, 0.55, 0.5, 0.5)), .Names = c("independent_variable", 
"dependent_variable"), class = "data.frame", row.names = c(NA, 
-9L))

Вот график данных в dframe1:

library(ggplot2)

# Plot my original data
ggplot(dframe1, aes(independent_variable, dependent_variable)) + geom_point()

enter image description here

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

library(VGAM)

# Generate model
my_model <- vglm(formula = dependent_variable ~ independent_variable, family = weibull, data = dframe1)

# Create a new dataframe based on the model, so that it can be plotted
model_dframe <- data.frame(dframe1$independent_variable, fitted(my_model))

# Plot my model fitted data
ggplot(model_dframe, aes(dframe1.independent_variable, fitted.my_model.)) + geom_point()

enter image description here

Как вы можете видеть, это вовсе не означает мои исходные данные. Я либо неправильно создаю свою модель, либо неправильно создаю свой график модели. Что я делаю неправильно?

Примечание. Я редактировал этот вопрос, чтобы сделать его более понятным; ранее я полностью использовал неправильную функцию (weibreg()). Следовательно, некоторые из комментариев ниже могут не иметь смысла. .....

Ответ 1

Здесь мое решение, с bbmle.

Данные:

dframe1 <- structure(list(independent_variable = c(0.3, 0.24, 0.23, 0.16, 
0.14, 0.05, 0.01, -0.1, -0.2), dependent_variable = c(1, 1, 
1, 0.95, 0.93, 0.65, 0.55, 0.5, 0.5)), .Names = c("independent_variable", 
"dependent_variable"), class = "data.frame", row.names = c(NA, 
-9L))

Постройте кумулятивный Weibull, который по определению составляет от 0.5 до 1.0:

wfun <- function(x,shape,scale) {
    (1+pweibull(x,shape,scale))/2.0
}

dframe2 <- transform(dframe1,y=round(40*dependent_variable),x=independent_variable)

Установите вейбулл (соответствующие параметры логарифмической шкалы) с биномиальным изменением:

library(bbmle)
m1 <- mle2(y~dbinom(prob=wfun(exp(a+b*x),shape=exp(logshape),scale=1),size=40),
     data=dframe2,start=list(a=0,b=0,logshape=0))

Создание прогнозов:

pframe <- data.frame(x=seq(-0.2,0.3,length=101))
pframe$y <- predict(m1,pframe)

png("wplot.png")
with(dframe2,plot(y/40~x))
with(pframe,lines(y/40~x,col=2))
dev.off()

enter image description here

Ответ 2

Вы также можете использовать drc-пакет (моделирование доза-реакция).

Я на самом деле нуб для таких моделей, но perhabs это помогает как-то...

Здесь я установил четыре параметра Weibull с фиксированными параметрами для асимптот (иначе верхняя асимптота будет немного больше 1, не знаю, является ли это проблемой для вас). Мне также пришлось преобразовать независимую переменную (+0.2) так, чтобы ее было >= 0 из-за проблем сходимости.

require(drc)
# four-parameter Weibull with fixed parameters for the asymptote, added +0.2 to IV to overcome convergence problems
mod <- drm(dependent_variable ~ I(independent_variable+0.2), 
           data = dframe1, 
           fct = W1.4(fixed = c(NA, 0.5, 1, NA)))

# predicts
df2 <- data.frame(pred = predict(mod, newdata = data.frame(idenpendent_variable = seq(0, 0.5, length.out=100))), 
                  x = seq(0, 0.5, length.out=100))

ggplot() + 
  geom_point(data = dframe1, aes(x = independent_variable + 0.2, y = dependent_variable)) +
  geom_line(data = df2, aes(x = x, y = pred))

Однако я согласен с Бен Болкером в том, что другие модели могут быть лучше подходят.

Я знаю только такие модели из экотоксикологии (модели дозозависимости, где вас интересует концентрация, где у нас 50% смертности [= EC50]).

enter image description here

Обновление Четырехпараметрическая лог-логистическая модель подходит и неплохо (меньшие AIC и RSE, затем weibull): Снова я зафиксировал здесь параметр асимптоты и преобразовал IV.

# four-parameter log-logistic with fixed parameters for the asymptote, added +0.2 to IV to overcome convergence problems
mod1 <- drm(dependent_variable ~ I(independent_variable+0.2), 
           data = dframe1, 
           fct = LL2.4(fixed=c(NA, 0.5, 1, NA)))
summary(mod1)

# predicts
df2 <- data.frame(pred = predict(mod1, newdata = data.frame(idenpendent_variable = seq(0, 0.5, length.out=100))), 
                  x = seq(0, 0.5, length.out=100))

ggplot() + 
  geom_point(data = dframe1, aes(x = independent_variable + 0.2, y = dependent_variable)) +
  geom_line(data = df2, aes(x = x, y = pred))

enter image description here

Ответ 3

Хорошо, я только что настал через несколько месяцев, но вы также можете использовать ссылка mafc.cloglog из пакета psyphy с glm. Если x следует за cloglog, тогда log (x) будет следовать психометрической функции weibull. Улов, как и в приведенных выше ответах, что вам нужно количество испытаний для правильной пропорции. Я просто установил его на 100, чтобы он дал целое число испытаний но вы должны исправить это, чтобы соответствовать номерам, которые вы фактически использован. Вот код для этого.

dframe1 <- structure(list(independent_variable = c(0.3, 0.24, 0.23, 0.16, 
0.14, 0.05, 0.01, -0.1, -0.2), dependent_variable = c(1, 1, 
1, 0.95, 0.93, 0.65, 0.55, 0.5, 0.5)), .Names = c("independent_variable", 
"dependent_variable"), class = "data.frame", row.names = c(NA, 
-9L))

library(psyphy)

plot(dependent_variable ~ independent_variable, dframe1)
fit <- glm(dependent_variable ~ exp(independent_variable), 
    binomial(mafc.cloglog(2)), 
    data = dframe1, 
    weights = rep(100, nrow(dframe1)))  # assuming 100 observations per point
xx <- seq(-0.2, 0.3, len = 100)
pred <- predict(fit, newdata = data.frame(independent_variable = xx), type = "response")
lines(xx, pred)

Fit to data