-
-
Notifications
You must be signed in to change notification settings - Fork 19.2k
BUG: Series.combine() fails with ExtensionArray inside of Series #21183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
7469ca9
bbb6640
339b23a
61a09e7
d862e83
4c925fc
27480ac
f96372e
677fe18
9fceee7
1010cb5
aceea9f
79506ac
0e4720b
2a21117
e08f832
d3ed2c7
4ca28b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2185,18 +2185,32 @@ def _binop(self, other, func, level=None, fill_value=None): | |
|
|
||
| this_vals, other_vals = ops.fill_binop(this.values, other.values, | ||
| fill_value) | ||
|
|
||
| with np.errstate(all='ignore'): | ||
| result = func(this_vals, other_vals) | ||
| name = ops.get_op_result_name(self, other) | ||
|
|
||
| if is_extension_array_dtype(this) or is_extension_array_dtype(other): | ||
| try: | ||
| result = func(this_vals, other_vals) | ||
| except TypeError: | ||
| result = NotImplemented | ||
|
|
||
| if result is NotImplemented: | ||
| result = [func(a, b) for a, b in zip(this_vals, other_vals)] | ||
| if is_extension_array_dtype(this): | ||
| excons = type(this_vals)._from_sequence | ||
| else: | ||
| excons = type(other_vals)._from_sequence | ||
| result = excons(result) | ||
| else: | ||
| with np.errstate(all='ignore'): | ||
| result = func(this_vals, other_vals) | ||
| result = self._constructor(result, index=new_index, name=name) | ||
| result = result.__finalize__(self) | ||
| if name is None: | ||
| # When name is None, __finalize__ overwrites current name | ||
| result.name = None | ||
| return result | ||
|
|
||
| def combine(self, other, func, fill_value=np.nan): | ||
| def combine(self, other, func, fill_value=None): | ||
| """ | ||
| Perform elementwise binary operation on two Series using given function | ||
| with optional fill value when an index is missing from one Series or | ||
|
|
@@ -2208,6 +2222,9 @@ def combine(self, other, func, fill_value=np.nan): | |
| func : function | ||
| Function that takes two scalars as inputs and return a scalar | ||
| fill_value : scalar value | ||
| The default specifies to use np.nan unless self is | ||
| backed by ExtensionArray, in which case the ExtensionArray | ||
| na_value is used. | ||
|
|
||
| Returns | ||
| ------- | ||
|
|
@@ -2227,20 +2244,33 @@ def combine(self, other, func, fill_value=np.nan): | |
| Series.combine_first : Combine Series values, choosing the calling | ||
| Series's values first | ||
| """ | ||
| self_is_ext = is_extension_array_dtype(self) | ||
| if fill_value is None: | ||
| if self_is_ext: | ||
|
||
| fill_value = self.dtype.na_value | ||
| else: | ||
| fill_value = np.nan | ||
| if isinstance(other, Series): | ||
| new_index = self.index.union(other.index) | ||
| new_name = ops.get_op_result_name(self, other) | ||
| new_values = np.empty(len(new_index), dtype=self.dtype) | ||
| for i, idx in enumerate(new_index): | ||
| new_values = [] | ||
| for idx in new_index: | ||
| lv = self.get(idx, fill_value) | ||
| rv = other.get(idx, fill_value) | ||
| with np.errstate(all='ignore'): | ||
| new_values[i] = func(lv, rv) | ||
| new_values.append(func(lv, rv)) | ||
| else: | ||
| new_index = self.index | ||
| with np.errstate(all='ignore'): | ||
| new_values = func(self._values, other) | ||
| if not self_is_ext: | ||
| with np.errstate(all='ignore'): | ||
| new_values = func(self._values, other) | ||
|
||
| else: | ||
| new_values = [func(lv, other) for lv in self._values] | ||
| new_name = self.name | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you put a comment on what is going on here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| if (self_is_ext and self.values.is_sequence_of_dtype(new_values)): | ||
| new_values = self._values._from_sequence(new_values) | ||
|
||
|
|
||
| return self._constructor(new_values, index=new_index, name=new_name) | ||
|
|
||
| def combine_first(self, other): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,6 +138,17 @@ def test_value_counts(self, all_data, dropna): | |
|
|
||
| tm.assert_series_equal(result, expected) | ||
|
|
||
| def test_combine(self): | ||
|
||
| # GH 20825 | ||
| orig_data1 = make_data() | ||
| orig_data2 = make_data() | ||
| s1 = pd.Series(orig_data1) | ||
| s2 = pd.Series(orig_data2) | ||
| result = s1.combine(s2, lambda x1, x2: x1 <= x2) | ||
| expected = pd.Series([a <= b for (a, b) in | ||
| zip(orig_data1, orig_data2)]) | ||
| tm.assert_series_equal(result, expected) | ||
|
|
||
|
|
||
| class TestCasting(BaseDecimal, base.BaseCastingTests): | ||
| pass | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to 0.24
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved it to 0.24