[R-sig-ME] LMM with Big data using binary DV

Douglas Bates bates at stat.wisc.edu
Fri Feb 10 21:43:04 CET 2012


On Fri, Feb 10, 2012 at 12:01 PM, Malcolm Fairbrother
<m.fairbrother at bristol.ac.uk> wrote:
> Thanks very much for the correction. Just to clarify, are you saying there are two distinct problems:

> (1) The possibility of rows with both zero successes and zero failures. This seems minor--one can just check for those and exclude them if there are any, no?

I'm just saying that it is best to avoid the zero successes/zero
failues rows if you can.  When you use expand.grid a covariate with a
large number of unique values can inflate the size of the resulting
array substantially, possibly resulting in most of the rows having
zero successes and zero failures.  (In such cases it is doubtful that
you would achieve much of a speed-up by going to the reduced form
anyway.) That is why I would choose to use what corresponds to
obtaining the unique combinations of covariates present in the data.
You can always generate the zero successes/zero failures rows and then
filter them but that is the sort of thing that J. Edwards Deming
called "burning the toast and then scraping it".

> (2) Even if there are no rows with zero successes and zero failures, the optimisation could converge on some very inaccurate parameter estimates, because of the problems you mention with the deviance? (I hope this is roughly the right way to express this point.)

The location of the optimum is the same but, in the case of the
binomial representation the calculation of the deviance is off from
the Bernoulli representation by an additive factor.  There are
actually two issues here.  One is that the deviance for the Bernoulli
model differs from the deviance for the binomial model by

> with(dat2, 2 * sum(lchoose(success + failure, success)))
[1] 89442.18

In other words, it is twice the sum of the logarithms of the "n choose
k" terms in the binomial probability density function.  The binomial
model deviance is for all possible combinations of patterns of
successes and failures.  The Bernoulli model deviance is for the
particular pattern that you observed.

There is a further additive constant related to the fact that deviance
of the binomial model is not the sum of the squared deviance
residuals.  This is why there is another function in the family called
"aic" which, naturally, returns the deviance.

When I first wrote this reply I had a long rant in here about the
design of the glm family structure in general but that is not very
illuminating.  Suffice it to say that it is a bad design because it is
a holdover from S and S-PLUS which did not have the ability to
evaluate functions in a shared environment.

The short version of the story is that if you use the aic member
function then the deviances from the two model fits agree up to the
difference caused by the "n choose k" terms

> (gmsdb at resp$aic() + with(dat2, 2 * sum(lchoose(success + failure, success))))
[1] 112510.5
> gm01b at resp$aic()
[1] 112510.5

(Please don't go off and copy that type of code - we'll create better
extractor functions.)

> For problems like AC's, it would be quite helpful to have confidence that the "cbind(successes, failures)" approach is trustworthy, so thanks for looking into this.
>
> - Malcolm
>
>
>
> On 10 Feb 2012, at 17:36, Douglas Bates wrote:
>
>> On Fri, Feb 10, 2012 at 6:20 AM, Malcolm Fairbrother
>> <m.fairbrother at bristol.ac.uk> wrote:
>>> Dear AC (and perhaps Doug),
>>>
>>>>>> 2. Are there any clever work arounds (e.g., random sampling of subset of
>>>>>> data, etc) that would allow me to use only R packages to run this dataset
>>>>>> (assuming I need to use another program due to the size of the dataset)?
>>>
>>> You may be well aware of this, but one way of substantially speeding up the estimation of models with binary data is to use "cbind", though the feasibility of this depends on the nature of the model (number of predictors and number of unique values for each predictor variable). The kind of code you need for this is below. You'll see that the fixed effects estimates, standard errors, and random effects variances turn out the same.
>>>
>>>> If you would have an opportunity to run that model fit or a comparable
>>>> on lme4Eigen::glmer we would appreciate information about speed,
>>>> accuracy and memory usage.
>>>
>>>> As a fallback, we would appreciate the code that you used to simulate
>>>> the response.  We could generate something ourselves, of course, but
>>>> it is easier to compare when you copy someone else's simulation.
>>>
>>> I've compared the speed of lme4 versus lme4Eigen, on a simulated dataset with 100,000 observations, using a 2GHz MacBook. Based on a handful of simulations, there doesn't appear to be much difference between the two packages in terms of speed (sometimes one is faster, sometimes the other). I have reported the results of one simulation here. The two packages generate identical results for this dataset.
>>>
>>> Cheers,
>>> Malcolm
>>>
>>>
>>> N <- 100000
>>> grps <- 100
>>> dat <- data.frame(x1 = sample(1:10, N, replace=T), x2 = sample(18:23, N, replace=T), grp=rep(1:grps, each=N/grps))
>>> dat$y <- rbinom(N, prob = plogis(-5 + 0.1*dat$x1 + 0.2*dat$x2 + rnorm(grps)[dat$grp]), size = 1)
>>> failures <- by(dat, list(dat$x1, dat$x2, dat$grp), function(x) sum(x$y==0))
>>> successes <- by(dat, list(dat$x1, dat$x2, dat$grp), function(x) sum(x$y==1))
>>> dat2 <- expand.grid(x1=sort(unique(dat$x1)), x2=sort(unique(dat$x2)), grp=sort(unique(dat$grp)))
>>> dat2$failures <- as.vector(failures)
>>> dat2$successes <- as.vector(successes)
>>> library(lme4)
>>> system.time(glmer(y ~ x1 + x2 + (1 | grp), dat, family=binomial))
>>> #   user  system elapsed
>>> # 22.918   0.660  24.441
>>> system.time(glmer(cbind(successes, failures) ~ x1 + x2 + (1 | grp), dat2, family=binomial))
>>> #   user  system elapsed
>>> #  1.833   0.017   1.855
>>> detach("package:lme4")
>>> library(lme4Eigen)
>>> system.time(glmer(y ~ x1 + x2 + (1 | grp), dat, family=binomial))
>>> #   user  system elapsed
>>> # 24.824   1.811  26.773
>>> system.time(glmer(cbind(successes, failures) ~ x1 + x2 + (1 | grp), dat2, family=binomial))
>>> #   user  system elapsed
>>> #  1.687   0.039   1.723
>>
>> Thanks for sending that, Malcolm.
>>
>> Your collapsing of the binary responses to the number of successes and
>> failures works in this case by can't be expected to work in general.
>> In establishing dat2 using expand.grid you are assuming that all
>> combinations of covariates occur in the data.  If not you would end up
>> with a successes=0, failures=0 row and that might cause problems in
>> glm or glmer finding the proportion of successes (I havent' gone back
>> to look at the code to determine this).  I am trying to think of a way
>> of doing this using the type of strategy in the hidden function
>> duplicated.data.frame.  If you have the model frame and you know that
>> there are only two unique values for the response you can get the
>> counts by determining the unique combinations of covariates and using
>> xtabs. If you look at duplicated.data.frame, you will see that getting
>> the unique combinations is done by pasting the text representation of
>> the row using a separator that will not occur in numeric data.  The C
>> function do_duplicated uses hash tables and hashing a character string
>> is very fast.
>>
>> The end result looks like the enclosed.
>>
>> Of course, there is probably a much cleaner way of doing this using
>> Hadley Wickham's reshape package but I haven't studied that package
>> enough yet.
>>
>> As Malcolm said, the two sets of parameter estimates are very similar
>> but the deviance is different.  I am working on changes that will
>> create the proper value of the deviance from the model in terms of
>> successes and failure.  It is very confusing - the function in the glm
>> family that produces the deviance is called "aic" and the function
>> called "dev.resids" actually produces the square of the deviance
>> residuals and their sum should be the glm deviance, except when it
>> isn't.  It's disheartening at best.
>>
>> I also include a timing of the model fit using nAGQ=25 which should be
>> a very accurate evaluation of the deviance.
>>
>> The other version with nAGQ=0 uses a Laplace approximation and
>> (approximately) profiles out the fixed-effects parameters.  In many
>> situations this gets close enough to the correct deviance that the
>> results can be used for rough model comparisons.
>>
>>
>>>> Date: Thu, 9 Feb 2012 14:13:24 -0600
>>>> From: Douglas Bates <bates at stat.wisc.edu>
>>>> To: Joshua Wiley <jwiley.psych at gmail.com>
>>>> Cc: AC Del Re <acdelre at stanford.edu>, r-sig-mixed-models at r-project.org
>>>> Subject: Re: [R-sig-ME] LMM with Big data using binary DV
>>>>
>>>> On Wed, Feb 8, 2012 at 8:28 PM, Joshua Wiley <jwiley.psych at gmail.com> wrote:
>>>>> Hi AC,
>>>>>
>>>>> My personal preference would be glmer from the lme4 package. ?I prefer
>>>>> the Laplace approximation for the likelihood over the quasilikelihood
>>>>> in glmmPQL. ?To give some exemplary numbers, I simulated a dataset
>>>>> with 2 million observations nested within 200 groups (10,000
>>>>> observations per group). ?I then ran an random intercepts model using:
>>>>>
>>>>> system.time(m <- glmer(Y ~ X + W + (1 | G), family = "binomial"))
>>>>>
>>>>> where the matrices/vectors are of sizes: Y = [2 million, 1]; X = [2
>>>>> million, 6]; W = [2 million, 3]; G = [2 million, 1]
>>>>>
>>>>> This took around 481 seconds to fit on a 1.6ghz dual core laptop.
>>>>> With the OS and R running, my system used ~ 6GB of RAM for the model
>>>>> and went up to ~7GB to show the summary (copies of the data are
>>>>> made---changed in the upcoming version of lme4).
>>>>>
>>>>> So as long as you have plenty of memory, you should have no trouble
>>>>> modelling your data using glmer(). ?To initially make sure all your
>>>>> code works, I might use a subset of your data (say 10k), once you are
>>>>> convinced you have the model you want, run it on the full data.
>>>>
>>>> If you would have an opportunity to run that model fit or a comparable
>>>> on lme4Eigen::glmer we would appreciate information about speed,
>>>> accuracy and memory usage.
>>>>
>>>> In lme4Eigen::glmer there are different levels of precision in the
>>>> approximation to the deviance being optimizer.  These are controlled
>>>> by the nAGQ argument to the function.  The default, nAGQ=1, uses the
>>>> Laplace approximation.  The special value nAGQ=0 also uses the Laplace
>>>> approximation but profiles out the fixed-effects parameters.  This
>>>> profiling is not exact but usually gets you close to the optimum that
>>>> you would get from nAGQ=1, but much, much faster.  In a model like
>>>> this you can also use nAGQ>1 and <= 25.  On the model fits we have
>>>> tried we don't see a lot of difference in timing between, say, nAGQ=9
>>>> and nAGQ=25 but on a model fit like this you might.
>>>>
>>>> As a fallback, we would appreciate the code that you used to simulate
>>>> the response.  We could generate something ourselves, of course, but
>>>> it is easier to compare when you copy someone else's simulation.
>>>>> On Wed, Feb 8, 2012 at 5:28 PM, AC Del Re <acdelre at stanford.edu> wrote:
>>>>>> Hi,
>>>>>>
>>>>>> I have a huge dataset (2.5 million patients nested within ?> 100
>>>>>> facilities) and would like to examine variability across facilities in
>>>>>> program utilization (0=n, 1=y; utilization rates are low in general), along
>>>>>> with patient and facility predictors of utilization.
>>>>>>
>>>>>> I have 3 questions:
>>>>>>
>>>>>> 1. What program and/or package(s) do you recommend for running LMMs with
>>>>>> big data (even if they are not R packages)?
>>>>>>
>>>>>> 2. Are there any clever work arounds (e.g., random sampling of subset of
>>>>>> data, etc) that would allow me to use only R packages to run this dataset
>>>>>> (assuming I need to use another program due to the size of the dataset)?
>>>>>>
>>>>>> 3. What type of LMM is recommended with a binary DV similar to the one I am
>>>>>> wanting to examine? I know of two potential options (family=binomial option
>>>>>> in lmer and the glmmPQL in the MASS package) but am not sure which is more
>>>>>> appropriate or what other R packages and functions are available for this
>>>>>> purpose?
>>>>>>
>>>>>> Thank you,
>>>>>>
>>>>>> AC
>>>
>>> _______________________________________________
>>> R-sig-mixed-models at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-sig-mixed-models
>> <Malcolm_Rout.txt><Malcolm.R>
>




More information about the R-sig-mixed-models mailing list