53
53
54
54
55
55
class _Window (PandasObject , SelectionMixin ):
56
- _attributes = ['window' , 'min_periods' , 'freq ' , 'center ' , 'win_type ' ,
57
- 'axis' , 'on' ]
56
+ _attributes = ['window' , 'min_periods' , 'min_weight ' , 'freq ' , 'center ' ,
57
+ 'win_type' , ' axis' , 'on' ]
58
58
exclusions = set ()
59
59
60
- def __init__ (self , obj , window = None , min_periods = None , freq = None ,
61
- center = False , win_type = None , axis = 0 , on = None , ** kwargs ):
60
+ def __init__ (self , obj , window = None , min_periods = None , min_weight = None ,
61
+ freq = None , center = False , win_type = None , axis = 0 , on = None ,
62
+ ** kwargs ):
62
63
63
64
if freq is not None :
64
65
warnings .warn ("The freq kw is deprecated and will be removed in a "
@@ -71,6 +72,7 @@ def __init__(self, obj, window=None, min_periods=None, freq=None,
71
72
self .on = on
72
73
self .window = window
73
74
self .min_periods = min_periods
75
+ self .min_weight = min_weight
74
76
self .freq = freq
75
77
self .center = center
76
78
self .win_type = win_type
@@ -744,7 +746,12 @@ def calc(x):
744
746
745
747
results .append (result )
746
748
747
- return self ._wrap_results (results , blocks , obj )
749
+ result = self ._wrap_results (results , blocks , obj )
750
+
751
+ if self .min_weight :
752
+ result = result .where (_min_weight_mask (self , self .min_weight ))
753
+
754
+ return result
748
755
749
756
750
757
class _Rolling_and_Expanding (_Rolling ):
@@ -1187,6 +1194,9 @@ class Expanding(_Rolling_and_Expanding):
1187
1194
min_periods : int, default None
1188
1195
Minimum number of observations in window required to have a value
1189
1196
(otherwise result is NA).
1197
+ min_weight : int, default None
1198
+ Minimum proportion of weight in available values in window required
1199
+ to have a value (otherwies result in NA)
1190
1200
freq : string or DateOffset object, optional (default None) (DEPRECATED)
1191
1201
Frequency to conform the data to before computing the statistic.
1192
1202
Specified as a frequency string or DateOffset object.
@@ -1227,12 +1237,13 @@ class Expanding(_Rolling_and_Expanding):
1227
1237
of :meth:`~pandas.Series.resample` (i.e. using the `mean`).
1228
1238
"""
1229
1239
1230
- _attributes = ['min_periods' , 'freq' , 'center' , 'axis' ]
1240
+ _attributes = ['min_periods' , 'min_weight' , ' freq' , 'center' , 'axis' ]
1231
1241
1232
- def __init__ (self , obj , min_periods = 1 , freq = None , center = False , axis = 0 ,
1233
- ** kwargs ):
1234
- super (Expanding , self ).__init__ (obj = obj , min_periods = min_periods ,
1235
- freq = freq , center = center , axis = axis )
1242
+ def __init__ (self , obj , min_periods = 1 , min_weight = None , freq = None ,
1243
+ center = False , axis = 0 , ** kwargs ):
1244
+ super (Expanding , self ).__init__ (
1245
+ obj = obj , min_periods = min_periods , min_weight = min_weight ,
1246
+ freq = freq , center = center , axis = axis )
1236
1247
1237
1248
@property
1238
1249
def _constructor (self ):
@@ -1473,14 +1484,16 @@ class EWM(_Rolling):
1473
1484
More details can be found at
1474
1485
http://pandas.pydata.org/pandas-docs/stable/computation.html#exponentially-weighted-windows
1475
1486
"""
1476
- _attributes = ['com' , 'min_periods' , 'freq' , 'adjust' , 'ignore_na' , 'axis' ]
1487
+ _attributes = ['com' , 'min_periods' , 'min_weight' , 'freq' , 'adjust' ,
1488
+ 'ignore_na' , 'axis' ]
1477
1489
1478
1490
def __init__ (self , obj , com = None , span = None , halflife = None , alpha = None ,
1479
- min_periods = 0 , freq = None , adjust = True , ignore_na = False ,
1480
- axis = 0 ):
1491
+ min_periods = 0 , min_weight = None , freq = None , adjust = True ,
1492
+ ignore_na = False , axis = 0 ):
1481
1493
self .obj = obj
1482
1494
self .com = _get_center_of_mass (com , span , halflife , alpha )
1483
1495
self .min_periods = min_periods
1496
+ self .min_weight = min_weight
1484
1497
self .freq = freq
1485
1498
self .adjust = adjust
1486
1499
self .ignore_na = ignore_na
@@ -1540,7 +1553,12 @@ def func(arg):
1540
1553
1541
1554
results .append (np .apply_along_axis (func , self .axis , values ))
1542
1555
1543
- return self ._wrap_results (results , blocks , obj )
1556
+ result = self ._wrap_results (results , blocks , obj )
1557
+
1558
+ if self .min_weight :
1559
+ result = result .where (_min_weight_mask (self , self .min_weight ))
1560
+
1561
+ return result
1544
1562
1545
1563
@Substitution (name = 'ewm' )
1546
1564
@Appender (_doc_template )
@@ -1751,6 +1769,25 @@ def _check_func(minp, window):
1751
1769
return _check_func
1752
1770
1753
1771
1772
+ def _min_weight_mask (rolling , min_weight ):
1773
+ """
1774
+ Takes a rolling object and a min_weight proportion, and returns
1775
+ a pandas bool object with True where enough weight exists
1776
+ """
1777
+
1778
+ data = rolling .obj
1779
+ # all valid values have a value of 1 in valid_data
1780
+ valid_data = data .notnull ()
1781
+
1782
+ # This copies the rolling object, replacing obj with valid_data
1783
+ # The resulting values are the proportion of weight from values that _do_
1784
+ # contribute out of those that _could_
1785
+ valid_proportion = rolling ._shallow_copy (
1786
+ obj = valid_data , min_periods = 0 , min_weight = None ).mean ()
1787
+
1788
+ return valid_proportion >= min_weight
1789
+
1790
+
1754
1791
def _use_window (minp , window ):
1755
1792
if minp is None :
1756
1793
return window
0 commit comments