From 843376e8bec0b2c0e25e203185044c3e27ff2353 Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 1 Oct 2019 10:30:42 -0700 Subject: [PATCH 1/9] Add support for DateTime output. --- src/DotNetBridge/NativeDataInterop.cs | 10 ++++++++++ src/NativeBridge/ManagedInterop.cpp | 6 ++++-- src/NativeBridge/PythonInterop.cpp | 14 ++++++++++++++ src/python/nimbusml/internal/utils/dataframes.py | 4 +++- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/DotNetBridge/NativeDataInterop.cs b/src/DotNetBridge/NativeDataInterop.cs index b7f1a762..7205986f 100644 --- a/src/DotNetBridge/NativeDataInterop.cs +++ b/src/DotNetBridge/NativeDataInterop.cs @@ -182,6 +182,7 @@ private static unsafe void SendViewToNativeAsDataFrame(IChannel ch, EnvironmentB case InternalDataKind.R8: case InternalDataKind.BL: case InternalDataKind.TX: + case InternalDataKind.DT: break; } keyCard = -1; @@ -624,6 +625,15 @@ public static BufferFillerBase Create(EnvironmentBlock* penv, DataViewRow input, ValuePoker pokeU8 = (ulong value, int col, long m, long n) => fnU8(penv, col, m, n, value); return new Impl(input, pyCol, idvCol, type, pokeU8); + case InternalDataKind.DT: + var fnDT = MarshalDelegate(setter); + ValuePoker pokeDT = + (DateTime value, int col, long m, long n) => + { + DateTimeOffset dto = new DateTimeOffset(value); + fnDT(penv, col, m, n, dto.ToUnixTimeMilliseconds()); + }; + return new Impl(input, pyCol, idvCol, type, pokeDT); case InternalDataKind.TX: var fnTX = MarshalDelegate(setter); ValuePoker> pokeTX = diff --git a/src/NativeBridge/ManagedInterop.cpp b/src/NativeBridge/ManagedInterop.cpp index 46062fb5..6a80000d 100644 --- a/src/NativeBridge/ManagedInterop.cpp +++ b/src/NativeBridge/ManagedInterop.cpp @@ -81,6 +81,7 @@ void EnvironmentBlock::DataSinkCore(const DataViewBlock * pdata) case I4: _vset.push_back((void*)&SetI4); break; + case DT: case I8: _vset.push_back((void*)&SetI8); break; @@ -106,7 +107,6 @@ void EnvironmentBlock::DataSinkCore(const DataViewBlock * pdata) _vset.push_back((void*)&SetTX); break; case TS: // tbd - case DT: // tbd case DZ: // tbd default: throw std::invalid_argument("data type is not supported " + std::to_string(kind)); @@ -259,8 +259,10 @@ bp::dict EnvironmentBlock::GetData() AddToDict(std::string); delete column; break; - case TS: case DT: + AddToDict(CxInt64); + break; + case TS: case DZ: default: throw std::invalid_argument("data type is not supported " + std::to_string(kind)); diff --git a/src/NativeBridge/PythonInterop.cpp b/src/NativeBridge/PythonInterop.cpp index 46586fa7..f2d4ee87 100644 --- a/src/NativeBridge/PythonInterop.cpp +++ b/src/NativeBridge/PythonInterop.cpp @@ -40,6 +40,7 @@ PyColumnBase::creation_map* PyColumnBase::CreateSingleMap() map->insert(creation_map_entry(R4, CreateSingle)); map->insert(creation_map_entry(R8, CreateSingle)); map->insert(creation_map_entry(TX, CreateSingle)); + map->insert(creation_map_entry(DT, CreateSingle)); return map; } @@ -161,6 +162,19 @@ void PyColumnSingle::AddToDict(bp::dict& dict, bp::make_tuple(sizeof(T)), bp::object(h)); } break; + case DataKind::DT: + { + bp::handle<> h(::PyCapsule_New((void*)this, NULL, (PyCapsule_Destructor)&destroyManagerCObject)); + np::ndarray npdata = np::from_data( + data, + np::dtype::get_builtin(), + bp::make_tuple(_pData->size()), + bp::make_tuple(sizeof(T)), bp::object(h)); + + dict[name] = bp::dict(); + dict[name]["..DateTime"] = npdata; + } + break; } } diff --git a/src/python/nimbusml/internal/utils/dataframes.py b/src/python/nimbusml/internal/utils/dataframes.py index 5d058fb5..6454d7e6 100644 --- a/src/python/nimbusml/internal/utils/dataframes.py +++ b/src/python/nimbusml/internal/utils/dataframes.py @@ -6,7 +6,7 @@ import numpy as np import six -from pandas import DataFrame, Series, concat, Categorical +from pandas import DataFrame, Series, concat, Categorical, to_datetime from pandas.api.types import infer_dtype from scipy.sparse import csr_matrix @@ -208,6 +208,8 @@ def resolve_output_as_dataframe(ret): for key in ret.keys(): if not isinstance(ret[key], dict): data[key] = ret[key] + elif "..DateTime" in ret[key]: + data[key] = to_datetime(ret[key]["..DateTime"], unit='ms') else: data[key] = Categorical.from_codes( ret[key]["..Data"], ret[key]["..KeyValues"]) From 831a1959d3ef9b488eb0e8196da277f463f411c8 Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 1 Oct 2019 13:36:57 -0700 Subject: [PATCH 2/9] Add support for DateTime input columns. --- src/DotNetBridge/NativeDataView.cs | 29 +++++++++++++++++++ src/NativeBridge/DataViewInterop.cpp | 4 +++ src/NativeBridge/DataViewInterop.h | 1 + .../nimbusml/internal/utils/dataframes.py | 8 +++++ 4 files changed, 42 insertions(+) diff --git a/src/DotNetBridge/NativeDataView.cs b/src/DotNetBridge/NativeDataView.cs index 7576781c..1a829889 100644 --- a/src/DotNetBridge/NativeDataView.cs +++ b/src/DotNetBridge/NativeDataView.cs @@ -142,6 +142,10 @@ public NativeDataView(IHostEnvironment env, DataSourceBlock* pdata) case InternalDataKind.Text: columns.Add(new TextColumn(pdata, pdata->getters[c], c, name)); break; + case InternalDataKind.DT: + if (pdata->vecCards[c] == -1) + columns.Add(new DateTimeColumn(pdata, pdata->getters[c], c, name)); + break; } } @@ -866,6 +870,31 @@ public override void Dispose() } } + private sealed class DateTimeColumn : Column + { + private I8Getter _getter; + + public DateTimeColumn(DataSourceBlock* data, void* getter, int colIndex, string name) + : base(data, colIndex, name, DateTimeDataViewType.Instance) + { + _getter = MarshalDelegate(getter); + } + + public override void CopyOut(long index, Batch batch, ref DateTime value) + { + Contracts.Check(Data != null, AlreadyDisposed); + Contracts.Assert(0 <= index); + _getter(Data, ColIndex, index, out var val); + value = DateTimeOffset.FromUnixTimeMilliseconds(val).UtcDateTime; + } + + public override void Dispose() + { + _getter = null; + base.Dispose(); + } + } + private sealed class TextColumn : Column> { private TXGetter _getter; diff --git a/src/NativeBridge/DataViewInterop.cpp b/src/NativeBridge/DataViewInterop.cpp index 3c30c3c4..d681df1f 100644 --- a/src/NativeBridge/DataViewInterop.cpp +++ b/src/NativeBridge/DataViewInterop.cpp @@ -98,6 +98,10 @@ DataSourceBlock::DataSourceBlock(bp::dict& data) kind = R8; pgetter = (void*)&GetR8; break; + case (ML_PY_DATETIME): + kind = DT; + pgetter = (void*)&GetI8; + break; default: throw std::invalid_argument("column " + colName + " has unsupported type"); } diff --git a/src/NativeBridge/DataViewInterop.h b/src/NativeBridge/DataViewInterop.h index 01dc21fc..c764b285 100644 --- a/src/NativeBridge/DataViewInterop.h +++ b/src/NativeBridge/DataViewInterop.h @@ -545,5 +545,6 @@ enum ML_PY_TYPE_MAP_ENUM { ML_PY_CAT = 'c', ML_PY_TEXT = 't', ML_PY_UNICODE = 'u', + ML_PY_DATETIME = 'z', ML_PY_UNSUPPORTED = 'x' }; diff --git a/src/python/nimbusml/internal/utils/dataframes.py b/src/python/nimbusml/internal/utils/dataframes.py index 6454d7e6..17572ad1 100644 --- a/src/python/nimbusml/internal/utils/dataframes.py +++ b/src/python/nimbusml/internal/utils/dataframes.py @@ -47,6 +47,13 @@ def resolve_dataframe(dataframe): # Workaround, empty dataframe needs to be sent as an array # to convey type information ret[name_i] = serie.values.reshape((len(serie), 1)) + + elif serie.dtype == np.dtype('datetime64[ns]'): + values = serie.values.astype(np.int64, copy=False) + values = values // 1000000 # convert from nanoseconds to milliseconds + ret[str(i)] = values + types.append(_global_dtype_to_char_dict[np.dtype('datetime64[ns]')]) + elif serie.dtype == np.object or str(serie.dtype) == ' Date: Tue, 1 Oct 2019 15:46:02 -0700 Subject: [PATCH 3/9] Add unit test for DateTime column input and output. --- src/python/nimbusml.pyproj | 1 + .../nimbusml/tests/data_type/test_datetime.py | 121 ++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/python/nimbusml/tests/data_type/test_datetime.py diff --git a/src/python/nimbusml.pyproj b/src/python/nimbusml.pyproj index eeedbdad..5266ee0d 100644 --- a/src/python/nimbusml.pyproj +++ b/src/python/nimbusml.pyproj @@ -654,6 +654,7 @@ + diff --git a/src/python/nimbusml/tests/data_type/test_datetime.py b/src/python/nimbusml/tests/data_type/test_datetime.py new file mode 100644 index 00000000..db889cf4 --- /dev/null +++ b/src/python/nimbusml/tests/data_type/test_datetime.py @@ -0,0 +1,121 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------------------------- +import os +import unittest +import tempfile + +import numpy as np +import pandas as pd +import azureml.dataprep as dprep +from nimbusml import Pipeline, DprepDataStream +from nimbusml.preprocessing.missing_values import Handler + + +def get_temp_file(suffix=None): + fd, file_name = tempfile.mkstemp(suffix=suffix) + fl = os.fdopen(fd, 'w') + fl.close() + return file_name + + +class TestDateTimeDataType(unittest.TestCase): + def test_negative_values(self): + milliseconds_in_year = 365*24*60*60*1000 + data = [i * milliseconds_in_year for i in [-1, -2, -3, -3.3]] + + df = pd.DataFrame({'c1': data, 'c2': [3,4,5,6]}) + df = df.astype({'c1': np.dtype('datetime64[ms]')}) + + pipeline = Pipeline(steps=[Handler(columns={'c2': 'c2'})]) + result = pipeline.fit_transform(df) + + self.assertTrue(result.loc[:, 'c1'].equals(df.loc[:, 'c1'])) + self.assertEqual(result.loc[:, 'c1'].dtype, np.dtype('datetime64[ns]')) + + self.assertEqual(result.loc[0, 'c1'].year, 1969) + self.assertEqual(result.loc[3, 'c1'].year, 1966) + + def test_timestamp_boundaries(self): + # Here are the current min and max for a Pandas Timestamp + # 1677-09-21 00:12:43.145225 + # 2262-04-11 23:47:16.854775807 + + data = [pd.Timestamp(1677, 9, 22, 1), pd.Timestamp.max] + df = pd.DataFrame({'c1': data, 'c2': [3,4]}) + df = df.astype({'c1': np.dtype('datetime64[ms]')}) + + pipeline = Pipeline(steps=[Handler(columns={'c2': 'c2'})]) + result = pipeline.fit_transform(df) + + self.assertTrue(result.loc[:, 'c1'].equals(df.loc[:, 'c1'])) + self.assertEqual(result.dtypes[0], np.dtype('datetime64[ns]')) + + self.assertEqual(result.loc[0, 'c1'].year, 1677) + self.assertEqual(result.loc[0, 'c1'].month, 9) + self.assertEqual(result.loc[0, 'c1'].day, 22) + + self.assertEqual(result.loc[1, 'c1'].year, 2262) + self.assertEqual(result.loc[1, 'c1'].month, 4) + self.assertEqual(result.loc[1, 'c1'].day, 11) + + def test_datetime_column_parsed_from_string(self): + dates = ["2018-01-02", "2018-02-01"] + df = pd.DataFrame({'c1': dates, 'c2': [3,4]}) + + file_name = get_temp_file('.csv') + df.to_csv(file_name) + df = pd.read_csv(file_name, parse_dates=['c1'], index_col=0) + + self.assertEqual(df.dtypes[0], np.dtype('datetime64[ns]')) + + pipeline = Pipeline(steps=[Handler(columns={'c2': 'c2'})]) + result = pipeline.fit_transform(df) + + self.assertEqual(result.loc[0, 'c1'].year, 2018) + self.assertEqual(result.loc[0, 'c1'].month, 1) + self.assertEqual(result.loc[0, 'c1'].day, 2) + + self.assertEqual(result.loc[1, 'c1'].year, 2018) + self.assertEqual(result.loc[1, 'c1'].month, 2) + self.assertEqual(result.loc[1, 'c1'].day, 1) + + self.assertEqual(len(result), 2) + self.assertEqual(result.dtypes[0], np.dtype('datetime64[ns]')) + + os.remove(file_name) + + def test_dprep_datastream(self): + dates = ["2018-01-02", "2018-02-01"] + col2 = ['0', '1'] + label_array = np.repeat([0], 2) + train_df = pd.DataFrame({'col1': dates, 'col2': col2, 'label': label_array}) + + pipeline = Pipeline(steps=[ + Handler(columns={'2': 'col2'}, concat=False, impute_by_slot=True, replace_with='Mean') + ]) + + file_name = get_temp_file('.csv') + train_df.to_csv(file_name) + + dataflow = dprep.read_csv(file_name, infer_column_types=True) + dprepDataStream = DprepDataStream(dataflow) + + result = pipeline.fit_transform(dprepDataStream) + + self.assertEqual(result.dtypes[1], np.dtype('datetime64[ns]')) + + self.assertEqual(result.loc[0, 'col1'].year, 2018) + self.assertEqual(result.loc[0, 'col1'].month, 1) + self.assertEqual(result.loc[0, 'col1'].day, 2) + + self.assertEqual(result.loc[1, 'col1'].year, 2018) + self.assertEqual(result.loc[1, 'col1'].month, 2) + self.assertEqual(result.loc[1, 'col1'].day, 1) + + os.remove(file_name) + + +if __name__ == '__main__': + unittest.main() From 039acee7f5408ce1dc0b1052ecdceb8d49b15e45 Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 1 Oct 2019 17:47:06 -0700 Subject: [PATCH 4/9] Fix DateTime.Kind == Unspecified output from dprep. --- src/DotNetBridge/NativeDataInterop.cs | 4 +++- .../nimbusml/tests/data_type/test_datetime.py | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/DotNetBridge/NativeDataInterop.cs b/src/DotNetBridge/NativeDataInterop.cs index 7205986f..461beb3c 100644 --- a/src/DotNetBridge/NativeDataInterop.cs +++ b/src/DotNetBridge/NativeDataInterop.cs @@ -630,7 +630,9 @@ public static BufferFillerBase Create(EnvironmentBlock* penv, DataViewRow input, ValuePoker pokeDT = (DateTime value, int col, long m, long n) => { - DateTimeOffset dto = new DateTimeOffset(value); + DateTimeOffset dto = (value.Kind == DateTimeKind.Unspecified) ? + new DateTimeOffset(value, TimeSpan.Zero) : + new DateTimeOffset(value); fnDT(penv, col, m, n, dto.ToUnixTimeMilliseconds()); }; return new Impl(input, pyCol, idvCol, type, pokeDT); diff --git a/src/python/nimbusml/tests/data_type/test_datetime.py b/src/python/nimbusml/tests/data_type/test_datetime.py index db889cf4..018da2df 100644 --- a/src/python/nimbusml/tests/data_type/test_datetime.py +++ b/src/python/nimbusml/tests/data_type/test_datetime.py @@ -35,6 +35,10 @@ def test_negative_values(self): self.assertEqual(result.loc[:, 'c1'].dtype, np.dtype('datetime64[ns]')) self.assertEqual(result.loc[0, 'c1'].year, 1969) + self.assertEqual(result.loc[0, 'c1'].hour, 0) + self.assertEqual(result.loc[0, 'c1'].minute, 0) + self.assertEqual(result.loc[0, 'c1'].second, 0) + self.assertEqual(result.loc[3, 'c1'].year, 1966) def test_timestamp_boundaries(self): @@ -76,10 +80,16 @@ def test_datetime_column_parsed_from_string(self): self.assertEqual(result.loc[0, 'c1'].year, 2018) self.assertEqual(result.loc[0, 'c1'].month, 1) self.assertEqual(result.loc[0, 'c1'].day, 2) + self.assertEqual(result.loc[0, 'c1'].hour, 0) + self.assertEqual(result.loc[0, 'c1'].minute, 0) + self.assertEqual(result.loc[0, 'c1'].second, 0) self.assertEqual(result.loc[1, 'c1'].year, 2018) self.assertEqual(result.loc[1, 'c1'].month, 2) self.assertEqual(result.loc[1, 'c1'].day, 1) + self.assertEqual(result.loc[1, 'c1'].hour, 0) + self.assertEqual(result.loc[1, 'c1'].minute, 0) + self.assertEqual(result.loc[1, 'c1'].second, 0) self.assertEqual(len(result), 2) self.assertEqual(result.dtypes[0], np.dtype('datetime64[ns]')) @@ -87,7 +97,7 @@ def test_datetime_column_parsed_from_string(self): os.remove(file_name) def test_dprep_datastream(self): - dates = ["2018-01-02", "2018-02-01"] + dates = ["2018-01-02 00:00:00", "2018-02-01 10:00:00"] col2 = ['0', '1'] label_array = np.repeat([0], 2) train_df = pd.DataFrame({'col1': dates, 'col2': col2, 'label': label_array}) @@ -109,10 +119,16 @@ def test_dprep_datastream(self): self.assertEqual(result.loc[0, 'col1'].year, 2018) self.assertEqual(result.loc[0, 'col1'].month, 1) self.assertEqual(result.loc[0, 'col1'].day, 2) + self.assertEqual(result.loc[0, 'col1'].hour, 0) + self.assertEqual(result.loc[0, 'col1'].minute, 0) + self.assertEqual(result.loc[0, 'col1'].second, 0) self.assertEqual(result.loc[1, 'col1'].year, 2018) self.assertEqual(result.loc[1, 'col1'].month, 2) self.assertEqual(result.loc[1, 'col1'].day, 1) + self.assertEqual(result.loc[1, 'col1'].hour, 10) + self.assertEqual(result.loc[1, 'col1'].minute, 0) + self.assertEqual(result.loc[1, 'col1'].second, 0) os.remove(file_name) From e5b6182467eaa37be33bf9c1bcf41221be1b084d Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 8 Oct 2019 17:09:07 -0700 Subject: [PATCH 5/9] Update the csproj files to point to the latest nuget packages. --- src/DotNetBridge/DotNetBridge.csproj | 22 +++++++++++----------- src/Platforms/build.csproj | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/DotNetBridge/DotNetBridge.csproj b/src/DotNetBridge/DotNetBridge.csproj index db737e30..a4c6aea7 100644 --- a/src/DotNetBridge/DotNetBridge.csproj +++ b/src/DotNetBridge/DotNetBridge.csproj @@ -32,17 +32,17 @@ all runtime; build; native; contentfiles; analyzers - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/Platforms/build.csproj b/src/Platforms/build.csproj index 10f89106..46231756 100644 --- a/src/Platforms/build.csproj +++ b/src/Platforms/build.csproj @@ -11,17 +11,17 @@ - - - - - - - - - - - + + + + + + + + + + + From 752fadd990d3f93186eb74f172b314d5ea90d282 Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 8 Oct 2019 17:33:28 -0700 Subject: [PATCH 6/9] Update the Tensorflow.NET library version. --- src/DotNetBridge/DotNetBridge.csproj | 2 +- src/Platforms/build.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DotNetBridge/DotNetBridge.csproj b/src/DotNetBridge/DotNetBridge.csproj index a4c6aea7..95bd830d 100644 --- a/src/DotNetBridge/DotNetBridge.csproj +++ b/src/DotNetBridge/DotNetBridge.csproj @@ -44,7 +44,7 @@ - + diff --git a/src/Platforms/build.csproj b/src/Platforms/build.csproj index 46231756..b872f878 100644 --- a/src/Platforms/build.csproj +++ b/src/Platforms/build.csproj @@ -23,7 +23,7 @@ - + From cf47452a66d9d4e689460289382894d8a25a4eac Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 8 Oct 2019 17:53:21 -0700 Subject: [PATCH 7/9] Fix azureml dprep not available for Python 2.7 --- src/python/nimbusml/tests/data_type/test_datetime.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/python/nimbusml/tests/data_type/test_datetime.py b/src/python/nimbusml/tests/data_type/test_datetime.py index 018da2df..7ba32777 100644 --- a/src/python/nimbusml/tests/data_type/test_datetime.py +++ b/src/python/nimbusml/tests/data_type/test_datetime.py @@ -8,7 +8,6 @@ import numpy as np import pandas as pd -import azureml.dataprep as dprep from nimbusml import Pipeline, DprepDataStream from nimbusml.preprocessing.missing_values import Handler @@ -96,7 +95,10 @@ def test_datetime_column_parsed_from_string(self): os.remove(file_name) + @unittest.skipIf(sys.version_info[:2] == (2, 7), "azureml-dataprep is not installed.") def test_dprep_datastream(self): + import azureml.dataprep as dprep + dates = ["2018-01-02 00:00:00", "2018-02-01 10:00:00"] col2 = ['0', '1'] label_array = np.repeat([0], 2) From 46b33412d62ed4fc6c105c723d7253ad70f862fd Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 8 Oct 2019 18:01:48 -0700 Subject: [PATCH 8/9] Fix missing sys import. --- src/python/nimbusml/tests/data_type/test_datetime.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/python/nimbusml/tests/data_type/test_datetime.py b/src/python/nimbusml/tests/data_type/test_datetime.py index 7ba32777..80b19194 100644 --- a/src/python/nimbusml/tests/data_type/test_datetime.py +++ b/src/python/nimbusml/tests/data_type/test_datetime.py @@ -3,6 +3,7 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------------------------- import os +import sys import unittest import tempfile From 8e38d84f2cfa23690a41a7261784093d358990c6 Mon Sep 17 00:00:00 2001 From: "pieths.dev@gmail.com" Date: Tue, 8 Oct 2019 18:40:26 -0700 Subject: [PATCH 9/9] Fix broken assertEqual on Python 3.5. --- src/python/nimbusml/tests/data_type/test_datetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/nimbusml/tests/data_type/test_datetime.py b/src/python/nimbusml/tests/data_type/test_datetime.py index 80b19194..fabab5b0 100644 --- a/src/python/nimbusml/tests/data_type/test_datetime.py +++ b/src/python/nimbusml/tests/data_type/test_datetime.py @@ -117,7 +117,7 @@ def test_dprep_datastream(self): result = pipeline.fit_transform(dprepDataStream) - self.assertEqual(result.dtypes[1], np.dtype('datetime64[ns]')) + self.assertEqual(result.loc[:, 'col1'].dtype, np.dtype('datetime64[ns]')) self.assertEqual(result.loc[0, 'col1'].year, 2018) self.assertEqual(result.loc[0, 'col1'].month, 1)