Repository: biolab/orange3

Issue:
Preprocess / Continuize: hard to normalize only specific values
##### Orange version
3.8.dev

##### Expected behavior
Don't normalize datetime. I suppose it makes little sense to normalize by span/SD or one should normalize with, say, localize().


##### Actual behavior
Datetime is normalized and one can't use it properly with Timeseries add-on.


##### Steps to reproduce the behavior
Data Sets (Online Retail) - Select Columns (move Date to Features) - Preprocess (normalize) - Data Table.


##### Additional info (worksheets, data, screenshots, ...)
One could of course move datetime object to metas, but then you can't use it with Timeseries. Fix either or both.




Discussion:

Resolving patch:
diff --git a/Orange/preprocess/normalize.py b/Orange/preprocess/normalize.py
--- a/Orange/preprocess/normalize.py
+++ b/Orange/preprocess/normalize.py
@@ -3,7 +3,6 @@
 from Orange.util import Reprable
 from .preprocess import Normalize
 from .transformation import Normalizer as Norm
-
 __all__ = ["Normalizer"]
 
 
@@ -12,11 +11,13 @@ def __init__(self,
                  zero_based=True,
                  norm_type=Normalize.NormalizeBySD,
                  transform_class=False,
-                 center=True):
+                 center=True,
+                 normalize_datetime=False):
         self.zero_based = zero_based
         self.norm_type = norm_type
         self.transform_class = transform_class
         self.center = center
+        self.normalize_datetime = normalize_datetime
 
     def __call__(self, data):
         dists = distribution.get_distributions(data)
@@ -33,7 +34,7 @@ def __call__(self, data):
         return data.transform(domain)
 
     def normalize(self, dist, var):
-        if not var.is_continuous:
+        if not var.is_continuous or (var.is_time and not self.normalize_datetime):
             return var
         elif self.norm_type == Normalize.NormalizeBySD:
             return self.normalize_by_sd(dist, var)
diff --git a/Orange/preprocess/preprocess.py b/Orange/preprocess/preprocess.py
--- a/Orange/preprocess/preprocess.py
+++ b/Orange/preprocess/preprocess.py
@@ -293,6 +293,9 @@ class Normalize(Preprocess):
 
         Whether or not to center the data so it has mean zero.
 
+    normalize_datetime : bool (default=False)
+
+
     Examples
     --------
     >>> from Orange.data import Table
@@ -309,11 +312,13 @@ def __init__(self,
                  zero_based=True,
                  norm_type=NormalizeBySD,
                  transform_class=False,
-                 center=True):
+                 center=True,
+                 normalize_datetime=False):
         self.zero_based = zero_based
         self.norm_type = norm_type
         self.transform_class = transform_class
         self.center = center
+        self.normalize_datetime = normalize_datetime
 
     def __call__(self, data):
         """
@@ -340,11 +345,13 @@ def __call__(self, data):
             # matrix, which requires too much memory. For example, this is used for Bag of Words
             # models where normalization is not really needed.
             return data
+
         normalizer = normalize.Normalizer(
             zero_based=self.zero_based,
             norm_type=self.norm_type,
             transform_class=self.transform_class,
             center=self.center,
+            normalize_datetime=self.normalize_datetime
         )
         return normalizer(data)
 
diff --git a/Orange/widgets/data/owpreprocess.py b/Orange/widgets/data/owpreprocess.py
--- a/Orange/widgets/data/owpreprocess.py
+++ b/Orange/widgets/data/owpreprocess.py
@@ -36,7 +36,6 @@
     ParametersRole, Controller, SequenceFlow
 )
 
-
 class _NoneDisc(preprocess.discretize.Discretization):
     """Discretize all variables into None.
 


Test patch:
diff --git a/Orange/tests/test10.tab b/Orange/tests/test10.tab
new file mode 100644
--- /dev/null
+++ b/Orange/tests/test10.tab
@@ -0,0 +1,6 @@
+c1	c2	d1	d2	n1	n2	c3	d3	cl1	cl2
+c	t	d	d	c	d	c	d	d	c
+								class	class
+1	1995-01-21	a	a	?	a	2	a	a	2
+1	2003-07-23	a	b	1	?	0	b	b	0
+1	1967-03-12	a	b	2	b	-2	c	c	1
diff --git a/Orange/tests/test_normalize.py b/Orange/tests/test_normalize.py
--- a/Orange/tests/test_normalize.py
+++ b/Orange/tests/test_normalize.py
@@ -131,3 +131,14 @@ def test_skip_normalization(self):
         normalizer = Normalize()
         normalized = normalizer(data)
         np.testing.assert_array_equal(data.X, normalized.X)
+
+    def test_datetime_normalization(self):
+        data = Table(test_filename("test10.tab"))
+        normalizer = Normalize(zero_based=False,
+                               norm_type=Normalize.NormalizeBySD,
+                               transform_class=False)
+        data_norm = normalizer(data)
+        solution = [[0., '1995-01-21', 'a', 'a', '?', 'a', 1.225, 'a', 'a', 2],
+                    [0., '2003-07-23', 'a', 'b', -1., '?', 0., 'b', 'b', 0],
+                    [0., '1967-03-12', 'a', 'b', 1., 'b', -1.225, 'c', 'c', 1]]
+        self.compare_tables(data_norm, solution)