📄 owfeatureselection.py
字号:
"""
<name>Feature Selection</name>
<description>Removes features from the data according to some criteria.</description>
<icon>icons/SelectData.png</icon>
<priority>3500</priority>
"""
import orange
from OWWidget import *
from qttable import *
import OWGUI
from orngTextCorpus import *
class OWFeatureSelection(OWWidget):
settingsList = ["updateOnChange", "loadedConditions", "loadedVarNames"]
def __init__(self, parent = None, signalManager = None, name = "Select data"):
OWWidget.__init__(self, parent, signalManager, name) #initialize base class
# set channels
self.inputs = [("Examples", ExampleTable, self.onDataInput)]
self.outputs = [("Examples", ExampleTable)]
# manually set member variables
self.name2var = {} # key: variable name, item: orange.Variable
self.Conditions = []
# handled member variables
self.currentVar = None
self.NegateCondition = False
self.currentOperatorDict = {orange.VarTypes.Continuous:Operator(Operator.operatorsC[0], orange.VarTypes.Continuous),
orange.VarTypes.Discrete:Operator(Operator.operatorsD[0],orange.VarTypes.Discrete),
orange.VarTypes.String:Operator(Operator.operatorsS[0], orange.VarTypes.String)}
self.Num1 = 0.0
self.Num2 = 0.0
self.Str1 = ""
self.Str2 = ""
self.currentVals = []
self.CaseSensitive = False
self.updateOnChange = True
# load settings
self.loadedVarNames = []
self.loadedConditions = []
self.loadSettings()
# GUI
self.mainArea.setFixedWidth(0)
ca=QFrame(self.controlArea)
ca.adjustSize()
gl=QGridLayout(ca,4,3,5)
# attribute condition box
boxAttrCond = QVGroupBox('Attribute Condition', ca)
gl.addMultiCellWidget(boxAttrCond, 0,0,0,2)
frmAttrCond = QFrame(boxAttrCond)
frmAttrCond.adjustSize()
glac=QGridLayout(frmAttrCond,1,3,5)
glac.setColStretch(0,2)
glac.setColStretch(1,1)
glac.setColStretch(2,2)
# attributes
boxAttr = QVGroupBox(frmAttrCond)
glac.addWidget(boxAttr,0,0)
boxAttr.setTitle('Attribute')
self.lbAttr = QListBox(boxAttr, 'SelAttr')
self.connect(self.lbAttr, SIGNAL('selectionChanged()'), self.lbAttrChange)
# operators
boxOper = QVGroupBox('Operator', frmAttrCond)
# operators 0: empty
self.lbOperatosNone = QListBox(boxOper, 'SelAttr')
# operators 1: discrete
self.lbOperatorsD = QListBox(boxOper, 'SelAttr')
self.lbOperatorsD.hide()
self.connect(self.lbOperatorsD, SIGNAL('selectionChanged()'), self.lbOperatorsChange)
for op in Operator.operatorsD + [Operator.operatorDef]:
self.lbOperatorsD.insertItem(op)
# operators 2: continuous
self.lbOperatorsC = QListBox(boxOper, 'SelAttr')
self.lbOperatorsC.hide()
self.connect(self.lbOperatorsC, SIGNAL('selectionChanged()'), self.lbOperatorsChange)
for op in Operator.operatorsC + [Operator.operatorDef]:
self.lbOperatorsC.insertItem(op)
# operators 6: string
self.lbOperatorsS = QListBox(boxOper, 'SelAttr')
self.lbOperatorsS.hide()
self.connect(self.lbOperatorsS, SIGNAL('selectionChanged()'), self.lbOperatorsChange)
for op in Operator.operatorsS + [Operator.operatorDef]:
self.lbOperatorsS.insertItem(op)
self.lbOperatorsDict = {0: self.lbOperatosNone,
orange.VarTypes.Continuous: self.lbOperatorsC,
orange.VarTypes.Discrete: self.lbOperatorsD,
orange.VarTypes.String: self.lbOperatorsS}
# NOT checkbox
glac.addWidget(boxOper,0,1)
self.cbNot = OWGUI.checkBox(boxOper, self, "NegateCondition", "NOT")
# values
self.valuesStack = QWidgetStack(frmAttrCond)
glac.addWidget(self.valuesStack,0,2)
# values 0: empty
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, 0)
# values 2: continuous between num and num
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, orange.VarTypes.Continuous)
self.leNum1 = OWGUI.lineEdit(boxVal, self, "Num1")
self.lblAndCon = OWGUI.widgetLabel(boxVal, "and")
self.leNum2 = OWGUI.lineEdit(boxVal, self, "Num2")
boxAttrStat = QVGroupBox("Statistics", boxVal)
self.lblMin = QLabel("Min: ", boxAttrStat)
self.lblAvg = QLabel("Avg: ", boxAttrStat)
self.lblMax = QLabel("Max: ", boxAttrStat)
# values 1: discrete
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, orange.VarTypes.Discrete)
self.lbVals = QListBox(boxVal)
self.connect(self.lbVals , SIGNAL('selectionChanged()'), self.lbValsChange)
# values 6: string between str and str
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, orange.VarTypes.String)
self.leStr1 = OWGUI.lineEdit(boxVal, self, "Str1")
self.lblAndStr = OWGUI.widgetLabel(boxVal, "and")
self.leStr2 = OWGUI.lineEdit(boxVal, self, "Str2")
self.cbCaseSensitive = OWGUI.checkBox(boxVal, self, "CaseSensitive", "Case sensitive")
# buttons Add, Update, Remove, Disjunction, Up, Down
self.boxButtons = QHBox(ca)
gl.addMultiCellWidget(self.boxButtons, 1,1,0,2)
btnNew = OWGUI.button(self.boxButtons, self, "Add", self.OnNewCondition)
self.btnUpdate = OWGUI.button(self.boxButtons, self, "Update", self.OnUpdateCondition)
self.btnRemove = OWGUI.button(self.boxButtons, self, "Remove", self.OnRemoveCondition)
self.btnOR = OWGUI.button(self.boxButtons, self, "OR", self.OnDisjunction)
self.btnMoveUp = OWGUI.button(self.boxButtons, self, "Move Up", self.btnMoveUpClicked)
self.btnMoveDown = OWGUI.button(self.boxButtons, self, "Move Down", self.btnMoveDownClicked)
self.btnRemove.setEnabled(False)
self.btnUpdate.setEnabled(False)
self.btnMoveUp.setEnabled(False)
self.btnMoveDown.setEnabled(False)
# data selection criteria
boxCriteria = QVGroupBox(ca)
boxCriteria.setTitle('Data Selection Criteria')
gl.addMultiCellWidget(boxCriteria, 2,2,0,2)
self.criteriaTable = QTable(boxCriteria)
self.criteriaTable.setShowGrid(False)
self.criteriaTable.setSelectionMode(QTable.NoSelection)
self.criteriaTable.setNumCols(2)
self.criteriaTable.verticalHeader().setClickEnabled(False)
self.criteriaTable.verticalHeader().setResizeEnabled(False,-1)
hheader=self.criteriaTable.horizontalHeader()
hheader.setClickEnabled(False)
hheader.setLabel(0, "Active ")
hheader.setLabel(1, "Condition")
self.connect(self.criteriaTable, SIGNAL('currentChanged(int, int)'), self.currentCriteriaChange)
self.criteriaTable.adjustColumn(0)
self.criteriaTable.setColumnWidth(1, 360)
# data in
boxDataIn = QVGroupBox(ca)
boxDataIn.setTitle('Data In')
gl.addWidget(boxDataIn, 3,0)
self.dataInExamplesLabel = OWGUI.widgetLabel(boxDataIn, "num examples")
self.dataInAttributesLabel = OWGUI.widgetLabel(boxDataIn, "num attributes")
# data out
boxDataOut = QVGroupBox(ca)
boxDataOut.setTitle('Data Out')
gl.addWidget(boxDataOut, 3,1)
self.dataOutExamplesLabel = OWGUI.widgetLabel(boxDataOut, "num examples")
self.dataOutAttributesLabel = OWGUI.widgetLabel(boxDataOut, "num attributes")
# update
boxSettings = QVGroupBox(ca)
boxSettings.setTitle('Update')
gl.addWidget(boxSettings, 3,2)
OWGUI.checkBox(boxSettings, self, "updateOnChange", "Update on any change", box=None)
btnUpdate = OWGUI.button(boxSettings, self, "Update", self.setOutput)
# icons
self.icons = self.createAttributeIconDict()
self.onDataInput(None)
self.lbOperatorsD.setCurrentItem(0)
self.lbOperatorsC.setCurrentItem(0)
self.lbOperatorsS.setCurrentItem(0)
self.resize(500,661)
self.measures = FeatureSelection.measures.keys()
############################################################################################################################################################
## Data input and output management ########################################################################################################################
############################################################################################################################################################
def onDataInput(self, data):
"""Loads stored conditions (if we have a similar domain), updates list boxes and data in info, sends out data.
"""
self.fs = FeatureSelection(data)
self.bas = orange.DomainBasicAttrStat(self.fs.data)
if self.fs.data:
# set self.name2var
varList = self.fs.data.domain.variables.native() + self.fs.data.domain.getmetas().values()
varNames = []
for v in varList:
self.name2var[v.name] = v
varNames.append(v.name)
if varNames == self.loadedVarNames:
if self.Conditions == []:
self.Conditions = self.loadedConditions
else:
self.loadedVarNames = varNames
if self.lbAttr.count() <> len(varList):
# update attribute listbox
self.lbAttr.clear()
for v in varList:
self.lbAttr.insertItem(self.icons[v.varType], v.name)
self.lbAttr.setSelected(0,True)
# clear conditions and criteria table
self.Conditions = []
for row in range(self.criteriaTable.numRows()-1,-1,-1):
self.criteriaTable.clearCellWidget(row,0)
self.criteriaTable.clearCell(row,1)
self.criteriaTable.hideRow(row)
self.criteriaTable.setNumRows(0)
self.criteriaTable.setCurrentCell(-1,1)
self.boxButtons.setEnabled(True)
else:
self.name2var = {}
self.Conditions = []
self.lbAttr.clear()
self.currentVar = None
for row in range(self.criteriaTable.numRows()-1,-1,-1):
self.criteriaTable.clearCellWidget(row,0)
self.criteriaTable.clearCell(row,1)
self.criteriaTable.hideRow(row)
self.criteriaTable.setNumRows(0)
self.criteriaTable.setCurrentCell(-1,1)
self.boxButtons.setEnabled(False)
# update operators, values and info, and send out data
self.updateOperatorStack()
self.updateValuesStack()
self.updateInfoIn(data)
self.setOutput()
def setOutput(self):
"""Sends out data, updates data out info.
"""
if self.fs.data:
filterList = self.getFilterList(self.fs.data.domain, self.Conditions, enabledOnly=True)
if len(filterList)>0:
filter = orange.Filter_disjunction([orange.Filter_conjunction(l) for l in filterList])
else:
filter = orange.Filter_conjunction([]) # a filter that does nothing
matchingOutput = self.fs.selectFeatures(filter)
else:
matchingOutput = None
self.send("Examples", matchingOutput)
self.updateInfoOut(matchingOutput)
def getFilterList(self, domain, conditions, enabledOnly):
"""Returns list of lists of orange filters, e.g. [[f1,f2],[f3]].
OR is always enabled (with no respect to cond.enabled)
"""
fdList = [[]]
for cond in conditions:
if cond.type == "OR":
fdList.append([])
elif cond.enabled or not enabledOnly:
fdList[-1].append(cond.operator.getFilter(domain, cond.varName, cond.val1, cond.val2, cond.negated, cond.caseSensitive))
## # remove the first list if empty
## if len(fdList) > 1 and len(fdList[0]) == 0:
## fdList.pop(0)
return fdList
############################################################################################################################################################
## Callback handlers ###################################################################################################################################
############################################################################################################################################################
def lbAttrChange(self):
"""Updates operator listBox and value stack, only if necesarry.
"""
text = str(self.lbAttr.currentText())
prevVar = self.currentVar
if prevVar:
prevVarType = prevVar.varType
prevVarName = prevVar.name
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -