📄 owliftcurve.py
字号:
"""
<name>Lift Curve</name>
<description>Displays a lift curve based on evaluation of classifiers.</description>
<contact>Tomaz Curk</contact>
<icon>LiftCurve.png</icon>
<priority>1020</priority>
"""
from OWTools import *
from OWWidget import *
from OWGraph import *
from OWGUI import *
from OWROC import *
import orngStat, orngEval
import statc, math
class singleClassLiftCurveGraph(singleClassROCgraph):
def __init__(self, parent = None, name = None, title = ""):
singleClassROCgraph.__init__(self, parent, name)
self.enableYRaxis(1)
self.setXaxisTitle("P Rate")
self.setAxisAutoScale(QwtPlot.yRight)
self.setAxisAutoScale(QwtPlot.yLeft)
self.setYLaxisTitle("TP")
self.setShowYRaxisTitle(1)
self.setYRaxisTitle("Cost")
self.setShowMainTitle(1)
self.setMainTitle(title)
self.averagingMethod = 'merge'
def computeCurve(self, res, classIndex=-1, keepConcavities=1):
return orngStat.computeLiftCurve(res, classIndex)
def setNumberOfClassifiersIterationsAndClassifierColors(self, classifierNames, iterationsNum, classifierColor):
singleClassROCgraph.setNumberOfClassifiersIterationsAndClassifierColors(self, classifierNames, iterationsNum, classifierColor)
self.setCurveYAxis(self.performanceLineCKey, QwtPlot.yRight)
self.setCurveSymbol(self.performanceLineCKey, QwtSymbol())
def setTestSetData(self, splitByIterations, targetClass):
self.splitByIterations = splitByIterations
## generate the "base" unmodified Lift curves
self.targetClass = targetClass
iteration = 0
for isplit in splitByIterations:
# unmodified Lift curve
P, N, curves = self.computeCurve(isplit, self.targetClass)
self.setIterationCurves(iteration, curves)
iteration += 1
## the lift curve is the average curve from the selected test sets
## no other average curves here
def calcAverageCurves(self):
##
## self.averagingMethod == 'merge':
mergedIterations = orngEval.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
self.mergedConvexHullData = []
if len(mergedIterations.results) > 0:
self.P, self.N, curves = self.computeCurve(mergedIterations, self.targetClass, 1)
_, _, convexCurves = self.computeCurve(mergedIterations, self.targetClass, 0)
classifier = 0
for c in curves:
x = [px for (px, py, pf) in c]
y = [py for (px, py, pf) in c]
ckey = self.mergedCKeys[classifier]
self.setCurveData(ckey, x, y)
classifier += 1
classifier = 0
for c in convexCurves:
self.mergedConvexHullData.append(c) ## put all points of all curves into one big array
x = [px for (px, py, pf) in c]
y = [py for (px, py, pf) in c]
ckey = self.mergedConvexCKeys[classifier]
self.setCurveData(ckey, x, y)
classifier += 1
self.setCurveData(self.diagonalCKey, [0.0, 1.0], [0.0, self.P])
else:
for c in range(len(self.mergedCKeys)):
self.setCurveData(self.mergedCKeys[c], [], [])
self.setCurveData(self.mergedConvexCKeys[c], [], [])
## always set to 'merge' mode
def setAveragingMethod(self, m):
self.averagingMethod = 'merge'
self.updateCurveDisplay()
## performance line
def calcUpdatePerformanceLine(self):
## now draw the closest line to the curve
b = (self.averagingMethod == 'merge') and self.showPerformanceLine
self.removeMarkers()
costx = []
costy = []
firstGlobalMinP = 1
globalMinCost = 0
globalMinCostPoints = []
for (x, TP, fp) in self.hullCurveDataForPerfLine:
first = 1
minc = 0
localMinCostPoints = []
for (cNum, (threshold, FPrate)) in fp:
cost = self.pvalue*(1.0 - TP/self.P)*self.FNcost + (1.0 - self.pvalue)*FPrate*self.FPcost
if first or cost < minc:
first = 0
minc = cost
localMinCostPoints = [ (x, minc, threshold, cNum) ]
else:
if cost == minc:
localMinCostPoints.append( (x, minc, threshold, cNum) )
if firstGlobalMinP or minc < globalMinCost:
firstGlobalMinP = 0
globalMinCost = minc
globalMinCostPoints = [l for l in localMinCostPoints]
else:
if minc == globalMinCost:
globalMinCostPoints.extend(localMinCostPoints)
costx.append(x)
costy.append(minc)
self.setCurveData(self.performanceLineCKey, costx, costy)
self.curve(self.performanceLineCKey).setEnabled(b)
self.update()
nOnMinc = {}
for (x, minc, threshold, cNum) in globalMinCostPoints:
s = "c:%.1f, th:%1.3f %s" % (minc, threshold, self.classifierNames[cNum])
mkey = self.insertMarker(s, QwtPlot.xBottom, QwtPlot.yRight)
onYCn = nOnMinc.get(str(x), 0)
lminc = self.invTransform(QwtPlot.yLeft, self.transform(QwtPlot.yRight, minc)) ## ugly
if onYCn > 0:
lminc = lminc - onYCn*0.05
nOnMinc[str(x)] = nOnMinc[str(x)] + 1
self.setMarkerSymbol(mkey, QwtSymbol())
else:
nOnMinc[str(x)] = 1
self.setMarkerSymbol(mkey, self.performanceLineSymbol)
lminc = self.invTransform(QwtPlot.yRight, self.transform(QwtPlot.yLeft, lminc)) ## ugly ugly
self.marker(mkey).setXValue(x)
self.marker(mkey).setYValue(lminc)
if x >= 0.90:
self.marker(mkey).setLabelAlignment(Qt.AlignLeft)
else:
self.marker(mkey).setLabelAlignment(Qt.AlignRight)
self.marker(mkey).setEnabled(b)
def setPointWidth(self, v):
self.performanceLineSymbol.setSize(v, v)
for mkey in self.markerKeys():
self.setMarkerSymbol(mkey, self.performanceLineSymbol)
self.update()
class OWLiftCurve(OWROC):
settingsList = ["PointWidth", "CurveWidth", "ShowDiagonal",
"ConvexHullCurveWidth", "HullColor", "ShowConvexHull", "ShowConvexCurves", "EnablePerformance"]
def __init__(self, parent=None, signalManager = None):
OWWidget.__init__(self, parent, signalManager, "Lift Curve Analysis", 1)
# inputs
self.inputs=[("Evaluation Results", orngTest.ExperimentResults, self.results, Default)]
# default settings
self.PointWidth = 7
self.CurveWidth = 3
self.ConvexCurveWidth = 1
self.ShowDiagonal = TRUE
self.ConvexHullCurveWidth = 3
self.HullColor = str(Qt.yellow.name())
self.ShowConvexHull = TRUE
self.ShowConvexCurves = FALSE
self.EnablePerformance = TRUE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -