def equals( self, other: tp.Any, *, compare_name: bool = False, compare_dtype: bool = False, compare_class: bool = False, skipna: bool = True, ) -> bool: ''' {doc} Args: {compare_name} {compare_dtype} {compare_class} {skipna} ''' if id(other) == id(self): return True if compare_class and self.__class__ != other.__class__: return False elif not isinstance(other, Index): return False # defer updating cache if self._recache: self._update_array_cache() # same type from here if len(self) != len(other): return False if compare_name and self.name != other.name: return False if compare_dtype and self.dtype != other.dtype: return False eq = self.values == other.values # NOTE: will only be False, or an array if eq is False: return eq #type: ignore if skipna: isna_both = (isna_array(self.values, include_none=False) & isna_array(other.values, include_none=False)) eq[isna_both] = True if not eq.all(): return False return True
def test_isna_array(self, array: np.ndarray) -> None: post = util.isna_array(array) self.assertTrue(post.dtype == bool) values = np.ravel(array) count_na = sum(util.isna_element(x) for x in values) self.assertTrue(np.ravel(post).sum() == count_na)
def test_isna_array_b(self) -> None: a1 = np.array([[1, 2], [3, 4]]) a2 = np.array([[False, True, False], [False, True, False]]) a3 = np.array([['b', 'c', 'd'], ['b', 'c', 'd']]) a4 = np.array([[2.3, 3.2, np.nan], [2.3, 3.2, np.nan]]) a5 = np.array([['test', 'test again', np.nan], ['test', 'test again', np.nan]], dtype=object) a6 = np.array([[2.3, 5.4, np.nan], [2.3, 5.4, np.nan]], dtype='float32') self.assertEqual(isna_array(a1).tolist(), [[False, False], [False, False]]) self.assertEqual(isna_array(a2).tolist(), [[False, False, False], [False, False, False]]) self.assertEqual(isna_array(a3).tolist(), [[False, False, False], [False, False, False]]) self.assertEqual(isna_array(a4).tolist(), [[False, False, True], [False, False, True]]) self.assertEqual(isna_array(a5).tolist(), [[False, False, True], [False, False, True]]) self.assertEqual(isna_array(a6).tolist(), [[False, False, True], [False, False, True]])
def test_ufunc_skipna_1d(self, array: np.ndarray) -> None: has_na = util.isna_array(array).any() for ufunc, ufunc_skipna, dtype in UFUNC_AXIS_SKIPNA.values(): with np.errstate(over='ignore', under='ignore'): v1 = ufunc_skipna(array) # this should return a single value self.assertFalse(isinstance(v1, np.ndarray)) if has_na: v2 = ufunc(array) self.assertFalse(isinstance(v2, np.ndarray))
def test_ufunc_axis_skipna(self, array: np.ndarray) -> None: has_na = util.isna_array(array).any() for nt in UFUNC_AXIS_SKIPNA.values(): ufunc = nt.ufunc ufunc_skipna = nt.ufunc_skipna # dtypes = nt.dtypes # composable = nt.composable # doc = nt.doc_header # size_one_unity = nt.size_one_unity with np.errstate(over='ignore', under='ignore', divide='ignore'): post = util.ufunc_axis_skipna(array=array, skipna=True, axis=0, ufunc=ufunc, ufunc_skipna=ufunc_skipna) if array.ndim == 2: self.assertTrue(post.ndim == 1)
def test_isna_array_a(self) -> None: a1 = np.array([1, 2, 3]) a2 = np.array([False, True, False]) a3 = np.array(['b', 'c', 'd']) a4 = np.array([2.3, 3.2]) a5 = np.array(['test', 'test again'], dtype='S') a6 = np.array([2.3, 5.4], dtype='float32') self.assertEqual(isna_array(a1).tolist(), [False, False, False]) self.assertEqual(isna_array(a2).tolist(), [False, False, False]) self.assertEqual(isna_array(a3).tolist(), [False, False, False]) self.assertEqual(isna_array(a4).tolist(), [False, False]) self.assertEqual(isna_array(a5).tolist(), [False, False]) self.assertEqual(isna_array(a6).tolist(), [False, False]) a1 = np.array([1, 2, 3, None]) a2 = np.array([False, True, False, None]) a3 = np.array(['b', 'c', 'd', None]) a4 = np.array([2.3, 3.2, None]) a5 = np.array(['test', 'test again', None]) a6 = np.array([2.3, 5.4, None]) self.assertEqual(isna_array(a1).tolist(), [False, False, False, True]) self.assertEqual(isna_array(a2).tolist(), [False, False, False, True]) self.assertEqual(isna_array(a3).tolist(), [False, False, False, True]) self.assertEqual(isna_array(a4).tolist(), [False, False, True]) self.assertEqual(isna_array(a5).tolist(), [False, False, True]) self.assertEqual(isna_array(a6).tolist(), [False, False, True]) a1 = np.array([1, 2, 3, np.nan]) a2 = np.array([False, True, False, np.nan]) a3 = np.array(['b', 'c', 'd', np.nan], dtype=object) a4 = np.array([2.3, 3.2, np.nan], dtype=object) a5 = np.array(['test', 'test again', np.nan], dtype=object) a6 = np.array([2.3, 5.4, np.nan], dtype='float32') self.assertEqual(isna_array(a1).tolist(), [False, False, False, True]) self.assertEqual(isna_array(a2).tolist(), [False, False, False, True]) self.assertEqual(isna_array(a3).tolist(), [False, False, False, True]) self.assertEqual(isna_array(a4).tolist(), [False, False, True]) self.assertEqual(isna_array(a5).tolist(), [False, False, True]) self.assertEqual(isna_array(a6).tolist(), [False, False, True])
def _ufunc_logical_skipna(array: np.ndarray, ufunc: AnyCallable, skipna: bool, axis: int = 0, out: tp.Optional[np.ndarray] = None) -> np.ndarray: ''' Given a logical (and, or) ufunc that does not support skipna, implement skipna behavior. ''' if ufunc != np.all and ufunc != np.any: raise NotImplementedError( f'unsupported ufunc ({ufunc}); use np.all or np.any') if len(array) == 0: # TODO: handle if this is ndim == 2 and has no length # any() of an empty array is False return ufunc == np.all kind = array.dtype.kind #--------------------------------------------------------------------------- # types that cannot have NA if kind == 'b': return ufunc(array, axis=axis, out=out) if kind in DTYPE_INT_KIND: return ufunc(array, axis=axis, out=out) if kind in DTYPE_STR_KIND: # only string in object arrays can be converted to bool, where the empty string will be evaluated as False; here, manually check return ufunc(array != '', axis=axis, out=out) #--------------------------------------------------------------------------- # types that can have NA if kind in DTYPE_NAN_KIND: isna = isna_array(array) hasna = isna.any() # returns single value for 1d, 2d if hasna and skipna: fill_value = 0.0 if ufunc == np.any else 1.0 v = array.copy() v[isna] = fill_value return ufunc(v, axis=axis, out=out) elif hasna and not skipna: # if array.ndim == 1: # return np.nan raise TypeError( 'cannot propagate NaN without expanding to object array result' ) return ufunc(array, axis=axis, out=out) if kind in DTYPE_NAT_KIND: isna = isna_array(array) hasna = isna.any() # returns single value for 1d, 2d # all dates are truthy, special handling only to propagate NaNs if hasna and not skipna: # if array.ndim == 1: # return NAT raise TypeError( 'cannot propagate NaN without expanding to object array result' ) # to ignore NaN, simply fall back on all-truth behavior, below if kind == 'O': # all object types: convert to boolean aray then process isna = isna_array(array) hasna = isna.any() # returns single value for 1d, 2d if hasna and skipna: # supply True for np.all, False for np.any fill_value = False if ufunc == np.any else True v = array.copy() v = v.astype(bool) # nan will be converted to True v[isna] = fill_value elif hasna and not skipna: # if array.ndim == 1: # return np.nan raise TypeError( 'cannot propagate NaN without expanding to object array result' ) else: v = array.astype(bool) return ufunc(v, axis=axis, out=out) # all types other than strings or objects assume truthy if array.ndim == 1: return True return np.full(array.shape[0 if axis else 1], fill_value=True, dtype=bool)