将 confusionMatrix() 应用于 R 中拆分列表的元素
Apply confusionMatrix() to Elements of a Split List in R
我正在寻找将 {caret} 中的 confusionMatrix() 函数应用于拆分列表的特定元素的解决方案。我有 3 个组,每个组有 10 个实际值观察值和 3 个预测值列。
library(caret)
set.seed(10)
dat <- data.frame(Group = c(rep(1, 10), rep(2, 10), rep(3, 10)), Actual = round(runif(30, 0, 1)),
Preds1 = round(runif(30, 0, 1)), Preds2 = round(runif(30, 0, 1)), Preds3 = round(runif(30, 0, 1)))
> dat
Group Actual Preds1 Preds2 Preds3
1 1 1 1 0 0
2 1 0 0 0 1
3 1 0 0 0 1
4 1 1 1 0 1
...........
27 3 1 0 1 0
28 3 0 0 0 1
29 3 1 0 0 1
30 3 0 1 0 1
最终解决方案应该按组、每个 Preds 列创建混淆矩阵。我将需要实际的混淆矩阵 tables,但最终将需要提取 $overall 和 $byClass 元素并最终得到如下所示的内容。
> conf_matrix
$Preds1
Accuracy Sensitivity Specificity
[1,] 0.73 0.8 0.6
[2,] 0.93 0.91 1
[3,] 0.87 0.83 1
[4,] 0.8 0.82 0.75
...............
[27,] 0.8 0.82 0.75
[28,] 0.58 0.67 0.5
[29,] 1 0.67 1
[30,] 1 0 1
$Preds2
Accuracy Sensitivity Specificity
[1,] 0.73 0.8 0.6
[2,] 0.93 0.91 1
[3,] 0.87 0.83 1
[4,] 0.8 0.82 0.75
...............
[27,] 0.8 0.82 0.75
[28,] 0.58 0.67 0.5
[29,] 1 0.67 1
[30,] 1 0 1
$Preds3
...............
我尝试了下面的脚本,但是在尝试每个组中的 Preds 列的二级索引时,运行 仍然存在问题。我相信它与我的嵌套 lapply 以及我的索引方式有关,因为当我分解代码并一次一个地执行它时,它就起作用了。
我也曾尝试使用 table() 手动执行此操作,但是放弃了该方法,因为它无法像使用 confusionMatrix() 那样给我提供一致的结果。
lapply(seq_along(split(dat[3:5], list(dat$Group))), function(x) {
x_temp <- split(dat[3:5], list(dat$Group))[[x]]
lapply(seq_along(x_temp), function(x2) {
x_temp <- x_temp[[x2]]
lapply(seq_along(split(dat[2], list(dat$Group))), function(y) {
y_temp <- split(dat[2], list(dat$Group))[[y]]
lapply(seq_along(y_temp), function(y2) {
y_temp <- y_temp[[y2]]
confusionMatrix(x_temp, y_temp)
})
})
})
})
我可能离题太远,所以我愿意接受所有建议和评论。
我不明白最后的结果,但混淆矩阵可以通过以下方式获得。
library(caret)
set.seed(10)
dat <- data.frame(Group = c(rep(1, 10), rep(2, 10), rep(3, 10)), Actual = round(runif(30, 0, 1)),
Preds1 = round(runif(30, 0, 1)), Preds2 = round(runif(30, 0, 1)), Preds3 = round(runif(30, 0, 1)))
dat[] <- lapply(dat, as.factor)
# split by group
dats <- split(dat[,-1], dat$Group)
cm <- do.call(c, lapply(dats, function(x) {
actual <- x[, 1]
lapply(x[, 2:4], function(y) {
confusionMatrix(actual, unlist(y))$table
})
}))
cm[1:3]
$`1.Preds1`
Reference
Prediction 0 1
0 3 4
1 0 3
$`1.Preds2`
Reference
Prediction 0 1
0 4 3
1 3 0
$`1.Preds3`
Reference
Prediction 0 1
0 3 4
1 1 2
@布莱恩
在 link (What's the difference between lapply and do.call in R?) 中,我发现 Paul Hiemstra 的回答非常直截了当。
-lapply
类似于map
,do.call
则不然。 lapply
将函数应用于列表的所有元素,do.call
调用所有函数参数都在列表中的函数。因此对于 n
元素列表,lapply
有 n
函数调用,而 do.call
有 one
函数调用。所以 do.call
与 lapply
完全不同。
示例中,
dats
具有三个元素 - 1
、2
和 3
dats <- split(dat[,-1], dat$Group)
dats[1]
$`1`
Actual Preds1 Preds2 Preds3
1 1 1 0 0
2 0 0 0 1
3 0 0 0 1
4 1 1 0 1
5 0 0 1 0
6 0 1 1 1
7 0 1 1 0
8 0 1 0 1
9 1 1 0 1
10 0 1 0 0
下面是双循环,第一个循环应用于 1
、2
和 3
,第二个循环应用于 Preds1、Preds2 和 Preds3。因此 lapply()
单独生成的列表会生成如下所示的嵌套列表。
lapply(dats, function(x) {
actual <- x[, 1]
lapply(x[, 2:4], function(y) {
confusionMatrix(actual, unlist(y))$table
})
})[1]
$`1`
$`1`$Preds1
Reference
Prediction 0 1
0 3 4
1 0 3
$`1`$Preds2
Reference
Prediction 0 1
0 4 3
1 3 0
$`1`$Preds3
Reference
Prediction 0 1
0 3 4
1 1 2
然而,上面的内容以后不容易使用,因为需要另一个双循环才能访问每个混淆矩阵。它被简化为 do.call()
。第一个参数 c
是一个函数,它执行 c(dats$
1$Preds1, dats$
1$Preds2, dats$
1$Preds2 ...)
以便将结构简化为可通过单循环访问。通常我倾向于在需要更改列表结构时使用 do.call()
。
do.call(c, lapply(dats, function(x) {
actual <- x[, 1]
lapply(x[, 2:4], function(y) {
confusionMatrix(actual, unlist(y))$table
})
}))[1:3]
$`1.Preds1`
Reference
Prediction 0 1
0 3 4
1 0 3
$`1.Preds2`
Reference
Prediction 0 1
0 4 3
1 3 0
$`1.Preds3`
Reference
Prediction 0 1
0 3 4
1 1 2
我正在寻找将 {caret} 中的 confusionMatrix() 函数应用于拆分列表的特定元素的解决方案。我有 3 个组,每个组有 10 个实际值观察值和 3 个预测值列。
library(caret)
set.seed(10)
dat <- data.frame(Group = c(rep(1, 10), rep(2, 10), rep(3, 10)), Actual = round(runif(30, 0, 1)),
Preds1 = round(runif(30, 0, 1)), Preds2 = round(runif(30, 0, 1)), Preds3 = round(runif(30, 0, 1)))
> dat
Group Actual Preds1 Preds2 Preds3
1 1 1 1 0 0
2 1 0 0 0 1
3 1 0 0 0 1
4 1 1 1 0 1
...........
27 3 1 0 1 0
28 3 0 0 0 1
29 3 1 0 0 1
30 3 0 1 0 1
最终解决方案应该按组、每个 Preds 列创建混淆矩阵。我将需要实际的混淆矩阵 tables,但最终将需要提取 $overall 和 $byClass 元素并最终得到如下所示的内容。
> conf_matrix
$Preds1
Accuracy Sensitivity Specificity
[1,] 0.73 0.8 0.6
[2,] 0.93 0.91 1
[3,] 0.87 0.83 1
[4,] 0.8 0.82 0.75
...............
[27,] 0.8 0.82 0.75
[28,] 0.58 0.67 0.5
[29,] 1 0.67 1
[30,] 1 0 1
$Preds2
Accuracy Sensitivity Specificity
[1,] 0.73 0.8 0.6
[2,] 0.93 0.91 1
[3,] 0.87 0.83 1
[4,] 0.8 0.82 0.75
...............
[27,] 0.8 0.82 0.75
[28,] 0.58 0.67 0.5
[29,] 1 0.67 1
[30,] 1 0 1
$Preds3
...............
我尝试了下面的脚本,但是在尝试每个组中的 Preds 列的二级索引时,运行 仍然存在问题。我相信它与我的嵌套 lapply 以及我的索引方式有关,因为当我分解代码并一次一个地执行它时,它就起作用了。
我也曾尝试使用 table() 手动执行此操作,但是放弃了该方法,因为它无法像使用 confusionMatrix() 那样给我提供一致的结果。
lapply(seq_along(split(dat[3:5], list(dat$Group))), function(x) {
x_temp <- split(dat[3:5], list(dat$Group))[[x]]
lapply(seq_along(x_temp), function(x2) {
x_temp <- x_temp[[x2]]
lapply(seq_along(split(dat[2], list(dat$Group))), function(y) {
y_temp <- split(dat[2], list(dat$Group))[[y]]
lapply(seq_along(y_temp), function(y2) {
y_temp <- y_temp[[y2]]
confusionMatrix(x_temp, y_temp)
})
})
})
})
我可能离题太远,所以我愿意接受所有建议和评论。
我不明白最后的结果,但混淆矩阵可以通过以下方式获得。
library(caret)
set.seed(10)
dat <- data.frame(Group = c(rep(1, 10), rep(2, 10), rep(3, 10)), Actual = round(runif(30, 0, 1)),
Preds1 = round(runif(30, 0, 1)), Preds2 = round(runif(30, 0, 1)), Preds3 = round(runif(30, 0, 1)))
dat[] <- lapply(dat, as.factor)
# split by group
dats <- split(dat[,-1], dat$Group)
cm <- do.call(c, lapply(dats, function(x) {
actual <- x[, 1]
lapply(x[, 2:4], function(y) {
confusionMatrix(actual, unlist(y))$table
})
}))
cm[1:3]
$`1.Preds1`
Reference
Prediction 0 1
0 3 4
1 0 3
$`1.Preds2`
Reference
Prediction 0 1
0 4 3
1 3 0
$`1.Preds3`
Reference
Prediction 0 1
0 3 4
1 1 2
@布莱恩
在 link (What's the difference between lapply and do.call in R?) 中,我发现 Paul Hiemstra 的回答非常直截了当。
-lapply
类似于map
,do.call
则不然。 lapply
将函数应用于列表的所有元素,do.call
调用所有函数参数都在列表中的函数。因此对于 n
元素列表,lapply
有 n
函数调用,而 do.call
有 one
函数调用。所以 do.call
与 lapply
完全不同。
示例中,
dats
具有三个元素 - 1
、2
和 3
dats <- split(dat[,-1], dat$Group)
dats[1]
$`1`
Actual Preds1 Preds2 Preds3
1 1 1 0 0
2 0 0 0 1
3 0 0 0 1
4 1 1 0 1
5 0 0 1 0
6 0 1 1 1
7 0 1 1 0
8 0 1 0 1
9 1 1 0 1
10 0 1 0 0
下面是双循环,第一个循环应用于 1
、2
和 3
,第二个循环应用于 Preds1、Preds2 和 Preds3。因此 lapply()
单独生成的列表会生成如下所示的嵌套列表。
lapply(dats, function(x) {
actual <- x[, 1]
lapply(x[, 2:4], function(y) {
confusionMatrix(actual, unlist(y))$table
})
})[1]
$`1`
$`1`$Preds1
Reference
Prediction 0 1
0 3 4
1 0 3
$`1`$Preds2
Reference
Prediction 0 1
0 4 3
1 3 0
$`1`$Preds3
Reference
Prediction 0 1
0 3 4
1 1 2
然而,上面的内容以后不容易使用,因为需要另一个双循环才能访问每个混淆矩阵。它被简化为 do.call()
。第一个参数 c
是一个函数,它执行 c(dats$
1$Preds1, dats$
1$Preds2, dats$
1$Preds2 ...)
以便将结构简化为可通过单循环访问。通常我倾向于在需要更改列表结构时使用 do.call()
。
do.call(c, lapply(dats, function(x) {
actual <- x[, 1]
lapply(x[, 2:4], function(y) {
confusionMatrix(actual, unlist(y))$table
})
}))[1:3]
$`1.Preds1`
Reference
Prediction 0 1
0 3 4
1 0 3
$`1.Preds2`
Reference
Prediction 0 1
0 4 3
1 3 0
$`1.Preds3`
Reference
Prediction 0 1
0 3 4
1 1 2