-
-
Notifications
You must be signed in to change notification settings - Fork 419
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
Much faster FormatStringEncoding #5315
Conversation
Thanks for the contribution and detailed write up! And sorry about the performance problems! I should be able to take a look either today or tomorrow. |
for more information, see https://pre-commit.ci
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.
Fantastic speedup here! Approving with just a minor comment about a variable name.
One thing to watch out for is that when Layer.features
is present, it will not necessarily be a pandas DataFrame in the future. Currently we always coerce it to be exactly a pandas DataFrame. But in the future we may want to support other dataframe libraries (dask dataframe, cudf) using a Protocol
.
I've currently done a half-baked job of indicating that with the docstring and typing. But ideally, we can define exactly what attributes and methods we expect to find in a dataframe Protocol
.
Previously we needed the dataframe to define iloc
and support len
, but now we need itertuples
. I checked dask's and cudf's dataframe APIs and they both provide itertuples
, so there's no problem here.
Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
Also, if you have the profile data or even just a screenshot of snakeviz for the optimized version, that would be ideal. I'm curious what takes up the rest of that 5s. |
Thanks for clarifying. The optimization here should just go in as is. There was an effort to replace |
Also, FYI, I ran the relevant ASV benchmark for the format string case and we also see a big speedup there. At least 10x on my machine, though we only go up to 65536 (2^16) elements and timings are not linear.
|
Sweet! |
I'll merge this after 48 hours unless anyone objects. |
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.
Awesome! Small suggestion, but otherwise approving.
feature_names = features.columns.to_list() | ||
values = [ | ||
self.format.format(**_get_feature_row(features, i)) | ||
for i in range(len(features)) | ||
self.format.format(**dict(zip(feature_names, row))) | ||
for row in features.itertuples(index=False, name=None) | ||
] |
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 we should add a comment explaining the code here. Before it had at least the name of the function explaining something, but now it's rather cryptic.
The functionality is very similar to This PR:
with
|
@JoOkuma, and |
Hi! I came across this PR due to the cuDF mention. Performance gains look fantastic with this change! I wanted to add some context about cuDF and
cuDF doesn't support this kind of row based iteration via I also wanted to mention that cuDF is adding support for import cudf
df = cudf.datasets.randomdata(nrows=3)
pdf = df.to_pandas()
print(pdf.to_dict(orient="records"))
# from the function in the PR
feature_names = pdf.columns.to_list()
print([dict(zip(feature_names, row)) for row in pdf.itertuples(index=False, name=None)])
[{'id': 1023, 'x': -0.3437607026238143, 'y': 0.4419788553645101}, {'id': 1012, 'x': 0.2760312523846038, 'y': 0.8273451449034162}, {'id': 1013, 'x': -0.35755297004454434, 'y': -0.13542889747873632}]
[{'id': 1023, 'x': -0.3437607026238143, 'y': 0.4419788553645101}, {'id': 1012, 'x': 0.2760312523846038, 'y': 0.8273451449034162}, {'id': 1013, 'x': -0.35755297004454434, 'y': -0.13542889747873632}] Happy to chat further if helpful. |
Thanks for the very useful information! napari doesn't yet support different types of tables/dataframes, but we can at least imagine that it could in the not too distant future. Will definitely reference this information then and may pick your brains more. I imagine support would look something like defining a core functional protocol and maybe do some specialized implementation for specific types (e.g. here doing something special if it's a cuDF dataframe). |
FYI RAPIDS viz works closely with HoloViews and have done a similar cuDF implementations with success, for example. |
Merging after 24 but before 48 hours since we have multiple approvals here. |
* Much faster iteration over a DataFrame's rows * Remove unused import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update napari/layers/utils/string_encoding.py Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
* Much faster iteration over a DataFrame's rows * Remove unused import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update napari/layers/utils/string_encoding.py Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
* Much faster iteration over a DataFrame's rows * Remove unused import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update napari/layers/utils/string_encoding.py Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
* Much faster iteration over a DataFrame's rows * Remove unused import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update napari/layers/utils/string_encoding.py Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
* Much faster iteration over a DataFrame's rows * Remove unused import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update napari/layers/utils/string_encoding.py Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
* Much faster iteration over a DataFrame's rows * Remove unused import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update napari/layers/utils/string_encoding.py Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
* Much faster iteration over a DataFrame's rows * Remove unused import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update napari/layers/utils/string_encoding.py Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
Description
Loading a large pose estimation data file with a simple "{id}–{label}" format (using the napari-deeplabcut plugin; resulting feature table with >6M rows and four columns) lasted 3+ min.
While I first thought it had something to do with rendering the keypoints, a bit of profiling (see pink lines below) indicated that 92% of the time it took to load the annotations (177 s!) was spent in the TextManager, and specifically in
_get_feature_row
.I substituted df.iloc with df.itertuples, and loading now takes only roughly 5 s (~35x speedup).
Type of change
References
How has this been tested?
as there are small differences between the two Qt bindings.
Final checklist:
trans.
to make them localizable.For more information see our translations guide.