Skip to content

Commit f4e7012

Browse files
jbrockmendelvictor
authored and
victor
committed
use memoryviews instead of ndarrays (pandas-dev#22147)
1 parent 115611e commit f4e7012

File tree

1 file changed

+122
-8
lines changed

1 file changed

+122
-8
lines changed

pandas/_libs/tslibs/timedeltas.pyx

+122-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ from cpython cimport PyUnicode_Check, Py_NE, Py_EQ, PyObject_RichCompare
1313

1414
import numpy as np
1515
cimport numpy as cnp
16-
from numpy cimport int64_t, ndarray
16+
from numpy cimport int64_t
1717
cnp.import_array()
1818

1919
from cpython.datetime cimport (datetime, timedelta,
@@ -33,6 +33,7 @@ from np_datetime cimport (cmp_scalar, reverse_ops, td64_to_tdstruct,
3333

3434
from nattype import nat_strings, NaT
3535
from nattype cimport checknull_with_nat, NPY_NAT
36+
from offsets cimport to_offset
3637

3738
# ----------------------------------------------------------------------
3839
# Constants
@@ -78,6 +79,44 @@ cdef dict timedelta_abbrevs = { 'D': 'd',
7879

7980
_no_input = object()
8081

82+
83+
# ----------------------------------------------------------------------
84+
# API
85+
86+
def ints_to_pytimedelta(int64_t[:] arr, box=False):
87+
"""
88+
convert an i8 repr to an ndarray of timedelta or Timedelta (if box ==
89+
True)
90+
91+
Parameters
92+
----------
93+
arr : ndarray[int64_t]
94+
box : bool, default False
95+
96+
Returns
97+
-------
98+
result : ndarray[object]
99+
array of Timedelta or timedeltas objects
100+
"""
101+
cdef:
102+
Py_ssize_t i, n = len(arr)
103+
int64_t value
104+
object[:] result = np.empty(n, dtype=object)
105+
106+
for i in range(n):
107+
108+
value = arr[i]
109+
if value == NPY_NAT:
110+
result[i] = NaT
111+
else:
112+
if box:
113+
result[i] = Timedelta(value)
114+
else:
115+
result[i] = timedelta(microseconds=int(value) / 1000)
116+
117+
return result.base # .base to access underlying np.ndarray
118+
119+
81120
# ----------------------------------------------------------------------
82121

83122
cpdef int64_t delta_to_nanoseconds(delta) except? -1:
@@ -144,7 +183,11 @@ cpdef convert_to_timedelta64(object ts, object unit):
144183
ts = cast_from_unit(ts, unit)
145184
ts = np.timedelta64(ts)
146185
elif is_string_object(ts):
147-
ts = np.timedelta64(parse_timedelta_string(ts))
186+
if len(ts) > 0 and ts[0] == 'P':
187+
ts = parse_iso_format_string(ts)
188+
else:
189+
ts = parse_timedelta_string(ts)
190+
ts = np.timedelta64(ts)
148191
elif hasattr(ts, 'delta'):
149192
ts = np.timedelta64(delta_to_nanoseconds(ts), 'ns')
150193

@@ -156,15 +199,15 @@ cpdef convert_to_timedelta64(object ts, object unit):
156199
return ts.astype('timedelta64[ns]')
157200

158201

159-
cpdef array_to_timedelta64(ndarray[object] values, unit='ns', errors='raise'):
202+
cpdef array_to_timedelta64(object[:] values, unit='ns', errors='raise'):
160203
"""
161204
Convert an ndarray to an array of timedeltas. If errors == 'coerce',
162205
coerce non-convertible objects to NaT. Otherwise, raise.
163206
"""
164207

165208
cdef:
166209
Py_ssize_t i, n
167-
ndarray[int64_t] iresult
210+
int64_t[:] iresult
168211

169212
if errors not in ('ignore', 'raise', 'coerce'):
170213
raise ValueError("errors must be one of 'ignore', "
@@ -190,7 +233,7 @@ cpdef array_to_timedelta64(ndarray[object] values, unit='ns', errors='raise'):
190233
else:
191234
raise
192235

193-
return iresult
236+
return iresult.base # .base to access underlying np.ndarray
194237

195238

196239
cpdef inline int64_t cast_from_unit(object ts, object unit) except? -1:
@@ -795,12 +838,81 @@ cdef class _Timedelta(timedelta):
795838

796839
@property
797840
def asm8(self):
798-
""" return a numpy timedelta64 array view of myself """
841+
"""
842+
Return a numpy timedelta64 array scalar view.
843+
844+
Provides access to the array scalar view (i.e. a combination of the
845+
value and the units) associated with the numpy.timedelta64().view(),
846+
including a 64-bit integer representation of the timedelta in
847+
nanoseconds (Python int compatible).
848+
849+
Returns
850+
-------
851+
numpy timedelta64 array scalar view
852+
Array scalar view of the timedelta in nanoseconds.
853+
854+
Examples
855+
--------
856+
>>> td = pd.Timedelta('1 days 2 min 3 us 42 ns')
857+
>>> td.asm8
858+
numpy.timedelta64(86520000003042,'ns')
859+
860+
>>> td = pd.Timedelta('2 min 3 s')
861+
>>> td.asm8
862+
numpy.timedelta64(123000000000,'ns')
863+
864+
>>> td = pd.Timedelta('3 ms 5 us')
865+
>>> td.asm8
866+
numpy.timedelta64(3005000,'ns')
867+
868+
>>> td = pd.Timedelta(42, unit='ns')
869+
>>> td.asm8
870+
numpy.timedelta64(42,'ns')
871+
"""
799872
return np.int64(self.value).view('m8[ns]')
800873

801874
@property
802875
def resolution(self):
803-
""" return a string representing the lowest resolution that we have """
876+
"""
877+
Return a string representing the lowest timedelta resolution.
878+
879+
Each timedelta has a defined resolution that represents the lowest OR
880+
most granular level of precision. Each level of resolution is
881+
represented by a short string as defined below:
882+
883+
Resolution: Return value
884+
885+
* Days: 'D'
886+
* Hours: 'H'
887+
* Minutes: 'T'
888+
* Seconds: 'S'
889+
* Milliseconds: 'L'
890+
* Microseconds: 'U'
891+
* Nanoseconds: 'N'
892+
893+
Returns
894+
-------
895+
str
896+
Timedelta resolution.
897+
898+
Examples
899+
--------
900+
>>> td = pd.Timedelta('1 days 2 min 3 us 42 ns')
901+
>>> td.resolution
902+
'N'
903+
904+
>>> td = pd.Timedelta('1 days 2 min 3 us')
905+
>>> td.resolution
906+
'U'
907+
908+
>>> td = pd.Timedelta('2 min 3 s')
909+
>>> td.resolution
910+
'S'
911+
912+
>>> td = pd.Timedelta(36, unit='us')
913+
>>> td.resolution
914+
'U'
915+
"""
804916

805917
self._ensure_components()
806918
if self._ns:
@@ -904,6 +1016,9 @@ cdef class _Timedelta(timedelta):
9041016
def __str__(self):
9051017
return self._repr_base(format='long')
9061018

1019+
def __bool__(self):
1020+
return self.value != 0
1021+
9071022
def isoformat(self):
9081023
"""
9091024
Format Timedelta as ISO 8601 Duration like
@@ -1063,7 +1178,6 @@ class Timedelta(_Timedelta):
10631178
cdef:
10641179
int64_t result, unit
10651180

1066-
from pandas.tseries.frequencies import to_offset
10671181
unit = to_offset(freq).nanos
10681182
result = unit * rounder(self.value / float(unit))
10691183
return Timedelta(result, unit='ns')

0 commit comments

Comments
 (0)