dplyr 访问列表所有元素的子元素
dplyr accessing a subelement of all elements of a list
我正在尝试将 purrr 包中的 safely() 与 glmnet 包中的套索回归一起使用。我被困在交叉验证部分,因为 safely() returns 是一个包含两个元素 $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_holder),其中有一列 (cv),其中包含包含每个物种的交叉验证列表的列表。但是,我只能让 dplyr 到 return 错误,例如 "simpleError in rep(1, N): invalid 'times' argument"
这是通过循环完成的方法:
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
}
您仍然需要对列表进行索引,即使只有 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
框架中有什么意义。
我让它与 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
我正在尝试将 purrr 包中的 safely() 与 glmnet 包中的套索回归一起使用。我被困在交叉验证部分,因为 safely() returns 是一个包含两个元素 $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_holder),其中有一列 (cv),其中包含包含每个物种的交叉验证列表的列表。但是,我只能让 dplyr 到 return 错误,例如 "simpleError in rep(1, N): invalid 'times' argument"
这是通过循环完成的方法:
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
}
您仍然需要对列表进行索引,即使只有 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
框架中有什么意义。
我让它与 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