From 9e1affb5f6553addb6aeb6116d3e3b70e6ee7cff Mon Sep 17 00:00:00 2001 From: VidhyaVarshanyJS Date: Tue, 30 Jan 2024 14:21:36 +0530 Subject: [PATCH 1/3] implemented round() function --- temporian/core/event_set_ops.py | 33 +++++++++++++++++++ temporian/core/operators/unary.py | 30 +++++++++++++++++ .../implementation/numpy/operators/unary.py | 9 +++++ 3 files changed, 72 insertions(+) diff --git a/temporian/core/event_set_ops.py b/temporian/core/event_set_ops.py index d635ce4b7..e5f9370fd 100644 --- a/temporian/core/event_set_ops.py +++ b/temporian/core/event_set_ops.py @@ -1501,6 +1501,38 @@ def abs( return abs(self) + def __round__(self): + from temporian.core.operators.unary import round + + return round(input=self) + + def round( + self: EventSetOrNode, + ) -> EventSetOrNode: + """Rounds the values of an [`EventSet`][temporian.EventSet]'s features to the nearest integer. + + Example: + ```python + >>> a = tp.event_set( + ... timestamps=[1, 2, 3], + ... features={"M": [1.4, 2.6, 3.1], "N": [-1.9, -3.5, 5.8]}, + ... ) + >>> a.round() + indexes: ... + 'M': [1, 3, 3] + 'N': [-2, -4, 6] + ... + + ``` + + Returns: + EventSet with rounded feature values. + """ + from temporian.core.operators.unary import round + + return round(self) + + def add_index( self: EventSetOrNode, indexes: Union[str, List[str]] ) -> EventSetOrNode: @@ -2895,6 +2927,7 @@ def log(self: EventSetOrNode) -> EventSetOrNode: return log(self) + def moving_count( self: EventSetOrNode, window_length: WindowLength, diff --git a/temporian/core/operators/unary.py b/temporian/core/operators/unary.py index bd3313c56..604db18f1 100644 --- a/temporian/core/operators/unary.py +++ b/temporian/core/operators/unary.py @@ -182,11 +182,30 @@ def get_output_dtype(cls, feature_dtype: DType) -> DType: return feature_dtype +class RoundOperator(BaseUnaryOperator): + @classmethod + def op_key_definition(cls) -> str: + return "ROUND" + + @classmethod + def allowed_dtypes(cls) -> List[DType]: + return [ + DType.INT32, + DType.INT64, + ] + + @classmethod + def get_output_dtype(cls, feature_dtype: DType) -> DType: + return feature_dtype + + operator_lib.register_operator(InvertOperator) operator_lib.register_operator(IsNanOperator) operator_lib.register_operator(NotNanOperator) operator_lib.register_operator(AbsOperator) operator_lib.register_operator(LogOperator) +operator_lib.register_operator(RoundOperator) + @compile @@ -242,3 +261,14 @@ def log( return LogOperator( input=input, ).outputs["output"] + + +@compile +def round( + input: EventSetOrNode, +) -> EventSetOrNode: + assert isinstance(input, EventSetNode) + + return RoundOperator( + input=input, + ).outputs["output"] diff --git a/temporian/implementation/numpy/operators/unary.py b/temporian/implementation/numpy/operators/unary.py index 1624da3f7..4a6d85918 100644 --- a/temporian/implementation/numpy/operators/unary.py +++ b/temporian/implementation/numpy/operators/unary.py @@ -10,6 +10,7 @@ NotNanOperator, IsNanOperator, LogOperator, + RoundOperator, ) from temporian.implementation.numpy import implementation_lib from temporian.implementation.numpy.data.event_set import IndexData @@ -77,6 +78,11 @@ def _do_operation(self, feature: np.ndarray) -> np.ndarray: return np.log(feature) +class RoundNumpyImplementation(BaseUnaryNumpyImplementation): + def _do_operation(self, feature: np.ndarray) -> np.ndarray: + return np.round(feature) + + implementation_lib.register_operator_implementation( AbsOperator, AbsNumpyImplementation ) @@ -92,3 +98,6 @@ def _do_operation(self, feature: np.ndarray) -> np.ndarray: implementation_lib.register_operator_implementation( LogOperator, LogNumpyImplementation ) +implementation_lib.register_operator_implementation( + RoundOperator, RoundNumpyImplementation +) From b64b22404844e22249ba082fbf7788baf411f615 Mon Sep 17 00:00:00 2001 From: VidhyaVarshanyJS Date: Sat, 3 Feb 2024 15:22:14 +0530 Subject: [PATCH 2/3] added test cases for round in test_unary.py --- temporian/core/event_set_ops.py | 3 +- temporian/core/operators/test/test_unary.py | 47 +++++++++++++++++++++ temporian/core/operators/unary.py | 3 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/temporian/core/event_set_ops.py b/temporian/core/event_set_ops.py index e5f9370fd..49b5536a6 100644 --- a/temporian/core/event_set_ops.py +++ b/temporian/core/event_set_ops.py @@ -1505,7 +1505,7 @@ def __round__(self): from temporian.core.operators.unary import round return round(input=self) - + def round( self: EventSetOrNode, ) -> EventSetOrNode: @@ -2927,7 +2927,6 @@ def log(self: EventSetOrNode) -> EventSetOrNode: return log(self) - def moving_count( self: EventSetOrNode, window_length: WindowLength, diff --git a/temporian/core/operators/test/test_unary.py b/temporian/core/operators/test/test_unary.py index 2f81a46c9..9cf3183ff 100644 --- a/temporian/core/operators/test/test_unary.py +++ b/temporian/core/operators/test/test_unary.py @@ -99,6 +99,53 @@ def test_correct_notnan(self) -> None: ) assertOperatorResult(self, evset.notnan(), expected) + def test_round_single_feature(self): + evset = event_set( + timestamps=[1, 2, 3], + features={"f": [1.1, -2.5, -3.9]}, + ) + expected = event_set( + timestamps=[1, 2, 3], + features={"f": [1.0, -3.0, -4.0]}, + same_sampling_as=evset, + ) + assertOperatorResult(self, evset.round(), expected) + assertOperatorResult(self, round(evset), expected) # __round__ magic + + def test_round_multiple_features(self): + evset = event_set( + timestamps=[1, 2], + features={"a": [10.5, 11.7], "b": [1.2, 2.9]}, + ) + expected = event_set( + timestamps=[1, 2], + features={"a": [11, 12], "b": [1, 3]}, + same_sampling_as=evset, + ) + assertOperatorResult(self, evset.round(), expected) + assertOperatorResult(self, round(evset), expected) # __round__ magic + + def test_round_non_accepted_types(self): + evset = event_set( + timestamps=[1, 2], + features={"a": ["10.5", 11.7], "b": [1, 2]}, + ) + with self.assertRaises(TypeError): + _ = evset + + def test_round_float32_and_float64_features(self): + evset = event_set( + timestamps=[1, 2], + features={"a": [10.5, 11.7], "b": [1.2, 2.9]}, + ) + expected = event_set( + timestamps=[1, 2], + features={"a": [11.0, 12.0], "b": [1.0, 3.0]}, + same_sampling_as=evset, + ) + assertOperatorResult(self, evset.round(), expected) + assertOperatorResult(self, round(evset), expected) # __round__ magic + if __name__ == "__main__": absltest.main() diff --git a/temporian/core/operators/unary.py b/temporian/core/operators/unary.py index 604db18f1..385987958 100644 --- a/temporian/core/operators/unary.py +++ b/temporian/core/operators/unary.py @@ -190,6 +190,8 @@ def op_key_definition(cls) -> str: @classmethod def allowed_dtypes(cls) -> List[DType]: return [ + DType.FLOAT32, + DType.FLOAT64, DType.INT32, DType.INT64, ] @@ -207,7 +209,6 @@ def get_output_dtype(cls, feature_dtype: DType) -> DType: operator_lib.register_operator(RoundOperator) - @compile def invert( input: EventSetOrNode, From 94ab0606bed11d82182d2ab2e90b5ac6c0ac733d Mon Sep 17 00:00:00 2001 From: VidhyaVarshanyJS Date: Mon, 26 Feb 2024 23:00:06 +0530 Subject: [PATCH 3/3] made changes in few files --- docs/src/reference/index.md | 3 ++- .../temporian/operators/unary/round.md | 1 + temporian/core/event_set_ops.py | 2 +- temporian/core/operators/test/test_unary.py | 18 +++++++++++++++--- temporian/core/operators/unary.py | 2 -- 5 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 docs/src/reference/temporian/operators/unary/round.md diff --git a/docs/src/reference/index.md b/docs/src/reference/index.md index 2dfc04575..38d7a464d 100644 --- a/docs/src/reference/index.md +++ b/docs/src/reference/index.md @@ -42,7 +42,7 @@ Check the index on the left for a more detailed description of any symbol. | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | [`tp.combine()`][temporian.combine] | Combines events from [`EventSets`][temporian.EventSet] with different samplings. | | [`tp.glue()`][temporian.glue] | Concatenates features from [`EventSets`][temporian.EventSet] with the same sampling. | -| [`EventSet.abs()`][temporian.EventSet.abs] | Computes the absolute value of the features. | +| [`EventSet.abs()`][temporian.EventSet.abs] | Computes the absolute value of the features. | [`EventSet.add_index()`][temporian.EventSet.add_index] | Adds indexes to an [`EventSet`][temporian.EventSet]. | | [`EventSet.begin()`][temporian.EventSet.begin] | Generates a single timestamp at the beginning of the input. | | [`EventSet.cast()`][temporian.EventSet.cast] | Casts the dtype of features. | @@ -64,6 +64,7 @@ Check the index on the left for a more detailed description of any symbol. | [`EventSet.propagate()`][temporian.EventSet.propagate] | Propagates feature values over a sub index. | | [`EventSet.rename()`][temporian.EventSet.rename] | Renames an [`EventSet`][temporian.EventSet]'s features and index. | | [`EventSet.resample()`][temporian.EventSet.resample] | Resamples an [`EventSet`][temporian.EventSet] at each timestamp of another [`EventSet`][temporian.EventSet]. | +| [`EventSet.round()`][temporian.EventSet.round] | Computes the round value of the features. | | [`EventSet.select()`][temporian.EventSet.select] | Selects a subset of features from an [`EventSet`][temporian.EventSet]. | | [`EventSet.select_index_values()`][temporian.EventSet.select_index_values] | Selects a subset of index values from an [`EventSet`][temporian.EventSet]. | | [`EventSet.set_index()`][temporian.EventSet.set_index] | Replaces the indexes in an [`EventSet`][temporian.EventSet]. | diff --git a/docs/src/reference/temporian/operators/unary/round.md b/docs/src/reference/temporian/operators/unary/round.md new file mode 100644 index 000000000..fc0758981 --- /dev/null +++ b/docs/src/reference/temporian/operators/unary/round.md @@ -0,0 +1 @@ +::: temporian.EventSet.round \ No newline at end of file diff --git a/temporian/core/event_set_ops.py b/temporian/core/event_set_ops.py index 49b5536a6..6f0145ca4 100644 --- a/temporian/core/event_set_ops.py +++ b/temporian/core/event_set_ops.py @@ -1510,7 +1510,7 @@ def round( self: EventSetOrNode, ) -> EventSetOrNode: """Rounds the values of an [`EventSet`][temporian.EventSet]'s features to the nearest integer. - +only float types are allowed and the output. Output type wil be same as the input type Example: ```python >>> a = tp.event_set( diff --git a/temporian/core/operators/test/test_unary.py b/temporian/core/operators/test/test_unary.py index 9cf3183ff..3ad780c5a 100644 --- a/temporian/core/operators/test/test_unary.py +++ b/temporian/core/operators/test/test_unary.py @@ -119,7 +119,7 @@ def test_round_multiple_features(self): ) expected = event_set( timestamps=[1, 2], - features={"a": [11, 12], "b": [1, 3]}, + features={"a": [11.0, 12.0], "b": [1.0, 3.0]}, same_sampling_as=evset, ) assertOperatorResult(self, evset.round(), expected) @@ -131,9 +131,9 @@ def test_round_non_accepted_types(self): features={"a": ["10.5", 11.7], "b": [1, 2]}, ) with self.assertRaises(TypeError): - _ = evset + _ = evset.round() - def test_round_float32_and_float64_features(self): + def test_round_float32(self): evset = event_set( timestamps=[1, 2], features={"a": [10.5, 11.7], "b": [1.2, 2.9]}, @@ -146,6 +146,18 @@ def test_round_float32_and_float64_features(self): assertOperatorResult(self, evset.round(), expected) assertOperatorResult(self, round(evset), expected) # __round__ magic + def test_round_float64(self): + evset = event_set( + timestamps=[1, 2], + features={"a": [10.5, 11.7], "b": [1.2, 2.9]}, + ) + expected = event_set( + timestamps=[1, 2], + features={"a": [11.0, 12.0], "b": [1.0, 3.0]}, + same_sampling_as=evset, + ) + assertOperatorResult(self, evset.round(), expected) + assertOperatorResult(self, round(evset), expected) # __round__ magic if __name__ == "__main__": absltest.main() diff --git a/temporian/core/operators/unary.py b/temporian/core/operators/unary.py index 385987958..fbd3a15ac 100644 --- a/temporian/core/operators/unary.py +++ b/temporian/core/operators/unary.py @@ -192,8 +192,6 @@ def allowed_dtypes(cls) -> List[DType]: return [ DType.FLOAT32, DType.FLOAT64, - DType.INT32, - DType.INT64, ] @classmethod