Example #1
0
    def wrapper(self, other):

        if isinstance(other, str):
            try:
                other = self._scalar_from_string(other)
            except ValueError:
                # failed to parse as timedelta
                return invalid_comparison(self, other, op)

        if isinstance(other, self._recognized_scalars) or other is NaT:
            other = self._scalar_type(other)
            self._check_compatible_with(other)

            other_i8 = self._unbox_scalar(other)

            result = op(self.view("i8"), other_i8)
            if isna(other):
                result.fill(nat_result)

        elif not is_list_like(other):
            return invalid_comparison(self, other, op)

        elif len(other) != len(self):
            raise ValueError("Lengths must match")

        else:
            if isinstance(other, list):
                other = np.array(other)

            if not isinstance(other, (np.ndarray, cls)):
                return invalid_comparison(self, other, op)

            if is_object_dtype(other):
                with np.errstate(all="ignore"):
                    result = ops.comp_method_OBJECT_ARRAY(
                        op, self.astype(object), other
                    )
                o_mask = isna(other)

            elif not cls._is_recognized_dtype(other.dtype):
                # e.g. other is datetimearray
                return invalid_comparison(self, other, op)

            else:
                other = type(self)._from_sequence(other)

                self._check_compatible_with(other)

                result = op(self.view("i8"), other.view("i8"))
                o_mask = other._isnan

            if o_mask.any():
                result[o_mask] = nat_result

        if self._hasnans:
            result[self._isnan] = nat_result

        return result
Example #2
0
def comparison_op(left: Union[np.ndarray, ABCExtensionArray], right: Any,
                  op) -> Union[np.ndarray, ABCExtensionArray]:
    """
    Evaluate a comparison operation `=`, `!=`, `>=`, `>`, `<=`, or `<`.

    Parameters
    ----------
    left : np.ndarray or ExtensionArray
    right : object
        Cannot be a DataFrame, Series, or Index.
    op : {operator.eq, operator.ne, operator.gt, operator.ge, operator.lt, operator.le}

    Returns
    -------
    ndarrray or ExtensionArray
    """
    from pandas.core.ops import should_extension_dispatch, dispatch_to_extension_op

    # NB: We assume extract_array has already been called on left and right
    lvalues = left
    rvalues = right

    rvalues = lib.item_from_zerodim(rvalues)
    if isinstance(rvalues, list):
        # TODO: same for tuples?
        rvalues = np.asarray(rvalues)

    if isinstance(rvalues, (np.ndarray, ABCExtensionArray, ABCIndexClass)):
        # TODO: make this treatment consistent across ops and classes.
        #  We are not catching all listlikes here (e.g. frozenset, tuple)
        #  The ambiguous case is object-dtype.  See GH#27803
        if len(lvalues) != len(rvalues):
            raise ValueError("Lengths must match to compare")

    if should_extension_dispatch(lvalues, rvalues):
        res_values = dispatch_to_extension_op(op, lvalues, rvalues)

    elif is_scalar(rvalues) and isna(rvalues):
        # numpy does not like comparisons vs None
        if op is operator.ne:
            res_values = np.ones(len(lvalues), dtype=bool)
        else:
            res_values = np.zeros(len(lvalues), dtype=bool)

    elif is_object_dtype(lvalues.dtype):
        res_values = comp_method_OBJECT_ARRAY(op, lvalues, rvalues)

    else:
        op_name = "__{op}__".format(op=op.__name__)
        method = getattr(lvalues, op_name)
        with np.errstate(all="ignore"):
            res_values = method(rvalues)

        if res_values is NotImplemented:
            res_values = invalid_comparison(lvalues, rvalues, op)
        if is_scalar(res_values):
            raise TypeError("Could not compare {typ} type with Series".format(
                typ=type(rvalues)))

    return res_values
Example #3
0
def comparison_op(left: ArrayLike, right: Any, op) -> ArrayLike:
    """
    Evaluate a comparison operation `=`, `!=`, `>=`, `>`, `<=`, or `<`.

    Note: the caller is responsible for ensuring that numpy warnings are
    suppressed (with np.errstate(all="ignore")) if needed.

    Parameters
    ----------
    left : np.ndarray or ExtensionArray
    right : object
        Cannot be a DataFrame, Series, or Index.
    op : {operator.eq, operator.ne, operator.gt, operator.ge, operator.lt, operator.le}

    Returns
    -------
    ndarray or ExtensionArray
    """
    # NB: We assume extract_array has already been called on left and right
    lvalues = ensure_wrapped_if_datetimelike(left)
    rvalues = ensure_wrapped_if_datetimelike(right)

    rvalues = lib.item_from_zerodim(rvalues)
    if isinstance(rvalues, list):
        # TODO: same for tuples?
        rvalues = np.asarray(rvalues)

    if isinstance(rvalues, (np.ndarray, ABCExtensionArray)):
        # TODO: make this treatment consistent across ops and classes.
        #  We are not catching all listlikes here (e.g. frozenset, tuple)
        #  The ambiguous case is object-dtype.  See GH#27803
        if len(lvalues) != len(rvalues):
            raise ValueError("Lengths must match to compare", lvalues.shape,
                             rvalues.shape)

    if should_extension_dispatch(lvalues, rvalues) or (
        (isinstance(rvalues,
                    (Timedelta, BaseOffset, Timestamp)) or right is NaT)
            and not is_object_dtype(lvalues.dtype)):
        # Call the method on lvalues
        res_values = op(lvalues, rvalues)

    elif is_scalar(rvalues) and isna(rvalues):
        # numpy does not like comparisons vs None
        if op is operator.ne:
            res_values = np.ones(lvalues.shape, dtype=bool)
        else:
            res_values = np.zeros(lvalues.shape, dtype=bool)

    elif is_numeric_v_string_like(lvalues, rvalues):
        # GH#36377 going through the numexpr path would incorrectly raise
        return invalid_comparison(lvalues, rvalues, op)

    elif is_object_dtype(lvalues.dtype) or isinstance(rvalues, str):
        res_values = comp_method_OBJECT_ARRAY(op, lvalues, rvalues)

    else:
        res_values = _na_arithmetic_op(lvalues, rvalues, op, is_cmp=True)

    return res_values
Example #4
0
    def na_op(x, y):
        # TODO:
        # should have guarantess on what x, y can be type-wise
        # Extension Dtypes are not called here

        # Checking that cases that were once handled here are no longer
        # reachable.
        assert not (is_categorical_dtype(y) and not is_scalar(y))

        if is_object_dtype(x.dtype):
            result = _comp_method_OBJECT_ARRAY(op, x, y)

        elif is_datetimelike_v_numeric(x, y):
            return invalid_comparison(x, y, op)

        else:

            # we want to compare like types
            # we only want to convert to integer like if
            # we are not NotImplemented, otherwise
            # we would allow datetime64 (but viewed as i8) against
            # integer comparisons

            # we have a datetime/timedelta and may need to convert
            assert not needs_i8_conversion(x)
            mask = None
            if not is_scalar(y) and needs_i8_conversion(y):
                mask = isna(x) | isna(y)
                y = y.view("i8")
                x = x.view("i8")

            method = getattr(x, op_name, None)
            if method is not None:
                with np.errstate(all="ignore"):
                    result = method(y)
                if result is NotImplemented:
                    return invalid_comparison(x, y, op)
            else:
                result = op(x, y)

            if mask is not None and mask.any():
                result[mask] = masker

        return result
Example #5
0
    def na_op(x, y):
        # TODO:
        # should have guarantees on what x, y can be type-wise
        # Extension Dtypes are not called here

        if is_object_dtype(x.dtype):
            result = comp_method_OBJECT_ARRAY(op, x, y)

        elif is_datetimelike_v_numeric(x, y):
            return invalid_comparison(x, y, op)

        else:
            method = getattr(x, op_name)
            with np.errstate(all="ignore"):
                result = method(y)
            if result is NotImplemented:
                return invalid_comparison(x, y, op)

        return result
Example #6
0
    def wrapper(self, other):
        ordinal_op = getattr(self.asi8, opname)

        if is_list_like(other) and len(other) != len(self):
            raise ValueError("Lengths must match")

        if isinstance(other, str):
            try:
                other = self._scalar_from_string(other)
            except ValueError:
                # string that can't be parsed as Period
                return invalid_comparison(self, other, op)
        elif isinstance(other, int):
            # TODO: sure we want to allow this?  we dont for DTA/TDA
            #  2 tests rely on this
            other = Period(other, freq=self.freq)
            result = ordinal_op(other.ordinal)

        if isinstance(other, Period):
            self._check_compatible_with(other)

            result = ordinal_op(other.ordinal)
        elif isinstance(other, cls):
            self._check_compatible_with(other)

            result = ordinal_op(other.asi8)

            mask = self._isnan | other._isnan
            if mask.any():
                result[mask] = nat_result

            return result
        elif other is NaT:
            result = np.empty(len(self.asi8), dtype=bool)
            result.fill(nat_result)
        else:
            return invalid_comparison(self, other, op)

        if self._hasnans:
            result[self._isnan] = nat_result

        return result
Example #7
0
    def wrapper(self, other):
        other = lib.item_from_zerodim(other)
        if isinstance(other, (ABCDataFrame, ABCSeries, ABCIndexClass)):
            return NotImplemented

        if _is_convertible_to_td(other) or other is NaT:
            try:
                other = Timedelta(other)
            except ValueError:
                # failed to parse as timedelta
                return invalid_comparison(self, other, op)

            result = op(self.view("i8"), other.value)
            if isna(other):
                result.fill(nat_result)

        elif not is_list_like(other):
            return invalid_comparison(self, other, op)

        elif len(other) != len(self):
            raise ValueError("Lengths must match")

        else:
            try:
                other = type(self)._from_sequence(other)._data
            except (ValueError, TypeError):
                return invalid_comparison(self, other, op)

            result = op(self.view("i8"), other.view("i8"))
            result = com.values_from_object(result)

            o_mask = np.array(isna(other))
            if o_mask.any():
                result[o_mask] = nat_result

        if self._hasnans:
            result[self._isnan] = nat_result

        return result
Example #8
0
    def wrapper(self, other):

        if isinstance(other, str):
            try:
                other = self._scalar_from_string(other)
            except ValueError:
                # failed to parse as timedelta
                return invalid_comparison(self, other, op)

        if _is_convertible_to_td(other) or other is NaT:
            other = Timedelta(other)

            result = op(self.view("i8"), other.value)
            if isna(other):
                result.fill(nat_result)

        elif not is_list_like(other):
            return invalid_comparison(self, other, op)

        elif len(other) != len(self):
            raise ValueError("Lengths must match")

        else:
            try:
                other = type(self)._from_sequence(other)._data
            except (ValueError, TypeError):
                return invalid_comparison(self, other, op)

            result = op(self.view("i8"), other.view("i8"))
            result = com.values_from_object(result)

            o_mask = np.array(isna(other))
            if o_mask.any():
                result[o_mask] = nat_result

        if self._hasnans:
            result[self._isnan] = nat_result

        return result
Example #9
0
def _na_arithmetic_op(left: np.ndarray, right, op, is_cmp: bool = False):
    """
    Return the result of evaluating op on the passed in values.

    If native types are not compatible, try coercion to object dtype.

    Parameters
    ----------
    left : np.ndarray
    right : np.ndarray or scalar
        Excludes DataFrame, Series, Index, ExtensionArray.
    is_cmp : bool, default False
        If this a comparison operation.

    Returns
    -------
    array-like

    Raises
    ------
    TypeError : invalid operation
    """
    if isinstance(right, str):
        # can never use numexpr
        func = op
    else:
        func = partial(expressions.evaluate, op)

    try:
        result = func(left, right)
    except TypeError:
        if not is_cmp and (is_object_dtype(left.dtype)
                           or is_object_dtype(right)):
            # For object dtype, fallback to a masked operation (only operating
            #  on the non-missing values)
            # Don't do this for comparisons, as that will handle complex numbers
            #  incorrectly, see GH#32047
            result = _masked_arith_op(left, right, op)
        else:
            raise

    if is_cmp and (is_scalar(result) or result is NotImplemented):
        # numpy returned a scalar instead of operating element-wise
        # e.g. numeric array vs str
        # TODO: can remove this after dropping some future numpy version?
        return invalid_comparison(left, right, op)

    return missing.dispatch_fill_zeros(op, left, right, result)
Example #10
0
def na_arithmetic_op(left,
                     right,
                     op,
                     str_rep: Optional[str],
                     is_cmp: bool = False):
    """
    Return the result of evaluating op on the passed in values.

    If native types are not compatible, try coersion to object dtype.

    Parameters
    ----------
    left : np.ndarray
    right : np.ndarray or scalar
    str_rep : str or None
    is_cmp : bool, default False
        If this a comparison operation.

    Returns
    -------
    array-like

    Raises
    ------
    TypeError : invalid operation
    """
    import pandas.core.computation.expressions as expressions

    try:
        result = expressions.evaluate(op, str_rep, left, right)
    except TypeError:
        if is_cmp:
            # numexpr failed on comparison op, e.g. ndarray[float] > datetime
            #  In this case we do not fall back to the masked op, as that
            #  will handle complex numbers incorrectly, see GH#32047
            raise
        result = masked_arith_op(left, right, op)

    if is_cmp and (is_scalar(result) or result is NotImplemented):
        # numpy returned a scalar instead of operating element-wise
        # e.g. numeric array vs str
        return invalid_comparison(left, right, op)

    return missing.dispatch_fill_zeros(op, left, right, result)
Example #11
0
def _na_arithmetic_op(left, right, op, is_cmp: bool = False):
    """
    Return the result of evaluating op on the passed in values.

    If native types are not compatible, try coercion to object dtype.

    Parameters
    ----------
    left : np.ndarray
    right : np.ndarray or scalar
    is_cmp : bool, default False
        If this a comparison operation.

    Returns
    -------
    array-like

    Raises
    ------
    TypeError : invalid operation
    """
    try:
        result = expressions.evaluate(op, left, right)
    except TypeError:
        if is_object_dtype(left) or is_object_dtype(right) and not is_cmp:
            # For object dtype, fallback to a masked operation (only operating
            #  on the non-missing values)
            # Don't do this for comparisons, as that will handle complex numbers
            #  incorrectly, see GH#32047
            result = _masked_arith_op(left, right, op)
        else:
            raise

    if is_cmp and (is_scalar(result) or result is NotImplemented):
        # numpy returned a scalar instead of operating element-wise
        # e.g. numeric array vs str
        return invalid_comparison(left, right, op)

    return missing.dispatch_fill_zeros(op, left, right, result)
Example #12
0
    def wrapper(self, other):

        res_name = get_op_result_name(self, other)

        # TODO: shouldn't we be applying finalize whenever
        #  not isinstance(other, ABCSeries)?
        finalizer = (lambda x: x.__finalize__(self)
                     if isinstance(other, (np.ndarray, ABCIndexClass)) else x)

        if isinstance(other, ABCDataFrame):  # pragma: no cover
            # Defer to DataFrame implementation; fail early
            return NotImplemented

        if isinstance(other, ABCSeries) and not self._indexed_same(other):
            raise ValueError(
                "Can only compare identically-labeled Series objects")

        other = lib.item_from_zerodim(other)
        if isinstance(other, list):
            # TODO: same for tuples?
            other = np.asarray(other)

        if isinstance(other, (np.ndarray, ABCExtensionArray, ABCIndexClass)):
            # TODO: make this treatment consistent across ops and classes.
            #  We are not catching all listlikes here (e.g. frozenset, tuple)
            #  The ambiguous case is object-dtype.  See GH#27803
            if len(self) != len(other):
                raise ValueError("Lengths must match to compare")

        lvalues = extract_array(self, extract_numpy=True)
        rvalues = extract_array(other, extract_numpy=True)

        if should_extension_dispatch(lvalues, rvalues):
            res_values = dispatch_to_extension_op(op, lvalues, rvalues)

        elif is_scalar(rvalues) and isna(rvalues):
            # numpy does not like comparisons vs None
            if op is operator.ne:
                res_values = np.ones(len(lvalues), dtype=bool)
            else:
                res_values = np.zeros(len(lvalues), dtype=bool)

        elif is_object_dtype(lvalues.dtype):
            res_values = comp_method_OBJECT_ARRAY(op, lvalues, rvalues)

        else:
            op_name = "__{op}__".format(op=op.__name__)
            method = getattr(lvalues, op_name)
            with np.errstate(all="ignore"):
                res_values = method(rvalues)

            if res_values is NotImplemented:
                res_values = invalid_comparison(lvalues, rvalues, op)
            if is_scalar(res_values):
                raise TypeError(
                    "Could not compare {typ} type with Series".format(
                        typ=type(rvalues)))

        result = self._constructor(res_values, index=self.index)
        result = finalizer(result)

        # Set the result's name after finalizer is called because finalizer
        #  would set it back to self.name
        result.name = res_name
        return result
Example #13
0
    def wrapper(self, other):
        ordinal_op = getattr(self.asi8, opname)

        if is_list_like(other) and len(other) != len(self):
            raise ValueError("Lengths must match")

        if isinstance(other, str):
            try:
                other = self._scalar_from_string(other)
            except ValueError:
                # string that can't be parsed as Period
                return invalid_comparison(self, other, op)
        elif isinstance(other, int):
            # TODO: sure we want to allow this?  we dont for DTA/TDA
            #  2 tests rely on this
            other = Period(other, freq=self.freq)
            result = ordinal_op(other.ordinal)

        if isinstance(other, Period):
            self._check_compatible_with(other)

            result = ordinal_op(other.ordinal)

        elif other is NaT:
            result = np.empty(len(self.asi8), dtype=bool)
            result.fill(nat_result)

        elif not is_list_like(other):
            return invalid_comparison(self, other, op)

        else:
            if isinstance(other, list):
                # TODO: could use pd.Index to do inference?
                other = np.array(other)

            if not isinstance(other, (np.ndarray, cls)):
                return invalid_comparison(self, other, op)

            if is_object_dtype(other):
                with np.errstate(all="ignore"):
                    result = ops.comp_method_OBJECT_ARRAY(
                        op, self.astype(object), other
                    )
                o_mask = isna(other)

            elif not is_period_dtype(other):
                # e.g. is_timedelta64_dtype(other)
                return invalid_comparison(self, other, op)

            else:
                assert isinstance(other, cls), type(other)

                self._check_compatible_with(other)

                result = ordinal_op(other.asi8)
                o_mask = other._isnan

            if o_mask.any():
                result[o_mask] = nat_result

        if self._hasnans:
            result[self._isnan] = nat_result

        return result