Selects rows from the sample data frame that fall `margin` or greater
    cycles earlier than the NTC for that target. NTC wells are recognized by
    string matching against the Sample column.

    :param DataFrame sample_frame: A sample data frame.
    :param iterable ntc_samples: A sequence of strings giving the sample names of your NTC wells, i.e. ['NTC']
    :param float margin: The number of cycles earlier than the NTC for a "good" sample, i.e. log2(10)
    :return: a view of the sample data frame containing only non-background rows
    :rtype: DataFrame

def censor_background(sample_frame, ntc_samples=['NTC'], margin=log2(10)):
    """Selects rows from the sample data frame that fall `margin` or greater
    cycles earlier than the NTC for that target. NTC wells are recognized by
    string matching against the Sample column.

    :param DataFrame sample_frame: A sample data frame.
    :param iterable ntc_samples: A sequence of strings giving the sample names of your NTC wells, i.e. ['NTC']
    :param float margin: The number of cycles earlier than the NTC for a "good" sample, i.e. log2(10)
    :return: a view of the sample data frame containing only non-background rows
    :rtype: DataFrame
    """
    ntcs = sample_frame.loc[ sample_frame['Sample'].apply(lambda x: x in ntc_samples), ]
    if ntcs.empty:
        return sample_frame
    g = ntcs.groupby('Target')
    min_ntcs = g['Cq'].min()
    # if a target has no NTC, min_ntcs.loc[sample] is NaN
    # we should retain all values from targets with no NTC
    # all comparisons with NaN are false
    # so we test for the "wrong" condition and invert the result
    censored = sample_frame.loc[ ~(sample_frame['Cq'] > (min_ntcs.loc[sample_frame['Target']] - margin)) ]
    return censored