diff --git a/docs/source/_static/logo-no-text.png b/docs/source/_static/logo_no_text.png similarity index 100% rename from docs/source/_static/logo-no-text.png rename to docs/source/_static/logo_no_text.png diff --git a/streamsight/matrix/interaction_matrix.py b/streamsight/matrix/interaction_matrix.py index 99eeb21..2977826 100644 --- a/streamsight/matrix/interaction_matrix.py +++ b/streamsight/matrix/interaction_matrix.py @@ -457,7 +457,7 @@ def __sub__(self, im: "InteractionMatrix") -> "InteractionMatrix": True ) - def __repr__(self): + def __repr__(self) -> str: return repr(self._df) def __eq__(self, value: object) -> bool: @@ -466,6 +466,19 @@ def __eq__(self, value: object) -> bool: return False return self._df.equals(value._df) + def __len__(self) -> int: + """Return the number of interactions in the matrix. + + This is distinct from the shape of the matrix, which is the number of + users and items that has been released to the model. The length of the + matrix is the number of interactions present in the matrix resulting + from filter operations. + + :return: Number of interactions in the matrix. + :rtype: int + """ + return len(self._df) + @overload def items_in(self, I: Set[int], inplace=False) -> "InteractionMatrix": ... @overload diff --git a/streamsight/settings/base.py b/streamsight/settings/base.py index 4591674..83677d7 100644 --- a/streamsight/settings/base.py +++ b/streamsight/settings/base.py @@ -132,6 +132,7 @@ def split(self, data: InteractionMatrix) -> None: self._check_split() self._split_complete = True + logger.info(f"{self.name} data split complete.") def _check_split_complete(self): """Check if the setting is ready to be used for evaluation. diff --git a/streamsight/settings/sliding_window_setting.py b/streamsight/settings/sliding_window_setting.py index b433d5a..b2b4772 100644 --- a/streamsight/settings/sliding_window_setting.py +++ b/streamsight/settings/sliding_window_setting.py @@ -115,6 +115,13 @@ def _split(self, data: InteractionMatrix): past_interaction, future_interaction = self._window_splitter.split( data ) + + # if past_interaction, future_interaction is empty, log an info message + if len(past_interaction) == 0: + logger.info(f"Split at time {sub_time} resulted in empty unlabelled testing samples.") + if len(future_interaction) == 0: + logger.info(f"Split at time {sub_time} resulted in empty incremental data.") + unlabeled_set, ground_truth = self.prediction_data_processor.process(past_interaction, future_interaction, self.top_K)