| # Copyright (c) 1999-2008 Gary Strangman; All Rights Reserved. |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining a copy |
| # of this software and associated documentation files (the "Software"), to deal |
| # in the Software without restriction, including without limitation the rights |
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| # copies of the Software, and to permit persons to whom the Software is |
| # furnished to do so, subject to the following conditions: |
| # |
| # The above copyright notice and this permission notice shall be included in |
| # all copies or substantial portions of the Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| # THE SOFTWARE. |
| # |
| # Comments and/or additions are welcome (send e-mail to: |
| # strang@nmr.mgh.harvard.edu). |
| # |
| """ |
| stats.py module |
| |
| (Requires pstat.py module.) |
| |
| ################################################# |
| ####### Written by: Gary Strangman ########### |
| ####### Last modified: Oct 31, 2008 ########### |
| ################################################# |
| |
| A collection of basic statistical functions for python. The function |
| names appear below. |
| |
| IMPORTANT: There are really *3* sets of functions. The first set has an 'l' |
| prefix, which can be used with list or tuple arguments. The second set has |
| an 'a' prefix, which can accept NumPy array arguments. These latter |
| functions are defined only when NumPy is available on the system. The third |
| type has NO prefix (i.e., has the name that appears below). Functions of |
| this set are members of a "Dispatch" class, c/o David Ascher. This class |
| allows different functions to be called depending on the type of the passed |
| arguments. Thus, stats.mean is a member of the Dispatch class and |
| stats.mean(range(20)) will call stats.lmean(range(20)) while |
| stats.mean(Numeric.arange(20)) will call stats.amean(Numeric.arange(20)). |
| This is a handy way to keep consistent function names when different |
| argument types require different functions to be called. Having |
| implementated the Dispatch class, however, means that to get info on |
| a given function, you must use the REAL function name ... that is |
| "print stats.lmean.__doc__" or "print stats.amean.__doc__" work fine, |
| while "print stats.mean.__doc__" will print the doc for the Dispatch |
| class. NUMPY FUNCTIONS ('a' prefix) generally have more argument options |
| but should otherwise be consistent with the corresponding list functions. |
| |
| Disclaimers: The function list is obviously incomplete and, worse, the |
| functions are not optimized. All functions have been tested (some more |
| so than others), but they are far from bulletproof. Thus, as with any |
| free software, no warranty or guarantee is expressed or implied. :-) A |
| few extra functions that don't appear in the list below can be found by |
| interested treasure-hunters. These functions don't necessarily have |
| both list and array versions but were deemed useful |
| |
| CENTRAL TENDENCY: geometricmean |
| harmonicmean |
| mean |
| median |
| medianscore |
| mode |
| |
| MOMENTS: moment |
| variation |
| skew |
| kurtosis |
| skewtest (for Numpy arrays only) |
| kurtosistest (for Numpy arrays only) |
| normaltest (for Numpy arrays only) |
| |
| ALTERED VERSIONS: tmean (for Numpy arrays only) |
| tvar (for Numpy arrays only) |
| tmin (for Numpy arrays only) |
| tmax (for Numpy arrays only) |
| tstdev (for Numpy arrays only) |
| tsem (for Numpy arrays only) |
| describe |
| |
| FREQUENCY STATS: itemfreq |
| scoreatpercentile |
| percentileofscore |
| histogram |
| cumfreq |
| relfreq |
| |
| VARIABILITY: obrientransform |
| samplevar |
| samplestdev |
| signaltonoise (for Numpy arrays only) |
| var |
| stdev |
| sterr |
| sem |
| z |
| zs |
| zmap (for Numpy arrays only) |
| |
| TRIMMING FCNS: threshold (for Numpy arrays only) |
| trimboth |
| trim1 |
| round (round all vals to 'n' decimals; Numpy only) |
| |
| CORRELATION FCNS: covariance (for Numpy arrays only) |
| correlation (for Numpy arrays only) |
| paired |
| pearsonr |
| spearmanr |
| pointbiserialr |
| kendalltau |
| linregress |
| |
| INFERENTIAL STATS: ttest_1samp |
| ttest_ind |
| ttest_rel |
| chisquare |
| ks_2samp |
| mannwhitneyu |
| ranksums |
| wilcoxont |
| kruskalwallish |
| friedmanchisquare |
| |
| PROBABILITY CALCS: chisqprob |
| erfcc |
| zprob |
| ksprob |
| fprob |
| betacf |
| gammln |
| betai |
| |
| ANOVA FUNCTIONS: F_oneway |
| F_value |
| |
| SUPPORT FUNCTIONS: writecc |
| incr |
| sign (for Numpy arrays only) |
| sum |
| cumsum |
| ss |
| summult |
| sumdiffsquared |
| square_of_sums |
| shellsort |
| rankdata |
| outputpairedstats |
| findwithin |
| """ |
| ## CHANGE LOG: |
| ## =========== |
| ## 09-07-21 ... added capability for getting the 'proportion' out of l/amannwhitneyu (but comment-disabled) |
| ## 08-10-31 ... fixed import LinearAlgebra bug before glm fcns |
| ## 07-11-26 ... conversion for numpy started |
| ## 07-05-16 ... added Lin's Concordance Correlation Coefficient (alincc) and acov |
| ## 05-08-21 ... added "Dice's coefficient" |
| ## 04-10-26 ... added ap2t(), an ugly fcn for converting p-vals to T-vals |
| ## 04-04-03 ... added amasslinregress() function to do regression on N-D arrays |
| ## 03-01-03 ... CHANGED VERSION TO 0.6 |
| ## fixed atsem() to properly handle limits=None case |
| ## improved histogram and median functions (estbinwidth) and |
| ## fixed atvar() function (wrong answers for neg numbers?!?) |
| ## 02-11-19 ... fixed attest_ind and attest_rel for div-by-zero Overflows |
| ## 02-05-10 ... fixed lchisqprob indentation (failed when df=even) |
| ## 00-12-28 ... removed aanova() to separate module, fixed licensing to |
| ## match Python License, fixed doc string & imports |
| ## 00-04-13 ... pulled all "global" statements, except from aanova() |
| ## added/fixed lots of documentation, removed io.py dependency |
| ## changed to version 0.5 |
| ## 99-11-13 ... added asign() function |
| ## 99-11-01 ... changed version to 0.4 ... enough incremental changes now |
| ## 99-10-25 ... added acovariance and acorrelation functions |
| ## 99-10-10 ... fixed askew/akurtosis to avoid divide-by-zero errors |
| ## added aglm function (crude, but will be improved) |
| ## 99-10-04 ... upgraded acumsum, ass, asummult, asamplevar, avar, etc. to |
| ## all handle lists of 'dimension's and keepdims |
| ## REMOVED ar0, ar2, ar3, ar4 and replaced them with around |
| ## reinserted fixes for abetai to avoid math overflows |
| ## 99-09-05 ... rewrote achisqprob/aerfcc/aksprob/afprob/abetacf/abetai to |
| ## handle multi-dimensional arrays (whew!) |
| ## 99-08-30 ... fixed l/amoment, l/askew, l/akurtosis per D'Agostino (1990) |
| ## added anormaltest per same reference |
| ## re-wrote azprob to calc arrays of probs all at once |
| ## 99-08-22 ... edited attest_ind printing section so arrays could be rounded |
| ## 99-08-19 ... fixed amean and aharmonicmean for non-error(!) overflow on |
| ## short/byte arrays (mean of #s btw 100-300 = -150??) |
| ## 99-08-09 ... fixed asum so that the None case works for Byte arrays |
| ## 99-08-08 ... fixed 7/3 'improvement' to handle t-calcs on N-D arrays |
| ## 99-07-03 ... improved attest_ind, attest_rel (zero-division errortrap) |
| ## 99-06-24 ... fixed bug(?) in attest_ind (n1=a.shape[0]) |
| ## 04/11/99 ... added asignaltonoise, athreshold functions, changed all |
| ## max/min in array section to N.maximum/N.minimum, |
| ## fixed square_of_sums to prevent integer overflow |
| ## 04/10/99 ... !!! Changed function name ... sumsquared ==> square_of_sums |
| ## 03/18/99 ... Added ar0, ar2, ar3 and ar4 rounding functions |
| ## 02/28/99 ... Fixed aobrientransform to return an array rather than a list |
| ## 01/15/99 ... Essentially ceased updating list-versions of functions (!!!) |
| ## 01/13/99 ... CHANGED TO VERSION 0.3 |
| ## fixed bug in a/lmannwhitneyu p-value calculation |
| ## 12/31/98 ... fixed variable-name bug in ldescribe |
| ## 12/19/98 ... fixed bug in findwithin (fcns needed pstat. prefix) |
| ## 12/16/98 ... changed amedianscore to return float (not array) for 1 score |
| ## 12/14/98 ... added atmin and atmax functions |
| ## removed umath from import line (not needed) |
| ## l/ageometricmean modified to reduce chance of overflows (take |
| ## nth root first, then multiply) |
| ## 12/07/98 ... added __version__variable (now 0.2) |
| ## removed all 'stats.' from anova() fcn |
| ## 12/06/98 ... changed those functions (except shellsort) that altered |
| ## arguments in-place ... cumsum, ranksort, ... |
| ## updated (and fixed some) doc-strings |
| ## 12/01/98 ... added anova() function (requires NumPy) |
| ## incorporated Dispatch class |
| ## 11/12/98 ... added functionality to amean, aharmonicmean, ageometricmean |
| ## added 'asum' function (added functionality to N.add.reduce) |
| ## fixed both moment and amoment (two errors) |
| ## changed name of skewness and askewness to skew and askew |
| ## fixed (a)histogram (which sometimes counted points <lowerlimit) |
| |
| import pstat # required 3rd party module |
| import math, string, copy # required python modules |
| from types import * |
| |
| __version__ = 0.6 |
| |
| ############# DISPATCH CODE ############## |
| |
| |
| class Dispatch: |
| """ |
| The Dispatch class, care of David Ascher, allows different functions to |
| be called depending on the argument types. This way, there can be one |
| function name regardless of the argument type. To access function doc |
| in stats.py module, prefix the function with an 'l' or 'a' for list or |
| array arguments, respectively. That is, print stats.lmean.__doc__ or |
| print stats.amean.__doc__ or whatever. |
| """ |
| |
| def __init__(self, *tuples): |
| self._dispatch = {} |
| for func, types in tuples: |
| for t in types: |
| if t in self._dispatch.keys(): |
| raise ValueError, "can't have two dispatches on "+str(t) |
| self._dispatch[t] = func |
| self._types = self._dispatch.keys() |
| |
| def __call__(self, arg1, *args, **kw): |
| if type(arg1) not in self._types: |
| raise TypeError, "don't know how to dispatch %s arguments" % type(arg1) |
| return apply(self._dispatch[type(arg1)], (arg1,) + args, kw) |
| |
| |
| ########################################################################## |
| ######################## LIST-BASED FUNCTIONS ######################## |
| ########################################################################## |
| |
| ### Define these regardless |
| |
| #################################### |
| ####### CENTRAL TENDENCY ######### |
| #################################### |
| |
| def lgeometricmean (inlist): |
| """ |
| Calculates the geometric mean of the values in the passed list. |
| That is: n-th root of (x1 * x2 * ... * xn). Assumes a '1D' list. |
| |
| Usage: lgeometricmean(inlist) |
| """ |
| mult = 1.0 |
| one_over_n = 1.0/len(inlist) |
| for item in inlist: |
| mult = mult * pow(item,one_over_n) |
| return mult |
| |
| |
| def lharmonicmean (inlist): |
| """ |
| Calculates the harmonic mean of the values in the passed list. |
| That is: n / (1/x1 + 1/x2 + ... + 1/xn). Assumes a '1D' list. |
| |
| Usage: lharmonicmean(inlist) |
| """ |
| sum = 0 |
| for item in inlist: |
| sum = sum + 1.0/item |
| return len(inlist) / sum |
| |
| |
| def lmean (inlist): |
| """ |
| Returns the arithematic mean of the values in the passed list. |
| Assumes a '1D' list, but will function on the 1st dim of an array(!). |
| |
| Usage: lmean(inlist) |
| """ |
| sum = 0 |
| for item in inlist: |
| sum = sum + item |
| return sum/float(len(inlist)) |
| |
| |
| def lmedian (inlist,numbins=1000): |
| """ |
| Returns the computed median value of a list of numbers, given the |
| number of bins to use for the histogram (more bins brings the computed value |
| closer to the median score, default number of bins = 1000). See G.W. |
| Heiman's Basic Stats (1st Edition), or CRC Probability & Statistics. |
| |
| Usage: lmedian (inlist, numbins=1000) |
| """ |
| (hist, smallest, binsize, extras) = histogram(inlist,numbins,[min(inlist),max(inlist)]) # make histog |
| cumhist = cumsum(hist) # make cumulative histogram |
| for i in range(len(cumhist)): # get 1st(!) index holding 50%ile score |
| if cumhist[i]>=len(inlist)/2.0: |
| cfbin = i |
| break |
| LRL = smallest + binsize*cfbin # get lower read limit of that bin |
| cfbelow = cumhist[cfbin-1] |
| freq = float(hist[cfbin]) # frequency IN the 50%ile bin |
| median = LRL + ((len(inlist)/2.0 - cfbelow)/float(freq))*binsize # median formula |
| return median |
| |
| |
| def lmedianscore (inlist): |
| """ |
| Returns the 'middle' score of the passed list. If there is an even |
| number of scores, the mean of the 2 middle scores is returned. |
| |
| Usage: lmedianscore(inlist) |
| """ |
| |
| newlist = copy.deepcopy(inlist) |
| newlist.sort() |
| if len(newlist) % 2 == 0: # if even number of scores, average middle 2 |
| index = len(newlist)/2 # integer division correct |
| median = float(newlist[index] + newlist[index-1]) /2 |
| else: |
| index = len(newlist)/2 # int divsion gives mid value when count from 0 |
| median = newlist[index] |
| return median |
| |
| |
| def lmode(inlist): |
| """ |
| Returns a list of the modal (most common) score(s) in the passed |
| list. If there is more than one such score, all are returned. The |
| bin-count for the mode(s) is also returned. |
| |
| Usage: lmode(inlist) |
| Returns: bin-count for mode(s), a list of modal value(s) |
| """ |
| |
| scores = pstat.unique(inlist) |
| scores.sort() |
| freq = [] |
| for item in scores: |
| freq.append(inlist.count(item)) |
| maxfreq = max(freq) |
| mode = [] |
| stillmore = 1 |
| while stillmore: |
| try: |
| indx = freq.index(maxfreq) |
| mode.append(scores[indx]) |
| del freq[indx] |
| del scores[indx] |
| except ValueError: |
| stillmore=0 |
| return maxfreq, mode |
| |
| |
| #################################### |
| ############ MOMENTS ############# |
| #################################### |
| |
| def lmoment(inlist,moment=1): |
| """ |
| Calculates the nth moment about the mean for a sample (defaults to |
| the 1st moment). Used to calculate coefficients of skewness and kurtosis. |
| |
| Usage: lmoment(inlist,moment=1) |
| Returns: appropriate moment (r) from ... 1/n * SUM((inlist(i)-mean)**r) |
| """ |
| if moment == 1: |
| return 0.0 |
| else: |
| mn = mean(inlist) |
| n = len(inlist) |
| s = 0 |
| for x in inlist: |
| s = s + (x-mn)**moment |
| return s/float(n) |
| |
| |
| def lvariation(inlist): |
| """ |
| Returns the coefficient of variation, as defined in CRC Standard |
| Probability and Statistics, p.6. |
| |
| Usage: lvariation(inlist) |
| """ |
| return 100.0*samplestdev(inlist)/float(mean(inlist)) |
| |
| |
| def lskew(inlist): |
| """ |
| Returns the skewness of a distribution, as defined in Numerical |
| Recipies (alternate defn in CRC Standard Probability and Statistics, p.6.) |
| |
| Usage: lskew(inlist) |
| """ |
| return moment(inlist,3)/pow(moment(inlist,2),1.5) |
| |
| |
| def lkurtosis(inlist): |
| """ |
| Returns the kurtosis of a distribution, as defined in Numerical |
| Recipies (alternate defn in CRC Standard Probability and Statistics, p.6.) |
| |
| Usage: lkurtosis(inlist) |
| """ |
| return moment(inlist,4)/pow(moment(inlist,2),2.0) |
| |
| |
| def ldescribe(inlist): |
| """ |
| Returns some descriptive statistics of the passed list (assumed to be 1D). |
| |
| Usage: ldescribe(inlist) |
| Returns: n, mean, standard deviation, skew, kurtosis |
| """ |
| n = len(inlist) |
| mm = (min(inlist),max(inlist)) |
| m = mean(inlist) |
| sd = stdev(inlist) |
| sk = skew(inlist) |
| kurt = kurtosis(inlist) |
| return n, mm, m, sd, sk, kurt |
| |
| |
| #################################### |
| ####### FREQUENCY STATS ########## |
| #################################### |
| |
| def litemfreq(inlist): |
| """ |
| Returns a list of pairs. Each pair consists of one of the scores in inlist |
| and it's frequency count. Assumes a 1D list is passed. |
| |
| Usage: litemfreq(inlist) |
| Returns: a 2D frequency table (col [0:n-1]=scores, col n=frequencies) |
| """ |
| scores = pstat.unique(inlist) |
| scores.sort() |
| freq = [] |
| for item in scores: |
| freq.append(inlist.count(item)) |
| return pstat.abut(scores, freq) |
| |
| |
| def lscoreatpercentile (inlist, percent): |
| """ |
| Returns the score at a given percentile relative to the distribution |
| given by inlist. |
| |
| Usage: lscoreatpercentile(inlist,percent) |
| """ |
| if percent > 1: |
| print "\nDividing percent>1 by 100 in lscoreatpercentile().\n" |
| percent = percent / 100.0 |
| targetcf = percent*len(inlist) |
| h, lrl, binsize, extras = histogram(inlist) |
| cumhist = cumsum(copy.deepcopy(h)) |
| for i in range(len(cumhist)): |
| if cumhist[i] >= targetcf: |
| break |
| score = binsize * ((targetcf - cumhist[i-1]) / float(h[i])) + (lrl+binsize*i) |
| return score |
| |
| |
| def lpercentileofscore (inlist, score,histbins=10,defaultlimits=None): |
| """ |
| Returns the percentile value of a score relative to the distribution |
| given by inlist. Formula depends on the values used to histogram the data(!). |
| |
| Usage: lpercentileofscore(inlist,score,histbins=10,defaultlimits=None) |
| """ |
| |
| h, lrl, binsize, extras = histogram(inlist,histbins,defaultlimits) |
| cumhist = cumsum(copy.deepcopy(h)) |
| i = int((score - lrl)/float(binsize)) |
| pct = (cumhist[i-1]+((score-(lrl+binsize*i))/float(binsize))*h[i])/float(len(inlist)) * 100 |
| return pct |
| |
| |
| def lhistogram (inlist,numbins=10,defaultreallimits=None,printextras=0): |
| """ |
| Returns (i) a list of histogram bin counts, (ii) the smallest value |
| of the histogram binning, and (iii) the bin width (the last 2 are not |
| necessarily integers). Default number of bins is 10. If no sequence object |
| is given for defaultreallimits, the routine picks (usually non-pretty) bins |
| spanning all the numbers in the inlist. |
| |
| Usage: lhistogram (inlist, numbins=10, defaultreallimits=None,suppressoutput=0) |
| Returns: list of bin values, lowerreallimit, binsize, extrapoints |
| """ |
| if (defaultreallimits <> None): |
| if type(defaultreallimits) not in [ListType,TupleType] or len(defaultreallimits)==1: # only one limit given, assumed to be lower one & upper is calc'd |
| lowerreallimit = defaultreallimits |
| upperreallimit = 1.000001 * max(inlist) |
| else: # assume both limits given |
| lowerreallimit = defaultreallimits[0] |
| upperreallimit = defaultreallimits[1] |
| binsize = (upperreallimit-lowerreallimit)/float(numbins) |
| else: # no limits given for histogram, both must be calc'd |
| estbinwidth=(max(inlist)-min(inlist))/float(numbins) +1e-6 #1=>cover all |
| binsize = ((max(inlist)-min(inlist)+estbinwidth))/float(numbins) |
| lowerreallimit = min(inlist) - binsize/2 #lower real limit,1st bin |
| bins = [0]*(numbins) |
| extrapoints = 0 |
| for num in inlist: |
| try: |
| if (num-lowerreallimit) < 0: |
| extrapoints = extrapoints + 1 |
| else: |
| bintoincrement = int((num-lowerreallimit)/float(binsize)) |
| bins[bintoincrement] = bins[bintoincrement] + 1 |
| except: |
| extrapoints = extrapoints + 1 |
| if (extrapoints > 0 and printextras == 1): |
| print '\nPoints outside given histogram range =',extrapoints |
| return (bins, lowerreallimit, binsize, extrapoints) |
| |
| |
| def lcumfreq(inlist,numbins=10,defaultreallimits=None): |
| """ |
| Returns a cumulative frequency histogram, using the histogram function. |
| |
| Usage: lcumfreq(inlist,numbins=10,defaultreallimits=None) |
| Returns: list of cumfreq bin values, lowerreallimit, binsize, extrapoints |
| """ |
| h,l,b,e = histogram(inlist,numbins,defaultreallimits) |
| cumhist = cumsum(copy.deepcopy(h)) |
| return cumhist,l,b,e |
| |
| |
| def lrelfreq(inlist,numbins=10,defaultreallimits=None): |
| """ |
| Returns a relative frequency histogram, using the histogram function. |
| |
| Usage: lrelfreq(inlist,numbins=10,defaultreallimits=None) |
| Returns: list of cumfreq bin values, lowerreallimit, binsize, extrapoints |
| """ |
| h,l,b,e = histogram(inlist,numbins,defaultreallimits) |
| for i in range(len(h)): |
| h[i] = h[i]/float(len(inlist)) |
| return h,l,b,e |
| |
| |
| #################################### |
| ##### VARIABILITY FUNCTIONS ###### |
| #################################### |
| |
| def lobrientransform(*args): |
| """ |
| Computes a transform on input data (any number of columns). Used to |
| test for homogeneity of variance prior to running one-way stats. From |
| Maxwell and Delaney, p.112. |
| |
| Usage: lobrientransform(*args) |
| Returns: transformed data for use in an ANOVA |
| """ |
| TINY = 1e-10 |
| k = len(args) |
| n = [0.0]*k |
| v = [0.0]*k |
| m = [0.0]*k |
| nargs = [] |
| for i in range(k): |
| nargs.append(copy.deepcopy(args[i])) |
| n[i] = float(len(nargs[i])) |
| v[i] = var(nargs[i]) |
| m[i] = mean(nargs[i]) |
| for j in range(k): |
| for i in range(n[j]): |
| t1 = (n[j]-1.5)*n[j]*(nargs[j][i]-m[j])**2 |
| t2 = 0.5*v[j]*(n[j]-1.0) |
| t3 = (n[j]-1.0)*(n[j]-2.0) |
| nargs[j][i] = (t1-t2) / float(t3) |
| check = 1 |
| for j in range(k): |
| if v[j] - mean(nargs[j]) > TINY: |
| check = 0 |
| if check <> 1: |
| raise ValueError, 'Problem in obrientransform.' |
| else: |
| return nargs |
| |
| |
| def lsamplevar (inlist): |
| """ |
| Returns the variance of the values in the passed list using |
| N for the denominator (i.e., DESCRIBES the sample variance only). |
| |
| Usage: lsamplevar(inlist) |
| """ |
| n = len(inlist) |
| mn = mean(inlist) |
| deviations = [] |
| for item in inlist: |
| deviations.append(item-mn) |
| return ss(deviations)/float(n) |
| |
| |
| def lsamplestdev (inlist): |
| """ |
| Returns the standard deviation of the values in the passed list using |
| N for the denominator (i.e., DESCRIBES the sample stdev only). |
| |
| Usage: lsamplestdev(inlist) |
| """ |
| return math.sqrt(samplevar(inlist)) |
| |
| |
| def lcov (x,y, keepdims=0): |
| """ |
| Returns the estimated covariance of the values in the passed |
| array (i.e., N-1). Dimension can equal None (ravel array first), an |
| integer (the dimension over which to operate), or a sequence (operate |
| over multiple dimensions). Set keepdims=1 to return an array with the |
| same number of dimensions as inarray. |
| |
| Usage: lcov(x,y,keepdims=0) |
| """ |
| |
| n = len(x) |
| xmn = mean(x) |
| ymn = mean(y) |
| xdeviations = [0]*len(x) |
| ydeviations = [0]*len(y) |
| for i in range(len(x)): |
| xdeviations[i] = x[i] - xmn |
| ydeviations[i] = y[i] - ymn |
| ss = 0.0 |
| for i in range(len(xdeviations)): |
| ss = ss + xdeviations[i]*ydeviations[i] |
| return ss/float(n-1) |
| |
| |
| def lvar (inlist): |
| """ |
| Returns the variance of the values in the passed list using N-1 |
| for the denominator (i.e., for estimating population variance). |
| |
| Usage: lvar(inlist) |
| """ |
| n = len(inlist) |
| mn = mean(inlist) |
| deviations = [0]*len(inlist) |
| for i in range(len(inlist)): |
| deviations[i] = inlist[i] - mn |
| return ss(deviations)/float(n-1) |
| |
| |
| def lstdev (inlist): |
| """ |
| Returns the standard deviation of the values in the passed list |
| using N-1 in the denominator (i.e., to estimate population stdev). |
| |
| Usage: lstdev(inlist) |
| """ |
| return math.sqrt(var(inlist)) |
| |
| |
| def lsterr(inlist): |
| """ |
| Returns the standard error of the values in the passed list using N-1 |
| in the denominator (i.e., to estimate population standard error). |
| |
| Usage: lsterr(inlist) |
| """ |
| return stdev(inlist) / float(math.sqrt(len(inlist))) |
| |
| |
| def lsem (inlist): |
| """ |
| Returns the estimated standard error of the mean (sx-bar) of the |
| values in the passed list. sem = stdev / sqrt(n) |
| |
| Usage: lsem(inlist) |
| """ |
| sd = stdev(inlist) |
| n = len(inlist) |
| return sd/math.sqrt(n) |
| |
| |
| def lz (inlist, score): |
| """ |
| Returns the z-score for a given input score, given that score and the |
| list from which that score came. Not appropriate for population calculations. |
| |
| Usage: lz(inlist, score) |
| """ |
| z = (score-mean(inlist))/samplestdev(inlist) |
| return z |
| |
| |
| def lzs (inlist): |
| """ |
| Returns a list of z-scores, one for each score in the passed list. |
| |
| Usage: lzs(inlist) |
| """ |
| zscores = [] |
| for item in inlist: |
| zscores.append(z(inlist,item)) |
| return zscores |
| |
| |
| #################################### |
| ####### TRIMMING FUNCTIONS ####### |
| #################################### |
| |
| def ltrimboth (l,proportiontocut): |
| """ |
| Slices off the passed proportion of items from BOTH ends of the passed |
| list (i.e., with proportiontocut=0.1, slices 'leftmost' 10% AND 'rightmost' |
| 10% of scores. Assumes list is sorted by magnitude. Slices off LESS if |
| proportion results in a non-integer slice index (i.e., conservatively |
| slices off proportiontocut). |
| |
| Usage: ltrimboth (l,proportiontocut) |
| Returns: trimmed version of list l |
| """ |
| lowercut = int(proportiontocut*len(l)) |
| uppercut = len(l) - lowercut |
| return l[lowercut:uppercut] |
| |
| |
| def ltrim1 (l,proportiontocut,tail='right'): |
| """ |
| Slices off the passed proportion of items from ONE end of the passed |
| list (i.e., if proportiontocut=0.1, slices off 'leftmost' or 'rightmost' |
| 10% of scores). Slices off LESS if proportion results in a non-integer |
| slice index (i.e., conservatively slices off proportiontocut). |
| |
| Usage: ltrim1 (l,proportiontocut,tail='right') or set tail='left' |
| Returns: trimmed version of list l |
| """ |
| if tail == 'right': |
| lowercut = 0 |
| uppercut = len(l) - int(proportiontocut*len(l)) |
| elif tail == 'left': |
| lowercut = int(proportiontocut*len(l)) |
| uppercut = len(l) |
| return l[lowercut:uppercut] |
| |
| |
| #################################### |
| ##### CORRELATION FUNCTIONS ###### |
| #################################### |
| |
| def lpaired(x,y): |
| """ |
| Interactively determines the type of data and then runs the |
| appropriated statistic for paired group data. |
| |
| Usage: lpaired(x,y) |
| Returns: appropriate statistic name, value, and probability |
| """ |
| samples = '' |
| while samples not in ['i','r','I','R','c','C']: |
| print '\nIndependent or related samples, or correlation (i,r,c): ', |
| samples = raw_input() |
| |
| if samples in ['i','I','r','R']: |
| print '\nComparing variances ...', |
| # USE O'BRIEN'S TEST FOR HOMOGENEITY OF VARIANCE, Maxwell & delaney, p.112 |
| r = obrientransform(x,y) |
| f,p = F_oneway(pstat.colex(r,0),pstat.colex(r,1)) |
| if p<0.05: |
| vartype='unequal, p='+str(round(p,4)) |
| else: |
| vartype='equal' |
| print vartype |
| if samples in ['i','I']: |
| if vartype[0]=='e': |
| t,p = ttest_ind(x,y,0) |
| print '\nIndependent samples t-test: ', round(t,4),round(p,4) |
| else: |
| if len(x)>20 or len(y)>20: |
| z,p = ranksums(x,y) |
| print '\nRank Sums test (NONparametric, n>20): ', round(z,4),round(p,4) |
| else: |
| u,p = mannwhitneyu(x,y) |
| print '\nMann-Whitney U-test (NONparametric, ns<20): ', round(u,4),round(p,4) |
| |
| else: # RELATED SAMPLES |
| if vartype[0]=='e': |
| t,p = ttest_rel(x,y,0) |
| print '\nRelated samples t-test: ', round(t,4),round(p,4) |
| else: |
| t,p = ranksums(x,y) |
| print '\nWilcoxon T-test (NONparametric): ', round(t,4),round(p,4) |
| else: # CORRELATION ANALYSIS |
| corrtype = '' |
| while corrtype not in ['c','C','r','R','d','D']: |
| print '\nIs the data Continuous, Ranked, or Dichotomous (c,r,d): ', |
| corrtype = raw_input() |
| if corrtype in ['c','C']: |
| m,b,r,p,see = linregress(x,y) |
| print '\nLinear regression for continuous variables ...' |
| lol = [['Slope','Intercept','r','Prob','SEestimate'],[round(m,4),round(b,4),round(r,4),round(p,4),round(see,4)]] |
| pstat.printcc(lol) |
| elif corrtype in ['r','R']: |
| r,p = spearmanr(x,y) |
| print '\nCorrelation for ranked variables ...' |
| print "Spearman's r: ",round(r,4),round(p,4) |
| else: # DICHOTOMOUS |
| r,p = pointbiserialr(x,y) |
| print '\nAssuming x contains a dichotomous variable ...' |
| print 'Point Biserial r: ',round(r,4),round(p,4) |
| print '\n\n' |
| return None |
| |
| |
| def lpearsonr(x,y): |
| """ |
| Calculates a Pearson correlation coefficient and the associated |
| probability value. Taken from Heiman's Basic Statistics for the Behav. |
| Sci (2nd), p.195. |
| |
| Usage: lpearsonr(x,y) where x and y are equal-length lists |
| Returns: Pearson's r value, two-tailed p-value |
| """ |
| TINY = 1.0e-30 |
| if len(x) <> len(y): |
| raise ValueError, 'Input values not paired in pearsonr. Aborting.' |
| n = len(x) |
| x = map(float,x) |
| y = map(float,y) |
| xmean = mean(x) |
| ymean = mean(y) |
| r_num = n*(summult(x,y)) - sum(x)*sum(y) |
| r_den = math.sqrt((n*ss(x) - square_of_sums(x))*(n*ss(y)-square_of_sums(y))) |
| r = (r_num / r_den) # denominator already a float |
| df = n-2 |
| t = r*math.sqrt(df/((1.0-r+TINY)*(1.0+r+TINY))) |
| prob = betai(0.5*df,0.5,df/float(df+t*t)) |
| return r, prob |
| |
| |
| def llincc(x,y): |
| """ |
| Calculates Lin's concordance correlation coefficient. |
| |
| Usage: alincc(x,y) where x, y are equal-length arrays |
| Returns: Lin's CC |
| """ |
| covar = lcov(x,y)*(len(x)-1)/float(len(x)) # correct denom to n |
| xvar = lvar(x)*(len(x)-1)/float(len(x)) # correct denom to n |
| yvar = lvar(y)*(len(y)-1)/float(len(y)) # correct denom to n |
| lincc = (2 * covar) / ((xvar+yvar) +((amean(x)-amean(y))**2)) |
| return lincc |
| |
| |
| def lspearmanr(x,y): |
| """ |
| Calculates a Spearman rank-order correlation coefficient. Taken |
| from Heiman's Basic Statistics for the Behav. Sci (1st), p.192. |
| |
| Usage: lspearmanr(x,y) where x and y are equal-length lists |
| Returns: Spearman's r, two-tailed p-value |
| """ |
| TINY = 1e-30 |
| if len(x) <> len(y): |
| raise ValueError, 'Input values not paired in spearmanr. Aborting.' |
| n = len(x) |
| rankx = rankdata(x) |
| ranky = rankdata(y) |
| dsq = sumdiffsquared(rankx,ranky) |
| rs = 1 - 6*dsq / float(n*(n**2-1)) |
| t = rs * math.sqrt((n-2) / ((rs+1.0)*(1.0-rs))) |
| df = n-2 |
| probrs = betai(0.5*df,0.5,df/(df+t*t)) # t already a float |
| # probability values for rs are from part 2 of the spearman function in |
| # Numerical Recipies, p.510. They are close to tables, but not exact. (?) |
| return rs, probrs |
| |
| |
| def lpointbiserialr(x,y): |
| """ |
| Calculates a point-biserial correlation coefficient and the associated |
| probability value. Taken from Heiman's Basic Statistics for the Behav. |
| Sci (1st), p.194. |
| |
| Usage: lpointbiserialr(x,y) where x,y are equal-length lists |
| Returns: Point-biserial r, two-tailed p-value |
| """ |
| TINY = 1e-30 |
| if len(x) <> len(y): |
| raise ValueError, 'INPUT VALUES NOT PAIRED IN pointbiserialr. ABORTING.' |
| data = pstat.abut(x,y) |
| categories = pstat.unique(x) |
| if len(categories) <> 2: |
| raise ValueError, "Exactly 2 categories required for pointbiserialr()." |
| else: # there are 2 categories, continue |
| codemap = pstat.abut(categories,range(2)) |
| recoded = pstat.recode(data,codemap,0) |
| x = pstat.linexand(data,0,categories[0]) |
| y = pstat.linexand(data,0,categories[1]) |
| xmean = mean(pstat.colex(x,1)) |
| ymean = mean(pstat.colex(y,1)) |
| n = len(data) |
| adjust = math.sqrt((len(x)/float(n))*(len(y)/float(n))) |
| rpb = (ymean - xmean)/samplestdev(pstat.colex(data,1))*adjust |
| df = n-2 |
| t = rpb*math.sqrt(df/((1.0-rpb+TINY)*(1.0+rpb+TINY))) |
| prob = betai(0.5*df,0.5,df/(df+t*t)) # t already a float |
| return rpb, prob |
| |
| |
| def lkendalltau(x,y): |
| """ |
| Calculates Kendall's tau ... correlation of ordinal data. Adapted |
| from function kendl1 in Numerical Recipies. Needs good test-routine.@@@ |
| |
| Usage: lkendalltau(x,y) |
| Returns: Kendall's tau, two-tailed p-value |
| """ |
| n1 = 0 |
| n2 = 0 |
| iss = 0 |
| for j in range(len(x)-1): |
| for k in range(j,len(y)): |
| a1 = x[j] - x[k] |
| a2 = y[j] - y[k] |
| aa = a1 * a2 |
| if (aa): # neither list has a tie |
| n1 = n1 + 1 |
| n2 = n2 + 1 |
| if aa > 0: |
| iss = iss + 1 |
| else: |
| iss = iss -1 |
| else: |
| if (a1): |
| n1 = n1 + 1 |
| else: |
| n2 = n2 + 1 |
| tau = iss / math.sqrt(n1*n2) |
| svar = (4.0*len(x)+10.0) / (9.0*len(x)*(len(x)-1)) |
| z = tau / math.sqrt(svar) |
| prob = erfcc(abs(z)/1.4142136) |
| return tau, prob |
| |
| |
| def llinregress(x,y): |
| """ |
| Calculates a regression line on x,y pairs. |
| |
| Usage: llinregress(x,y) x,y are equal-length lists of x-y coordinates |
| Returns: slope, intercept, r, two-tailed prob, sterr-of-estimate |
| """ |
| TINY = 1.0e-20 |
| if len(x) <> len(y): |
| raise ValueError, 'Input values not paired in linregress. Aborting.' |
| n = len(x) |
| x = map(float,x) |
| y = map(float,y) |
| xmean = mean(x) |
| ymean = mean(y) |
| r_num = float(n*(summult(x,y)) - sum(x)*sum(y)) |
| r_den = math.sqrt((n*ss(x) - square_of_sums(x))*(n*ss(y)-square_of_sums(y))) |
| r = r_num / r_den |
| z = 0.5*math.log((1.0+r+TINY)/(1.0-r+TINY)) |
| df = n-2 |
| t = r*math.sqrt(df/((1.0-r+TINY)*(1.0+r+TINY))) |
| prob = betai(0.5*df,0.5,df/(df+t*t)) |
| slope = r_num / float(n*ss(x) - square_of_sums(x)) |
| intercept = ymean - slope*xmean |
| sterrest = math.sqrt(1-r*r)*samplestdev(y) |
| return slope, intercept, r, prob, sterrest |
| |
| |
| #################################### |
| ##### INFERENTIAL STATISTICS ##### |
| #################################### |
| |
| def lttest_1samp(a,popmean,printit=0,name='Sample',writemode='a'): |
| """ |
| Calculates the t-obtained for the independent samples T-test on ONE group |
| of scores a, given a population mean. If printit=1, results are printed |
| to the screen. If printit='filename', the results are output to 'filename' |
| using the given writemode (default=append). Returns t-value, and prob. |
| |
| Usage: lttest_1samp(a,popmean,Name='Sample',printit=0,writemode='a') |
| Returns: t-value, two-tailed prob |
| """ |
| x = mean(a) |
| v = var(a) |
| n = len(a) |
| df = n-1 |
| svar = ((n-1)*v)/float(df) |
| t = (x-popmean)/math.sqrt(svar*(1.0/n)) |
| prob = betai(0.5*df,0.5,float(df)/(df+t*t)) |
| |
| if printit <> 0: |
| statname = 'Single-sample T-test.' |
| outputpairedstats(printit,writemode, |
| 'Population','--',popmean,0,0,0, |
| name,n,x,v,min(a),max(a), |
| statname,t,prob) |
| return t,prob |
| |
| |
| def lttest_ind (a, b, printit=0, name1='Samp1', name2='Samp2', writemode='a'): |
| """ |
| Calculates the t-obtained T-test on TWO INDEPENDENT samples of |
| scores a, and b. From Numerical Recipies, p.483. If printit=1, results |
| are printed to the screen. If printit='filename', the results are output |
| to 'filename' using the given writemode (default=append). Returns t-value, |
| and prob. |
| |
| Usage: lttest_ind(a,b,printit=0,name1='Samp1',name2='Samp2',writemode='a') |
| Returns: t-value, two-tailed prob |
| """ |
| x1 = mean(a) |
| x2 = mean(b) |
| v1 = stdev(a)**2 |
| v2 = stdev(b)**2 |
| n1 = len(a) |
| n2 = len(b) |
| df = n1+n2-2 |
| svar = ((n1-1)*v1+(n2-1)*v2)/float(df) |
| if not svar: |
| svar = 1.0e-26 |
| t = (x1-x2)/math.sqrt(svar*(1.0/n1 + 1.0/n2)) |
| prob = betai(0.5*df,0.5,df/(df+t*t)) |
| |
| if printit <> 0: |
| statname = 'Independent samples T-test.' |
| outputpairedstats(printit,writemode, |
| name1,n1,x1,v1,min(a),max(a), |
| name2,n2,x2,v2,min(b),max(b), |
| statname,t,prob) |
| return t,prob |
| |
| |
| def lttest_rel (a,b,printit=0,name1='Sample1',name2='Sample2',writemode='a'): |
| """ |
| Calculates the t-obtained T-test on TWO RELATED samples of scores, |
| a and b. From Numerical Recipies, p.483. If printit=1, results are |
| printed to the screen. If printit='filename', the results are output to |
| 'filename' using the given writemode (default=append). Returns t-value, |
| and prob. |
| |
| Usage: lttest_rel(a,b,printit=0,name1='Sample1',name2='Sample2',writemode='a') |
| Returns: t-value, two-tailed prob |
| """ |
| if len(a)<>len(b): |
| raise ValueError, 'Unequal length lists in ttest_rel.' |
| x1 = mean(a) |
| x2 = mean(b) |
| v1 = var(a) |
| v2 = var(b) |
| n = len(a) |
| cov = 0 |
| for i in range(len(a)): |
| cov = cov + (a[i]-x1) * (b[i]-x2) |
| df = n-1 |
| cov = cov / float(df) |
| sd = math.sqrt((v1+v2 - 2.0*cov)/float(n)) |
| t = (x1-x2)/sd |
| prob = betai(0.5*df,0.5,df/(df+t*t)) |
| |
| if printit <> 0: |
| statname = 'Related samples T-test.' |
| outputpairedstats(printit,writemode, |
| name1,n,x1,v1,min(a),max(a), |
| name2,n,x2,v2,min(b),max(b), |
| statname,t,prob) |
| return t, prob |
| |
| |
| def lchisquare(f_obs,f_exp=None): |
| """ |
| Calculates a one-way chi square for list of observed frequencies and returns |
| the result. If no expected frequencies are given, the total N is assumed to |
| be equally distributed across all groups. |
| |
| Usage: lchisquare(f_obs, f_exp=None) f_obs = list of observed cell freq. |
| Returns: chisquare-statistic, associated p-value |
| """ |
| k = len(f_obs) # number of groups |
| if f_exp == None: |
| f_exp = [sum(f_obs)/float(k)] * len(f_obs) # create k bins with = freq. |
| chisq = 0 |
| for i in range(len(f_obs)): |
| chisq = chisq + (f_obs[i]-f_exp[i])**2 / float(f_exp[i]) |
| return chisq, chisqprob(chisq, k-1) |
| |
| |
| def lks_2samp (data1,data2): |
| """ |
| Computes the Kolmogorov-Smirnof statistic on 2 samples. From |
| Numerical Recipies in C, page 493. |
| |
| Usage: lks_2samp(data1,data2) data1&2 are lists of values for 2 conditions |
| Returns: KS D-value, associated p-value |
| """ |
| j1 = 0 |
| j2 = 0 |
| fn1 = 0.0 |
| fn2 = 0.0 |
| n1 = len(data1) |
| n2 = len(data2) |
| en1 = n1 |
| en2 = n2 |
| d = 0.0 |
| data1.sort() |
| data2.sort() |
| while j1 < n1 and j2 < n2: |
| d1=data1[j1] |
| d2=data2[j2] |
| if d1 <= d2: |
| fn1 = (j1)/float(en1) |
| j1 = j1 + 1 |
| if d2 <= d1: |
| fn2 = (j2)/float(en2) |
| j2 = j2 + 1 |
| dt = (fn2-fn1) |
| if math.fabs(dt) > math.fabs(d): |
| d = dt |
| try: |
| en = math.sqrt(en1*en2/float(en1+en2)) |
| prob = ksprob((en+0.12+0.11/en)*abs(d)) |
| except: |
| prob = 1.0 |
| return d, prob |
| |
| |
| def lmannwhitneyu(x,y): |
| """ |
| Calculates a Mann-Whitney U statistic on the provided scores and |
| returns the result. Use only when the n in each condition is < 20 and |
| you have 2 independent samples of ranks. NOTE: Mann-Whitney U is |
| significant if the u-obtained is LESS THAN or equal to the critical |
| value of U found in the tables. Equivalent to Kruskal-Wallis H with |
| just 2 groups. |
| |
| Usage: lmannwhitneyu(data) |
| Returns: u-statistic, one-tailed p-value (i.e., p(z(U))) |
| """ |
| n1 = len(x) |
| n2 = len(y) |
| ranked = rankdata(x+y) |
| rankx = ranked[0:n1] # get the x-ranks |
| ranky = ranked[n1:] # the rest are y-ranks |
| u1 = n1*n2 + (n1*(n1+1))/2.0 - sum(rankx) # calc U for x |
| u2 = n1*n2 - u1 # remainder is U for y |
| bigu = max(u1,u2) |
| smallu = min(u1,u2) |
| proportion = bigu/float(n1*n2) |
| T = math.sqrt(tiecorrect(ranked)) # correction factor for tied scores |
| if T == 0: |
| raise ValueError, 'All numbers are identical in lmannwhitneyu' |
| sd = math.sqrt(T*n1*n2*(n1+n2+1)/12.0) |
| z = abs((bigu-n1*n2/2.0) / sd) # normal approximation for prob calc |
| return smallu, 1.0 - zprob(z) #, proportion |
| |
| |
| def ltiecorrect(rankvals): |
| """ |
| Corrects for ties in Mann Whitney U and Kruskal Wallis H tests. See |
| Siegel, S. (1956) Nonparametric Statistics for the Behavioral Sciences. |
| New York: McGraw-Hill. Code adapted from |Stat rankind.c code. |
| |
| Usage: ltiecorrect(rankvals) |
| Returns: T correction factor for U or H |
| """ |
| sorted,posn = shellsort(rankvals) |
| n = len(sorted) |
| T = 0.0 |
| i = 0 |
| while (i<n-1): |
| if sorted[i] == sorted[i+1]: |
| nties = 1 |
| while (i<n-1) and (sorted[i] == sorted[i+1]): |
| nties = nties +1 |
| i = i +1 |
| T = T + nties**3 - nties |
| i = i+1 |
| T = T / float(n**3-n) |
| return 1.0 - T |
| |
| |
| def lranksums(x,y): |
| """ |
| Calculates the rank sums statistic on the provided scores and |
| returns the result. Use only when the n in each condition is > 20 and you |
| have 2 independent samples of ranks. |
| |
| Usage: lranksums(x,y) |
| Returns: a z-statistic, two-tailed p-value |
| """ |
| n1 = len(x) |
| n2 = len(y) |
| alldata = x+y |
| ranked = rankdata(alldata) |
| x = ranked[:n1] |
| y = ranked[n1:] |
| s = sum(x) |
| expected = n1*(n1+n2+1) / 2.0 |
| z = (s - expected) / math.sqrt(n1*n2*(n1+n2+1)/12.0) |
| prob = 2*(1.0 -zprob(abs(z))) |
| return z, prob |
| |
| |
| def lwilcoxont(x,y): |
| """ |
| Calculates the Wilcoxon T-test for related samples and returns the |
| result. A non-parametric T-test. |
| |
| Usage: lwilcoxont(x,y) |
| Returns: a t-statistic, two-tail probability estimate |
| """ |
| if len(x) <> len(y): |
| raise ValueError, 'Unequal N in wilcoxont. Aborting.' |
| d=[] |
| for i in range(len(x)): |
| diff = x[i] - y[i] |
| if diff <> 0: |
| d.append(diff) |
| count = len(d) |
| absd = map(abs,d) |
| absranked = rankdata(absd) |
| r_plus = 0.0 |
| r_minus = 0.0 |
| for i in range(len(absd)): |
| if d[i] < 0: |
| r_minus = r_minus + absranked[i] |
| else: |
| r_plus = r_plus + absranked[i] |
| wt = min(r_plus, r_minus) |
| mn = count * (count+1) * 0.25 |
| se = math.sqrt(count*(count+1)*(2.0*count+1.0)/24.0) |
| z = math.fabs(wt-mn) / se |
| prob = 2*(1.0 -zprob(abs(z))) |
| return wt, prob |
| |
| |
| def lkruskalwallish(*args): |
| """ |
| The Kruskal-Wallis H-test is a non-parametric ANOVA for 3 or more |
| groups, requiring at least 5 subjects in each group. This function |
| calculates the Kruskal-Wallis H-test for 3 or more independent samples |
| and returns the result. |
| |
| Usage: lkruskalwallish(*args) |
| Returns: H-statistic (corrected for ties), associated p-value |
| """ |
| args = list(args) |
| n = [0]*len(args) |
| all = [] |
| n = map(len,args) |
| for i in range(len(args)): |
| all = all + args[i] |
| ranked = rankdata(all) |
| T = tiecorrect(ranked) |
| for i in range(len(args)): |
| args[i] = ranked[0:n[i]] |
| del ranked[0:n[i]] |
| rsums = [] |
| for i in range(len(args)): |
| rsums.append(sum(args[i])**2) |
| rsums[i] = rsums[i] / float(n[i]) |
| ssbn = sum(rsums) |
| totaln = sum(n) |
| h = 12.0 / (totaln*(totaln+1)) * ssbn - 3*(totaln+1) |
| df = len(args) - 1 |
| if T == 0: |
| raise ValueError, 'All numbers are identical in lkruskalwallish' |
| h = h / float(T) |
| return h, chisqprob(h,df) |
| |
| |
| def lfriedmanchisquare(*args): |
| """ |
| Friedman Chi-Square is a non-parametric, one-way within-subjects |
| ANOVA. This function calculates the Friedman Chi-square test for repeated |
| measures and returns the result, along with the associated probability |
| value. It assumes 3 or more repeated measures. Only 3 levels requires a |
| minimum of 10 subjects in the study. Four levels requires 5 subjects per |
| level(??). |
| |
| Usage: lfriedmanchisquare(*args) |
| Returns: chi-square statistic, associated p-value |
| """ |
| k = len(args) |
| if k < 3: |
| raise ValueError, 'Less than 3 levels. Friedman test not appropriate.' |
| n = len(args[0]) |
| data = apply(pstat.abut,tuple(args)) |
| for i in range(len(data)): |
| data[i] = rankdata(data[i]) |
| ssbn = 0 |
| for i in range(k): |
| ssbn = ssbn + sum(args[i])**2 |
| chisq = 12.0 / (k*n*(k+1)) * ssbn - 3*n*(k+1) |
| return chisq, chisqprob(chisq,k-1) |
| |
| |
| #################################### |
| #### PROBABILITY CALCULATIONS #### |
| #################################### |
| |
| def lchisqprob(chisq,df): |
| """ |
| Returns the (1-tailed) probability value associated with the provided |
| chi-square value and df. Adapted from chisq.c in Gary Perlman's |Stat. |
| |
| Usage: lchisqprob(chisq,df) |
| """ |
| BIG = 20.0 |
| def ex(x): |
| BIG = 20.0 |
| if x < -BIG: |
| return 0.0 |
| else: |
| return math.exp(x) |
| |
| if chisq <=0 or df < 1: |
| return 1.0 |
| a = 0.5 * chisq |
| if df%2 == 0: |
| even = 1 |
| else: |
| even = 0 |
| if df > 1: |
| y = ex(-a) |
| if even: |
| s = y |
| else: |
| s = 2.0 * zprob(-math.sqrt(chisq)) |
| if (df > 2): |
| chisq = 0.5 * (df - 1.0) |
| if even: |
| z = 1.0 |
| else: |
| z = 0.5 |
| if a > BIG: |
| if even: |
| e = 0.0 |
| else: |
| e = math.log(math.sqrt(math.pi)) |
| c = math.log(a) |
| while (z <= chisq): |
| e = math.log(z) + e |
| s = s + ex(c*z-a-e) |
| z = z + 1.0 |
| return s |
| else: |
| if even: |
| e = 1.0 |
| else: |
| e = 1.0 / math.sqrt(math.pi) / math.sqrt(a) |
| c = 0.0 |
| while (z <= chisq): |
| e = e * (a/float(z)) |
| c = c + e |
| z = z + 1.0 |
| return (c*y+s) |
| else: |
| return s |
| |
| |
| def lerfcc(x): |
| """ |
| Returns the complementary error function erfc(x) with fractional |
| error everywhere less than 1.2e-7. Adapted from Numerical Recipies. |
| |
| Usage: lerfcc(x) |
| """ |
| z = abs(x) |
| t = 1.0 / (1.0+0.5*z) |
| ans = t * math.exp(-z*z-1.26551223 + t*(1.00002368+t*(0.37409196+t*(0.09678418+t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+t*(-0.82215223+t*0.17087277))))))))) |
| if x >= 0: |
| return ans |
| else: |
| return 2.0 - ans |
| |
| |
| def lzprob(z): |
| """ |
| Returns the area under the normal curve 'to the left of' the given z value. |
| Thus, |
| for z<0, zprob(z) = 1-tail probability |
| for z>0, 1.0-zprob(z) = 1-tail probability |
| for any z, 2.0*(1.0-zprob(abs(z))) = 2-tail probability |
| Adapted from z.c in Gary Perlman's |Stat. |
| |
| Usage: lzprob(z) |
| """ |
| Z_MAX = 6.0 # maximum meaningful z-value |
| if z == 0.0: |
| x = 0.0 |
| else: |
| y = 0.5 * math.fabs(z) |
| if y >= (Z_MAX*0.5): |
| x = 1.0 |
| elif (y < 1.0): |
| w = y*y |
| x = ((((((((0.000124818987 * w |
| -0.001075204047) * w +0.005198775019) * w |
| -0.019198292004) * w +0.059054035642) * w |
| -0.151968751364) * w +0.319152932694) * w |
| -0.531923007300) * w +0.797884560593) * y * 2.0 |
| else: |
| y = y - 2.0 |
| x = (((((((((((((-0.000045255659 * y |
| +0.000152529290) * y -0.000019538132) * y |
| -0.000676904986) * y +0.001390604284) * y |
| -0.000794620820) * y -0.002034254874) * y |
| +0.006549791214) * y -0.010557625006) * y |
| +0.011630447319) * y -0.009279453341) * y |
| +0.005353579108) * y -0.002141268741) * y |
| +0.000535310849) * y +0.999936657524 |
| if z > 0.0: |
| prob = ((x+1.0)*0.5) |
| else: |
| prob = ((1.0-x)*0.5) |
| return prob |
| |
| |
| def lksprob(alam): |
| """ |
| Computes a Kolmolgorov-Smirnov t-test significance level. Adapted from |
| Numerical Recipies. |
| |
| Usage: lksprob(alam) |
| """ |
| fac = 2.0 |
| sum = 0.0 |
| termbf = 0.0 |
| a2 = -2.0*alam*alam |
| for j in range(1,201): |
| term = fac*math.exp(a2*j*j) |
| sum = sum + term |
| if math.fabs(term) <= (0.001*termbf) or math.fabs(term) < (1.0e-8*sum): |
| return sum |
| fac = -fac |
| termbf = math.fabs(term) |
| return 1.0 # Get here only if fails to converge; was 0.0!! |
| |
| |
| def lfprob (dfnum, dfden, F): |
| """ |
| Returns the (1-tailed) significance level (p-value) of an F |
| statistic given the degrees of freedom for the numerator (dfR-dfF) and |
| the degrees of freedom for the denominator (dfF). |
| |
| Usage: lfprob(dfnum, dfden, F) where usually dfnum=dfbn, dfden=dfwn |
| """ |
| p = betai(0.5*dfden, 0.5*dfnum, dfden/float(dfden+dfnum*F)) |
| return p |
| |
| |
| def lbetacf(a,b,x): |
| """ |
| This function evaluates the continued fraction form of the incomplete |
| Beta function, betai. (Adapted from: Numerical Recipies in C.) |
| |
| Usage: lbetacf(a,b,x) |
| """ |
| ITMAX = 200 |
| EPS = 3.0e-7 |
| |
| bm = az = am = 1.0 |
| qab = a+b |
| qap = a+1.0 |
| qam = a-1.0 |
| bz = 1.0-qab*x/qap |
| for i in range(ITMAX+1): |
| em = float(i+1) |
| tem = em + em |
| d = em*(b-em)*x/((qam+tem)*(a+tem)) |
| ap = az + d*am |
| bp = bz+d*bm |
| d = -(a+em)*(qab+em)*x/((qap+tem)*(a+tem)) |
| app = ap+d*az |
| bpp = bp+d*bz |
| aold = az |
| am = ap/bpp |
| bm = bp/bpp |
| az = app/bpp |
| bz = 1.0 |
| if (abs(az-aold)<(EPS*abs(az))): |
| return az |
| print 'a or b too big, or ITMAX too small in Betacf.' |
| |
| |
| def lgammln(xx): |
| """ |
| Returns the gamma function of xx. |
| Gamma(z) = Integral(0,infinity) of t^(z-1)exp(-t) dt. |
| (Adapted from: Numerical Recipies in C.) |
| |
| Usage: lgammln(xx) |
| """ |
| |
| coeff = [76.18009173, -86.50532033, 24.01409822, -1.231739516, |
| 0.120858003e-2, -0.536382e-5] |
| x = xx - 1.0 |
| tmp = x + 5.5 |
| tmp = tmp - (x+0.5)*math.log(tmp) |
| ser = 1.0 |
| for j in range(len(coeff)): |
| x = x + 1 |
| ser = ser + coeff[j]/x |
| return -tmp + math.log(2.50662827465*ser) |
| |
| |
| def lbetai(a,b,x): |
| """ |
| Returns the incomplete beta function: |
| |
| I-sub-x(a,b) = 1/B(a,b)*(Integral(0,x) of t^(a-1)(1-t)^(b-1) dt) |
| |
| where a,b>0 and B(a,b) = G(a)*G(b)/(G(a+b)) where G(a) is the gamma |
| function of a. The continued fraction formulation is implemented here, |
| using the betacf function. (Adapted from: Numerical Recipies in C.) |
| |
| Usage: lbetai(a,b,x) |
| """ |
| if (x<0.0 or x>1.0): |
| raise ValueError, 'Bad x in lbetai' |
| if (x==0.0 or x==1.0): |
| bt = 0.0 |
| else: |
| bt = math.exp(gammln(a+b)-gammln(a)-gammln(b)+a*math.log(x)+b* |
| math.log(1.0-x)) |
| if (x<(a+1.0)/(a+b+2.0)): |
| return bt*betacf(a,b,x)/float(a) |
| else: |
| return 1.0-bt*betacf(b,a,1.0-x)/float(b) |
| |
| |
| #################################### |
| ####### ANOVA CALCULATIONS ####### |
| #################################### |
| |
| def lF_oneway(*lists): |
| """ |
| Performs a 1-way ANOVA, returning an F-value and probability given |
| any number of groups. From Heiman, pp.394-7. |
| |
| Usage: F_oneway(*lists) where *lists is any number of lists, one per |
| treatment group |
| Returns: F value, one-tailed p-value |
| """ |
| a = len(lists) # ANOVA on 'a' groups, each in it's own list |
| means = [0]*a |
| vars = [0]*a |
| ns = [0]*a |
| alldata = [] |
| tmp = map(N.array,lists) |
| means = map(amean,tmp) |
| vars = map(avar,tmp) |
| ns = map(len,lists) |
| for i in range(len(lists)): |
| alldata = alldata + lists[i] |
| alldata = N.array(alldata) |
| bign = len(alldata) |
| sstot = ass(alldata)-(asquare_of_sums(alldata)/float(bign)) |
| ssbn = 0 |
| for list in lists: |
| ssbn = ssbn + asquare_of_sums(N.array(list))/float(len(list)) |
| ssbn = ssbn - (asquare_of_sums(alldata)/float(bign)) |
| sswn = sstot-ssbn |
| dfbn = a-1 |
| dfwn = bign - a |
| msb = ssbn/float(dfbn) |
| msw = sswn/float(dfwn) |
| f = msb/msw |
| prob = fprob(dfbn,dfwn,f) |
| return f, prob |
| |
| |
| def lF_value (ER,EF,dfnum,dfden): |
| """ |
| Returns an F-statistic given the following: |
| ER = error associated with the null hypothesis (the Restricted model) |
| EF = error associated with the alternate hypothesis (the Full model) |
| dfR-dfF = degrees of freedom of the numerator |
| dfF = degrees of freedom associated with the denominator/Full model |
| |
| Usage: lF_value(ER,EF,dfnum,dfden) |
| """ |
| return ((ER-EF)/float(dfnum) / (EF/float(dfden))) |
| |
| |
| #################################### |
| ######## SUPPORT FUNCTIONS ####### |
| #################################### |
| |
| def writecc (listoflists,file,writetype='w',extra=2): |
| """ |
| Writes a list of lists to a file in columns, customized by the max |
| size of items within the columns (max size of items in col, +2 characters) |
| to specified file. File-overwrite is the default. |
| |
| Usage: writecc (listoflists,file,writetype='w',extra=2) |
| Returns: None |
| """ |
| if type(listoflists[0]) not in [ListType,TupleType]: |
| listoflists = [listoflists] |
| outfile = open(file,writetype) |
| rowstokill = [] |
| list2print = copy.deepcopy(listoflists) |
| for i in range(len(listoflists)): |
| if listoflists[i] == ['\n'] or listoflists[i]=='\n' or listoflists[i]=='dashes': |
| rowstokill = rowstokill + [i] |
| rowstokill.reverse() |
| for row in rowstokill: |
| del list2print[row] |
| maxsize = [0]*len(list2print[0]) |
| for col in range(len(list2print[0])): |
| items = pstat.colex(list2print,col) |
| items = map(pstat.makestr,items) |
| maxsize[col] = max(map(len,items)) + extra |
| for row in listoflists: |
| if row == ['\n'] or row == '\n': |
| outfile.write('\n') |
| elif row == ['dashes'] or row == 'dashes': |
| dashes = [0]*len(maxsize) |
| for j in range(len(maxsize)): |
| dashes[j] = '-'*(maxsize[j]-2) |
| outfile.write(pstat.lineincustcols(dashes,maxsize)) |
| else: |
| outfile.write(pstat.lineincustcols(row,maxsize)) |
| outfile.write('\n') |
| outfile.close() |
| return None |
| |
| |
| def lincr(l,cap): # to increment a list up to a max-list of 'cap' |
| """ |
| Simulate a counting system from an n-dimensional list. |
| |
| Usage: lincr(l,cap) l=list to increment, cap=max values for each list pos'n |
| Returns: next set of values for list l, OR -1 (if overflow) |
| """ |
| l[0] = l[0] + 1 # e.g., [0,0,0] --> [2,4,3] (=cap) |
| for i in range(len(l)): |
| if l[i] > cap[i] and i < len(l)-1: # if carryover AND not done |
| l[i] = 0 |
| l[i+1] = l[i+1] + 1 |
| elif l[i] > cap[i] and i == len(l)-1: # overflow past last column, must be finished |
| l = -1 |
| return l |
| |
| |
| def lsum (inlist): |
| """ |
| Returns the sum of the items in the passed list. |
| |
| Usage: lsum(inlist) |
| """ |
| s = 0 |
| for item in inlist: |
| s = s + item |
| return s |
| |
| |
| def lcumsum (inlist): |
| """ |
| Returns a list consisting of the cumulative sum of the items in the |
| passed list. |
| |
| Usage: lcumsum(inlist) |
| """ |
| newlist = copy.deepcopy(inlist) |
| for i in range(1,len(newlist)): |
| newlist[i] = newlist[i] + newlist[i-1] |
| return newlist |
| |
| |
| def lss(inlist): |
| """ |
| Squares each value in the passed list, adds up these squares and |
| returns the result. |
| |
| Usage: lss(inlist) |
| """ |
| ss = 0 |
| for item in inlist: |
| ss = ss + item*item |
| return ss |
| |
| |
| def lsummult (list1,list2): |
| """ |
| Multiplies elements in list1 and list2, element by element, and |
| returns the sum of all resulting multiplications. Must provide equal |
| length lists. |
| |
| Usage: lsummult(list1,list2) |
| """ |
| if len(list1) <> len(list2): |
| raise ValueError, "Lists not equal length in summult." |
| s = 0 |
| for item1,item2 in pstat.abut(list1,list2): |
| s = s + item1*item2 |
| return s |
| |
| |
| def lsumdiffsquared(x,y): |
| """ |
| Takes pairwise differences of the values in lists x and y, squares |
| these differences, and returns the sum of these squares. |
| |
| Usage: lsumdiffsquared(x,y) |
| Returns: sum[(x[i]-y[i])**2] |
| """ |
| sds = 0 |
| for i in range(len(x)): |
| sds = sds + (x[i]-y[i])**2 |
| return sds |
| |
| |
| def lsquare_of_sums(inlist): |
| """ |
| Adds the values in the passed list, squares the sum, and returns |
| the result. |
| |
| Usage: lsquare_of_sums(inlist) |
| Returns: sum(inlist[i])**2 |
| """ |
| s = sum(inlist) |
| return float(s)*s |
| |
| |
| def lshellsort(inlist): |
| """ |
| Shellsort algorithm. Sorts a 1D-list. |
| |
| Usage: lshellsort(inlist) |
| Returns: sorted-inlist, sorting-index-vector (for original list) |
| """ |
| n = len(inlist) |
| svec = copy.deepcopy(inlist) |
| ivec = range(n) |
| gap = n/2 # integer division needed |
| while gap >0: |
| for i in range(gap,n): |
| for j in range(i-gap,-1,-gap): |
| while j>=0 and svec[j]>svec[j+gap]: |
| temp = svec[j] |
| svec[j] = svec[j+gap] |
| svec[j+gap] = temp |
| itemp = ivec[j] |
| ivec[j] = ivec[j+gap] |
| ivec[j+gap] = itemp |
| gap = gap / 2 # integer division needed |
| # svec is now sorted inlist, and ivec has the order svec[i] = vec[ivec[i]] |
| return svec, ivec |
| |
| |
| def lrankdata(inlist): |
| """ |
| Ranks the data in inlist, dealing with ties appropritely. Assumes |
| a 1D inlist. Adapted from Gary Perlman's |Stat ranksort. |
| |
| Usage: lrankdata(inlist) |
| Returns: a list of length equal to inlist, containing rank scores |
| """ |
| n = len(inlist) |
| svec, ivec = shellsort(inlist) |
| sumranks = 0 |
| dupcount = 0 |
| newlist = [0]*n |
| for i in range(n): |
| sumranks = sumranks + i |
| dupcount = dupcount + 1 |
| if i==n-1 or svec[i] <> svec[i+1]: |
| averank = sumranks / float(dupcount) + 1 |
| for j in range(i-dupcount+1,i+1): |
| newlist[ivec[j]] = averank |
| sumranks = 0 |
| dupcount = 0 |
| return newlist |
| |
| |
| def outputpairedstats(fname,writemode,name1,n1,m1,se1,min1,max1,name2,n2,m2,se2,min2,max2,statname,stat,prob): |
| """ |
| Prints or write to a file stats for two groups, using the name, n, |
| mean, sterr, min and max for each group, as well as the statistic name, |
| its value, and the associated p-value. |
| |
| Usage: outputpairedstats(fname,writemode, |
| name1,n1,mean1,stderr1,min1,max1, |
| name2,n2,mean2,stderr2,min2,max2, |
| statname,stat,prob) |
| Returns: None |
| """ |
| suffix = '' # for *s after the p-value |
| try: |
| x = prob.shape |
| prob = prob[0] |
| except: |
| pass |
| if prob < 0.001: suffix = ' ***' |
| elif prob < 0.01: suffix = ' **' |
| elif prob < 0.05: suffix = ' *' |
| title = [['Name','N','Mean','SD','Min','Max']] |
| lofl = title+[[name1,n1,round(m1,3),round(math.sqrt(se1),3),min1,max1], |
| [name2,n2,round(m2,3),round(math.sqrt(se2),3),min2,max2]] |
| if type(fname)<>StringType or len(fname)==0: |
| print |
| print statname |
| print |
| pstat.printcc(lofl) |
| print |
| try: |
| if stat.shape == (): |
| stat = stat[0] |
| if prob.shape == (): |
| prob = prob[0] |
| except: |
| pass |
| print 'Test statistic = ',round(stat,3),' p = ',round(prob,3),suffix |
| print |
| else: |
| file = open(fname,writemode) |
| file.write('\n'+statname+'\n\n') |
| file.close() |
| writecc(lofl,fname,'a') |
| file = open(fname,'a') |
| try: |
| if stat.shape == (): |
| stat = stat[0] |
| if prob.shape == (): |
| prob = prob[0] |
| except: |
| pass |
| file.write(pstat.list2string(['\nTest statistic = ',round(stat,4),' p = ',round(prob,4),suffix,'\n\n'])) |
| file.close() |
| return None |
| |
| |
| def lfindwithin (data): |
| """ |
| Returns an integer representing a binary vector, where 1=within- |
| subject factor, 0=between. Input equals the entire data 2D list (i.e., |
| column 0=random factor, column -1=measured values (those two are skipped). |
| Note: input data is in |Stat format ... a list of lists ("2D list") with |
| one row per measured value, first column=subject identifier, last column= |
| score, one in-between column per factor (these columns contain level |
| designations on each factor). See also stats.anova.__doc__. |
| |
| Usage: lfindwithin(data) data in |Stat format |
| """ |
| |
| numfact = len(data[0])-1 |
| withinvec = 0 |
| for col in range(1,numfact): |
| examplelevel = pstat.unique(pstat.colex(data,col))[0] |
| rows = pstat.linexand(data,col,examplelevel) # get 1 level of this factor |
| factsubjs = pstat.unique(pstat.colex(rows,0)) |
| allsubjs = pstat.unique(pstat.colex(data,0)) |
| if len(factsubjs) == len(allsubjs): # fewer Ss than scores on this factor? |
| withinvec = withinvec + (1 << col) |
| return withinvec |
| |
| |
| ######################################################### |
| ######################################################### |
| ####### DISPATCH LISTS AND TUPLES TO ABOVE FCNS ######### |
| ######################################################### |
| ######################################################### |
| |
| ## CENTRAL TENDENCY: |
| geometricmean = Dispatch ( (lgeometricmean, (ListType, TupleType)), ) |
| harmonicmean = Dispatch ( (lharmonicmean, (ListType, TupleType)), ) |
| mean = Dispatch ( (lmean, (ListType, TupleType)), ) |
| median = Dispatch ( (lmedian, (ListType, TupleType)), ) |
| medianscore = Dispatch ( (lmedianscore, (ListType, TupleType)), ) |
| mode = Dispatch ( (lmode, (ListType, TupleType)), ) |
| |
| ## MOMENTS: |
| moment = Dispatch ( (lmoment, (ListType, TupleType)), ) |
| variation = Dispatch ( (lvariation, (ListType, TupleType)), ) |
| skew = Dispatch ( (lskew, (ListType, TupleType)), ) |
| kurtosis = Dispatch ( (lkurtosis, (ListType, TupleType)), ) |
| describe = Dispatch ( (ldescribe, (ListType, TupleType)), ) |
| |
| ## FREQUENCY STATISTICS: |
| itemfreq = Dispatch ( (litemfreq, (ListType, TupleType)), ) |
| scoreatpercentile = Dispatch ( (lscoreatpercentile, (ListType, TupleType)), ) |
| percentileofscore = Dispatch ( (lpercentileofscore, (ListType, TupleType)), ) |
| histogram = Dispatch ( (lhistogram, (ListType, TupleType)), ) |
| cumfreq = Dispatch ( (lcumfreq, (ListType, TupleType)), ) |
| relfreq = Dispatch ( (lrelfreq, (ListType, TupleType)), ) |
| |
| ## VARIABILITY: |
| obrientransform = Dispatch ( (lobrientransform, (ListType, TupleType)), ) |
| samplevar = Dispatch ( (lsamplevar, (ListType, TupleType)), ) |
| samplestdev = Dispatch ( (lsamplestdev, (ListType, TupleType)), ) |
| var = Dispatch ( (lvar, (ListType, TupleType)), ) |
| stdev = Dispatch ( (lstdev, (ListType, TupleType)), ) |
| sterr = Dispatch ( (lsterr, (ListType, TupleType)), ) |
| sem = Dispatch ( (lsem, (ListType, TupleType)), ) |
| z = Dispatch ( (lz, (ListType, TupleType)), ) |
| zs = Dispatch ( (lzs, (ListType, TupleType)), ) |
| |
| ## TRIMMING FCNS: |
| trimboth = Dispatch ( (ltrimboth, (ListType, TupleType)), ) |
| trim1 = Dispatch ( (ltrim1, (ListType, TupleType)), ) |
| |
| ## CORRELATION FCNS: |
| paired = Dispatch ( (lpaired, (ListType, TupleType)), ) |
| pearsonr = Dispatch ( (lpearsonr, (ListType, TupleType)), ) |
| spearmanr = Dispatch ( (lspearmanr, (ListType, TupleType)), ) |
| pointbiserialr = Dispatch ( (lpointbiserialr, (ListType, TupleType)), ) |
| kendalltau = Dispatch ( (lkendalltau, (ListType, TupleType)), ) |
| linregress = Dispatch ( (llinregress, (ListType, TupleType)), ) |
| |
| ## INFERENTIAL STATS: |
| ttest_1samp = Dispatch ( (lttest_1samp, (ListType, TupleType)), ) |
| ttest_ind = Dispatch ( (lttest_ind, (ListType, TupleType)), ) |
| ttest_rel = Dispatch ( (lttest_rel, (ListType, TupleType)), ) |
| chisquare = Dispatch ( (lchisquare, (ListType, TupleType)), ) |
| ks_2samp = Dispatch ( (lks_2samp, (ListType, TupleType)), ) |
| mannwhitneyu = Dispatch ( (lmannwhitneyu, (ListType, TupleType)), ) |
| ranksums = Dispatch ( (lranksums, (ListType, TupleType)), ) |
| tiecorrect = Dispatch ( (ltiecorrect, (ListType, TupleType)), ) |
| wilcoxont = Dispatch ( (lwilcoxont, (ListType, TupleType)), ) |
| kruskalwallish = Dispatch ( (lkruskalwallish, (ListType, TupleType)), ) |
| friedmanchisquare = Dispatch ( (lfriedmanchisquare, (ListType, TupleType)), ) |
| |
| ## PROBABILITY CALCS: |
| chisqprob = Dispatch ( (lchisqprob, (IntType, FloatType)), ) |
| zprob = Dispatch ( (lzprob, (IntType, FloatType)), ) |
| ksprob = Dispatch ( (lksprob, (IntType, FloatType)), ) |
| fprob = Dispatch ( (lfprob, (IntType, FloatType)), ) |
| betacf = Dispatch ( (lbetacf, (IntType, FloatType)), ) |
| betai = Dispatch ( (lbetai, (IntType, FloatType)), ) |
| erfcc = Dispatch ( (lerfcc, (IntType, FloatType)), ) |
| gammln = Dispatch ( (lgammln, (IntType, FloatType)), ) |
| |
| ## ANOVA FUNCTIONS: |
| F_oneway = Dispatch ( (lF_oneway, (ListType, TupleType)), ) |
| F_value = Dispatch ( (lF_value, (ListType, TupleType)), ) |
| |
| ## SUPPORT FUNCTIONS: |
| incr = Dispatch ( (lincr, (ListType, TupleType)), ) |
| sum = Dispatch ( (lsum, (ListType, TupleType)), ) |
| cumsum = Dispatch ( (lcumsum, (ListType, TupleType)), ) |
| ss = Dispatch ( (lss, (ListType, TupleType)), ) |
| summult = Dispatch ( (lsummult, (ListType, TupleType)), ) |
| square_of_sums = Dispatch ( (lsquare_of_sums, (ListType, TupleType)), ) |
| sumdiffsquared = Dispatch ( (lsumdiffsquared, (ListType, TupleType)), ) |
| shellsort = Dispatch ( (lshellsort, (ListType, TupleType)), ) |
| rankdata = Dispatch ( (lrankdata, (ListType, TupleType)), ) |
| findwithin = Dispatch ( (lfindwithin, (ListType, TupleType)), ) |
| |
| |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| #============= THE ARRAY-VERSION OF THE STATS FUNCTIONS =============== |
| |
| try: # DEFINE THESE *ONLY* IF NUMERIC IS AVAILABLE |
| import numpy as N |
| import numpy.linalg as LA |
| |
| |
| ##################################### |
| ######## ACENTRAL TENDENCY ######## |
| ##################################### |
| |
| def ageometricmean (inarray,dimension=None,keepdims=0): |
| """ |
| Calculates the geometric mean of the values in the passed array. |
| That is: n-th root of (x1 * x2 * ... * xn). Defaults to ALL values in |
| the passed array. Use dimension=None to flatten array first. REMEMBER: if |
| dimension=0, it collapses over dimension 0 ('rows' in a 2D array) only, and |
| if dimension is a sequence, it collapses over all specified dimensions. If |
| keepdims is set to 1, the resulting array will have as many dimensions as |
| inarray, with only 1 'level' per dim that was collapsed over. |
| |
| Usage: ageometricmean(inarray,dimension=None,keepdims=0) |
| Returns: geometric mean computed over dim(s) listed in dimension |
| """ |
| inarray = N.array(inarray,N.float_) |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| size = len(inarray) |
| mult = N.power(inarray,1.0/size) |
| mult = N.multiply.reduce(mult) |
| elif type(dimension) in [IntType,FloatType]: |
| size = inarray.shape[dimension] |
| mult = N.power(inarray,1.0/size) |
| mult = N.multiply.reduce(mult,dimension) |
| if keepdims == 1: |
| shp = list(inarray.shape) |
| shp[dimension] = 1 |
| sum = N.reshape(sum,shp) |
| else: # must be a SEQUENCE of dims to average over |
| dims = list(dimension) |
| dims.sort() |
| dims.reverse() |
| size = N.array(N.multiply.reduce(N.take(inarray.shape,dims)),N.float_) |
| mult = N.power(inarray,1.0/size) |
| for dim in dims: |
| mult = N.multiply.reduce(mult,dim) |
| if keepdims == 1: |
| shp = list(inarray.shape) |
| for dim in dims: |
| shp[dim] = 1 |
| mult = N.reshape(mult,shp) |
| return mult |
| |
| |
| def aharmonicmean (inarray,dimension=None,keepdims=0): |
| """ |
| Calculates the harmonic mean of the values in the passed array. |
| That is: n / (1/x1 + 1/x2 + ... + 1/xn). Defaults to ALL values in |
| the passed array. Use dimension=None to flatten array first. REMEMBER: if |
| dimension=0, it collapses over dimension 0 ('rows' in a 2D array) only, and |
| if dimension is a sequence, it collapses over all specified dimensions. If |
| keepdims is set to 1, the resulting array will have as many dimensions as |
| inarray, with only 1 'level' per dim that was collapsed over. |
| |
| Usage: aharmonicmean(inarray,dimension=None,keepdims=0) |
| Returns: harmonic mean computed over dim(s) in dimension |
| """ |
| inarray = inarray.astype(N.float_) |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| size = len(inarray) |
| s = N.add.reduce(1.0 / inarray) |
| elif type(dimension) in [IntType,FloatType]: |
| size = float(inarray.shape[dimension]) |
| s = N.add.reduce(1.0/inarray, dimension) |
| if keepdims == 1: |
| shp = list(inarray.shape) |
| shp[dimension] = 1 |
| s = N.reshape(s,shp) |
| else: # must be a SEQUENCE of dims to average over |
| dims = list(dimension) |
| dims.sort() |
| nondims = [] |
| for i in range(len(inarray.shape)): |
| if i not in dims: |
| nondims.append(i) |
| tinarray = N.transpose(inarray,nondims+dims) # put keep-dims first |
| idx = [0] *len(nondims) |
| if idx == []: |
| size = len(N.ravel(inarray)) |
| s = asum(1.0 / inarray) |
| if keepdims == 1: |
| s = N.reshape([s],N.ones(len(inarray.shape))) |
| else: |
| idx[0] = -1 |
| loopcap = N.array(tinarray.shape[0:len(nondims)]) -1 |
| s = N.zeros(loopcap+1,N.float_) |
| while incr(idx,loopcap) <> -1: |
| s[idx] = asum(1.0/tinarray[idx]) |
| size = N.multiply.reduce(N.take(inarray.shape,dims)) |
| if keepdims == 1: |
| shp = list(inarray.shape) |
| for dim in dims: |
| shp[dim] = 1 |
| s = N.reshape(s,shp) |
| return size / s |
| |
| |
| def amean (inarray,dimension=None,keepdims=0): |
| """ |
| Calculates the arithmatic mean of the values in the passed array. |
| That is: 1/n * (x1 + x2 + ... + xn). Defaults to ALL values in the |
| passed array. Use dimension=None to flatten array first. REMEMBER: if |
| dimension=0, it collapses over dimension 0 ('rows' in a 2D array) only, and |
| if dimension is a sequence, it collapses over all specified dimensions. If |
| keepdims is set to 1, the resulting array will have as many dimensions as |
| inarray, with only 1 'level' per dim that was collapsed over. |
| |
| Usage: amean(inarray,dimension=None,keepdims=0) |
| Returns: arithematic mean calculated over dim(s) in dimension |
| """ |
| if inarray.dtype in [N.int_, N.short,N.ubyte]: |
| inarray = inarray.astype(N.float_) |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| sum = N.add.reduce(inarray) |
| denom = float(len(inarray)) |
| elif type(dimension) in [IntType,FloatType]: |
| sum = asum(inarray,dimension) |
| denom = float(inarray.shape[dimension]) |
| if keepdims == 1: |
| shp = list(inarray.shape) |
| shp[dimension] = 1 |
| sum = N.reshape(sum,shp) |
| else: # must be a TUPLE of dims to average over |
| dims = list(dimension) |
| dims.sort() |
| dims.reverse() |
| sum = inarray *1.0 |
| for dim in dims: |
| sum = N.add.reduce(sum,dim) |
| denom = N.array(N.multiply.reduce(N.take(inarray.shape,dims)),N.float_) |
| if keepdims == 1: |
| shp = list(inarray.shape) |
| for dim in dims: |
| shp[dim] = 1 |
| sum = N.reshape(sum,shp) |
| return sum/denom |
| |
| |
| def amedian (inarray,numbins=1000): |
| """ |
| Calculates the COMPUTED median value of an array of numbers, given the |
| number of bins to use for the histogram (more bins approaches finding the |
| precise median value of the array; default number of bins = 1000). From |
| G.W. Heiman's Basic Stats, or CRC Probability & Statistics. |
| NOTE: THIS ROUTINE ALWAYS uses the entire passed array (flattens it first). |
| |
| Usage: amedian(inarray,numbins=1000) |
| Returns: median calculated over ALL values in inarray |
| """ |
| inarray = N.ravel(inarray) |
| (hist, smallest, binsize, extras) = ahistogram(inarray,numbins,[min(inarray),max(inarray)]) |
| cumhist = N.cumsum(hist) # make cumulative histogram |
| otherbins = N.greater_equal(cumhist,len(inarray)/2.0) |
| otherbins = list(otherbins) # list of 0/1s, 1s start at median bin |
| cfbin = otherbins.index(1) # get 1st(!) index holding 50%ile score |
| LRL = smallest + binsize*cfbin # get lower read limit of that bin |
| cfbelow = N.add.reduce(hist[0:cfbin]) # cum. freq. below bin |
| freq = hist[cfbin] # frequency IN the 50%ile bin |
| median = LRL + ((len(inarray)/2.0-cfbelow)/float(freq))*binsize # MEDIAN |
| return median |
| |
| |
| def amedianscore (inarray,dimension=None): |
| """ |
| Returns the 'middle' score of the passed array. If there is an even |
| number of scores, the mean of the 2 middle scores is returned. Can function |
| with 1D arrays, or on the FIRST dimension of 2D arrays (i.e., dimension can |
| be None, to pre-flatten the array, or else dimension must equal 0). |
| |
| Usage: amedianscore(inarray,dimension=None) |
| Returns: 'middle' score of the array, or the mean of the 2 middle scores |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| inarray = N.sort(inarray,dimension) |
| if inarray.shape[dimension] % 2 == 0: # if even number of elements |
| indx = inarray.shape[dimension]/2 # integer division correct |
| median = N.asarray(inarray[indx]+inarray[indx-1]) / 2.0 |
| else: |
| indx = inarray.shape[dimension] / 2 # integer division correct |
| median = N.take(inarray,[indx],dimension) |
| if median.shape == (1,): |
| median = median[0] |
| return median |
| |
| |
| def amode(a, dimension=None): |
| """ |
| Returns an array of the modal (most common) score in the passed array. |
| If there is more than one such score, ONLY THE FIRST is returned. |
| The bin-count for the modal values is also returned. Operates on whole |
| array (dimension=None), or on a given dimension. |
| |
| Usage: amode(a, dimension=None) |
| Returns: array of bin-counts for mode(s), array of corresponding modal values |
| """ |
| |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| scores = pstat.aunique(N.ravel(a)) # get ALL unique values |
| testshape = list(a.shape) |
| testshape[dimension] = 1 |
| oldmostfreq = N.zeros(testshape) |
| oldcounts = N.zeros(testshape) |
| for score in scores: |
| template = N.equal(a,score) |
| counts = asum(template,dimension,1) |
| mostfrequent = N.where(counts>oldcounts,score,oldmostfreq) |
| oldcounts = N.where(counts>oldcounts,counts,oldcounts) |
| oldmostfreq = mostfrequent |
| return oldcounts, mostfrequent |
| |
| |
| def atmean(a,limits=None,inclusive=(1,1)): |
| """ |
| Returns the arithmetic mean of all values in an array, ignoring values |
| strictly outside the sequence passed to 'limits'. Note: either limit |
| in the sequence, or the value of limits itself, can be set to None. The |
| inclusive list/tuple determines whether the lower and upper limiting bounds |
| (respectively) are open/exclusive (0) or closed/inclusive (1). |
| |
| Usage: atmean(a,limits=None,inclusive=(1,1)) |
| """ |
| if a.dtype in [N.int_, N.short,N.ubyte]: |
| a = a.astype(N.float_) |
| if limits == None: |
| return mean(a) |
| assert type(limits) in [ListType,TupleType,N.ndarray], "Wrong type for limits in atmean" |
| if inclusive[0]: lowerfcn = N.greater_equal |
| else: lowerfcn = N.greater |
| if inclusive[1]: upperfcn = N.less_equal |
| else: upperfcn = N.less |
| if limits[0] > N.maximum.reduce(N.ravel(a)) or limits[1] < N.minimum.reduce(N.ravel(a)): |
| raise ValueError, "No array values within given limits (atmean)." |
| elif limits[0]==None and limits[1]<>None: |
| mask = upperfcn(a,limits[1]) |
| elif limits[0]<>None and limits[1]==None: |
| mask = lowerfcn(a,limits[0]) |
| elif limits[0]<>None and limits[1]<>None: |
| mask = lowerfcn(a,limits[0])*upperfcn(a,limits[1]) |
| s = float(N.add.reduce(N.ravel(a*mask))) |
| n = float(N.add.reduce(N.ravel(mask))) |
| return s/n |
| |
| |
| def atvar(a,limits=None,inclusive=(1,1)): |
| """ |
| Returns the sample variance of values in an array, (i.e., using N-1), |
| ignoring values strictly outside the sequence passed to 'limits'. |
| Note: either limit in the sequence, or the value of limits itself, |
| can be set to None. The inclusive list/tuple determines whether the lower |
| and upper limiting bounds (respectively) are open/exclusive (0) or |
| closed/inclusive (1). ASSUMES A FLAT ARRAY (OR ELSE PREFLATTENS). |
| |
| Usage: atvar(a,limits=None,inclusive=(1,1)) |
| """ |
| a = a.astype(N.float_) |
| if limits == None or limits == [None,None]: |
| return avar(a) |
| assert type(limits) in [ListType,TupleType,N.ndarray], "Wrong type for limits in atvar" |
| if inclusive[0]: lowerfcn = N.greater_equal |
| else: lowerfcn = N.greater |
| if inclusive[1]: upperfcn = N.less_equal |
| else: upperfcn = N.less |
| if limits[0] > N.maximum.reduce(N.ravel(a)) or limits[1] < N.minimum.reduce(N.ravel(a)): |
| raise ValueError, "No array values within given limits (atvar)." |
| elif limits[0]==None and limits[1]<>None: |
| mask = upperfcn(a,limits[1]) |
| elif limits[0]<>None and limits[1]==None: |
| mask = lowerfcn(a,limits[0]) |
| elif limits[0]<>None and limits[1]<>None: |
| mask = lowerfcn(a,limits[0])*upperfcn(a,limits[1]) |
| |
| a = N.compress(mask,a) # squish out excluded values |
| return avar(a) |
| |
| |
| def atmin(a,lowerlimit=None,dimension=None,inclusive=1): |
| """ |
| Returns the minimum value of a, along dimension, including only values less |
| than (or equal to, if inclusive=1) lowerlimit. If the limit is set to None, |
| all values in the array are used. |
| |
| Usage: atmin(a,lowerlimit=None,dimension=None,inclusive=1) |
| """ |
| if inclusive: lowerfcn = N.greater |
| else: lowerfcn = N.greater_equal |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| if lowerlimit == None: |
| lowerlimit = N.minimum.reduce(N.ravel(a))-11 |
| biggest = N.maximum.reduce(N.ravel(a)) |
| ta = N.where(lowerfcn(a,lowerlimit),a,biggest) |
| return N.minimum.reduce(ta,dimension) |
| |
| |
| def atmax(a,upperlimit,dimension=None,inclusive=1): |
| """ |
| Returns the maximum value of a, along dimension, including only values greater |
| than (or equal to, if inclusive=1) upperlimit. If the limit is set to None, |
| a limit larger than the max value in the array is used. |
| |
| Usage: atmax(a,upperlimit,dimension=None,inclusive=1) |
| """ |
| if inclusive: upperfcn = N.less |
| else: upperfcn = N.less_equal |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| if upperlimit == None: |
| upperlimit = N.maximum.reduce(N.ravel(a))+1 |
| smallest = N.minimum.reduce(N.ravel(a)) |
| ta = N.where(upperfcn(a,upperlimit),a,smallest) |
| return N.maximum.reduce(ta,dimension) |
| |
| |
| def atstdev(a,limits=None,inclusive=(1,1)): |
| """ |
| Returns the standard deviation of all values in an array, ignoring values |
| strictly outside the sequence passed to 'limits'. Note: either limit |
| in the sequence, or the value of limits itself, can be set to None. The |
| inclusive list/tuple determines whether the lower and upper limiting bounds |
| (respectively) are open/exclusive (0) or closed/inclusive (1). |
| |
| Usage: atstdev(a,limits=None,inclusive=(1,1)) |
| """ |
| return N.sqrt(tvar(a,limits,inclusive)) |
| |
| |
| def atsem(a,limits=None,inclusive=(1,1)): |
| """ |
| Returns the standard error of the mean for the values in an array, |
| (i.e., using N for the denominator), ignoring values strictly outside |
| the sequence passed to 'limits'. Note: either limit in the sequence, |
| or the value of limits itself, can be set to None. The inclusive list/tuple |
| determines whether the lower and upper limiting bounds (respectively) are |
| open/exclusive (0) or closed/inclusive (1). |
| |
| Usage: atsem(a,limits=None,inclusive=(1,1)) |
| """ |
| sd = tstdev(a,limits,inclusive) |
| if limits == None or limits == [None,None]: |
| n = float(len(N.ravel(a))) |
| limits = [min(a)-1, max(a)+1] |
| assert type(limits) in [ListType,TupleType,N.ndarray], "Wrong type for limits in atsem" |
| if inclusive[0]: lowerfcn = N.greater_equal |
| else: lowerfcn = N.greater |
| if inclusive[1]: upperfcn = N.less_equal |
| else: upperfcn = N.less |
| if limits[0] > N.maximum.reduce(N.ravel(a)) or limits[1] < N.minimum.reduce(N.ravel(a)): |
| raise ValueError, "No array values within given limits (atsem)." |
| elif limits[0]==None and limits[1]<>None: |
| mask = upperfcn(a,limits[1]) |
| elif limits[0]<>None and limits[1]==None: |
| mask = lowerfcn(a,limits[0]) |
| elif limits[0]<>None and limits[1]<>None: |
| mask = lowerfcn(a,limits[0])*upperfcn(a,limits[1]) |
| term1 = N.add.reduce(N.ravel(a*a*mask)) |
| n = float(N.add.reduce(N.ravel(mask))) |
| return sd/math.sqrt(n) |
| |
| |
| ##################################### |
| ############ AMOMENTS ############# |
| ##################################### |
| |
| def amoment(a,moment=1,dimension=None): |
| """ |
| Calculates the nth moment about the mean for a sample (defaults to the |
| 1st moment). Generally used to calculate coefficients of skewness and |
| kurtosis. Dimension can equal None (ravel array first), an integer |
| (the dimension over which to operate), or a sequence (operate over |
| multiple dimensions). |
| |
| Usage: amoment(a,moment=1,dimension=None) |
| Returns: appropriate moment along given dimension |
| """ |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| if moment == 1: |
| return 0.0 |
| else: |
| mn = amean(a,dimension,1) # 1=keepdims |
| s = N.power((a-mn),moment) |
| return amean(s,dimension) |
| |
| |
| def avariation(a,dimension=None): |
| """ |
| Returns the coefficient of variation, as defined in CRC Standard |
| Probability and Statistics, p.6. Dimension can equal None (ravel array |
| first), an integer (the dimension over which to operate), or a |
| sequence (operate over multiple dimensions). |
| |
| Usage: avariation(a,dimension=None) |
| """ |
| return 100.0*asamplestdev(a,dimension)/amean(a,dimension) |
| |
| |
| def askew(a,dimension=None): |
| """ |
| Returns the skewness of a distribution (normal ==> 0.0; >0 means extra |
| weight in left tail). Use askewtest() to see if it's close enough. |
| Dimension can equal None (ravel array first), an integer (the |
| dimension over which to operate), or a sequence (operate over multiple |
| dimensions). |
| |
| Usage: askew(a, dimension=None) |
| Returns: skew of vals in a along dimension, returning ZERO where all vals equal |
| """ |
| denom = N.power(amoment(a,2,dimension),1.5) |
| zero = N.equal(denom,0) |
| if type(denom) == N.ndarray and asum(zero) <> 0: |
| print "Number of zeros in askew: ",asum(zero) |
| denom = denom + zero # prevent divide-by-zero |
| return N.where(zero, 0, amoment(a,3,dimension)/denom) |
| |
| |
| def akurtosis(a,dimension=None): |
| """ |
| Returns the kurtosis of a distribution (normal ==> 3.0; >3 means |
| heavier in the tails, and usually more peaked). Use akurtosistest() |
| to see if it's close enough. Dimension can equal None (ravel array |
| first), an integer (the dimension over which to operate), or a |
| sequence (operate over multiple dimensions). |
| |
| Usage: akurtosis(a,dimension=None) |
| Returns: kurtosis of values in a along dimension, and ZERO where all vals equal |
| """ |
| denom = N.power(amoment(a,2,dimension),2) |
| zero = N.equal(denom,0) |
| if type(denom) == N.ndarray and asum(zero) <> 0: |
| print "Number of zeros in akurtosis: ",asum(zero) |
| denom = denom + zero # prevent divide-by-zero |
| return N.where(zero,0,amoment(a,4,dimension)/denom) |
| |
| |
| def adescribe(inarray,dimension=None): |
| """ |
| Returns several descriptive statistics of the passed array. Dimension |
| can equal None (ravel array first), an integer (the dimension over |
| which to operate), or a sequence (operate over multiple dimensions). |
| |
| Usage: adescribe(inarray,dimension=None) |
| Returns: n, (min,max), mean, standard deviation, skew, kurtosis |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| n = inarray.shape[dimension] |
| mm = (N.minimum.reduce(inarray),N.maximum.reduce(inarray)) |
| m = amean(inarray,dimension) |
| sd = astdev(inarray,dimension) |
| skew = askew(inarray,dimension) |
| kurt = akurtosis(inarray,dimension) |
| return n, mm, m, sd, skew, kurt |
| |
| |
| ##################################### |
| ######## NORMALITY TESTS ########## |
| ##################################### |
| |
| def askewtest(a,dimension=None): |
| """ |
| Tests whether the skew is significantly different from a normal |
| distribution. Dimension can equal None (ravel array first), an |
| integer (the dimension over which to operate), or a sequence (operate |
| over multiple dimensions). |
| |
| Usage: askewtest(a,dimension=None) |
| Returns: z-score and 2-tail z-probability |
| """ |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| b2 = askew(a,dimension) |
| n = float(a.shape[dimension]) |
| y = b2 * N.sqrt(((n+1)*(n+3)) / (6.0*(n-2)) ) |
| beta2 = ( 3.0*(n*n+27*n-70)*(n+1)*(n+3) ) / ( (n-2.0)*(n+5)*(n+7)*(n+9) ) |
| W2 = -1 + N.sqrt(2*(beta2-1)) |
| delta = 1/N.sqrt(N.log(N.sqrt(W2))) |
| alpha = N.sqrt(2/(W2-1)) |
| y = N.where(y==0,1,y) |
| Z = delta*N.log(y/alpha + N.sqrt((y/alpha)**2+1)) |
| return Z, (1.0-zprob(Z))*2 |
| |
| |
| def akurtosistest(a,dimension=None): |
| """ |
| Tests whether a dataset has normal kurtosis (i.e., |
| kurtosis=3(n-1)/(n+1)) Valid only for n>20. Dimension can equal None |
| (ravel array first), an integer (the dimension over which to operate), |
| or a sequence (operate over multiple dimensions). |
| |
| Usage: akurtosistest(a,dimension=None) |
| Returns: z-score and 2-tail z-probability, returns 0 for bad pixels |
| """ |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| n = float(a.shape[dimension]) |
| if n<20: |
| print "akurtosistest only valid for n>=20 ... continuing anyway, n=",n |
| b2 = akurtosis(a,dimension) |
| E = 3.0*(n-1) /(n+1) |
| varb2 = 24.0*n*(n-2)*(n-3) / ((n+1)*(n+1)*(n+3)*(n+5)) |
| x = (b2-E)/N.sqrt(varb2) |
| sqrtbeta1 = 6.0*(n*n-5*n+2)/((n+7)*(n+9)) * N.sqrt((6.0*(n+3)*(n+5))/ |
| (n*(n-2)*(n-3))) |
| A = 6.0 + 8.0/sqrtbeta1 *(2.0/sqrtbeta1 + N.sqrt(1+4.0/(sqrtbeta1**2))) |
| term1 = 1 -2/(9.0*A) |
| denom = 1 +x*N.sqrt(2/(A-4.0)) |
| denom = N.where(N.less(denom,0), 99, denom) |
| term2 = N.where(N.equal(denom,0), term1, N.power((1-2.0/A)/denom,1/3.0)) |
| Z = ( term1 - term2 ) / N.sqrt(2/(9.0*A)) |
| Z = N.where(N.equal(denom,99), 0, Z) |
| return Z, (1.0-zprob(Z))*2 |
| |
| |
| def anormaltest(a,dimension=None): |
| """ |
| Tests whether skew and/OR kurtosis of dataset differs from normal |
| curve. Can operate over multiple dimensions. Dimension can equal |
| None (ravel array first), an integer (the dimension over which to |
| operate), or a sequence (operate over multiple dimensions). |
| |
| Usage: anormaltest(a,dimension=None) |
| Returns: z-score and 2-tail probability |
| """ |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| s,p = askewtest(a,dimension) |
| k,p = akurtosistest(a,dimension) |
| k2 = N.power(s,2) + N.power(k,2) |
| return k2, achisqprob(k2,2) |
| |
| |
| ##################################### |
| ###### AFREQUENCY FUNCTIONS ####### |
| ##################################### |
| |
| def aitemfreq(a): |
| """ |
| Returns a 2D array of item frequencies. Column 1 contains item values, |
| column 2 contains their respective counts. Assumes a 1D array is passed. |
| @@@sorting OK? |
| |
| Usage: aitemfreq(a) |
| Returns: a 2D frequency table (col [0:n-1]=scores, col n=frequencies) |
| """ |
| scores = pstat.aunique(a) |
| scores = N.sort(scores) |
| freq = N.zeros(len(scores)) |
| for i in range(len(scores)): |
| freq[i] = N.add.reduce(N.equal(a,scores[i])) |
| return N.array(pstat.aabut(scores, freq)) |
| |
| |
| def ascoreatpercentile (inarray, percent): |
| """ |
| Usage: ascoreatpercentile(inarray,percent) 0<percent<100 |
| Returns: score at given percentile, relative to inarray distribution |
| """ |
| percent = percent / 100.0 |
| targetcf = percent*len(inarray) |
| h, lrl, binsize, extras = histogram(inarray) |
| cumhist = cumsum(h*1) |
| for i in range(len(cumhist)): |
| if cumhist[i] >= targetcf: |
| break |
| score = binsize * ((targetcf - cumhist[i-1]) / float(h[i])) + (lrl+binsize*i) |
| return score |
| |
| |
| def apercentileofscore (inarray,score,histbins=10,defaultlimits=None): |
| """ |
| Note: result of this function depends on the values used to histogram |
| the data(!). |
| |
| Usage: apercentileofscore(inarray,score,histbins=10,defaultlimits=None) |
| Returns: percentile-position of score (0-100) relative to inarray |
| """ |
| h, lrl, binsize, extras = histogram(inarray,histbins,defaultlimits) |
| cumhist = cumsum(h*1) |
| i = int((score - lrl)/float(binsize)) |
| pct = (cumhist[i-1]+((score-(lrl+binsize*i))/float(binsize))*h[i])/float(len(inarray)) * 100 |
| return pct |
| |
| |
| def ahistogram (inarray,numbins=10,defaultlimits=None,printextras=1): |
| """ |
| Returns (i) an array of histogram bin counts, (ii) the smallest value |
| of the histogram binning, and (iii) the bin width (the last 2 are not |
| necessarily integers). Default number of bins is 10. Defaultlimits |
| can be None (the routine picks bins spanning all the numbers in the |
| inarray) or a 2-sequence (lowerlimit, upperlimit). Returns all of the |
| following: array of bin values, lowerreallimit, binsize, extrapoints. |
| |
| Usage: ahistogram(inarray,numbins=10,defaultlimits=None,printextras=1) |
| Returns: (array of bin counts, bin-minimum, min-width, #-points-outside-range) |
| """ |
| inarray = N.ravel(inarray) # flatten any >1D arrays |
| if (defaultlimits <> None): |
| lowerreallimit = defaultlimits[0] |
| upperreallimit = defaultlimits[1] |
| binsize = (upperreallimit-lowerreallimit) / float(numbins) |
| else: |
| Min = N.minimum.reduce(inarray) |
| Max = N.maximum.reduce(inarray) |
| estbinwidth = float(Max - Min)/float(numbins) + 1e-6 |
| binsize = (Max-Min+estbinwidth)/float(numbins) |
| lowerreallimit = Min - binsize/2.0 #lower real limit,1st bin |
| bins = N.zeros(numbins) |
| extrapoints = 0 |
| for num in inarray: |
| try: |
| if (num-lowerreallimit) < 0: |
| extrapoints = extrapoints + 1 |
| else: |
| bintoincrement = int((num-lowerreallimit) / float(binsize)) |
| bins[bintoincrement] = bins[bintoincrement] + 1 |
| except: # point outside lower/upper limits |
| extrapoints = extrapoints + 1 |
| if (extrapoints > 0 and printextras == 1): |
| print '\nPoints outside given histogram range =',extrapoints |
| return (bins, lowerreallimit, binsize, extrapoints) |
| |
| |
| def acumfreq(a,numbins=10,defaultreallimits=None): |
| """ |
| Returns a cumulative frequency histogram, using the histogram function. |
| Defaultreallimits can be None (use all data), or a 2-sequence containing |
| lower and upper limits on values to include. |
| |
| Usage: acumfreq(a,numbins=10,defaultreallimits=None) |
| Returns: array of cumfreq bin values, lowerreallimit, binsize, extrapoints |
| """ |
| h,l,b,e = histogram(a,numbins,defaultreallimits) |
| cumhist = cumsum(h*1) |
| return cumhist,l,b,e |
| |
| |
| def arelfreq(a,numbins=10,defaultreallimits=None): |
| """ |
| Returns a relative frequency histogram, using the histogram function. |
| Defaultreallimits can be None (use all data), or a 2-sequence containing |
| lower and upper limits on values to include. |
| |
| Usage: arelfreq(a,numbins=10,defaultreallimits=None) |
| Returns: array of cumfreq bin values, lowerreallimit, binsize, extrapoints |
| """ |
| h,l,b,e = histogram(a,numbins,defaultreallimits) |
| h = N.array(h/float(a.shape[0])) |
| return h,l,b,e |
| |
| |
| ##################################### |
| ###### AVARIABILITY FUNCTIONS ##### |
| ##################################### |
| |
| def aobrientransform(*args): |
| """ |
| Computes a transform on input data (any number of columns). Used to |
| test for homogeneity of variance prior to running one-way stats. Each |
| array in *args is one level of a factor. If an F_oneway() run on the |
| transformed data and found significant, variances are unequal. From |
| Maxwell and Delaney, p.112. |
| |
| Usage: aobrientransform(*args) *args = 1D arrays, one per level of factor |
| Returns: transformed data for use in an ANOVA |
| """ |
| TINY = 1e-10 |
| k = len(args) |
| n = N.zeros(k,N.float_) |
| v = N.zeros(k,N.float_) |
| m = N.zeros(k,N.float_) |
| nargs = [] |
| for i in range(k): |
| nargs.append(args[i].astype(N.float_)) |
| n[i] = float(len(nargs[i])) |
| v[i] = var(nargs[i]) |
| m[i] = mean(nargs[i]) |
| for j in range(k): |
| for i in range(n[j]): |
| t1 = (n[j]-1.5)*n[j]*(nargs[j][i]-m[j])**2 |
| t2 = 0.5*v[j]*(n[j]-1.0) |
| t3 = (n[j]-1.0)*(n[j]-2.0) |
| nargs[j][i] = (t1-t2) / float(t3) |
| check = 1 |
| for j in range(k): |
| if v[j] - mean(nargs[j]) > TINY: |
| check = 0 |
| if check <> 1: |
| raise ValueError, 'Lack of convergence in obrientransform.' |
| else: |
| return N.array(nargs) |
| |
| |
| def asamplevar (inarray,dimension=None,keepdims=0): |
| """ |
| Returns the sample standard deviation of the values in the passed |
| array (i.e., using N). Dimension can equal None (ravel array first), |
| an integer (the dimension over which to operate), or a sequence |
| (operate over multiple dimensions). Set keepdims=1 to return an array |
| with the same number of dimensions as inarray. |
| |
| Usage: asamplevar(inarray,dimension=None,keepdims=0) |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| if dimension == 1: |
| mn = amean(inarray,dimension)[:,N.NewAxis] |
| else: |
| mn = amean(inarray,dimension,keepdims=1) |
| deviations = inarray - mn |
| if type(dimension) == ListType: |
| n = 1 |
| for d in dimension: |
| n = n*inarray.shape[d] |
| else: |
| n = inarray.shape[dimension] |
| svar = ass(deviations,dimension,keepdims) / float(n) |
| return svar |
| |
| |
| def asamplestdev (inarray, dimension=None, keepdims=0): |
| """ |
| Returns the sample standard deviation of the values in the passed |
| array (i.e., using N). Dimension can equal None (ravel array first), |
| an integer (the dimension over which to operate), or a sequence |
| (operate over multiple dimensions). Set keepdims=1 to return an array |
| with the same number of dimensions as inarray. |
| |
| Usage: asamplestdev(inarray,dimension=None,keepdims=0) |
| """ |
| return N.sqrt(asamplevar(inarray,dimension,keepdims)) |
| |
| |
| def asignaltonoise(instack,dimension=0): |
| """ |
| Calculates signal-to-noise. Dimension can equal None (ravel array |
| first), an integer (the dimension over which to operate), or a |
| sequence (operate over multiple dimensions). |
| |
| Usage: asignaltonoise(instack,dimension=0): |
| Returns: array containing the value of (mean/stdev) along dimension, |
| or 0 when stdev=0 |
| """ |
| m = mean(instack,dimension) |
| sd = stdev(instack,dimension) |
| return N.where(sd==0,0,m/sd) |
| |
| |
| def acov (x,y, dimension=None,keepdims=0): |
| """ |
| Returns the estimated covariance of the values in the passed |
| array (i.e., N-1). Dimension can equal None (ravel array first), an |
| integer (the dimension over which to operate), or a sequence (operate |
| over multiple dimensions). Set keepdims=1 to return an array with the |
| same number of dimensions as inarray. |
| |
| Usage: acov(x,y,dimension=None,keepdims=0) |
| """ |
| if dimension == None: |
| x = N.ravel(x) |
| y = N.ravel(y) |
| dimension = 0 |
| xmn = amean(x,dimension,1) # keepdims |
| xdeviations = x - xmn |
| ymn = amean(y,dimension,1) # keepdims |
| ydeviations = y - ymn |
| if type(dimension) == ListType: |
| n = 1 |
| for d in dimension: |
| n = n*x.shape[d] |
| else: |
| n = x.shape[dimension] |
| covar = N.sum(xdeviations*ydeviations)/float(n-1) |
| return covar |
| |
| |
| def avar (inarray, dimension=None,keepdims=0): |
| """ |
| Returns the estimated population variance of the values in the passed |
| array (i.e., N-1). Dimension can equal None (ravel array first), an |
| integer (the dimension over which to operate), or a sequence (operate |
| over multiple dimensions). Set keepdims=1 to return an array with the |
| same number of dimensions as inarray. |
| |
| Usage: avar(inarray,dimension=None,keepdims=0) |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| mn = amean(inarray,dimension,1) |
| deviations = inarray - mn |
| if type(dimension) == ListType: |
| n = 1 |
| for d in dimension: |
| n = n*inarray.shape[d] |
| else: |
| n = inarray.shape[dimension] |
| var = ass(deviations,dimension,keepdims)/float(n-1) |
| return var |
| |
| |
| def astdev (inarray, dimension=None, keepdims=0): |
| """ |
| Returns the estimated population standard deviation of the values in |
| the passed array (i.e., N-1). Dimension can equal None (ravel array |
| first), an integer (the dimension over which to operate), or a |
| sequence (operate over multiple dimensions). Set keepdims=1 to return |
| an array with the same number of dimensions as inarray. |
| |
| Usage: astdev(inarray,dimension=None,keepdims=0) |
| """ |
| return N.sqrt(avar(inarray,dimension,keepdims)) |
| |
| |
| def asterr (inarray, dimension=None, keepdims=0): |
| """ |
| Returns the estimated population standard error of the values in the |
| passed array (i.e., N-1). Dimension can equal None (ravel array |
| first), an integer (the dimension over which to operate), or a |
| sequence (operate over multiple dimensions). Set keepdims=1 to return |
| an array with the same number of dimensions as inarray. |
| |
| Usage: asterr(inarray,dimension=None,keepdims=0) |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| return astdev(inarray,dimension,keepdims) / float(N.sqrt(inarray.shape[dimension])) |
| |
| |
| def asem (inarray, dimension=None, keepdims=0): |
| """ |
| Returns the standard error of the mean (i.e., using N) of the values |
| in the passed array. Dimension can equal None (ravel array first), an |
| integer (the dimension over which to operate), or a sequence (operate |
| over multiple dimensions). Set keepdims=1 to return an array with the |
| same number of dimensions as inarray. |
| |
| Usage: asem(inarray,dimension=None, keepdims=0) |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| if type(dimension) == ListType: |
| n = 1 |
| for d in dimension: |
| n = n*inarray.shape[d] |
| else: |
| n = inarray.shape[dimension] |
| s = asamplestdev(inarray,dimension,keepdims) / N.sqrt(n-1) |
| return s |
| |
| |
| def az (a, score): |
| """ |
| Returns the z-score of a given input score, given thearray from which |
| that score came. Not appropriate for population calculations, nor for |
| arrays > 1D. |
| |
| Usage: az(a, score) |
| """ |
| z = (score-amean(a)) / asamplestdev(a) |
| return z |
| |
| |
| def azs (a): |
| """ |
| Returns a 1D array of z-scores, one for each score in the passed array, |
| computed relative to the passed array. |
| |
| Usage: azs(a) |
| """ |
| zscores = [] |
| for item in a: |
| zscores.append(z(a,item)) |
| return N.array(zscores) |
| |
| |
| def azmap (scores, compare, dimension=0): |
| """ |
| Returns an array of z-scores the shape of scores (e.g., [x,y]), compared to |
| array passed to compare (e.g., [time,x,y]). Assumes collapsing over dim 0 |
| of the compare array. |
| |
| Usage: azs(scores, compare, dimension=0) |
| """ |
| mns = amean(compare,dimension) |
| sstd = asamplestdev(compare,0) |
| return (scores - mns) / sstd |
| |
| |
| ##################################### |
| ####### ATRIMMING FUNCTIONS ####### |
| ##################################### |
| |
| ## deleted around() as it's in numpy now |
| |
| def athreshold(a,threshmin=None,threshmax=None,newval=0): |
| """ |
| Like Numeric.clip() except that values <threshmid or >threshmax are replaced |
| by newval instead of by threshmin/threshmax (respectively). |
| |
| Usage: athreshold(a,threshmin=None,threshmax=None,newval=0) |
| Returns: a, with values <threshmin or >threshmax replaced with newval |
| """ |
| mask = N.zeros(a.shape) |
| if threshmin <> None: |
| mask = mask + N.where(a<threshmin,1,0) |
| if threshmax <> None: |
| mask = mask + N.where(a>threshmax,1,0) |
| mask = N.clip(mask,0,1) |
| return N.where(mask,newval,a) |
| |
| |
| def atrimboth (a,proportiontocut): |
| """ |
| Slices off the passed proportion of items from BOTH ends of the passed |
| array (i.e., with proportiontocut=0.1, slices 'leftmost' 10% AND |
| 'rightmost' 10% of scores. You must pre-sort the array if you want |
| "proper" trimming. Slices off LESS if proportion results in a |
| non-integer slice index (i.e., conservatively slices off |
| proportiontocut). |
| |
| Usage: atrimboth (a,proportiontocut) |
| Returns: trimmed version of array a |
| """ |
| lowercut = int(proportiontocut*len(a)) |
| uppercut = len(a) - lowercut |
| return a[lowercut:uppercut] |
| |
| |
| def atrim1 (a,proportiontocut,tail='right'): |
| """ |
| Slices off the passed proportion of items from ONE end of the passed |
| array (i.e., if proportiontocut=0.1, slices off 'leftmost' or 'rightmost' |
| 10% of scores). Slices off LESS if proportion results in a non-integer |
| slice index (i.e., conservatively slices off proportiontocut). |
| |
| Usage: atrim1(a,proportiontocut,tail='right') or set tail='left' |
| Returns: trimmed version of array a |
| """ |
| if string.lower(tail) == 'right': |
| lowercut = 0 |
| uppercut = len(a) - int(proportiontocut*len(a)) |
| elif string.lower(tail) == 'left': |
| lowercut = int(proportiontocut*len(a)) |
| uppercut = len(a) |
| return a[lowercut:uppercut] |
| |
| |
| ##################################### |
| ##### ACORRELATION FUNCTIONS ###### |
| ##################################### |
| |
| def acovariance(X): |
| """ |
| Computes the covariance matrix of a matrix X. Requires a 2D matrix input. |
| |
| Usage: acovariance(X) |
| Returns: covariance matrix of X |
| """ |
| if len(X.shape) <> 2: |
| raise TypeError, "acovariance requires 2D matrices" |
| n = X.shape[0] |
| mX = amean(X,0) |
| return N.dot(N.transpose(X),X) / float(n) - N.multiply.outer(mX,mX) |
| |
| |
| def acorrelation(X): |
| """ |
| Computes the correlation matrix of a matrix X. Requires a 2D matrix input. |
| |
| Usage: acorrelation(X) |
| Returns: correlation matrix of X |
| """ |
| C = acovariance(X) |
| V = N.diagonal(C) |
| return C / N.sqrt(N.multiply.outer(V,V)) |
| |
| |
| def apaired(x,y): |
| """ |
| Interactively determines the type of data in x and y, and then runs the |
| appropriated statistic for paired group data. |
| |
| Usage: apaired(x,y) x,y = the two arrays of values to be compared |
| Returns: appropriate statistic name, value, and probability |
| """ |
| samples = '' |
| while samples not in ['i','r','I','R','c','C']: |
| print '\nIndependent or related samples, or correlation (i,r,c): ', |
| samples = raw_input() |
| |
| if samples in ['i','I','r','R']: |
| print '\nComparing variances ...', |
| # USE O'BRIEN'S TEST FOR HOMOGENEITY OF VARIANCE, Maxwell & delaney, p.112 |
| r = obrientransform(x,y) |
| f,p = F_oneway(pstat.colex(r,0),pstat.colex(r,1)) |
| if p<0.05: |
| vartype='unequal, p='+str(round(p,4)) |
| else: |
| vartype='equal' |
| print vartype |
| if samples in ['i','I']: |
| if vartype[0]=='e': |
| t,p = ttest_ind(x,y,None,0) |
| print '\nIndependent samples t-test: ', round(t,4),round(p,4) |
| else: |
| if len(x)>20 or len(y)>20: |
| z,p = ranksums(x,y) |
| print '\nRank Sums test (NONparametric, n>20): ', round(z,4),round(p,4) |
| else: |
| u,p = mannwhitneyu(x,y) |
| print '\nMann-Whitney U-test (NONparametric, ns<20): ', round(u,4),round(p,4) |
| |
| else: # RELATED SAMPLES |
| if vartype[0]=='e': |
| t,p = ttest_rel(x,y,0) |
| print '\nRelated samples t-test: ', round(t,4),round(p,4) |
| else: |
| t,p = ranksums(x,y) |
| print '\nWilcoxon T-test (NONparametric): ', round(t,4),round(p,4) |
| else: # CORRELATION ANALYSIS |
| corrtype = '' |
| while corrtype not in ['c','C','r','R','d','D']: |
| print '\nIs the data Continuous, Ranked, or Dichotomous (c,r,d): ', |
| corrtype = raw_input() |
| if corrtype in ['c','C']: |
| m,b,r,p,see = linregress(x,y) |
| print '\nLinear regression for continuous variables ...' |
| lol = [['Slope','Intercept','r','Prob','SEestimate'],[round(m,4),round(b,4),round(r,4),round(p,4),round(see,4)]] |
| pstat.printcc(lol) |
| elif corrtype in ['r','R']: |
| r,p = spearmanr(x,y) |
| print '\nCorrelation for ranked variables ...' |
| print "Spearman's r: ",round(r,4),round(p,4) |
| else: # DICHOTOMOUS |
| r,p = pointbiserialr(x,y) |
| print '\nAssuming x contains a dichotomous variable ...' |
| print 'Point Biserial r: ',round(r,4),round(p,4) |
| print '\n\n' |
| return None |
| |
| |
| def dices(x,y): |
| """ |
| Calculates Dice's coefficient ... (2*number of common terms)/(number of terms in x + |
| number of terms in y). Returns a value between 0 (orthogonal) and 1. |
| |
| Usage: dices(x,y) |
| """ |
| import sets |
| x = sets.Set(x) |
| y = sets.Set(y) |
| common = len(x.intersection(y)) |
| total = float(len(x) + len(y)) |
| return 2*common/total |
| |
| |
| def icc(x,y=None,verbose=0): |
| """ |
| Calculates intraclass correlation coefficients using simple, Type I sums of squares. |
| If only one variable is passed, assumed it's an Nx2 matrix |
| |
| Usage: icc(x,y=None,verbose=0) |
| Returns: icc rho, prob ####PROB IS A GUESS BASED ON PEARSON |
| """ |
| TINY = 1.0e-20 |
| if y: |
| all = N.concatenate([x,y],0) |
| else: |
| all = x+0 |
| x = all[:,0] |
| y = all[:,1] |
| totalss = ass(all-mean(all)) |
| pairmeans = (x+y)/2. |
| withinss = ass(x-pairmeans) + ass(y-pairmeans) |
| withindf = float(len(x)) |
| betwdf = float(len(x)-1) |
| withinms = withinss / withindf |
| betweenms = (totalss-withinss) / betwdf |
| rho = (betweenms-withinms)/(withinms+betweenms) |
| t = rho*math.sqrt(betwdf/((1.0-rho+TINY)*(1.0+rho+TINY))) |
| prob = abetai(0.5*betwdf,0.5,betwdf/(betwdf+t*t),verbose) |
| return rho, prob |
| |
| |
| def alincc(x,y): |
| """ |
| Calculates Lin's concordance correlation coefficient. |
| |
| Usage: alincc(x,y) where x, y are equal-length arrays |
| Returns: Lin's CC |
| """ |
| x = N.ravel(x) |
| y = N.ravel(y) |
| covar = acov(x,y)*(len(x)-1)/float(len(x)) # correct denom to n |
| xvar = avar(x)*(len(x)-1)/float(len(x)) # correct denom to n |
| yvar = avar(y)*(len(y)-1)/float(len(y)) # correct denom to n |
| lincc = (2 * covar) / ((xvar+yvar) +((amean(x)-amean(y))**2)) |
| return lincc |
| |
| |
| def apearsonr(x,y,verbose=1): |
| """ |
| Calculates a Pearson correlation coefficient and returns p. Taken |
| from Heiman's Basic Statistics for the Behav. Sci (2nd), p.195. |
| |
| Usage: apearsonr(x,y,verbose=1) where x,y are equal length arrays |
| Returns: Pearson's r, two-tailed p-value |
| """ |
| TINY = 1.0e-20 |
| n = len(x) |
| xmean = amean(x) |
| ymean = amean(y) |
| r_num = n*(N.add.reduce(x*y)) - N.add.reduce(x)*N.add.reduce(y) |
| r_den = math.sqrt((n*ass(x) - asquare_of_sums(x))*(n*ass(y)-asquare_of_sums(y))) |
| r = (r_num / r_den) |
| df = n-2 |
| t = r*math.sqrt(df/((1.0-r+TINY)*(1.0+r+TINY))) |
| prob = abetai(0.5*df,0.5,df/(df+t*t),verbose) |
| return r,prob |
| |
| |
| def aspearmanr(x,y): |
| """ |
| Calculates a Spearman rank-order correlation coefficient. Taken |
| from Heiman's Basic Statistics for the Behav. Sci (1st), p.192. |
| |
| Usage: aspearmanr(x,y) where x,y are equal-length arrays |
| Returns: Spearman's r, two-tailed p-value |
| """ |
| TINY = 1e-30 |
| n = len(x) |
| rankx = rankdata(x) |
| ranky = rankdata(y) |
| dsq = N.add.reduce((rankx-ranky)**2) |
| rs = 1 - 6*dsq / float(n*(n**2-1)) |
| t = rs * math.sqrt((n-2) / ((rs+1.0)*(1.0-rs))) |
| df = n-2 |
| probrs = abetai(0.5*df,0.5,df/(df+t*t)) |
| # probability values for rs are from part 2 of the spearman function in |
| # Numerical Recipies, p.510. They close to tables, but not exact.(?) |
| return rs, probrs |
| |
| |
| def apointbiserialr(x,y): |
| """ |
| Calculates a point-biserial correlation coefficient and the associated |
| probability value. Taken from Heiman's Basic Statistics for the Behav. |
| Sci (1st), p.194. |
| |
| Usage: apointbiserialr(x,y) where x,y are equal length arrays |
| Returns: Point-biserial r, two-tailed p-value |
| """ |
| TINY = 1e-30 |
| categories = pstat.aunique(x) |
| data = pstat.aabut(x,y) |
| if len(categories) <> 2: |
| raise ValueError, "Exactly 2 categories required (in x) for pointbiserialr()." |
| else: # there are 2 categories, continue |
| codemap = pstat.aabut(categories,N.arange(2)) |
| recoded = pstat.arecode(data,codemap,0) |
| x = pstat.alinexand(data,0,categories[0]) |
| y = pstat.alinexand(data,0,categories[1]) |
| xmean = amean(pstat.acolex(x,1)) |
| ymean = amean(pstat.acolex(y,1)) |
| n = len(data) |
| adjust = math.sqrt((len(x)/float(n))*(len(y)/float(n))) |
| rpb = (ymean - xmean)/asamplestdev(pstat.acolex(data,1))*adjust |
| df = n-2 |
| t = rpb*math.sqrt(df/((1.0-rpb+TINY)*(1.0+rpb+TINY))) |
| prob = abetai(0.5*df,0.5,df/(df+t*t)) |
| return rpb, prob |
| |
| |
| def akendalltau(x,y): |
| """ |
| Calculates Kendall's tau ... correlation of ordinal data. Adapted |
| from function kendl1 in Numerical Recipies. Needs good test-cases.@@@ |
| |
| Usage: akendalltau(x,y) |
| Returns: Kendall's tau, two-tailed p-value |
| """ |
| n1 = 0 |
| n2 = 0 |
| iss = 0 |
| for j in range(len(x)-1): |
| for k in range(j,len(y)): |
| a1 = x[j] - x[k] |
| a2 = y[j] - y[k] |
| aa = a1 * a2 |
| if (aa): # neither array has a tie |
| n1 = n1 + 1 |
| n2 = n2 + 1 |
| if aa > 0: |
| iss = iss + 1 |
| else: |
| iss = iss -1 |
| else: |
| if (a1): |
| n1 = n1 + 1 |
| else: |
| n2 = n2 + 1 |
| tau = iss / math.sqrt(n1*n2) |
| svar = (4.0*len(x)+10.0) / (9.0*len(x)*(len(x)-1)) |
| z = tau / math.sqrt(svar) |
| prob = erfcc(abs(z)/1.4142136) |
| return tau, prob |
| |
| |
| def alinregress(*args): |
| """ |
| Calculates a regression line on two arrays, x and y, corresponding to x,y |
| pairs. If a single 2D array is passed, alinregress finds dim with 2 levels |
| and splits data into x,y pairs along that dim. |
| |
| Usage: alinregress(*args) args=2 equal-length arrays, or one 2D array |
| Returns: slope, intercept, r, two-tailed prob, sterr-of-the-estimate, n |
| """ |
| TINY = 1.0e-20 |
| if len(args) == 1: # more than 1D array? |
| args = args[0] |
| if len(args) == 2: |
| x = args[0] |
| y = args[1] |
| else: |
| x = args[:,0] |
| y = args[:,1] |
| else: |
| x = args[0] |
| y = args[1] |
| n = len(x) |
| xmean = amean(x) |
| ymean = amean(y) |
| r_num = n*(N.add.reduce(x*y)) - N.add.reduce(x)*N.add.reduce(y) |
| r_den = math.sqrt((n*ass(x) - asquare_of_sums(x))*(n*ass(y)-asquare_of_sums(y))) |
| r = r_num / r_den |
| z = 0.5*math.log((1.0+r+TINY)/(1.0-r+TINY)) |
| df = n-2 |
| t = r*math.sqrt(df/((1.0-r+TINY)*(1.0+r+TINY))) |
| prob = abetai(0.5*df,0.5,df/(df+t*t)) |
| slope = r_num / (float(n)*ass(x) - asquare_of_sums(x)) |
| intercept = ymean - slope*xmean |
| sterrest = math.sqrt(1-r*r)*asamplestdev(y) |
| return slope, intercept, r, prob, sterrest, n |
| |
| def amasslinregress(*args): |
| """ |
| Calculates a regression line on one 1D array (x) and one N-D array (y). |
| |
| Returns: slope, intercept, r, two-tailed prob, sterr-of-the-estimate, n |
| """ |
| TINY = 1.0e-20 |
| if len(args) == 1: # more than 1D array? |
| args = args[0] |
| if len(args) == 2: |
| x = N.ravel(args[0]) |
| y = args[1] |
| else: |
| x = N.ravel(args[:,0]) |
| y = args[:,1] |
| else: |
| x = args[0] |
| y = args[1] |
| x = x.astype(N.float_) |
| y = y.astype(N.float_) |
| n = len(x) |
| xmean = amean(x) |
| ymean = amean(y,0) |
| shp = N.ones(len(y.shape)) |
| shp[0] = len(x) |
| x.shape = shp |
| print x.shape, y.shape |
| r_num = n*(N.add.reduce(x*y,0)) - N.add.reduce(x)*N.add.reduce(y,0) |
| r_den = N.sqrt((n*ass(x) - asquare_of_sums(x))*(n*ass(y,0)-asquare_of_sums(y,0))) |
| zerodivproblem = N.equal(r_den,0) |
| r_den = N.where(zerodivproblem,1,r_den) # avoid zero-division in 1st place |
| r = r_num / r_den # need to do this nicely for matrix division |
| r = N.where(zerodivproblem,0.0,r) |
| z = 0.5*N.log((1.0+r+TINY)/(1.0-r+TINY)) |
| df = n-2 |
| t = r*N.sqrt(df/((1.0-r+TINY)*(1.0+r+TINY))) |
| prob = abetai(0.5*df,0.5,df/(df+t*t)) |
| |
| ss = float(n)*ass(x)-asquare_of_sums(x) |
| s_den = N.where(ss==0,1,ss) # avoid zero-division in 1st place |
| slope = r_num / s_den |
| intercept = ymean - slope*xmean |
| sterrest = N.sqrt(1-r*r)*asamplestdev(y,0) |
| return slope, intercept, r, prob, sterrest, n |
| |
| |
| ##################################### |
| ##### AINFERENTIAL STATISTICS ##### |
| ##################################### |
| |
| def attest_1samp(a,popmean,printit=0,name='Sample',writemode='a'): |
| """ |
| Calculates the t-obtained for the independent samples T-test on ONE group |
| of scores a, given a population mean. If printit=1, results are printed |
| to the screen. If printit='filename', the results are output to 'filename' |
| using the given writemode (default=append). Returns t-value, and prob. |
| |
| Usage: attest_1samp(a,popmean,Name='Sample',printit=0,writemode='a') |
| Returns: t-value, two-tailed prob |
| """ |
| if type(a) != N.ndarray: |
| a = N.array(a) |
| x = amean(a) |
| v = avar(a) |
| n = len(a) |
| df = n-1 |
| svar = ((n-1)*v) / float(df) |
| t = (x-popmean)/math.sqrt(svar*(1.0/n)) |
| prob = abetai(0.5*df,0.5,df/(df+t*t)) |
| |
| if printit <> 0: |
| statname = 'Single-sample T-test.' |
| outputpairedstats(printit,writemode, |
| 'Population','--',popmean,0,0,0, |
| name,n,x,v,N.minimum.reduce(N.ravel(a)), |
| N.maximum.reduce(N.ravel(a)), |
| statname,t,prob) |
| return t,prob |
| |
| |
| def attest_ind (a, b, dimension=None, printit=0, name1='Samp1', name2='Samp2',writemode='a'): |
| """ |
| Calculates the t-obtained T-test on TWO INDEPENDENT samples of scores |
| a, and b. From Numerical Recipies, p.483. If printit=1, results are |
| printed to the screen. If printit='filename', the results are output |
| to 'filename' using the given writemode (default=append). Dimension |
| can equal None (ravel array first), or an integer (the dimension over |
| which to operate on a and b). |
| |
| Usage: attest_ind (a,b,dimension=None,printit=0, |
| Name1='Samp1',Name2='Samp2',writemode='a') |
| Returns: t-value, two-tailed p-value |
| """ |
| if dimension == None: |
| a = N.ravel(a) |
| b = N.ravel(b) |
| dimension = 0 |
| x1 = amean(a,dimension) |
| x2 = amean(b,dimension) |
| v1 = avar(a,dimension) |
| v2 = avar(b,dimension) |
| n1 = a.shape[dimension] |
| n2 = b.shape[dimension] |
| df = n1+n2-2 |
| svar = ((n1-1)*v1+(n2-1)*v2) / float(df) |
| zerodivproblem = N.equal(svar,0) |
| svar = N.where(zerodivproblem,1,svar) # avoid zero-division in 1st place |
| t = (x1-x2)/N.sqrt(svar*(1.0/n1 + 1.0/n2)) # N-D COMPUTATION HERE!!!!!! |
| t = N.where(zerodivproblem,1.0,t) # replace NaN/wrong t-values with 1.0 |
| probs = abetai(0.5*df,0.5,float(df)/(df+t*t)) |
| |
| if type(t) == N.ndarray: |
| probs = N.reshape(probs,t.shape) |
| if probs.shape == (1,): |
| probs = probs[0] |
| |
| if printit <> 0: |
| if type(t) == N.ndarray: |
| t = t[0] |
| if type(probs) == N.ndarray: |
| probs = probs[0] |
| statname = 'Independent samples T-test.' |
| outputpairedstats(printit,writemode, |
| name1,n1,x1,v1,N.minimum.reduce(N.ravel(a)), |
| N.maximum.reduce(N.ravel(a)), |
| name2,n2,x2,v2,N.minimum.reduce(N.ravel(b)), |
| N.maximum.reduce(N.ravel(b)), |
| statname,t,probs) |
| return |
| return t, probs |
| |
| def ap2t(pval,df): |
| """ |
| Tries to compute a t-value from a p-value (or pval array) and associated df. |
| SLOW for large numbers of elements(!) as it re-computes p-values 20 times |
| (smaller step-sizes) at which point it decides it's done. Keeps the signs |
| of the input array. Returns 1000 (or -1000) if t>100. |
| |
| Usage: ap2t(pval,df) |
| Returns: an array of t-values with the shape of pval |
| """ |
| pval = N.array(pval) |
| signs = N.sign(pval) |
| pval = abs(pval) |
| t = N.ones(pval.shape,N.float_)*50 |
| step = N.ones(pval.shape,N.float_)*25 |
| print "Initial ap2t() prob calc" |
| prob = abetai(0.5*df,0.5,float(df)/(df+t*t)) |
| print 'ap2t() iter: ', |
| for i in range(10): |
| print i,' ', |
| t = N.where(pval<prob,t+step,t-step) |
| prob = abetai(0.5*df,0.5,float(df)/(df+t*t)) |
| step = step/2 |
| print |
| # since this is an ugly hack, we get ugly boundaries |
| t = N.where(t>99.9,1000,t) # hit upper-boundary |
| t = t+signs |
| return t #, prob, pval |
| |
| |
| def attest_rel (a,b,dimension=None,printit=0,name1='Samp1',name2='Samp2',writemode='a'): |
| """ |
| Calculates the t-obtained T-test on TWO RELATED samples of scores, a |
| and b. From Numerical Recipies, p.483. If printit=1, results are |
| printed to the screen. If printit='filename', the results are output |
| to 'filename' using the given writemode (default=append). Dimension |
| can equal None (ravel array first), or an integer (the dimension over |
| which to operate on a and b). |
| |
| Usage: attest_rel(a,b,dimension=None,printit=0, |
| name1='Samp1',name2='Samp2',writemode='a') |
| Returns: t-value, two-tailed p-value |
| """ |
| if dimension == None: |
| a = N.ravel(a) |
| b = N.ravel(b) |
| dimension = 0 |
| if len(a)<>len(b): |
| raise ValueError, 'Unequal length arrays.' |
| x1 = amean(a,dimension) |
| x2 = amean(b,dimension) |
| v1 = avar(a,dimension) |
| v2 = avar(b,dimension) |
| n = a.shape[dimension] |
| df = float(n-1) |
| d = (a-b).astype('d') |
| |
| denom = N.sqrt((n*N.add.reduce(d*d,dimension) - N.add.reduce(d,dimension)**2) /df) |
| zerodivproblem = N.equal(denom,0) |
| denom = N.where(zerodivproblem,1,denom) # avoid zero-division in 1st place |
| t = N.add.reduce(d,dimension) / denom # N-D COMPUTATION HERE!!!!!! |
| t = N.where(zerodivproblem,1.0,t) # replace NaN/wrong t-values with 1.0 |
| probs = abetai(0.5*df,0.5,float(df)/(df+t*t)) |
| if type(t) == N.ndarray: |
| probs = N.reshape(probs,t.shape) |
| if probs.shape == (1,): |
| probs = probs[0] |
| |
| if printit <> 0: |
| statname = 'Related samples T-test.' |
| outputpairedstats(printit,writemode, |
| name1,n,x1,v1,N.minimum.reduce(N.ravel(a)), |
| N.maximum.reduce(N.ravel(a)), |
| name2,n,x2,v2,N.minimum.reduce(N.ravel(b)), |
| N.maximum.reduce(N.ravel(b)), |
| statname,t,probs) |
| return |
| return t, probs |
| |
| |
| def achisquare(f_obs,f_exp=None): |
| """ |
| Calculates a one-way chi square for array of observed frequencies and returns |
| the result. If no expected frequencies are given, the total N is assumed to |
| be equally distributed across all groups. |
| @@@NOT RIGHT?? |
| |
| Usage: achisquare(f_obs, f_exp=None) f_obs = array of observed cell freq. |
| Returns: chisquare-statistic, associated p-value |
| """ |
| |
| k = len(f_obs) |
| if f_exp == None: |
| f_exp = N.array([sum(f_obs)/float(k)] * len(f_obs),N.float_) |
| f_exp = f_exp.astype(N.float_) |
| chisq = N.add.reduce((f_obs-f_exp)**2 / f_exp) |
| return chisq, achisqprob(chisq, k-1) |
| |
| |
| def aks_2samp (data1,data2): |
| """ |
| Computes the Kolmogorov-Smirnof statistic on 2 samples. Modified from |
| Numerical Recipies in C, page 493. Returns KS D-value, prob. Not ufunc- |
| like. |
| |
| Usage: aks_2samp(data1,data2) where data1 and data2 are 1D arrays |
| Returns: KS D-value, p-value |
| """ |
| j1 = 0 # N.zeros(data1.shape[1:]) TRIED TO MAKE THIS UFUNC-LIKE |
| j2 = 0 # N.zeros(data2.shape[1:]) |
| fn1 = 0.0 # N.zeros(data1.shape[1:],N.float_) |
| fn2 = 0.0 # N.zeros(data2.shape[1:],N.float_) |
| n1 = data1.shape[0] |
| n2 = data2.shape[0] |
| en1 = n1*1 |
| en2 = n2*1 |
| d = N.zeros(data1.shape[1:],N.float_) |
| data1 = N.sort(data1,0) |
| data2 = N.sort(data2,0) |
| while j1 < n1 and j2 < n2: |
| d1=data1[j1] |
| d2=data2[j2] |
| if d1 <= d2: |
| fn1 = (j1)/float(en1) |
| j1 = j1 + 1 |
| if d2 <= d1: |
| fn2 = (j2)/float(en2) |
| j2 = j2 + 1 |
| dt = (fn2-fn1) |
| if abs(dt) > abs(d): |
| d = dt |
| # try: |
| en = math.sqrt(en1*en2/float(en1+en2)) |
| prob = aksprob((en+0.12+0.11/en)*N.fabs(d)) |
| # except: |
| # prob = 1.0 |
| return d, prob |
| |
| |
| def amannwhitneyu(x,y): |
| """ |
| Calculates a Mann-Whitney U statistic on the provided scores and |
| returns the result. Use only when the n in each condition is < 20 and |
| you have 2 independent samples of ranks. REMEMBER: Mann-Whitney U is |
| significant if the u-obtained is LESS THAN or equal to the critical |
| value of U. |
| |
| Usage: amannwhitneyu(x,y) where x,y are arrays of values for 2 conditions |
| Returns: u-statistic, one-tailed p-value (i.e., p(z(U))) |
| """ |
| n1 = len(x) |
| n2 = len(y) |
| ranked = rankdata(N.concatenate((x,y))) |
| rankx = ranked[0:n1] # get the x-ranks |
| ranky = ranked[n1:] # the rest are y-ranks |
| u1 = n1*n2 + (n1*(n1+1))/2.0 - sum(rankx) # calc U for x |
| u2 = n1*n2 - u1 # remainder is U for y |
| bigu = max(u1,u2) |
| smallu = min(u1,u2) |
| proportion = bigu/float(n1*n2) |
| T = math.sqrt(tiecorrect(ranked)) # correction factor for tied scores |
| if T == 0: |
| raise ValueError, 'All numbers are identical in amannwhitneyu' |
| sd = math.sqrt(T*n1*n2*(n1+n2+1)/12.0) |
| z = abs((bigu-n1*n2/2.0) / sd) # normal approximation for prob calc |
| return smallu, 1.0 - azprob(z), proportion |
| |
| |
| def atiecorrect(rankvals): |
| """ |
| Tie-corrector for ties in Mann Whitney U and Kruskal Wallis H tests. |
| See Siegel, S. (1956) Nonparametric Statistics for the Behavioral |
| Sciences. New York: McGraw-Hill. Code adapted from |Stat rankind.c |
| code. |
| |
| Usage: atiecorrect(rankvals) |
| Returns: T correction factor for U or H |
| """ |
| sorted,posn = ashellsort(N.array(rankvals)) |
| n = len(sorted) |
| T = 0.0 |
| i = 0 |
| while (i<n-1): |
| if sorted[i] == sorted[i+1]: |
| nties = 1 |
| while (i<n-1) and (sorted[i] == sorted[i+1]): |
| nties = nties +1 |
| i = i +1 |
| T = T + nties**3 - nties |
| i = i+1 |
| T = T / float(n**3-n) |
| return 1.0 - T |
| |
| |
| def aranksums(x,y): |
| """ |
| Calculates the rank sums statistic on the provided scores and returns |
| the result. |
| |
| Usage: aranksums(x,y) where x,y are arrays of values for 2 conditions |
| Returns: z-statistic, two-tailed p-value |
| """ |
| n1 = len(x) |
| n2 = len(y) |
| alldata = N.concatenate((x,y)) |
| ranked = arankdata(alldata) |
| x = ranked[:n1] |
| y = ranked[n1:] |
| s = sum(x) |
| expected = n1*(n1+n2+1) / 2.0 |
| z = (s - expected) / math.sqrt(n1*n2*(n1+n2+1)/12.0) |
| prob = 2*(1.0 - azprob(abs(z))) |
| return z, prob |
| |
| |
| def awilcoxont(x,y): |
| """ |
| Calculates the Wilcoxon T-test for related samples and returns the |
| result. A non-parametric T-test. |
| |
| Usage: awilcoxont(x,y) where x,y are equal-length arrays for 2 conditions |
| Returns: t-statistic, two-tailed p-value |
| """ |
| if len(x) <> len(y): |
| raise ValueError, 'Unequal N in awilcoxont. Aborting.' |
| d = x-y |
| d = N.compress(N.not_equal(d,0),d) # Keep all non-zero differences |
| count = len(d) |
| absd = abs(d) |
| absranked = arankdata(absd) |
| r_plus = 0.0 |
| r_minus = 0.0 |
| for i in range(len(absd)): |
| if d[i] < 0: |
| r_minus = r_minus + absranked[i] |
| else: |
| r_plus = r_plus + absranked[i] |
| wt = min(r_plus, r_minus) |
| mn = count * (count+1) * 0.25 |
| se = math.sqrt(count*(count+1)*(2.0*count+1.0)/24.0) |
| z = math.fabs(wt-mn) / se |
| z = math.fabs(wt-mn) / se |
| prob = 2*(1.0 -zprob(abs(z))) |
| return wt, prob |
| |
| |
| def akruskalwallish(*args): |
| """ |
| The Kruskal-Wallis H-test is a non-parametric ANOVA for 3 or more |
| groups, requiring at least 5 subjects in each group. This function |
| calculates the Kruskal-Wallis H and associated p-value for 3 or more |
| independent samples. |
| |
| Usage: akruskalwallish(*args) args are separate arrays for 3+ conditions |
| Returns: H-statistic (corrected for ties), associated p-value |
| """ |
| assert len(args) == 3, "Need at least 3 groups in stats.akruskalwallish()" |
| args = list(args) |
| n = [0]*len(args) |
| n = map(len,args) |
| all = [] |
| for i in range(len(args)): |
| all = all + args[i].tolist() |
| ranked = rankdata(all) |
| T = tiecorrect(ranked) |
| for i in range(len(args)): |
| args[i] = ranked[0:n[i]] |
| del ranked[0:n[i]] |
| rsums = [] |
| for i in range(len(args)): |
| rsums.append(sum(args[i])**2) |
| rsums[i] = rsums[i] / float(n[i]) |
| ssbn = sum(rsums) |
| totaln = sum(n) |
| h = 12.0 / (totaln*(totaln+1)) * ssbn - 3*(totaln+1) |
| df = len(args) - 1 |
| if T == 0: |
| raise ValueError, 'All numbers are identical in akruskalwallish' |
| h = h / float(T) |
| return h, chisqprob(h,df) |
| |
| |
| def afriedmanchisquare(*args): |
| """ |
| Friedman Chi-Square is a non-parametric, one-way within-subjects |
| ANOVA. This function calculates the Friedman Chi-square test for |
| repeated measures and returns the result, along with the associated |
| probability value. It assumes 3 or more repeated measures. Only 3 |
| levels requires a minimum of 10 subjects in the study. Four levels |
| requires 5 subjects per level(??). |
| |
| Usage: afriedmanchisquare(*args) args are separate arrays for 2+ conditions |
| Returns: chi-square statistic, associated p-value |
| """ |
| k = len(args) |
| if k < 3: |
| raise ValueError, '\nLess than 3 levels. Friedman test not appropriate.\n' |
| n = len(args[0]) |
| data = apply(pstat.aabut,args) |
| data = data.astype(N.float_) |
| for i in range(len(data)): |
| data[i] = arankdata(data[i]) |
| ssbn = asum(asum(args,1)**2) |
| chisq = 12.0 / (k*n*(k+1)) * ssbn - 3*n*(k+1) |
| return chisq, achisqprob(chisq,k-1) |
| |
| |
| ##################################### |
| #### APROBABILITY CALCULATIONS #### |
| ##################################### |
| |
| def achisqprob(chisq,df): |
| """ |
| Returns the (1-tail) probability value associated with the provided chi-square |
| value and df. Heavily modified from chisq.c in Gary Perlman's |Stat. Can |
| handle multiple dimensions. |
| |
| Usage: achisqprob(chisq,df) chisq=chisquare stat., df=degrees of freedom |
| """ |
| BIG = 200.0 |
| def ex(x): |
| BIG = 200.0 |
| exponents = N.where(N.less(x,-BIG),-BIG,x) |
| return N.exp(exponents) |
| |
| if type(chisq) == N.ndarray: |
| arrayflag = 1 |
| else: |
| arrayflag = 0 |
| chisq = N.array([chisq]) |
| if df < 1: |
| return N.ones(chisq.shape,N.float) |
| probs = N.zeros(chisq.shape,N.float_) |
| probs = N.where(N.less_equal(chisq,0),1.0,probs) # set prob=1 for chisq<0 |
| a = 0.5 * chisq |
| if df > 1: |
| y = ex(-a) |
| if df%2 == 0: |
| even = 1 |
| s = y*1 |
| s2 = s*1 |
| else: |
| even = 0 |
| s = 2.0 * azprob(-N.sqrt(chisq)) |
| s2 = s*1 |
| if (df > 2): |
| chisq = 0.5 * (df - 1.0) |
| if even: |
| z = N.ones(probs.shape,N.float_) |
| else: |
| z = 0.5 *N.ones(probs.shape,N.float_) |
| if even: |
| e = N.zeros(probs.shape,N.float_) |
| else: |
| e = N.log(N.sqrt(N.pi)) *N.ones(probs.shape,N.float_) |
| c = N.log(a) |
| mask = N.zeros(probs.shape) |
| a_big = N.greater(a,BIG) |
| a_big_frozen = -1 *N.ones(probs.shape,N.float_) |
| totalelements = N.multiply.reduce(N.array(probs.shape)) |
| while asum(mask)<>totalelements: |
| e = N.log(z) + e |
| s = s + ex(c*z-a-e) |
| z = z + 1.0 |
| # print z, e, s |
| newmask = N.greater(z,chisq) |
| a_big_frozen = N.where(newmask*N.equal(mask,0)*a_big, s, a_big_frozen) |
| mask = N.clip(newmask+mask,0,1) |
| if even: |
| z = N.ones(probs.shape,N.float_) |
| e = N.ones(probs.shape,N.float_) |
| else: |
| z = 0.5 *N.ones(probs.shape,N.float_) |
| e = 1.0 / N.sqrt(N.pi) / N.sqrt(a) * N.ones(probs.shape,N.float_) |
| c = 0.0 |
| mask = N.zeros(probs.shape) |
| a_notbig_frozen = -1 *N.ones(probs.shape,N.float_) |
| while asum(mask)<>totalelements: |
| e = e * (a/z.astype(N.float_)) |
| c = c + e |
| z = z + 1.0 |
| # print '#2', z, e, c, s, c*y+s2 |
| newmask = N.greater(z,chisq) |
| a_notbig_frozen = N.where(newmask*N.equal(mask,0)*(1-a_big), |
| c*y+s2, a_notbig_frozen) |
| mask = N.clip(newmask+mask,0,1) |
| probs = N.where(N.equal(probs,1),1, |
| N.where(N.greater(a,BIG),a_big_frozen,a_notbig_frozen)) |
| return probs |
| else: |
| return s |
| |
| |
| def aerfcc(x): |
| """ |
| Returns the complementary error function erfc(x) with fractional error |
| everywhere less than 1.2e-7. Adapted from Numerical Recipies. Can |
| handle multiple dimensions. |
| |
| Usage: aerfcc(x) |
| """ |
| z = abs(x) |
| t = 1.0 / (1.0+0.5*z) |
| ans = t * N.exp(-z*z-1.26551223 + t*(1.00002368+t*(0.37409196+t*(0.09678418+t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+t*(-0.82215223+t*0.17087277))))))))) |
| return N.where(N.greater_equal(x,0), ans, 2.0-ans) |
| |
| |
| def azprob(z): |
| """ |
| Returns the area under the normal curve 'to the left of' the given z value. |
| Thus, |
| for z<0, zprob(z) = 1-tail probability |
| for z>0, 1.0-zprob(z) = 1-tail probability |
| for any z, 2.0*(1.0-zprob(abs(z))) = 2-tail probability |
| Adapted from z.c in Gary Perlman's |Stat. Can handle multiple dimensions. |
| |
| Usage: azprob(z) where z is a z-value |
| """ |
| def yfunc(y): |
| x = (((((((((((((-0.000045255659 * y |
| +0.000152529290) * y -0.000019538132) * y |
| -0.000676904986) * y +0.001390604284) * y |
| -0.000794620820) * y -0.002034254874) * y |
| +0.006549791214) * y -0.010557625006) * y |
| +0.011630447319) * y -0.009279453341) * y |
| +0.005353579108) * y -0.002141268741) * y |
| +0.000535310849) * y +0.999936657524 |
| return x |
| |
| def wfunc(w): |
| x = ((((((((0.000124818987 * w |
| -0.001075204047) * w +0.005198775019) * w |
| -0.019198292004) * w +0.059054035642) * w |
| -0.151968751364) * w +0.319152932694) * w |
| -0.531923007300) * w +0.797884560593) * N.sqrt(w) * 2.0 |
| return x |
| |
| Z_MAX = 6.0 # maximum meaningful z-value |
| x = N.zeros(z.shape,N.float_) # initialize |
| y = 0.5 * N.fabs(z) |
| x = N.where(N.less(y,1.0),wfunc(y*y),yfunc(y-2.0)) # get x's |
| x = N.where(N.greater(y,Z_MAX*0.5),1.0,x) # kill those with big Z |
| prob = N.where(N.greater(z,0),(x+1)*0.5,(1-x)*0.5) |
| return prob |
| |
| |
| def aksprob(alam): |
| """ |
| Returns the probability value for a K-S statistic computed via ks_2samp. |
| Adapted from Numerical Recipies. Can handle multiple dimensions. |
| |
| Usage: aksprob(alam) |
| """ |
| if type(alam) == N.ndarray: |
| frozen = -1 *N.ones(alam.shape,N.float64) |
| alam = alam.astype(N.float64) |
| arrayflag = 1 |
| else: |
| frozen = N.array(-1.) |
| alam = N.array(alam,N.float64) |
| arrayflag = 1 |
| mask = N.zeros(alam.shape) |
| fac = 2.0 *N.ones(alam.shape,N.float_) |
| sum = N.zeros(alam.shape,N.float_) |
| termbf = N.zeros(alam.shape,N.float_) |
| a2 = N.array(-2.0*alam*alam,N.float64) |
| totalelements = N.multiply.reduce(N.array(mask.shape)) |
| for j in range(1,201): |
| if asum(mask) == totalelements: |
| break |
| exponents = (a2*j*j) |
| overflowmask = N.less(exponents,-746) |
| frozen = N.where(overflowmask,0,frozen) |
| mask = mask+overflowmask |
| term = fac*N.exp(exponents) |
| sum = sum + term |
| newmask = N.where(N.less_equal(abs(term),(0.001*termbf)) + |
| N.less(abs(term),1.0e-8*sum), 1, 0) |
| frozen = N.where(newmask*N.equal(mask,0), sum, frozen) |
| mask = N.clip(mask+newmask,0,1) |
| fac = -fac |
| termbf = abs(term) |
| if arrayflag: |
| return N.where(N.equal(frozen,-1), 1.0, frozen) # 1.0 if doesn't converge |
| else: |
| return N.where(N.equal(frozen,-1), 1.0, frozen)[0] # 1.0 if doesn't converge |
| |
| |
| def afprob (dfnum, dfden, F): |
| """ |
| Returns the 1-tailed significance level (p-value) of an F statistic |
| given the degrees of freedom for the numerator (dfR-dfF) and the degrees |
| of freedom for the denominator (dfF). Can handle multiple dims for F. |
| |
| Usage: afprob(dfnum, dfden, F) where usually dfnum=dfbn, dfden=dfwn |
| """ |
| if type(F) == N.ndarray: |
| return abetai(0.5*dfden, 0.5*dfnum, dfden/(1.0*dfden+dfnum*F)) |
| else: |
| return abetai(0.5*dfden, 0.5*dfnum, dfden/float(dfden+dfnum*F)) |
| |
| |
| def abetacf(a,b,x,verbose=1): |
| """ |
| Evaluates the continued fraction form of the incomplete Beta function, |
| betai. (Adapted from: Numerical Recipies in C.) Can handle multiple |
| dimensions for x. |
| |
| Usage: abetacf(a,b,x,verbose=1) |
| """ |
| ITMAX = 200 |
| EPS = 3.0e-7 |
| |
| arrayflag = 1 |
| if type(x) == N.ndarray: |
| frozen = N.ones(x.shape,N.float_) *-1 #start out w/ -1s, should replace all |
| else: |
| arrayflag = 0 |
| frozen = N.array([-1]) |
| x = N.array([x]) |
| mask = N.zeros(x.shape) |
| bm = az = am = 1.0 |
| qab = a+b |
| qap = a+1.0 |
| qam = a-1.0 |
| bz = 1.0-qab*x/qap |
| for i in range(ITMAX+1): |
| if N.sum(N.ravel(N.equal(frozen,-1)))==0: |
| break |
| em = float(i+1) |
| tem = em + em |
| d = em*(b-em)*x/((qam+tem)*(a+tem)) |
| ap = az + d*am |
| bp = bz+d*bm |
| d = -(a+em)*(qab+em)*x/((qap+tem)*(a+tem)) |
| app = ap+d*az |
| bpp = bp+d*bz |
| aold = az*1 |
| am = ap/bpp |
| bm = bp/bpp |
| az = app/bpp |
| bz = 1.0 |
| newmask = N.less(abs(az-aold),EPS*abs(az)) |
| frozen = N.where(newmask*N.equal(mask,0), az, frozen) |
| mask = N.clip(mask+newmask,0,1) |
| noconverge = asum(N.equal(frozen,-1)) |
| if noconverge <> 0 and verbose: |
| print 'a or b too big, or ITMAX too small in Betacf for ',noconverge,' elements' |
| if arrayflag: |
| return frozen |
| else: |
| return frozen[0] |
| |
| |
| def agammln(xx): |
| """ |
| Returns the gamma function of xx. |
| Gamma(z) = Integral(0,infinity) of t^(z-1)exp(-t) dt. |
| Adapted from: Numerical Recipies in C. Can handle multiple dims ... but |
| probably doesn't normally have to. |
| |
| Usage: agammln(xx) |
| """ |
| coeff = [76.18009173, -86.50532033, 24.01409822, -1.231739516, |
| 0.120858003e-2, -0.536382e-5] |
| x = xx - 1.0 |
| tmp = x + 5.5 |
| tmp = tmp - (x+0.5)*N.log(tmp) |
| ser = 1.0 |
| for j in range(len(coeff)): |
| x = x + 1 |
| ser = ser + coeff[j]/x |
| return -tmp + N.log(2.50662827465*ser) |
| |
| |
| def abetai(a,b,x,verbose=1): |
| """ |
| Returns the incomplete beta function: |
| |
| I-sub-x(a,b) = 1/B(a,b)*(Integral(0,x) of t^(a-1)(1-t)^(b-1) dt) |
| |
| where a,b>0 and B(a,b) = G(a)*G(b)/(G(a+b)) where G(a) is the gamma |
| function of a. The continued fraction formulation is implemented |
| here, using the betacf function. (Adapted from: Numerical Recipies in |
| C.) Can handle multiple dimensions. |
| |
| Usage: abetai(a,b,x,verbose=1) |
| """ |
| TINY = 1e-15 |
| if type(a) == N.ndarray: |
| if asum(N.less(x,0)+N.greater(x,1)) <> 0: |
| raise ValueError, 'Bad x in abetai' |
| x = N.where(N.equal(x,0),TINY,x) |
| x = N.where(N.equal(x,1.0),1-TINY,x) |
| |
| bt = N.where(N.equal(x,0)+N.equal(x,1), 0, -1) |
| exponents = ( gammln(a+b)-gammln(a)-gammln(b)+a*N.log(x)+b* |
| N.log(1.0-x) ) |
| # 746 (below) is the MAX POSSIBLE BEFORE OVERFLOW |
| exponents = N.where(N.less(exponents,-740),-740,exponents) |
| bt = N.exp(exponents) |
| if type(x) == N.ndarray: |
| ans = N.where(N.less(x,(a+1)/(a+b+2.0)), |
| bt*abetacf(a,b,x,verbose)/float(a), |
| 1.0-bt*abetacf(b,a,1.0-x,verbose)/float(b)) |
| else: |
| if x<(a+1)/(a+b+2.0): |
| ans = bt*abetacf(a,b,x,verbose)/float(a) |
| else: |
| ans = 1.0-bt*abetacf(b,a,1.0-x,verbose)/float(b) |
| return ans |
| |
| |
| ##################################### |
| ####### AANOVA CALCULATIONS ####### |
| ##################################### |
| |
| import numpy.linalg, operator |
| LA = numpy.linalg |
| |
| def aglm(data,para): |
| """ |
| Calculates a linear model fit ... anova/ancova/lin-regress/t-test/etc. Taken |
| from: |
| Peterson et al. Statistical limitations in functional neuroimaging |
| I. Non-inferential methods and statistical models. Phil Trans Royal Soc |
| Lond B 354: 1239-1260. |
| |
| Usage: aglm(data,para) |
| Returns: statistic, p-value ??? |
| """ |
| if len(para) <> len(data): |
| print "data and para must be same length in aglm" |
| return |
| n = len(para) |
| p = pstat.aunique(para) |
| x = N.zeros((n,len(p))) # design matrix |
| for l in range(len(p)): |
| x[:,l] = N.equal(para,p[l]) |
| b = N.dot(N.dot(LA.inv(N.dot(N.transpose(x),x)), # i.e., b=inv(X'X)X'Y |
| N.transpose(x)), |
| data) |
| diffs = (data - N.dot(x,b)) |
| s_sq = 1./(n-len(p)) * N.dot(N.transpose(diffs), diffs) |
| |
| if len(p) == 2: # ttest_ind |
| c = N.array([1,-1]) |
| df = n-2 |
| fact = asum(1.0/asum(x,0)) # i.e., 1/n1 + 1/n2 + 1/n3 ... |
| t = N.dot(c,b) / N.sqrt(s_sq*fact) |
| probs = abetai(0.5*df,0.5,float(df)/(df+t*t)) |
| return t, probs |
| |
| |
| def aF_oneway(*args): |
| """ |
| Performs a 1-way ANOVA, returning an F-value and probability given |
| any number of groups. From Heiman, pp.394-7. |
| |
| Usage: aF_oneway (*args) where *args is 2 or more arrays, one per |
| treatment group |
| Returns: f-value, probability |
| """ |
| na = len(args) # ANOVA on 'na' groups, each in it's own array |
| means = [0]*na |
| vars = [0]*na |
| ns = [0]*na |
| alldata = [] |
| tmp = map(N.array,args) |
| means = map(amean,tmp) |
| vars = map(avar,tmp) |
| ns = map(len,args) |
| alldata = N.concatenate(args) |
| bign = len(alldata) |
| sstot = ass(alldata)-(asquare_of_sums(alldata)/float(bign)) |
| ssbn = 0 |
| for a in args: |
| ssbn = ssbn + asquare_of_sums(N.array(a))/float(len(a)) |
| ssbn = ssbn - (asquare_of_sums(alldata)/float(bign)) |
| sswn = sstot-ssbn |
| dfbn = na-1 |
| dfwn = bign - na |
| msb = ssbn/float(dfbn) |
| msw = sswn/float(dfwn) |
| f = msb/msw |
| prob = fprob(dfbn,dfwn,f) |
| return f, prob |
| |
| |
| def aF_value (ER,EF,dfR,dfF): |
| """ |
| Returns an F-statistic given the following: |
| ER = error associated with the null hypothesis (the Restricted model) |
| EF = error associated with the alternate hypothesis (the Full model) |
| dfR = degrees of freedom the Restricted model |
| dfF = degrees of freedom associated with the Restricted model |
| """ |
| return ((ER-EF)/float(dfR-dfF) / (EF/float(dfF))) |
| |
| |
| def outputfstats(Enum, Eden, dfnum, dfden, f, prob): |
| Enum = round(Enum,3) |
| Eden = round(Eden,3) |
| dfnum = round(Enum,3) |
| dfden = round(dfden,3) |
| f = round(f,3) |
| prob = round(prob,3) |
| suffix = '' # for *s after the p-value |
| if prob < 0.001: suffix = ' ***' |
| elif prob < 0.01: suffix = ' **' |
| elif prob < 0.05: suffix = ' *' |
| title = [['EF/ER','DF','Mean Square','F-value','prob','']] |
| lofl = title+[[Enum, dfnum, round(Enum/float(dfnum),3), f, prob, suffix], |
| [Eden, dfden, round(Eden/float(dfden),3),'','','']] |
| pstat.printcc(lofl) |
| return |
| |
| |
| def F_value_multivariate(ER, EF, dfnum, dfden): |
| """ |
| Returns an F-statistic given the following: |
| ER = error associated with the null hypothesis (the Restricted model) |
| EF = error associated with the alternate hypothesis (the Full model) |
| dfR = degrees of freedom the Restricted model |
| dfF = degrees of freedom associated with the Restricted model |
| where ER and EF are matrices from a multivariate F calculation. |
| """ |
| if type(ER) in [IntType, FloatType]: |
| ER = N.array([[ER]]) |
| if type(EF) in [IntType, FloatType]: |
| EF = N.array([[EF]]) |
| n_um = (LA.det(ER) - LA.det(EF)) / float(dfnum) |
| d_en = LA.det(EF) / float(dfden) |
| return n_um / d_en |
| |
| |
| ##################################### |
| ####### ASUPPORT FUNCTIONS ######## |
| ##################################### |
| |
| def asign(a): |
| """ |
| Usage: asign(a) |
| Returns: array shape of a, with -1 where a<0 and +1 where a>=0 |
| """ |
| a = N.asarray(a) |
| if ((type(a) == type(1.4)) or (type(a) == type(1))): |
| return a-a-N.less(a,0)+N.greater(a,0) |
| else: |
| return N.zeros(N.shape(a))-N.less(a,0)+N.greater(a,0) |
| |
| |
| def asum (a, dimension=None,keepdims=0): |
| """ |
| An alternative to the Numeric.add.reduce function, which allows one to |
| (1) collapse over multiple dimensions at once, and/or (2) to retain |
| all dimensions in the original array (squashing one down to size. |
| Dimension can equal None (ravel array first), an integer (the |
| dimension over which to operate), or a sequence (operate over multiple |
| dimensions). If keepdims=1, the resulting array will have as many |
| dimensions as the input array. |
| |
| Usage: asum(a, dimension=None, keepdims=0) |
| Returns: array summed along 'dimension'(s), same _number_ of dims if keepdims=1 |
| """ |
| if type(a) == N.ndarray and a.dtype in [N.int_, N.short, N.ubyte]: |
| a = a.astype(N.float_) |
| if dimension == None: |
| s = N.sum(N.ravel(a)) |
| elif type(dimension) in [IntType,FloatType]: |
| s = N.add.reduce(a, dimension) |
| if keepdims == 1: |
| shp = list(a.shape) |
| shp[dimension] = 1 |
| s = N.reshape(s,shp) |
| else: # must be a SEQUENCE of dims to sum over |
| dims = list(dimension) |
| dims.sort() |
| dims.reverse() |
| s = a *1.0 |
| for dim in dims: |
| s = N.add.reduce(s,dim) |
| if keepdims == 1: |
| shp = list(a.shape) |
| for dim in dims: |
| shp[dim] = 1 |
| s = N.reshape(s,shp) |
| return s |
| |
| |
| def acumsum (a,dimension=None): |
| """ |
| Returns an array consisting of the cumulative sum of the items in the |
| passed array. Dimension can equal None (ravel array first), an |
| integer (the dimension over which to operate), or a sequence (operate |
| over multiple dimensions, but this last one just barely makes sense). |
| |
| Usage: acumsum(a,dimension=None) |
| """ |
| if dimension == None: |
| a = N.ravel(a) |
| dimension = 0 |
| if type(dimension) in [ListType, TupleType, N.ndarray]: |
| dimension = list(dimension) |
| dimension.sort() |
| dimension.reverse() |
| for d in dimension: |
| a = N.add.accumulate(a,d) |
| return a |
| else: |
| return N.add.accumulate(a,dimension) |
| |
| |
| def ass(inarray, dimension=None, keepdims=0): |
| """ |
| Squares each value in the passed array, adds these squares & returns |
| the result. Unfortunate function name. :-) Defaults to ALL values in |
| the array. Dimension can equal None (ravel array first), an integer |
| (the dimension over which to operate), or a sequence (operate over |
| multiple dimensions). Set keepdims=1 to maintain the original number |
| of dimensions. |
| |
| Usage: ass(inarray, dimension=None, keepdims=0) |
| Returns: sum-along-'dimension' for (inarray*inarray) |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| return asum(inarray*inarray,dimension,keepdims) |
| |
| |
| def asummult (array1,array2,dimension=None,keepdims=0): |
| """ |
| Multiplies elements in array1 and array2, element by element, and |
| returns the sum (along 'dimension') of all resulting multiplications. |
| Dimension can equal None (ravel array first), an integer (the |
| dimension over which to operate), or a sequence (operate over multiple |
| dimensions). A trivial function, but included for completeness. |
| |
| Usage: asummult(array1,array2,dimension=None,keepdims=0) |
| """ |
| if dimension == None: |
| array1 = N.ravel(array1) |
| array2 = N.ravel(array2) |
| dimension = 0 |
| return asum(array1*array2,dimension,keepdims) |
| |
| |
| def asquare_of_sums(inarray, dimension=None, keepdims=0): |
| """ |
| Adds the values in the passed array, squares that sum, and returns the |
| result. Dimension can equal None (ravel array first), an integer (the |
| dimension over which to operate), or a sequence (operate over multiple |
| dimensions). If keepdims=1, the returned array will have the same |
| NUMBER of dimensions as the original. |
| |
| Usage: asquare_of_sums(inarray, dimension=None, keepdims=0) |
| Returns: the square of the sum over dim(s) in dimension |
| """ |
| if dimension == None: |
| inarray = N.ravel(inarray) |
| dimension = 0 |
| s = asum(inarray,dimension,keepdims) |
| if type(s) == N.ndarray: |
| return s.astype(N.float_)*s |
| else: |
| return float(s)*s |
| |
| |
| def asumdiffsquared(a,b, dimension=None, keepdims=0): |
| """ |
| Takes pairwise differences of the values in arrays a and b, squares |
| these differences, and returns the sum of these squares. Dimension |
| can equal None (ravel array first), an integer (the dimension over |
| which to operate), or a sequence (operate over multiple dimensions). |
| keepdims=1 means the return shape = len(a.shape) = len(b.shape) |
| |
| Usage: asumdiffsquared(a,b) |
| Returns: sum[ravel(a-b)**2] |
| """ |
| if dimension == None: |
| inarray = N.ravel(a) |
| dimension = 0 |
| return asum((a-b)**2,dimension,keepdims) |
| |
| |
| def ashellsort(inarray): |
| """ |
| Shellsort algorithm. Sorts a 1D-array. |
| |
| Usage: ashellsort(inarray) |
| Returns: sorted-inarray, sorting-index-vector (for original array) |
| """ |
| n = len(inarray) |
| svec = inarray *1.0 |
| ivec = range(n) |
| gap = n/2 # integer division needed |
| while gap >0: |
| for i in range(gap,n): |
| for j in range(i-gap,-1,-gap): |
| while j>=0 and svec[j]>svec[j+gap]: |
| temp = svec[j] |
| svec[j] = svec[j+gap] |
| svec[j+gap] = temp |
| itemp = ivec[j] |
| ivec[j] = ivec[j+gap] |
| ivec[j+gap] = itemp |
| gap = gap / 2 # integer division needed |
| # svec is now sorted input vector, ivec has the order svec[i] = vec[ivec[i]] |
| return svec, ivec |
| |
| |
| def arankdata(inarray): |
| """ |
| Ranks the data in inarray, dealing with ties appropritely. Assumes |
| a 1D inarray. Adapted from Gary Perlman's |Stat ranksort. |
| |
| Usage: arankdata(inarray) |
| Returns: array of length equal to inarray, containing rank scores |
| """ |
| n = len(inarray) |
| svec, ivec = ashellsort(inarray) |
| sumranks = 0 |
| dupcount = 0 |
| newarray = N.zeros(n,N.float_) |
| for i in range(n): |
| sumranks = sumranks + i |
| dupcount = dupcount + 1 |
| if i==n-1 or svec[i] <> svec[i+1]: |
| averank = sumranks / float(dupcount) + 1 |
| for j in range(i-dupcount+1,i+1): |
| newarray[ivec[j]] = averank |
| sumranks = 0 |
| dupcount = 0 |
| return newarray |
| |
| |
| def afindwithin(data): |
| """ |
| Returns a binary vector, 1=within-subject factor, 0=between. Input |
| equals the entire data array (i.e., column 1=random factor, last |
| column = measured values. |
| |
| Usage: afindwithin(data) data in |Stat format |
| """ |
| numfact = len(data[0])-2 |
| withinvec = [0]*numfact |
| for col in range(1,numfact+1): |
| rows = pstat.linexand(data,col,pstat.unique(pstat.colex(data,1))[0]) # get 1 level of this factor |
| if len(pstat.unique(pstat.colex(rows,0))) < len(rows): # if fewer subjects than scores on this factor |
| withinvec[col-1] = 1 |
| return withinvec |
| |
| |
| ######################################################### |
| ######################################################### |
| ###### RE-DEFINE DISPATCHES TO INCLUDE ARRAYS ######### |
| ######################################################### |
| ######################################################### |
| |
| ## CENTRAL TENDENCY: |
| geometricmean = Dispatch ( (lgeometricmean, (ListType, TupleType)), |
| (ageometricmean, (N.ndarray,)) ) |
| harmonicmean = Dispatch ( (lharmonicmean, (ListType, TupleType)), |
| (aharmonicmean, (N.ndarray,)) ) |
| mean = Dispatch ( (lmean, (ListType, TupleType)), |
| (amean, (N.ndarray,)) ) |
| median = Dispatch ( (lmedian, (ListType, TupleType)), |
| (amedian, (N.ndarray,)) ) |
| medianscore = Dispatch ( (lmedianscore, (ListType, TupleType)), |
| (amedianscore, (N.ndarray,)) ) |
| mode = Dispatch ( (lmode, (ListType, TupleType)), |
| (amode, (N.ndarray,)) ) |
| tmean = Dispatch ( (atmean, (N.ndarray,)) ) |
| tvar = Dispatch ( (atvar, (N.ndarray,)) ) |
| tstdev = Dispatch ( (atstdev, (N.ndarray,)) ) |
| tsem = Dispatch ( (atsem, (N.ndarray,)) ) |
| |
| ## VARIATION: |
| moment = Dispatch ( (lmoment, (ListType, TupleType)), |
| (amoment, (N.ndarray,)) ) |
| variation = Dispatch ( (lvariation, (ListType, TupleType)), |
| (avariation, (N.ndarray,)) ) |
| skew = Dispatch ( (lskew, (ListType, TupleType)), |
| (askew, (N.ndarray,)) ) |
| kurtosis = Dispatch ( (lkurtosis, (ListType, TupleType)), |
| (akurtosis, (N.ndarray,)) ) |
| describe = Dispatch ( (ldescribe, (ListType, TupleType)), |
| (adescribe, (N.ndarray,)) ) |
| |
| ## DISTRIBUTION TESTS |
| |
| skewtest = Dispatch ( (askewtest, (ListType, TupleType)), |
| (askewtest, (N.ndarray,)) ) |
| kurtosistest = Dispatch ( (akurtosistest, (ListType, TupleType)), |
| (akurtosistest, (N.ndarray,)) ) |
| normaltest = Dispatch ( (anormaltest, (ListType, TupleType)), |
| (anormaltest, (N.ndarray,)) ) |
| |
| ## FREQUENCY STATS: |
| itemfreq = Dispatch ( (litemfreq, (ListType, TupleType)), |
| (aitemfreq, (N.ndarray,)) ) |
| scoreatpercentile = Dispatch ( (lscoreatpercentile, (ListType, TupleType)), |
| (ascoreatpercentile, (N.ndarray,)) ) |
| percentileofscore = Dispatch ( (lpercentileofscore, (ListType, TupleType)), |
| (apercentileofscore, (N.ndarray,)) ) |
| histogram = Dispatch ( (lhistogram, (ListType, TupleType)), |
| (ahistogram, (N.ndarray,)) ) |
| cumfreq = Dispatch ( (lcumfreq, (ListType, TupleType)), |
| (acumfreq, (N.ndarray,)) ) |
| relfreq = Dispatch ( (lrelfreq, (ListType, TupleType)), |
| (arelfreq, (N.ndarray,)) ) |
| |
| ## VARIABILITY: |
| obrientransform = Dispatch ( (lobrientransform, (ListType, TupleType)), |
| (aobrientransform, (N.ndarray,)) ) |
| samplevar = Dispatch ( (lsamplevar, (ListType, TupleType)), |
| (asamplevar, (N.ndarray,)) ) |
| samplestdev = Dispatch ( (lsamplestdev, (ListType, TupleType)), |
| (asamplestdev, (N.ndarray,)) ) |
| signaltonoise = Dispatch( (asignaltonoise, (N.ndarray,)),) |
| var = Dispatch ( (lvar, (ListType, TupleType)), |
| (avar, (N.ndarray,)) ) |
| stdev = Dispatch ( (lstdev, (ListType, TupleType)), |
| (astdev, (N.ndarray,)) ) |
| sterr = Dispatch ( (lsterr, (ListType, TupleType)), |
| (asterr, (N.ndarray,)) ) |
| sem = Dispatch ( (lsem, (ListType, TupleType)), |
| (asem, (N.ndarray,)) ) |
| z = Dispatch ( (lz, (ListType, TupleType)), |
| (az, (N.ndarray,)) ) |
| zs = Dispatch ( (lzs, (ListType, TupleType)), |
| (azs, (N.ndarray,)) ) |
| |
| ## TRIMMING FCNS: |
| threshold = Dispatch( (athreshold, (N.ndarray,)),) |
| trimboth = Dispatch ( (ltrimboth, (ListType, TupleType)), |
| (atrimboth, (N.ndarray,)) ) |
| trim1 = Dispatch ( (ltrim1, (ListType, TupleType)), |
| (atrim1, (N.ndarray,)) ) |
| |
| ## CORRELATION FCNS: |
| paired = Dispatch ( (lpaired, (ListType, TupleType)), |
| (apaired, (N.ndarray,)) ) |
| lincc = Dispatch ( (llincc, (ListType, TupleType)), |
| (alincc, (N.ndarray,)) ) |
| pearsonr = Dispatch ( (lpearsonr, (ListType, TupleType)), |
| (apearsonr, (N.ndarray,)) ) |
| spearmanr = Dispatch ( (lspearmanr, (ListType, TupleType)), |
| (aspearmanr, (N.ndarray,)) ) |
| pointbiserialr = Dispatch ( (lpointbiserialr, (ListType, TupleType)), |
| (apointbiserialr, (N.ndarray,)) ) |
| kendalltau = Dispatch ( (lkendalltau, (ListType, TupleType)), |
| (akendalltau, (N.ndarray,)) ) |
| linregress = Dispatch ( (llinregress, (ListType, TupleType)), |
| (alinregress, (N.ndarray,)) ) |
| |
| ## INFERENTIAL STATS: |
| ttest_1samp = Dispatch ( (lttest_1samp, (ListType, TupleType)), |
| (attest_1samp, (N.ndarray,)) ) |
| ttest_ind = Dispatch ( (lttest_ind, (ListType, TupleType)), |
| (attest_ind, (N.ndarray,)) ) |
| ttest_rel = Dispatch ( (lttest_rel, (ListType, TupleType)), |
| (attest_rel, (N.ndarray,)) ) |
| chisquare = Dispatch ( (lchisquare, (ListType, TupleType)), |
| (achisquare, (N.ndarray,)) ) |
| ks_2samp = Dispatch ( (lks_2samp, (ListType, TupleType)), |
| (aks_2samp, (N.ndarray,)) ) |
| mannwhitneyu = Dispatch ( (lmannwhitneyu, (ListType, TupleType)), |
| (amannwhitneyu, (N.ndarray,)) ) |
| tiecorrect = Dispatch ( (ltiecorrect, (ListType, TupleType)), |
| (atiecorrect, (N.ndarray,)) ) |
| ranksums = Dispatch ( (lranksums, (ListType, TupleType)), |
| (aranksums, (N.ndarray,)) ) |
| wilcoxont = Dispatch ( (lwilcoxont, (ListType, TupleType)), |
| (awilcoxont, (N.ndarray,)) ) |
| kruskalwallish = Dispatch ( (lkruskalwallish, (ListType, TupleType)), |
| (akruskalwallish, (N.ndarray,)) ) |
| friedmanchisquare = Dispatch ( (lfriedmanchisquare, (ListType, TupleType)), |
| (afriedmanchisquare, (N.ndarray,)) ) |
| |
| ## PROBABILITY CALCS: |
| chisqprob = Dispatch ( (lchisqprob, (IntType, FloatType)), |
| (achisqprob, (N.ndarray,)) ) |
| zprob = Dispatch ( (lzprob, (IntType, FloatType)), |
| (azprob, (N.ndarray,)) ) |
| ksprob = Dispatch ( (lksprob, (IntType, FloatType)), |
| (aksprob, (N.ndarray,)) ) |
| fprob = Dispatch ( (lfprob, (IntType, FloatType)), |
| (afprob, (N.ndarray,)) ) |
| betacf = Dispatch ( (lbetacf, (IntType, FloatType)), |
| (abetacf, (N.ndarray,)) ) |
| betai = Dispatch ( (lbetai, (IntType, FloatType)), |
| (abetai, (N.ndarray,)) ) |
| erfcc = Dispatch ( (lerfcc, (IntType, FloatType)), |
| (aerfcc, (N.ndarray,)) ) |
| gammln = Dispatch ( (lgammln, (IntType, FloatType)), |
| (agammln, (N.ndarray,)) ) |
| |
| ## ANOVA FUNCTIONS: |
| F_oneway = Dispatch ( (lF_oneway, (ListType, TupleType)), |
| (aF_oneway, (N.ndarray,)) ) |
| F_value = Dispatch ( (lF_value, (ListType, TupleType)), |
| (aF_value, (N.ndarray,)) ) |
| |
| ## SUPPORT FUNCTIONS: |
| incr = Dispatch ( (lincr, (ListType, TupleType, N.ndarray)), ) |
| sum = Dispatch ( (lsum, (ListType, TupleType)), |
| (asum, (N.ndarray,)) ) |
| cumsum = Dispatch ( (lcumsum, (ListType, TupleType)), |
| (acumsum, (N.ndarray,)) ) |
| ss = Dispatch ( (lss, (ListType, TupleType)), |
| (ass, (N.ndarray,)) ) |
| summult = Dispatch ( (lsummult, (ListType, TupleType)), |
| (asummult, (N.ndarray,)) ) |
| square_of_sums = Dispatch ( (lsquare_of_sums, (ListType, TupleType)), |
| (asquare_of_sums, (N.ndarray,)) ) |
| sumdiffsquared = Dispatch ( (lsumdiffsquared, (ListType, TupleType)), |
| (asumdiffsquared, (N.ndarray,)) ) |
| shellsort = Dispatch ( (lshellsort, (ListType, TupleType)), |
| (ashellsort, (N.ndarray,)) ) |
| rankdata = Dispatch ( (lrankdata, (ListType, TupleType)), |
| (arankdata, (N.ndarray,)) ) |
| findwithin = Dispatch ( (lfindwithin, (ListType, TupleType)), |
| (afindwithin, (N.ndarray,)) ) |
| |
| ###################### END OF NUMERIC FUNCTION BLOCK ##################### |
| |
| ###################### END OF STATISTICAL FUNCTIONS ###################### |
| |
| except ImportError: |
| pass |