Skip to content

perf improvements in tslibs.period #21447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 15, 2018
2 changes: 1 addition & 1 deletion pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def ints_to_pydatetime(ndarray[int64_t] arr, tz=None, freq=None,
elif box == "datetime":
func_create = create_datetime_from_ts
else:
raise ValueError("box must be one of 'datetime', 'date', 'time' or" +
raise ValueError("box must be one of 'datetime', 'date', 'time' or"
" 'timestamp'")

if tz is not None:
Expand Down
20 changes: 12 additions & 8 deletions pandas/_libs/tslibs/period.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ from pandas.compat import PY2

cimport cython

from cpython.datetime cimport PyDateTime_Check, PyDateTime_IMPORT
from cpython.datetime cimport (PyDateTime_Check, PyDelta_Check,
PyDateTime_IMPORT)
# import datetime C API
PyDateTime_IMPORT

Expand Down Expand Up @@ -1058,18 +1059,21 @@ cdef class _Period(object):
return hash((self.ordinal, self.freqstr))

def _add_delta(self, other):
if isinstance(other, (timedelta, np.timedelta64, offsets.Tick)):
cdef:
int64_t nanos, offset_nanos

if (PyDelta_Check(other) or util.is_timedelta64_object(other) or
isinstance(other, offsets.Tick)):
offset = frequencies.to_offset(self.freq.rule_code)
if isinstance(offset, offsets.Tick):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This along with the line above is redundant; isinstance(offset, offsets.Tick) if and only if isinstance(self.freq, offsets.Tick).

nanos = delta_to_nanoseconds(other)
offset_nanos = delta_to_nanoseconds(offset)

if nanos % offset_nanos == 0:
ordinal = self.ordinal + (nanos // offset_nanos)
return Period(ordinal=ordinal, freq=self.freq)
msg = 'Input cannot be converted to Period(freq={0})'
raise IncompatibleFrequency(msg.format(self.freqstr))
elif isinstance(other, offsets.DateOffset):
elif getattr(other, "_typ", None) == "dateoffset":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe should add an is_offset_object in util.pxd

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you do this

freqstr = other.rule_code
base = get_base_alias(freqstr)
if base == self.freq.rule_code:
Expand All @@ -1082,8 +1086,8 @@ cdef class _Period(object):

def __add__(self, other):
if is_period_object(self):
if isinstance(other, (timedelta, np.timedelta64,
offsets.DateOffset)):
if (PyDelta_Check(other) or util.is_timedelta64_object(other) or
getattr(other, "_typ", None) == "dateoffset"):
return self._add_delta(other)
elif other is NaT:
return NaT
Expand All @@ -1109,8 +1113,8 @@ cdef class _Period(object):

def __sub__(self, other):
if is_period_object(self):
if isinstance(other, (timedelta, np.timedelta64,
offsets.DateOffset)):
if (PyDelta_Check(other) or util.is_timedelta64_object(other) or
getattr(other, "_typ", None) == "dateoffset"):
neg_other = -other
return self + neg_other
elif util.is_integer_object(other):
Expand Down