source: orange/Orange/OrangeWidgets/Unsupervised/OWSOM.py @ 11319:9b15c56f817f

Revision 11319:9b15c56f817f, 6.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 14 months ago (diff)

Added 'Codebook vectors' output channel.

Line 
1"""
2<name>SOM</name>
3<description>Self organizing maps learner.</description>
4<icon>icons/SOM.svg</icon>
5<contact>Ales Erjavec (ales.erjevec(@at@)fri.uni.lj.si)</contact>
6<priority>5010</priority>
7"""
8
9import Orange
10from Orange.projection import som
11
12from OWWidget import *
13import OWGUI
14
15
16class OWSOM(OWWidget):
17    settingsList = ["xdim", "ydim", "neighborhood", "topology", "alphaType",
18                    "iterations1", "iterations2", "radius1", "radius2",
19                    "alpha1", "alpha2", "initialization", "eps"]
20
21    def __init__(self, parent=None, signalManager=None, name="SOM"):
22        OWWidget.__init__(self, parent, signalManager, name,
23                          wantMainArea=False)
24
25        self.inputs = [("Data", Orange.data.Table, self.setData)]
26        self.outputs = [("Classifier", Orange.core.Classifier),
27                        ("Learner", Orange.core.Learner),
28                        ("SOM", som.SOMMap),
29                        ("Codebook vectors", Orange.data.Table)]
30
31        self.LearnerName = "SOM Map"
32        self.xdim = 5
33        self.ydim = 10
34        self.initialization = som.InitializeLinear
35        self.neighborhood = 0
36        self.topology = 0
37        self.alphaType = 0
38        self.iterations1 = 100
39        self.iterations2 = 10000
40        self.radius1 = 3
41        self.radius2 = 1
42        self.eps = 1e-5
43        self.alpha1 = 0.05
44        self.alpha2 = 0.01
45        self.loadSettings()
46
47        self.TopolMap = [som.HexagonalTopology,
48                         som.RectangularTopology]
49
50        self.NeighMap = [som.NeighbourhoodGaussian,
51                         som.NeighbourhoodBubble]
52
53        self.learnerName = OWGUI.lineEdit(
54            self.controlArea, self, "LearnerName",
55            box="Learner/Classifier Name",
56            tooltip=("Name to be used by other widgets to identify your "
57                     "Learner/Classifier")
58        )
59
60        box = OWGUI.radioButtonsInBox(
61            self.controlArea, self, "topology",
62            ["Hexagonal topology", "Rectangular topology"],
63            box="Topology"
64        )
65
66        OWGUI.spin(box, self, "xdim", 4, 1000,
67                   orientation="horizontal",
68                   label="Columns")
69
70        OWGUI.spin(box, self, "ydim", 4, 1000,
71                   orientation="horizontal",
72                   label="Rows")
73
74        OWGUI.radioButtonsInBox(self.controlArea, self, "initialization",
75                                ["Linear", "Random"],
76                                box="Map Initialization")
77
78        OWGUI.radioButtonsInBox(self.controlArea, self, "neighborhood",
79                                ["Gaussian neighborhood",
80                                 "Bubble neighborhood"],
81                                box="Neighborhood")
82
83        b = OWGUI.widgetBox(self.controlArea, "Radius")
84
85        OWGUI.spin(b, self, "radius1", 2, 50,
86                   orientation="horizontal", label="Initial radius")
87
88        OWGUI.spin(b, self, "radius2", 1, 50,
89                   orientation="horizontal", label="Final radius")
90
91        b = OWGUI.widgetBox(self.controlArea, "Stopping Conditions")
92        OWGUI.spin(b, self, "iterations1", 10, 10000, label="Iterations")
93
94        OWGUI.button(self.controlArea, self, "&Apply",
95                     callback=self.ApplySettings,
96                     default=True)
97
98        OWGUI.rubber(self.controlArea)
99
100        self.data = None
101        self.classifier = None
102        self.learner = None
103
104        self.resize(100, 100)
105
106    def dataWithDefinedValues(self, data):
107        self.warning(1235)
108        self.warning(1236)
109        exclude = []
110        for attr in data.domain.variables:
111            if not any(not ex[attr].isSpecial() for ex in data):
112                exclude.append(attr)
113
114        if exclude:
115            self.warning(1235,
116                         "Excluding attributes with all unknown "
117                         "values: %s." % \
118                         ", ".join(attr.name for attr in exclude))
119
120            exclude_class = data.domain.class_var in exclude
121            if exclude_class:
122                self.warning(1236,
123                             "Excluding class attribute: %s" % \
124                             data.domain.class_var.name)
125
126            domain = Orange.data.Domain(
127                [attr for attr in data.domain.variables
128                 if attr not in exclude],
129                data.domain.class_var if not exclude_class else False
130            )
131
132            domain.addmetas(data.domain.getmetas())
133            data = Orange.data.Table(domain, data)
134
135        return data
136
137    def setData(self, data=None):
138        self.data = data
139        if data:
140            self.data = self.dataWithDefinedValues(data)
141            self.ApplySettings()
142        else:
143            self.send("Classifier", None)
144            self.send("SOM", None)
145            self.send("Learner", None)
146            self.send("odebook vectors", None)
147
148    def ApplySettings(self):
149        topology = self.TopolMap[self.topology]
150        neigh = self.NeighMap[self.neighborhood]
151
152        self.learner = som.SOMLearner(
153            name=self.LearnerName,
154            map_shape=(self.xdim, self.ydim),
155            topology=topology,
156            neighbourhood=neigh,
157            epochs=self.iterations1,
158            eps=self.eps,
159            initialize=self.initialization,
160            radius_ini=self.radius1,
161            radius_fin=self.radius2
162        )
163
164        self.send("Learner", self.learner)
165
166        if self.data:
167            self.progressBarInit()
168            self.classifier = self.learner(
169                self.data, progressCallback=self.progressBarSet
170            )
171
172            self.progressBarFinished()
173            self.classifier.name = self.LearnerName
174            self.classifier.setattr("data", self.data)
175            if self.data.domain.class_var:
176                self.send("Classifier", self.classifier)
177            self.send("SOM", self.classifier)
178            self.send("Codebook vectors", codebook_table(self.classifier))
179
180    def sendReport(self):
181        self.reportSettings(
182            "Topology",
183            [("Shape", ["hexagonal", "rectangular"][self.topology]),
184             ("Size", "%i columns, %i rows" % (self.xdim, self.ydim))]
185        )
186
187        self.reportSettings(
188            "Optimization",
189            [("Initialization", ["linear", "random"][self.initialization]),
190             ("Neighborhood", ["Gaussian", "bubble"][self.neighborhood]),
191             ("Radius", "initial: %i, final: %i" % \
192              (self.radius1, self.radius2)),
193             ("Number of iterations", self.iterations1)
194            ])
195
196
197def codebook_table(map):
198    """
199    Return n Orange.data.Table instance of all the codebook vectors
200    in the given SOMMap instance.
201
202    """
203    nodes = list(map.map)
204    instances = [node.reference_instance for node in nodes]
205    return Orange.data.Table(map.data.domain, instances)
206
207
208if __name__ == "__main__":
209    app = QApplication(sys.argv)
210    w = OWSOM()
211    w.show()
212    data = Orange.data.Table("iris")
213
214    w.setData(data)
215    app.exec_()
Note: See TracBrowser for help on using the repository browser.