python - 在 Python 中手动计算 AUC
问题描述
使用 R,我可以使用以下代码和 for 循环手动计算 [并绘制] AUC:
test = data.frame(cbind(dt$DV, predicted_prob))
colnames(test)[1] = 'DV'
colnames(test)[2] = 'DV_pred_prob'
TP = rep(NA,101)
FN = rep(NA,101)
FP = rep(NA,101)
TN = rep(NA,101)
Sensitivity = rep(NA,101)
Specificity = rep(NA,101)
AUROC = 0
for(i in 0:100){
test$temp = 0
test[test$DV_pred_prob > (i/100),"temp"] = 1
TP[i+1] = nrow(test[test$DV==1 & test$temp==1,])
FN[i+1] = nrow(test[test$DV==1 & test$temp==0,])
FP[i+1] = nrow(test[test$DV==0 & test$temp==1,])
TN[i+1] = nrow(test[test$DV==0 & test$temp==0,])
Sensitivity[i+1] = TP[i+1] / (TP[i+1] + FN[i+1] )
Specificity[i+1] = TN[i+1] / (TN[i+1] + FP[i+1] )
if(i>0){
AUROC = AUROC+0.5*(Specificity[i+1] - Specificity[i])*(Sensitivity[i+1] +
Sensitivity[i])
}
}
data = data.frame(cbind(Sensitivity,Specificity,id=(0:100)/100))
我试图在 Python 中编写相同的代码,但遇到错误“TypeError:'Series' 对象是可变的,因此它们不能被散列”
我对 Python 非常陌生,并且正在尝试使用 R 和 Python 成为双语。有人可以指出我解决这个问题的正确方向吗?
predictions = pd.DataFrame(predictions[1])
actual = pd.DataFrame(y_test)
test = pd.concat([actual.reset_index(drop=True), predictions], axis=1)
# Rename column Renew to 'actual' and '1' to 'predictions'
test.rename(columns={"Renew": "actual", 1: "predictions"}, inplace=True)
TP = np.repeat('NA', 101)
FN = np.repeat('NA', 101)
FP = np.repeat('NA', 101)
TN = np.repeat('NA', 101)
Sensitivity = np.repeat('NA', 101)
Specificity = np.repeat('NA', 101)
AUROC = 0
for i in range(100):
test['temp'] = 0
test[test['predictions'] > (i/100), "temp"] = 1
TP[i+1] = [test[test["actual"]==1 and test["temp"]==1,]].shape[0]
FN[i+1] = [test[test["actual"]==1 and test["temp"]==0,]].shape[0]
FP[i+1] = [test[test["actual"]==0 and test["temp"]==1,]].shape[0]
TN[i+1] = [test[test["actual"]==0 and test["temp"]==0,]].shape[0]
Sensitivity[i+1] = TP[i+1] / (TP[i+1] + FN[i+1])
Specificity[i+1] = TN[i+1] / (TN[i+1] + FP[i+1])
if(i > 0):
AUROC = AUROC+0.5*(Specificity[i+1] - Specificity[i])*
(Sensitivity[i+1] + Sensitivity[i])
该错误似乎发生在包含 (i/100) 的代码部分周围。
解决方案
Pandas 索引无法按您预期的方式工作。你不能使用df[rows, cols]
你使用.loc
(https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.loc.html)
所以是的 - 你是对的,错误是由你的线路引起的:
test[test['predictions'] > (i/100), "temp"] = 1
.
要修复它,您将使用:
test.loc[test['predictions'] > (i/100), "temp"] = 1
.
...然后您将在以下 4 行中遇到问题,格式如下:
TP[i+1] = test[test["actual"]==1 and test["temp"]==1,].shape[0]
您需要将每个评估语句包装在括号中并将您的更改and
为&
. 有一个很好的讨论为什么会在这里:系列的真值是模棱两可的。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()。所以你的代码应该是这样的:
TP[i+1] = len(test[(test["actual"]==1) & (test["temp"]==1)])
笔记; 我们可以使用len
函数而不是 dataframesshape
属性的第一个元素来计算行数。不过,这只是我的偏好。
最后; 您不能在 python 中以这种方式设置“NA”值;你会用np.NAN
. 最后的 if 语句将失败,因为您已将字符串数组作为占位符。我想np.zeros(101)
会为你工作。
您的完整代码与我的编辑:
predictions = pd.DataFrame(predictions[1])
actual = pd.DataFrame(y_test)
test = pd.concat([actual.reset_index(drop=True), predictions], axis=1)
# Rename column Renew to 'actual' and '1' to 'predictions'
test.columns = ['actual', 'predictions'] #<- You can assign column names using a list
TP = np.zeros(101)
FN = np.zeros(101)
FP = np.zeros(101)
TN = np.zeros(101)
Sensitivity = np.zeros(101)
Specificity = np.zeros(101)
AUROC = 0
for i in range(10):
test['temp'] = 0
test.loc[test['predictions'] > (i / 100), 'temp'] = 1
TP[i+1] = len(test[(test["actual"]==1) & (test["temp"]==1)])
FN[i+1] = len(test[(test["actual"]==1) & (test["temp"]==0)])
FP[i+1] = len(test[(test["actual"]==0) & (test["temp"]==1)])
TN[i+1] = len(test[(test["actual"]==0) & (test["temp"]==0)])
Sensitivity[i+1] = TP[i+1] / (TP[i+1] + FN[i+1])
Specificity[i+1] = TN[i+1] / (TN[i+1] + FP[i+1])
if i > 0:
AUROC += 0.5 * (Specificity[i+1] - Specificity[i]) * (Sensitivity[i+1] + Sensitivity[i])
推荐阅读
- python - Python:类和json之间的映射
- azure - 深度传感器的输出有线条吗?
- derby - 一条sql语句中可以存在多个join吗
- reactjs - 如何在不导入整个 Font Awesome 包的情况下使用图标名称作为字符串导入 Font Awesome 图标?
- azure - 应用程序网关前面的 Azure 前门
- javascript - 使用 vuex 从另一条路由访问本地存储中的数据
- c# - 在 C# 中的 SQL CLR 函数中设置小数精度
- python - Spark:如何将元组转换为 DataFrame
- linux - 如果文件描述符关闭,Linux write() 会使应用程序崩溃
- javascript - 如何在 li 标记中添加?