Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Widget Logistic Regression: can handle unused values #2116

Merged
merged 2 commits into from
Apr 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions Orange/widgets/model/owlogisticregression.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import numpy as np
from itertools import chain
import numpy as np
from AnyQt import QtWidgets
from AnyQt.QtCore import Qt

Expand Down Expand Up @@ -61,17 +61,17 @@ def add_main_layout(self):
self.set_c()

def set_c(self):
self.C = self.C_s[self.C_index]
fmt = "C={}" if self.C >= 1 else "C={:.3f}"
self.c_label.setText(fmt.format(self.C))
self.strength_C = self.C_s[self.C_index]
fmt = "C={}" if self.strength_C >= 1 else "C={:.3f}"
self.c_label.setText(fmt.format(self.strength_C))

def create_learner(self):
penalty = self.penalty_types_short[self.penalty_type]
return self.LEARNER(
penalty=penalty,
dual=self.dual,
tol=self.tol,
C=self.C,
C=self.strength_C,
fit_intercept=self.fit_intercept,
intercept_scaling=self.intercept_scaling,
preprocessors=self.preprocessors
Expand All @@ -86,16 +86,16 @@ def update_model(self):

def get_learner_parameters(self):
return (("Regularization", "{}, C={}".format(
self.penalty_types[self.penalty_type], self.C_s[self.C_index])),)
self.penalty_types[self.penalty_type], self.C_s[self.C_index])),)


def create_coef_table(classifier):
i = classifier.intercept
c = classifier.coefficients
if len(classifier.domain.class_var.values) > 2:
values = classifier.domain.class_var.values
if c.shape[0] > 2:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this something different? Wasn't the previous code correct? Isn't classifier.coefficients equal to the number of attributes + 1? Or am I overlooking something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous code was probably not correct. c.shape[0] is not always equal to len(classifier.domain.class_var.values). That is in the case when we have a domain with more class values than contained in a data table. And of course always in the case when number of that values is 2.

values = [classifier.domain.class_var.values[int(i)] for i in classifier.used_vals[0]]
else:
values = ["coef"]
values = [classifier.domain.class_var.values[int(classifier.used_vals[0][1])]]
domain = Domain([ContinuousVariable(value, number_of_decimals=7)
for value in values], metas=[StringVariable("name")])
coefs = np.vstack((i.reshape(1, len(i)), c.T))
Expand Down
41 changes: 39 additions & 2 deletions Orange/widgets/model/tests/test_owlogisticregression.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
import unittest

from Orange.classification import LogisticRegressionLearner
from Orange.data import Table
from Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable
from Orange.statistics.util import stats
from Orange.widgets.model.owlogisticregression import (create_coef_table,
OWLogisticRegression)
from Orange.widgets.tests.base import (WidgetTest, WidgetLearnerTestMixin,
ParameterMapping)


class LogisticRegressionTest(unittest.TestCase):
def test_coef_table_single(self):
data = Table("titanic")
Expand Down Expand Up @@ -58,3 +57,41 @@ def test_output_coefficients(self):
self.send_signal("Data", self.data)
self.widget.apply_button.button.click()
self.assertIsInstance(self.get_output("Coefficients"), Table)

def test_domain_with_more_values_than_table(self):
"""
When the data with a domain which has more values than
a table was sent, the widget threw error Invalid number of variable columns.
GH-2116
"""
table = Table("iris")
cases = [[list(range(80))],
[list(range(90, 140))],
[list(range(30)) + list(range(120, 140))]]
for case in cases:
data = table[case, :]
self.send_signal("Data", data)
self.widget.apply_button.button.click()

def test_coefficients_one_value(self):
"""
In case we have only two values of a target we get coefficients of only value.
Instead of writing "coef" or sth similar it is written a second value name.
GH-2116
"""
table = Table(
Domain(
[ContinuousVariable("a"),
ContinuousVariable("b")],
[DiscreteVariable("c", values=["yes", "no"])]
),
list(zip(
[1., 0.],
[0., 1.],
["yes", "no"]))
)
self.send_signal("Data", table)
self.widget.apply_button.button.click()
coef = self.get_output("Coefficients")
self.assertEqual(coef.domain[0].name, "no")
self.assertGreater(coef[2][0], 0.)