~ubuntu-branches/ubuntu/karmic/python-scipy/karmic

« back to all changes in this revision

Viewing changes to scipy/sandbox/pyloess/src/_loess.pyx

  • Committer: Bazaar Package Importer
  • Author(s): Ondrej Certik
  • Date: 2008-06-16 22:58:01 UTC
  • mfrom: (2.1.24 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080616225801-irdhrpcwiocfbcmt
Tags: 0.6.0-12
* The description updated to match the current SciPy (Closes: #489149).
* Standards-Version bumped to 3.8.0 (no action needed)
* Build-Depends: netcdf-dev changed to libnetcdf-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- Mode: Python -*-  
 
2
cimport c_python
 
3
cimport c_numpy
 
4
from c_numpy cimport ndarray, npy_intp, \
 
5
    PyArray_SIZE, PyArray_EMPTY, PyArray_FROMANY, \
 
6
    NPY_INT, NPY_DOUBLE, NPY_OWNDATA, NPY_ALIGNED, NPY_FORTRAN, \
 
7
    PyArray_SimpleNewFromData
 
8
import numpy
 
9
narray = numpy.array
 
10
float_ = numpy.float_
 
11
 
 
12
# NumPy must be initialized
 
13
c_numpy.import_array()
 
14
 
 
15
cimport c_loess
 
16
 
 
17
cdef floatarray_from_data(int rows, int cols, double *data):
 
18
    cdef ndarray a_ndr
 
19
    cdef npy_intp size
 
20
    size = rows*cols
 
21
    a_ndr = <object>PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, data)
 
22
    if cols > 1:
 
23
        a_ndr.shape = (rows, cols)
 
24
    return a_ndr
 
25
 
 
26
cdef boolarray_from_data(int rows, int cols, int *data):
 
27
    cdef ndarray a_ndr
 
28
    cdef npy_intp size
 
29
    size = rows*cols
 
30
    a_ndr = <object>PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, data)
 
31
    if cols > 1:
 
32
        a_ndr.shape = (rows, cols)
 
33
    return a_ndr.astype(numpy.bool)
 
34
 
 
35
 
 
36
"""
 
37
        
 
38
 
 
39
    newdata : ndarray
 
40
        The (m,p) array of independent variables where the surface must be estimated.
 
41
    values : ndarray
 
42
        The (m,) ndarray of loess values evaluated at newdata
 
43
    stderr : ndarray
 
44
        The (m,) ndarray of the estimates of the standard error on the estimated
 
45
        values.
 
46
    residual_scale : float
 
47
        Estimate of the scale of the residuals
 
48
    df : integer
 
49
        Degrees of freedom of the t-distribution used to compute pointwise 
 
50
        confidence intervals for the evaluated surface.
 
51
    nest : integer
 
52
        Number of new observations.
 
53
       
 
54
        
 
55
"""
 
56
 
 
57
 
 
58
#####---------------------------------------------------------------------------
 
59
#---- ---- loess model ---
 
60
#####---------------------------------------------------------------------------
 
61
cdef class loess_inputs:
 
62
    """Loess inputs
 
63
    
 
64
:IVariables:
 
65
    x : ndarray
 
66
        A (n,p) ndarray of independent variables, with n the number of observations
 
67
        and p the number of variables.
 
68
    y : ndarray
 
69
        A (n,) ndarray of observations
 
70
    nobs : integer
 
71
        Number of observations: nobs=n.
 
72
    npar : integer
 
73
        Number of independent variables: npar=p.
 
74
    weights : ndarray
 
75
        A (n,) ndarray of weights to be given to individual observations in the 
 
76
        sum of squared residuals that forms the local fitting criterion. If not
 
77
        None, the weights should be non negative. If the different observations
 
78
        have non-equal variances, the weights should be inversely proportional 
 
79
        to the variances.
 
80
        By default, an unweighted fit is carried out (all the weights are one).
 
81
    """
 
82
    cdef c_loess.c_loess_inputs *_base
 
83
    cdef ndarray w_ndr
 
84
    cdef readonly ndarray x, y, masked, x_eff, y_eff
 
85
    cdef readonly int nobs, npar
 
86
    #.........
 
87
    def __init__(self, x_data, y_data):
 
88
        cdef ndarray unmasked
 
89
        self.x = narray(x_data, copy=False, subok=True, dtype=float_, order='C')
 
90
        self.y = narray(y_data, copy=False, subok=True, dtype=float_, order='C')
 
91
        # Check the dimensions ........
 
92
        if self.x.ndim == 1:
 
93
            self.npar = 1
 
94
        elif self.x.ndim == 2:
 
95
            self.npar = self.x.shape[-1]
 
96
        else:
 
97
            raise ValueError("The array of indepedent varibales should be 2D at most!")
 
98
        self.nobs = len(self.x)         
 
99
        # Get the effective data ......
 
100
        self.x_eff = self.x.ravel()
 
101
        self.y_eff = self.y
 
102
        self.w_ndr = numpy.ones((self.nobs,), dtype=float_)
 
103
 
 
104
    #.........    
 
105
    property weights:
 
106
        """A (n,) ndarray of weights to be given to individual observations in the 
 
107
        sum of squared residuals that forms the local fitting criterion. If not
 
108
        None, the weights should be non negative. If the different observations
 
109
        have non-equal variances, the weights should be inversely proportional 
 
110
        to the variances.
 
111
        By default, an unweighted fit is carried out (all the weights are one).
 
112
        """
 
113
        def __get__(self):
 
114
            return self.w_ndr
 
115
        
 
116
        def __set__(self, w):
 
117
            cdef npy_intp *dims
 
118
            cdef ndarray w_ndr
 
119
            w_ndr = narray(w, copy=False, subok=False)
 
120
            if w_ndr.ndim > 1 or w_ndr.size != self.nobs:
 
121
                raise ValueError, "Invalid size of the 'weights' vector!"
 
122
            self.w_ndr = w_ndr
 
123
            self._base.weights = <double *>w_ndr.data
 
124
#       
 
125
######---------------------------------------------------------------------------
 
126
##---- ---- loess control ---
 
127
######---------------------------------------------------------------------------
 
128
cdef class loess_control:
 
129
    """Loess control parameters.
 
130
    
 
131
:IVariables:
 
132
    surface : string ["interpolate"]
 
133
        Determines whether the fitted surface is computed directly at all points
 
134
        ("direct") or whether an interpolation method is used ("interpolate").
 
135
        The default ("interpolate") is what most users should use unless special 
 
136
        circumstances warrant.
 
137
    statistics : string ["approximate"]
 
138
        Determines whether the statistical quantities are computed exactly 
 
139
        ("exact") or approximately ("approximate"). "exact" should only be used 
 
140
        for testing the approximation in statistical development and is not meant 
 
141
        for routine usage because computation time can be horrendous.
 
142
    trace_hat : string ["wait.to.decide"]
 
143
        Determines how the trace of the hat matrix should be computed. The hat
 
144
        matrix is used in the computation of the statistical quantities. 
 
145
        If "exact", an exact computation is done; this could be slow when the
 
146
        number of observations n becomes large. If "wait.to.decide" is selected, 
 
147
        then a default is "exact" for n < 500 and "approximate" otherwise. 
 
148
        This option is only useful when the fitted surface is interpolated. If  
 
149
        surface is "exact", an exact computation is always done for the trace. 
 
150
        Setting trace_hat to "approximate" for large dataset will substantially 
 
151
        reduce the computation time.
 
152
    iterations : integer
 
153
        Number of iterations of the robust fitting method. If the family is 
 
154
        "gaussian", the number of iterations is set to 0.
 
155
    cell : integer
 
156
        Maximum cell size of the kd-tree. Suppose k = floor(n*cell*span),
 
157
        where n is the number of observations, and span the smoothing parameter.
 
158
        Then, a cell is further divided if the number of observations within it 
 
159
        is greater than or equal to k. This option is only used if the surface 
 
160
        is interpolated.
 
161
    
 
162
    """
 
163
    cdef c_loess.c_loess_control *_base
 
164
    #.........    
 
165
    property surface:
 
166
        """
 
167
    surface : string ["interpolate"]
 
168
        Determines whether the fitted surface is computed directly at all points
 
169
        ("direct") or whether an interpolation method is used ("interpolate").
 
170
        The default ("interpolate") is what most users should use unless special 
 
171
        circumstances warrant.
 
172
        """
 
173
        def __get__(self):
 
174
            return self._base.surface
 
175
        def __set__(self, surface):
 
176
            if surface.lower() not in ('interpolate', 'direct'):
 
177
                raise ValueError("Invalid value for the 'surface' argument: "+
 
178
                                 "should be in ('interpolate', 'direct').")
 
179
            tmpx = surface.lower()
 
180
            self._base.surface = tmpx
 
181
    #.........
 
182
    property statistics:
 
183
        """
 
184
    statistics : string ["approximate"]
 
185
        Determines whether the statistical quantities are computed exactly 
 
186
        ("exact") or approximately ("approximate"). "exact" should only be used 
 
187
        for testing the approximation in statistical development and is not meant 
 
188
        for routine usage because computation time can be horrendous.
 
189
        """
 
190
        def __get__(self):
 
191
            return self._base.statistics
 
192
        def __set__(self, statistics):
 
193
            if statistics.lower() not in ('approximate', 'exact'):
 
194
                raise ValueError("Invalid value for the 'statistics' argument: "\
 
195
                                 "should be in ('approximate', 'exact').")
 
196
            tmpx = statistics.lower()
 
197
            self._base.statistics = tmpx
 
198
    #.........
 
199
    property trace_hat:
 
200
        """
 
201
    trace_hat : string ["wait.to.decide"]
 
202
        Determines how the trace of the hat matrix should be computed. The hat
 
203
        matrix is used in the computation of the statistical quantities. 
 
204
        If "exact", an exact computation is done; this could be slow when the
 
205
        number of observations n becomes large. If "wait.to.decide" is selected, 
 
206
        then a default is "exact" for n < 500 and "approximate" otherwise. 
 
207
        This option is only useful when the fitted surface is interpolated. If  
 
208
        surface is "exact", an exact computation is always done for the trace. 
 
209
        Setting trace_hat to "approximate" for large dataset will substantially 
 
210
        reduce the computation time.
 
211
        """
 
212
        def __get__(self):
 
213
            return self._base.trace_hat
 
214
        def __set__(self, trace_hat):
 
215
            if trace_hat.lower() not in ('approximate', 'exact'):
 
216
                raise ValueError("Invalid value for the 'trace_hat' argument: "\
 
217
                                 "should be in ('approximate', 'exact').")
 
218
            tmpx = trace_hat.lower()
 
219
            self._base.trace_hat = tmpx
 
220
    #.........
 
221
    property iterations:
 
222
        """
 
223
    iterations : integer
 
224
        Number of iterations of the robust fitting method. If the family is 
 
225
        "gaussian", the number of iterations is set to 0.
 
226
        """
 
227
        def __get__(self):
 
228
            return self._base.iterations
 
229
        def __set__(self, iterations):
 
230
            if iterations < 0:
 
231
                raise ValueError("Invalid number of iterations: should be positive")
 
232
            self._base.iterations = iterations
 
233
    #.........
 
234
    property cell:
 
235
        """
 
236
    cell : integer
 
237
        Maximum cell size of the kd-tree. Suppose k = floor(n*cell*span),
 
238
        where n is the number of observations, and span the smoothing parameter.
 
239
        Then, a cell is further divided if the number of observations within it 
 
240
        is greater than or equal to k. This option is only used if the surface 
 
241
        is interpolated.
 
242
        """     
 
243
        def __get__(self):
 
244
            return self._base.cell
 
245
        def __set__(self, cell):
 
246
            if cell <= 0:
 
247
                raise ValueError("Invalid value for the cell argument: should be positive")
 
248
            self._base.cell = cell
 
249
    #.........
 
250
    def update(self, **cellargs):
 
251
        """Updates several parameters at once."""
 
252
        surface = cellargs.get('surface', None)
 
253
        if surface is not None:
 
254
            self.surface = surface
 
255
        #
 
256
        statistics = cellargs.get('statistics', None)
 
257
        if statistics is not None:
 
258
            self.statistics = statistics
 
259
        #    
 
260
        trace_hat = cellargs.get('trace_hat', None)
 
261
        if trace_hat is not None:
 
262
            self.trace_hat = trace_hat
 
263
        #
 
264
        iterations = cellargs.get('iterations', None)
 
265
        if iterations is not None:
 
266
            self.iterations = iterations
 
267
        #
 
268
        cell = cellargs.get('cell', None)
 
269
        if cell is not None:
 
270
            self.parametric_flags = cell
 
271
        #
 
272
    #.........
 
273
    def __str__(self):
 
274
        strg = ["Control          :",
 
275
                "Surface type     : %s" % self.surface,
 
276
                "Statistics       : %s" % self.statistics,
 
277
                "Trace estimation : %s" % self.trace_hat,
 
278
                "Cell size        : %s" % self.cell,
 
279
                "Nb iterations    : %s" % self.iterations,]
 
280
        return '\n'.join(strg)
 
281
        
 
282
#    
 
283
######---------------------------------------------------------------------------
 
284
##---- ---- loess kd_tree ---
 
285
######---------------------------------------------------------------------------
 
286
cdef class loess_kd_tree:
 
287
    cdef c_loess.c_loess_kd_tree *_base
 
288
 
 
289
######---------------------------------------------------------------------------
 
290
##---- ---- loess model ---
 
291
######---------------------------------------------------------------------------
 
292
cdef class loess_model:
 
293
    """loess_model contains parameters required for a loess fit.
 
294
    
 
295
:IVariables:
 
296
    normalize : boolean [True]
 
297
        Determines whether the independent variables should be normalized.  
 
298
        If True, the normalization is performed by setting the 10% trimmed 
 
299
        standard deviation to one. If False, no normalization is carried out. 
 
300
        This option is only useful for more than one variable. For spatial
 
301
        coordinates predictors or variables with a common scale, it should be 
 
302
        set to False.
 
303
    span : float [0.75]
 
304
        Smoothing factor, as a fraction of the number of points to take into
 
305
        account. 
 
306
    degree : integer [2]
 
307
        Overall degree of locally-fitted polynomial. 1 is locally-linear 
 
308
        fitting and 2 is locally-quadratic fitting.  Degree should be 2 at most.
 
309
    family : string ["gaussian"]
 
310
        Determines the assumed distribution of the errors. The values are 
 
311
        "gaussian" or "symmetric". If "gaussian" is selected, the fit is 
 
312
        performed with least-squares. If "symmetric" is selected, the fit
 
313
        is performed robustly by redescending M-estimators.
 
314
    parametric_flags : sequence [ [False]*p ]
 
315
        Indicates which independent variables should be conditionally-parametric
 
316
        (if there are two or more independent variables). The argument should be
 
317
        a sequence of booleans, with the same size as the number of independent 
 
318
        variables, specified in the order of the predictor group ordered in x. 
 
319
        Note: elements of the sequence cannot be modified individually: the whole
 
320
        sequence must be given.
 
321
    drop_square : sequence [ [False]* p]
 
322
        When there are two or more independent variables and when a 2nd order
 
323
        polynomial is used, "drop_square_flags" specifies those numeric predictors 
 
324
        whose squares should be dropped from the set of fitting variables. 
 
325
        The method of specification is the same as for parametric.  
 
326
        Note: elements of the sequence cannot be modified individually: the whole
 
327
        sequence must be given.
 
328
 
 
329
    """
 
330
        
 
331
    cdef c_loess.c_loess_model *_base
 
332
    cdef long npar
 
333
    #.........
 
334
    cdef setup(self, c_loess.c_loess_model *base, long npar):
 
335
        self._base = base
 
336
        self.npar = npar
 
337
        return self    
 
338
    #.........
 
339
    property normalize:
 
340
        def __get__(self):
 
341
            return bool(self._base.normalize)
 
342
        def __set__(self, normalize):
 
343
            self._base.normalize = normalize
 
344
    #.........
 
345
    property span:
 
346
        def __get__(self):
 
347
            return self._base.span
 
348
        def __set__(self, span):
 
349
            if span <= 0. or span > 1.:
 
350
                raise ValueError("Span should be between 0 and 1!")
 
351
            self._base.span = span
 
352
    #.........
 
353
    property degree:
 
354
        def __get__(self):
 
355
            return self._base.degree
 
356
        def __set__(self, degree):
 
357
            if degree < 0 or degree > 2:
 
358
                raise ValueError("Degree should be between 0 and 2!")
 
359
            self._base.degree = degree
 
360
    #.........
 
361
    property family:
 
362
        def __get__(self):
 
363
            return self._base.family
 
364
        def __set__(self, family):
 
365
            if family.lower() not in ('symmetric', 'gaussian'):
 
366
                raise ValueError("Invalid value for the 'family' argument: "\
 
367
                                 "should be in ('symmetric', 'gaussian').")
 
368
            self._base.family = family
 
369
    #.........
 
370
    property parametric_flags:
 
371
        def __get__(self):
 
372
            return boolarray_from_data(self.npar, 1, self._base.parametric)
 
373
        def __set__(self, paramf):
 
374
            cdef ndarray p_ndr
 
375
            cdef int i
 
376
            p_ndr = numpy.atleast_1d(narray(paramf, copy=False, subok=True, 
 
377
                                            dtype=numpy.bool))
 
378
            for i from 0 <= i < min(self.npar, p_ndr.size):
 
379
                self._base.parametric[i] = p_ndr[i]
 
380
    #.........
 
381
    property drop_square_flags:
 
382
        def __get__(self):
 
383
            return boolarray_from_data(self.npar, 1, self._base.drop_square)
 
384
        def __set__(self, drop_sq):
 
385
            cdef ndarray d_ndr
 
386
            cdef int i
 
387
            d_ndr = numpy.atleast_1d(narray(drop_sq, copy=False, subok=True, 
 
388
                                            dtype=numpy.bool))
 
389
            for i from 0 <= i < min(self.npar, d_ndr.size):
 
390
                self._base.drop_square[i] = d_ndr[i]
 
391
    #........
 
392
    def update(self, **modelargs):
 
393
        family = modelargs.get('family', None)
 
394
        if family is not None:
 
395
            self.family = family
 
396
        #
 
397
        span = modelargs.get('span', None)
 
398
        if span is not None:
 
399
            self.span = span
 
400
        #    
 
401
        degree = modelargs.get('degree', None)
 
402
        if degree is not None:
 
403
            self.degree = degree
 
404
        #
 
405
        normalize = modelargs.get('normalize', None)
 
406
        if normalize is not None:
 
407
            self.normalize = normalize
 
408
        #
 
409
        parametric = modelargs.get('parametric', None)
 
410
        if parametric is not None:
 
411
            self.parametric_flags = parametric
 
412
        #
 
413
        drop_square = modelargs.get('drop_square', None)
 
414
        if drop_square is not None:
 
415
            self.drop_square_flags = drop_square
 
416
    #.........
 
417
    def __repr__(self):
 
418
        return "<loess object: model parameters>"
 
419
    #.........
 
420
    def __str__(self):
 
421
        strg = ["Model parameters.....",
 
422
                "Family          : %s" % self.family,
 
423
                "Span            : %s" % self.span,
 
424
                "Degree          : %s" % self.degree,
 
425
                "Normalized      : %s" % self.normalize,
 
426
                "Parametric      : %s" % self.parametric_flags[:self.npar],
 
427
                "Drop_square     : %s" % self.drop_square_flags[:self.npar]
 
428
                ]
 
429
        return '\n'.join(strg)
 
430
        
 
431
#####---------------------------------------------------------------------------
 
432
#---- ---- loess outputs ---
 
433
#####---------------------------------------------------------------------------
 
434
cdef class loess_outputs:
 
435
    """Outputs of a loess fit. This object is automatically created with empty
 
436
values when a new loess object is instantiated. The object gets filled when the 
 
437
loess.fit() method is called.
 
438
    
 
439
:IVariables:
 
440
    fitted_values : ndarray
 
441
        The (n,) ndarray of fitted values.
 
442
    fitted_residuals : ndarray
 
443
        The (n,) ndarray of fitted residuals (observations - fitted values).
 
444
    enp : float
 
445
        Equivalent number of parameters.
 
446
    s : float
 
447
        Estimate of the scale of residuals.
 
448
    one_delta: float
 
449
        Statistical parameter used in the computation of standard errors.
 
450
    two_delta : float
 
451
        Statistical parameter used in the computation of standard errors.
 
452
    pseudovalues : ndarray
 
453
        The (n,) ndarray of adjusted values of the response when robust estimation 
 
454
        is used.
 
455
    trace_hat : float    
 
456
        Trace of the operator hat matrix.
 
457
    diagonal : ndarray
 
458
        Diagonal of the operator hat matrix.
 
459
    robust : ndarray
 
460
        The (n,) ndarray of robustness weights for robust fitting.
 
461
    divisor : ndarray
 
462
        The (p,) array of normalization divisors for numeric predictors.
 
463
    """
 
464
    cdef c_loess.c_loess_outputs *_base
 
465
    cdef long nobs, npar
 
466
    cdef readonly int activated
 
467
    cdef setup(self,c_loess.c_loess_outputs *base, long nobs, long npar):
 
468
        self._base = base
 
469
        self.nobs = nobs
 
470
        self.npar = npar
 
471
        self.activated = False
 
472
    #........
 
473
    property fitted_values:    
 
474
        def __get__(self):
 
475
            return floatarray_from_data(self.nobs, 1, self._base.fitted_values)
 
476
    #.........
 
477
    property fitted_residuals:
 
478
        def __get__(self):
 
479
            return floatarray_from_data(self.nobs, 1, self._base.fitted_residuals)
 
480
    #.........
 
481
    property pseudovalues:
 
482
        def __get__(self):
 
483
            return floatarray_from_data(self.nobs, 1, self._base.pseudovalues)
 
484
    #.........
 
485
    property diagonal:
 
486
        def __get__(self):
 
487
            return floatarray_from_data(self.nobs, 1, self._base.diagonal)
 
488
    #.........
 
489
    property robust:
 
490
        def __get__(self):
 
491
            return floatarray_from_data(self.nobs, 1, self._base.robust)
 
492
    #.........
 
493
    property divisor:
 
494
        def __get__(self):
 
495
            return floatarray_from_data(self.npar, 1, self._base.divisor)
 
496
    #.........    
 
497
    property enp:
 
498
        def __get__(self):
 
499
            return self._base.enp
 
500
    #.........
 
501
    property s:
 
502
        def __get__(self):
 
503
            return self._base.s
 
504
    #.........
 
505
    property one_delta:
 
506
        def __get__(self):
 
507
            return self._base.one_delta 
 
508
    #.........
 
509
    property two_delta:
 
510
        def __get__(self):
 
511
            return self._base.two_delta
 
512
    #.........
 
513
    property trace_hat:
 
514
        def __get__(self):
 
515
            return self._base.trace_hat
 
516
    #.........
 
517
    def __str__(self):
 
518
        strg = ["Outputs................",
 
519
                "Fitted values         : %s\n" % self.fitted_values,
 
520
                "Fitted residuals      : %s\n" % self.fitted_residuals,
 
521
                "Eqv. nb of parameters : %s" % self.enp,
 
522
                "Residual error        : %s" % self.s,
 
523
                "Deltas                : %s - %s" % (self.one_delta, self.two_delta),
 
524
                "Normalization factors : %s" % self.divisor,]
 
525
        return '\n'.join(strg)
 
526
 
 
527
 
 
528
        
 
529
#####---------------------------------------------------------------------------
 
530
#---- ---- loess confidence ---
 
531
#####---------------------------------------------------------------------------
 
532
cdef class conf_intervals:
 
533
    """Pointwise confidence intervals of a loess-predicted object:
 
534
    
 
535
:IVariables:
 
536
    fit : ndarray
 
537
        Predicted values.
 
538
    lower : ndarray
 
539
        Lower bounds of the confidence intervals.
 
540
    upper : ndarray
 
541
        Upper bounds of the confidence intervals.
 
542
    """
 
543
    cdef c_loess.c_conf_inv _base
 
544
    cdef readonly ndarray lower, fit, upper
 
545
    #.........
 
546
    def __dealloc__(self):
 
547
        c_loess.pw_free_mem(&self._base)
 
548
    #.........
 
549
    cdef setup(self, c_loess.c_conf_inv base, long nest):
 
550
        self._base = base
 
551
        self.fit = floatarray_from_data(nest, 1, base.fit)
 
552
        self.upper = floatarray_from_data(nest, 1, base.upper)
 
553
        self.lower = floatarray_from_data(nest, 1, base.lower)
 
554
    #.........
 
555
    def __str__(self):
 
556
        cdef ndarray tmp_ndr
 
557
        tmp_ndr = numpy.r_[[self.lower,self.fit,self.upper]].T
 
558
        return "Confidence intervals....\nLower b./ fit / upper b.\n%s" % \
 
559
               tmp_ndr 
 
560
 
 
561
#####---------------------------------------------------------------------------
 
562
#---- ---- loess predictions ---
 
563
#####---------------------------------------------------------------------------
 
564
cdef class loess_predicted:
 
565
    """Predicted values and standard errors of a loess object
 
566
 
 
567
:IVariables:
 
568
    values : ndarray
 
569
        The (m,) ndarray of loess values evaluated at newdata
 
570
    stderr : ndarray
 
571
        The (m,) ndarray of the estimates of the standard error on the estimated
 
572
        values.
 
573
    residual_scale : float
 
574
        Estimate of the scale of the residuals
 
575
    df : integer
 
576
        Degrees of freedom of the t-distribution used to compute pointwise 
 
577
        confidence intervals for the evaluated surface.
 
578
    nest : integer
 
579
        Number of new observations.
 
580
    """
 
581
        
 
582
    cdef c_loess.c_prediction _base
 
583
    cdef readonly long nest
 
584
    cdef readonly conf_intervals confidence_intervals
 
585
    #.........
 
586
    def __dealloc__(self):
 
587
        c_loess.pred_free_mem(&self._base)      
 
588
    #.........
 
589
    cdef setup(self, c_loess.c_prediction base, long nest):
 
590
        self._base = base
 
591
        self.nest = nest
 
592
    #.........
 
593
    property values:
 
594
        def __get__(self):
 
595
            return floatarray_from_data(self.nest, 1, self._base.fit)
 
596
    #.........
 
597
    property stderr:
 
598
        def __get__(self):
 
599
            return floatarray_from_data(self.nest, 1, self._base.se_fit)
 
600
    #.........
 
601
    property residual_scale:
 
602
        def __get__(self):
 
603
            return self._base.residual_scale
 
604
    #.........
 
605
    property df:
 
606
        def __get__(self):
 
607
            return self._base.df        
 
608
    #.........
 
609
    def confidence(self, coverage=0.95):
 
610
        """Returns the pointwise confidence intervals for each predicted values,
 
611
at the given confidence interval coverage.
 
612
        
 
613
:Parameters:
 
614
    coverage : float
 
615
        Confidence level of the confidence intervals limits, as a fraction.
 
616
        
 
617
:Returns:
 
618
    A new conf_intervals object, consisting of:
 
619
    fit : ndarray
 
620
        Predicted values.
 
621
    lower : ndarray
 
622
        Lower bounds of the confidence intervals.
 
623
    upper : ndarray
 
624
        Upper bounds of the confidence intervals.
 
625
        """
 
626
        cdef c_loess.c_conf_inv _confintv
 
627
        if coverage < 0.5:
 
628
            coverage = 1. - coverage 
 
629
        if coverage > 1. :
 
630
            raise ValueError("The coverage precentage should be between 0 and 1!")
 
631
        c_loess.c_pointwise(&self._base, self.nest, coverage, &_confintv)
 
632
        self.confidence_intervals = conf_intervals()
 
633
        self.confidence_intervals.setup(_confintv, self.nest)
 
634
        return self.confidence_intervals
 
635
    #.........
 
636
    def __str__(self):
 
637
        strg = ["Outputs................",
 
638
                "Predicted values      : %s\n" % self.values,
 
639
                "Predicted std error   : %s\n" % self.stderr,
 
640
                "Residual scale        : %s" % self.residual_scale,
 
641
                "Degrees of freedom    : %s" % self.df,
 
642
#                "Confidence intervals  : %s" % self.confidence,
 
643
                ]
 
644
        return '\n'.join(strg)
 
645
    
 
646
 
 
647
#####---------------------------------------------------------------------------
 
648
#---- ---- loess base class ---
 
649
#####---------------------------------------------------------------------------
 
650
cdef class loess:
 
651
    """
 
652
    
 
653
:Keywords:
 
654
    x : ndarray
 
655
        A (n,p) ndarray of independent variables, with n the number of observations
 
656
        and p the number of variables.
 
657
    y : ndarray
 
658
        A (n,) ndarray of observations
 
659
    weights : ndarray
 
660
        A (n,) ndarray of weights to be given to individual observations in the 
 
661
        sum of squared residuals that forms the local fitting criterion. If not
 
662
        None, the weights should be non negative. If the different observations
 
663
        have non-equal variances, the weights should be inversely proportional 
 
664
        to the variances.
 
665
        By default, an unweighted fit is carried out (all the weights are one).
 
666
    surface : string ["interpolate"]
 
667
        Determines whether the fitted surface is computed directly at all points
 
668
        ("direct") or whether an interpolation method is used ("interpolate").
 
669
        The default ("interpolate") is what most users should use unless special 
 
670
        circumstances warrant.
 
671
    statistics : string ["approximate"]
 
672
        Determines whether the statistical quantities are computed exactly 
 
673
        ("exact") or approximately ("approximate"). "exact" should only be used 
 
674
        for testing the approximation in statistical development and is not meant 
 
675
        for routine usage because computation time can be horrendous.
 
676
    trace_hat : string ["wait.to.decide"]
 
677
        Determines how the trace of the hat matrix should be computed. The hat
 
678
        matrix is used in the computation of the statistical quantities. 
 
679
        If "exact", an exact computation is done; this could be slow when the
 
680
        number of observations n becomes large. If "wait.to.decide" is selected, 
 
681
        then a default is "exact" for n < 500 and "approximate" otherwise. 
 
682
        This option is only useful when the fitted surface is interpolated. If  
 
683
        surface is "exact", an exact computation is always done for the trace. 
 
684
        Setting trace_hat to "approximate" for large dataset will substantially 
 
685
        reduce the computation time.
 
686
    iterations : integer
 
687
        Number of iterations of the robust fitting method. If the family is 
 
688
        "gaussian", the number of iterations is set to 0.
 
689
    cell : integer
 
690
        Maximum cell size of the kd-tree. Suppose k = floor(n*cell*span),
 
691
        where n is the number of observations, and span the smoothing parameter.
 
692
        Then, a cell is further divided if the number of observations within it 
 
693
        is greater than or equal to k. This option is only used if the surface 
 
694
        is interpolated.
 
695
    span : float [0.75]
 
696
        Smoothing factor, as a fraction of the number of points to take into
 
697
        account. 
 
698
    degree : integer [2]
 
699
        Overall degree of locally-fitted polynomial. 1 is locally-linear 
 
700
        fitting and 2 is locally-quadratic fitting.  Degree should be 2 at most.
 
701
    normalize : boolean [True]
 
702
        Determines whether the independent variables should be normalized.  
 
703
        If True, the normalization is performed by setting the 10% trimmed 
 
704
        standard deviation to one. If False, no normalization is carried out. 
 
705
        This option is only useful for more than one variable. For spatial
 
706
        coordinates predictors or variables with a common scale, it should be 
 
707
        set to False.
 
708
    family : string ["gaussian"]
 
709
        Determines the assumed distribution of the errors. The values are 
 
710
        "gaussian" or "symmetric". If "gaussian" is selected, the fit is 
 
711
        performed with least-squares. If "symmetric" is selected, the fit
 
712
        is performed robustly by redescending M-estimators.
 
713
    parametric_flags : sequence [ [False]*p ]
 
714
        Indicates which independent variables should be conditionally-parametric
 
715
       (if there are two or more independent variables). The argument should 
 
716
       be a sequence of booleans, with the same size as the number of independent 
 
717
       variables, specified in the order of the predictor group ordered in x. 
 
718
    drop_square : sequence [ [False]* p]
 
719
        When there are two or more independent variables and when a 2nd order
 
720
        polynomial is used, "drop_square_flags" specifies those numeric predictors 
 
721
        whose squares should be dropped from the set of fitting variables. 
 
722
        The method of specification is the same as for parametric.  
 
723
        
 
724
:Outputs:
 
725
    fitted_values : ndarray
 
726
        The (n,) ndarray of fitted values.
 
727
    fitted_residuals : ndarray
 
728
        The (n,) ndarray of fitted residuals (observations - fitted values).
 
729
    enp : float
 
730
        Equivalent number of parameters.
 
731
    s : float
 
732
        Estimate of the scale of residuals.
 
733
    one_delta: float
 
734
        Statistical parameter used in the computation of standard errors.
 
735
    two_delta : float
 
736
        Statistical parameter used in the computation of standard errors.
 
737
    pseudovalues : ndarray
 
738
        The (n,) ndarray of adjusted values of the response when robust estimation 
 
739
        is used.
 
740
    trace_hat : float    
 
741
        Trace of the operator hat matrix.
 
742
    diagonal :
 
743
        Diagonal of the operator hat matrix.
 
744
    robust : ndarray
 
745
        The (n,) ndarray of robustness weights for robust fitting.
 
746
    divisor : ndarray
 
747
        The (p,) array of normalization divisors for numeric predictors.
 
748
 
 
749
    """
 
750
    cdef c_loess.c_loess _base
 
751
    cdef readonly loess_inputs inputs
 
752
    cdef readonly loess_model model
 
753
    cdef readonly loess_control control
 
754
    cdef readonly loess_kd_tree kd_tree
 
755
    cdef readonly loess_outputs outputs
 
756
    cdef readonly loess_predicted predicted
 
757
    
 
758
    def __init__(self, object x, object y, object weights=None, **options):
 
759
        #
 
760
        cdef ndarray x_ndr, y_ndr
 
761
        cdef double *x_dat, *y_dat
 
762
        cdef int i
 
763
        # Initialize the inputs .......
 
764
        self.inputs = loess_inputs(x, y)
 
765
        x_dat = <double *>self.inputs.x_eff.data
 
766
        y_dat = <double *>self.inputs.y_eff.data
 
767
        n = self.inputs.nobs
 
768
        p = self.inputs.npar
 
769
        c_loess.loess_setup(x_dat, y_dat, n, p, &self._base)
 
770
        # Sets the _base input .........
 
771
        self.inputs._base = &self._base.inputs
 
772
        # Initialize the model parameters
 
773
        self.model = loess_model()
 
774
        self.model.setup(&self._base.model, p)
 
775
        # Initialize the control parameters
 
776
        self.control = loess_control()
 
777
        self.control._base = &self._base.control
 
778
        # Initialize the kd tree ......
 
779
        self.kd_tree = loess_kd_tree()
 
780
        self.kd_tree._base = &self._base.kd_tree
 
781
        # Initialize the outputs ......
 
782
        self.outputs = loess_outputs()
 
783
        self.outputs.setup(&self._base.outputs, n, p,)
 
784
        # Process options .............
 
785
        modelopt = {}
 
786
        controlopt = {}
 
787
        for (k,v) in options.iteritems():
 
788
            if k in ('family', 'span', 'degree', 'normalize', 
 
789
                     'parametric', 'drop_square',):
 
790
                modelopt[k] = v
 
791
            elif k in ('surface', 'statistics', 'trace_hat', 
 
792
                       'iterations', 'cell'):
 
793
                controlopt[k] = v
 
794
        self.control.update(**controlopt)
 
795
        self.model.update(**modelopt)
 
796
    #......................................................
 
797
    def fit(self):
 
798
        """Computes the loess parameters on the current inputs and sets of parameters."""
 
799
        c_loess.loess_fit(&self._base)
 
800
        self.outputs.activated = True
 
801
        if self._base.status.err_status:
 
802
            raise ValueError(self._base.status.err_msg)
 
803
        return
 
804
    #......................................................
 
805
    def input_summary(self):
 
806
        """Returns some generic information about the loess parameters.
 
807
        """
 
808
        toprint = [str(self.inputs), str(self.model), str(self.control)]
 
809
        return "\n".join(toprint)
 
810
        
 
811
    def output_summary(self):
 
812
        """Returns some generic information about the loess fit."""
 
813
        print "Number of Observations         : %d" % self.inputs.nobs
 
814
        print "Fit flag                       : %d" % bool(self.outputs.activated)
 
815
        print "Equivalent Number of Parameters: %.1f" % self.outputs.enp
 
816
        if self.model.family == "gaussian":
 
817
            print "Residual Standard Error        : %.4f" % self.outputs.s
 
818
        else:
 
819
            print "Residual Scale Estimate        : %.4f" % self.outputs.s
 
820
    #......................................................
 
821
    def predict(self, newdata, stderror=False):
 
822
        """Computes loess estimates at the given new data points newdata. Returns
 
823
a loess_predicted object, whose attributes are described below.
 
824
        
 
825
:Parameters:
 
826
    newdata : ndarray
 
827
        The (m,p) array of independent variables where the surface must be estimated,
 
828
        with m the number of new data points, and p the number of independent
 
829
        variables.
 
830
    stderror : boolean
 
831
        Whether the standard error should be computed
 
832
        
 
833
:Returns:
 
834
    A new loess_predicted object, consisting of:
 
835
    values : ndarray
 
836
        The (m,) ndarray of loess values evaluated at newdata
 
837
    stderr : ndarray
 
838
        The (m,) ndarray of the estimates of the standard error on the estimated
 
839
        values.
 
840
    residual_scale : float
 
841
        Estimate of the scale of the residuals
 
842
    df : integer
 
843
        Degrees of freedom of the t-distribution used to compute pointwise 
 
844
        confidence intervals for the evaluated surface.
 
845
    nest : integer
 
846
        Number of new observations.
 
847
        """
 
848
        cdef ndarray p_ndr
 
849
        cdef double *p_dat
 
850
        cdef c_loess.c_prediction _prediction
 
851
        cdef int i, m
 
852
        # Make sure there's been a fit earlier ...
 
853
        if self.outputs.activated == 0:
 
854
            c_loess.loess_fit(&self._base)
 
855
            self.outputs.activated = True
 
856
            if self._base.status.err_status:
 
857
                raise ValueError(self._base.status.err_msg)
 
858
        # Note : we need a copy as we may have to normalize
 
859
        p_ndr = narray(newdata, copy=True, subok=True, order='C').ravel()
 
860
        p_dat = <double *>p_ndr.data
 
861
        # Test the compatibility of sizes .......
 
862
        if p_ndr.size == 0:
 
863
            raise ValueError("Can't predict without input data !")
 
864
        (m, notOK) = divmod(len(p_ndr), self.inputs.npar)
 
865
        if notOK:
 
866
            raise ValueError(
 
867
                  "Incompatible data size: there should be as many rows as parameters")
 
868
        #.....
 
869
        c_loess.c_predict(p_dat, m, &self._base, &_prediction, stderror)
 
870
        if self._base.status.err_status:
 
871
            raise ValueError(self._base.status.err_msg)
 
872
        self.predicted = loess_predicted()
 
873
        self.predicted._base = _prediction
 
874
        self.predicted.nest = m
 
875
#        self.predicted.setup(_prediction, m)
 
876
        return self.predicted
 
877
    #.........
 
878
    def __dealloc__(self):
 
879
        c_loess.loess_free_mem(&self._base)
 
880
    #......................................................
 
881
    
 
882
 
 
883
#####---------------------------------------------------------------------------
 
884
#---- ---- loess anova ---
 
885
#####---------------------------------------------------------------------------
 
886
cdef class anova:
 
887
    cdef readonly double dfn, dfd, F_value, Pr_F
 
888
    #
 
889
    def __init__(self, loess_one, loess_two):
 
890
        cdef double one_d1, one_d2, one_s, two_d1, two_d2, two_s, rssdiff,\
 
891
                    d1diff, tmp, df1, df2
 
892
        #
 
893
        if not isinstance(loess_one, loess) or not isinstance(loess_two, loess):
 
894
            raise ValueError("Arguments should be valid loess objects!"\
 
895
                             "got '%s' instead" % type(loess_one))
 
896
        #
 
897
        out_one = loess_one.outputs
 
898
        out_two = loess_two.outputs
 
899
        #
 
900
        one_d1 = out_one.one_delta
 
901
        one_d2 = out_one.two_delta
 
902
        one_s = out_one.s
 
903
        #
 
904
        two_d1 = out_two.one_delta
 
905
        two_d2 = out_two.two_delta
 
906
        two_s = out_two.s
 
907
        #
 
908
        rssdiff = abs(one_s * one_s * one_d1 - two_s * two_s * two_d1)
 
909
        d1diff = abs(one_d1 - two_d1)
 
910
        self.dfn = d1diff * d1diff / abs(one_d2 - two_d2)
 
911
        df1 = self.dfn
 
912
        #
 
913
        if out_one.enp > out_two.enp:
 
914
            self.dfd = one_d1 * one_d1 / one_d2
 
915
            tmp = one_s
 
916
        else:
 
917
            self.dfd = two_d1 * two_d1 / two_d2
 
918
            tmp = two_s
 
919
        df2 = self.dfd
 
920
        F_value = (rssdiff / d1diff) / (tmp * tmp)
 
921
        
 
922
        self.Pr_F = 1. - c_loess.ibeta(F_value*df1/(df2+F_value*df1), df1/2, df2/2)
 
923
        self.F_value = F_value
 
924
 
 
925
        
 
 
b'\\ No newline at end of file'