Skip to content
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
113 changes: 59 additions & 54 deletions Orange/widgets/evaluate/owconfusionmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from AnyQt.QtCore import (
Qt, QSize, QItemSelectionModel, QItemSelection, QT_VERSION
)
import numpy
import numpy as np
import sklearn.metrics as skl_metrics

import Orange
Expand All @@ -33,10 +33,10 @@ def confusion_matrix(res, index):

Returns: Confusion matrix
"""
labels = numpy.arange(len(res.domain.class_var.values))
labels = np.arange(len(res.domain.class_var.values))
if not res.actual.size:
# scikit-learn will not return an zero matrix
return numpy.zeros((len(labels), len(labels)))
return np.zeros((len(labels), len(labels)))
else:
return skl_metrics.confusion_matrix(
res.actual, res.predicted[index], labels=labels)
Expand Down Expand Up @@ -252,8 +252,8 @@ def set_results(self, results):
nan_values = False
if results is not None:
assert isinstance(results, Orange.evaluation.Results)
if numpy.any(numpy.isnan(results.actual)) or \
numpy.any(numpy.isnan(results.predicted)):
if np.any(np.isnan(results.actual)) or \
np.any(np.isnan(results.predicted)):
# Error out here (could filter them out with a warning
# instead).
nan_values = True
Expand Down Expand Up @@ -354,53 +354,58 @@ def cell_clicked(self, model_index):
self.tableview.selectionModel().select(
selection, QItemSelectionModel.ClearAndSelect)

def _prepare_data(self):
indices = self.tableview.selectedIndexes()
indices = {(ind.row() - 2, ind.column() - 2) for ind in indices}
actual = self.results.actual
learner_name = self.learners[self.selected_learner[0]]
predicted = self.results.predicted[self.selected_learner[0]]
selected = [i for i, t in enumerate(zip(actual, predicted))
if t in indices]

extra = []
class_var = self.data.domain.class_var
metas = self.data.domain.metas

if self.append_predictions:
extra.append(predicted.reshape(-1, 1))
var = Orange.data.DiscreteVariable(
"{}({})".format(class_var.name, learner_name),
class_var.values
)
metas = metas + (var,)

if self.append_probabilities and \
self.results.probabilities is not None:
probs = self.results.probabilities[self.selected_learner[0]]
extra.append(np.array(probs, dtype=object))
pvars = [Orange.data.ContinuousVariable("p({})".format(value))
for value in class_var.values]
metas = metas + tuple(pvars)

domain = Orange.data.Domain(self.data.domain.attributes,
self.data.domain.class_vars,
metas)
data = self.data.transform(domain)
if len(extra):
data.metas[:, len(self.data.domain.metas):] = \
np.hstack(tuple(extra))
data.name = learner_name

if selected:
annotated_data = create_annotated_table(data, selected)
data = data[selected]
else:
annotated_data = create_annotated_table(data, [])
data = None

return data, annotated_data

def commit(self):
"""Output data instances corresponding to selected cells"""
if self.results is not None and self.data is not None \
and self.selected_learner:
indices = self.tableview.selectedIndexes()
indices = {(ind.row() - 2, ind.column() - 2) for ind in indices}
actual = self.results.actual
learner_name = self.learners[self.selected_learner[0]]
predicted = self.results.predicted[self.selected_learner[0]]
selected = [i for i, t in enumerate(zip(actual, predicted))
if t in indices]

extra = []
class_var = self.data.domain.class_var
metas = self.data.domain.metas

if self.append_predictions:
extra.append(predicted.reshape(-1, 1))
var = Orange.data.DiscreteVariable(
"{}({})".format(class_var.name, learner_name),
class_var.values
)
metas = metas + (var,)

if self.append_probabilities and \
self.results.probabilities is not None:
probs = self.results.probabilities[self.selected_learner[0]]
extra.append(numpy.array(probs, dtype=object))
pvars = [Orange.data.ContinuousVariable("p({})".format(value))
for value in class_var.values]
metas = metas + tuple(pvars)

domain = Orange.data.Domain(self.data.domain.attributes,
self.data.domain.class_vars,
metas)
data = self.data.transform(domain)
data.metas[:, len(self.data.domain.metas):] = \
numpy.hstack(tuple(extra))
data.name = learner_name

if selected:
annotated_data = create_annotated_table(data, selected)
data = data[selected]
else:
annotated_data = create_annotated_table(data, [])
data = None

data, annotated_data = self._prepare_data()
else:
data = None
annotated_data = None
Expand Down Expand Up @@ -437,21 +442,21 @@ def _isinvalid(x):
colsum = cmatrix.sum(axis=0)
rowsum = cmatrix.sum(axis=1)
n = len(cmatrix)
diag = numpy.diag_indices(n)
diag = np.diag_indices(n)

colors = cmatrix.astype(numpy.double)
colors = cmatrix.astype(np.double)
colors[diag] = 0
if self.selected_quantity == 0:
normalized = cmatrix.astype(numpy.int)
normalized = cmatrix.astype(np.int)
formatstr = "{}"
div = numpy.array([colors.max()])
div = np.array([colors.max()])
else:
if self.selected_quantity == 1:
normalized = 100 * cmatrix / colsum
div = colors.max(axis=0)
else:
normalized = 100 * cmatrix / rowsum[:, numpy.newaxis]
div = colors.max(axis=1)[:, numpy.newaxis]
normalized = 100 * cmatrix / rowsum[:, np.newaxis]
div = colors.max(axis=1)[:, np.newaxis]
formatstr = "{:2.1f} %"
div[div == 0] = 1
colors /= div
Expand Down
9 changes: 9 additions & 0 deletions Orange/widgets/evaluate/tests/test_owconfusionmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,12 @@ def test_nan_results(self):
self.assertTrue(self.widget.Error.invalid_values.is_shown())
self.send_signal(self.widget.Inputs.evaluation_results, None)
self.assertFalse(self.widget.Error.invalid_values.is_shown())

def test_not_append_extra_meta_columns(self):
"""
When a user does not want append extra meta column, the widget
should not crash.
GH-2386
"""
self.widget.append_predictions = False
self.send_signal(self.widget.Inputs.evaluation_results, self.results_1_iris)