Repository: biolab/orange3

Issue:
predictions displaying error that the target is not in domain
<!-- 
Thanks for taking the time to report a bug!
If you're raising an issue about an add-on (i.e., installed via Options > Add-ons), raise an issue in the relevant add-on's issue tracker instead. See: https://github.com/biolab?q=orange3
To fix the bug, we need to be able to reproduce it. Please answer the following questions to the best of your ability.
-->

**What's wrong?**
<!-- Be specific, clear, and concise. Include screenshots if relevant. -->
<!-- If you're getting an error message, copy it, and enclose it with three backticks (```). -->

 the predictions is displaying that error 
 Some predictor(s) failed (see more ...)
- Random Forest: Random Forest: 'fetal_health' is not in domain
![image](https://github.com/biolab/orange3/assets/68437948/76dfbebc-ee2c-40ea-9a2b-b8608125d71a)
![image](https://github.com/biolab/orange3/assets/68437948/dae690a8-75f4-499c-aa50-8b45056670de)
![image](https://github.com/biolab/orange3/assets/68437948/0f82b5f4-8f96-4f68-81b5-1fc772bd9a46)





**How can we reproduce the problem?** 
<!-- Upload a zip with the .ows file and data. -->
<!-- Describe the steps (open this widget, click there, then add this...) -->

[fetal_health_data.csv](https://github.com/biolab/orange3/files/13403821/fetal_health_data.csv)




**What's your environment?**
<!-- To find your Orange version, see "Help → About → Version" or `Orange.version.full_version` in code -->
- Operating system: windows 11
- Orange version: 3.31.1
- How you installed Orange: downloaded from the website


Discussion:
Curious. I tried reproducing it, but it works for me. Could you also attach an .ows file?
yes of course here it is cause i can't upload it on github
https://drive.google.com/file/d/1UXl2TRq_295pMliXfSa9y558vm1CKcUq/view?usp=sharing
this is a drive link to the file
On Sun, 19 Nov 2023 at 19:50, Janez Demšar ***@***.***> wrote:

> Curious. I tried reproducing it, but it works for me. Could you also
> attach an .ows file?
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/biolab/orange3/issues/6644#issuecomment-1817929653>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AQKEPPHQE5KPHQEUJHYCDKLYFJBG3AVCNFSM6AAAAAA7R3A5T6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMJXHEZDSNRVGM>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>

Github allows zip file. Here's your file: [Model Training.ows.zip](https://github.com/biolab/orange3/files/13404494/Model.Training.ows.zip). (But right now I have another work, this will have to wait.)
The problem appears due to the Imputer (Model based)
![image](https://github.com/biolab/orange3/assets/11465003/ce35d0eb-eae3-40e4-905d-c1eb3a8c1713)

Thanks a lot!! I changed the method of imputation and it's working now
I'm glad to see that it solved your problem. Still, Orange should behave better; I'm reopening the issue.
Note: this happens only if classes are imputed, too.
Hm, @VesnaT, as @janezd says I only get this problem when I impute the class. And this widget does indeed also impute the class with a default method.

Resolving patch:
diff --git a/Orange/preprocess/impute.py b/Orange/preprocess/impute.py
--- a/Orange/preprocess/impute.py
+++ b/Orange/preprocess/impute.py
@@ -2,6 +2,7 @@
 import scipy.sparse as sp
 
 import Orange.data
+from Orange.data.table import DomainTransformationError
 from Orange.statistics import distribution, basic_stats
 from Orange.util import Reprable
 from .transformation import Transformation, Lookup
@@ -172,7 +173,7 @@ def copy(self):
         return FixedValueByType(*self.defaults.values())
 
 
-class ReplaceUnknownsModel(Reprable):
+class ReplaceUnknownsModel(Transformation):
     """
     Replace unknown values with predicted values using a `Orange.base.Model`
 
@@ -185,15 +186,14 @@ class ReplaceUnknownsModel(Reprable):
     """
     def __init__(self, variable, model):
         assert model.domain.class_var == variable
-        self.variable = variable
+        super().__init__(variable)
         self.model = model
 
     def __call__(self, data):
         if isinstance(data, Orange.data.Instance):
             data = Orange.data.Table.from_list(data.domain, [data])
         domain = data.domain
-        column = data.get_column(self.variable, copy=True)
-
+        column = data.transform(self._target_domain).get_column(self.variable, copy=True)
         mask = np.isnan(column)
         if not np.any(mask):
             return column
@@ -203,10 +203,17 @@ def __call__(self, data):
             data = data.transform(
                 Orange.data.Domain(domain.attributes, None, domain.metas)
             )
-        predicted = self.model(data[mask])
-        column[mask] = predicted
+        try:
+            column[mask] = self.model(data[mask])
+        except DomainTransformationError:
+            # owpredictions showed error when imputing target using a Model
+            # based imputer (owpredictions removes the target before predicing)
+            pass
         return column
 
+    def transform(self, c):
+        assert False, "abstract in Transformation, never used here"
+
     def __eq__(self, other):
         return type(self) is type(other) \
                and self.variable == other.variable \


Test patch:
diff --git a/Orange/tests/test_impute.py b/Orange/tests/test_impute.py
--- a/Orange/tests/test_impute.py
+++ b/Orange/tests/test_impute.py
@@ -9,7 +9,7 @@
 from Orange import preprocess
 from Orange.preprocess import impute, SklImpute
 from Orange import data
-from Orange.data import Unknown, Table
+from Orange.data import Unknown, Table, Domain
 
 from Orange.classification import MajorityLearner, SimpleTreeLearner
 from Orange.regression import MeanLearner
@@ -293,6 +293,27 @@ def test_bad_domain(self):
         self.assertRaises(ValueError, imputer, data=table,
                           variable=table.domain[0])
 
+    def test_missing_imputed_columns(self):
+        housing = Table("housing")
+
+        learner = SimpleTreeLearner(min_instances=10, max_depth=10)
+        method = preprocess.impute.Model(learner)
+
+        ivar = method(housing, housing.domain.attributes[0])
+        imputed = housing.transform(
+            Domain([ivar],
+                   housing.domain.class_var)
+        )
+        removed_imputed = imputed.transform(
+            Domain([], housing.domain.class_var))
+
+        r = removed_imputed.transform(imputed.domain)
+
+        no_class = removed_imputed.transform(Domain(removed_imputed.domain.attributes, None))
+        model_prediction_for_unknowns = ivar.compute_value.model(no_class[0])
+
+        np.testing.assert_equal(r.X, model_prediction_for_unknowns)
+
 
 class TestRandom(unittest.TestCase):
     def test_replacement(self):