Here's the speed-dating version:
Everything in R
is an object—punctuation, numerals, arrays, matrices, vectors, lists, data frame, data tables, their supersets and subsets, the S3
object here, the sometimes seen S4
objects, the rarely seen R6
objects, functions and even operators like + - / *
.
To distinguish objects they have all sorts of properties that provide a key to the internal structure, which is what str()
does. The fragment for cl
looks like a typical regression model fit, but I can tell for sure. So let's walk through a simple example without all the bells and whistles about getting it into printable shape.
I'm going to use the reprex
style mentioned earlier. I'm using a built-in dataset that illustrates the behavior, but it could be my real data or fake data. It just has to operate similarly.
There is a wealth of information packed into the object
# create ordinary least square regression model
fit <- lm(mpg~drat,mtcars)
fit
#>
#> Call:
#> lm(formula = mpg ~ drat, data = mtcars)
#>
#> Coefficients:
#> (Intercept) drat
#> -7.525 7.678
summary(fit)
#>
#> Call:
#> lm(formula = mpg ~ drat, data = mtcars)
#>
#> Residuals:
#> Min 1Q Median 3Q Max
#> -9.0775 -2.6803 -0.2095 2.2976 9.0225
#>
#> Coefficients:
#> Estimate Std. Error t value Pr(>|t|)
#> (Intercept) -7.525 5.477 -1.374 0.18
#> drat 7.678 1.507 5.096 1.78e-05 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> Residual standard error: 4.485 on 30 degrees of freedom
#> Multiple R-squared: 0.464, Adjusted R-squared: 0.4461
#> F-statistic: 25.97 on 1 and 30 DF, p-value: 1.776e-05
str(fit)
#> List of 12
#> $ coefficients : Named num [1:2] -7.52 7.68
#> ..- attr(*, "names")= chr [1:2] "(Intercept)" "drat"
#> $ residuals : Named num [1:32] -1.42 -1.42 0.763 5.276 2.038 ...
#> ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
#> $ effects : Named num [1:32] -113.65 -22.86 1.05 5.28 2.07 ...
#> ..- attr(*, "names")= chr [1:32] "(Intercept)" "drat" "" "" ...
#> $ rank : int 2
#> $ fitted.values: Named num [1:32] 22.4 22.4 22 16.1 16.7 ...
#> ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
#> $ assign : int [1:2] 0 1
#> $ qr :List of 5
#> ..$ qr : num [1:32, 1:2] -5.657 0.177 0.177 0.177 0.177 ...
#> .. ..- attr(*, "dimnames")=List of 2
#> .. .. ..$ : chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
#> .. .. ..$ : chr [1:2] "(Intercept)" "drat"
#> .. ..- attr(*, "assign")= int [1:2] 0 1
#> ..$ qraux: num [1:2] 1.18 1.09
#> ..$ pivot: int [1:2] 1 2
#> ..$ tol : num 1e-07
#> ..$ rank : int 2
#> ..- attr(*, "class")= chr "qr"
#> $ df.residual : int 30
#> $ xlevels : Named list()
#> $ call : language lm(formula = mpg ~ drat, data = mtcars)
#> $ terms :Classes 'terms', 'formula' language mpg ~ drat
#> .. ..- attr(*, "variables")= language list(mpg, drat)
#> .. ..- attr(*, "factors")= int [1:2, 1] 0 1
#> .. .. ..- attr(*, "dimnames")=List of 2
#> .. .. .. ..$ : chr [1:2] "mpg" "drat"
#> .. .. .. ..$ : chr "drat"
#> .. ..- attr(*, "term.labels")= chr "drat"
#> .. ..- attr(*, "order")= int 1
#> .. ..- attr(*, "intercept")= int 1
#> .. ..- attr(*, "response")= int 1
#> .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
#> .. ..- attr(*, "predvars")= language list(mpg, drat)
#> .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
#> .. .. ..- attr(*, "names")= chr [1:2] "mpg" "drat"
#> $ model :'data.frame': 32 obs. of 2 variables:
#> ..$ mpg : num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
#> ..$ drat: num [1:32] 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
#> ..- attr(*, "terms")=Classes 'terms', 'formula' language mpg ~ drat
#> .. .. ..- attr(*, "variables")= language list(mpg, drat)
#> .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
#> .. .. .. ..- attr(*, "dimnames")=List of 2
#> .. .. .. .. ..$ : chr [1:2] "mpg" "drat"
#> .. .. .. .. ..$ : chr "drat"
#> .. .. ..- attr(*, "term.labels")= chr "drat"
#> .. .. ..- attr(*, "order")= int 1
#> .. .. ..- attr(*, "intercept")= int 1
#> .. .. ..- attr(*, "response")= int 1
#> .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
#> .. .. ..- attr(*, "predvars")= language list(mpg, drat)
#> .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
#> .. .. .. ..- attr(*, "names")= chr [1:2] "mpg" "drat"
#> - attr(*, "class")= chr "lm"
# example formatter
broom::tidy(fit)
#> # A tibble: 2 Ă— 5
#> term estimate std.error statistic p.value
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 (Intercept) -7.52 5.48 -1.37 0.180
#> 2 drat 7.68 1.51 5.10 0.0000178
summary(fit)
#>
#> Call:
#> lm(formula = mpg ~ drat, data = mtcars)
#>
#> Residuals:
#> Min 1Q Median 3Q Max
#> -9.0775 -2.6803 -0.2095 2.2976 9.0225
#>
#> Coefficients:
#> Estimate Std. Error t value Pr(>|t|)
#> (Intercept) -7.525 5.477 -1.374 0.18
#> drat 7.678 1.507 5.096 1.78e-05 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> Residual standard error: 4.485 on 30 degrees of freedom
#> Multiple R-squared: 0.464, Adjusted R-squared: 0.4461
#> F-statistic: 25.97 on 1 and 30 DF, p-value: 1.776e-05
fit[1] # numeric indexing
#> $coefficients
#> (Intercept) drat
#> -7.524618 7.678233
fit$coefficients # name attributs
#> (Intercept) drat
#> -7.524618 7.678233
fit[2]
#> $residuals
#> Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
#> -1.42048871 -1.42048871 0.76342292 5.27566203
#> Hornet Sportabout Valiant Duster 360 Merc 240D
#> 2.03818575 4.43269646 -2.82250821 3.59194014
#> Merc 230 Merc 280 Merc 280C Merc 450SE
#> 0.22594664 -3.37405336 -4.77405336 0.35244435
#> Merc 450SL Merc 450SLC Cadillac Fleetwood Lincoln Continental
#> 1.25244435 -0.84755565 -4.57260308 -5.11007936
#> Chrysler Imperial Fiat 128 Honda Civic Toyota Corolla
#> -2.57607286 8.59742943 0.07093171 9.02247686
#> Toyota Corona Dodge Challenger AMC Javelin Camaro Z28
#> 0.61515782 1.83269646 -1.46181425 -7.81518916
#> Pontiac Firebird Fiat X1-9 Porsche 914-2 Lotus Europa
#> 3.07566203 3.49742943 -0.48995198 8.97768153
#> Ford Pantera L Ferrari Dino Maserati Bora Volvo 142E
#> -9.07752314 -0.57058358 -4.65632497 -2.63291755
fit$residuals
#> Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
#> -1.42048871 -1.42048871 0.76342292 5.27566203
#> Hornet Sportabout Valiant Duster 360 Merc 240D
#> 2.03818575 4.43269646 -2.82250821 3.59194014
#> Merc 230 Merc 280 Merc 280C Merc 450SE
#> 0.22594664 -3.37405336 -4.77405336 0.35244435
#> Merc 450SL Merc 450SLC Cadillac Fleetwood Lincoln Continental
#> 1.25244435 -0.84755565 -4.57260308 -5.11007936
#> Chrysler Imperial Fiat 128 Honda Civic Toyota Corolla
#> -2.57607286 8.59742943 0.07093171 9.02247686
#> Toyota Corona Dodge Challenger AMC Javelin Camaro Z28
#> 0.61515782 1.83269646 -1.46181425 -7.81518916
#> Pontiac Firebird Fiat X1-9 Porsche 914-2 Lotus Europa
#> 3.07566203 3.49742943 -0.48995198 8.97768153
#> Ford Pantera L Ferrari Dino Maserati Bora Volvo 142E
#> -9.07752314 -0.57058358 -4.65632497 -2.63291755
fit$call
#> lm(formula = mpg ~ drat, data = mtcars)
and it can be tedious digging it out, which is the attraction of tools like {jtools}
but it helps to be able to know how to do it manually.
The place to start is help(lm)
in the Value
section, where it explains not only what these are all called but what they are
An object of class "lm" is a list containing at least the following components:
coefficients
a named vector of coefficients
residuals
the residuals, that is response minus fitted values.
fitted.values
the fitted mean values.
rank
the numeric rank of the fitted linear model.
weights
(only for weighted fits) the specified weights.
df.residual
the residual degrees of freedom.
call
the matched call.
terms
the terms object used.
contrasts
(only where relevant) the contrasts used.
xlevels
(only where relevant) a record of the levels of the factors used in fitting.
offset
the offset used (missing if none were used).
y
if requested, the response used.
x
if requested, the model matrix used.
model
if requested (the default), the model frame used.
na.action
(where relevant) information returned by model.frame on the special handling of NAs.
In addition, non-null fits will have components assign, effects and (unless not requested) qr relating to the linear fit, for use by extractor functions such as summary and effects.
So we have that lm
objects are lists. Lists are like vectors except that they can contain both numeric and character content. Like vectors they can be subset using the square bracket operator. Here's an example of a list both with and without naming
s <- list(LETTERS,letters)
s[2]
#> [[1]]
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
#> [20] "t" "u" "v" "w" "x" "y" "z"
s$uppercase
#> NULL
s <- list(uppercase = LETTERS, lowercase = letters)
s[2]
#> $lowercase
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
#> [20] "t" "u" "v" "w" "x" "y" "z"
s$lowercase
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
#> [20] "t" "u" "v" "w" "x" "y" "z"
What I'd suggest is working at this level for a bit before going on to get them all gussied up for display.