-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
PERF: Implement round on the block level #51498
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
Conversation
pandas/core/internals/blocks.py
Outdated
Whether Copy on Write is enabled right now | ||
""" | ||
if not self.is_numeric or self.is_bool: | ||
return self.copy(deep=None if using_cow else True) |
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.
possibly raise?
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 believe that DataFrame.round() never raises even when there are no numeric columns, but Series.round() does.
Do you want me to add a comment that this doesn't raise?
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.
if this is just a perf PR than this should maintain behavior, but might merit an issue or TODO comment. looks like some of our EAs have round methods that are not documented as part of the interface.
pandas/core/internals/blocks.py
Outdated
Whether Copy on Write is enabled right now | ||
""" | ||
if not self.is_numeric or self.is_bool: | ||
return self.copy(deep=using_cow) |
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.
not using_cow I think?
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.
Thanks for the catch.
pandas/core/internals/blocks.py
Outdated
# error: Item "ExtensionArray" of "Union[ndarray[Any, Any], ExtensionArray]" | ||
# has no attribute "round" | ||
return new_block_2d( | ||
self.values.round(decimals), # type: ignore[union-attr] |
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 think you want to use self.make_block_same_class
here? If class could change then self.make_block
. Don't have to set placement there
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.
This is dangerous, I don't think that round guarantees a copy, e.g.
arr = np.array([1, 2])
arr2 = arr.round(2)
arr2[0] = 100
You can check this with
arr is arr2
(also please add a test for this case)
Edit: You can just pass the refs of self in this case like we do in other places
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.
Thanks for the tip.
I found the source here https://github.com/numpy/numpy/blob/486878b37fc7439a3b2b87747f50db9b62fea8eb/numpy/core/src/multiarray/calculation.c#L625-L636
and it looks like this is only triggered for integer case with decimals >= 0.
BTW, it also looks like round is an operation that can be done inplace
by using the out
parameter in numpy.
Maybe I should open a PR for that as a follow-up?
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.
Would have to check if it's actually faster, but if yes then should utilise it in CoW cases
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.
Follow up sounds good to me
pandas/core/internals/blocks.py
Outdated
# returns the same array, so need to set refs | ||
# https://github.com/numpy/numpy/blob/486878b37fc7439a3b2b87747f50db9b62fea8eb/numpy/core/src/multiarray/calculation.c#L625-L636 | ||
refs = None | ||
if not self.is_extension and self.dtype.kind == "i" and decimals >= 0: |
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'd prefer checking:
result = self.values.round(..)
if self.values is result:
refs = self.refs
This would not depend on an implementation detail of numpy
|
||
if using_copy_on_write: | ||
assert np.shares_memory(get_array(df2, "b"), get_array(df, "b")) | ||
assert np.shares_memory(get_array(df2, "a"), get_array(df, "a")) | ||
if decimals >= 0: | ||
assert np.shares_memory(get_array(df2, "a"), get_array(df, "a")) |
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.
Can you do a else: assert not and add a todo that we can optimise with out?
if using_copy_on_write: | ||
assert not np.shares_memory(get_array(df2, "b"), get_array(df, "b")) | ||
if decimals >= 0: |
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.
if think this if is not necessary? Both cases shouldn't share
pandas/core/internals/blocks.py
Outdated
# https://github.com/numpy/numpy/blob/486878b37fc7439a3b2b87747f50db9b62fea8eb/numpy/core/src/multiarray/calculation.c#L625-L636 | ||
values = values.copy() | ||
return self.make_block_same_class( | ||
values, |
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.
This could fit into one line?
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.
small comment, otherwise lgtm
Owee, I'm MrMeeseeks, Look at me. There seem to be a conflict, please backport manually. Here are approximate instructions:
And apply the correct labels and milestones. Congratulations — you did some good work! Hopefully your backport PR will be tested by the continuous integration and merged soon! Remember to remove the If these instructions are inaccurate, feel free to suggest an improvement. |
Belated: LGTM |
doc/source/whatsnew/vX.X.X.rst
file if fixing a bug or adding a new feature.Benchmarks are showing same speedup as OP.