Beispiel #1
0
    def fillcontinents(self,ax,color=0.8):
        """
 Fill continents.

 ax - current axis instance.
 color - color to fill continents (default gray).
        """
        # define corners of map domain.
        p1 = (self.llcrnrx,self.llcrnry); p2 = (self.urcrnrx,self.urcrnry)
        p3 = (self.llcrnrx,self.urcrnry); p4 = (self.urcrnrx,self.llcrnry)
        for x,y in self.coastpolygons:
            xa = N.array(x,'f')
            ya = N.array(y,'f')
        # clip to map domain.
            xa = N.clip(xa, self.xmin, self.xmax)
            ya = N.clip(ya, self.ymin, self.ymax)
        # check to see if all four corners of domain in polygon (if so,
        # don't draw since it will just fill in the whole map).
            test1 = N.fabs(xa-self.xmax) < 10.
            test2 = N.fabs(xa-self.xmin) < 10.
            test3 = N.fabs(ya-self.ymax) < 10.
            test4 = N.fabs(ya-self.ymin) < 10.
            hasp1 = sum(test1*test3)
            hasp2 = sum(test2*test3)
            hasp4 = sum(test2*test4)
            hasp3 = sum(test1*test4)
            if not hasp1 or not hasp2 or not hasp3 or not hasp4:
                xy = zip(xa.tolist(),ya.tolist())
                poly = Polygon(xy,facecolor=color,edgecolor=color,linewidth=0)
                ax.add_patch(poly)
Beispiel #2
0
    def fillcontinents(self, ax, color=0.8):
        """
 Fill continents.

 ax - current axis instance.
 color - color to fill continents (default gray).
        """
        # define corners of map domain.
        p1 = (self.llcrnrx, self.llcrnry)
        p2 = (self.urcrnrx, self.urcrnry)
        p3 = (self.llcrnrx, self.urcrnry)
        p4 = (self.urcrnrx, self.llcrnry)
        for x, y in self.coastpolygons:
            xa = N.array(x, 'f')
            ya = N.array(y, 'f')
            # clip to map domain.
            xa = N.clip(xa, self.xmin, self.xmax)
            ya = N.clip(ya, self.ymin, self.ymax)
            # check to see if all four corners of domain in polygon (if so,
            # don't draw since it will just fill in the whole map).
            test1 = N.fabs(xa - self.xmax) < 10.
            test2 = N.fabs(xa - self.xmin) < 10.
            test3 = N.fabs(ya - self.ymax) < 10.
            test4 = N.fabs(ya - self.ymin) < 10.
            hasp1 = sum(test1 * test3)
            hasp2 = sum(test2 * test3)
            hasp4 = sum(test2 * test4)
            hasp3 = sum(test1 * test4)
            if not hasp1 or not hasp2 or not hasp3 or not hasp4:
                xy = zip(xa.tolist(), ya.tolist())
                poly = Polygon(xy,
                               facecolor=color,
                               edgecolor=color,
                               linewidth=0)
                ax.add_patch(poly)
Beispiel #3
0
def _mad2(data, included):
    # adapted from NR function moment
    # same as mad3 but ignores zero values
    n = len(data[:,0,0])
    s = num.zeros(data[0,:,:].shape, num.Float32)
    # First pass to get the mean.
    for j in range(n): s += data[j,:,:]
    ave = s/included
    adev = num.zeros(s.shape, num.Float32)
    for j in range(n):
        d = where(num.fabs(data[j]) > tiny,
                  num.fabs(data[j] - ave),
                  0.0)
        num.add(adev, d, adev)
    return adev / included
def _simple_logistic_regression(x,y,beta_start=None,verbose=False,
                               CONV_THRESH=1.e-3,MAXIT=500):
    """
 Faster than logistic_regression when there is only one predictor.
    """
    if len(x) != len(y):
        raise ValueError, "x and y should be the same length!"
    if beta_start is None:
        beta_start = NA.zeros(2,x.typecode())
    iter = 0; diff = 1.; beta = beta_start  # initial values
    if verbose:
        print 'iteration  beta log-likliehood |beta-beta_old|' 
    while iter < MAXIT:
        beta_old = beta 
        p = NA.exp(beta[0]+beta[1]*x)/(1.+NA.exp(beta[0]+beta[1]*x))
        l = NA.sum(y*NA.log(p) + (1.-y)*NA.log(1.-p)) # log-likliehood
        s = NA.array([NA.sum(y-p), NA.sum((y-p)*x)])  # scoring function
        # information matrix
        J_bar = NA.array([[NA.sum(p*(1-p)),NA.sum(p*(1-p)*x)],
                          [NA.sum(p*(1-p)*x),NA.sum(p*(1-p)*x*x)]])
        beta = beta_old + NA.dot(LA.inverse(J_bar),s) # new value of beta
        diff = NA.sum(NA.fabs(beta-beta_old)) # sum of absolute differences
        if verbose:
            print iter+1, beta, l, diff
        if diff <= CONV_THRESH: break
        iter = iter + 1
    return beta, J_bar, l
def _simple_logistic_regression(x,y,beta_start=None,verbose=False,
                               CONV_THRESH=1.e-3,MAXIT=500):
    """
 Faster than logistic_regression when there is only one predictor.
    """
    if len(x) != len(y):
        raise ValueError, "x and y should be the same length!"
    if beta_start is None:
        beta_start = NA.zeros(2,x.dtype.char)
    iter = 0; diff = 1.; beta = beta_start  # initial values
    if verbose:
        print 'iteration  beta log-likliehood |beta-beta_old|' 
    while iter < MAXIT:
        beta_old = beta 
        p = NA.exp(beta[0]+beta[1]*x)/(1.+NA.exp(beta[0]+beta[1]*x))
        l = NA.sum(y*NA.log(p) + (1.-y)*NA.log(1.-p)) # log-likliehood
        s = NA.array([NA.sum(y-p), NA.sum((y-p)*x)])  # scoring function
        # information matrix
        J_bar = NA.array([[NA.sum(p*(1-p)),NA.sum(p*(1-p)*x)],
                          [NA.sum(p*(1-p)*x),NA.sum(p*(1-p)*x*x)]])
        beta = beta_old + NA.dot(LA.inverse(J_bar),s) # new value of beta
        diff = NA.sum(NA.fabs(beta-beta_old)) # sum of absolute differences
        if verbose:
            print iter+1, beta, l, diff
        if diff <= CONV_THRESH: break
        iter = iter + 1
    return beta, J_bar, l
Beispiel #6
0
def _mad3(data):
    # adapted from NR function moment
    n = len(data[:,0,0])
    s = num.zeros(data[0,:,:].shape, num.Float32)
    # First pass to get the mean.
    for j in range(n): s += data[j,:,:]
    ave = s/n
    adev = num.zeros(s.shape, num.Float32)
    for j in range(n):
        num.add(adev, num.fabs(data[j] - ave), adev)
    return adev / n
def logistic_regression(x,
                        y,
                        beta_start=None,
                        verbose=False,
                        CONV_THRESH=1.e-3,
                        MAXIT=500):
    """
 Uses the Newton-Raphson algorithm to calculate a maximum
 likelihood estimate logistic regression.
 The algorithm is known as 'iteratively re-weighted least squares', or IRLS.

 x - rank-1 or rank-2 array of predictors. If x is rank-2,
     the number of predictors = x.shape[0] = N.  If x is rank-1,
     it is assumed N=1.
     
 y - binary outcomes (if N>1 len(y) = x.shape[1], if N=1 len(y) = len(x))
 
 beta_start - initial beta vector (default zeros(N+1,x.dtype.char))
 
 if verbose=True, diagnostics printed for each iteration (default False).
 
 MAXIT - max number of iterations (default 500)
 
 CONV_THRESH - convergence threshold (sum of absolute differences
  of beta-beta_old, default 0.001)

 returns beta (the logistic regression coefficients, an N+1 element vector),
 J_bar (the (N+1)x(N+1) information matrix), and l (the log-likeliehood).
 
 J_bar can be used to estimate the covariance matrix and the standard
 error for beta.
 
 l can be used for a chi-squared significance test.

 covmat = inverse(J_bar)     --> covariance matrix of coefficents (beta)
 stderr = sqrt(diag(covmat)) --> standard errors for beta
 deviance = -2l              --> scaled deviance statistic
 chi-squared value for -2l is the model chi-squared test.
    """
    if x.shape[-1] != len(y):
        raise ValueError, "x.shape[-1] and y should be the same length!"
    try:
        N, npreds = x.shape[1], x.shape[0]
    except:  # single predictor, use simple logistic regression routine.
        return _simple_logistic_regression(x,
                                           y,
                                           beta_start=beta_start,
                                           CONV_THRESH=CONV_THRESH,
                                           MAXIT=MAXIT,
                                           verbose=verbose)
    if beta_start is None:
        beta_start = NA.zeros(npreds + 1, x.dtype.char)
    X = NA.ones((npreds + 1, N), x.dtype.char)
    X[1:, :] = x
    Xt = NA.transpose(X)
    iter = 0
    diff = 1.
    beta = beta_start  # initial values
    if verbose:
        print 'iteration  beta log-likliehood |beta-beta_old|'
    while iter < MAXIT:
        beta_old = beta
        ebx = NA.exp(NA.dot(beta, X))
        p = ebx / (1. + ebx)
        l = NA.sum(y * NA.log(p) +
                   (1. - y) * NA.log(1. - p))  # log-likeliehood
        s = NA.dot(X, y - p)  # scoring function
        J_bar = NA.dot(X * p, Xt)  # information matrix
        beta = beta_old + NA.dot(LA.inverse(J_bar), s)  # new value of beta
        diff = NA.sum(NA.fabs(beta - beta_old))  # sum of absolute differences
        if verbose:
            print iter + 1, beta, l, diff
        if diff <= CONV_THRESH: break
        iter = iter + 1
    if iter == MAXIT and diff > CONV_THRESH:
        print 'warning: convergence not achieved with threshold of %s in %s iterations' % (
            CONV_THRESH, MAXIT)
    return beta, J_bar, l
Beispiel #8
0
    def drawmeridians(self,ax,meridians,color='k',linewidth=1., \
                      linestyle='--',dashes=[1,1],labels=[0,0,0,0],\
                      font='rm',fontsize=12):
        """
 draw meridians (longitude lines).

 ax - current axis instance.
 meridians - list containing longitude values to draw (in degrees).
 color - color to draw meridians (default black).
 linewidth - line width for meridians (default 1.)
 linestyle - line style for meridians (default '--', i.e. dashed).
 dashes - dash pattern for meridians (default [1,1], i.e. 1 pixel on,
  1 pixel off).
 labels - list of 4 values (default [0,0,0,0]) that control whether
  meridians are labelled where they intersect the left, right, top or 
  bottom of the plot. For example labels=[1,0,0,1] will cause meridians
  to be labelled where they intersect the left and bottom of the plot,
  but not the right and top. Labels are located with a precision of 0.1
  degrees and are drawn using mathtext.
 font - mathtext font used for labels ('rm','tt','it' or 'cal', default 'rm'.
 fontsize - font size in points for labels (default 12).
        """
        # don't draw meridians past latmax, always draw parallel at latmax.
        latmax = 80. # not used for cyl, merc projections.
        # offset for labels.
	yoffset = (self.urcrnry-self.llcrnry)/100./self.aspect
	xoffset = (self.urcrnrx-self.llcrnrx)/100.

        if self.projection not in ['merc','cyl']:
            lats = N.arange(-latmax,latmax+1).astype('f')
        else:
            lats = N.arange(-90,91).astype('f')
        xdelta = 0.1*(self.xmax-self.xmin)
        ydelta = 0.1*(self.ymax-self.ymin)
        for merid in meridians:
            lons = merid*N.ones(len(lats),'f')
            x,y = self(lons,lats)
            # remove points outside domain.
            testx = N.logical_and(x>=self.xmin-xdelta,x<=self.xmax+xdelta)
            x = N.compress(testx, x)
            y = N.compress(testx, y)
            testy = N.logical_and(y>=self.ymin-ydelta,y<=self.ymax+ydelta)
            x = N.compress(testy, x)
            y = N.compress(testy, y)
            if len(x) > 1 and len(y) > 1:
                # split into separate line segments if necessary.
                # (not necessary for mercator or cylindrical).
                xd = (x[1:]-x[0:-1])**2
                yd = (y[1:]-y[0:-1])**2
                dist = N.sqrt(xd+yd)
                split = dist > 500000.
                if N.sum(split) and self.projection not in ['merc','cyl']:
                   ind = (N.compress(split,pylab.squeeze(split*N.indices(xd.shape)))+1).tolist()
                   xl = []
                   yl = []
                   iprev = 0
                   ind.append(len(xd))
                   for i in ind:
                       xl.append(x[iprev:i])
                       yl.append(y[iprev:i])
                       iprev = i
                else:
                    xl = [x]
                    yl = [y]
                # draw each line segment.
                for x,y in zip(xl,yl):
                    # skip if only a point.
                    if len(x) > 1 and len(y) > 1:
                        l = Line2D(x,y,linewidth=linewidth,linestyle=linestyle)
                        l.set_color(color)
                        l.set_dashes(dashes)
                        ax.add_line(l)
        # draw labels for meridians.
        # search along edges of map to see if parallels intersect.
        # if so, find x,y location of intersection and draw a label there.
        if self.projection == 'cyl':
            dx = 0.01; dy = 0.01
        elif self.projection == 'merc':
            dx = 0.01; dy = 1000
        else:
            dx = 1000; dy = 1000
        for dolab,side in zip(labels,['l','r','t','b']):
            if not dolab: continue
            # for cyl or merc, don't draw meridians on left or right.
            if self.projection in ['cyl','merc'] and side in ['l','r']: continue
            if side in ['l','r']:
	        nmax = int((self.ymax-self.ymin)/dy+1)
                if self.urcrnry < self.llcrnry:
	            yy = self.llcrnry-dy*N.arange(nmax)
                else:
	            yy = self.llcrnry+dy*N.arange(nmax)
                if side == 'l':
	            lons,lats = self(self.llcrnrx*N.ones(yy.shape,'f'),yy,inverse=True)
                else:
	            lons,lats = self(self.urcrnrx*N.ones(yy.shape,'f'),yy,inverse=True)
                lons = N.where(lons < 0, lons+360, lons)
                lons = [int(lon*10) for lon in lons.tolist()]
                lats = [int(lat*10) for lat in lats.tolist()]
            else:
	        nmax = int((self.xmax-self.xmin)/dx+1)
                if self.urcrnrx < self.llcrnrx:
	            xx = self.llcrnrx-dx*N.arange(nmax)
                else:
	            xx = self.llcrnrx+dx*N.arange(nmax)
                if side == 'b':
	            lons,lats = self(xx,self.llcrnry*N.ones(xx.shape,'f'),inverse=True)
                else:
	            lons,lats = self(xx,self.urcrnry*N.ones(xx.shape,'f'),inverse=True)
                lons = N.where(lons < 0, lons+360, lons)
                lons = [int(lon*10) for lon in lons.tolist()]
                lats = [int(lat*10) for lat in lats.tolist()]
            for lon in meridians:
                if lon<0: lon=lon+360.
                # find index of meridian (there may be two, so
                # search from left and right).
                try:
                    nl = lons.index(int(lon*10))
                except:
                    nl = -1
                try:
                    nr = len(lons)-lons[::-1].index(int(lon*10))-1
                except:
                    nr = -1
        	if lon>180:
        	    lonlab = r'$\%s{%g\/^{\circ}\/W}$'%(font,N.fabs(lon-360))
        	elif lon<180 and lon != 0:
        	    lonlab = r'$\%s{%g\/^{\circ}\/E}$'%(font,lon)
        	else:
        	    lonlab = r'$\%s{%g\/^{\circ}}$'%(font,lon)
                # meridians can intersect each map edge twice.
                for i,n in enumerate([nl,nr]):
                    lat = lats[n]/10.
                    # no meridians > latmax for projections other than merc,cyl.
                    if self.projection not in ['merc','cyl'] and lat > latmax: continue
                    # don't bother if close to the first label.
                    if i and abs(nr-nl) < 100: continue
                    if n > 0:
                        if side == 'l':
        	            pylab.text(self.llcrnrx-xoffset,yy[n],lonlab,horizontalalignment='right',verticalalignment='center',fontsize=fontsize)
                        elif side == 'r':
        	            pylab.text(self.urcrnrx+xoffset,yy[n],lonlab,horizontalalignment='left',verticalalignment='center',fontsize=fontsize)
                        elif side == 'b':
        	            pylab.text(xx[n],self.llcrnry-yoffset,lonlab,horizontalalignment='center',verticalalignment='top',fontsize=fontsize)
                        else:
        	            pylab.text(xx[n],self.urcrnry+yoffset,lonlab,horizontalalignment='center',verticalalignment='bottom',fontsize=fontsize)

        # make sure axis ticks are turned off
        ax.set_xticks([]) 
        ax.set_yticks([])
Beispiel #9
0
    def drawmeridians(self,ax,meridians,color='k',linewidth=1., \
                      linestyle='--',dashes=[1,1],labels=[0,0,0,0],\
                      font='rm',fontsize=12):
        """
 draw meridians (longitude lines).

 ax - current axis instance.
 meridians - list containing longitude values to draw (in degrees).
 color - color to draw meridians (default black).
 linewidth - line width for meridians (default 1.)
 linestyle - line style for meridians (default '--', i.e. dashed).
 dashes - dash pattern for meridians (default [1,1], i.e. 1 pixel on,
  1 pixel off).
 labels - list of 4 values (default [0,0,0,0]) that control whether
  meridians are labelled where they intersect the left, right, top or 
  bottom of the plot. For example labels=[1,0,0,1] will cause meridians
  to be labelled where they intersect the left and bottom of the plot,
  but not the right and top. Labels are located with a precision of 0.1
  degrees and are drawn using mathtext.
 font - mathtext font used for labels ('rm','tt','it' or 'cal', default 'rm'.
 fontsize - font size in points for labels (default 12).
        """
        # don't draw meridians past latmax, always draw parallel at latmax.
        latmax = 80.  # not used for cyl, merc projections.
        # offset for labels.
        yoffset = (self.urcrnry - self.llcrnry) / 100. / self.aspect
        xoffset = (self.urcrnrx - self.llcrnrx) / 100.

        if self.projection not in ['merc', 'cyl']:
            lats = N.arange(-latmax, latmax + 1).astype('f')
        else:
            lats = N.arange(-90, 91).astype('f')
        xdelta = 0.1 * (self.xmax - self.xmin)
        ydelta = 0.1 * (self.ymax - self.ymin)
        for merid in meridians:
            lons = merid * N.ones(len(lats), 'f')
            x, y = self(lons, lats)
            # remove points outside domain.
            testx = N.logical_and(x >= self.xmin - xdelta,
                                  x <= self.xmax + xdelta)
            x = N.compress(testx, x)
            y = N.compress(testx, y)
            testy = N.logical_and(y >= self.ymin - ydelta,
                                  y <= self.ymax + ydelta)
            x = N.compress(testy, x)
            y = N.compress(testy, y)
            if len(x) > 1 and len(y) > 1:
                # split into separate line segments if necessary.
                # (not necessary for mercator or cylindrical).
                xd = (x[1:] - x[0:-1])**2
                yd = (y[1:] - y[0:-1])**2
                dist = N.sqrt(xd + yd)
                split = dist > 500000.
                if N.sum(split) and self.projection not in ['merc', 'cyl']:
                    ind = (N.compress(
                        split, pylab.squeeze(split * N.indices(xd.shape))) +
                           1).tolist()
                    xl = []
                    yl = []
                    iprev = 0
                    ind.append(len(xd))
                    for i in ind:
                        xl.append(x[iprev:i])
                        yl.append(y[iprev:i])
                        iprev = i
                else:
                    xl = [x]
                    yl = [y]
                # draw each line segment.
                for x, y in zip(xl, yl):
                    # skip if only a point.
                    if len(x) > 1 and len(y) > 1:
                        l = Line2D(x,
                                   y,
                                   linewidth=linewidth,
                                   linestyle=linestyle)
                        l.set_color(color)
                        l.set_dashes(dashes)
                        ax.add_line(l)
        # draw labels for meridians.
        # search along edges of map to see if parallels intersect.
        # if so, find x,y location of intersection and draw a label there.
        if self.projection == 'cyl':
            dx = 0.01
            dy = 0.01
        elif self.projection == 'merc':
            dx = 0.01
            dy = 1000
        else:
            dx = 1000
            dy = 1000
        for dolab, side in zip(labels, ['l', 'r', 't', 'b']):
            if not dolab: continue
            # for cyl or merc, don't draw meridians on left or right.
            if self.projection in ['cyl', 'merc'] and side in ['l', 'r']:
                continue
            if side in ['l', 'r']:
                nmax = int((self.ymax - self.ymin) / dy + 1)
                if self.urcrnry < self.llcrnry:
                    yy = self.llcrnry - dy * N.arange(nmax)
                else:
                    yy = self.llcrnry + dy * N.arange(nmax)
                if side == 'l':
                    lons, lats = self(self.llcrnrx * N.ones(yy.shape, 'f'),
                                      yy,
                                      inverse=True)
                else:
                    lons, lats = self(self.urcrnrx * N.ones(yy.shape, 'f'),
                                      yy,
                                      inverse=True)
                lons = N.where(lons < 0, lons + 360, lons)
                lons = [int(lon * 10) for lon in lons.tolist()]
                lats = [int(lat * 10) for lat in lats.tolist()]
            else:
                nmax = int((self.xmax - self.xmin) / dx + 1)
                if self.urcrnrx < self.llcrnrx:
                    xx = self.llcrnrx - dx * N.arange(nmax)
                else:
                    xx = self.llcrnrx + dx * N.arange(nmax)
                if side == 'b':
                    lons, lats = self(xx,
                                      self.llcrnry * N.ones(xx.shape, 'f'),
                                      inverse=True)
                else:
                    lons, lats = self(xx,
                                      self.urcrnry * N.ones(xx.shape, 'f'),
                                      inverse=True)
                lons = N.where(lons < 0, lons + 360, lons)
                lons = [int(lon * 10) for lon in lons.tolist()]
                lats = [int(lat * 10) for lat in lats.tolist()]
            for lon in meridians:
                if lon < 0: lon = lon + 360.
                # find index of meridian (there may be two, so
                # search from left and right).
                try:
                    nl = lons.index(int(lon * 10))
                except:
                    nl = -1
                try:
                    nr = len(lons) - lons[::-1].index(int(lon * 10)) - 1
                except:
                    nr = -1
                if lon > 180:
                    lonlab = r'$\%s{%g\/^{\circ}\/W}$' % (font,
                                                          N.fabs(lon - 360))
                elif lon < 180 and lon != 0:
                    lonlab = r'$\%s{%g\/^{\circ}\/E}$' % (font, lon)
                else:
                    lonlab = r'$\%s{%g\/^{\circ}}$' % (font, lon)
                # meridians can intersect each map edge twice.
                for i, n in enumerate([nl, nr]):
                    lat = lats[n] / 10.
                    # no meridians > latmax for projections other than merc,cyl.
                    if self.projection not in ['merc', 'cyl'] and lat > latmax:
                        continue
                    # don't bother if close to the first label.
                    if i and abs(nr - nl) < 100: continue
                    if n > 0:
                        if side == 'l':
                            pylab.text(self.llcrnrx - xoffset,
                                       yy[n],
                                       lonlab,
                                       horizontalalignment='right',
                                       verticalalignment='center',
                                       fontsize=fontsize)
                        elif side == 'r':
                            pylab.text(self.urcrnrx + xoffset,
                                       yy[n],
                                       lonlab,
                                       horizontalalignment='left',
                                       verticalalignment='center',
                                       fontsize=fontsize)
                        elif side == 'b':
                            pylab.text(xx[n],
                                       self.llcrnry - yoffset,
                                       lonlab,
                                       horizontalalignment='center',
                                       verticalalignment='top',
                                       fontsize=fontsize)
                        else:
                            pylab.text(xx[n],
                                       self.urcrnry + yoffset,
                                       lonlab,
                                       horizontalalignment='center',
                                       verticalalignment='bottom',
                                       fontsize=fontsize)

        # make sure axis ticks are turned off
        ax.set_xticks([])
        ax.set_yticks([])
def logistic_regression(x,y,beta_start=None,verbose=False,CONV_THRESH=1.e-3,
                        MAXIT=500):
    """
 Uses the Newton-Raphson algorithm to calculate a maximum
 likelihood estimate logistic regression.
 The algorithm is known as 'iteratively re-weighted least squares', or IRLS.

 x - rank-1 or rank-2 array of predictors. If x is rank-2,
     the number of predictors = x.shape[0] = N.  If x is rank-1,
     it is assumed N=1.
     
 y - binary outcomes (if N>1 len(y) = x.shape[1], if N=1 len(y) = len(x))
 
 beta_start - initial beta vector (default zeros(N+1,x.dtype.char))
 
 if verbose=True, diagnostics printed for each iteration (default False).
 
 MAXIT - max number of iterations (default 500)
 
 CONV_THRESH - convergence threshold (sum of absolute differences
  of beta-beta_old, default 0.001)

 returns beta (the logistic regression coefficients, an N+1 element vector),
 J_bar (the (N+1)x(N+1) information matrix), and l (the log-likeliehood).
 
 J_bar can be used to estimate the covariance matrix and the standard
 error for beta.
 
 l can be used for a chi-squared significance test.

 covmat = inverse(J_bar)     --> covariance matrix of coefficents (beta)
 stderr = sqrt(diag(covmat)) --> standard errors for beta
 deviance = -2l              --> scaled deviance statistic
 chi-squared value for -2l is the model chi-squared test.
    """
    if x.shape[-1] != len(y):
        raise ValueError, "x.shape[-1] and y should be the same length!"
    try:
        N, npreds = x.shape[1], x.shape[0]
    except: # single predictor, use simple logistic regression routine.
        return _simple_logistic_regression(x,y,beta_start=beta_start,
               CONV_THRESH=CONV_THRESH,MAXIT=MAXIT,verbose=verbose)
    if beta_start is None:
        beta_start = NA.zeros(npreds+1,x.dtype.char)
    X = NA.ones((npreds+1,N), x.dtype.char)
    X[1:, :] = x
    Xt = NA.transpose(X)
    iter = 0; diff = 1.; beta = beta_start  # initial values
    if verbose:
        print 'iteration  beta log-likliehood |beta-beta_old|' 
    while iter < MAXIT:
        beta_old = beta 
        ebx = NA.exp(NA.dot(beta, X))
        p = ebx/(1.+ebx)
        l = NA.sum(y*NA.log(p) + (1.-y)*NA.log(1.-p)) # log-likeliehood
        s = NA.dot(X, y-p)                            # scoring function
        J_bar = NA.dot(X*p,Xt)                        # information matrix
        beta = beta_old + NA.dot(LA.inverse(J_bar),s) # new value of beta
        diff = NA.sum(NA.fabs(beta-beta_old)) # sum of absolute differences
        if verbose:
            print iter+1, beta, l, diff
        if diff <= CONV_THRESH: break
        iter = iter + 1
    if iter == MAXIT and diff > CONV_THRESH: 
        print 'warning: convergence not achieved with threshold of %s in %s iterations' % (CONV_THRESH,MAXIT)
    return beta, J_bar, l