@@ -108,8 +108,8 @@ def __init__(
108
108
self .min_periods = min_periods
109
109
self .center = center
110
110
self .win_type = win_type
111
- self .win_freq = None
112
111
self .axis = obj ._get_axis_number (axis ) if axis is not None else None
112
+ self ._win_freq_i8 = None
113
113
self .validate ()
114
114
115
115
@property
@@ -120,10 +120,6 @@ def is_datetimelike(self) -> Optional[bool]:
120
120
def _on (self ):
121
121
return None
122
122
123
- @property
124
- def is_freq_type (self ) -> bool :
125
- return self .win_type == "freq"
126
-
127
123
def validate (self ) -> None :
128
124
if self .center is not None and not is_bool (self .center ):
129
125
raise ValueError ("center must be a boolean" )
@@ -329,9 +325,9 @@ def _get_window_indexer(self) -> BaseIndexer:
329
325
"""
330
326
if isinstance (self .window , BaseIndexer ):
331
327
return self .window
332
- if self .is_freq_type :
328
+ if self ._win_freq_i8 is not None :
333
329
return VariableWindowIndexer (
334
- index_array = self ._index_array , window_size = self .window
330
+ index_array = self ._index_array , window_size = self ._win_freq_i8
335
331
)
336
332
return FixedWindowIndexer (window_size = self .window )
337
333
@@ -816,7 +812,6 @@ def _gotitem(self, key, ndim, subset=None):
816
812
# when we do the splitting for the groupby
817
813
if self .on is not None :
818
814
self .obj = self .obj .set_index (self ._on )
819
- self .on = None
820
815
return super ()._gotitem (key , ndim , subset = subset )
821
816
822
817
def _validate_monotonic (self ):
@@ -992,22 +987,21 @@ class Window(BaseWindow):
992
987
def validate (self ):
993
988
super ().validate ()
994
989
990
+ if not isinstance (self .win_type , str ):
991
+ raise ValueError (f"Invalid win_type { self .win_type } " )
992
+ signal = import_optional_dependency (
993
+ "scipy.signal" , extra = "Scipy is required to generate window weight."
994
+ )
995
+ self ._scipy_weight_generator = getattr (signal , self .win_type , None )
996
+ if self ._scipy_weight_generator is None :
997
+ raise ValueError (f"Invalid win_type { self .win_type } " )
998
+
995
999
if isinstance (self .window , BaseIndexer ):
996
1000
raise NotImplementedError (
997
1001
"BaseIndexer subclasses not implemented with win_types."
998
1002
)
999
- elif is_integer (self .window ):
1000
- if self .window <= 0 :
1001
- raise ValueError ("window must be > 0 " )
1002
- sig = import_optional_dependency (
1003
- "scipy.signal" , extra = "Scipy is required to generate window weight."
1004
- )
1005
- if not isinstance (self .win_type , str ):
1006
- raise ValueError (f"Invalid win_type { self .win_type } " )
1007
- if getattr (sig , self .win_type , None ) is None :
1008
- raise ValueError (f"Invalid win_type { self .win_type } " )
1009
- else :
1010
- raise ValueError (f"Invalid window { self .window } " )
1003
+ elif not is_integer (self .window ) or self .window < 0 :
1004
+ raise ValueError ("window must be an integer 0 or greater" )
1011
1005
1012
1006
def _center_window (self , result : np .ndarray , offset : int ) -> np .ndarray :
1013
1007
"""
@@ -1047,11 +1041,7 @@ def _apply(
1047
1041
-------
1048
1042
y : type of input
1049
1043
"""
1050
- signal = import_optional_dependency (
1051
- "scipy.signal" , extra = "Scipy is required to generate window weight."
1052
- )
1053
- assert self .win_type is not None # for mypy
1054
- window = getattr (signal , self .win_type )(self .window , ** kwargs )
1044
+ window = self ._scipy_weight_generator (self .window , ** kwargs )
1055
1045
offset = (len (window ) - 1 ) // 2 if self .center else 0
1056
1046
1057
1047
def homogeneous_func (values : np .ndarray ):
@@ -1669,9 +1659,7 @@ def cov(self, other=None, pairwise=None, ddof=1, **kwargs):
1669
1659
# to the rolling constructors the data used when constructing self:
1670
1660
# window width, frequency data, or a BaseIndexer subclass
1671
1661
# GH 16058: offset window
1672
- window = (
1673
- self ._get_cov_corr_window (other ) if not self .is_freq_type else self .win_freq
1674
- )
1662
+ window = self ._get_cov_corr_window (other )
1675
1663
1676
1664
def _get_cov (X , Y ):
1677
1665
# GH #12373 : rolling functions error on float32 data
@@ -1814,9 +1802,7 @@ def corr(self, other=None, pairwise=None, **kwargs):
1814
1802
# to the rolling constructors the data used when constructing self:
1815
1803
# window width, frequency data, or a BaseIndexer subclass
1816
1804
# GH 16058: offset window
1817
- window = (
1818
- self ._get_cov_corr_window (other ) if not self .is_freq_type else self .win_freq
1819
- )
1805
+ window = self ._get_cov_corr_window (other )
1820
1806
1821
1807
def _get_corr (a , b ):
1822
1808
a = a .rolling (
@@ -1878,9 +1864,17 @@ def validate(self):
1878
1864
)
1879
1865
1880
1866
# this will raise ValueError on non-fixed freqs
1881
- self .win_freq = self .window
1882
- self .window = self ._determine_window_length ()
1883
- self .win_type = "freq"
1867
+ try :
1868
+ freq = to_offset (self .window )
1869
+ except (TypeError , ValueError ) as err :
1870
+ raise ValueError (
1871
+ f"passed window { self .window } is not "
1872
+ "compatible with a datetimelike index"
1873
+ ) from err
1874
+ if isinstance (self ._on , ABCPeriodIndex ):
1875
+ self ._win_freq_i8 = freq .nanos / (self ._on .freq .nanos / self ._on .freq .n )
1876
+ else :
1877
+ self ._win_freq_i8 = freq .nanos
1884
1878
1885
1879
# min_periods must be an integer
1886
1880
if self .min_periods is None :
@@ -1889,20 +1883,8 @@ def validate(self):
1889
1883
elif isinstance (self .window , BaseIndexer ):
1890
1884
# Passed BaseIndexer subclass should handle all other rolling kwargs
1891
1885
return
1892
- elif not is_integer (self .window ):
1893
- raise ValueError ("window must be an integer" )
1894
- elif self .window < 0 :
1895
- raise ValueError ("window must be non-negative" )
1896
-
1897
- def _determine_window_length (self ) -> Union [int , float ]:
1898
- """
1899
- Calculate freq for PeriodIndexes based on Index freq. Can not use
1900
- nanos, because asi8 of PeriodIndex is not in nanos
1901
- """
1902
- freq = self ._validate_freq ()
1903
- if isinstance (self ._on , ABCPeriodIndex ):
1904
- return freq .nanos / (self ._on .freq .nanos / self ._on .freq .n )
1905
- return freq .nanos
1886
+ elif not is_integer (self .window ) or self .window < 0 :
1887
+ raise ValueError ("window must be an integer 0 or greater" )
1906
1888
1907
1889
def _validate_monotonic (self ):
1908
1890
"""
@@ -1917,18 +1899,6 @@ def _raise_monotonic_error(self):
1917
1899
formatted = "index"
1918
1900
raise ValueError (f"{ formatted } must be monotonic" )
1919
1901
1920
- def _validate_freq (self ):
1921
- """
1922
- Validate & return window frequency.
1923
- """
1924
- try :
1925
- return to_offset (self .window )
1926
- except (TypeError , ValueError ) as err :
1927
- raise ValueError (
1928
- f"passed window { self .window } is not "
1929
- "compatible with a datetimelike index"
1930
- ) from err
1931
-
1932
1902
_agg_see_also_doc = dedent (
1933
1903
"""
1934
1904
See Also
@@ -2138,8 +2108,9 @@ def _get_window_indexer(self) -> GroupbyIndexer:
2138
2108
# We'll be using the index of each group later
2139
2109
indexer_kwargs .pop ("index_array" , None )
2140
2110
window = 0
2141
- elif self .is_freq_type :
2111
+ elif self ._win_freq_i8 is not None :
2142
2112
rolling_indexer = VariableWindowIndexer
2113
+ window = self ._win_freq_i8
2143
2114
else :
2144
2115
rolling_indexer = FixedWindowIndexer
2145
2116
index_array = None
0 commit comments