Skip to content

PERF: periodarr_to_dt64arr #35171

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
Jul 9, 2020
38 changes: 37 additions & 1 deletion asv_bench/benchmarks/tslibs/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
Period benchmarks that rely only on tslibs. See benchmarks.period for
Period benchmarks that rely on other parts fo pandas.
"""
from pandas import Period

import numpy as np

from pandas._libs.tslibs.period import Period, periodarr_to_dt64arr

from pandas.tseries.frequencies import to_offset

from .tslib import _sizes


class PeriodProperties:

Expand Down Expand Up @@ -68,3 +73,34 @@ def setup(self, freq, is_offset):

def time_period_constructor(self, freq, is_offset):
Period("2012-06-01", freq=freq)


class TimePeriodArrToDT64Arr:
params = [
_sizes,
[
1000,
1011, # Annual - November End
2000,
2011, # Quarterly - November End
3000,
4000,
4006, # Weekly - Saturday End
5000,
6000,
7000,
8000,
9000,
10000,
11000,
12000,
],
]
param_names = ["size", "freq"]

def setup(self, size, freq):
arr = np.arange(10, dtype="i8").repeat(size // 10)
self.i8values = arr

def time_periodarray_to_dt64arr(self, size, freq):
periodarr_to_dt64arr(self.i8values, freq)
24 changes: 21 additions & 3 deletions pandas/_libs/tslibs/period.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ from pandas._libs.tslibs.ccalendar cimport (
get_days_in_month,
)
from pandas._libs.tslibs.ccalendar cimport c_MONTH_NUMBERS
from pandas._libs.tslibs.conversion import ensure_datetime64ns

from pandas._libs.tslibs.dtypes cimport (
PeriodDtypeBase,
Expand Down Expand Up @@ -937,7 +938,7 @@ cdef inline int month_to_quarter(int month) nogil:

@cython.wraparound(False)
@cython.boundscheck(False)
def periodarr_to_dt64arr(const int64_t[:] periodarr, int freq):
def periodarr_to_dt64arr(periodarr: ndarray, freq: int) -> ndarray:
"""
Convert array to datetime64 values from a set of ordinals corresponding to
periods per period convention.
Expand All @@ -946,9 +947,26 @@ def periodarr_to_dt64arr(const int64_t[:] periodarr, int freq):
int64_t[:] out
Py_ssize_t i, l

l = len(periodarr)
if freq >= FR_DAY:
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 add a comment here that you are short-circuiting for perf

if freq == FR_NS:
return periodarr

if freq == FR_US:
dta = periodarr.view("M8[us]")
elif freq == FR_MS:
dta = periodarr.view("M8[ms]")
elif freq == FR_SEC:
dta = periodarr.view("M8[s]")
elif freq == FR_MIN:
dta = periodarr.view("M8[m]")
elif freq == FR_HR:
dta = periodarr.view("M8[h]")
elif freq == FR_DAY:
dta = periodarr.view("M8[D]")
return ensure_datetime64ns(dta)

out = np.empty(l, dtype='i8')
l = len(periodarr)
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 add a comment on which cases this hits

out = np.empty(l, dtype="i8")
Copy link
Contributor

Choose a reason for hiding this comment

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

this could be a nogil loop right? (actually couldn't this entire function)?

Copy link
Contributor

Choose a reason for hiding this comment

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

worth doing this here?

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 cant be nogil becuase it calls check_dts_bounds, which may raise


for i in range(l):
out[i] = period_ordinal_to_dt64(periodarr[i], freq)
Expand Down