Skip to content

Commit 1d760af

Browse files
qwhelanjreback
authored andcommitted
PERF: speed up PeriodArray creation by exposing dayfirst/yearfirst params (#24118)
1 parent 2c8c5df commit 1d760af

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

asv_bench/benchmarks/period.py

+31-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from pandas import (
22
DataFrame, Period, PeriodIndex, Series, date_range, period_range)
3+
from pandas.tseries.frequencies import to_offset
34

45

56
class PeriodProperties(object):
@@ -35,25 +36,48 @@ def time_asfreq(self, freq):
3536
self.per.asfreq('A')
3637

3738

39+
class PeriodConstructor(object):
40+
params = [['D'], [True, False]]
41+
param_names = ['freq', 'is_offset']
42+
43+
def setup(self, freq, is_offset):
44+
if is_offset:
45+
self.freq = to_offset(freq)
46+
else:
47+
self.freq = freq
48+
49+
def time_period_constructor(self, freq, is_offset):
50+
Period('2012-06-01', freq=freq)
51+
52+
3853
class PeriodIndexConstructor(object):
3954

40-
params = ['D']
41-
param_names = ['freq']
55+
params = [['D'], [True, False]]
56+
param_names = ['freq', 'is_offset']
4257

43-
def setup(self, freq):
58+
def setup(self, freq, is_offset):
4459
self.rng = date_range('1985', periods=1000)
4560
self.rng2 = date_range('1985', periods=1000).to_pydatetime()
4661
self.ints = list(range(2000, 3000))
47-
48-
def time_from_date_range(self, freq):
62+
self.daily_ints = date_range('1/1/2000', periods=1000,
63+
freq=freq).strftime('%Y%m%d').map(int)
64+
if is_offset:
65+
self.freq = to_offset(freq)
66+
else:
67+
self.freq = freq
68+
69+
def time_from_date_range(self, freq, is_offset):
4970
PeriodIndex(self.rng, freq=freq)
5071

51-
def time_from_pydatetime(self, freq):
72+
def time_from_pydatetime(self, freq, is_offset):
5273
PeriodIndex(self.rng2, freq=freq)
5374

54-
def time_from_ints(self, freq):
75+
def time_from_ints(self, freq, is_offset):
5576
PeriodIndex(self.ints, freq=freq)
5677

78+
def time_from_ints_daily(self, freq, is_offset):
79+
PeriodIndex(self.daily_ints, freq=freq)
80+
5781

5882
class DataFramePeriodColumn(object):
5983

doc/source/whatsnew/v0.24.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,7 @@ Performance Improvements
12941294
- Improved performance of :meth:`~DataFrame.where` for Categorical data (:issue:`24077`)
12951295
- Improved performance of iterating over a :class:`Series`. Using :meth:`DataFrame.itertuples` now creates iterators
12961296
without internally allocating lists of all elements (:issue:`20783`)
1297+
- Improved performance of :class:`Period` constructor, additionally benefitting ``PeriodArray`` and ``PeriodIndex`` creation (:issue:`24084` and :issue:`24118`)
12971298

12981299
.. _whatsnew_0240.docs:
12991300

pandas/_libs/tslibs/parsing.pyx

+14-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ cdef set _not_datelike_strings = {'a', 'A', 'm', 'M', 'p', 'P', 't', 'T'}
4747

4848
# ----------------------------------------------------------------------
4949

50+
_get_option = None
51+
52+
53+
def get_option(param):
54+
""" Defer import of get_option to break an import cycle that caused
55+
significant performance degradation in Period construction. See
56+
GH#24118 for details
57+
"""
58+
global _get_option
59+
if _get_option is None:
60+
from pandas.core.config import get_option
61+
_get_option = get_option
62+
return _get_option(param)
63+
5064

5165
def parse_datetime_string(date_string, freq=None, dayfirst=False,
5266
yearfirst=False, **kwargs):
@@ -117,7 +131,6 @@ def parse_time_string(arg, freq=None, dayfirst=None, yearfirst=None):
117131
freq = freq.rule_code
118132

119133
if dayfirst is None or yearfirst is None:
120-
from pandas.core.config import get_option
121134
if dayfirst is None:
122135
dayfirst = get_option("display.date_dayfirst")
123136
if yearfirst is None:

0 commit comments

Comments
 (0)