[python-package] Allow to pass Arrow array & Polars series as position#7260
[python-package] Allow to pass Arrow array & Polars series as position#7260maxzw wants to merge 6 commits into
Conversation
position field in Dataset|
Thanks for working on this! Very supportive of this change. I haven't reviewed yet, just a quick note... CI will be blocked until someone can review this PR to fix a couple issues: #7249. Sorry for the delay. |
4fdf64f to
365f7dd
Compare
jameslamb
left a comment
There was a problem hiding this comment.
Thanks for this, at a glance it looks pretty good to me and I support this.
There are some test failures:
FAILED tests/python_package_test/test_basic.py::test_dataset_construction_overwrites_user_provided_metadata_fields - AssertionError:
Arrays are not equal
(dtypes int32, float32 mismatch)
ACTUAL: array([0, 1], dtype=int32)
DESIRED: array([0., 1.], dtype=float32)
FAILED tests/python_package_test/test_engine.py::test_ranking_with_position_information_with_dataset_constructor - AssertionError:
Arrays are not equal
(dtypes int32, int64 mismatch)
ACTUAL: array([0, 1, 2, ..., 1, 3, 9], shape=(3005,), dtype=int32)
DESIRED: array([0, 5, 9, ..., 5, 4, 8], shape=(3005,))
= 2 failed, 1486 passed, 15 skipped, 8 xfailed, 52 xpassed, 3395 warnings in 542.38s (0:09:02) =
Can you please investigate those?
It'll be faster to run these tests locally yourself, which you can do like this:
# build lib_lightgbm (only needs to be re-run for C++ changes)
rm -rf ./build
cmake -B build -S .
cmake --build build --target _lightgbm -j4
# build and install lightgbm Python package
sh build-python.sh --precompile install
# run tests
pytest \
tests/python_package_test/test_basic.py \
tests/python_package_test/test_engine.pyHappy to review more thoroughly once the tests are passing. @ me if you need help.
Oops 😄 They should be passing now! |
8a98de1 to
450f71a
Compare
839db0d to
4f62abb
Compare
| _LGBM_PositionType = Union[ | ||
| List[int], |
There was a problem hiding this comment.
| _LGBM_PositionType = Union[ | |
| List[int], | |
| # 'position' intentionally does not support 'list' inputs | |
| # ref: https://github.com/lightgbm-org/LightGBM/pull/5929#discussion_r1262646998 | |
| _LGBM_PositionType = Union[ |
It's an intentional choice to not support list inputs for position: #5929 (comment)
Please revert this and anything else in this PR that allows for position to be a list.
And let's add a code comment to prevent anyone from trying to introduce this again in the future. I could imagine others seeing this as an inconsistency to be "fixed" and I don't want to rely on maintainers remembering that conversation thread.
There was a problem hiding this comment.
In general, list inputs for array-like data are painful to support. I'd prefer that lightgbm not add any more of them.
There was a problem hiding this comment.
I've removed the support for list inputs 👍🏻
| dataset.construct() | ||
|
|
||
| expected = np.array([0, 1, 2, 3, 4], dtype=np.int32) | ||
| np_assert_array_equal(expected, dataset.get_field("position"), strict=True) |
There was a problem hiding this comment.
This test_dataset_construct_position() test looks great.
Could you please add one more test here ensuring that cases where position has duplicate or out-of-order values are handled correctly? I don't see a bug in your changes, but could imagine cases where some logic bug would produce the values 0, 1, 2, 3, 4 for a 5-element position even when that encoding is not correct.
A test case like position=pa.chunked_array([15, 15, 15, 27, 8, 9, 15]) or something would be a strong test of correctness. It'd also be a way to cover that difference between get_field("position") and .position that you called out in a comment in the set_position() body.
There was a problem hiding this comment.
Added a unit test that addresses these cases! 👍🏻
597d98b to
a0c01e5
Compare
a0c01e5 to
8909317
Compare
| dataset.construct() | ||
|
|
||
| # positions are remapped on the C++ side to dense indices in first-seen order: | ||
| # 15 -> 0, 8 -> 1, 27 -> 2 |
There was a problem hiding this comment.
Love this description of how this works, thank you.
Summary
All other metadata fields (
label,weight,group,init_score) accept PyArrow ChunkedArray types as input, butpositiononly acceptsnumpy 1-D arrayorpandas Series. This is inconsistent and forces users working with Arrow-native or Polars data to manually convert to NumPy before passing position data. This contributes to #6204.Reference PRs (part of #6022)
Changes
positionfield