fig.text(.05, .47, r"logistic", rotation=90, **fontspecs) fig.text(.1, .47, r"$f(x)=\frac{1}{1+\exp(-x)}$", rotation=90, **fontspecs) fig.text(.05, .2, r"exponential", rotation=90, **fontspecs) fig.text(.1, .2, r"$f(x)=1-\exp(-x)$", rotation=90, **fontspecs) fig.text(.6, .95, r"ab", **fontspecs) fig.text(.6, .9, r"$g(x,a,b)=\frac{x-a}{b}$", **fontspecs) fig.text(.85, .95, r"poly", **fontspecs) fig.text(.85, .9, r"$g(x,a,b)=(\frac{x}{a})^b$", **fontspecs) axes_ab = [ax_ab, ax_logist, ax_logistab, ax_lgumbel, ax_gumbelab] axes_wei = [ax_weibull, ax_logistweib, ax_gumbelweib] abcore = sft.abCore() weicore = sft.polyCore(sft.PsiData([1, 2, 3], [2, 2, 2], [2, 2, 2], 2)) logistic = sft.PsiLogistic() gumbel = sft.PsiExponential() x = p.mgrid[-7:7:1000j] ax_logist.plot(x, [logistic.f(xx) for xx in x], color="k") ax_lgumbel.plot(x, [gumbel.f(xx) for xx in x], color="k") prm = [(1, 2, .02), (2, 2, .02), (1, 1, .02), (2, 1, .02)] col = ['b', 'r', 'g', 'c'] for pr, c in zip(prm, col): dab = [abcore.g(xx, pr) for xx in x] ax_ab.plot(x, dab, color=c) ax_logistab.plot(x, [logistic.f(dd) for dd in dab], color=c)
def diagnostics(data, params, nafc=2, sigmoid='logistic', core='ab', cuts=None, gammaislambda=False): """ Some diagnostic statistics for a psychometric function fit. This function is a bit messy since it has three functions depending on the type of the `data` argument. Parameters ---------- data : variable real data : A list of lists or an array of data. The first column should be stimulus intensity, the second column should be number of correct responses (in 2AFC) or number of yes- responses (in Yes/No), the third column should be number of trials. See also: the examples section below. intensities : sequence of floats The x-values of the psychometric function, then we obtain only the predicted values. no data : empty sequence In this case we evaluate the psychometric function at the cuts. All other return values are then irrelevant. params : sequence of len nparams parameter vector at which the diagnostic information should be evaluated nafc : int Number of responses alternatives for nAFC tasks. If nafc==1 a Yes/No task is assumed. sigmoid : string Name of the sigmoid to be fitted. Valid sigmoids include: logistic gauss gumbel_l gumbel_r See `swignifit.utility.available_sigmoids()` for all available sigmoids. core : string \"core\"-type of the psychometric function. Valid choices include: ab (x-a)/b mw%g midpoint and width linear a+bx log a+b log(x) See `swignifit.utility.available_cores()` for all available sigmoids. cuts : sequence of floats Cuts at which thresholds should be determined. That is if cuts = (.25,.5,.75), thresholds (F^{-1} ( 0.25 ), F^{-1} ( 0.5 ), F^{-1} ( 0.75 )) are returned. Here F^{-1} denotes the inverse of the function specified by sigmoid. If cuts==None, this is modified to cuts=[0.5]. Output ------ (predicted, deviance_residuals, deviance, thres, Rpd, Rkd) predicted : numpy array of length nblocks predicted values associated with the respective stimulus intensities deviance_residuals : numpy array of length nblocks deviance residuals of the data deviance float deviance of the data thres : numpy array length ncuts the model prediction at the cuts Rpd : float correlation between predicted performance and deviance residuals Rkd : float correlation between block index and deviance residuals Example ------- >>> x = [float(2*k) for k in xrange(6)] >>> k = [34,32,40,48,50,48] >>> n = [50]*6 >>> d = [[xx,kk,nn] for xx,kk,nn in zip(x,k,n)] >>> prm = [2.75, 1.45, 0.015] >>> pred,di,D,thres,slope,Rpd,Rkd = diagnostics(d,prm) >>> D 8.0748485860836254 >>> di[0] 1.6893279652591433 >>> Rpd -0.19344675783032755 """ # here we need to hack stuff, since data can be either 'real' data, or just # a list of intensities, or just an empty sequence # in order to remain compatible with psipy we must check for an empty # sequence here, and return a specially crafted return value in that case. # sorry.. # TODO after removal of psipy we can probably change this. if op.isSequenceType(data) and len(data) == 0: pmf, nparams = sfu.make_pmf(sfr.PsiData([0], [0], [0], 1), nafc, sigmoid, core, None, gammaislambda=gammaislambda) thres = np.array( [pmf.getThres(params, cut) for cut in sfu.get_cuts(cuts)]) slope = np.array([pmf.getSlope(params, th) for th in thres]) return np.array([]), np.array([]), 0.0, thres, np.nan, np.nan shape = np.shape(np.array(data)) intensities_only = False if len(shape) == 1: # just intensities, make a dataset with k and n all zero k = n = [0] * shape[0] data = [[xx, kk, nn] for xx, kk, nn in zip(data, k, n)] intensities_only = True else: # data is 'real', just do nothing pass dataset, pmf, nparams = sfu.make_dataset_and_pmf( data, nafc, sigmoid, core, None, gammaislambda=gammaislambda) cuts = sfu.get_cuts(cuts) params = sfu.get_params(params, nparams) predicted = np.array([ pmf.evaluate(intensity, params) for intensity in dataset.getIntensities() ]) if intensities_only: return predicted else: deviance_residuals = pmf.getDevianceResiduals(params, dataset) deviance = pmf.deviance(params, dataset) thres = np.array([pmf.getThres(params, cut) for cut in cuts]) slope = np.array([pmf.getSlope(params, th) for th in thres]) rpd = pmf.getRpd(deviance_residuals, params, dataset) rkd = pmf.getRkd(deviance_residuals, dataset) return predicted, deviance_residuals, deviance, thres, slope, rpd, rkd
def generate_test_dataset(): x = sfr.vector_double([0.,2.,4.,6., 8., 10.]) k = sfr.vector_int([24, 32, 40,48, 50,48]) n = sfr.vector_int(6*[50]) return sfr.PsiData(x, n, k, 2)