Sunteți pe pagina 1din 7

7/7/2017 quantreg/nlrq.

R at master · cran/quantreg · GitHub

Features Business Explore Marketplace Pricing This repository Search Sign in or Sign up

cran / quantreg Watch 0 Star 4 Fork 5

Code Pull requests 0 Projects 0 Insights

Branch: master quantreg / R / nlrq.R Find file Copy path

Roger Koenker version 5.33 e155e99 on Apr 18

1 contributor

399 lines (378 sloc) 14.2 KB Raw Blame History

1 ###====== Nonlinear quantile regression with an interior point algorithm ======


2 # see: Koenker, R. & B.J. Park, 1996. An interior point algorithm
3 # for nonlinear quantile regression. J. Econom., 71(1-2): 265-283.
4 # adapted from nlrq routine of Koenker, R. to be compatible with R nls models
5 # by Ph. Grosjean, 2001 (phgrosjean@sciviews.org)
6 # large parts of code are reused from the nls package of R v. 1.2.3
7
8 # TO DO:
9 # - nlrq should return a code 0 = convergence, 1 = lambda -> 0, etc..
10 # - Extensive diagnostic for summary() (Roger, what would you propose?)
11 # - Calculate with a list of tau values at once (currently accept only 1 value)
12 # - When providing several tau values, allow also to calculate a single value
13 # for one or several parameters across all models fitted to all tau values...
14 # ...but I have another idea for doing that more efficiently.
15
16 "nlrq.control" <- function (maxiter=100, k=2, InitialStepSize = 1,
17 big=1e+20, eps=1.0e-07, beta=0.97)
18 {
19 list(maxiter=maxiter, k=k, InitialStepSize = InitialStepSize,
20 big=big, eps=eps, beta=beta)
21 }
22
23 # Still needs to be cleaned up: several parts of the code not used here (QR,...)
24 "nlrqModel" <- function (form, tau, data, start)
25 {
26 thisEnv <- environment()
27 env <- new.env(parent = environment(form))
28 for (i in names(data)) {
29 assign(i, data[[i]], envir = env)
30 }
31 ind <- as.list(start)
32 parLength <- 0
33 for (i in names(ind)) {
34 temp <- start[[i]]
35 storage.mode(temp) <- "double"
36 assign(i, temp, envir = env)
37 ind[[i]] <- parLength + seq(along = start[[i]])
38 parLength <- parLength + length(start[[i]])
39 }
40 useParams <- rep(TRUE, parLength)
41 lhs <- eval(form[[2]], envir = env)
42 rhs <- eval(form[[3]], envir = env)
43 resid <- lhs - rhs
44 tau <- tau
45 dev <- sum(tau * pmax(resid, 0) + (tau - 1) * pmin(resid, 0))
46 if (is.null(attr(rhs, "gradient"))) {
47 getRHS.noVarying <- function() numericDeriv(form[[3]],
48 names(ind), env)
49 getRHS <- getRHS.noVarying

https://github.com/cran/quantreg/blob/master/R/nlrq.R 1/7
7/7/2017 quantreg/nlrq.R at master · cran/quantreg · GitHub
50 rhs <- getRHS()
51 }
52 else {
53 getRHS.noVarying <- function() eval(form[[3]], envir = env)
54 getRHS <- getRHS.noVarying
55 }
56 dimGrad <- dim(attr(rhs, "gradient"))
57 marg <- length(dimGrad)
58 if (marg > 0) {
59 gradSetArgs <- vector("list", marg + 1)
60 for (i in 2:marg) gradSetArgs[[i]] <- rep(TRUE, dimGrad[i -
61 1])
62 useParams <- rep(TRUE, dimGrad[marg])
63 }
64 else {
65 gradSetArgs <- vector("list", 2)
66 useParams <- rep(TRUE, length(attr(rhs, "gradient")))
67 }
68 npar <- length(useParams)
69 gradSetArgs[[1]] <- (~attr(ans, "gradient"))[[2]]
70 gradCall <- switch(length(gradSetArgs) - 1, call("[", gradSetArgs[[1]],
71 gradSetArgs[[2]]), call("[", gradSetArgs[[1]], gradSetArgs[[2]],
72 gradSetArgs[[2]]), call("[", gradSetArgs[[1]], gradSetArgs[[2]],
73 gradSetArgs[[2]], gradSetArgs[[3]]), call("[", gradSetArgs[[1]],
74 gradSetArgs[[2]], gradSetArgs[[2]], gradSetArgs[[3]],
75 gradSetArgs[[4]]))
76 getRHS.varying <- function() {
77 ans <- getRHS.noVarying()
78 attr(ans, "gradient") <- eval(gradCall)
79 ans
80 }
81 QR <- qr(attr(rhs, "gradient"))
82 qrDim <- min(dim(QR$qr))
83 if (QR$rank < qrDim)
84 stop("singular gradient matrix at initial parameter estimates")
85 getPars.noVarying <- function() unlist(setNames(lapply(names(ind),
86 get, envir = env), names(ind)))
87 getPars.varying <- function() unlist(setNames(lapply(names(ind),
88 get, envir = env), names(ind)))[useParams]
89 getPars <- getPars.noVarying
90 internalPars <- getPars()
91 setPars.noVarying <- function(newPars) {
92 assign("internalPars", newPars, envir = thisEnv)
93 for (i in names(ind)) {
94 assign(i, unname(newPars[ind[[i]]]), envir = env)
95 }
96 }
97 setPars.varying <- function(newPars) {
98 internalPars[useParams] <- newPars
99 for (i in names(ind)) {
100 assign(i, unname(internalPars[ind[[i]]]), envir = env)
101 }
102 }
103 setPars <- setPars.noVarying
104 on.exit(remove(i, data, parLength, start, temp))
105 m <- list(resid = function() resid, fitted = function() rhs,
106 formula = function() form, tau = function() tau, deviance = function() dev,
107 gradient = function() attr(rhs, "gradient"), incr = function() qr.coef(QR, resid), setVarying = function(vary = rep(TRUE,
108 length(useParams))) {
109 assign("useParams", if (is.character(vary)) {
110 temp <- logical(length(useParams))
111 temp[unlist(ind[vary])] <- TRUE
112 temp
113 } else if (is.logical(vary) && length(vary) != length(useParams)) stop("setVarying : vary length must match length of parameters
114 vary
115 }, envir = thisEnv)
116 gradCall[[length(gradCall)]] <<- useParams

https://github.com/cran/quantreg/blob/master/R/nlrq.R 2/7
7/7/2017 quantreg/nlrq.R at master · cran/quantreg · GitHub
117 if (all(useParams)) {
118 assign("setPars", setPars.noVarying, envir = thisEnv)
119 assign("getPars", getPars.noVarying, envir = thisEnv)
120 assign("getRHS", getRHS.noVarying, envir = thisEnv)
121 assign("npar", length(useParams), envir = thisEnv)
122 } else {
123 assign("setPars", setPars.varying, envir = thisEnv)
124 assign("getPars", getPars.varying, envir = thisEnv)
125 assign("getRHS", getRHS.varying, envir = thisEnv)
126 assign("npar", length((1:length(useParams))[useParams]),
127 envir = thisEnv)
128 }
129 }, changeTau = function(newTau) {
130 assign("tau", newTau, envir = thisEnv)
131 assign("dev", sum(tau * pmax(resid, 0) + (tau - 1) * pmin(resid, 0)), envir = thisEnv)
132 return(dev)
133 }, setPars = function(newPars) {
134 setPars(newPars)
135 assign("resid", lhs - assign("rhs", getRHS(), envir = thisEnv),
136 envir = thisEnv)
137 assign("dev", sum(tau * pmax(resid, 0) + (tau - 1) * pmin(resid, 0)), envir = thisEnv)
138 assign("QR", qr(attr(rhs, "gradient")), envir = thisEnv)
139 return(QR$rank < min(dim(QR$qr)))
140 }, getPars = function() getPars(), getAllPars = function() getPars(),
141 getEnv = function() env, trace = function() cat(format(dev),
142 ": ", format(getPars()), "\n"), Rmat = function() qr.R(QR),
143 predict = function(newdata = list(), qr = FALSE) {
144 Env <- new.env()
145 for (i in objects(envir = env)) {
146 assign(i, get(i, envir = env), envir = Env)
147 }
148 newdata <- as.list(newdata)
149 for (i in names(newdata)) {
150 assign(i, newdata[[i]], envir = Env)
151 }
152 eval(form[[3]], envir = Env)
153 })
154 class(m) <- "nlrqModel"
155 m
156 }
157
158 "nlrq" <- function (formula, data=parent.frame(), start, tau=0.5,
159 control, trace=FALSE, method = "L-BFGS-B")
160 {
161 mf <- match.call()
162 formula <- as.formula(formula)
163 varNames <- all.vars(formula)
164 if (length(formula) == 2) {
165 formula[[3]] <- formula[[2]]
166 formula[[2]] <- 0
167 }
168 if (missing(start)) {
169 if (!is.null(attr(data, "parameters"))) {
170 pnames <- names(attr(data, "parameters"))
171 }
172 else {
173 cll <- formula[[length(formula)]]
174 func <- get(as.character(cll[[1]]))
175 pnames <- as.character(as.list(match.call(func, call = cll))[-1][attr(func, "pnames")])
176 }
177 }
178 else {
179 pnames <- names(start)
180 }
181 varNames <- varNames[is.na(match(varNames, pnames, nomatch = NA))]
182 varIndex <- sapply(varNames, function(varName, data, respLength) {
183 length(eval(as.name(varName), data))%%respLength == 0

https://github.com/cran/quantreg/blob/master/R/nlrq.R 3/7
7/7/2017 quantreg/nlrq.R at master · cran/quantreg · GitHub
184 }, data, length(eval(formula[[2]], data)))
185 mf$formula <- parse(text = paste("~", paste(varNames[varIndex], collapse = "+")))[[1]]
186 mf$start <- mf$tau <- mf$control <- mf$algorithm <- mf$trace <- mf$method <- NULL
187 mf[[1]] <- as.name("model.frame")
188 mf <- as.list(eval(mf, parent.frame()))
189 if (missing(start)) {
190 start <- getInitial(formula, mf)
191 }
192 for (var in varNames[!varIndex]) mf[[var]] <- eval(as.name(var), data)
193 ctrl <- nlrq.control()
194 if (!missing(control)) {
195 control <- as.list(control)
196 ctrl[names(control)] <- control
197 }
198 m <- nlrqModel(formula, tau, mf, start)
199 nlrq.calc <- function (model, ctrl, trace) {
200 meketon <- function(x, y, w, tau, ctrl) {
201 yw <- ctrl$big
202 k <- 1
203 while(k <= ctrl$k & yw - crossprod(y, w) > ctrl$eps) {
204 d <- pmin(tau - w, 1 - tau + w)
205 z <- lsfit(x, y, d^2, intercept=FALSE)
206 yw <- sum(tau * pmax(z$resid, 0) + (tau - 1) * pmin(z$resid, 0))
207 k <- k + 1
208 s <- z$resid * d^2
209 alpha <- max(ctrl$eps, pmax(s/(tau - w), -s/(1 - tau + w)))
210 w <- w + (ctrl$beta/alpha) * s
211 }
212 coef <- z$coef
213 return(list(coef=coef, w=w))
214 }
215 model.step <- function(lambda, Step, model, pars) {
216 model$setPars(pars + lambda * Step)
217 model$deviance()
218 }
219 w <- rep(0, length(model$resid()))
220 snew <- model$deviance()
221 sold <- ctrl$big
222 nit <- 0
223 if (trace) {
224 model$trace()
225 optim.ctrl <- list(trace=1)
226 } else {
227 optim.ctrl <- list(trace=0)
228 }
229 lam0 <- ctrl$InitialStepSize
230 while(sold - snew > ctrl$eps & nit < ctrl$maxiter) {
231 z <- meketon(model$gradient(),as.vector(model$resid()), w, tau=tau, ctrl=ctrl)
232 Step <- z$coef
233 Pars <- model$getPars()
234 lam <- try(optim(par=lam0, fn=model.step, method=method, lower=0, upper=1,
235 Step=Step, model=model, pars=Pars, control=optim.ctrl)$par)
236 if(inherits(lam,"try.error") || !is.finite(lam))
237 stop("optim unable to find valid step size")
238 if (trace) {cat("lambda =", lam, "\n")}
239 model$setPars(Pars + lam * Step)
240 sold <- snew
241 snew <- model$deviance()
242 w <- qr.resid(qr(model$gradient()), z$w)
243 w1 <- max(pmax(w, 0))
244 if(w1 > tau) {w <- (w * tau)/(w1 + ctrl$eps)}
245 w0 <- max(pmax( - w, 0))
246 if(w0 > 1 - tau) {w <- (w * (1 - tau))/(w0 + ctrl$eps)}
247 if (trace) {model$trace()}
248 if (R.Version()$os == "Win32") {flush.console()}
249 nit <- nit + 1
250 }

https://github.com/cran/quantreg/blob/master/R/nlrq.R 4/7
7/7/2017 quantreg/nlrq.R at master · cran/quantreg · GitHub
251 Rho <- function(u,tau) u * (tau - (u < 0))
252 model$rho <- sum(Rho(model$resid(),tau))
253 model
254 }
255 nlrq.out <- list(m=nlrq.calc(m, ctrl, trace), data=substitute(data),
256 call=match.call())
257 nlrq.out$call$control <- ctrl
258 nlrq.out$call$trace <- trace
259 class(nlrq.out) <- "nlrq"
260 nlrq.out
261 }
262 "logLik.nlrq" <- function(object, ...){
263 n <- length(object$m$resid())
264 p <- length(object$m$getPars())
265 tau <- object$m$tau()
266 fid <- object$m$rho
267 val <- n * (log(tau * (1-tau)) - 1 - log(fid/n))
268 attr(val,"n") <- n
269 attr(val,"df") <- p
270 class(val) <- "logLik"
271 val
272 }
273 "AIC.nlrq" <- function(object, ... , k = 2){
274 v <- logLik(object)
275 if(k <= 0)
276 k <- log(attr(v,"n"))
277 val <- AIC(v, k = k)
278 attr(val,"edf") <- attr(v,"df")
279 val
280 }
281 "extractAIC.nlrq" <- function(fit, scale, k=2, ...){
282 aic <- AIC(fit,k)
283 edf <- attr(aic, "edf")
284 c(edf, aic)
285 }
286
287
288
289
290 "print.nlrq" <- function (x, ...)
291 {
292 cat("Nonlinear quantile regression\n")
293 cat(" model: ", deparse(formula(x)), "\n")
294 cat(" data: ", as.character(x$data), "\n")
295 cat(" tau: ", as.character(x$m$tau()), "\n")
296 cat("deviance: ", format(x$m$deviance()), "\n")
297 print(x$m$getAllPars())
298 invisible(x)
299 }
300
301 # For the moment, print.summary is the same as print
302 # However, some extra diagnostic should be done here
303 "summary.nlrq" <- function (object, ...)
304 structure(object, class=c("summary.nlrq", class(object)))
305
306 "print.summary.nlrq" <- function (x, ...)
307 {
308 cat("Nonlinear quantile regression\n")
309 cat(" model: ", deparse(formula(x)), "\n")
310 cat(" data: ", as.character(x$data), "\n")
311 cat(" tau: ", as.character(x$m$tau()), "\n")
312 cat("deviance: ", format(x$m$deviance()), "\n")
313 print(x$m$getAllPars())
314 invisible(x)
315 }
316
317 "coef.nlrq" <- function (object, ...)

https://github.com/cran/quantreg/blob/master/R/nlrq.R 5/7
7/7/2017 quantreg/nlrq.R at master · cran/quantreg · GitHub
318 object$m$getAllPars()
319
320 "deviance.nlrq" <- function (object, ...)
321 object$m$deviance()
322
323
324 "tau.nlrq" <- function (object, ...)
325 object$m$tau()
326
327 "fitted.nlrq" <- function (object, ...)
328 {
329 val <- as.vector(object$m$fitted())
330 lab <- "Fitted values"
331 if (!is.null(aux <- attr(object, "units")$y)) {
332 lab <- paste(lab, aux)
333 }
334 attr(val, "label") <- lab
335 val
336 }
337
338 "formula.nlrq" <- function (x, ...)
339 x$m$formula()
340
341 "predict.nlrq" <- function (object, newdata, ...)
342 {
343 if (missing(newdata))
344 return(as.vector(fitted(object)))
345 object$m$predict(newdata)
346 }
347
348 "residuals.nlrq" <- function (object, type = c("response", "rho"), ...)
349 {
350 type <- match.arg(type)
351 val <- as.vector(object$m$resid())
352 if (type == "rho") {
353 tau <- object$m$tau()
354 val <- tau * pmax(val, 0) + (1 - tau) * pmin(val, 0)
355 attr(val, "label") <- paste("quantile residuals rho(", tau ,")", sep="")
356 }
357 else {
358 lab <- "Residuals"
359 if (!is.null(aux <- attr(object, "units")$y)) {
360 lab <- paste(lab, aux)
361 }
362 attr(val, "label") <- lab
363 }
364 val
365 }
366 "summary.nlrq" <- function(object, ...)
367 {
368 y <- as.vector(object$m$resid())
369 X <- object$m$gradient()
370 tau <- object$m$tau()
371 pnames <- names(object$m$getPars())
372 f <- summary(rq(y ~X-1,tau), se = "boot", covariance = TRUE, ...)
373 f$coefficients[,1] <- object$m$getPars()
374 f$coefficients[,3] <- f$coefficients[, 1]/f$coefficients[, 2]
375 f$coefficients[, 4] <- if (f$rdf > 0)
376 2 * (1 - pt(abs(f$coef[, 3]), f$rdf))
377 dimnames(f$coefficients)[[1]] <- pnames
378 f$call <- object$call
379 f$tau <- tau
380 class(f) <- "summary.nlrq"
381 return(f)
382 }
383 "print.summary.nlrq" <- function (x, digits = max(5, .Options$digits - 2), ...)
384 {

https://github.com/cran/quantreg/blob/master/R/nlrq.R 6/7
7/7/2017 quantreg/nlrq.R at master · cran/quantreg · GitHub
385 cat("\nCall: ")
386 dput(x$call)
387 coef <- x$coef
388 tau <- x$tau
389 cat("\ntau: ")
390 print(format(round(tau, digits = digits)), quote = FALSE,
391 ...)
392 cat("\nCoefficients:\n")
393 print(format(round(coef, digits = digits)), quote = FALSE,
394 ...)
395 invisible(x)
396 }
397
398

© 2017 GitHub, Inc. Terms Privacy Security Status Help Contact GitHub API Training Shop Blog About

https://github.com/cran/quantreg/blob/master/R/nlrq.R 7/7

S-ar putea să vă placă și