def decayfit(t, y, p=(0.05, 0.9), prepend_zero=False, rse=False, lm=False): """ Fit exponential decay, y(t) = w exp(-t/tau), to latter part of trajectory. :param t: time :param y: variable, e.g. an ion current :param p: proportion of return to initial value, as for action potential duration :param bool prepend_zero: add a 0 at the start of y (hack for use with ion currents) :param bool rse: return relative standard error of slope (not of *tau*!). :param bool lm: Return R object for fitted linear model. :return tau: -1/slope for estimated slope of log(y) vs t tau has dimension 'time' and is analogous to half-life: '1/e'-life = 0.37-life. For use with results from :meth:`Clampable.vecvclamp`, see :func:`decayfits`. Trivial example. >>> t = np.arange(10) >>> y = np.exp(-t) >>> y[0] = 0 >>> decayfit(t, y) 1.0 Relative standard error when adding noise. >>> np.random.seed(0) >>> noisy = y + 0.05 * np.random.random(size=y.shape) >>> decayfit(t, noisy, rse=True, p=[0.5, 0.99]) (1.292..., 0.045...) """ assert len(p) == 2 if prepend_zero: t = np.r_[0, t] y = np.r_[0, y] stats = apd(t, y, p) _ip, i0, i1 = stats["i"] # Avoid "Warning message: In is.na(rows) : # is.na() applied to non-(list or vector) of type 'NULL'" if i1 <= i0: tau = rse_slope = np.nan rlm = None else: with roptions(show_error_messages=False, deparse_max_lines=0): try: rlm = r.lm("log(y)~t", data=dict(t=t[i0:i1], y=y[i0:i1].squeeze())) coef = r2rec(r.as_data_frame(r.coef(r.summary(rlm)))) _intercept, slope = coef.Estimate _rse_intercept, rse_slope = (coef["Std. Error"] / abs(coef.Estimate)) tau = - 1.0 / slope except RRuntimeError: tau = rse_slope = np.nan rlm = None result = (tau,) if rse: result += (rse_slope,) if lm: result += (rlm,) return result if len(result) > 1 else result[0]
>>> mmfit(x, -y) (nan, nan) """ with roptions(show_error_messages=False, deparse_max_lines=0): kwargs = dict(formula="y~ymax*x/(x+xhalf)", data=dict(x=x, y=y), start=dict(ymax=max(y), xhalf=np.mean(x))) try: fit = r.nls(**kwargs) except RRuntimeError, exc: s = str(exc.exc).split("\n")[1].strip() errmsg = "Michaelis-Menten fit failed with message '%s'. " % s errmsg += "Arguments to r.nls() were: %s" logger.debug(errmsg, kwargs) ymax = xhalf = rse_ymax = rse_xhalf = np.nan else: coef = r2rec(r.as_data_frame(r.coef(r.summary(fit)))) ymax, xhalf = coef.Estimate rse_ymax, rse_xhalf = coef["Std. Error"] / coef.Estimate if (ymax < 0) or (xhalf < 0): errmsg = ("Michalis-Menten fit gave negative estimate(s): " "ymax=%s, xhalf=%s. Arguments to r.nls() were: %s") logger.debug(errmsg, ymax, xhalf, kwargs) ymax = xhalf = rse_ymax = rse_xhalf = np.nan return (ymax, xhalf, rse_ymax, rse_xhalf) if rse else (ymax, xhalf) def decayfits(L, i, k, abs_=True): """ Convenience wrapper for applying decayfit() to list returned by vecvclamp(). :param L: list of (proto, traj), where *proto* is a list of (duration, voltage) for each pulse, and *traj* is a list of