Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/core/array_algos/masked_reductions.py: 25%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

75 statements  

1""" 

2masked_reductions.py is for reduction algorithms using a mask-based approach 

3for missing values. 

4""" 

5 

6from __future__ import annotations 

7 

8from typing import ( 

9 TYPE_CHECKING, 

10 Any, 

11) 

12import warnings 

13 

14import numpy as np 

15 

16from pandas._libs import ( 

17 lib, 

18 missing as libmissing, 

19) 

20 

21from pandas.core.nanops import check_below_min_count 

22 

23if TYPE_CHECKING: 

24 from collections.abc import Callable 

25 

26 from pandas._typing import ( 

27 AxisInt, 

28 npt, 

29 ) 

30 

31 

32def _get_min_value(dtype: np.dtype) -> int | float: 

33 """Get the minimum value for a given numpy dtype.""" 

34 if dtype.kind == "f": 

35 return -np.inf 

36 elif dtype.kind == "u": 

37 return 0 

38 else: 

39 return np.iinfo(dtype).min 

40 

41 

42def _get_max_value(dtype: np.dtype) -> int | float: 

43 """Get the maximum value for a given numpy dtype.""" 

44 if dtype.kind == "f": 

45 return np.inf 

46 else: 

47 return np.iinfo(dtype).max 

48 

49 

50def _reductions( 

51 func: Callable[..., Any], 

52 values: np.ndarray, 

53 mask: npt.NDArray[np.bool_], 

54 *, 

55 skipna: bool = True, 

56 min_count: int = 0, 

57 axis: AxisInt | None = None, 

58 initial: object | lib.NoDefault = lib.no_default, 

59 **kwargs, 

60): 

61 """ 

62 Sum, mean or product for 1D masked array. 

63 

64 Parameters 

65 ---------- 

66 func : np.sum or np.prod 

67 values : np.ndarray 

68 Numpy array with the values (can be of any dtype that support the 

69 operation). 

70 mask : np.ndarray[bool] 

71 Boolean numpy array (True values indicate missing values). 

72 skipna : bool, default True 

73 Whether to skip NA. 

74 min_count : int, default 0 

75 The required number of valid values to perform the operation. If fewer than 

76 ``min_count`` non-NA values are present the result will be NA. 

77 axis : int, optional, default None 

78 initial : scalar, optional 

79 Starting value for the reduction. NumPy has a default value for most 

80 data types, but for object-dtype arrays we need to specify it explicitly 

81 """ 

82 if initial is not lib.no_default: 

83 kwargs["initial"] = initial 

84 

85 if not skipna: 

86 if axis is not None and values.ndim > 1: 

87 # For 2D with axis, compute the reduction and let the caller 

88 # handle per-row/column masking via _wrap_reduction_result. 

89 return func(values, axis=axis, **kwargs) 

90 if mask.any() or check_below_min_count(values.shape, None, min_count): 

91 return libmissing.NA 

92 else: 

93 return func(values, axis=axis, **kwargs) 

94 else: 

95 if check_below_min_count(values.shape, mask, min_count) and ( 

96 axis is None or values.ndim == 1 

97 ): 

98 return libmissing.NA 

99 

100 return func(values, where=~mask, axis=axis, **kwargs) 

101 

102 

103def sum( 

104 values: np.ndarray, 

105 mask: npt.NDArray[np.bool_], 

106 *, 

107 skipna: bool = True, 

108 min_count: int = 0, 

109 axis: AxisInt | None = None, 

110 initial: object | lib.NoDefault = lib.no_default, 

111): 

112 return _reductions( 

113 np.sum, 

114 values=values, 

115 mask=mask, 

116 skipna=skipna, 

117 min_count=min_count, 

118 axis=axis, 

119 initial=initial, 

120 ) 

121 

122 

123def prod( 

124 values: np.ndarray, 

125 mask: npt.NDArray[np.bool_], 

126 *, 

127 skipna: bool = True, 

128 min_count: int = 0, 

129 axis: AxisInt | None = None, 

130): 

131 return _reductions( 

132 np.prod, values=values, mask=mask, skipna=skipna, min_count=min_count, axis=axis 

133 ) 

134 

135 

136def _minmax( 

137 func: Callable[..., Any], 

138 values: np.ndarray, 

139 mask: npt.NDArray[np.bool_], 

140 *, 

141 skipna: bool = True, 

142 axis: AxisInt | None = None, 

143): 

144 """ 

145 Reduction for 1D masked array. 

146 

147 Parameters 

148 ---------- 

149 func : np.min or np.max 

150 values : np.ndarray 

151 Numpy array with the values (can be of any dtype that support the 

152 operation). 

153 mask : np.ndarray[bool] 

154 Boolean numpy array (True values indicate missing values). 

155 skipna : bool, default True 

156 Whether to skip NA. 

157 axis : int, optional, default None 

158 """ 

159 if not skipna: 

160 if axis is not None and values.ndim > 1: 

161 # For 2D with axis, compute the reduction and let the caller 

162 # handle per-row/column masking via _wrap_reduction_result. 

163 return func(values, axis=axis) 

164 if mask.any() or not values.size: 

165 # min/max with empty array raise in numpy, pandas returns NA 

166 return libmissing.NA 

167 else: 

168 return func(values, axis=axis) 

169 else: 

170 if axis is not None and values.ndim > 1: 

171 # Can't use values[~mask] which would flatten the array. 

172 # Instead, replace masked values with the identity element 

173 # and then reduce. 

174 if func is np.min: 

175 fill_value = _get_max_value(values.dtype) 

176 else: 

177 fill_value = _get_min_value(values.dtype) 

178 filled = np.where(mask, fill_value, values) 

179 return func(filled, axis=axis) 

180 subset = values[~mask] 

181 if subset.size: 

182 return func(subset, axis=axis) 

183 else: 

184 # min/max with empty array raise in numpy, pandas returns NA 

185 return libmissing.NA 

186 

187 

188def min( 

189 values: np.ndarray, 

190 mask: npt.NDArray[np.bool_], 

191 *, 

192 skipna: bool = True, 

193 axis: AxisInt | None = None, 

194): 

195 return _minmax(np.min, values=values, mask=mask, skipna=skipna, axis=axis) 

196 

197 

198def max( 

199 values: np.ndarray, 

200 mask: npt.NDArray[np.bool_], 

201 *, 

202 skipna: bool = True, 

203 axis: AxisInt | None = None, 

204): 

205 return _minmax(np.max, values=values, mask=mask, skipna=skipna, axis=axis) 

206 

207 

208def mean( 

209 values: np.ndarray, 

210 mask: npt.NDArray[np.bool_], 

211 *, 

212 skipna: bool = True, 

213 axis: AxisInt | None = None, 

214): 

215 if not values.size or (mask.all() and (axis is None or values.ndim == 1)): 

216 return libmissing.NA 

217 with warnings.catch_warnings(): 

218 warnings.simplefilter("ignore", RuntimeWarning) 

219 return _reductions(np.mean, values=values, mask=mask, skipna=skipna, axis=axis) 

220 

221 

222def var( 

223 values: np.ndarray, 

224 mask: npt.NDArray[np.bool_], 

225 *, 

226 skipna: bool = True, 

227 axis: AxisInt | None = None, 

228 ddof: int = 1, 

229): 

230 if not values.size or (mask.all() and (axis is None or values.ndim == 1)): 

231 return libmissing.NA 

232 

233 with warnings.catch_warnings(): 

234 warnings.simplefilter("ignore", RuntimeWarning) 

235 return _reductions( 

236 np.var, values=values, mask=mask, skipna=skipna, axis=axis, ddof=ddof 

237 ) 

238 

239 

240def std( 

241 values: np.ndarray, 

242 mask: npt.NDArray[np.bool_], 

243 *, 

244 skipna: bool = True, 

245 axis: AxisInt | None = None, 

246 ddof: int = 1, 

247): 

248 if not values.size or (mask.all() and (axis is None or values.ndim == 1)): 

249 return libmissing.NA 

250 

251 with warnings.catch_warnings(): 

252 warnings.simplefilter("ignore", RuntimeWarning) 

253 return _reductions( 

254 np.std, values=values, mask=mask, skipna=skipna, axis=axis, ddof=ddof 

255 )