tassones
tassones

Reputation: 1692

Converting residual output from list to data frame in R

How do I convert the list of residuals (beer_residuals) below into a data frame?

beer <- read.csv("http://users.stat.umn.edu/~helwig/notes/MNbeer.csv")
beer_model <- lapply(unique(beer$Style),
                     function(x) lm(Rating~ABV, beer[beer$Style == x,]))
beer_residuals <- lapply(beer_model, resid)

I have tried the following, but neither work:

df_beer <- as.data.frame(beer_residuals)
df_beer <- do.call(rbind.data.frame, beer_residuals)

Ideally, the output would be a data frame with columns Style and ResidualValue as below:

   Style ResidualValue
1  Lager    1.08823529
2  Lager    1.14705882
3  Lager   -0.91176471
4  Lager    1.14705882
5  Lager    0.88235294
6  Lager    1.47058824
7  Lager   -2.64705882
8  Lager   -2.52941176
9  Lager    0.35294118
10   IPA   -3.05011974
11   IPA    3.17858365
12   IPA    2.24136161
...32 more rows

I am not looking for an answer like below because the true dataset I have has 100's of grouping variables (i.e., Style) of varying styles:

df_beer <- data.frame(matrix(ncol = 2, nrow = 44))
x <- c("Style", "ResidualValue")
colnames(df_beer) <- x
df_beer$Style <- c(rep("Lager",9),rep("IPA",17),rep("Ale",18))
df_beer$ResidualValue <- c(beer_residuals[[1]],beer_residuals[[2]],beer_residuals[[3]])

Upvotes: 3

Views: 213

Answers (2)

thelatemail
thelatemail

Reputation: 93813

Do it with the basic lm functionality via the formula interface directly:

lm(Rating ~ ABV:Style + Style, data = beer)$resid

Or put into a dataset:

data.frame(
   beer["Style"],
   Resid = lm(Rating ~ ABV:Style + Style, data = beer)$resid
)
#   Style       Resid
#1  Lager  1.08823529
#2  Lager  1.14705882
#3  Lager -0.91176471
#4    IPA -3.05011974
#5    Ale -0.27154460
#...

Upvotes: 2

Ronak Shah
Ronak Shah

Reputation: 388982

Using dplyr you can follow this approach :

library(dplyr)

beer %>%
  group_by(Style) %>%
  summarise(model = list(lm(Rating~ABV, cur_data())), 
            ResidualValue = purrr::map(model, resid)) %>%
  select(-model) %>%
  tidyr::unnest(ResidualValue)

#   Style ResidualValue
#   <chr>         <dbl>
# 1 Ale          -0.272
# 2 Ale           0.929
# 3 Ale           1.03 
# 4 Ale           3.38 
# 5 Ale           2.08 
# 6 Ale          -6.27 
# 7 Ale          -0.721
# 8 Ale          -1.09 
# 9 Ale          -2.22 
#10 Ale          -3.17 
# … with 34 more rows

In base R, we can use by :

do.call(rbind, by(beer, beer$Style, function(x) {
  model <- lm(Rating~ABV, x)
  data.frame(Style = x$Style[1], ResidualValue = resid(model))
}))

Upvotes: 4

Related Questions