Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

plot.lm Error: $ operator is invalid for atomic vectors

I have the following regression model with transformations:

fit <- lm( I(NewValue ^ (1 / 3)) ~ I(CurrentValue ^ (1 / 3)) + Age + Type - 1,
           data = dataReg)
plot(fit)                                                                      

But plot gives me the following error:

Error: $ operator is invalid for atomic vectors

Any ideas about what I am doing wrong?

Note: summary, predict, and residuals all work correctly.

like image 690
k88074 Avatar asked Jan 06 '23 02:01

k88074


1 Answers

This is actually quite a interesting observation. In fact, among all 6 plots supported by plot.lm, only the Q-Q plot fails in this case. Consider the following reproducible example:

x <- runif(20)
y <- runif(20)
fit <- lm(I(y ^ (1/3)) ~ I(x ^ (1/3)))
## only `which = 2L` (QQ plot) fails; `which = 1, 3, 4, 5, 6` all work
stats:::plot.lm(fit, which = 2L)

Inside plot.lm, the Q-Q plot is simply produced as follow:

rs <- rstandard(fit)  ## standardised residuals
qqnorm(rs)  ## fine
## inside `qqline(rs)`
yy <- quantile(rs, c(0.25, 0.75))
xx <- qnorm(c(0.25, 0.75))
slope <- diff(yy)/diff(xx)
int <- yy[1L] - slope * xx[1L]
abline(int, slope)  ## this fails!!!

Error: $ operator is invalid for atomic vectors

So this is purely a problem of abline function! Note:

is.object(int)
# [1] TRUE

is.object(slope)
# [1] TRUE

i.e., both int and slope has class attribute (read ?is.object; it is a very efficient way to check whether an object has class attribute). What class?

class(int)
# [1] AsIs

class(slope)
# [1] AsIs

This is the result of using I(). Precisely, they inherits such class from rs and further from the response variable. That is, if we use I() on response, the RHS of the model formula, we get this behaviour.

You can do a few experiment here:

abline(as.numeric(int), as.numeric(slope))  ## OK
abline(as.numeric(int), slope)  ## OK
abline(int, as.numeric(slope))  ## fails!!
abline(int, slope)  ## fails!!

So abline(a, b) is very sensitive to whether the first argument a has class attribute or not.

Why? Because abline can accept a linear model object with "lm" class. Inside abline:

if (is.object(a) || is.list(a)) {
    p <- length(coefa <- as.vector(coef(a)))

If a has a class, abline is assuming it as a model object (regardless whether it is really is!!!), then try to use coef to obtain coefficients. The check being done here is fairly not robust; we can make abline fail rather easily:

plot(0:1, 0:1)
a <- 0  ## plain numeric
abline(a, 1)  ## OK
class(a) <- "whatever"  ## add a class
abline(a, 1)  ## oops, fails!!!

Error: $ operator is invalid for atomic vectors

So here is the conclusion: avoid using I() on your response variable in the model formula. It is OK to have I() on covariates, but not on response. lm and most generic functions won't have trouble dealing with this, but plot.lm will.

like image 172
Zheyuan Li Avatar answered Jan 13 '23 10:01

Zheyuan Li