Skip to content

Commit 3f4c786

Browse files
authored
Merge pull request #4601 from robertcv/enh/editdomain_time
[FIX] Edit Domain: Improve Text/Categorical to Time conversion
2 parents c999ab9 + fcf24c6 commit 3f4c786

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

Orange/widgets/data/oweditdomain.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2527,8 +2527,16 @@ def mapper(arr, out=None, dtype=dtype, **kwargs):
25272527
def time_parse(values: Sequence[str], name="__"):
25282528
tvar = Orange.data.TimeVariable(name)
25292529
parse_time = ftry(tvar.parse, ValueError, np.nan)
2530-
values = [parse_time(v) for v in values]
2531-
return tvar, values
2530+
_values = [parse_time(v) for v in values]
2531+
if np.all(np.isnan(_values)):
2532+
# try parsing it with pandas (like in transform)
2533+
dti = pd.to_datetime(values, errors="coerce")
2534+
_values = datetime_to_epoch(dti)
2535+
date_only = getattr(dti, "_is_dates_only", False)
2536+
if np.all(dti != pd.NaT):
2537+
tvar.have_date = True
2538+
tvar.have_time = not date_only
2539+
return tvar, _values
25322540

25332541

25342542
as_string = np.frompyfunc(str, 1, 1)
@@ -2734,17 +2742,23 @@ def transform(self, c):
27342742
raise TypeError
27352743

27362744

2745+
def datetime_to_epoch(dti: pd.DatetimeIndex) -> np.ndarray:
2746+
"""Convert datetime to epoch"""
2747+
data = dti.values.astype("M8[us]")
2748+
mask = np.isnat(data)
2749+
data = data.astype(float) / 1e6
2750+
data[mask] = np.nan
2751+
return data
2752+
2753+
27372754
class ReparseTimeTransform(Transformation):
27382755
"""
27392756
Re-parse the column's string repr as datetime.
27402757
"""
27412758
def transform(self, c):
27422759
c = column_str_repr(self.variable, c)
2743-
c = pd.to_datetime(c, errors="coerce").values.astype("M8[us]")
2744-
mask = np.isnat(c)
2745-
orangecol = c.astype(float) / 1e6
2746-
orangecol[mask] = np.nan
2747-
return orangecol
2760+
c = pd.to_datetime(c, errors="coerce")
2761+
return datetime_to_epoch(c)
27482762

27492763

27502764
class LookupMappingTransform(Transformation):

Orange/widgets/data/tests/test_oweditdomain.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import numpy as np
1010
from numpy.testing import assert_array_equal
11+
import pandas as pd
1112

1213
from AnyQt.QtCore import QItemSelectionModel, Qt, QItemSelection
1314
from AnyQt.QtWidgets import QAction, QComboBox, QLineEdit, \
@@ -33,7 +34,7 @@
3334
table_column_data, ReinterpretVariableEditor, CategoricalVector,
3435
VariableEditDelegate, TransformRole,
3536
RealVector, TimeVector, StringVector, make_dict_mapper, DictMissingConst,
36-
LookupMappingTransform, as_float_or_nan, column_str_repr,
37+
LookupMappingTransform, as_float_or_nan, column_str_repr, time_parse,
3738
GroupItemsDialog)
3839
from Orange.widgets.data.owcolor import OWColor, ColorRole
3940
from Orange.widgets.tests.base import WidgetTest, GuiTest
@@ -917,6 +918,19 @@ def test_column_str_repr(self):
917918
d = column_str_repr(v, np.array([0., np.nan, 1.0]))
918919
assert_array_equal(d, ["00:00:00", "?", "00:00:01"])
919920

921+
def test_time_parse(self):
922+
"""parsing additional datetimes by pandas"""
923+
date = ["1/22/20", "1/23/20", "1/24/20"]
924+
# we use privet method, check if still exists
925+
assert hasattr(pd.DatetimeIndex, '_is_dates_only')
926+
927+
tval, values = time_parse(date)
928+
929+
self.assertTrue(tval.have_date)
930+
self.assertFalse(tval.have_time)
931+
self.assertListEqual(list(values),
932+
[1579651200.0, 1579737600.0, 1579824000.0])
933+
920934

921935
class TestLookupMappingTransform(TestCase):
922936
def setUp(self) -> None:

0 commit comments

Comments
 (0)