ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

cuDF libcudf 列表合并 API 全解:concatenate_rows 与 concatenate_list_elements 的实现原理与实战

cuDF libcudf 列表合并 API 全解:concatenate_rows 与 concatenate_list_elements 的实现原理与实战 数据分析数据工程机器学习【免费下载链接】cudfcuDF - GPU DataFrame Library项目地址https://gitcode.com/gh_mirrors/cu/cudf点击查看免费下载导读本文以 libcudf 官方 API 文档中的 lists_combine 主题为骨架系统讲解 cuDF 中列表lists列的两种合并操作按行合并多个列表列cudf::lists::concatenate_rows与将同一行内的多个子列表合并为一个列表cudf::lists::concatenate_list_elements。读完本文你将掌握这两个 API 的语义、concatenate_null_policy空值策略的取舍、底层 GPU 实现思路concatenate gather offsets 重组、Python 侧的调用方式以及如何通过测试用例验证其行为。1. 概述lists_combine 是什么lists_combine是 libcudf 中负责合并/拼接列表的 API 分组。在文档层面它由 cpp/include/cudf/lists/combine.hpp 中的addtogroup lists_combine定义并通过 docs/cudf/source/libcudf/api_docs/lists_combine.rst 中的.. doxygengroup:: lists_combine指令自动展开为完整的 API 参考页。该分组包含两个公开 APIAPI输入输出cudf::lists::concatenate_rows一个table_view多列每列都是列表列单列列表列每一行是各输入列对应行的拼接结果cudf::lists::concatenate_list_elements单个列表列要求至少两层嵌套listlist 单层列表列每一行是输入行内所有子列表的拼接结果二者共享一个关键语义逐行row-wise拼接即结果中的每一行只由输入中对应行的元素决定不跨行混合。这区别于cudf::concatenatecpp/include/cudf/concatenate.hpp那种把整个列垂直堆叠的列向拼接。1.1 什么是列表列在 cuDF 中lists 列是一个两级结构offsets 子列int32长度为num_rows 1用前缀和的方式描述每行的起止位置child 子列listT的元素列存放实际的元素数据。lists_column_viewcpp/include/cudf/lists/lists_column_view.hpp提供了offsets_begin()、child()等访问接口下面的源码分析会大量用到这些概念。2. 核心 APIconcatenate_rows按行合并多个列表列2.1 函数签名与语义声明位于 cpp/include/cudf/lists/combine.hppstd::unique_ptrcolumn concatenate_rows( table_view const input, concatenate_null_policy null_policy concatenate_null_policy::IGNORE, cuda::stream_ref stream cudf::get_default_stream(), rmm::device_async_resource_ref mr cudf::get_current_device_resource_ref());头文件中的伪代码示例s1 [{0, 1}, {2, 3, 4}, {5}, {}, {6, 7}] s2 [{8}, {9}, {}, {10, 11, 12}, {13, 14, 15, 16}] r lists::concatenate_rows(s1, s2) r [{0, 1, 8}, {2, 3, 4, 9}, {5}, {10, 11, 12}, {6, 7, 13, 14, 15, 16}]注意这个示例还揭示了两个边界行为空列表{}在拼接时会被吸收不贡献任何元素当某一行在所有输入列中都是空列表时示例第 4 行输出行是空列表{}而非 null。2.2 参数说明参数类型默认值说明inputtable_view const必填待拼接的多个列表列。要求每列类型均为type_id::LIST且所有列的元素类型必须一致null_policyconcatenate_null_policyIGNORE见下文 2.3 节streamcuda::stream_refget_default_stream()设备内存操作与 kernel 启动使用的 CUDA 流mrrmm::device_async_resource_refget_current_device_resource_ref()结果列设备内存的分配资源2.3 空值策略concatenate_null_policy定义于 cpp/include/cudf/lists/combine.hppenum class concatenate_null_policy { IGNORE, NULLIFY_OUTPUT_ROW };两种策略的语义策略行为IGNORE默认拼接时忽略null 列表元素仅当一行中所有输入列都是 null 时输出行才为 nullNULLIFY_OUTPUT_ROW一行中只要有任意一个输入列是 null整个输出行就置为 null注意这里的null指的是列表元素本身为 null整行是一个空指针/缺失值而不是列表内部元素为 null。列表内部元素的 null 不会被提升到列表层——测试SimpleInputWithNullableChildcpp/tests/lists/combine/concatenate_rows_tests.cpp表明子元素为 null 的行仍会正常参与拼接null 子元素原样保留在结果中。2.4 异常约束头文件与实现cpp/src/lists/combine/concatenate_rows.cu共同定义了以下约束输入表至少有一列否则抛出cudf::logic_error所有输入列必须是 lists 列否则抛出cudf::data_type_error错误消息All columns of the input table must be of list column type.所有列表列的元素类型必须一致否则抛出cudf::data_type_error若输入 0 行返回与第一列同类型的空列cudf::empty_like若只有 1 列直接浅拷贝该列返回std::make_uniquecolumn(*(input.begin()), ...)避免无谓计算。测试用例InvalidInputcpp/tests/lists/combine/concatenate_rows_tests.cpp逐一验证了空表、含非列表列、类型不一致三种场景的异常抛出。3. 核心 APIconcatenate_list_elements合并行内子列表3.1 函数签名与语义std::unique_ptrcolumn concatenate_list_elements( column_view const input, concatenate_null_policy null_policy concatenate_null_policy::IGNORE, cuda::stream_ref stream cudf::get_default_stream(), rmm::device_async_resource_ref mr cudf::get_current_device_resource_ref());头文件伪代码示例l [ [{1, 2}, {3, 4}, {5}], [{6}, {}, {7, 8, 9}] ] r lists::concatenate_list_elements(l) r [ {1, 2, 3, 4, 5}, {6, 7, 8, 9} ]与concatenate_rows的区别输入不是多列而是一个两层嵌套的列表列listlistT输出降为listT。空子列表同样被吸收不产生元素。3.2 参数与约束input必须满足input.type().id() type_id::LIST且其 child 也必须是 LIST 类型至少两层深度否则抛出std::invalid_argument见 cpp/src/lists/combine/concatenate_list_elements.cunull_policy语义与 2.3 节相同IGNORE时输出行只有当所有子列表都是 null 时才为 nullNULLIFY_OUTPUT_ROW时只要任一子列表为 null输出行即 null。测试用例InvalidInputcpp/tests/lists/combine/concatenate_list_elements_tests.cpp验证了普通列非列表与单层列表列都会触发std::invalid_argument。SimpleInputNestedManyLevelsNoNull则验证了超过两层的嵌套输入同样工作正常输出保持逐行合并的语义。4. 底层实现原理从源码看 GPU 上的拼接过程4.1 concatenate_rowsconcatenate gather offsets 重组实现位于 cpp/src/lists/combine/concatenate_rows.cu算法分三步列向拼接先把所有输入列用cudf::detail::concatenate垂直拼成一个大列表列concat此时数据是按先整列、后行组织的gather 重排用一个变换迭代器生成 gather map把拼接结果重排为先行、后列的顺序——即 child 数据变为{row0的元素们, row1的元素们, ...}。实现里通过src_col_index i % num_columns、src_row_index i / num_columns反推源位置concatenate_rows.cu再调用cudf::detail::gatheroffsets 重组generate_regrouped_offsets_and_null_mask用reduce_by_key把每行的多个子列表长度累加生成新的前缀和 offsets并依据 null_policy 生成 null maskconcatenate_rows.cu。最后用cudf::make_lists_column组装结果。源码注释concatenate_rows.cu以示例形式记录了这种先按列拼、再用 gather 重排、最后重算 offsets的等价变换是理解该算法的最佳入口。关键实现细节空值行统计generate_null_counts对每行统计有多少列在该行是 nullIGNORE策略下只有null_count num_columns全部为 null的行才置 nullNULLIFY_OUTPUT_ROW下null_count 0的行才有效concatenate_rows.cu在IGNORE策略下null 行的 child 数据会通过 gather 前的 null mask 清洗掉避免残留无效元素偏移量总和超出int32上限时抛出std::overflow_errorconcatenate_rows.cu。4.2 concatenate_list_elements两个内部 kernel 路径实现位于 cpp/src/lists/combine/concatenate_list_elements.cu派发逻辑在 concatenate_list_elements.cunull_policy IGNORE 或 子列无 null └─ concatenate_lists_ignore_null 否则有 null 且 NULLIFY_OUTPUT_ROW └─ concatenate_lists_nullifying_rowsconcatenate_lists_ignore_null核心技巧是利用第二层 offsets 的差值直接生成输出 offsets。输出第idx行的元素个数等于d_list_offsets[d_row_offsets[idx]]到d_list_offsets[d_row_offsets[idx1]]的跨度于是每个输出 offsets 位置可直接由内层 offsets 数组经一次thrust::transform得到concatenate_list_elements.cuchild 数据则整体拷贝输入的子列表拼接结果在内存中本就是连续的。null mask 通过cudf::detail::valid_if逐行判定该行是否至少有一个有效子列表concatenate_lists_nullifying_rows需要两阶段。先用generate_list_offsets_and_validities计算输出 offsets 与逐行有效性thrust::all_of要求该行所有子列表都有效再用gather_list_entries生成 gather map 并cudf::detail::gather收集有效元素concatenate_list_elements.cu。另外还有一个边界守卫当内层列表列child为 0 行时即每个外层行都是 null 或空列表直接构造全零 offsets 0 行 child 拷贝外层 null mask的结果避免对未分配的内存缓冲区解引用触发cudaErrorIllegalAddressconcatenate_list_elements.cu。5. Python 侧调用pylibcudf 与 cudf5.1 pylibcudf 绑定C API 通过 Cython 暴露给 Python绑定定义于 python/pylibcudf/pylibcudf/lists.pyxplc.lists.concatenate_rows(Table input, streamNone, mrNone)接收Table可含多列内部固定以concatenate_null_policy.IGNORE调用 C 实现plc.lists.concatenate_list_elements(Column input, concatenate_null_policy null_policy, streamNone, mrNone)null_policy 通过枚举plc.lists.ConcatenateNullPolicy其底层即 C 的concatenate_null_policy见 python/pylibcudf/pylibcudf/libcudf/lists/combine.pxd传入。5.2 cuDF 高层封装在 cuDF 的 Python 层列表列的运算符会走concatenate_rows。ListColumn.concatenate_rowspython/cudf/cudf/core/column/lists.py把自身与其他列组装成ColumnList后调用plc.lists.concatenate_rows测试 python/cudf/cudf/tests/series/test_binops.py 验证了cudf.Series([[a,a],[b],[c]]) 自身的结果与 pandas 一致concatenate_list_elements封装在ListColumn.concatenate_list_elementspython/cudf/cudf/core/column/lists.py并通过dropna参数映射到两种 null 策略dropnaTrue→IGNOREdropnaFalse→NULLIFY_OUTPUT_ROW。6. 测试验证与行为边界两个 API 各有独立测试文件cpp/tests/lists/combine/concatenate_rows_tests.cpp953 行覆盖空列、单列、含 null、字符串列、空列表列等多种组合cpp/tests/lists/combine/concatenate_list_elements_tests.cpp899 行覆盖多级嵌套、字符串、含 null、dropna语义等场景。值得注意的行为边界均可从测试与源码确认空列表不产生 null某行所有输入都是空列表时输出是空列表而非 null子元素 null 不提升列表内部元素的 null 保留在结果中不触发列表层 null 策略类型一致性所有输入列的元素类型必须相同字符串与数值列表列混用会抛cudf::data_type_error最少两层嵌套concatenate_list_elements要求输入为listlistT单层列表会抛std::invalid_argument极端规模防护拼接总元素数超过int32偏移量上限时抛std::overflow_error。7. 选型建议何时用哪个 API需要把多个列表列逐行拼成一行如多特征列表合并、多列 list 特征拼接用concatenate_rows在 cuDF Python 层直接对两个Series做运算即可输入是单个嵌套列表列如 JSON 解析出的listlist...想把行内所有子列表摊平成一条用concatenate_list_elements需要保留任一行含 null 即整行 null的严格语义时显式传NULLIFY_OUTPUT_ROW若希望容忍部分缺失、尽可能保留有效数据使用默认的IGNORE。这两个 API 只做行内合并、不改变行数输出行数等于输入行数也不会对元素做排序或去重与lists::set_operations等集合运算类 API见 cpp/include/cudf/lists/set_operations.hpp在定位上有明确区分。赞分享数据分析数据工程机器学习【免费下载链接】cudfcuDF - GPU DataFrame Library项目地址https://gitcode.com/gh_mirrors/cu/cudf点击查看免费下载相关推荐cuDF libcudf Lists Sort API 深度解析列表内元素分段排序的实现原理与实战用法cuDF libcudf Lists Sort API 深度解析列表内元素分段排序的实现原理与实战用法 本篇技术指南围绕 cuDF 中 libcudf 的 l数据分析数据工程机器学习cuDF/libcudf 列表提取lists_extractAPI 完全指南按索引从列表列中提取元素cuDF/libcudf 列表提取lists_extractAPI 完全指南按索引从列表列中提取元素 lists_extract 是 cuDF/libcu数据分析数据工程机器学习如何为不同平台和架构选择并下载正确的 UniGetUI 发布包如何为不同平台和架构选择并下载正确的 UniGetUI 发布包 UniGetUI 的官方发布页上同时提供 Windows、macOS 和 Linux 的多个安装数据分析数据工程机器学习上一篇10分钟上手Earthdata SearchNASA地球数据检索神器快速教程下一篇angular-calendar拖拽功能完全解析创建、移动、调整事件一气呵成创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进