4
/* Helper function for TimeSeries_convert:
5
determine the size of the second dimension for the resulting
7
static long get_height(int fromFreq, int toFreq) {
9
int maxBusDaysPerYear, maxBusDaysPerQuarter, maxBusDaysPerMonth;
10
int maxDaysPerYear, maxDaysPerQuarter, maxDaysPerMonth;
12
int fromGroup = get_freq_group(fromFreq);
13
int toGroup = get_freq_group(toFreq);
15
if (fromGroup == FR_UND) { fromGroup = FR_DAY; }
17
maxBusDaysPerYear = 262;
18
maxBusDaysPerQuarter = 66;
19
maxBusDaysPerMonth = 23;
22
maxDaysPerQuarter = 92;
27
case FR_ANN: return 1;
31
case FR_ANN: return 4;
34
case FR_MTH: //monthly
37
case FR_ANN: return 12;
38
case FR_QTR: return 3;
44
case FR_ANN: return 53;
45
case FR_QTR: return 13;
46
case FR_MTH: return 4;
49
case FR_BUS: //business
52
case FR_ANN: return maxBusDaysPerYear;;
53
case FR_QTR: return maxBusDaysPerQuarter;
54
case FR_MTH: return maxBusDaysPerMonth;
61
case FR_ANN: return maxDaysPerYear;;
62
case FR_QTR: return maxDaysPerQuarter;
63
case FR_MTH: return maxDaysPerMonth;
70
case FR_ANN: return 24 * maxDaysPerYear;;
71
case FR_QTR: return 24 * maxDaysPerQuarter;
72
case FR_MTH: return 24 * maxDaysPerMonth;
73
case FR_WK: return 24 * 7;
74
case FR_DAY: return 24;
75
case FR_BUS: return 24;
78
case FR_MIN: //minutely
81
case FR_ANN: return 24 * 60 * maxDaysPerYear;;
82
case FR_QTR: return 24 * 60 * maxDaysPerQuarter;
83
case FR_MTH: return 24 * 60 * maxDaysPerMonth;
84
case FR_WK: return 24 * 60 * 7;
85
case FR_DAY: return 24 * 60;
86
case FR_BUS: return 24 * 60;
87
case FR_HR: return 60;
90
case FR_SEC: //minutely
93
case FR_ANN: return 24 * 60 * 60 * maxDaysPerYear;;
94
case FR_QTR: return 24 * 60 * 60 * maxDaysPerQuarter;
95
case FR_MTH: return 24 * 60 * 60 * maxDaysPerMonth;
96
case FR_WK: return 24 * 60 * 60 * 7;
97
case FR_DAY: return 24 * 60 * 60;
98
case FR_BUS: return 24 * 60 * 60;
99
case FR_HR: return 60 * 60;
100
case FR_MIN: return 60;
108
TimeSeries_convert(PyObject *self, PyObject *args)
111
PyArrayObject *array, *newArray;
112
PyArrayObject *mask, *newMask;
114
PyObject *returnVal = NULL;
115
PyObject *start_index_retval;
118
long newStart, newStartTemp;
119
long newEnd, newEndTemp;
120
long newLen, newHeight;
121
long currIndex, prevIndex;
123
npy_intp *dim, *newIdx;
126
PyObject *fromFreq_arg, *toFreq_arg;
127
int fromFreq, toFreq;
132
PyObject *val, *valMask;
134
long (*asfreq_main)(long, char, asfreq_info*) = NULL;
135
long (*asfreq_endpoints)(long, char, asfreq_info*) = NULL;
136
long (*asfreq_reverse)(long, char, asfreq_info*) = NULL;
138
returnVal = PyDict_New();
140
if (!PyArg_ParseTuple(args,
141
"OOOslO:convert(array, fromfreq, tofreq, position, startIndex, mask)",
142
&array, &fromFreq_arg, &toFreq_arg,
143
&position, &startIndex, &mask)) return NULL;
145
if((fromFreq = check_freq(fromFreq_arg)) == INT_ERR_CODE) return NULL;
146
if((toFreq = check_freq(toFreq_arg)) == INT_ERR_CODE) return NULL;
148
if (toFreq == fromFreq)
151
newArray = (PyArrayObject *)PyArray_Copy(array);
152
newMask = (PyArrayObject *)PyArray_Copy(mask);
153
sidx = PyInt_FromLong(startIndex);
155
PyDict_SetItemString(returnVal, "values", (PyObject*)newArray);
156
PyDict_SetItemString(returnVal, "mask", (PyObject*)newMask);
157
PyDict_SetItemString(returnVal, "startindex", sidx);
181
get_asfreq_info(fromFreq, toFreq, &af_info);
183
asfreq_main = get_asfreq_func(fromFreq, toFreq, 1);
184
asfreq_endpoints = get_asfreq_func(fromFreq, toFreq, 0);
186
//convert start index to new frequency
187
CHECK_ASFREQ(newStartTemp = asfreq_main(startIndex, 'B', &af_info));
188
if (newStartTemp < 1) {
189
CHECK_ASFREQ(newStart = asfreq_endpoints(startIndex, 'A', &af_info));
191
else { newStart = newStartTemp; }
193
//convert end index to new frequency
194
CHECK_ASFREQ(newEndTemp = asfreq_main(startIndex+array->dimensions[0]-1, 'A', &af_info));
195
if (newEndTemp < 1) {
196
CHECK_ASFREQ(newEnd = asfreq_endpoints(startIndex+array->dimensions[0]-1, 'B', &af_info));
198
else { newEnd = newEndTemp; }
201
PyErr_SetString(PyExc_ValueError, "start_date outside allowable range for destination frequency");
205
newLen = newEnd - newStart + 1;
206
newHeight = get_height(fromFreq, toFreq);
210
asfreq_info af_info_rev;
212
get_asfreq_info(toFreq, fromFreq, &af_info_rev);
213
asfreq_reverse = get_asfreq_func(toFreq, fromFreq, 0);
215
CHECK_ASFREQ(tempval = asfreq_reverse(newStart, 'B', &af_info_rev));
216
currPerLen = startIndex - tempval;
219
dim = PyDimMem_NEW(nd);
220
dim[0] = (npy_intp)newLen;
221
dim[1] = (npy_intp)newHeight;
224
dim = PyDimMem_NEW(nd);
225
dim[0] = (npy_intp)newLen;
228
newIdx = PyDimMem_NEW(nd);
229
arrayTest = PyArray_SimpleNew(nd, dim, array->descr->type_num);
230
if (arrayTest == NULL) { return NULL; }
231
newArray = (PyArrayObject*)arrayTest;
232
newMask = (PyArrayObject*)PyArray_SimpleNew(nd, dim, mask->descr->type_num);
236
PyArray_FILLWBYTE(newArray,0);
237
PyArray_FILLWBYTE(newMask,1);
239
prevIndex = newStart;
241
//set values in the new array
242
for (i = 0; i < array->dimensions[0]; i++) {
244
npy_intp idx = (npy_intp)i;
246
val = PyArray_GETITEM(array, PyArray_GetPtr(array, &idx));
247
valMask = PyArray_GETITEM(mask, PyArray_GetPtr(mask, &idx));
249
CHECK_ASFREQ(currIndex = asfreq_main(startIndex + i, relation, &af_info));
251
newIdx[0] = (npy_intp)(currIndex-newStart);
255
if (currIndex != prevIndex)
257
//reset period length
259
prevIndex = currIndex;
262
newIdx[1] = (npy_intp)currPerLen;
266
if (newIdx[0] > -1) {
267
PyArray_SETITEM(newArray, PyArray_GetPtr(newArray, newIdx), val);
268
PyArray_SETITEM(newMask, PyArray_GetPtr(newMask, newIdx), valMask);
276
PyDimMem_FREE(newIdx);
278
start_index_retval = (PyObject*)PyInt_FromLong(newStart);
280
PyDict_SetItemString(returnVal, "values", (PyObject*)newArray);
281
PyDict_SetItemString(returnVal, "mask", (PyObject*)newMask);
282
PyDict_SetItemString(returnVal, "startindex", start_index_retval);
286
Py_DECREF(start_index_retval);
292
/* This function is directly copied from the numpy source */
293
/* Return typenumber from dtype2 unless it is NULL, then return
294
NPY_DOUBLE if dtype1->type_num is integer or bool
295
and dtype1->type_num otherwise.
298
_get_type_num_double(PyArray_Descr *dtype1, PyArray_Descr *dtype2)
300
if (dtype2 != NULL) {
301
return dtype2->type_num;
304
/* For integer or bool data-types */
305
if (dtype1->type_num < NPY_FLOAT) {
309
return dtype1->type_num;
314
_get_type_num(PyArray_Descr *dtype1, PyArray_Descr *dtype2)
316
if (dtype2 != NULL) {
317
return dtype2->type_num;
319
return dtype1->type_num;
324
/* validates the standard arguments to moving functions and set the original
325
mask, original ndarray, and mask for the result */
327
check_mov_args(PyObject *orig_arrayobj, int span, int min_win_size,
328
PyObject **orig_ndarray, PyObject **result_mask) {
330
PyObject *orig_mask=NULL;
331
PyArrayObject **orig_ndarray_tmp, **result_mask_tmp;
332
int *raw_result_mask;
334
if (!PyArray_Check(orig_arrayobj)) {
335
PyErr_SetString(PyExc_ValueError, "array must be a valid subtype of ndarray");
339
// check if array has a mask, and if that mask is an array
340
if (PyObject_HasAttrString(orig_arrayobj, "_mask")) {
341
PyObject *tempMask = PyObject_GetAttrString(orig_arrayobj, "_mask");
342
if (PyArray_Check(tempMask)) {
343
orig_mask = PyArray_EnsureArray(tempMask);
349
*orig_ndarray = PyArray_EnsureArray(orig_arrayobj);
350
orig_ndarray_tmp = (PyArrayObject**)orig_ndarray;
352
if ((*orig_ndarray_tmp)->nd != 1) {
353
PyErr_SetString(PyExc_ValueError, "array must be 1 dimensional");
357
if (span < min_win_size) {
359
error_str = malloc(60 * sizeof(char));
362
"span must be greater than or equal to %i",
364
PyErr_SetString(PyExc_ValueError, error_str);
369
raw_result_mask = malloc((*orig_ndarray_tmp)->dimensions[0] * sizeof(int));
370
MEM_CHECK(raw_result_mask)
373
PyArrayObject *orig_mask_tmp;
374
int i, valid_points=0, is_masked;
376
orig_mask_tmp = (PyArrayObject*)orig_mask;
378
for (i=0; i<((*orig_ndarray_tmp)->dimensions[0]); i++) {
380
npy_intp idx = (npy_intp)i;
383
if (orig_mask != NULL) {
385
valMask = PyArray_GETITEM(orig_mask_tmp,
386
PyArray_GetPtr(orig_mask_tmp, &idx));
387
is_masked = (int)PyInt_AsLong(valMask);
394
if (valid_points < span) { valid_points += 1; }
395
if (valid_points < span) { is_masked = 1; }
398
raw_result_mask[i] = is_masked;
402
*result_mask = PyArray_SimpleNewFromData(
403
1, (*orig_ndarray_tmp)->dimensions,
404
PyArray_INT32, raw_result_mask);
405
MEM_CHECK(*result_mask)
406
result_mask_tmp = (PyArrayObject**)result_mask;
407
(*result_mask_tmp)->flags = ((*result_mask_tmp)->flags) | NPY_OWNDATA;
411
/* computation portion of moving sum. Appropriate mask is overlayed on top
414
calc_mov_sum(PyArrayObject *orig_ndarray, int span, int rtype)
416
PyArrayObject *result_ndarray=NULL;
419
result_ndarray = (PyArrayObject*)PyArray_ZEROS(
421
orig_ndarray->dimensions,
423
ERR_CHECK(result_ndarray)
425
for (i=0; i<orig_ndarray->dimensions[0]; i++) {
427
PyObject *val=NULL, *mov_sum_val=NULL;
428
npy_intp idx = (npy_intp)i;
430
val = PyArray_GETITEM(orig_ndarray, PyArray_GetPtr(orig_ndarray, &idx));
435
idx = (npy_intp)(i-1);
436
PyObject *mov_sum_prevval;
437
mov_sum_prevval= PyArray_GETITEM(result_ndarray,
438
PyArray_GetPtr(result_ndarray, &idx));
439
mov_sum_val = np_add(val, mov_sum_prevval);
440
Py_DECREF(mov_sum_prevval);
441
ERR_CHECK(mov_sum_val)
444
PyObject *temp_val, *rem_val;
445
idx = (npy_intp)(i-span);
446
temp_val = mov_sum_val;
447
rem_val = PyArray_GETITEM(orig_ndarray,
448
PyArray_GetPtr(orig_ndarray, &idx));
450
mov_sum_val = np_subtract(temp_val, rem_val);
451
ERR_CHECK(mov_sum_val)
460
PyArray_SETITEM(result_ndarray,
461
PyArray_GetPtr(result_ndarray, &idx),
464
if (mov_sum_val != val) { Py_DECREF(val); }
466
Py_DECREF(mov_sum_val);
469
return (PyObject*)result_ndarray;
474
MaskedArray_mov_sum(PyObject *self, PyObject *args, PyObject *kwds)
476
PyObject *orig_arrayobj=NULL, *orig_ndarray=NULL,
477
*result_ndarray=NULL, *result_mask=NULL,
479
PyArray_Descr *dtype=NULL;
483
static char *kwlist[] = {"array", "span", "dtype", NULL};
485
if (!PyArg_ParseTupleAndKeywords(args, kwds,
486
"Oi|O&:mov_sum(array, span, dtype)", kwlist,
487
&orig_arrayobj, &span,
488
PyArray_DescrConverter2, &dtype)) return NULL;
490
check_mov_args(orig_arrayobj, span, 1,
491
&orig_ndarray, &result_mask);
493
rtype = _get_type_num(((PyArrayObject*)orig_ndarray)->descr, dtype);
495
result_ndarray = calc_mov_sum((PyArrayObject*)orig_ndarray,
497
ERR_CHECK(result_ndarray)
499
result_dict = PyDict_New();
500
MEM_CHECK(result_dict)
501
PyDict_SetItemString(result_dict, "array", result_ndarray);
502
PyDict_SetItemString(result_dict, "mask", result_mask);
504
Py_DECREF(result_ndarray);
505
Py_DECREF(result_mask);
510
MaskedArray_mov_average(PyObject *self, PyObject *args, PyObject *kwds)
512
PyObject *orig_arrayobj=NULL, *orig_ndarray=NULL,
513
*result_ndarray=NULL, *result_mask=NULL,
515
*mov_sum=NULL, *denom=NULL;
516
PyArray_Descr *dtype=NULL;
520
static char *kwlist[] = {"array", "span", "dtype", NULL};
522
if (!PyArg_ParseTupleAndKeywords(args, kwds,
523
"Oi|O&:mov_average(array, span, dtype)", kwlist,
524
&orig_arrayobj, &span,
525
PyArray_DescrConverter2, &dtype)) return NULL;
528
check_mov_args(orig_arrayobj, span, 2,
529
&orig_ndarray, &result_mask);
531
rtype = _get_type_num_double(((PyArrayObject*)orig_ndarray)->descr, dtype);
533
mov_sum = calc_mov_sum((PyArrayObject*)orig_ndarray, span, rtype);
536
denom = PyFloat_FromDouble(1.0/(double)(span));
538
result_ndarray = np_multiply(mov_sum, denom);
539
ERR_CHECK(result_ndarray)
544
result_dict = PyDict_New();
545
MEM_CHECK(result_dict)
546
PyDict_SetItemString(result_dict, "array", result_ndarray);
547
PyDict_SetItemString(result_dict, "mask", result_mask);
549
Py_DECREF(result_ndarray);
550
Py_DECREF(result_mask);
555
/* computation portion of moving median. Appropriate mask is overlayed on top
558
The algorithm used here is based on the code found at:
559
http://cran.r-project.org/src/contrib/Devel/runStat_1.1.tar.gz
561
This code was originally released under the GPL, but the author
562
(David Brahm) has granted me (and scipy) permission to use it under the BSD
565
calc_mov_median(PyArrayObject *orig_ndarray, int span, int rtype)
567
PyArrayObject *result_ndarray=NULL;
568
PyObject **result_array, **ref_array, **even_array=NULL;
569
PyObject *new_val, *old_val;
570
PyObject *temp_add, *one_half;
571
int a, i, k, R, arr_size, z;
575
arr_size = (int)(orig_ndarray->dimensions[0]);
577
result_ndarray = (PyArrayObject*)PyArray_ZEROS(
579
orig_ndarray->dimensions,
581
ERR_CHECK(result_ndarray)
583
if (arr_size >= span) {
584
result_array = calloc(arr_size, sizeof(PyObject*));
585
MEM_CHECK(result_array)
587
/* this array will be used for quick access to the data in the original
588
array (so PyArray_GETITEM doesn't have to be used over and over in the
590
ref_array = malloc(arr_size * sizeof(PyObject*));
593
for (i=0; i<arr_size; i++) {
595
ref_array[i] = PyArray_GETITEM(orig_ndarray, PyArray_GetPtr(orig_ndarray, &idx));
598
/* this array wll be used for keeping track of the "ranks" of the values
599
in the current window */
600
r = malloc(span * sizeof(int));
603
for (i=0; i < span; i++) {
607
if ((span % 2) == 0) {
608
// array to store two median values when span is an even #
609
even_array = calloc(2, sizeof(PyObject*));
610
MEM_CHECK(even_array)
614
one_half = PyFloat_FromDouble(0.5);
618
/* Calculate initial ranks "r" */
619
for (i=0; i < span; i++) {
621
for (k=0; k < i; k++) {
622
if (np_greater_equal(ref_array[z+i], ref_array[z+k])) {
626
for (k=i+1; k < span; k++) {
627
if (np_greater(ref_array[z+i], ref_array[z+k])) {
632
/* If rank=R, this is the median */
633
if (even_array != NULL) {
635
even_array[0] = ref_array[z+i];
636
} else if (r[i] == (R+1)) {
637
even_array[1] = ref_array[z+i];
641
result_array[arr_size-1] = ref_array[z+i];
646
if (even_array != NULL) {
647
temp_add = np_add(even_array[0], even_array[1]);
648
result_array[arr_size-1] = np_multiply(temp_add, one_half);
652
for (i=arr_size-2; i >= span-1; i--) {
655
old_val = ref_array[i+1];
656
new_val = ref_array[i-span+1];
658
for (k=span-1; k > 0; k--) {
659
r[k] = r[k-1]; /* Shift previous iteration's ranks */
660
if (np_greater_equal(ref_array[z+k], new_val)) {r[k]++; a--;}
661
if (np_greater(ref_array[z+k], old_val)) {r[k]--;}
664
result_array[i] = ref_array[z+k];
667
if (even_array != NULL) {
669
even_array[0] = ref_array[z+k];
670
} else if (r[k] == (R+1)) {
671
even_array[1] = ref_array[z+k];
675
result_array[i] = ref_array[z+k];
683
if (even_array != NULL) {
685
even_array[0] = new_val;
686
} else if (a == (R+1)) {
687
even_array[1] = new_val;
690
temp_add = np_add(even_array[0], even_array[1]);
691
result_array[i] = np_multiply(temp_add, one_half);;
696
result_array[i] = new_val;
704
for (i=span-1; i<arr_size; i++) {
706
PyArray_SETITEM(result_ndarray,
707
PyArray_GetPtr(result_ndarray, &idx),
711
for (i=0; i<arr_size; i++) {
712
Py_DECREF(ref_array[i]);
715
if (even_array != NULL) {
716
for (i=span-1; i<arr_size; i++) {
717
Py_DECREF(result_array[i]);
725
return (PyObject*)result_ndarray;
730
MaskedArray_mov_median(PyObject *self, PyObject *args, PyObject *kwds)
732
PyObject *orig_arrayobj=NULL, *orig_ndarray=NULL,
733
*result_ndarray=NULL, *result_mask=NULL, *result_dict=NULL;
734
PyArray_Descr *dtype=NULL;
738
static char *kwlist[] = {"array", "span", "dtype", NULL};
740
if (!PyArg_ParseTupleAndKeywords(args, kwds,
741
"Oi|O&:mov_median(array, span, dtype)", kwlist,
742
&orig_arrayobj, &span,
743
PyArray_DescrConverter2, &dtype)) return NULL;
745
check_mov_args(orig_arrayobj, span, 1,
746
&orig_ndarray, &result_mask);
748
if ((span % 2) == 0) {
749
rtype = _get_type_num_double(((PyArrayObject*)orig_ndarray)->descr, dtype);
751
rtype = _get_type_num(((PyArrayObject*)orig_ndarray)->descr, dtype);
754
result_ndarray = calc_mov_median((PyArrayObject*)orig_ndarray,
756
ERR_CHECK(result_ndarray)
758
result_dict = PyDict_New();
759
MEM_CHECK(result_dict)
760
PyDict_SetItemString(result_dict, "array", result_ndarray);
761
PyDict_SetItemString(result_dict, "mask", result_mask);
763
Py_DECREF(result_ndarray);
764
Py_DECREF(result_mask);
770
MaskedArray_mov_stddev(PyObject *self, PyObject *args, PyObject *kwds)
773
PyObject *orig_ndarray=NULL, *orig_arrayobj=NULL,
774
*result_ndarray=NULL, *result_mask=NULL,
776
*result_temp1=NULL, *result_temp2=NULL, *result_temp3=NULL,
777
*mov_sum=NULL, *mov_sum_sq=NULL,
778
*denom1=NULL, *denom2=NULL;
780
PyArray_Descr *dtype=NULL;
782
int rtype, span, is_variance, bias;
784
static char *kwlist[] = {"array", "span", "is_variance", "bias", "dtype", NULL};
786
if (!PyArg_ParseTupleAndKeywords(args, kwds,
787
"Oiii|O&:mov_stddev(array, span, is_variance, bias, dtype)",
788
kwlist, &orig_arrayobj, &span, &is_variance, &bias,
789
PyArray_DescrConverter2, &dtype)) return NULL;
792
check_mov_args(orig_arrayobj, span, 2,
793
&orig_ndarray, &result_mask);
795
rtype = _get_type_num_double(((PyArrayObject*)orig_ndarray)->descr, dtype);
797
mov_sum = calc_mov_sum((PyArrayObject*)orig_ndarray, span, rtype);
800
result_temp1 = np_multiply(orig_ndarray, orig_ndarray);
801
ERR_CHECK(result_temp1)
803
mov_sum_sq = calc_mov_sum((PyArrayObject*)result_temp1, span, rtype);
804
Py_DECREF(result_temp1);
805
ERR_CHECK(mov_sum_sq)
810
http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
813
denom1 = PyFloat_FromDouble(1.0/(double)(span-1));
814
denom2 = PyFloat_FromDouble(1.0/(double)(span*(span-1)));
816
denom1 = PyFloat_FromDouble(1.0/(double)span);
817
denom2 = PyFloat_FromDouble(1.0/(double)(span*span));
820
result_temp1 = np_multiply(mov_sum_sq, denom1);
821
ERR_CHECK(result_temp1)
822
Py_DECREF(mov_sum_sq);
825
result_temp3 = np_multiply(mov_sum, mov_sum);
826
ERR_CHECK(result_temp3)
829
result_temp2 = np_multiply(result_temp3, denom2);
830
ERR_CHECK(result_temp2)
831
Py_DECREF(result_temp3);
834
result_temp3 = np_subtract(result_temp1, result_temp2);
835
ERR_CHECK(result_temp3)
836
Py_DECREF(result_temp1);
837
Py_DECREF(result_temp2);
840
result_ndarray = result_temp3;
842
result_temp1 = np_sqrt(result_temp3);
843
ERR_CHECK(result_temp1)
844
Py_DECREF(result_temp3);
845
result_ndarray = result_temp1;
848
result_dict = PyDict_New();
849
MEM_CHECK(result_dict)
850
PyDict_SetItemString(result_dict, "array", result_ndarray);
851
PyDict_SetItemString(result_dict, "mask", result_mask);
853
Py_DECREF(result_ndarray);
854
Py_DECREF(result_mask);
859
void import_c_tseries(PyObject *m) { import_array(); }