def _filter_input(
    self,
    noteTopics: pd.DataFrame,
    ratings: pd.DataFrame,
    noteStatusHistory: pd.DataFrame,
    userEnrollment: pd.DataFrame,
  ) -> Tuple[pd.DataFrame, pd.DataFrame]:
    """Prune the contents of ratings and noteStatusHistory to scope model behavior.

    Args:
      ratings (pd.DataFrame): preprocessed ratings
      noteStatusHistory (pd.DataFrame): one row per note; history of when note had each status
      userEnrollment (pd.DataFrame): one row per user specifying enrollment properties

    Returns:
      Tuple[pd.DataFrame, pd.DataFrame]:
        ratings: ratings filtered to only contain rows of interest
        noteStatusHistory: noteStatusHistory filtered to only contain rows of interest
    """
    if (not self._includedGroups) and (not self._includedTopics):
      return ratings, noteStatusHistory
    logger.info(f"Filtering ratings for {self.get_name()}.  Original rating length: {len(ratings)}")
    # Apply topic filter for topic models
    if self._includedTopics:
      notes = noteTopics[noteTopics[c.noteTopicKey].isin(self._includedTopics)][[c.noteIdKey]]
      ratings = ratings.merge(notes)
      noteStatusHistory = noteStatusHistory.merge(notes)
    if self._excludeTopics:
      ratings = ratings[~ratings[c.noteIdKey].isin(noteTopics[c.noteIdKey])]
      noteStatusHistory = noteStatusHistory[
        ~noteStatusHistory[c.noteIdKey].isin(noteTopics[c.noteIdKey])
      ]
    logger.info(f"  Ratings after topic filter: {len(ratings)}")
    # Apply group filter
    if self._includedGroups:
      userEnrollment = userEnrollment[[c.participantIdKey, c.modelingGroupKey]].rename(
        columns={c.participantIdKey: c.raterParticipantIdKey}
      )
      userEnrollment.loc[:, _IN_GROUP] = (
        userEnrollment[c.modelingGroupKey].isin(self._includedGroups).astype(pd.BooleanDtype())
      )
      ratings = ratings.merge(
        userEnrollment[[c.raterParticipantIdKey, _IN_GROUP]], on=c.raterParticipantIdKey, how="left"
      )
      logger.info(f"  Ratings without assigned group: {ratings[_IN_GROUP].isna().sum()}")

      ratings = ratings.fillna({_IN_GROUP: self._includeUnassigned})
      if self._strictInclusion:
        print("Excluding ratings outside of group")
        ratios = ratings[[c.noteIdKey, _IN_GROUP]].groupby(c.noteIdKey).mean().reset_index()
        ratings = ratings.merge(ratios[ratios[_IN_GROUP] >= self._captureThreshold][[c.noteIdKey]])
      ratings = ratings.fillna({_IN_GROUP: self._includeUnassigned})
      ratings = ratings[ratings[_IN_GROUP]].drop(columns=[_IN_GROUP])
    logger.info(f"  Ratings after group filter: {len(ratings)}")
    return ratings, noteStatusHistory
Prune the contents of ratings and noteStatusHistory to scope model behavior.

    Args:
      ratings (pd.DataFrame): preprocessed ratings
      noteStatusHistory (pd.DataFrame): one row per note; history of when note had each status
      userEnrollment (pd.DataFrame): one row per user specifying enrollment properties

    Returns:
      Tuple[pd.DataFrame, pd.DataFrame]:
        ratings: ratings filtered to only contain rows of interest
        noteStatusHistory: noteStatusHistory filtered to only contain rows of interest
    
sourcecode/scoring/scorer.py