class_docstr: A class to implement change point detection.
  
  Currently supports long-term change point detection only. Input is a dataframe with time_col
  indicating the column of time info (the format should be able to be parsed by pd.to_datetime),
  and value_col indicating the column of observed time series values.
  
  Attributes
  ----------
  original_df : `pandas.DataFrame`
      The original data df, used to retrieve original observations, if aggregation is used in
      fitting change points.
  time_col : `str`
      The column name for time column.
  value_col : `str`
      The column name for value column.
  trend_potential_changepoint_n: `int`
      The number of change points that are evenly distributed over the time period.
  yearly_seasonality_order : `int`
      The yearly seasonality order used when fitting trend.
  y : `pandas.Series`
      The observations after aggregation.
  trend_df : `pandas.DataFrame`
      The augmented df of the original_df, including regressors of trend change points and
      Fourier series for yearly seasonality.
  trend_model : `sklearn.base.RegressionMixin`
      The fitted trend model.
  trend_coef : `numpy.array`
      The estimated trend coefficients.
  trend_intercept : `float`
      The estimated trend intercept.
  adaptive_lasso_coef : `list`
      The list of length two, first element is estimated trend coefficients, and second element
      is intercept, both estimated by adaptive lasso.
  trend_changepoints : `list`
      The list of detected trend change points, parsable by pd.to_datetime
  trend_estimation : `pd.Series`
      The estimated trend with detected trend change points.
  seasonality_df : `pandas.DataFrame`
      The augmented df of ``original_df``, including regressors of seasonality change points with
      different Fourier series frequencies.
  seasonality_changepoints : `dict`
      The dictionary of detected seasonality change points for each component.
      Keys are component names, and values are list of change points.
  seasonality_estimation : `pandas.Series`
      The estimated seasonality with detected seasonality change points.
      The series has the same length as ``original_df``. Index is timestamp, and values
      are the estimated seasonality at each timestamp.
      The seasonality estimation is the estimated of seasonality effect with trend estimated
      by `~greykite.algo.changepoint.adalasso.changepoints_utils.estimate_trend_with_detected_changepoints`
      removed.
  
  Methods
  -------
  find_trend_changepoints : callable
      Finds the potential trend change points for a given time series df.
  plot : callable
      Plot the results after implementing find_trend_changepoints.
docstr: Finds the seasonality change points (defined as the time points where seasonality
  magnitude changes, i.e., the time series becomes "fatter" or "thinner".)
  
  Subtracts the estimated trend from the original time series first,
  then uses regression-based regularization methods to select important seasonality
  change points. Regressors are built from truncated Fourier series.
  
  If you have run ``find_trend_changepoints`` before running ``find_seasonality_changepoints``
  with the same df, the estimated trend will be automatically used for removing trend in
  ``find_seasonality_changepoints``.
  Otherwise, ``find_trend_changepoints`` will be run automatically with the same parameters
  as you passed to ``find_seasonality_changepoints``. If you do not want to use the same
  parameters, run ``find_trend_changepoints`` with your desired parameter before calling
  ``find_seasonality_changepoints``.
  
  The algorithm does an aggregation with a user-defined frequency, default hourly.
  
  The regression features consists of ``potential_changepoint_n`` + 1 blocks of
  predictors. The first block consists of Fourier series according to
  ``seasonality_components_df``, and other blocks are a copy of the first block
  truncated at the corresponding potential change point.
  
  If ``potential_changepoint_distance`` is not given,  ``potential_changepoint_n``
  potential change points are evenly distributed over the time period, else
  ``potential_changepoint_n`` is overridden by::
  
          total_time_length / ``potential_changepoint_distance``
  
  Users can specify either ``no_changepoint_proportion_from_end`` to specify what proportion
  from the end of data they do not want changepoints, or ``no_changepoint_distance_from_end``
  (overrides ``no_changepoint_proportion_from_end``) to specify how long from the end they
  do not want change points.
  
  Then all potential change points will be selected by adaptive lasso, with the initial
  estimator specified by ``adaptive_lasso_initial_estimator``. The regularization strength
  is specified by ``regularization_strength``, which lies between 0 and 1.
  
  A rule-based guard function is applied at the end to ensure change points are not
  too close, as specified by ``actual_changepoint_min_distance``.
  
  Parameters
  ----------
  df: `pandas.DataFrame`
      The data df
  time_col : `str`
      Time column name in ``df``
  value_col : `str`
      Value column name in ``df``
  seasonality_components_df : `pandas.DataFrame`
      The df to generate seasonality design matrix, which is compatible with
      ``seasonality_components_df`` in
      `~greykite.algo.changepoint.adalasso.changepoint_detector.ChangepointDetector.find_seasonality_changepoints`
  resample_freq : `DateOffset, Timedelta or str`, default "H".
      The frequency to aggregate data.
      Coarser aggregation leads to fitting longer term trends.
  regularization_strength : `float` in [0, 1] or `None`, default 0.6.
      The regularization for change points. Greater value implies fewer change points.
      0 indicates all change points, and 1 indicates no change point.
      If `None`, the turning parameter will be selected by cross-validation.
      If a value is given, it will be used as the tuning parameter.
      Here "None" is not recommended, because seasonality change has different levels,
      and automatic selection by cross-validation may produce more change points than
      desired. Practically, 0.6 is a good choice for most cases. Tuning around
      0.6 is recommended.
  actual_changepoint_min_distance : `DateOffset`, `Timedelta` or `str`, default "30D"
      The minimal distance allowed between detected change points. If consecutive change points
      are within this minimal distance, the one with smaller absolute change coefficient will
      be dropped.
      Note: maximal unit is 'D', i.e., you may use units no more than 'D' such as
      '10D', '5H', '100T', '200S'. The reason is that 'W', 'M' or higher has either
      cycles or indefinite number of days, thus is not parsable by pandas as timedelta.
  potential_changepoint_distance : `DateOffset`, `Timedelta`, `str` or None, default None
      The distance between potential change points.
      If provided, will override the parameter ``potential_changepoint_n``.
      Note: maximal unit is 'D', i.e., you may only use units no more than 'D' such as
      '10D', '5H', '100T', '200S'. The reason is that 'W', 'M' or higher has either
      cycles or indefinite number of days, thus is not parsable by pandas as timedelta.
  potential_changepoint_n : `int`, default 50
      Number of change points to be evenly distributed, recommended 1 per month, based
      on the training data length.
  no_changepoint_distance_from_end : `DateOffset`, `Timedelta`, `str` or None, default None
      The length of time from the end of training data, within which no change point will be placed.
      If provided, will override the parameter ``no_changepoint_proportion_from_end``.
      Note: maximal unit is 'D', i.e., you may only use units no more than 'D' such as
      '10D', '5H', '100T', '200S'. The reason is that 'W', 'M' or higher has either
      cycles or indefinite number of days, thus is not parsable by pandas as timedelta.
  no_changepoint_proportion_from_end : `float` in [0, 1], default 0.0.
      ``potential_changepoint_n`` change points will be placed evenly over the whole training period,
      however, only change points that are not located within the last ``no_changepoint_proportion_from_end``
      proportion of training period will be used for change point detection.
  trend_changepoints : `list` or None
      A list of user specified trend change points, used to estimated the trend to be removed
      from the time series before detecting seasonality change points. If provided, the algorithm
      will not check existence of detected trend change points or run ``find_trend_changepoints``,
      but will use these change points directly for trend estimation.
  
  Return
  ------
  result : `dict`
      result dictionary with keys:
  
      ``"seasonality_feature_df"`` : `pandas.DataFrame`
          The augmented df for seasonality changepoint detection, in other words, the design matrix for
          the regression model. Columns:
  
              - "cos1_tod_daily": cosine daily seasonality regressor of first order at change point 0.
              - "sin1_tod_daily": sine daily seasonality regressor of first order at change point 0.
              - ...
              - "cos1_conti_year_yearly": cosine yearly seasonality regressor of first order at
                change point 0.
              - "sin1_conti_year_yearly": sine yearly seasonality regressor of first order at
                change point 0.
              - ...
              - "cos{daily_seasonality_order}_tod_daily_cp{potential_changepoint_n}" : cosine
                daily seasonality regressor of {yearly_seasonality_order}th order at change point
                {potential_changepoint_n}.
              - "sin{daily_seasonality_order}_tod_daily_cp{potential_changepoint_n}" : sine
                daily seasonality regressor of {yearly_seasonality_order}th order at change point
                {potential_changepoint_n}.
              - ...
              - "cos{yearly_seasonality_order}_conti_year_yearly_cp{potential_changepoint_n}" : cosine
                yearly seasonality regressor of {yearly_seasonality_order}th order at change point
                {potential_changepoint_n}.
              - "sin{yearly_seasonality_order}_conti_year_yearly_cp{potential_changepoint_n}" : sine
                yearly seasonality regressor of {yearly_seasonality_order}th order at change point
                {potential_changepoint_n}.
  
      ``"seasonality_changepoints"`` : `dict`[`list`[`datetime`]]
          The dictionary of detected seasonality change points for each component.
          Keys are component names, and values are list of change points.
      ``"seasonality_estimation"`` : `pandas.Series`
          The estimated seasonality with detected seasonality change points.
              The series has the same length as ``original_df``. Index is timestamp, and values
              are the estimated seasonality at each timestamp.
              The seasonality estimation is the estimated of seasonality effect with trend estimated
              by `~greykite.algo.changepoint.adalasso.changepoints_utils.estimate_trend_with_detected_changepoints`
              removed.
      ``"seasonality_components_df`` : `pandas.DataFrame`
          The processed ``seasonality_components_df``. Daily component row is removed if
          inferred frequency or aggregation frequency is at least one day.
code: def find_seasonality_changepoints(
      self,
      df,
      time_col,
      value_col,
      seasonality_components_df=pd.DataFrame(
          {
              "name": [
                  TimeFeaturesEnum.tod.value,
                  TimeFeaturesEnum.tow.value,
                  TimeFeaturesEnum.conti_year.value,
              ],
              "period": [24.0, 7.0, 1.0],
              "order": [3, 3, 5],
              "seas_names": ["daily", "weekly", "yearly"],
          }
      ),
      resample_freq="H",
      regularization_strength=0.6,
      actual_changepoint_min_distance="30D",
      potential_changepoint_distance=None,
      potential_changepoint_n=50,
      no_changepoint_distance_from_end=None,
      no_changepoint_proportion_from_end=0.0,
      trend_changepoints=None,
  ):
      """Finds the seasonality change points (defined as the time points where seasonality
      magnitude changes, i.e., the time series becomes "fatter" or "thinner".)
  
      Subtracts the estimated trend from the original time series first,
      then uses regression-based regularization methods to select important seasonality
      change points. Regressors are built from truncated Fourier series.
  
      If you have run ``find_trend_changepoints`` before running ``find_seasonality_changepoints``
      with the same df, the estimated trend will be automatically used for removing trend in
      ``find_seasonality_changepoints``.
      Otherwise, ``find_trend_changepoints`` will be run automatically with the same parameters
      as you passed to ``find_seasonality_changepoints``. If you do not want to use the same
      parameters, run ``find_trend_changepoints`` with your desired parameter before calling
      ``find_seasonality_changepoints``.
  
      The algorithm does an aggregation with a user-defined frequency, default hourly.
  
      The regression features consists of ``potential_changepoint_n`` + 1 blocks of
      predictors. The first block consists of Fourier series according to
      ``seasonality_components_df``, and other blocks are a copy of the first block
      truncated at the corresponding potential change point.
  
      If ``potential_changepoint_distance`` is not given,  ``potential_changepoint_n``
      potential change points are evenly distributed over the time period, else
      ``potential_changepoint_n`` is overridden by::
  
              total_time_length / ``potential_changepoint_distance``
  
      Users can specify either ``no_changepoint_proportion_from_end`` to specify what proportion
      from the end of data they do not want changepoints, or ``no_changepoint_distance_from_end``
      (overrides ``no_changepoint_proportion_from_end``) to specify how long from the end they
      do not want change points.
  
      Then all potential change points will be selected by adaptive lasso, with the initial
      estimator specified by ``adaptive_lasso_initial_estimator``. The regularization strength
      is specified by ``regularization_strength``, which lies between 0 and 1.
  
      A rule-based guard function is applied at the end to ensure change points are not
      too close, as specified by ``actual_changepoint_min_distance``.
  
      Parameters
      ----------
      df: `pandas.DataFrame`
          The data df
      time_col : `str`
          Time column name in ``df``
      value_col : `str`
          Value column name in ``df``
      seasonality_components_df : `pandas.DataFrame`
          The df to generate seasonality design matrix, which is compatible with
          ``seasonality_components_df`` in
          `~greykite.algo.changepoint.adalasso.changepoint_detector.ChangepointDetector.find_seasonality_changepoints`
      resample_freq : `DateOffset, Timedelta or str`, default "H".
          The frequency to aggregate data.
          Coarser aggregation leads to fitting longer term trends.
      regularization_strength : `float` in [0, 1] or `None`, default 0.6.
          The regularization for change points. Greater value implies fewer change points.
          0 indicates all change points, and 1 indicates no change point.
          If `None`, the turning parameter will be selected by cross-validation.
          If a value is given, it will be used as the tuning parameter.
          Here "None" is not recommended, because seasonality change has different levels,
          and automatic selection by cross-validation may produce more change points than
          desired. Practically, 0.6 is a good choice for most cases. Tuning around
          0.6 is recommended.
      actual_changepoint_min_distance : `DateOffset`, `Timedelta` or `str`, default "30D"
          The minimal distance allowed between detected change points. If consecutive change points
          are within this minimal distance, the one with smaller absolute change coefficient will
          be dropped.
          Note: maximal unit is 'D', i.e., you may use units no more than 'D' such as
          '10D', '5H', '100T', '200S'. The reason is that 'W', 'M' or higher has either
          cycles or indefinite number of days, thus is not parsable by pandas as timedelta.
      potential_changepoint_distance : `DateOffset`, `Timedelta`, `str` or None, default None
          The distance between potential change points.
          If provided, will override the parameter ``potential_changepoint_n``.
          Note: maximal unit is 'D', i.e., you may only use units no more than 'D' such as
          '10D', '5H', '100T', '200S'. The reason is that 'W', 'M' or higher has either
          cycles or indefinite number of days, thus is not parsable by pandas as timedelta.
      potential_changepoint_n : `int`, default 50
          Number of change points to be evenly distributed, recommended 1 per month, based
          on the training data length.
      no_changepoint_distance_from_end : `DateOffset`, `Timedelta`, `str` or None, default None
          The length of time from the end of training data, within which no change point will be placed.
          If provided, will override the parameter ``no_changepoint_proportion_from_end``.
          Note: maximal unit is 'D', i.e., you may only use units no more than 'D' such as
          '10D', '5H', '100T', '200S'. The reason is that 'W', 'M' or higher has either
          cycles or indefinite number of days, thus is not parsable by pandas as timedelta.
      no_changepoint_proportion_from_end : `float` in [0, 1], default 0.0.
          ``potential_changepoint_n`` change points will be placed evenly over the whole training period,
          however, only change points that are not located within the last ``no_changepoint_proportion_from_end``
          proportion of training period will be used for change point detection.
      trend_changepoints : `list` or None
          A list of user specified trend change points, used to estimated the trend to be removed
          from the time series before detecting seasonality change points. If provided, the algorithm
          will not check existence of detected trend change points or run ``find_trend_changepoints``,
          but will use these change points directly for trend estimation.
  
      Return
      ------
      result : `dict`
          result dictionary with keys:
  
          ``"seasonality_feature_df"`` : `pandas.DataFrame`
              The augmented df for seasonality changepoint detection, in other words, the design matrix for
              the regression model. Columns:
  
                  - "cos1_tod_daily": cosine daily seasonality regressor of first order at change point 0.
                  - "sin1_tod_daily": sine daily seasonality regressor of first order at change point 0.
                  - ...
                  - "cos1_conti_year_yearly": cosine yearly seasonality regressor of first order at
                    change point 0.
                  - "sin1_conti_year_yearly": sine yearly seasonality regressor of first order at
                    change point 0.
                  - ...
                  - "cos{daily_seasonality_order}_tod_daily_cp{potential_changepoint_n}" : cosine
                    daily seasonality regressor of {yearly_seasonality_order}th order at change point
                    {potential_changepoint_n}.
                  - "sin{daily_seasonality_order}_tod_daily_cp{potential_changepoint_n}" : sine
                    daily seasonality regressor of {yearly_seasonality_order}th order at change point
                    {potential_changepoint_n}.
                  - ...
                  - "cos{yearly_seasonality_order}_conti_year_yearly_cp{potential_changepoint_n}" : cosine
                    yearly seasonality regressor of {yearly_seasonality_order}th order at change point
                    {potential_changepoint_n}.
                  - "sin{yearly_seasonality_order}_conti_year_yearly_cp{potential_changepoint_n}" : sine
                    yearly seasonality regressor of {yearly_seasonality_order}th order at change point
                    {potential_changepoint_n}.
  
          ``"seasonality_changepoints"`` : `dict`[`list`[`datetime`]]
              The dictionary of detected seasonality change points for each component.
              Keys are component names, and values are list of change points.
          ``"seasonality_estimation"`` : `pandas.Series`
              The estimated seasonality with detected seasonality change points.
                  The series has the same length as ``original_df``. Index is timestamp, and values
                  are the estimated seasonality at each timestamp.
                  The seasonality estimation is the estimated of seasonality effect with trend estimated
                  by `~greykite.algo.changepoint.adalasso.changepoints_utils.estimate_trend_with_detected_changepoints`
                  removed.
          ``"seasonality_components_df`` : `pandas.DataFrame`
              The processed ``seasonality_components_df``. Daily component row is removed if
              inferred frequency or aggregation frequency is at least one day.
      """
      # Checks parameter rationality.
      if potential_changepoint_n < 0:
          raise ValueError(
              "potential_changepoint_n can not be negative. "
              "A large number such as 50 is recommended"
          )
      if df.dropna().shape[0] < 5:
          raise ValueError(
              "Change point detector does not work for less than "
              "5 observations. Please increase sample size."
          )
      if (
          no_changepoint_proportion_from_end < 0
          or no_changepoint_proportion_from_end > 1
      ):
          raise ValueError(
              "``no_changepoint_proportion_from_end`` needs to be between 0 and 1."
          )
      if no_changepoint_distance_from_end is not None:
          check_freq_unit_at_most_day(
              no_changepoint_distance_from_end,
              "no_changepoint_distance_from_end",
          )
          data_length = pd.to_datetime(
              df[time_col].iloc[-1]
          ) - pd.to_datetime(df[time_col].iloc[0])
          no_changepoint_proportion_from_end = (
              to_offset(no_changepoint_distance_from_end).delta
              / data_length
          )
      if potential_changepoint_distance is not None:
          check_freq_unit_at_most_day(
              potential_changepoint_distance,
              "potential_changepoint_distance",
          )
          data_length = pd.to_datetime(
              df[time_col].iloc[-1]
          ) - pd.to_datetime(df[time_col].iloc[0])
          potential_changepoint_n = (
              data_length
              // to_offset(potential_changepoint_distance).delta
          )
      if regularization_strength is None:
          warnings.warn(
              "regularization_strength is set to None. This will trigger cross-validation to "
              "select the tuning parameter which might result in too many change points. "
              "Keep the default value or tuning around it is recommended."
          )
      if regularization_strength is not None and (
          regularization_strength < 0 or regularization_strength > 1
      ):
          raise ValueError(
              "regularization_strength must be between 0.0 and 1.0."
          )
      df[time_col] = pd.to_datetime(df[time_col])
      # If user provides a list of trend change points, these points will be used to estimate trend.
      if trend_changepoints is not None:
          trend_estimation = estimate_trend_with_detected_changepoints(
              df=df,
              time_col=time_col,
              value_col=value_col,
              changepoints=trend_changepoints,
          )
          self.trend_changepoints = trend_changepoints
          self.trend_estimation = trend_estimation
          self.original_df = df
          self.time_col = time_col
          self.value_col = value_col
          self.y = df[value_col]
          self.y.index = df[time_col]
      # If user doesn't provide trend change points, the trend change points will be found automatically.
      else:
          # Checks if trend change point is available.
          # Runs trend change point detection with default value if not.
          compare_df = df.copy()
          if time_col != self.time_col or value_col != self.value_col:
              compare_df.rename(
                  {time_col: self.time_col, value_col: self.value_col},
                  axis=1,
                  inplace=True,
              )
          if (
              self.original_df is not None
              and self.original_df[
                  [self.time_col, self.value_col]
              ].equals(compare_df[[self.time_col, self.value_col]])
              and self.trend_estimation is not None
          ):
              # If the passed df is the same as ``self.original_df``, then the previous
              # ``self.trend_estimation`` is to be subtracted from the time series.
              trend_estimation = self.trend_estimation
              warnings.warn(
                  "Trend changepoints are already identified, using past trend estimation. "
                  "If you would like to run trend change point detection again, "
                  "please call ``find_trend_changepoints`` with desired parameters "
                  "before calling ``find_seasonality_changepoints``."
              )
          else:
              # If the passed df is different from ``self.original_df``, then trend change point
              # detection algorithm is run first, and trend estimation is calculated afterward.
              # In this case, the parameters passed to ``find_seasonality_changepoints`` are also
              # passed to ``find_trend_changepoint``.
              # If you do not want the parameters passed, run ``find_trend_changepoints`` with
              # desired parameters before calling ``find_seasonality_changepoints``.
              trend_result = self.find_trend_changepoints(
                  df=df,
                  time_col=time_col,
                  value_col=value_col,
                  actual_changepoint_min_distance=actual_changepoint_min_distance,
                  no_changepoint_distance_from_end=no_changepoint_distance_from_end,
                  no_changepoint_proportion_from_end=no_changepoint_proportion_from_end,
              )
              warnings.warn(
                  f"Trend changepoints are not identified for the input dataframe, "
                  f"triggering trend change point detection with parameters"
                  f"actual_changepoint_min_distance={actual_changepoint_min_distance}\n"
                  f"no_changepoint_proportion_from_end={no_changepoint_proportion_from_end}\n"
                  f"no_changepoint_distance_from_end={no_changepoint_distance_from_end}\n"
                  f" Found trend change points\n{self.trend_changepoints}\n"
                  "If you would like to run trend change point detection with customized "
                  "parameters, please call ``find_trend_changepoints`` with desired parameters "
                  "before calling ``find_seasonality_changepoints``."
              )
              trend_estimation = trend_result["trend_estimation"]
      # Splits trend effects from time series.
      df_without_trend = df.copy()
      df_without_trend[value_col] -= trend_estimation.values
      # Aggregates df.
      df_resample = (
          df_without_trend.resample(resample_freq, on=time_col)
          .mean()
          .reset_index()
      )
      df_resample = df_resample.dropna()
      # Removes daily component from seasonality_components_df if data has minimum freq daily.
      freq_at_least_day = min(
          np.diff(df_resample[time_col]).astype("timedelta64[s]")
      ) >= timedelta(days=1)
      if (
          freq_at_least_day
          and "daily"
          in seasonality_components_df["seas_names"].tolist()
      ):
          warnings.warn(
              "Inferred minimum data frequency is at least 1 day, daily component is "
              "removed from seasonality_components_df."
          )
          seasonality_components_df = seasonality_components_df.loc[
              seasonality_components_df["seas_names"] != "daily"
          ]
      # Builds seasonality feature df.
      seasonality_df = build_seasonality_feature_df_with_changes(
          df=df_resample,
          time_col=time_col,
          fs_components_df=seasonality_components_df,
          changepoints_dict={
              "method": "uniform",
              "n_changepoints": potential_changepoint_n,
          },
      )
      # Eliminates change points from the end
      # the generated seasonality_df has {``potential_changepoint_n`` + 1} blocks, where there
      # are {sum_i(order of component i) * 2} columns consisting of the cosine and sine functions
      # for each order for each component.
      # The selection below selects the first {``n_changepoints_within_range`` + 1} columns,
      # which corresponds to the regular block (first block) and the blocks that correspond
      # to the change points that are within range.
      n_changepoints_within_range = int(
          potential_changepoint_n
          * (1 - no_changepoint_proportion_from_end)
      )
      orders = seasonality_components_df["order"].tolist()
      seasonality_df = seasonality_df.iloc[
          :, : (n_changepoints_within_range + 1) * sum(orders) * 2
      ]
      self.seasonality_df = seasonality_df
      # Fetches change point dates for reference as datetime format.
      changepoint_dates = get_evenly_spaced_changepoints_dates(
          df=df,
          time_col=time_col,
          n_changepoints=potential_changepoint_n,
      )
      # Gets the changepoint dates that are not within ``no_changepoint_proportion_from_end``.
      changepoint_dates = changepoint_dates.iloc[
          0 : n_changepoints_within_range + 1
      ]
      # Calculates the minimal allowed change point index distance.
      min_changepoint_index_distance = compute_min_changepoint_index_distance(
          df=df_resample,
          time_col=time_col,
          n_changepoints=potential_changepoint_n,
          min_distance_between_changepoints=actual_changepoint_min_distance,
      )
      seasonality_changepoints = (
          get_seasonality_changes_from_adaptive_lasso(
              x=seasonality_df.values,
              y=df_resample[value_col].values,
              changepoint_dates=changepoint_dates,
              initial_coef="lasso",
              seasonality_components_df=seasonality_components_df,
              min_index_distance=min_changepoint_index_distance,
              regularization_strength=regularization_strength,
          )
      )
      # Checks if the beginning date is picked as a change point. If yes, drop it, because we
      # always include the overall seasonality term in our model.
      for key in seasonality_changepoints.keys():
          if df_resample[time_col][0] in seasonality_changepoints[key]:
              seasonality_changepoints[key] = seasonality_changepoints[
                  key
              ][1:]
      self.seasonality_changepoints = seasonality_changepoints
      # logging
      log_message(
          f"The detected seasonality changepoints are\n"
          f"{pprint(seasonality_changepoints)}",
          LoggingLevelEnum.INFO,
      )
      # Performs a seasonality estimation for plotting purposes.
      seasonality_estimation = (
          estimate_seasonality_with_detected_changepoints(
              df=df_without_trend,
              time_col=time_col,
              value_col=value_col,
              seasonality_changepoints=seasonality_changepoints,
              seasonality_components_df=seasonality_components_df,
          )
      )
      self.seasonality_estimation = seasonality_estimation
      result = {
          "seasonality_feature_df": seasonality_df,
          "seasonality_changepoints": seasonality_changepoints,
          "seasonality_estimation": seasonality_estimation,
          "seasonality_components_df": seasonality_components_df,
      }
      return result
  
imports: import warnings
  from datetime import timedelta
  from typing import List
  from typing import Optional
  import numpy
  import pandas
  from pandas.tseries.frequencies import to_offset
  from sklearn.base import RegressorMixin
  from sklearn.exceptions import ConvergenceWarning
  from sklearn.linear_model import LassoCV
  from sklearn.linear_model import LinearRegression
  from sklearn.linear_model import RidgeCV
  from greykite.algo.changepoint.adalasso.changepoints_utils import build_seasonality_feature_df_with_changes
  from greykite.algo.changepoint.adalasso.changepoints_utils import build_trend_feature_df_with_changes
  from greykite.algo.changepoint.adalasso.changepoints_utils import check_freq_unit_at_most_day
  from greykite.algo.changepoint.adalasso.changepoints_utils import combine_detected_and_custom_trend_changepoints
  from greykite.algo.changepoint.adalasso.changepoints_utils import compute_fitted_components
  from greykite.algo.changepoint.adalasso.changepoints_utils import compute_min_changepoint_index_distance
  from greykite.algo.changepoint.adalasso.changepoints_utils import estimate_seasonality_with_detected_changepoints
  from greykite.algo.changepoint.adalasso.changepoints_utils import estimate_trend_with_detected_changepoints
  from greykite.algo.changepoint.adalasso.changepoints_utils import get_changepoint_dates_from_changepoints_dict
  from greykite.algo.changepoint.adalasso.changepoints_utils import get_seasonality_changes_from_adaptive_lasso
  from greykite.algo.changepoint.adalasso.changepoints_utils import get_trend_changes_from_adaptive_lasso
  from greykite.algo.changepoint.adalasso.changepoints_utils import get_yearly_seasonality_changepoint_dates_from_freq
  from greykite.algo.changepoint.adalasso.changepoints_utils import plot_change
  from greykite.algo.changepoint.shift_detection.shift_detector import ShiftDetection
  from greykite.common.constants import TimeFeaturesEnum
  from greykite.common.features.timeseries_features import get_evenly_spaced_changepoints_dates
  from greykite.common.logging import LoggingLevelEnum
  from greykite.common.logging import log_message
  from greykite.common.logging import pprint
  from greykite.common.python_utils import ignore_warnings
label_desc: Use image node_id 3 for calling the ChangepointDetector obj's underlying member method code with example usage: obj.find_seasonality_changepoints(df, time_col, value_col, seasonality_components_df, resample_freq, regularization_strength, actual_changepoint_min_distance, potential_changepoint_distance, potential_changepoint_n, no_changepoint_distance_from_end, no_changepoint_proportion_from_end, trend_changepoints) and returns: result