|
57 | 57 | notna, |
58 | 58 | ) |
59 | 59 |
|
| 60 | +import pandas as pd |
60 | 61 | from pandas.core import ( |
61 | 62 | algorithms as algos, |
62 | 63 | arraylike, |
@@ -1078,29 +1079,48 @@ def _reduce(self, name: str, *, skipna: bool = True, **kwargs): |
1078 | 1079 |
|
1079 | 1080 | # median, skew, kurt, sem |
1080 | 1081 | op = getattr(nanops, f"nan{name}") |
1081 | | - result = op(data, axis=0, skipna=skipna, mask=mask, **kwargs) |
1082 | | - |
| 1082 | + axis = kwargs.pop("axis", None) |
| 1083 | + result = op(data, axis=axis, skipna=skipna, mask=mask, **kwargs) |
1083 | 1084 | if np.isnan(result): |
1084 | | - return libmissing.NA |
| 1085 | + result = libmissing.NA |
1085 | 1086 |
|
1086 | | - return result |
| 1087 | + return self._wrap_reduction_result( |
| 1088 | + name, result, skipna=skipna, axis=axis, **kwargs |
| 1089 | + ) |
1087 | 1090 |
|
1088 | 1091 | def _reduce_with_wrap(self, name: str, *, skipna: bool = True, kwargs): |
1089 | | - res = self.reshape(-1, 1)._reduce(name=name, skipna=skipna, **kwargs) |
| 1092 | + res = self.reshape(-1, 1)._reduce(name=name, skipna=skipna, axis=0, **kwargs) |
1090 | 1093 | return res |
1091 | 1094 |
|
1092 | 1095 | def _wrap_reduction_result(self, name: str, result, skipna, **kwargs): |
| 1096 | + axis = kwargs["axis"] |
1093 | 1097 | if isinstance(result, np.ndarray): |
1094 | | - axis = kwargs["axis"] |
1095 | 1098 | if skipna: |
1096 | 1099 | # we only retain mask for all-NA rows/columns |
1097 | 1100 | mask = self._mask.all(axis=axis) |
1098 | 1101 | else: |
1099 | 1102 | mask = self._mask.any(axis=axis) |
1100 | 1103 |
|
1101 | 1104 | return self._maybe_mask_result(result, mask) |
| 1105 | + elif result is pd.NA and self.ndim == 2: |
| 1106 | + result = self._wrap_na_result(name=name, axis=axis) |
| 1107 | + return result |
1102 | 1108 | return result |
1103 | 1109 |
|
| 1110 | + def _wrap_na_result(self, *, name, axis): |
| 1111 | + mask_size = self.shape[1] if axis == 0 else self.shape[0] |
| 1112 | + mask = np.ones(mask_size, dtype=bool) |
| 1113 | + |
| 1114 | + if name in ["mean", "median", "var", "std", "skew"]: |
| 1115 | + np_dtype = "float64" |
| 1116 | + elif name in ["min", "max"]: |
| 1117 | + np_dtype = self.dtype.type |
| 1118 | + else: |
| 1119 | + np_dtype = {"i": "int64", "u": "uint64", "f": "float64"}[self.dtype.kind] |
| 1120 | + |
| 1121 | + value = np.array([1], dtype=np_dtype) |
| 1122 | + return self._maybe_mask_result(value, mask=mask) |
| 1123 | + |
1104 | 1124 | def _wrap_min_count_reduction_result( |
1105 | 1125 | self, name: str, result, skipna, min_count, **kwargs |
1106 | 1126 | ): |
@@ -1193,21 +1213,27 @@ def std( |
1193 | 1213 |
|
1194 | 1214 | def min(self, *, skipna: bool = True, axis: AxisInt | None = 0, **kwargs): |
1195 | 1215 | nv.validate_min((), kwargs) |
1196 | | - return masked_reductions.min( |
| 1216 | + result = masked_reductions.min( |
1197 | 1217 | self._data, |
1198 | 1218 | self._mask, |
1199 | 1219 | skipna=skipna, |
1200 | 1220 | axis=axis, |
1201 | 1221 | ) |
| 1222 | + return self._wrap_reduction_result( |
| 1223 | + "min", result, skipna=skipna, axis=axis, **kwargs |
| 1224 | + ) |
1202 | 1225 |
|
1203 | 1226 | def max(self, *, skipna: bool = True, axis: AxisInt | None = 0, **kwargs): |
1204 | 1227 | nv.validate_max((), kwargs) |
1205 | | - return masked_reductions.max( |
| 1228 | + result = masked_reductions.max( |
1206 | 1229 | self._data, |
1207 | 1230 | self._mask, |
1208 | 1231 | skipna=skipna, |
1209 | 1232 | axis=axis, |
1210 | 1233 | ) |
| 1234 | + return self._wrap_reduction_result( |
| 1235 | + "max", result, skipna=skipna, axis=axis, **kwargs |
| 1236 | + ) |
1211 | 1237 |
|
1212 | 1238 | def any(self, *, skipna: bool = True, **kwargs): |
1213 | 1239 | """ |
|
0 commit comments