1
1
import warnings
2
2
3
+ cimport numpy as cnp
3
4
from cpython.object cimport Py_EQ, Py_NE, PyObject_RichCompareBool
4
- from numpy cimport import_array, int64_t, ndarray
5
+ from numpy cimport int64_t, ndarray
5
6
6
7
import numpy as np
7
8
8
- import_array()
9
+ cnp. import_array()
9
10
10
11
from libc.stdlib cimport free, malloc
11
12
from libc.string cimport memset, strlen
@@ -75,6 +76,7 @@ from pandas._libs.tslibs.dtypes cimport (
75
76
attrname_to_abbrevs,
76
77
)
77
78
from pandas._libs.tslibs.parsing cimport quarter_to_myear
79
+
78
80
from pandas._libs.tslibs.parsing import parse_time_string
79
81
80
82
from pandas._libs.tslibs.nattype cimport (
@@ -993,29 +995,6 @@ def periodarr_to_dt64arr(const int64_t[:] periodarr, int freq):
993
995
return ensure_datetime64ns(dta)
994
996
995
997
996
- cpdef int64_t period_asfreq(int64_t ordinal, int freq1, int freq2, bint end):
997
- """
998
- Convert period ordinal from one frequency to another, and if upsampling,
999
- choose to use start ('S') or end ('E') of period.
1000
- """
1001
- cdef:
1002
- int64_t retval
1003
- freq_conv_func func
1004
- asfreq_info af_info
1005
-
1006
- if ordinal == NPY_NAT:
1007
- return NPY_NAT
1008
-
1009
- func = get_asfreq_func(freq1, freq2)
1010
- get_asfreq_info(freq1, freq2, end, & af_info)
1011
- retval = func(ordinal, & af_info)
1012
-
1013
- if retval == INT32_MIN:
1014
- raise ValueError (' Frequency conversion failed' )
1015
-
1016
- return retval
1017
-
1018
-
1019
998
cdef void get_asfreq_info(int from_freq, int to_freq,
1020
999
bint is_end, asfreq_info * af_info) nogil:
1021
1000
"""
@@ -1068,6 +1047,18 @@ cdef inline int calc_week_end(int freq, int group) nogil:
1068
1047
return freq - group
1069
1048
1070
1049
1050
+ cpdef int64_t period_asfreq(int64_t ordinal, int freq1, int freq2, bint end):
1051
+ """
1052
+ Convert period ordinal from one frequency to another, and if upsampling,
1053
+ choose to use start ('S') or end ('E') of period.
1054
+ """
1055
+ cdef:
1056
+ int64_t retval
1057
+
1058
+ _period_asfreq(& ordinal, & retval, 1 , freq1, freq2, end)
1059
+ return retval
1060
+
1061
+
1071
1062
@ cython.wraparound (False )
1072
1063
@ cython.boundscheck (False )
1073
1064
def period_asfreq_arr (ndarray[int64_t] arr , int freq1 , int freq2 , bint end ):
@@ -1076,35 +1067,50 @@ def period_asfreq_arr(ndarray[int64_t] arr, int freq1, int freq2, bint end):
1076
1067
if upsampling, choose to use start ('S') or end ('E') of period.
1077
1068
"""
1078
1069
cdef:
1079
- int64_t[:] result
1080
- Py_ssize_t i, n
1070
+ Py_ssize_t n = len (arr)
1071
+ ndarray[int64_t] result = np.empty(n, dtype = np.int64)
1072
+
1073
+ _period_asfreq(
1074
+ < int64_t* > cnp.PyArray_DATA(arr),
1075
+ < int64_t* > cnp.PyArray_DATA(result),
1076
+ n,
1077
+ freq1,
1078
+ freq2,
1079
+ end,
1080
+ )
1081
+ return result
1082
+
1083
+
1084
+ @ cython.wraparound (False )
1085
+ @ cython.boundscheck (False )
1086
+ cdef void _period_asfreq(
1087
+ int64_t* ordinals,
1088
+ int64_t* out,
1089
+ Py_ssize_t length,
1090
+ int freq1,
1091
+ int freq2,
1092
+ bint end,
1093
+ ):
1094
+ """ See period_asfreq.__doc__"""
1095
+ cdef:
1096
+ Py_ssize_t i
1081
1097
freq_conv_func func
1082
1098
asfreq_info af_info
1083
1099
int64_t val
1084
1100
1085
- n = len (arr)
1086
- result = np.empty(n, dtype = np.int64)
1101
+ if length == 1 and ordinals[0 ] == NPY_NAT:
1102
+ # fastpath avoid calling get_asfreq_func
1103
+ out[0 ] = NPY_NAT
1104
+ return
1087
1105
1088
1106
func = get_asfreq_func(freq1, freq2)
1089
1107
get_asfreq_info(freq1, freq2, end, & af_info)
1090
1108
1091
- mask = arr == NPY_NAT
1092
- if mask.any(): # NaT process
1093
- for i in range (n):
1094
- val = arr[i]
1095
- if val != NPY_NAT:
1096
- val = func(val, & af_info)
1097
- if val == INT32_MIN:
1098
- raise ValueError (" Unable to convert to desired frequency." )
1099
- result[i] = val
1100
- else :
1101
- for i in range (n):
1102
- val = func(arr[i], & af_info)
1103
- if val == INT32_MIN:
1104
- raise ValueError (" Unable to convert to desired frequency." )
1105
- result[i] = val
1106
-
1107
- return result.base # .base to access underlying np.ndarray
1109
+ for i in range (length):
1110
+ val = ordinals[i]
1111
+ if val != NPY_NAT:
1112
+ val = func(val, & af_info)
1113
+ out[i] = val
1108
1114
1109
1115
1110
1116
cpdef int64_t period_ordinal(int y, int m, int d, int h, int min ,
0 commit comments