acgc.stats.boxcar
1# -*- coding: utf-8 -*- 2 3import numpy as np 4 5__all__ = [ 6 "boxcar", 7 "boxcarpoly" 8] 9 10def boxcarpoly( array, width, order=2, align='center'): 11 '''Calculate a boxcar polynomial (i.e. running polynomial fit) of an array. 12 13 See `boxcar` for parameter definitions 14 ''' 15 return boxcar( array, width, order=order, align=align, method='polynomial') 16 17def boxcar( array, width, align='center', method='mean', order=2 ): 18 '''Calculate a boxcar average (i.e. running mean, median, or polynomial fit) of an array. 19 20 Elements of input array are assumed to be equally spaced along an (unspecified) 21 coordinate dimension. 22 23 A centered boxcar average with even widths is traditionally 24 not allowed. This BOXCAR program allows even widths by 25 giving half weights to elements on either end of the 26 averaging window and full weights to all others. A centered 27 average with even width therefore uses uses WIDTH+1 28 elements in its averaging kernel. 29 30 Parameters 31 ---------- 32 array : array of float (N,) 33 1D array of values to average 34 width : int 35 number of elements to include in the average. 36 align : str 37 specifies how the averaging window for each element of the output array 38 aligns with the input array. 39 Values: center (default), forward (trailing elements), backward (leading elements) 40 method : {'mean' (default), 'median', 'polynomial'} 41 specifies the averaging kernel function 42 order : int, default=2 43 specifies the polynomial order to fit within each boxcar window. 44 This has no effect unless `method`='polynomial' 45 A parabola is order=2; order=0 is equivalent to method="mean" 46 47 Returns 48 ------- 49 result : array of float (N,) 50 1D array with averages with same size as input array. 51 Elements on either end may be NaN 52 ''' 53 54 N = array.size 55 56 # Initialize smoothed array 57 smootharray = np.empty_like(array) 58 smootharray[:] = np.NaN 59 60 # uniform averaging kernel 61 kernel = np.ones(width) 62 63 # Setup for backward boxcar 64 if align=='backward': 65 # Half widths before and after element I 66 67 HW1 = width-1 68 HW2 = width-HW1-1 69 70 # Setup for forward boxcar 71 elif align=='forward': 72 HW1 = 0 73 HW2 = width-HW1-1 74 75 # Setup for centered boxcar 76 elif align=='center': 77 # Separate treatments for odd and even widths 78 if np.mod(width,2)==1: 79 # Odd widths 80 HW1 = np.floor(width/2) 81 HW2 = width-HW1-1 82 83 else: 84 # Even widths 85 HW1 = width/2 86 HW2 = width-HW1 87 88 # Uniform kernel in middle 89 kernel = np.ones(width+1) 90 91 # Half weight kernel for ends 92 kernel[0] = 0.5 93 kernel[width] = 0.5 94 95 # Normalize the kernel 96 kernel=kernel/kernel.sum() 97 else: 98 raise ValueError( f'align={align} not implemented. ' 99 + 'Value should be "center", "forward" or "backward".' ) 100 101 # Convert to integer type 102 HW1 = int(HW1) 103 HW2 = int(HW2) 104 105 # Do boxcar 106 for i in range(HW1,N-HW2-1): 107 108 # Sub array that we operate on 109 sub = array[i-HW1:i+HW2+1] 110 111 if method=='median': 112 # Running median 113 smootharray[i] = np.nanmedian(sub) 114 115 elif method=='mean': 116 # Running mean 117 # Kernel average, only over finite elements 118 #(NaNs removed from numerator and denominator 119 smootharray[i] = np.nansum( sub*kernel ) / np.sum(kernel[np.where(np.isfinite(sub))]) 120 121 elif method=='polynomial': 122 123 # Local x coordinate 124 x = np.arange(-HW1,HW2+1) 125 126 # Fit with polynomial of specified order 127 # Avoid NaNs 128 idx = np.isfinite(sub) 129 130 # number of valid points (non NaN) 131 nvalid = np.sum(idx) 132 133 if nvalid==0: 134 # smoothed value is NaN when there are no valid points 135 smootharray[i] = np.nan 136 137 else: 138 # A polynomial fit requires at least (order+1) points. 139 # When there are fewer points, use the highest possible order. 140 ordmax = np.max([np.min([order,np.sum(idx)-1]),0]) 141 142 p = np.polyfit(x[idx],sub[idx],ordmax,w=kernel[idx]) 143 144 # The fitted value at local x=0 is just the constant term 145 smootharray[i] = p[order] 146 147 else: 148 raise ValueError( f'method={method} not implemented. ' 149 + 'Value should be "mean", "median" or "polynomial"') 150 151 return smootharray
def
boxcar(array, width, align='center', method='mean', order=2):
18def boxcar( array, width, align='center', method='mean', order=2 ): 19 '''Calculate a boxcar average (i.e. running mean, median, or polynomial fit) of an array. 20 21 Elements of input array are assumed to be equally spaced along an (unspecified) 22 coordinate dimension. 23 24 A centered boxcar average with even widths is traditionally 25 not allowed. This BOXCAR program allows even widths by 26 giving half weights to elements on either end of the 27 averaging window and full weights to all others. A centered 28 average with even width therefore uses uses WIDTH+1 29 elements in its averaging kernel. 30 31 Parameters 32 ---------- 33 array : array of float (N,) 34 1D array of values to average 35 width : int 36 number of elements to include in the average. 37 align : str 38 specifies how the averaging window for each element of the output array 39 aligns with the input array. 40 Values: center (default), forward (trailing elements), backward (leading elements) 41 method : {'mean' (default), 'median', 'polynomial'} 42 specifies the averaging kernel function 43 order : int, default=2 44 specifies the polynomial order to fit within each boxcar window. 45 This has no effect unless `method`='polynomial' 46 A parabola is order=2; order=0 is equivalent to method="mean" 47 48 Returns 49 ------- 50 result : array of float (N,) 51 1D array with averages with same size as input array. 52 Elements on either end may be NaN 53 ''' 54 55 N = array.size 56 57 # Initialize smoothed array 58 smootharray = np.empty_like(array) 59 smootharray[:] = np.NaN 60 61 # uniform averaging kernel 62 kernel = np.ones(width) 63 64 # Setup for backward boxcar 65 if align=='backward': 66 # Half widths before and after element I 67 68 HW1 = width-1 69 HW2 = width-HW1-1 70 71 # Setup for forward boxcar 72 elif align=='forward': 73 HW1 = 0 74 HW2 = width-HW1-1 75 76 # Setup for centered boxcar 77 elif align=='center': 78 # Separate treatments for odd and even widths 79 if np.mod(width,2)==1: 80 # Odd widths 81 HW1 = np.floor(width/2) 82 HW2 = width-HW1-1 83 84 else: 85 # Even widths 86 HW1 = width/2 87 HW2 = width-HW1 88 89 # Uniform kernel in middle 90 kernel = np.ones(width+1) 91 92 # Half weight kernel for ends 93 kernel[0] = 0.5 94 kernel[width] = 0.5 95 96 # Normalize the kernel 97 kernel=kernel/kernel.sum() 98 else: 99 raise ValueError( f'align={align} not implemented. ' 100 + 'Value should be "center", "forward" or "backward".' ) 101 102 # Convert to integer type 103 HW1 = int(HW1) 104 HW2 = int(HW2) 105 106 # Do boxcar 107 for i in range(HW1,N-HW2-1): 108 109 # Sub array that we operate on 110 sub = array[i-HW1:i+HW2+1] 111 112 if method=='median': 113 # Running median 114 smootharray[i] = np.nanmedian(sub) 115 116 elif method=='mean': 117 # Running mean 118 # Kernel average, only over finite elements 119 #(NaNs removed from numerator and denominator 120 smootharray[i] = np.nansum( sub*kernel ) / np.sum(kernel[np.where(np.isfinite(sub))]) 121 122 elif method=='polynomial': 123 124 # Local x coordinate 125 x = np.arange(-HW1,HW2+1) 126 127 # Fit with polynomial of specified order 128 # Avoid NaNs 129 idx = np.isfinite(sub) 130 131 # number of valid points (non NaN) 132 nvalid = np.sum(idx) 133 134 if nvalid==0: 135 # smoothed value is NaN when there are no valid points 136 smootharray[i] = np.nan 137 138 else: 139 # A polynomial fit requires at least (order+1) points. 140 # When there are fewer points, use the highest possible order. 141 ordmax = np.max([np.min([order,np.sum(idx)-1]),0]) 142 143 p = np.polyfit(x[idx],sub[idx],ordmax,w=kernel[idx]) 144 145 # The fitted value at local x=0 is just the constant term 146 smootharray[i] = p[order] 147 148 else: 149 raise ValueError( f'method={method} not implemented. ' 150 + 'Value should be "mean", "median" or "polynomial"') 151 152 return smootharray
Calculate a boxcar average (i.e. running mean, median, or polynomial fit) of an array.
Elements of input array are assumed to be equally spaced along an (unspecified) coordinate dimension.
A centered boxcar average with even widths is traditionally not allowed. This BOXCAR program allows even widths by giving half weights to elements on either end of the averaging window and full weights to all others. A centered average with even width therefore uses uses WIDTH+1 elements in its averaging kernel.
Parameters
- array (array of float (N,)): 1D array of values to average
- width (int): number of elements to include in the average.
- align (str): specifies how the averaging window for each element of the output array aligns with the input array. Values: center (default), forward (trailing elements), backward (leading elements)
- method ({'mean' (default), 'median', 'polynomial'}): specifies the averaging kernel function
- order (int, default=2):
specifies the polynomial order to fit within each boxcar window.
This has no effect unless
method
='polynomial' A parabola is order=2; order=0 is equivalent to method="mean"
Returns
- result (array of float (N,)): 1D array with averages with same size as input array. Elements on either end may be NaN
def
boxcarpoly(array, width, order=2, align='center'):
11def boxcarpoly( array, width, order=2, align='center'): 12 '''Calculate a boxcar polynomial (i.e. running polynomial fit) of an array. 13 14 See `boxcar` for parameter definitions 15 ''' 16 return boxcar( array, width, order=order, align=align, method='polynomial')
Calculate a boxcar polynomial (i.e. running polynomial fit) of an array.
See boxcar
for parameter definitions