def transform(self, X):
        """Transform each time series into a bag of words.

        Parameters
        ----------
        X : array-like, shape = (n_samples, n_timestamps)
            Data to transform.

        Returns
        -------
        X_new : array, shape = (n_samples,)
            Bags of words.

        """
        X = check_array(X, dtype='float64')
        n_samples, n_timestamps = X.shape
        window_size, word_size, window_step, alphabet = self._check_params(
            n_timestamps)
        n_windows = (n_timestamps - window_size + window_step) // window_step

        # Standardize time series if quantile from standard normal distribution
        if self.strategy == 'normal':
            X_scaled = StandardScaler().transform(X)
        else:
            X_scaled = X

        # Extract subsequences using a sliding window
        X_window = _windowed_view(
            X_scaled, n_samples, n_timestamps, window_size, window_step
        ).reshape(n_samples * n_windows, window_size)

        if self.threshold_std is not None:

            # Identify subsequences whose standard deviation below threshold
            idx = np.std(X_window, axis=1) < self.threshold_std

            if np.any(idx):
                # Subsequences with standard deviations below threshold
                X_paa = PiecewiseAggregateApproximation(
                    window_size=None, output_size=word_size,
                    overlapping=self.overlapping
                ).transform(X_window[idx])

                # Compute the bin edges
                discretizer = KBinsDiscretizer(
                    n_bins=self.n_bins, strategy=self.strategy,
                    raise_warning=self.raise_warning
                )
                bin_edges = discretizer._compute_bins(
                    X_scaled, n_samples, self.n_bins, self.strategy)

                # Tile the bin edges for subsequences from the same time series
                if self.strategy != 'normal':
                    count = np.bincount(
                        np.floor_divide(np.nonzero(idx)[0], n_windows)
                    )
                    bin_edges = np.vstack([
                        np.tile(bin_edges[i], (count[i], 1))
                        for i in range(count.size) if count[i] != 0
                    ])

                X_sax_below_thresh = alphabet[_digitize(X_paa, bin_edges)]

        # Subsequences with standard deviations above threshold
        if (self.threshold_std is None) or (not np.all(idx)):
            pipeline = make_pipeline(
                StandardScaler(
                    with_mean=self.norm_mean, with_std=self.norm_std
                ),
                PiecewiseAggregateApproximation(
                    window_size=None, output_size=word_size,
                    overlapping=self.overlapping
                ),
                SymbolicAggregateApproximation(
                    n_bins=self.n_bins, strategy=self.strategy,
                    alphabet=self.alphabet, raise_warning=self.raise_warning
                )
            )
            if self.threshold_std is None:
                X_sax_above_thresh = pipeline.fit_transform(X_window)
            else:
                X_sax_above_thresh = pipeline.fit_transform(X_window[~idx])

        # Concatenate SAX words
        if self.threshold_std is not None:
            if np.any(idx):
                if not np.all(idx):
                    X_sax = np.empty((n_samples * n_windows, word_size),
                                     dtype='<U1')
                    X_sax[idx] = X_sax_below_thresh
                    X_sax[~idx] = X_sax_above_thresh
                else:
                    X_sax = X_sax_below_thresh
            else:
                X_sax = X_sax_above_thresh
        else:
            X_sax = X_sax_above_thresh
        X_sax = X_sax.reshape(n_samples, n_windows, word_size)

        # Join letters to make words
        X_word = np.asarray([[''.join(X_sax[i, j])
                              for j in range(n_windows)]
                             for i in range(n_samples)])

        # Apply numerosity reduction
        if self.numerosity_reduction:
            not_equal = np.c_[X_word[:, 1:] != X_word[:, :-1],
                              np.full(n_samples, True)]
            X_bow = np.asarray([' '.join(X_word[i, not_equal[i]])
                                for i in range(n_samples)])
        else:
            X_bow = np.asarray([' '.join(X_word[i]) for i in range(n_samples)])

        return X_bow
Transform each time series into a bag of words.

        Parameters
        ----------
        X : array-like, shape = (n_samples, n_timestamps)
            Data to transform.

        Returns
        -------
        X_new : array, shape = (n_samples,)
            Bags of words.

        
pyts/bag_of_words/bow.py