<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def qth_survival_times(q, survival_functions, cdf=False):
 """ Find the times when one or more survival functions reach the qth percentile. Parameters q: float or array a float between 0 and 1 that represents the time when the survival function hits the qth percentile. survival_functions: a (n,d) DataFrame or numpy array. If DataFrame, will return index values (actual times) If numpy array, will return indices. cdf: boolean, optional When doing left-censored data, cdf=True is used. Returns ------- float, or DataFrame if d==1, returns a float, np.inf if infinity. if d > 1, an DataFrame containing the first times the value was crossed. See Also -------- qth_survival_time, median_survival_times """

    # pylint: disable=cell-var-from-loop,misplaced-comparison-constant,no-else-return

    q = pd.Series(q)

    if not ((q <= 1).all() and (0 <= q).all()):
        raise ValueError("q must be between 0 and 1")

    survival_functions = pd.DataFrame(survival_functions)

    if survival_functions.shape[1] == 1 and q.shape == (1,):
        q = q[0]
        # If you add print statements to `qth_survival_time`, you'll see it's called
        # once too many times. This is expected Pandas behavior
        # https://stackoverflow.com/questions/21635915/why-does-pandas-apply-calculate-twice
        return survival_functions.apply(lambda s: qth_survival_time(q, s, cdf=cdf)).iloc[0]
    else:
        d = {_q: survival_functions.apply(lambda s: qth_survival_time(_q, s, cdf=cdf)) for _q in q}
        survival_times = pd.DataFrame(d).T

        #  Typically, one would expect that the output should equal the "height" of q.
        #  An issue can arise if the Series q contains duplicate values. We solve
        #  this by duplicating the entire row.
        if q.duplicated().any():
            survival_times = survival_times.loc[q]

        return survival_times