Skip to content

[python-package] Allow to pass Arrow array & Polars series as position#7260

Open
maxzw wants to merge 6 commits into
lightgbm-org:mainfrom
maxzw:feat/dataset-construction-position-as-arrow
Open

[python-package] Allow to pass Arrow array & Polars series as position#7260
maxzw wants to merge 6 commits into
lightgbm-org:mainfrom
maxzw:feat/dataset-construction-position-as-arrow

Conversation

@maxzw

@maxzw maxzw commented May 5, 2026

Copy link
Copy Markdown
Contributor

Summary

All other metadata fields (label, weight, group, init_score) accept PyArrow ChunkedArray types as input, but position only accepts numpy 1-D array or pandas 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

  • Followed existing logic from other metadata fields to add PyArrow ChunkedArray and Polars support to the position field
  • Updated documentation
  • Added unit tests

@maxzw maxzw changed the title [python-package] Add PyArrow Array/ChunkedArray support for position field in Dataset [python-package] Allow to pass Arrow array as position May 6, 2026
@jameslamb

Copy link
Copy Markdown
Member

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.

@maxzw maxzw force-pushed the feat/dataset-construction-position-as-arrow branch 2 times, most recently from 4fdf64f to 365f7dd Compare May 6, 2026 19:35

@jameslamb jameslamb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) =

(build link)

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.py

Happy to review more thoroughly once the tests are passing. @ me if you need help.

@maxzw

maxzw commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

There are some test failures:

Can you please investigate those?

Oops 😄 They should be passing now!

@maxzw maxzw requested a review from jameslamb May 7, 2026 07:07
@maxzw maxzw force-pushed the feat/dataset-construction-position-as-arrow branch from 8a98de1 to 450f71a Compare June 4, 2026 13:22
@jameslamb

Copy link
Copy Markdown
Member

@maxzw could you please update this to account for the changes from #7275 , and add polars inputs for position?

I'd be happy to review after that, I think we can get this into the next release.

@maxzw maxzw force-pushed the feat/dataset-construction-position-as-arrow branch 2 times, most recently from 839db0d to 4f62abb Compare June 23, 2026 10:13
@maxzw maxzw changed the title [python-package] Allow to pass Arrow array as position [python-package] Allow to pass Arrow/Polars array as position Jun 23, 2026
@maxzw

maxzw commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

@maxzw could you please update this to account for the changes from #7275 , and add polars inputs for position?

I'd be happy to review after that, I think we can get this into the next release.

Should be up-to-date now!

@borchero borchero changed the title [python-package] Allow to pass Arrow/Polars array as position [python-package] Allow to pass Arrow array & Polars series as position Jun 23, 2026

@jameslamb jameslamb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation looks great, thank you! Looks to me like it's closely following the patterns @borchero set up for Arrow data in previous PRs.

I just left some small suggestions about type hints and tests.

Comment thread python-package/lightgbm/basic.py Outdated
Comment on lines +84 to +85
_LGBM_PositionType = Union[
List[int],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, list inputs for array-like data are painful to support. I'd prefer that lightgbm not add any more of them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the support for list inputs 👍🏻

Comment thread python-package/lightgbm/basic.py Outdated
dataset.construct()

expected = np.array([0, 1, 2, 3, 4], dtype=np.int32)
np_assert_array_equal(expected, dataset.get_field("position"), strict=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a unit test that addresses these cases! 👍🏻

@maxzw maxzw requested a review from jameslamb June 24, 2026 08:06
@maxzw maxzw force-pushed the feat/dataset-construction-position-as-arrow branch from 597d98b to a0c01e5 Compare June 24, 2026 08:07
@maxzw maxzw force-pushed the feat/dataset-construction-position-as-arrow branch from a0c01e5 to 8909317 Compare June 24, 2026 11:44

@jameslamb jameslamb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good to me, thanks!

Merging in master to get one more CI run with the changes from #7344 .

@borchero could you review too when you have time?

dataset.construct()

# positions are remapped on the C++ side to dense indices in first-seen order:
# 15 -> 0, 8 -> 1, 27 -> 2

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this description of how this works, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants