Skip to content

Commit 18a6483

Browse files
authored
Use ColumnBase.create more in cudf classic APIs (#21306)
Towards #21229 Namely, * `list.get` * `str.join` * `explode` Note: I added `tests/extension/test_arrow.py::test_str_join_string_type` to conftest-patch but expect to remove it again in a following PR. We need to enhance our dtype conversion utilities to convert between nested dtype variants like `cudf.ListDtype(object) -> pd.ArrowDtype(pa.string())` Authors: - Matthew Roeschke (https://github.com/mroeschke) Approvers: - GALI PREM SAGAR (https://github.com/galipremsagar) URL: #21306
1 parent b22e464 commit 18a6483

5 files changed

Lines changed: 44 additions & 52 deletions

File tree

python/cudf/cudf/core/accessors/lists.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,6 @@ def get(
115115
out_of_bounds_mask,
116116
pa_scalar_to_plc_scalar(pa.scalar(default)),
117117
)
118-
119-
if self._column.element_type != out.dtype:
120-
# libcudf doesn't maintain struct labels so we must transfer over
121-
# manually from the input column if we lost some information
122-
# somewhere. Not doing this unilaterally since the cost is
123-
# non-zero..
124-
out = out._with_type_metadata(self._column.element_type)
125118
return self._return_or_inplace(out)
126119

127120
def contains(self, search_key: ScalarLike) -> Series | Index:

python/cudf/cudf/core/accessors/string.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -517,17 +517,21 @@ def join(
517517

518518
if isinstance(self._column.dtype, ListDtype):
519519
list_column = self._column
520+
result_dtype = cast("ListDtype", list_column.dtype).element_type
520521
else:
521522
# If self._column is not a ListColumn, we will have to
522523
# split each row by character and create a ListColumn out of it.
523524
list_column = self._column.fillna("").character_tokenize()
525+
result_dtype = cast("ListDtype", list_column.dtype).element_type
524526
if len(list_column) == 0:
525527
list_column = column_empty( # type: ignore[assignment]
526528
len(self._column), dtype=list_column.dtype
527529
)
528530

529531
if is_scalar(sep):
530-
data = list_column.join_list_elements(sep, string_na_rep, "") # type: ignore[attr-defined]
532+
data = list_column.join_list_elements( # type: ignore[attr-defined]
533+
sep, string_na_rep, "", result_dtype
534+
)
531535
elif can_convert_to_column(sep):
532536
sep_column = as_column(sep)
533537
if len(sep_column) != len(list_column):
@@ -544,16 +548,15 @@ def join(
544548
sep_column,
545549
sep_na_rep,
546550
string_na_rep,
551+
result_dtype,
547552
)
548553
else:
549554
raise TypeError(
550555
f"sep should be an str, array-like or Series object, "
551556
f"found {type(sep)}"
552557
)
553558

554-
return self._return_or_inplace(
555-
data._with_type_metadata(self._column.dtype)
556-
)
559+
return self._return_or_inplace(data)
557560

558561
def extract(
559562
self, pat: str, flags: int = 0, expand: bool = True
@@ -4682,8 +4685,9 @@ def character_tokenize(self) -> Series | Index:
46824685
2 .
46834686
dtype: object
46844687
"""
4685-
result_col = ColumnBase.from_pylibcudf(
4686-
self._column.character_tokenize().plc_column.children()[1]
4688+
result_col = ColumnBase.create(
4689+
self._column.character_tokenize().plc_column.children()[1],
4690+
self._column.dtype,
46874691
)
46884692
if isinstance(self._parent, cudf.Series):
46894693
lengths = self.len().fillna(0)

python/cudf/cudf/core/column/lists.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -321,20 +321,24 @@ def sort_lists(
321321

322322
def extract_element_scalar(self, index: int) -> ColumnBase:
323323
with self.access(mode="read", scope="internal"):
324-
return ColumnBase.from_pylibcudf(
325-
plc.lists.extract_list_element(
326-
self.plc_column,
327-
index,
328-
)
324+
plc_column = plc.lists.extract_list_element(
325+
self.plc_column,
326+
index,
327+
)
328+
return ColumnBase.create(
329+
plc_column,
330+
self.dtype.element_type, # type: ignore[union-attr]
329331
)
330332

331333
def extract_element_column(self, index: ColumnBase) -> ColumnBase:
332334
with self.access(mode="read", scope="internal"):
333-
return ColumnBase.from_pylibcudf(
334-
plc.lists.extract_list_element(
335-
self.plc_column,
336-
index.plc_column,
337-
)
335+
plc_column = plc.lists.extract_list_element(
336+
self.plc_column,
337+
index.plc_column,
338+
)
339+
return ColumnBase.create(
340+
plc_column,
341+
self.dtype.element_type, # type: ignore[union-attr]
338342
)
339343

340344
def contains_scalar(self, search_key: pa.Scalar) -> ColumnBase:
@@ -404,6 +408,7 @@ def join_list_elements(
404408
separator: str | StringColumn,
405409
sep_na_rep: str,
406410
string_na_rep: str,
411+
result_dtype: DtypeObj,
407412
) -> StringColumn:
408413
with self.access(mode="read", scope="internal"):
409414
if isinstance(separator, str):
@@ -422,7 +427,7 @@ def join_list_elements(
422427
)
423428
return cast(
424429
"cudf.core.column.string.StringColumn",
425-
type(self).from_pylibcudf(plc_column),
430+
ColumnBase.create(plc_column, result_dtype),
426431
)
427432

428433
def minhash_ngrams(

python/cudf/cudf/core/indexed_frame.py

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5488,6 +5488,17 @@ def _explode(self, explode_column: Any, ignore_index: bool):
54885488
else:
54895489
idx_cols = ()
54905490

5491+
explode_column_idx = column_index + len(idx_cols)
5492+
# We must copy inner datatype of the exploded list column to
5493+
# maintain struct dtype key names
5494+
exploded_type = cast(
5495+
"ListDtype", self._columns[column_index].dtype
5496+
).element_type
5497+
result_types = (
5498+
exploded_type if i == explode_column_idx else col.dtype
5499+
for i, col in enumerate(itertools.chain(idx_cols, self._columns))
5500+
)
5501+
54915502
with access_columns(
54925503
*itertools.chain(idx_cols, self._columns),
54935504
mode="read",
@@ -5500,33 +5511,14 @@ def _explode(self, explode_column: Any, ignore_index: bool):
55005511
for col in itertools.chain(idx_cols, self._columns)
55015512
]
55025513
),
5503-
column_index + len(idx_cols),
5514+
explode_column_idx,
55045515
)
55055516
exploded = [
5506-
ColumnBase.from_pylibcudf(col) for col in plc_table.columns()
5507-
]
5508-
# We must copy inner datatype of the exploded list column to
5509-
# maintain struct dtype key names
5510-
element_type = cast(
5511-
ListDtype, self._columns[column_index].dtype
5512-
).element_type
5513-
5514-
column_index += len(idx_cols)
5515-
exploded = [
5516-
ColumnBase.create(
5517-
new_column.plc_column,
5518-
element_type,
5519-
)
5520-
if i == column_index
5521-
else ColumnBase.create(new_column.plc_column, old_column.dtype)
5522-
for i, (new_column, old_column) in enumerate(
5523-
zip(
5524-
exploded,
5525-
itertools.chain(idx_cols, self._columns),
5526-
strict=True,
5517+
ColumnBase.create(plc_column, dtype=dtype)
5518+
for plc_column, dtype in zip(
5519+
plc_table.columns(), result_types, strict=True
55275520
)
5528-
)
5529-
]
5521+
]
55305522

55315523
data = type(self._data)(
55325524
dict(
@@ -7078,9 +7070,7 @@ def _append_new_row_inplace(col: ColumnBase, value: ScalarLike) -> None:
70787070
to_type = col.dtype
70797071
val_col = val_col.astype(to_type)
70807072
old_col = col.astype(to_type)
7081-
res_col = ColumnBase.create(
7082-
concat_columns([old_col, val_col]).plc_column, to_type
7083-
)
7073+
res_col = concat_columns([old_col, val_col])
70847074
if (
70857075
cudf.get_option("mode.pandas_compatible")
70867076
and res_col.dtype != col.dtype

python/cudf/cudf/pandas/scripts/conftest-patch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,7 @@ def set_copy_on_write_option():
16061606
"tests/extension/test_arrow.py::test_round",
16071607
"tests/extension/test_arrow.py::test_str_extract_non_symbolic",
16081608
"tests/extension/test_arrow.py::test_str_find[ab-0-None-exp0-exp_typ0]",
1609+
"tests/extension/test_arrow.py::test_str_join_string_type",
16091610
"tests/extension/test_arrow.py::test_str_len",
16101611
"tests/extension/test_arrow.py::test_str_repeat_unsupported",
16111612
"tests/extension/test_arrow.py::test_str_replace_unsupported[pat-b]",
@@ -6056,7 +6057,6 @@ def set_copy_on_write_option():
60566057
"tests/series/accessors/test_dt_accessor.py::TestSeriesDatetimeValues::test_strftime",
60576058
"tests/series/accessors/test_dt_accessor.py::TestSeriesDatetimeValues::test_strftime_dt64_days",
60586059
"tests/series/accessors/test_dt_accessor.py::TestSeriesDatetimeValues::test_valid_dt_with_missing_values",
6059-
"tests/series/accessors/test_list_accessor.py::test_list_getitem_invalid_index[list_dtype0]",
60606060
"tests/series/accessors/test_list_accessor.py::test_list_len",
60616061
"tests/series/accessors/test_struct_accessor.py::test_struct_accessor_dtypes",
60626062
"tests/series/accessors/test_struct_accessor.py::test_struct_accessor_field_expanded[0-int_col]",

0 commit comments

Comments
 (0)