Skip to content

[Data] Avoid per-column Series materialization in tensor-column casting - #64038

Merged
goutamvenkat-anyscale merged 7 commits into
ray-project:masterfrom
ayushk7102:optimize_to_tensor_array
Jun 17, 2026
Merged

[Data] Avoid per-column Series materialization in tensor-column casting#64038
goutamvenkat-anyscale merged 7 commits into
ray-project:masterfrom
ayushk7102:optimize_to_tensor_array

Conversation

@ayushk7102

Copy link
Copy Markdown
Contributor

Description

When we are converting tensor columns of a block/batch to ndarrays and vice versa, our current implementation scans over the columns using df.items() and checks the dtype of each column. This is wasteful as we pay the cost of materializing the column as a pd.Series just to check its dtype. Instead, what we can do is iterate over the df.dtypes.items() which only yields numpy dtype objects.
_cast_tensor_columns_to_ndarrays and _cast_ndarray_columns_to_tensor_extension in data_batch_conversion.py .items(). df.items() materializes a pandas Series for every column just so the body can read its dtype: which is wasteful when most (or all) columns aren't tensor columns

Additional Information

Code paths

function hot path frequency
_cast_tensor_columns_to_ndarrays ArrowBlockAccessor.to_pandas() per batch in iter_batches(pandas)
_cast_ndarray_columns_to_tensor_extension TableBlockBuilder.build()_combine_tables() per block built

TODO: Add the microbenchmark

…andas conversion between numpy and tensors

Signed-off-by: Ayush Kumar <ayushk7102@gmail.com>
@ayushk7102
ayushk7102 requested a review from a team as a code owner June 11, 2026 18:34

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes pandas DataFrame conversions by scanning df.dtypes instead of df.items(), avoiding the unnecessary materialization of Series objects for non-tensor columns. The reviewer identified a critical issue where duplicate column names in the DataFrame would cause df[col_name] to return a DataFrame instead of a Series, leading to runtime errors. To resolve this, the reviewer suggested iterating with enumerate(df.dtypes.items()) and retrieving columns safely by index using df.iloc[:, i].

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread python/ray/data/util/data_batch_conversion.py Outdated
Comment thread python/ray/data/util/data_batch_conversion.py Outdated
Comment thread python/ray/data/util/data_batch_conversion.py Outdated
@ray-gardener ray-gardener Bot added the data Ray Data-related issues label Jun 11, 2026
@ayushk7102 ayushk7102 added this to the Autoscaler V2 milestone Jun 11, 2026
@ayushk7102 ayushk7102 removed this from the Autoscaler V2 milestone Jun 11, 2026
@ayushk7102

ayushk7102 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@goutamvenkat-anyscale A few comments to address conversion overhead:

Note that we cannot df[col_name].iloc[0] in the _cast_ndarray_columns_to_tensor_extension() path because numpy columns all report their dtypes as numpy.object_. However, N-D arrays all will report type(s.iloc[0]) as numpy.ndarray which is our only source of truth that this should be backed by a TensorDtype, rather than as a list of strings, scalars, etc. Also, df[col_name].iloc[0] should return a view over the first element in the buffer, which is cheaper than actually materializing the entire series.

This is different from the cast_tensor_columns_to_ndarrays() path where we already have the columns as TensorArrays, such that the check becomes a cheap isinstance(TensorDtype).

…e columns case (regression)

Signed-off-by: Ayush Kumar <ayushk7102@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit b71c050. Configure here.

Comment thread python/ray/data/util/data_batch_conversion.py Outdated
Signed-off-by: Ayush Kumar <ayushk7102@gmail.com>
@ayushk7102 ayushk7102 added the go add ONLY when ready to merge, run all tests label Jun 12, 2026
@goutamvenkat-anyscale
goutamvenkat-anyscale merged commit 44776c3 into ray-project:master Jun 17, 2026
6 checks passed
limarkdcunha pushed a commit to limarkdcunha/ray that referenced this pull request Jun 30, 2026
…ng (ray-project#64038)

## Description

When we are converting tensor columns of a block/batch to ndarrays and
vice versa, our current implementation scans over the columns using
`df.items()` and checks the dtype of each column. This is wasteful as we
pay the cost of materializing the column as a `pd.Series` just to check
its dtype. Instead, what we can do is iterate over the
`df.dtypes.items()` which only yields numpy dtype objects.
`_cast_tensor_columns_to_ndarrays` and
`_cast_ndarray_columns_to_tensor_extension` in
`data_batch_conversion.py` `.items()`. `df.items()` materializes a
pandas `Series` for every column just so the body can read its dtype:
which is wasteful when most (or all) columns aren't tensor columns

## Additional Information
### Code paths
| function | hot path | frequency |
|---|---|---|
| `_cast_tensor_columns_to_ndarrays` | `ArrowBlockAccessor.to_pandas()`
| **per batch** in `iter_batches(pandas)` |
| `_cast_ndarray_columns_to_tensor_extension` |
`TableBlockBuilder.build()` → `_combine_tables()` | **per block built**
|

###
TODO: Add the microbenchmark

---------

Signed-off-by: Ayush Kumar <ayushk7102@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

data Ray Data-related issues go add ONLY when ready to merge, run all tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants