@@ -111,32 +111,51 @@ def __repr__(self):
111
111
def __len__ (self ):
112
112
return self .obj .sizes [self .dim ]
113
113
114
- def _reduce_method (name : str ) -> Callable : # type: ignore
115
- array_agg_func = getattr (duck_array_ops , name )
114
+ def _reduce_method (name : str , fillna , rolling_agg_func : Callable = None ) -> Callable : # type: ignore
115
+ """Constructs reduction methods built on a numpy reduction function (e.g. sum),
116
+ a bottleneck reduction function (e.g. move_sum), or a Rolling reduction (_mean)."""
117
+ if rolling_agg_func :
118
+ array_agg_func = None
119
+ else :
120
+ array_agg_func = getattr (duck_array_ops , name )
121
+
116
122
bottleneck_move_func = getattr (bottleneck , "move_" + name , None )
117
123
118
124
def method (self , keep_attrs = None , ** kwargs ):
119
125
120
126
keep_attrs = self ._get_keep_attrs (keep_attrs )
121
127
122
128
return self ._numpy_or_bottleneck_reduce (
123
- array_agg_func , bottleneck_move_func , keep_attrs = keep_attrs , ** kwargs
129
+ array_agg_func ,
130
+ bottleneck_move_func ,
131
+ rolling_agg_func ,
132
+ keep_attrs = keep_attrs ,
133
+ fillna = fillna ,
134
+ ** kwargs ,
124
135
)
125
136
126
137
method .__name__ = name
127
138
method .__doc__ = _ROLLING_REDUCE_DOCSTRING_TEMPLATE .format (name = name )
128
139
return method
129
140
130
- argmax = _reduce_method ("argmax" )
131
- argmin = _reduce_method ("argmin" )
132
- max = _reduce_method ("max" )
133
- min = _reduce_method ("min" )
134
- mean = _reduce_method ("mean" )
135
- prod = _reduce_method ("prod" )
136
- sum = _reduce_method ("sum" )
137
- std = _reduce_method ("std" )
138
- var = _reduce_method ("var" )
139
- median = _reduce_method ("median" )
141
+ def _mean (self , keep_attrs , ** kwargs ):
142
+ result = self .sum (keep_attrs = False , ** kwargs ) / self .count (keep_attrs = False )
143
+ if keep_attrs :
144
+ result .attrs = self .obj .attrs
145
+ return result
146
+
147
+ _mean .__doc__ = _ROLLING_REDUCE_DOCSTRING_TEMPLATE .format (name = "mean" )
148
+
149
+ argmax = _reduce_method ("argmax" , dtypes .NINF )
150
+ argmin = _reduce_method ("argmin" , dtypes .INF )
151
+ max = _reduce_method ("max" , dtypes .NINF )
152
+ min = _reduce_method ("min" , dtypes .INF )
153
+ prod = _reduce_method ("prod" , 1 )
154
+ sum = _reduce_method ("sum" , 0 )
155
+ mean = _reduce_method ("mean" , None , _mean )
156
+ std = _reduce_method ("std" , None )
157
+ var = _reduce_method ("var" , None )
158
+ median = _reduce_method ("median" , None )
140
159
141
160
def count (self , keep_attrs = None ):
142
161
keep_attrs = self ._get_keep_attrs (keep_attrs )
@@ -301,6 +320,24 @@ def construct(
301
320
302
321
"""
303
322
323
+ return self ._construct (
324
+ self .obj ,
325
+ window_dim = window_dim ,
326
+ stride = stride ,
327
+ fill_value = fill_value ,
328
+ keep_attrs = keep_attrs ,
329
+ ** window_dim_kwargs ,
330
+ )
331
+
332
+ def _construct (
333
+ self ,
334
+ obj ,
335
+ window_dim = None ,
336
+ stride = 1 ,
337
+ fill_value = dtypes .NA ,
338
+ keep_attrs = None ,
339
+ ** window_dim_kwargs ,
340
+ ):
304
341
from .dataarray import DataArray
305
342
306
343
keep_attrs = self ._get_keep_attrs (keep_attrs )
@@ -317,18 +354,18 @@ def construct(
317
354
)
318
355
stride = self ._mapping_to_list (stride , default = 1 )
319
356
320
- window = self . obj .variable .rolling_window (
357
+ window = obj .variable .rolling_window (
321
358
self .dim , self .window , window_dim , self .center , fill_value = fill_value
322
359
)
323
360
324
- attrs = self . obj .attrs if keep_attrs else {}
361
+ attrs = obj .attrs if keep_attrs else {}
325
362
326
363
result = DataArray (
327
364
window ,
328
- dims = self . obj .dims + tuple (window_dim ),
329
- coords = self . obj .coords ,
365
+ dims = obj .dims + tuple (window_dim ),
366
+ coords = obj .coords ,
330
367
attrs = attrs ,
331
- name = self . obj .name ,
368
+ name = obj .name ,
332
369
)
333
370
return result .isel (
334
371
** {d : slice (None , None , s ) for d , s in zip (self .dim , stride )}
@@ -393,7 +430,18 @@ def reduce(self, func, keep_attrs=None, **kwargs):
393
430
d : utils .get_temp_dimname (self .obj .dims , f"_rolling_dim_{ d } " )
394
431
for d in self .dim
395
432
}
396
- windows = self .construct (rolling_dim , keep_attrs = keep_attrs )
433
+
434
+ # save memory with reductions GH4325
435
+ fillna = kwargs .pop ("fillna" , dtypes .NA )
436
+ if fillna is not dtypes .NA :
437
+ obj = self .obj .fillna (fillna )
438
+ else :
439
+ obj = self .obj
440
+
441
+ windows = self ._construct (
442
+ obj , rolling_dim , keep_attrs = keep_attrs , fill_value = fillna
443
+ )
444
+
397
445
result = windows .reduce (
398
446
func , dim = list (rolling_dim .values ()), keep_attrs = keep_attrs , ** kwargs
399
447
)
@@ -470,7 +518,13 @@ def _bottleneck_reduce(self, func, keep_attrs, **kwargs):
470
518
return DataArray (values , self .obj .coords , attrs = attrs , name = self .obj .name )
471
519
472
520
def _numpy_or_bottleneck_reduce (
473
- self , array_agg_func , bottleneck_move_func , keep_attrs , ** kwargs
521
+ self ,
522
+ array_agg_func ,
523
+ bottleneck_move_func ,
524
+ rolling_agg_func ,
525
+ keep_attrs ,
526
+ fillna ,
527
+ ** kwargs ,
474
528
):
475
529
if "dim" in kwargs :
476
530
warnings .warn (
@@ -494,6 +548,18 @@ def _numpy_or_bottleneck_reduce(
494
548
bottleneck_move_func , keep_attrs = keep_attrs , ** kwargs
495
549
)
496
550
else :
551
+ if rolling_agg_func :
552
+ return rolling_agg_func (
553
+ self , keep_attrs = self ._get_keep_attrs (keep_attrs )
554
+ )
555
+ if fillna is not None :
556
+ if fillna is dtypes .INF :
557
+ fillna = dtypes .get_pos_infinity (self .obj .dtype , max_for_int = True )
558
+ elif fillna is dtypes .NINF :
559
+ fillna = dtypes .get_neg_infinity (self .obj .dtype , min_for_int = True )
560
+ kwargs .setdefault ("skipna" , False )
561
+ kwargs .setdefault ("fillna" , fillna )
562
+
497
563
return self .reduce (array_agg_func , keep_attrs = keep_attrs , ** kwargs )
498
564
499
565
@@ -600,13 +666,19 @@ def _counts(self, keep_attrs):
600
666
)
601
667
602
668
def _numpy_or_bottleneck_reduce (
603
- self , array_agg_func , bottleneck_move_func , keep_attrs , ** kwargs
669
+ self ,
670
+ array_agg_func ,
671
+ bottleneck_move_func ,
672
+ rolling_agg_func ,
673
+ keep_attrs ,
674
+ ** kwargs ,
604
675
):
605
676
return self ._dataset_implementation (
606
677
functools .partial (
607
678
DataArrayRolling ._numpy_or_bottleneck_reduce ,
608
679
array_agg_func = array_agg_func ,
609
680
bottleneck_move_func = bottleneck_move_func ,
681
+ rolling_agg_func = rolling_agg_func ,
610
682
),
611
683
keep_attrs = keep_attrs ,
612
684
** kwargs ,
0 commit comments