n <- 200 logistic <- function(x) 1 / (1 + exp(-x)) p <- function(x) logistic(1 - 3 * sin(x)) set.seed(123456) X <- sort(runif(n = n, -3, 3)) Y <- rbinom(n = n, size = 1, prob = p(X)) # Set bandwidth and evaluation grid h <- 0.25 x <- seq(-3, 3, l = 501) # Approach 1: optimize the weighted log-likelihood through the workhorse # function underneath glm, glm.fit suppressWarnings( fit_glm <- sapply(x, function(x) { K <- dnorm(x = x, mean = X, sd = h) glm.fit(x = cbind(1, X - x), y = Y, weights = K, family = binomial())$coefficients[1] }) ) # Approach 2: optimize directly the weighted log-likelihood suppressWarnings( fit_nlm <- sapply(x, function(x) { K <- dnorm(x = x, mean = X, sd = h) nlm(f = function(beta) { -sum(K * (Y * (beta[1] + beta[2] * (X - x)) - log(1 + exp(beta[1] + beta[2] * (X - x))))) }, p = c(0, 0))$estimate[1] }) ) # Approach 3: employ locfit::locfit # CAREFUL: locfit::locfit uses a different internal parametrization for h! # As it can be see, the bandwidths in approaches 1-2 and approach 3 do NOT # give the same results! With h = 0.75 in locfit::locfit the fit is close # to the previous ones (done for h = 0.25), but not exactly the same... fit_locfit <- locfit::locfit(Y ~ locfit::lp(X, deg = 1, h = 0.75), family = "binomial", kern = "gauss") # Compare fits plot(x, p(x), ylim = c(0, 1.5), type = "l", lwd = 2) lines(x, logistic(fit_glm), col = 2) lines(x, logistic(fit_nlm), col = 3, lty = 2) lines(x, predict(fit_locfit, newdata = x), col = 4, lty = 2) legend("topright", legend = c("p(x)", "glm", "nlm", "locfit"), lwd = 2, col = c(1, 2, 3, 4), lty = c(1, 1, 2, 1))