//  [python]
def split(self, X, y) -> Iterable[tuple[list[int], list[int]]]:
        """
        Split the PCM dataset into train and test set such that the subsets are balanced
        with respect to the protein targets and there is not data leakage between the
        train and test set.

        Converts the PCM dataset into a multi-task dataset with protein targets as
        columns and uses the given splitter to split the multi-task dataset.

        Args:
            X (np.ndarray | pd.DataFrame): the input data matrix
            y (np.ndarray | pd.DataFrame | pd.Series): the target variable(s)

        Returns:
            an generator over the generated subsets represented as a tuple of
            (train_indices, test_indices) where the indices are the row indices of the
            input data matrix X (note that these are integer indices, rather than a
            pandas index!)
        """
        ds = self.getDataSet()
        df = ds.getDF()
        indices = df.index.tolist()
        proteins = df[ds.proteinCol].unique()
        task = ds.targetProperties[0].task
        th = ds.targetProperties[0].th if task.isClassification() else None
        assert (
            len(ds.targetProperties) == 1
        ), "PCMSplit only works for single-task datasets!"
        # TODO: Add support for multi-target (create a multi-task PCM dataset)
        # with all target-task combinations as different columns and split that
        # dataset with the given splitter
        # Pivot dataframe to get a matrix with protein targets as columns
        df_mt = df.pivot(
            index=ds.smilesCol,
            columns=ds.proteinCol,
            values=ds.targetProperties[0].name,
        ).reset_index()
        # Create target properties for multi-task dataset
        mt_targetProperties = [
            TargetProperty(
                name=target, task=task, th=th, imputer=SimpleImputer(strategy="median")
            )
            for target in proteins
        ]
        # temporarily create multi-task dataset and split it with the given splitter
        ds_mt = QSPRDataset(
            name=f"PCM_{self.splitter.__class__.__name__}_{hash(self)}",
            df=df_mt,
            smiles_col=ds.smilesCol,
            target_props=mt_targetProperties,
            random_state=ds.randomState,
        )
        ds_mt.split(self.splitter)
        # Convert MT indices to indices of original PCM dataset
        test_indices = []
        for i in ds_mt.X_ind.index:
            # Get SMILES and non-NaN targets for index i
            smiles = df_mt.loc[i, ds_mt.smilesCol]
            cols = df_mt.loc[i, :].dropna().index
            targets = [col for col in cols if col in proteins]
            for target in targets:
                # Get index in the original PCM dataset the SMILES-target pair
                a = df[ds.smilesCol] == smiles
                b = df[ds.proteinCol] == target
                if any(a & b):
                    ds_idx = df[a & b].index.astype(str)[0]
                    # Convert to numeric index
                    test_indices.append(indices.index(ds_idx))
        train_indices = [i for i in range(len(df)) if i not in test_indices]
        return iter([(train_indices, test_indices)])