11import warnings
22
3+ cimport numpy as cnp
34from 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
56
67import numpy as np
78
8- import_array()
9+ cnp. import_array()
910
1011from libc.stdlib cimport free, malloc
1112from libc.string cimport memset, strlen
@@ -75,6 +76,7 @@ from pandas._libs.tslibs.dtypes cimport (
7576 attrname_to_abbrevs,
7677)
7778from pandas._libs.tslibs.parsing cimport quarter_to_myear
79+
7880from pandas._libs.tslibs.parsing import parse_time_string
7981
8082from pandas._libs.tslibs.nattype cimport (
@@ -993,29 +995,6 @@ def periodarr_to_dt64arr(const int64_t[:] periodarr, int freq):
993995 return ensure_datetime64ns(dta)
994996
995997
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-
1019998cdef void get_asfreq_info(int from_freq, int to_freq,
1020999 bint is_end, asfreq_info * af_info) nogil:
10211000 """
@@ -1068,6 +1047,18 @@ cdef inline int calc_week_end(int freq, int group) nogil:
10681047 return freq - group
10691048
10701049
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+
10711062@ cython.wraparound (False )
10721063@ cython.boundscheck (False )
10731064def 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):
10761067 if upsampling, choose to use start ('S') or end ('E') of period.
10771068 """
10781069 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
10811097 freq_conv_func func
10821098 asfreq_info af_info
10831099 int64_t val
10841100
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
10871105
10881106 func = get_asfreq_func(freq1, freq2)
10891107 get_asfreq_info(freq1, freq2, end, & af_info)
10901108
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
11081114
11091115
11101116cpdef int64_t period_ordinal(int y, int m, int d, int h, int min ,
0 commit comments