dplyr访问列表中所有元素的子元素

时间:2019-04-10 19:32:28

标签: r dplyr purrr glmnet

我正在尝试从purrr包中安全地使用()和glmnet包中的套索回归。我被困在交叉验证部分,因为safely()返回一个包含两个元素的列表,即$ results和$ errors。我正在尝试使用dplyr仅获得$ results,但无法使其正常工作。

我可以使交叉验证适用于单个物种,但不能使用dplyr对所有物种进行交叉验证。

library(dplyr)
library(glmnet)
library(purrr)
data(iris)

# Group to perform regressions for every species
grouped <- iris %>% 
  group_by(Species)

# Make model matrices
mm <- grouped %>%
  do(mm = safely(model.matrix)(Sepal.Length ~ Sepal.Width + Petal.Width, data = .)[1])

# Join the dependent values with the model matrices in a tibble
sepallengths <- grouped %>% 
  summarise(Sepal.Length = list(Sepal.Length))
temp <- inner_join(sepallengths, mm, by = "Species")

# Perform cross validation using the tibble above
cv_holder <- temp %>% 
  group_by(Species) %>% 
  # How to get this to work inside dplyr?
  do(cv = safely(cv.glmnet)(.$mm[1]$result, .$Sepal.Length, alpha = 1, nlambda = 100))

# Contains only errors when it should contain the cross validations
cv_holder$cv

# Works for individual lists this way
safely(cv.glmnet)(temp$mm[[1]][1]$result, temp$Sepal.Length[[1]], alpha = 1, nlambda = 100)$result

我希望输出是带有列(cv)的小标题(cv_holder),该列​​包含包含每个物种的交叉验证列表的列表。但是,我可以让dplyr仅返回诸如“ rep(1,N)中的simpleError:无效的'times'参数”之类的错误

这可以通过循环来完成:

for(i in 1:length(temp$mm)){
    print(safely(cv.glmnet)(temp$mm[[i]][1]$result, temp$Sepal.Length[[i]], alpha = 1, nlambda = 100))
cv_holder$error <- NULL
}

2 个答案:

答案 0 :(得分:0)

即使只有1个值,您仍然需要索引列表。

例如:

cv_holder <- temp %>% 
  group_by(Species) %>% 
  # How to get this to work inside dplyr?
  do(cv = safely(cv.glmnet)(.$mm[1][[1]]$result, .$Sepal.Length[[1]], alpha = 1, nlambda = 100))

这只是一个意见,但:当数据整齐时使用tidyverse。如果需要,请使用for循环。我认为没有必要试图将某些内容强加到dplyr框架中,而这显然更令人困惑。

答案 1 :(得分:0)

我将其与purrr的pluck()配合使用,该工具从每个列表中选择第一项:

cv_holder <- temp %>% 
    group_by(Species) %>% 
    # Using pluck()
    do(cv = safely(cv.glmnet)(pluck(.$mm, 1)$result, pluck(.$Sepal.Length, 1), alpha = 1, nlambda = 100))

# Now works as intended
cv_holder$cv