We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
TypeError:  OneClassSVMLearner doesn't support multiple class variables
https://sentry.io/biolab/orange3/issues/202498152/

```
TypeError:  OneClassSVMLearner doesn't support multiple class variables
  Module "Orange.widgets.data.owoutliers", line 141, in commit

    y_pred = self.detect_outliers()
  Module "Orange.widgets.data.owoutliers", line 169, in detect_outliers

    model = learner(self.data)
  Module "Orange.base", line 253, in __call__

    m = super().__call__(data)
  Module "Orange.base", line 52, in __call__

    self.__class__.__name__)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Orange/widgets/data/owoutliers.py`
Content:
```
1 import sys
2 
3 import numpy as np
4 from AnyQt.QtWidgets import QLayout
5 
6 from Orange.base import SklLearner
7 from Orange.classification import OneClassSVMLearner, EllipticEnvelopeLearner
8 from Orange.data import Table, Domain, ContinuousVariable
9 from Orange.widgets import widget, gui
10 from Orange.widgets.settings import Setting
11 from Orange.widgets.utils.sql import check_sql_input
12 
13 
14 class OWOutliers(widget.OWWidget):
15     name = "Outliers"
16     description = "Detect outliers."
17     icon = "icons/Outliers.svg"
18     priority = 3000
19     category = "Data"
20     keywords = ["data", "outlier", "inlier"]
21 
22     inputs = [("Data", Table, "set_data")]
23     outputs = [("Inliers", Table), ("Outliers", Table)]
24 
25     want_main_area = False
26 
27     OneClassSVM, Covariance = range(2)
28 
29     outlier_method = Setting(OneClassSVM)
30     nu = Setting(50)
31     gamma = Setting(0.01)
32     cont = Setting(10)
33     empirical_covariance = Setting(False)
34     support_fraction = Setting(1)
35 
36     data_info_default = 'No data on input.'
37     in_out_info_default = ' '
38 
39     def __init__(self):
40         super().__init__()
41         self.data = None
42         self.n_inliers = self.n_outliers = None
43 
44         box = gui.vBox(self.controlArea, "Information")
45         self.data_info_label = gui.widgetLabel(box, self.data_info_default)
46         self.in_out_info_label = gui.widgetLabel(box,
47                                                  self.in_out_info_default)
48 
49         box = gui.vBox(self.controlArea, "Outlier Detection Method")
50         detection = gui.radioButtons(box, self, "outlier_method")
51 
52         gui.appendRadioButton(detection,
53                               "One class SVM with non-linear kernel (RBF)")
54         ibox = gui.indentedBox(detection)
55         tooltip = "An upper bound on the fraction of training errors and a " \
56                   "lower bound of the fraction of support vectors"
57         gui.widgetLabel(ibox, 'Nu:', tooltip=tooltip)
58         self.nu_slider = gui.hSlider(
59             ibox, self, "nu", minValue=1, maxValue=100, ticks=10,
60             labelFormat="%d %%", callback=self.nu_changed, tooltip=tooltip)
61         self.gamma_spin = gui.spin(
62             ibox, self, "gamma", label="Kernel coefficient:", step=1e-2,
63             spinType=float, minv=0.01, maxv=10, callback=self.gamma_changed)
64         gui.separator(detection, 12)
65 
66         self.rb_cov = gui.appendRadioButton(detection, "Covariance estimator")
67         ibox = gui.indentedBox(detection)
68         self.l_cov = gui.widgetLabel(ibox, 'Contamination:')
69         self.cont_slider = gui.hSlider(
70             ibox, self, "cont", minValue=0, maxValue=100, ticks=10,
71             labelFormat="%d %%", callback=self.cont_changed)
72 
73         ebox = gui.hBox(ibox)
74         self.cb_emp_cov = gui.checkBox(
75             ebox, self, "empirical_covariance",
76             "Support fraction:", callback=self.empirical_changed)
77         self.support_fraction_spin = gui.spin(
78             ebox, self, "support_fraction", step=1e-1, spinType=float,
79             minv=0.1, maxv=10, callback=self.support_fraction_changed)
80 
81         gui.separator(detection, 12)
82 
83         gui.button(self.buttonsArea, self, "Detect Outliers",
84                    callback=self.commit)
85         self.layout().setSizeConstraint(QLayout.SetFixedSize)
86 
87     def nu_changed(self):
88         self.outlier_method = self.OneClassSVM
89 
90     def gamma_changed(self):
91         self.outlier_method = self.OneClassSVM
92 
93     def cont_changed(self):
94         self.outlier_method = self.Covariance
95 
96     def support_fraction_changed(self):
97         self.outlier_method = self.Covariance
98 
99     def empirical_changed(self):
100         self.outlier_method = self.Covariance
101 
102     def disable_covariance(self):
103         self.outlier_method = self.OneClassSVM
104         self.rb_cov.setDisabled(True)
105         self.l_cov.setDisabled(True)
106         self.cont_slider.setDisabled(True)
107         self.cb_emp_cov.setDisabled(True)
108         self.support_fraction_spin.setDisabled(True)
109         self.warning('Too many features for covariance estimation.')
110 
111     def enable_covariance(self):
112         self.rb_cov.setDisabled(False)
113         self.l_cov.setDisabled(False)
114         self.cont_slider.setDisabled(False)
115         self.cb_emp_cov.setDisabled(False)
116         self.support_fraction_spin.setDisabled(False)
117         self.warning()
118 
119     @check_sql_input
120     def set_data(self, dataset):
121         self.data = dataset
122         if self.data is None:
123             self.data_info_label.setText(self.data_info_default)
124             self.in_out_info_label.setText(self.in_out_info_default)
125         else:
126             self.data_info_label.setText('%d instances' % len(self.data))
127             self.in_out_info_label.setText(' ')
128 
129         self.enable_covariance()
130         if self.data and len(self.data.domain.attributes) > 1500:
131             self.disable_covariance()
132 
133         self.commit()
134 
135     def commit(self):
136         self.error()
137         inliers = outliers = None
138         self.n_inliers = self.n_outliers = None
139         if self.data is not None and len(self.data) > 0:
140             try:
141                 y_pred = self.detect_outliers()
142             except ValueError:
143                 self.error("Singular covariance matrix.")
144                 self.in_out_info_label.setText(self.in_out_info_default)
145             else:
146                 inliers_ind = np.where(y_pred == 1)[0]
147                 outliers_ind = np.where(y_pred == -1)[0]
148                 inliers = Table(self.new_domain, self.new_data, inliers_ind)
149                 outliers = Table(self.new_domain,
150                                  self.new_data, outliers_ind)
151                 self.in_out_info_label.setText('%d inliers, %d outliers' %
152                                                (len(inliers), len(outliers)))
153                 self.n_inliers = len(inliers)
154                 self.n_outliers = len(outliers)
155 
156         self.send("Inliers", inliers)
157         self.send("Outliers", outliers)
158 
159     def detect_outliers(self):
160         if self.outlier_method == self.OneClassSVM:
161             learner = OneClassSVMLearner(
162                 gamma=self.gamma, nu=self.nu / 100,
163                 preprocessors=SklLearner.preprocessors)
164         else:
165             learner = EllipticEnvelopeLearner(
166                 support_fraction=self.support_fraction
167                 if self.empirical_covariance else None,
168                 contamination=self.cont / 100.)
169         model = learner(self.data)
170         y_pred = model(self.data)
171         self.add_metas(model)
172         return np.array(y_pred)
173 
174     def add_metas(self, model):
175         if self.outlier_method == self.Covariance:
176             mahal = model.mahalanobis(self.data.X)
177             mahal = mahal.reshape(len(self.data), 1)
178             attrs = self.data.domain.attributes
179             classes = self.data.domain.class_vars
180             new_metas = list(self.data.domain.metas) + \
181                         [ContinuousVariable(name="Mahalanobis")]
182             self.new_domain = Domain(attrs, classes, new_metas)
183             self.new_data = Table(self.new_domain, self.data)
184             self.new_data.metas = np.hstack((self.data.metas, mahal))
185         else:
186             self.new_domain = self.data.domain
187             self.new_data = self.data
188 
189     def send_report(self):
190         if self.n_outliers is None or self.n_inliers is None:
191             return
192         self.report_items("Data",
193                           (("Input instances", len(self.data)),
194                            ("Inliers", self.n_inliers),
195                            ("Outliers", self.n_outliers)))
196         if self.outlier_method == 0:
197             self.report_items(
198                 "Detection",
199                 (("Detection method",
200                   "One class SVM with non-linear kernel (RBF)"),
201                  ("Regularization (nu)", self.nu),
202                  ("Kernel coefficient", self.gamma)))
203         else:
204             self.report_items(
205                 "Detection",
206                 (("Detection method", "Covariance estimator"),
207                  ("Contamination", self.cont),
208                  ("Support fraction", self.support_fraction)))
209 
210 def test_main():
211     from AnyQt.QtWidgets import QApplication
212     app = QApplication([])
213     data = Table("iris")
214     w = OWOutliers()
215     w.set_data(data)
216     w.commit()
217     w.show()
218     return app.exec_()
219 
220 
221 if __name__ == "__main__":
222     sys.exit(test_main())
223
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Orange/widgets/data/owoutliers.py b/Orange/widgets/data/owoutliers.py
--- a/Orange/widgets/data/owoutliers.py
+++ b/Orange/widgets/data/owoutliers.py
@@ -8,6 +8,7 @@
 from Orange.data import Table, Domain, ContinuousVariable
 from Orange.widgets import widget, gui
 from Orange.widgets.settings import Setting
+from Orange.widgets.widget import Msg
 from Orange.widgets.utils.sql import check_sql_input
 
 
@@ -36,6 +37,10 @@
     data_info_default = 'No data on input.'
     in_out_info_default = ' '
 
+    class Error(widget.OWWidget.Error):
+        singular_cov = Msg("Singular covariance matrix.")
+        multiclass_error = Msg("Multiple class data is not supported")
+
     def __init__(self):
         super().__init__()
         self.data = None
@@ -133,25 +138,29 @@
         self.commit()
 
     def commit(self):
-        self.error()
+        self.clear_messages()
         inliers = outliers = None
         self.n_inliers = self.n_outliers = None
         if self.data is not None and len(self.data) > 0:
-            try:
-                y_pred = self.detect_outliers()
-            except ValueError:
-                self.error("Singular covariance matrix.")
-                self.in_out_info_label.setText(self.in_out_info_default)
+            if self.data.Y.ndim > 1:
+                self.Error.multiclass_error()
             else:
-                inliers_ind = np.where(y_pred == 1)[0]
-                outliers_ind = np.where(y_pred == -1)[0]
-                inliers = Table(self.new_domain, self.new_data, inliers_ind)
-                outliers = Table(self.new_domain,
-                                 self.new_data, outliers_ind)
-                self.in_out_info_label.setText('%d inliers, %d outliers' %
-                                               (len(inliers), len(outliers)))
-                self.n_inliers = len(inliers)
-                self.n_outliers = len(outliers)
+                try:
+                    y_pred = self.detect_outliers()
+                except ValueError:
+                    self.Error.singular_cov()
+                    self.in_out_info_label.setText(self.in_out_info_default)
+                else:
+                    inliers_ind = np.where(y_pred == 1)[0]
+                    outliers_ind = np.where(y_pred == -1)[0]
+                    inliers = Table(self.new_domain, self.new_data, inliers_ind)
+                    outliers = Table(self.new_domain,
+                                     self.new_data, outliers_ind)
+                    self.in_out_info_label.setText(
+                        "{} inliers, {} outliers".format(len(inliers),
+                                                         len(outliers)))
+                    self.n_inliers = len(inliers)
+                    self.n_outliers = len(outliers)
 
         self.send("Inliers", inliers)
         self.send("Outliers", outliers)

{"golden_diff": "diff --git a/Orange/widgets/data/owoutliers.py b/Orange/widgets/data/owoutliers.py\n--- a/Orange/widgets/data/owoutliers.py\n+++ b/Orange/widgets/data/owoutliers.py\n@@ -8,6 +8,7 @@\n from Orange.data import Table, Domain, ContinuousVariable\n from Orange.widgets import widget, gui\n from Orange.widgets.settings import Setting\n+from Orange.widgets.widget import Msg\n from Orange.widgets.utils.sql import check_sql_input\n \n \n@@ -36,6 +37,10 @@\n     data_info_default = 'No data on input.'\n     in_out_info_default = ' '\n \n+    class Error(widget.OWWidget.Error):\n+        singular_cov = Msg(\"Singular covariance matrix.\")\n+        multiclass_error = Msg(\"Multiple class data is not supported\")\n+\n     def __init__(self):\n         super().__init__()\n         self.data = None\n@@ -133,25 +138,29 @@\n         self.commit()\n \n     def commit(self):\n-        self.error()\n+        self.clear_messages()\n         inliers = outliers = None\n         self.n_inliers = self.n_outliers = None\n         if self.data is not None and len(self.data) > 0:\n-            try:\n-                y_pred = self.detect_outliers()\n-            except ValueError:\n-                self.error(\"Singular covariance matrix.\")\n-                self.in_out_info_label.setText(self.in_out_info_default)\n+            if self.data.Y.ndim > 1:\n+                self.Error.multiclass_error()\n             else:\n-                inliers_ind = np.where(y_pred == 1)[0]\n-                outliers_ind = np.where(y_pred == -1)[0]\n-                inliers = Table(self.new_domain, self.new_data, inliers_ind)\n-                outliers = Table(self.new_domain,\n-                                 self.new_data, outliers_ind)\n-                self.in_out_info_label.setText('%d inliers, %d outliers' %\n-                                               (len(inliers), len(outliers)))\n-                self.n_inliers = len(inliers)\n-                self.n_outliers = len(outliers)\n+                try:\n+                    y_pred = self.detect_outliers()\n+                except ValueError:\n+                    self.Error.singular_cov()\n+                    self.in_out_info_label.setText(self.in_out_info_default)\n+                else:\n+                    inliers_ind = np.where(y_pred == 1)[0]\n+                    outliers_ind = np.where(y_pred == -1)[0]\n+                    inliers = Table(self.new_domain, self.new_data, inliers_ind)\n+                    outliers = Table(self.new_domain,\n+                                     self.new_data, outliers_ind)\n+                    self.in_out_info_label.setText(\n+                        \"{} inliers, {} outliers\".format(len(inliers),\n+                                                         len(outliers)))\n+                    self.n_inliers = len(inliers)\n+                    self.n_outliers = len(outliers)\n \n         self.send(\"Inliers\", inliers)\n         self.send(\"Outliers\", outliers)\n", "issue": "TypeError:  OneClassSVMLearner doesn't support multiple class variables\nhttps://sentry.io/biolab/orange3/issues/202498152/\n\n```\nTypeError:  OneClassSVMLearner doesn't support multiple class variables\n  Module \"Orange.widgets.data.owoutliers\", line 141, in commit\n\n    y_pred = self.detect_outliers()\n  Module \"Orange.widgets.data.owoutliers\", line 169, in detect_outliers\n\n    model = learner(self.data)\n  Module \"Orange.base\", line 253, in __call__\n\n    m = super().__call__(data)\n  Module \"Orange.base\", line 52, in __call__\n\n    self.__class__.__name__)\n```\n", "before_files": [{"content": "import sys\n\nimport numpy as np\nfrom AnyQt.QtWidgets import QLayout\n\nfrom Orange.base import SklLearner\nfrom Orange.classification import OneClassSVMLearner, EllipticEnvelopeLearner\nfrom Orange.data import Table, Domain, ContinuousVariable\nfrom Orange.widgets import widget, gui\nfrom Orange.widgets.settings import Setting\nfrom Orange.widgets.utils.sql import check_sql_input\n\n\nclass OWOutliers(widget.OWWidget):\n    name = \"Outliers\"\n    description = \"Detect outliers.\"\n    icon = \"icons/Outliers.svg\"\n    priority = 3000\n    category = \"Data\"\n    keywords = [\"data\", \"outlier\", \"inlier\"]\n\n    inputs = [(\"Data\", Table, \"set_data\")]\n    outputs = [(\"Inliers\", Table), (\"Outliers\", Table)]\n\n    want_main_area = False\n\n    OneClassSVM, Covariance = range(2)\n\n    outlier_method = Setting(OneClassSVM)\n    nu = Setting(50)\n    gamma = Setting(0.01)\n    cont = Setting(10)\n    empirical_covariance = Setting(False)\n    support_fraction = Setting(1)\n\n    data_info_default = 'No data on input.'\n    in_out_info_default = ' '\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.n_inliers = self.n_outliers = None\n\n        box = gui.vBox(self.controlArea, \"Information\")\n        self.data_info_label = gui.widgetLabel(box, self.data_info_default)\n        self.in_out_info_label = gui.widgetLabel(box,\n                                                 self.in_out_info_default)\n\n        box = gui.vBox(self.controlArea, \"Outlier Detection Method\")\n        detection = gui.radioButtons(box, self, \"outlier_method\")\n\n        gui.appendRadioButton(detection,\n                              \"One class SVM with non-linear kernel (RBF)\")\n        ibox = gui.indentedBox(detection)\n        tooltip = \"An upper bound on the fraction of training errors and a \" \\\n                  \"lower bound of the fraction of support vectors\"\n        gui.widgetLabel(ibox, 'Nu:', tooltip=tooltip)\n        self.nu_slider = gui.hSlider(\n            ibox, self, \"nu\", minValue=1, maxValue=100, ticks=10,\n            labelFormat=\"%d %%\", callback=self.nu_changed, tooltip=tooltip)\n        self.gamma_spin = gui.spin(\n            ibox, self, \"gamma\", label=\"Kernel coefficient:\", step=1e-2,\n            spinType=float, minv=0.01, maxv=10, callback=self.gamma_changed)\n        gui.separator(detection, 12)\n\n        self.rb_cov = gui.appendRadioButton(detection, \"Covariance estimator\")\n        ibox = gui.indentedBox(detection)\n        self.l_cov = gui.widgetLabel(ibox, 'Contamination:')\n        self.cont_slider = gui.hSlider(\n            ibox, self, \"cont\", minValue=0, maxValue=100, ticks=10,\n            labelFormat=\"%d %%\", callback=self.cont_changed)\n\n        ebox = gui.hBox(ibox)\n        self.cb_emp_cov = gui.checkBox(\n            ebox, self, \"empirical_covariance\",\n            \"Support fraction:\", callback=self.empirical_changed)\n        self.support_fraction_spin = gui.spin(\n            ebox, self, \"support_fraction\", step=1e-1, spinType=float,\n            minv=0.1, maxv=10, callback=self.support_fraction_changed)\n\n        gui.separator(detection, 12)\n\n        gui.button(self.buttonsArea, self, \"Detect Outliers\",\n                   callback=self.commit)\n        self.layout().setSizeConstraint(QLayout.SetFixedSize)\n\n    def nu_changed(self):\n        self.outlier_method = self.OneClassSVM\n\n    def gamma_changed(self):\n        self.outlier_method = self.OneClassSVM\n\n    def cont_changed(self):\n        self.outlier_method = self.Covariance\n\n    def support_fraction_changed(self):\n        self.outlier_method = self.Covariance\n\n    def empirical_changed(self):\n        self.outlier_method = self.Covariance\n\n    def disable_covariance(self):\n        self.outlier_method = self.OneClassSVM\n        self.rb_cov.setDisabled(True)\n        self.l_cov.setDisabled(True)\n        self.cont_slider.setDisabled(True)\n        self.cb_emp_cov.setDisabled(True)\n        self.support_fraction_spin.setDisabled(True)\n        self.warning('Too many features for covariance estimation.')\n\n    def enable_covariance(self):\n        self.rb_cov.setDisabled(False)\n        self.l_cov.setDisabled(False)\n        self.cont_slider.setDisabled(False)\n        self.cb_emp_cov.setDisabled(False)\n        self.support_fraction_spin.setDisabled(False)\n        self.warning()\n\n    @check_sql_input\n    def set_data(self, dataset):\n        self.data = dataset\n        if self.data is None:\n            self.data_info_label.setText(self.data_info_default)\n            self.in_out_info_label.setText(self.in_out_info_default)\n        else:\n            self.data_info_label.setText('%d instances' % len(self.data))\n            self.in_out_info_label.setText(' ')\n\n        self.enable_covariance()\n        if self.data and len(self.data.domain.attributes) > 1500:\n            self.disable_covariance()\n\n        self.commit()\n\n    def commit(self):\n        self.error()\n        inliers = outliers = None\n        self.n_inliers = self.n_outliers = None\n        if self.data is not None and len(self.data) > 0:\n            try:\n                y_pred = self.detect_outliers()\n            except ValueError:\n                self.error(\"Singular covariance matrix.\")\n                self.in_out_info_label.setText(self.in_out_info_default)\n            else:\n                inliers_ind = np.where(y_pred == 1)[0]\n                outliers_ind = np.where(y_pred == -1)[0]\n                inliers = Table(self.new_domain, self.new_data, inliers_ind)\n                outliers = Table(self.new_domain,\n                                 self.new_data, outliers_ind)\n                self.in_out_info_label.setText('%d inliers, %d outliers' %\n                                               (len(inliers), len(outliers)))\n                self.n_inliers = len(inliers)\n                self.n_outliers = len(outliers)\n\n        self.send(\"Inliers\", inliers)\n        self.send(\"Outliers\", outliers)\n\n    def detect_outliers(self):\n        if self.outlier_method == self.OneClassSVM:\n            learner = OneClassSVMLearner(\n                gamma=self.gamma, nu=self.nu / 100,\n                preprocessors=SklLearner.preprocessors)\n        else:\n            learner = EllipticEnvelopeLearner(\n                support_fraction=self.support_fraction\n                if self.empirical_covariance else None,\n                contamination=self.cont / 100.)\n        model = learner(self.data)\n        y_pred = model(self.data)\n        self.add_metas(model)\n        return np.array(y_pred)\n\n    def add_metas(self, model):\n        if self.outlier_method == self.Covariance:\n            mahal = model.mahalanobis(self.data.X)\n            mahal = mahal.reshape(len(self.data), 1)\n            attrs = self.data.domain.attributes\n            classes = self.data.domain.class_vars\n            new_metas = list(self.data.domain.metas) + \\\n                        [ContinuousVariable(name=\"Mahalanobis\")]\n            self.new_domain = Domain(attrs, classes, new_metas)\n            self.new_data = Table(self.new_domain, self.data)\n            self.new_data.metas = np.hstack((self.data.metas, mahal))\n        else:\n            self.new_domain = self.data.domain\n            self.new_data = self.data\n\n    def send_report(self):\n        if self.n_outliers is None or self.n_inliers is None:\n            return\n        self.report_items(\"Data\",\n                          ((\"Input instances\", len(self.data)),\n                           (\"Inliers\", self.n_inliers),\n                           (\"Outliers\", self.n_outliers)))\n        if self.outlier_method == 0:\n            self.report_items(\n                \"Detection\",\n                ((\"Detection method\",\n                  \"One class SVM with non-linear kernel (RBF)\"),\n                 (\"Regularization (nu)\", self.nu),\n                 (\"Kernel coefficient\", self.gamma)))\n        else:\n            self.report_items(\n                \"Detection\",\n                ((\"Detection method\", \"Covariance estimator\"),\n                 (\"Contamination\", self.cont),\n                 (\"Support fraction\", self.support_fraction)))\n\ndef test_main():\n    from AnyQt.QtWidgets import QApplication\n    app = QApplication([])\n    data = Table(\"iris\")\n    w = OWOutliers()\n    w.set_data(data)\n    w.commit()\n    w.show()\n    return app.exec_()\n\n\nif __name__ == \"__main__\":\n    sys.exit(test_main())\n", "path": "Orange/widgets/data/owoutliers.py"}], "after_files": [{"content": "import sys\n\nimport numpy as np\nfrom AnyQt.QtWidgets import QLayout\n\nfrom Orange.base import SklLearner\nfrom Orange.classification import OneClassSVMLearner, EllipticEnvelopeLearner\nfrom Orange.data import Table, Domain, ContinuousVariable\nfrom Orange.widgets import widget, gui\nfrom Orange.widgets.settings import Setting\nfrom Orange.widgets.widget import Msg\nfrom Orange.widgets.utils.sql import check_sql_input\n\n\nclass OWOutliers(widget.OWWidget):\n    name = \"Outliers\"\n    description = \"Detect outliers.\"\n    icon = \"icons/Outliers.svg\"\n    priority = 3000\n    category = \"Data\"\n    keywords = [\"data\", \"outlier\", \"inlier\"]\n\n    inputs = [(\"Data\", Table, \"set_data\")]\n    outputs = [(\"Inliers\", Table), (\"Outliers\", Table)]\n\n    want_main_area = False\n\n    OneClassSVM, Covariance = range(2)\n\n    outlier_method = Setting(OneClassSVM)\n    nu = Setting(50)\n    gamma = Setting(0.01)\n    cont = Setting(10)\n    empirical_covariance = Setting(False)\n    support_fraction = Setting(1)\n\n    data_info_default = 'No data on input.'\n    in_out_info_default = ' '\n\n    class Error(widget.OWWidget.Error):\n        singular_cov = Msg(\"Singular covariance matrix.\")\n        multiclass_error = Msg(\"Multiple class data is not supported\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.n_inliers = self.n_outliers = None\n\n        box = gui.vBox(self.controlArea, \"Information\")\n        self.data_info_label = gui.widgetLabel(box, self.data_info_default)\n        self.in_out_info_label = gui.widgetLabel(box,\n                                                 self.in_out_info_default)\n\n        box = gui.vBox(self.controlArea, \"Outlier Detection Method\")\n        detection = gui.radioButtons(box, self, \"outlier_method\")\n\n        gui.appendRadioButton(detection,\n                              \"One class SVM with non-linear kernel (RBF)\")\n        ibox = gui.indentedBox(detection)\n        tooltip = \"An upper bound on the fraction of training errors and a \" \\\n                  \"lower bound of the fraction of support vectors\"\n        gui.widgetLabel(ibox, 'Nu:', tooltip=tooltip)\n        self.nu_slider = gui.hSlider(\n            ibox, self, \"nu\", minValue=1, maxValue=100, ticks=10,\n            labelFormat=\"%d %%\", callback=self.nu_changed, tooltip=tooltip)\n        self.gamma_spin = gui.spin(\n            ibox, self, \"gamma\", label=\"Kernel coefficient:\", step=1e-2,\n            spinType=float, minv=0.01, maxv=10, callback=self.gamma_changed)\n        gui.separator(detection, 12)\n\n        self.rb_cov = gui.appendRadioButton(detection, \"Covariance estimator\")\n        ibox = gui.indentedBox(detection)\n        self.l_cov = gui.widgetLabel(ibox, 'Contamination:')\n        self.cont_slider = gui.hSlider(\n            ibox, self, \"cont\", minValue=0, maxValue=100, ticks=10,\n            labelFormat=\"%d %%\", callback=self.cont_changed)\n\n        ebox = gui.hBox(ibox)\n        self.cb_emp_cov = gui.checkBox(\n            ebox, self, \"empirical_covariance\",\n            \"Support fraction:\", callback=self.empirical_changed)\n        self.support_fraction_spin = gui.spin(\n            ebox, self, \"support_fraction\", step=1e-1, spinType=float,\n            minv=0.1, maxv=10, callback=self.support_fraction_changed)\n\n        gui.separator(detection, 12)\n\n        gui.button(self.buttonsArea, self, \"Detect Outliers\",\n                   callback=self.commit)\n        self.layout().setSizeConstraint(QLayout.SetFixedSize)\n\n    def nu_changed(self):\n        self.outlier_method = self.OneClassSVM\n\n    def gamma_changed(self):\n        self.outlier_method = self.OneClassSVM\n\n    def cont_changed(self):\n        self.outlier_method = self.Covariance\n\n    def support_fraction_changed(self):\n        self.outlier_method = self.Covariance\n\n    def empirical_changed(self):\n        self.outlier_method = self.Covariance\n\n    def disable_covariance(self):\n        self.outlier_method = self.OneClassSVM\n        self.rb_cov.setDisabled(True)\n        self.l_cov.setDisabled(True)\n        self.cont_slider.setDisabled(True)\n        self.cb_emp_cov.setDisabled(True)\n        self.support_fraction_spin.setDisabled(True)\n        self.warning('Too many features for covariance estimation.')\n\n    def enable_covariance(self):\n        self.rb_cov.setDisabled(False)\n        self.l_cov.setDisabled(False)\n        self.cont_slider.setDisabled(False)\n        self.cb_emp_cov.setDisabled(False)\n        self.support_fraction_spin.setDisabled(False)\n        self.warning()\n\n    @check_sql_input\n    def set_data(self, dataset):\n        self.data = dataset\n        if self.data is None:\n            self.data_info_label.setText(self.data_info_default)\n            self.in_out_info_label.setText(self.in_out_info_default)\n        else:\n            self.data_info_label.setText('%d instances' % len(self.data))\n            self.in_out_info_label.setText(' ')\n\n        self.enable_covariance()\n        if self.data and len(self.data.domain.attributes) > 1500:\n            self.disable_covariance()\n\n        self.commit()\n\n    def commit(self):\n        self.clear_messages()\n        inliers = outliers = None\n        self.n_inliers = self.n_outliers = None\n        if self.data is not None and len(self.data) > 0:\n            if self.data.Y.ndim > 1:\n                self.Error.multiclass_error()\n            else:\n                try:\n                    y_pred = self.detect_outliers()\n                except ValueError:\n                    self.Error.singular_cov()\n                    self.in_out_info_label.setText(self.in_out_info_default)\n                else:\n                    inliers_ind = np.where(y_pred == 1)[0]\n                    outliers_ind = np.where(y_pred == -1)[0]\n                    inliers = Table(self.new_domain, self.new_data, inliers_ind)\n                    outliers = Table(self.new_domain,\n                                     self.new_data, outliers_ind)\n                    self.in_out_info_label.setText(\n                        \"{} inliers, {} outliers\".format(len(inliers),\n                                                         len(outliers)))\n                    self.n_inliers = len(inliers)\n                    self.n_outliers = len(outliers)\n\n        self.send(\"Inliers\", inliers)\n        self.send(\"Outliers\", outliers)\n\n    def detect_outliers(self):\n        if self.outlier_method == self.OneClassSVM:\n            learner = OneClassSVMLearner(\n                gamma=self.gamma, nu=self.nu / 100,\n                preprocessors=SklLearner.preprocessors)\n        else:\n            learner = EllipticEnvelopeLearner(\n                support_fraction=self.support_fraction\n                if self.empirical_covariance else None,\n                contamination=self.cont / 100.)\n        model = learner(self.data)\n        y_pred = model(self.data)\n        self.add_metas(model)\n        return np.array(y_pred)\n\n    def add_metas(self, model):\n        if self.outlier_method == self.Covariance:\n            mahal = model.mahalanobis(self.data.X)\n            mahal = mahal.reshape(len(self.data), 1)\n            attrs = self.data.domain.attributes\n            classes = self.data.domain.class_vars\n            new_metas = list(self.data.domain.metas) + \\\n                        [ContinuousVariable(name=\"Mahalanobis\")]\n            self.new_domain = Domain(attrs, classes, new_metas)\n            self.new_data = Table(self.new_domain, self.data)\n            self.new_data.metas = np.hstack((self.data.metas, mahal))\n        else:\n            self.new_domain = self.data.domain\n            self.new_data = self.data\n\n    def send_report(self):\n        if self.n_outliers is None or self.n_inliers is None:\n            return\n        self.report_items(\"Data\",\n                          ((\"Input instances\", len(self.data)),\n                           (\"Inliers\", self.n_inliers),\n                           (\"Outliers\", self.n_outliers)))\n        if self.outlier_method == 0:\n            self.report_items(\n                \"Detection\",\n                ((\"Detection method\",\n                  \"One class SVM with non-linear kernel (RBF)\"),\n                 (\"Regularization (nu)\", self.nu),\n                 (\"Kernel coefficient\", self.gamma)))\n        else:\n            self.report_items(\n                \"Detection\",\n                ((\"Detection method\", \"Covariance estimator\"),\n                 (\"Contamination\", self.cont),\n                 (\"Support fraction\", self.support_fraction)))\n\ndef test_main():\n    from AnyQt.QtWidgets import QApplication\n    app = QApplication([])\n    data = Table(\"iris\")\n    w = OWOutliers()\n    w.set_data(data)\n    w.commit()\n    w.show()\n    return app.exec_()\n\n\nif __name__ == \"__main__\":\n    sys.exit(test_main())\n", "path": "Orange/widgets/data/owoutliers.py"}]}