Ah, perfect! Thanks so much Ken.

In the meantime I played with developing an optim() driven ML search
(included below for posterity), but the glm() + mafc approach is faster and
apparently yields identical results.

########
# First generate some data
########

# Define a modified logistic function
mod.logistic = function(x,location,scale) plogis(x,location,scale)*.5 + .5

# Define the scale and location of the modified logistic to be fit
location = 40
scale = 5

# Choose some x values
x = runif(200,0,100)

# Generate some random noise to add to x in order to
# simulate real-word measurement and avoid perfect fits
x.noise = runif(length(x),-10,10)

# Define the probability of success for each x given the modified logistic
prob.success = mod.logistic(x+x.noise,location,scale)

# Obtain y, the observed success/failure at each x
y = rep(NA,length(x))
for(i in 1:length(x)){
    y[i] = sample(
        x = c(1,0)
        , size = 1
        , prob = c(prob.success[i], 1-prob.success[i])
    )
}

# Show the data and the source function
plot(x,y,ylab='Accuracy',xlab='Stimulus Duration (ms)',pch=3)
abline(h=.5,lty=3,col='grey',lwd=2)
curve(mod.logistic(x,location,scale),add=T)

########
# Now try to fit the data
########

# Fit using glm with the standard binomial link function
# and plot the result (obviously bad)
glm.binom.fit = glm(y ~ x , family='binomial')
curve(plogis(glm.binom.fit$coefficients[1]+x*glm.binom.fit$coefficients[2])*.5+.5,add=T,col='brown',lty=2)


# Define a function that obtains the sum log liklihood of
# data given a set of mod.logistic parameters
lik.mod.logistic = function(par,y,x){
    size  = length(x)
    lik = rep(NA,size)
    exp = mod.logistic(x,par[1],par[2])
    for(i in 1:size){
        lik[i] = ifelse(y[i]==1,exp[i],1-exp[i])
    }
    sl = sum(log(lik))
    if(!is.finite(sl)){
        sl=-99999999
    }
    return(sl)
}

# Fit the data using optim whilst keeping a record of how
# much time this takes. Starting points may need to be
# modfied, as may the limits.
optim.start=proc.time()[1]
from.optim = optim(
    par = c(
        location = sum(x*y)/sum(y)
        , scale = sum(x*y)/sum(y)
    )
    , lik.mod.logistic
    , method='L'
    , lower=c(1,1)
    , upper=c(1000,1000)
    , y=y
    , x=x
    , control=list(fnscale=-1)
)
optim.time=proc.time()[1]-optim.start

# Add the fit to the plot
curve(mod.logistic(x,from.optim$par[1],from.optim$par[2]),col='red',lty=2,lwd=2,add=T)


# Fit the data using glm and the mafc.logit link function
# provided in the psyphy package.
library(psyphy)
glm.mafc.logit.start=proc.time()[1]
glm.mafc.logit.fit = glm(y ~ x, binomial(mafc.logit(2))
)
glm.mafc.logit.time=proc.time()[1]-glm.mafc.logit.start

# Add the fit to the plot
x.ord <- order(x)
lines(x[x.ord], fitted(glm.mafc.logit.fit)[x.ord], col = "green", lty=3, lwd
= 2)

# Compare the time taken by the optim and
# glm(y ~ x, binomial(mafc.logit(2)) procedures
print(c(optim.time,glm.mafc.logit.start))


-- 
Mike Lawrence
Graduate Student
Department of Psychology
Dalhousie University
www.thatmike.com

Looking to arrange a meeting? Check my public calendar and find a time that
is mutually free:
http://tinyurl.com/mikescalendar
(tiny url redirects to google calendar)

~ Certainty is folly... I think. ~

	[[alternative HTML version deleted]]

