📄 owroc.py
字号:
"""
<name>ROC Analysis</name>
<description>Displays Receiver Operating Characteristics curve based on evaluation of classifiers.</description>
<contact>Tomaz Curk</contact>
<icon>ROCAnalysis.png</icon>
<priority>1010</priority>
"""
from OWTools import *
from OWWidget import *
from OWGraph import *
import OWGUI
import orngStat, orngTest
import statc, math
def TCconvexHull(curves):
## merge curves into one
mergedCurve = []
for c in curves:
mergedCurve.extend(c)
mergedCurve.sort() ## increasing by fp, tp
if len(mergedCurve) == 0: return []
hull = []
(prevX, maxY, fscore) = (mergedCurve[0] + (0.0,))[:3]
prevPfscore = [fscore]
px = prevX
for p in mergedCurve[1:]:
(px, py, fscore) = (p + (0.0,))[:3]
if (px == prevX):
if py > maxY:
prevPfscore = [fscore]
maxY = py
elif py == maxY:
prevPfscore.append(fscore)
elif (px > prevX):
hull = orngStat.ROCaddPoint((prevX, maxY, prevPfscore), hull, keepConcavities=0)
prevX = px
maxY = py
prevPfscore = [fscore]
hull = orngStat.ROCaddPoint((prevX, maxY, prevPfscore), hull, keepConcavities=0)
return hull
class singleClassROCgraph(OWGraph):
def __init__(self, parent = None, name = None, title = ""):
OWGraph.__init__(self, parent, name)
self.setYRlabels(None)
self.enableGridXB(0)
self.enableGridYL(0)
self.setAxisMaxMajor(QwtPlot.xBottom, 10)
self.setAxisMaxMinor(QwtPlot.xBottom, 5)
self.setAxisMaxMajor(QwtPlot.yLeft, 10)
self.setAxisMaxMinor(QwtPlot.yLeft, 5)
self.setAxisScale(QwtPlot.xBottom, -0.0, 1.0, 0)
self.setAxisScale(QwtPlot.yLeft, -0.0, 1.0, 0)
self.setShowXaxisTitle(1)
self.setXaxisTitle("FP Rate (1-Specificity)")
self.setShowYLaxisTitle(1)
self.setYLaxisTitle("TP Rate (Sensitivity)")
self.setShowMainTitle(1)
self.setMainTitle(title)
self.targetClass = 0
self.averagingMethod = None
self.splitByIterations = None
self.VTAsamples = 10 ## vertical threshold averaging, number of samples
self.FPcost = 500.0
self.FNcost = 500.0
self.pvalue = 400.0 ##0.400
self.performanceLineSymbol = QwtSymbol(QwtSymbol.Ellipse, QBrush(Qt.color0), QPen(self.black), QSize(7,7))
self.defaultLineSymbol = QwtSymbol(QwtSymbol.Ellipse, QBrush(Qt.black), QPen(self.black), QSize(8,8))
self.convexHullPen = QPen(Qt.yellow, 3)
self.removeMarkers()
self.performanceMarkerKeys = []
self.removeCurves()
def computeCurve(self, res, classIndex=-1, keepConcavities=1):
return orngStat.TCcomputeROC(res, classIndex, keepConcavities)
def setNumberOfClassifiersIterationsAndClassifierColors(self, classifierNames, iterationsNum, classifierColor):
classifiersNum = len(classifierNames)
self.removeCurves()
self.classifierColor = classifierColor
self.classifierNames = classifierNames
for cNum in range(classifiersNum):
self.classifierIterationCKeys.append([])
self.classifierIterationConvexCKeys.append([])
self.classifierIterationROCdata.append([])
for iNum in range(iterationsNum):
ckey = self.insertCurve('')
self.setCurvePen(ckey, QPen(self.classifierColor[cNum], 3))
self.classifierIterationCKeys[cNum].append(ckey)
ckey = self.insertCurve('')
self.setCurvePen(ckey, QPen(self.classifierColor[cNum], 1))
self.classifierIterationConvexCKeys[cNum].append(ckey)
self.classifierIterationROCdata[cNum].append(None)
self.showClassifiers.append(0)
self.showIterations.append(0)
## 'merge' average curve keys
ckey = self.insertCurve('')
self.setCurvePen(ckey, QPen(self.classifierColor[cNum], 2))
self.mergedCKeys.append(ckey)
ckey = self.insertCurve('')
self.setCurveSymbol(ckey, self.defaultLineSymbol)
self.setCurvePen(ckey, QPen(Qt.black, 5))
self.mergedCThresholdKeys.append(ckey)
self.mergedCThresholdMarkers.append([])
ckey = self.insertCurve('')
self.setCurvePen(ckey, QPen(self.classifierColor[cNum], 1))
self.mergedConvexCKeys.append(ckey)
newSymbol = QwtSymbol(QwtSymbol.None, QBrush(Qt.color0), QPen(self.classifierColor[cNum], 2), QSize(0,0))
## 'vertical' average curve keys
curve = errorBarQwtPlotCurve(self, '', connectPoints = 1, tickXw = 1.0/self.VTAsamples/5.0)
ckey = self.insertCurve(curve)
self.setCurveSymbol(ckey, newSymbol)
self.setCurveStyle(ckey, QwtCurve.UserCurve)
self.verticalCKeys.append(ckey)
## 'threshold' average curve keys
curve = errorBarQwtPlotCurve(self, '', connectPoints = 1, tickXw = 1.0/self.VTAsamples/5.0, tickYw = 1.0/self.VTAsamples/5.0, showVerticalErrorBar = 1, showHorizontalErrorBar = 1)
ckey = self.insertCurve(curve)
self.setCurveSymbol(ckey, newSymbol)
self.setCurveStyle(ckey, QwtCurve.UserCurve)
self.thresholdCKeys.append(ckey)
## iso-performance line on top of all curves
self.performanceLineCKey = self.insertCurve('')
self.setCurvePen(self.performanceLineCKey, QPen(Qt.black, 2))
self.setCurveSymbol(self.performanceLineCKey, self.performanceLineSymbol)
def removeCurves(self):
OWGraph.removeCurves(self)
self.classifierColor = []
self.classifierNames = []
self.classifierIterationROCdata = []
self.showClassifiers = []
self.showIterations = []
self.showConvexCurves = 0
self.showConvexHull = 0
self.showPerformanceLine = 0
self.showDefaultThresholdPoint = 0
self.showDiagonal = 0
## 'merge' average curve keys
self.mergedCKeys = []
self.mergedCThresholdKeys = []
self.mergedCThresholdMarkers = []
self.mergedConvexCKeys = []
## 'vertical' average curve keys
self.verticalCKeys = []
## 'threshold' average curve keys
self.thresholdCKeys = []
## 'None' average curve keys
self.classifierIterationCKeys = []
self.classifierIterationConvexCKeys = []
## convex hull calculation
self.mergedConvexHullData = []
self.verticalConvexHullData = []
self.thresholdConvexHullData = []
self.classifierConvexHullData = []
self.hullCurveDataForPerfLine = [] ## for performance analysis
## diagonal curve
self.diagonalCKey = self.insertCurve('')
self.setCurvePen(self.diagonalCKey, QPen(Qt.black, 1))
self.setCurveData(self.diagonalCKey, [0.0, 1.0], [0.0, 1.0])
## convex hull curve keys
self.mergedConvexHullCKey = self.insertCurve('')
self.setCurvePen(self.mergedConvexHullCKey, self.convexHullPen)
self.verticalConvexHullCKey = self.insertCurve('')
self.setCurvePen(self.verticalConvexHullCKey, self.convexHullPen)
self.thresholdConvexHullCKey = self.insertCurve('')
self.setCurvePen(self.thresholdConvexHullCKey, self.convexHullPen)
self.classifierConvexHullCKey = self.insertCurve('')
self.setCurvePen(self.classifierConvexHullCKey, self.convexHullPen)
## iso-performance line
self.performanceLineCKey = -1
def setIterationCurves(self, iteration, curves):
classifier = 0
for c in curves:
x = [px for (px, py, pf) in c]
y = [py for (px, py, pf) in c]
ckey = self.classifierIterationCKeys[classifier][iteration]
self.setCurveData(ckey, x, y)
self.classifierIterationROCdata[classifier][iteration] = c
classifier += 1
def setIterationConvexCurves(self, iteration, curves):
classifier = 0
for c in curves:
x = [px for (px, py, pf) in c]
y = [py for (px, py, pf) in c]
ckey = self.classifierIterationConvexCKeys[classifier][iteration]
self.setCurveData(ckey, x, y)
classifier += 1
def setTestSetData(self, splitByIterations, targetClass):
self.splitByIterations = splitByIterations
## generate the "base" unmodified ROC curves
self.targetClass = targetClass
iteration = 0
for isplit in splitByIterations:
# unmodified ROC curve
curves = self.computeCurve(isplit, self.targetClass, 1)
self.setIterationCurves(iteration, curves)
# convex ROC curve
curves = self.computeCurve(isplit, self.targetClass, 0)
self.setIterationConvexCurves(iteration, curves)
iteration += 1
def updateCurveDisplay(self):
self.curve(self.diagonalCKey).setEnabled(self.showDiagonal)
showSomething = 0
for cNum in range(len(self.showClassifiers)):
showCNum = (self.showClassifiers[cNum] <> 0)
## 'merge' averaging
b = (self.averagingMethod == 'merge') and showCNum
showSomething = showSomething or b
curve = self.curve(self.mergedCKeys[cNum])
if curve <> None: curve.setEnabled(b)
b2 = b and self.showDefaultThresholdPoint
curve = self.curve(self.mergedCThresholdKeys[cNum])
if curve <> None: curve.setEnabled(b2)
for mkey in self.mergedCThresholdMarkers[cNum]:
marker = self.marker(mkey)
if marker <> None: marker.setEnabled(b2)
b = b and self.showConvexCurves
curve = self.curve(self.mergedConvexCKeys[cNum])
if curve <> None: curve.setEnabled(b)
## 'vertical' averaging
b = (self.averagingMethod == 'vertical') and showCNum
showSomething = showSomething or b
curve = self.curve(self.verticalCKeys[cNum])
if curve <> None: curve.setEnabled(b)
## 'threshold' averaging
b = (self.averagingMethod == 'threshold') and showCNum
showSomething = showSomething or b
curve = self.curve(self.thresholdCKeys[cNum])
if curve <> None: curve.setEnabled(b)
## 'None' averaging
for iNum in range(len(self.showIterations)):
b = (self.averagingMethod == None) and showCNum and (self.showIterations[iNum] <> 0)
showSomething = showSomething or b
self.curve(self.classifierIterationCKeys[cNum][iNum]).setEnabled(b)
b = b and self.showConvexCurves
self.curve(self.classifierIterationConvexCKeys[cNum][iNum]).setEnabled(b)
chb = (showSomething) and (self.averagingMethod == None) and self.showConvexHull
curve = self.curve(self.classifierConvexHullCKey)
if curve <> None: curve.setEnabled(chb)
chb = (showSomething) and (self.averagingMethod == 'merge') and self.showConvexHull
curve = self.curve(self.mergedConvexHullCKey)
if curve <> None: curve.setEnabled(chb)
chb = (showSomething) and (self.averagingMethod == 'vertical') and self.showConvexHull
curve = self.curve(self.verticalConvexHullCKey)
if curve <> None: curve.setEnabled(chb)
chb = (showSomething) and (self.averagingMethod == 'threshold') and self.showConvexHull
curve = self.curve(self.thresholdConvexHullCKey)
if curve <> None: curve.setEnabled(chb)
## performance line
b = (self.averagingMethod == 'merge') and self.showPerformanceLine
for mkey in self.performanceMarkerKeys:
self.marker(mkey).setEnabled(b)
curve = self.curve(self.performanceLineCKey)
if curve <> None: curve.setEnabled(b)
self.updateLayout()
self.update()
def setShowConvexCurves(self, b):
self.showConvexCurves = b
self.updateCurveDisplay()
def setShowConvexHull(self, b):
self.showConvexHull = b
self.updateCurveDisplay()
def setShowPerformanceLine(self, b):
self.showPerformanceLine = b
self.updateCurveDisplay()
def setShowDefaultThresholdPoint(self, b):
self.showDefaultThresholdPoint = b
self.updateCurveDisplay()
def setShowClassifiers(self, list):
self.showClassifiers = list
self.calcConvexHulls()
self.calcUpdatePerformanceLine() ## new data for performance line
self.updateCurveDisplay()
def setShowIterations(self, list):
self.showIterations = list
self.calcAverageCurves()
self.calcConvexHulls()
self.calcUpdatePerformanceLine() ## new data for performance line
self.updateCurveDisplay()
## calculate the average curve for the selected test sets (with all the averaging methods)
def calcAverageCurves(self):
##
## self.averagingMethod == 'merge':
mergedIterations = orngTest.ExperimentResults(1, self.splitByIterations[0].classifierNames, self.splitByIterations[0].classValues, self.splitByIterations[0].weights, classifiers=self.splitByIterations[0].classifiers, loaded=self.splitByIterations[0].loaded)
i = 0
for isplit in self.splitByIterations:
if self.showIterations[i]:
for te in isplit.results:
mergedIterations.results.append( te )
i += 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -