Я пытаюсь создать несколько матриц путаницы из одного фрейма данных, причем каждая матрица создается на основе другого условия в фрейме данных.
Итак, для кадра данных ниже мне нужна матрица путаницы, когда Value = 1
, Value = 2
, Value =3
observed predicted Value
1 1 1
0 1 1
1 0 2
0 0 2
1 1 3
0 0 3
и увидеть результаты, такие как:
Value Sensitivity Specificity PPV NPV
1 .96 .71 .84 .95
2 .89 .63 .30 .45
3 .88 .95 .28 .80
Это то, что я пробовал с воспроизводимым примером. Я пытаюсь написать цикл, который просматривает каждую строку, определяет, есть ли Age = 1
, а затем извлекает значения из прогнозируемых и наблюдаемых столбцов для создания матрицы путаницы. Затем я вручную вытаскиваю значения из матрицы путаницы, чтобы записать sen, spec, ppv и npv, и пытаюсь объединить все матрицы вместе. А затем цикл снова начинается с Age = 2
.
data(scat)
df<-scat %>% transmute(observed=ifelse(Site= = "YOLA","case", "control"), predicted=ifelse(Location= = "edge","case", "control"),Age)
x<-1 #evaluate at ages 1 through 5
for (i in dim(df)[1]) { #for every row in df
while(x<6) { #loop stops at Age=5
if (x=df$Age) {
q<-confusionMatrix(data = df$predicted, reference = df$observed, positive = "case")
sensitivity = q$table[1,1]/(q$table[1,1]+q$table[2,1])
specificity = q$table[2,2]/(q$table[2,2]+q$table[1,2])
ppv = q$table[1,1]/(q$table[1,1]+q$table[1,2])
npv = q$table[2,2]/(q$table[2,2]+q$table[2,1])
matrix(c(sensitivity, specificity, ppv, npv),ncol=4,byrow=TRUE)
}
}
x <- x + 1 #confusion matrix at next Age value
}
final<- rbind(matrix) #combine all the matrices together
Однако эта петля совершенно нефункциональна. Я не уверен, где ошибка.
Ваш код можно упростить, и желаемый результат достигается следующим образом:
library(caret)
library(dplyr)
data(scat)
df <- scat %>%
transmute(observed = factor(ifelse(Site == "YOLA","case", "control")),
predicted = factor(ifelse(Location == "edge","case", "control")),
Age)
final <- t(sapply(sort(unique(df$Age)), function(i) {
q <- confusionMatrix(data = df$predicted[df$Age == i],
reference = df$observed[df$Age == i],
positive = "case")$table
c(sensitivity = q[1, 1] / (q[1, 1] + q[2, 1]),
specificity = q[2, 2] / (q[2, 2] + q[1, 2]),
ppv = q[1, 1] / (q[1, 1] + q[1, 2]),
npv = q[2, 2] / (q[2, 2] + q[2, 1]))
}))
В результате чего
final
#> sensitivity specificity ppv npv
#> [1,] 0.0 0.5625000 0.00000000 0.8181818
#> [2,] 0.0 1.0000000 NaN 0.8000000
#> [3,] 0.2 0.5882353 0.06666667 0.8333333
#> [4,] 0.0 0.6923077 0.00000000 0.6923077
#> [5,] 0.5 0.6400000 0.25000000 0.8421053
Тем не менее, приятно знать, почему ваш собственный код не работает, поэтому вот несколько вопросов, которые может быть полезно рассмотреть:
confusionMatrix
df
, но вам нужна одна итерация для каждого уникального возраста, а не для каждой строки в вашем фрейме данных.x
происходит вне цикла while
, поэтому x
никогда не увеличивается, и цикл никогда не завершается, поэтому консоль просто зависает.if (x = df$Age)
, но вам нужно ==
для проверки равенства.x
с df$Age
не имеет смысла, потому что x
имеет длину 1, а df$Age
— длинный вектор.q$table
каждый раз. Вы можете просто сделать q
равным q$table
, чтобы сделать ваш код более читабельным и менее подверженным ошибкам.matrix
в конце цикла, но нигде его не сохраняете, поэтому весь цикл на самом деле ничего не делает.rbind
объект с именем matrix
в последней строке, который не существует
Большое спасибо за развернутый ответ и объяснение! Я не был знаком с
sapply
, поэтому я немного почитал об этом. И я добавляю этот комментарий для всех в будущем, я также хотел иметь столбец с пометкойAge
и перечислением возрастов в виде строк, поэтому я преобразовалfinal
в фрейм данных, а затем сделалsetDT(final, keep.rownames = "Age")
.