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)
31 changes: 26 additions & 5 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 @@ -946,14 +947,34 @@ def periodarr_to_dt64arr(const int64_t[:] periodarr, int freq):
int64_t[:] out
Py_ssize_t i, l

l = len(periodarr)
if freq < 6000: # i.e. FR_DAY, hard-code to avoid need to cast
l = len(periodarr)
out = np.empty(l, dtype="i8")

out = np.empty(l, dtype='i8')
# We get here with freqs that do not correspond to a datetime64 unit
for i in range(l):
out[i] = period_ordinal_to_dt64(periodarr[i], freq)

for i in range(l):
out[i] = period_ordinal_to_dt64(periodarr[i], freq)
return out.base # .base to access underlying np.ndarray

return out.base # .base to access underlying np.ndarray
else:
# Short-circuit for performance
if freq == FR_NS:
return periodarr.base

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


cpdef int64_t period_asfreq(int64_t ordinal, int freq1, int freq2, bint end):
Expand Down