广义线性混合模型交叉验证错误:'data[[cat_col]]'中的值必须在每个ID内保持不变
Error in generalized linear mixed model cross-validation: The value in 'data[[cat_col]]' must be constant within each ID
我正在尝试使用 groupdata2 和 cvms 包对广义线性混合模型进行 5 折交叉验证。这是我尝试 运行:
的代码
data <- groupdata2::fold(detect, k = 5,
cat_col = 'outcome',
id_col = 'bird') %>%
arrange(.folds)
cvms::cross_validate(
data,
"outcome ~ sex + year + season + (1 | bird) + (1 | obsname)",
family="binomial",
fold_cols = ".folds",
control = NULL,
REML = FALSE)
这是我收到的错误:
Error in groupdata2::fold(detect, k = 4, cat_col = "outcome", id_col = "bird") %>% :
1 assertions failed:
* The value in 'data[[cat_col]]' must be constant within each ID.
在包小插图中,给出了以下解释:“参与者必须在整个数据集中始终具有相同的诊断(‘a’或‘b’)。否则,参与者可能会被置于多个折叠中。”这在示例中是有意义的。然而,我的数据是基于重新观察鸟类的结果,因此结果会根据特定调查中是否观察到鸟类而有所不同。有解决办法吗?
可重现的例子:
bird <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3)
outcome <- c(0,1,1,1,0,0,0,1,0,1,0,1,0,0,1)
df <- data.frame(bird, outcome)
df$outcome <- as.factor(df$outcome)
df$bird <- as.factor(df$bird)
data <- groupdata2::fold(df, k = 5,
cat_col = 'outcome',
id_col = 'bird') %>%
arrange(.folds)
完整文档说:
cat_col
: Name of categorical variable to balance between folds.
E.g. when predicting a binary variable (a or b), we usually
want both classes represented in every fold.
N.B. If also passing an ‘id_col
’, ‘cat_col
’ should be
constant within each ID.
因此,在这种情况下,结果因个别鸟类而异 (id_col
),您根本无法指定折数根据结果进行平衡。 (我不是 100% 理解软件中的这个限制:似乎应该可以通过选择具有平衡结果范围的组(鸟类)来至少进行近似平衡,但我可以看到它如何使平衡过程更难了)。
不过,在我看来,平衡结果的重要性总体上有些被高估了。缺乏平衡意味着 ?binomial_metrics
中一些较简单的指标(例如准确性、灵敏度、特异性)不是很有用,但其他指标(平衡准确性、AUC、aic)应该没问题。
一个可能更大的问题是您似乎具有(可能)交叉随机效应(即 (1|bird) + (1|obsname)
)。我猜 obsname
是一个观察者的名字:如果一些观察者检测到(或未能检测到)多只鸟,而一些鸟被多个观察者 detected/failed ,那么可能无法定义折叠实际上是独立的,或者至少它可能非常困难。
为此,您可以使用 groupdata2 v2.0.0
中的新 collapse_groups()
函数代替 fold()
。它允许您采用现有组(例如 bird
)并将它们折叠为更少的组(例如折叠),并尝试平衡多个分类列、数字列和因子列(唯一级别的数量 - 尽管相同的级别可能在多个组中)。
它没有 fold()
在改变结果方面所做的限制,但另一方面在“不变结果”上下文中没有相同的“保证”。例如。它不保证在所有折叠中至少有一个结果级别。
虽然你需要的鸟比折叠的数量更多,所以我在测试数据中添加了一些:
bird <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,
4,4,4,5,5,5,5,5,6,6,6,6,6,7,7,7,7)
outcome <- c(0,1,1,1,0,0,0,1,0,1,0,1,0,0,1,0,1,
0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1,1)
df <- data.frame(bird, outcome)
df$outcome <- as.factor(df$outcome)
df$bird <- as.factor(df$bird)
# Combine 'bird' groups to folds
data <- groupdata2::collapse_groups(
data = df,
n = 3,
group_cols="bird",
cat_col="outcome",
col_name = ".folds"
) %>%
arrange(.folds)
# Check the balance of the relevant columns
groupdata2::summarize_balances(
data=data,
group_cols=".folds",
cat_cols="outcome"
)$Groups
> # A tibble: 3 × 6
> .group_col .group `# rows` `# bird` `# outc_0` `# outc_1`
> <fct> <fct> <int> <int> <dbl> <dbl>
> 1 .folds 1 14 3 7 7
> 2 .folds 2 10 2 6 4
> 3 .folds 3 10 2 4 6
summarize_balances()
向我们展示了我们创建了 3 个折叠,第一个折叠有 14 行,其他折叠有 10 行。第一个折叠有 3 个独特的鸟级别,其他有 2 个(通常只在组内唯一,但在这里我们知道鸟只在一个组中,因为这就是 collapse_groups()
与其 [=18 一起工作的方式=] 参数)。
结果变量(这里 # outc_0
和 # outc_1
)在某种程度上是平衡的。
对于较大的数据集,您可能想要 运行 多次折叠并从摘要中选择具有最佳平衡的那个。这可以通过将 num_new_group_cols = 10
添加到 collapse_groups()
来完成(为了获得更好的结果,启用 auto_tune
设置)然后在 运行ning [=16] 时列出所有创建的组列=].
希望这对您或处于类似情况的其他人有所帮助。 fold()
中的约束很难通过其当前的内部方法解决,但 collapse_groups
希望在这些情况下可以解决问题。
查看更多https://rdrr.io/cran/groupdata2/man/collapse_groups.html
我正在尝试使用 groupdata2 和 cvms 包对广义线性混合模型进行 5 折交叉验证。这是我尝试 运行:
的代码data <- groupdata2::fold(detect, k = 5,
cat_col = 'outcome',
id_col = 'bird') %>%
arrange(.folds)
cvms::cross_validate(
data,
"outcome ~ sex + year + season + (1 | bird) + (1 | obsname)",
family="binomial",
fold_cols = ".folds",
control = NULL,
REML = FALSE)
这是我收到的错误:
Error in groupdata2::fold(detect, k = 4, cat_col = "outcome", id_col = "bird") %>% :
1 assertions failed:
* The value in 'data[[cat_col]]' must be constant within each ID.
在包小插图中,给出了以下解释:“参与者必须在整个数据集中始终具有相同的诊断(‘a’或‘b’)。否则,参与者可能会被置于多个折叠中。”这在示例中是有意义的。然而,我的数据是基于重新观察鸟类的结果,因此结果会根据特定调查中是否观察到鸟类而有所不同。有解决办法吗?
可重现的例子:
bird <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3)
outcome <- c(0,1,1,1,0,0,0,1,0,1,0,1,0,0,1)
df <- data.frame(bird, outcome)
df$outcome <- as.factor(df$outcome)
df$bird <- as.factor(df$bird)
data <- groupdata2::fold(df, k = 5,
cat_col = 'outcome',
id_col = 'bird') %>%
arrange(.folds)
完整文档说:
cat_col
: Name of categorical variable to balance between folds. E.g. when predicting a binary variable (a or b), we usually want both classes represented in every fold. N.B. If also passing an ‘id_col
’, ‘cat_col
’ should be constant within each ID.
因此,在这种情况下,结果因个别鸟类而异 (id_col
),您根本无法指定折数根据结果进行平衡。 (我不是 100% 理解软件中的这个限制:似乎应该可以通过选择具有平衡结果范围的组(鸟类)来至少进行近似平衡,但我可以看到它如何使平衡过程更难了)。
不过,在我看来,平衡结果的重要性总体上有些被高估了。缺乏平衡意味着 ?binomial_metrics
中一些较简单的指标(例如准确性、灵敏度、特异性)不是很有用,但其他指标(平衡准确性、AUC、aic)应该没问题。
一个可能更大的问题是您似乎具有(可能)交叉随机效应(即 (1|bird) + (1|obsname)
)。我猜 obsname
是一个观察者的名字:如果一些观察者检测到(或未能检测到)多只鸟,而一些鸟被多个观察者 detected/failed ,那么可能无法定义折叠实际上是独立的,或者至少它可能非常困难。
为此,您可以使用 groupdata2 v2.0.0
中的新 collapse_groups()
函数代替 fold()
。它允许您采用现有组(例如 bird
)并将它们折叠为更少的组(例如折叠),并尝试平衡多个分类列、数字列和因子列(唯一级别的数量 - 尽管相同的级别可能在多个组中)。
它没有 fold()
在改变结果方面所做的限制,但另一方面在“不变结果”上下文中没有相同的“保证”。例如。它不保证在所有折叠中至少有一个结果级别。
虽然你需要的鸟比折叠的数量更多,所以我在测试数据中添加了一些:
bird <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,
4,4,4,5,5,5,5,5,6,6,6,6,6,7,7,7,7)
outcome <- c(0,1,1,1,0,0,0,1,0,1,0,1,0,0,1,0,1,
0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1,1)
df <- data.frame(bird, outcome)
df$outcome <- as.factor(df$outcome)
df$bird <- as.factor(df$bird)
# Combine 'bird' groups to folds
data <- groupdata2::collapse_groups(
data = df,
n = 3,
group_cols="bird",
cat_col="outcome",
col_name = ".folds"
) %>%
arrange(.folds)
# Check the balance of the relevant columns
groupdata2::summarize_balances(
data=data,
group_cols=".folds",
cat_cols="outcome"
)$Groups
> # A tibble: 3 × 6
> .group_col .group `# rows` `# bird` `# outc_0` `# outc_1`
> <fct> <fct> <int> <int> <dbl> <dbl>
> 1 .folds 1 14 3 7 7
> 2 .folds 2 10 2 6 4
> 3 .folds 3 10 2 4 6
summarize_balances()
向我们展示了我们创建了 3 个折叠,第一个折叠有 14 行,其他折叠有 10 行。第一个折叠有 3 个独特的鸟级别,其他有 2 个(通常只在组内唯一,但在这里我们知道鸟只在一个组中,因为这就是 collapse_groups()
与其 [=18 一起工作的方式=] 参数)。
结果变量(这里 # outc_0
和 # outc_1
)在某种程度上是平衡的。
对于较大的数据集,您可能想要 运行 多次折叠并从摘要中选择具有最佳平衡的那个。这可以通过将 num_new_group_cols = 10
添加到 collapse_groups()
来完成(为了获得更好的结果,启用 auto_tune
设置)然后在 运行ning [=16] 时列出所有创建的组列=].
希望这对您或处于类似情况的其他人有所帮助。 fold()
中的约束很难通过其当前的内部方法解决,但 collapse_groups
希望在这些情况下可以解决问题。
查看更多https://rdrr.io/cran/groupdata2/man/collapse_groups.html