def _flex_method_SERIES(cls, op, special): name = _get_op_name(op, special) doc = _make_flex_doc(name, "series") @Appender(doc) def flex_wrapper(self, other, level=None, fill_value=None, axis=0): # validate axis if axis is not None: self._get_axis_number(axis) if isinstance(other, ABCSeries): return self._binop(other, op, level=level, fill_value=fill_value) elif isinstance(other, (np.ndarray, list, tuple)): if len(other) != len(self): raise ValueError("Lengths must be equal") other = self._constructor(other, self.index) return self._binop(other, op, level=level, fill_value=fill_value) else: if fill_value is not None: self = self.fillna(fill_value) return op(self, other) flex_wrapper.__name__ = name return flex_wrapper
def _arith_method_FRAME(cls, op, special): str_rep = _get_opstr(op) op_name = _get_op_name(op, special) default_axis = _get_frame_op_default_axis(op_name) na_op = define_na_arithmetic_op(op, str_rep) is_logical = str_rep in ["&", "|", "^"] if op_name in _op_descriptions: # i.e. include "add" but not "__add__" doc = _make_flex_doc(op_name, "dataframe") else: doc = _arith_doc_FRAME % op_name @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): other = _align_method_FRAME(self, other, axis) if isinstance(other, ABCDataFrame): # Another DataFrame pass_op = op if should_series_dispatch(self, other, op) else na_op pass_op = pass_op if not is_logical else op left, right = self.align(other, join="outer", level=level, copy=False) new_data = left._combine_frame(right, pass_op, fill_value) return left._construct_result(new_data) elif isinstance(other, ABCSeries): # For these values of `axis`, we end up dispatching to Series op, # so do not want the masked op. pass_op = op if axis in [0, "columns", None] else na_op pass_op = pass_op if not is_logical else op if fill_value is not None: raise NotImplementedError( f"fill_value {fill_value} not supported.") axis = self._get_axis_number(axis) if axis is not None else 1 self, other = self.align(other, join="outer", axis=axis, level=level, copy=False) return _combine_series_frame(self, other, pass_op, axis=axis) else: # in this case we always have `np.ndim(other) == 0` if fill_value is not None: self = self.fillna(fill_value) new_data = dispatch_to_series(self, other, op, str_rep) return self._construct_result(new_data) f.__name__ = op_name return f
def _arith_method_FRAME(cls, op, special): op_name = _get_op_name(op, special) default_axis = _get_frame_op_default_axis(op_name) na_op = define_na_arithmetic_op(op) is_logical = op.__name__.strip("_").lstrip("_") in ["and", "or", "xor"] if op_name in _op_descriptions: # i.e. include "add" but not "__add__" doc = _make_flex_doc(op_name, "dataframe") else: doc = _arith_doc_FRAME % op_name @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): if _should_reindex_frame_op(self, other, op, axis, default_axis, fill_value, level): return _frame_arith_method_with_reindex(self, other, op) self, other = _align_method_FRAME(self, other, axis, flex=True, level=level) if isinstance(other, ABCDataFrame): # Another DataFrame pass_op = op if should_series_dispatch(self, other, op) else na_op pass_op = pass_op if not is_logical else op new_data = self._combine_frame(other, pass_op, fill_value) elif isinstance(other, ABCSeries): # For these values of `axis`, we end up dispatching to Series op, # so do not want the masked op. pass_op = op if axis in [0, "columns", None] else na_op pass_op = pass_op if not is_logical else op if fill_value is not None: raise NotImplementedError( f"fill_value {fill_value} not supported.") axis = self._get_axis_number(axis) if axis is not None else 1 new_data = _combine_series_frame(self, other, pass_op, axis=axis) else: # in this case we always have `np.ndim(other) == 0` if fill_value is not None: self = self.fillna(fill_value) new_data = dispatch_to_series(self, other, op) return self._construct_result(new_data) f.__name__ = op_name return f
def _arith_method_FRAME(cls: Type["DataFrame"], op, special: bool): # This is the only function where `special` can be either True or False op_name = _get_op_name(op, special) default_axis = _get_frame_op_default_axis(op_name) na_op = get_array_op(op) is_logical = op.__name__.strip("_").lstrip("_") in ["and", "or", "xor"] if op_name in _op_descriptions: # i.e. include "add" but not "__add__" doc = _make_flex_doc(op_name, "dataframe") else: doc = _arith_doc_FRAME % op_name @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): if _should_reindex_frame_op( self, other, op, axis, default_axis, fill_value, level ): return _frame_arith_method_with_reindex(self, other, op) # TODO: why are we passing flex=True instead of flex=not special? # 15 tests fail if we pass flex=not special instead self, other = _align_method_FRAME(self, other, axis, flex=True, level=level) if isinstance(other, ABCDataFrame): # Another DataFrame new_data = self._combine_frame(other, na_op, fill_value) elif isinstance(other, ABCSeries): # For these values of `axis`, we end up dispatching to Series op, # so do not want the masked op. # TODO: the above comment is no longer accurate since we now # operate blockwise if other._values is an ndarray pass_op = op if axis in [0, "columns", None] else na_op pass_op = pass_op if not is_logical else op if fill_value is not None: raise NotImplementedError(f"fill_value {fill_value} not supported.") axis = self._get_axis_number(axis) if axis is not None else 1 new_data = _combine_series_frame(self, other, pass_op, axis=axis) else: # in this case we always have `np.ndim(other) == 0` if fill_value is not None: self = self.fillna(fill_value) new_data = dispatch_to_series(self, other, op) return self._construct_result(new_data) f.__name__ = op_name return f
def _arith_method_FRAME(cls: Type["DataFrame"], op, special: bool): # This is the only function where `special` can be either True or False op_name = _get_op_name(op, special) default_axis = _get_frame_op_default_axis(op_name) na_op = get_array_op(op) if op_name in _op_descriptions: # i.e. include "add" but not "__add__" doc = _make_flex_doc(op_name, "dataframe") else: doc = _arith_doc_FRAME % op_name @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): if _should_reindex_frame_op(self, other, op, axis, default_axis, fill_value, level): return _frame_arith_method_with_reindex(self, other, op) if isinstance(other, ABCSeries) and fill_value is not None: # TODO: We could allow this in cases where we end up going # through the DataFrame path raise NotImplementedError( f"fill_value {fill_value} not supported.") axis = self._get_axis_number(axis) if axis is not None else 1 # TODO: why are we passing flex=True instead of flex=not special? # 15 tests fail if we pass flex=not special instead self, other = align_method_FRAME(self, other, axis, flex=True, level=level) if isinstance(other, ABCDataFrame): # Another DataFrame new_data = self._combine_frame(other, na_op, fill_value) elif isinstance(other, ABCSeries): new_data = dispatch_to_series(self, other, op, axis=axis) else: # in this case we always have `np.ndim(other) == 0` if fill_value is not None: self = self.fillna(fill_value) new_data = dispatch_to_series(self, other, op) return self._construct_result(new_data) f.__name__ = op_name return f
def _arith_method_FRAME(cls, op, special): str_rep = _get_opstr(op, cls) op_name = _get_op_name(op, special) eval_kwargs = _gen_eval_kwargs(op_name) default_axis = _get_frame_op_default_axis(op_name) def na_op(x, y): import pandas.core.computation.expressions as expressions try: result = expressions.evaluate(op, str_rep, x, y, **eval_kwargs) except TypeError: result = masked_arith_op(x, y, op) return missing.dispatch_fill_zeros(op, x, y, result) if op_name in _op_descriptions: # i.e. include "add" but not "__add__" doc = _make_flex_doc(op_name, "dataframe") else: doc = _arith_doc_FRAME % op_name @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): other = _align_method_FRAME(self, other, axis) if isinstance(other, ABCDataFrame): # Another DataFrame pass_op = op if should_series_dispatch(self, other, op) else na_op return self._combine_frame(other, pass_op, fill_value, level) elif isinstance(other, ABCSeries): # For these values of `axis`, we end up dispatching to Series op, # so do not want the masked op. pass_op = op if axis in [0, "columns", None] else na_op return _combine_series_frame(self, other, pass_op, fill_value=fill_value, axis=axis, level=level) else: if fill_value is not None: self = self.fillna(fill_value) assert np.ndim(other) == 0 return self._combine_const(other, op) f.__name__ = op_name return f
def _arith_method_FRAME(cls, op, special): str_rep = _get_opstr(op) op_name = _get_op_name(op, special) eval_kwargs = _gen_eval_kwargs(op_name) default_axis = _get_frame_op_default_axis(op_name) na_op = define_na_arithmetic_op(op, str_rep, eval_kwargs) is_logical = str_rep in ["&", "|", "^"] if op_name in _op_descriptions: # i.e. include "add" but not "__add__" doc = _make_flex_doc(op_name, "dataframe") else: doc = _arith_doc_FRAME % op_name @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): other = _align_method_FRAME(self, other, axis) if isinstance(other, ABCDataFrame): # Another DataFrame pass_op = op if should_series_dispatch(self, other, op) else na_op pass_op = pass_op if not is_logical else op return self._combine_frame(other, pass_op, fill_value, level) elif isinstance(other, ABCSeries): # For these values of `axis`, we end up dispatching to Series op, # so do not want the masked op. pass_op = op if axis in [0, "columns", None] else na_op pass_op = pass_op if not is_logical else op return _combine_series_frame(self, other, pass_op, fill_value=fill_value, axis=axis, level=level) else: # in this case we always have `np.ndim(other) == 0` if fill_value is not None: self = self.fillna(fill_value) new_data = dispatch_to_series(self, other, op) return self._construct_result(new_data) f.__name__ = op_name return f
def flex_arith_method_FRAME(op): op_name = op.__name__.strip("_") default_axis = "columns" na_op = get_array_op(op) doc = _make_flex_doc(op_name, "dataframe") @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): if should_reindex_frame_op(self, other, op, axis, default_axis, fill_value, level): return frame_arith_method_with_reindex(self, other, op) if isinstance(other, ABCSeries) and fill_value is not None: # TODO: We could allow this in cases where we end up going # through the DataFrame path raise NotImplementedError( f"fill_value {fill_value} not supported.") axis = self._get_axis_number(axis) if axis is not None else 1 self, other = align_method_FRAME(self, other, axis, flex=True, level=level) if isinstance(other, ABCDataFrame): # Another DataFrame new_data = self._combine_frame(other, na_op, fill_value) elif isinstance(other, ABCSeries): new_data = self._dispatch_frame_op(other, op, axis=axis) else: # in this case we always have `np.ndim(other) == 0` if fill_value is not None: self = self.fillna(fill_value) new_data = self._dispatch_frame_op(other, op) return self._construct_result(new_data) f.__name__ = op_name return f