def filter_sparse_samples(df, max_nan=0.5, verbose=True):
    """
    Removes samples (rows) from a Pandas dataframe whose number of NaN values exceeds the set number.

    Args:
        df: Pandas dataframe
        max_nan: maximum tolerated NaN values. If a float, this is a percentage of the features (columns).
        verbose: print number of dropped samples

    Returns:
        A True/False series indicating the sparse samples
    """

    n_samples, n_features = df.shape

    if type(max_nan) is float:
        max_nan = int(max_nan * n_features)

    max_nan = max(0, min(n_features, max_nan)) # 0 <= max_nan <= n_features
    filter_sparse_samples = df.isnull().sum(axis=1) <= max_nan # drop samples with nan > max_nan
    n_sparse = df.shape[0] - df[filter_sparse_samples].shape[0]

    if verbose:
        print(f'{n_sparse:,} out of {n_samples:,} samples contained more than {max_nan} NaN value{"s" if max_nan > 1 else ""} and were dropped')

    return filter_sparse_samples