嗨,我对 R 编程很陌生,我在不使用任何包的情况下绘制 ROC 曲线时遇到了麻烦。
我使用以下方法生成了我的数据:
d=rpearsonIII(100,0.5,360,20)
nd=rnorm(100,450,25)
Run Code Online (Sandbox Code Playgroud)
我需要一个向量,d 的值 <400,nd 的值 >400,所以我做了:
spec = (cumsum(nd[nd>400])/sum(nd))*100
sens = (cumsum(d[d<400])/sum(nd))*100
Run Code Online (Sandbox Code Playgroud)
我是这样绘制的:
plot(1-spec,sens)
Run Code Online (Sandbox Code Playgroud)
但情节与我预期的完全不同
编辑:感谢给出的建议,我的代码现在看起来像这样:
sc2 = c(rnorm(50,450,25),rpearsonIII(50,0.5,360,20))
scF = sc2 < 395
thresholds <- sort(sc2)
pos <- sum(scF);pos
neg <- sum(!scF);neg
tn <- cumsum(!scF);tn
spec <- tn/neg;spec
tp <- pos - cumsum(scF);tp
sens <- tp/pos;sens
plot(1 - spec, sens, type = "l", col = "red",
ylab = "Sensitivity", xlab = "1 - Specificity")
abline(c(0,0),c(1,1))
Run Code Online (Sandbox Code Playgroud)
绘制的 roc 曲线如下所示: roc 曲线
我现在的问题是,如果改变生成数据的顺序(rnorm 和 rpearsonIII),曲线就会反转。
我不知道是什么rpearsonIII,所以我将使用实际类actuals以及预测的分数制作一个样本随机数据scores。
set.seed(100)
actuals <- sample(c(TRUE,FALSE), 100, replace = TRUE)
scores <- runif(100,-1,1)
Run Code Online (Sandbox Code Playgroud)
如果您的数据中的实际值是字符串或因子而不是逻辑值,则需要使用以下方法将它们转换为逻辑值:
actuals <- actuals == "postiveClass"
Run Code Online (Sandbox Code Playgroud)
接下来,我们要根据实例的分数对实例进行排序。我们可以使用:
actuals <- actuals[order(scores)]
Run Code Online (Sandbox Code Playgroud)
如果您想跟踪灵敏度和特异性的阈值,您可以使用以下方法使它们保持一致:
thresholds <- sort(scores)
Run Code Online (Sandbox Code Playgroud)
现在我们需要获得我们的敏感性和特异性。敏感性是TP/P,特异性是TN/N。获得阳性总数P很容易,因为我们的实际值是合乎逻辑的,我们可以使用sum(actuals). 相似的是,我们可以N使用sum(!actuals).
pos <- sum(actuals)
neg <- sum(!actuals)
Run Code Online (Sandbox Code Playgroud)
首先让我们在每个阈值处获得真正的否定。这很简单,它只是FALSE等于或低于每个阈值的值的数量。由于我们的数据是按阈值排序的,我们可以使用以下方法计算(和特异性):
tn <- cumsum(!actuals)
spec <- tn/neg
Run Code Online (Sandbox Code Playgroud)
真正阳性的数量稍微困难一些,因为我们正在寻找大于阈值的阳性数量,因此cumsum单独使用是行不通的。但是,由于阈值以上的数字等于阈值以下或阈值处的总负数,因此我们可以使用以下方法获得真阳性:
tp <- pos - cumsum(actuals)
sens <- tp/pos
Run Code Online (Sandbox Code Playgroud)
现在我们需要做的就是绘制两者。
plot(1 - spec, sens, type = "l", col = "red",
ylab = "Sensitivity", xlab = "1 - Specificity")
abline(c(0,0),c(1,1))
Run Code Online (Sandbox Code Playgroud)
要获得曲线的 AUC,我们只需计算曲线的高度(灵敏度)乘以每个实际值处的宽度(1 差 - 特异性)。我们已经有了敏感性,我们只需要特异性。该diff函数将为我们提供相邻特异性值的差异,但是,我们需要0在开头放置一个值以获得第一列的宽度。
width <- diff(c(0, 1 - sens))
auc <- sum(spec*width)
Run Code Online (Sandbox Code Playgroud)
actuals <- actuals[order(scores)]
sens <- (sum(actuals) - cumsum(actuals))/sum(actuals)
spec <- cumsum(!actuals)/sum(!actuals)
plot(1 - spec, sens, type = "l", col = "red",
ylab = "Sensitivity", xlab = "1 - Specificity")
abline(c(0,0),c(1,1))
(auc <- sum(spec*diff(c(0, 1 - sens))))
Run Code Online (Sandbox Code Playgroud)