- 数据分析
- 数据工程
- 机器学习
【免费下载链接】cudf
cuDF - GPU DataFrame Library
本文以 RAPIDS cuDF 仓库中 pylibcudf 的strings.convert模块为核心,系统梳理字符串与数值(整数/浮点/定点)、布尔、时间戳、时长、IPv4 地址、列表与 URL 之间的双向转换 API。读完本文,你将掌握pylibcudf.strings.convert全部 9 个子模块的函数签名、格式串(format specifier)规则、NULL 语义与典型用法,并能对照 C++ 层实现(libcudf::strings::convert)理解底层行为。
模块概览:从 API 文档到 Python 实现
pylibcudf 是 cuDF 的 Cython 绑定层,其字符串转换功能集中在pylibcudf.strings.convert包中。该包的 API 文档入口为 docs/cudf/source/pylibcudf/api_docs/strings/convert/index.rst,通过 Sphinxtoctree聚合了 9 个独立子页面,每个子页面用automodule指令直接引用对应的 Python 模块,例如 convert_datetime.rst 对应pylibcudf.strings.convert.convert_datetime。这意味着文档内容完全由源码 docstring 生成,源码即规范。
在 Python 侧,包结构定义于 python/pylibcudf/pylibcudf/strings/convert/init.py,它导出了以下 9 个子模块:
| 子模块 | 核心函数 | 转换方向 |
|---|---|---|
convert_booleans | to_booleans/from_booleans | 字符串 ↔ 布尔 |
convert_datetime | to_timestamps/from_timestamps/is_timestamp | 字符串 ↔ 时间戳 |
convert_durations | to_durations/from_durations | 字符串 ↔ 时长 |
convert_fixed_point | to_fixed_point/from_fixed_point/is_fixed_point | 字符串 ↔ 定点小数 |
convert_floats | to_floats/from_floats/is_float | 字符串 ↔ 浮点 |
convert_integers | to_integers/from_integers/is_integer/hex_to_integers/is_hex/integers_to_hex | 字符串 ↔ 整数(含十六进制) |
convert_ipv4 | ipv4_to_integers/integers_to_ipv4/is_ipv4 | IPv4 字符串 ↔ UINT32 |
convert_lists | format_list_column | 字符串列表列 → 格式化字符串 |
convert_urls | url_encode/url_decode | URL 百分号编码 / 解码 |
每个.pyx模块都是对 C++ 层cudf::strings::convert系列接口的薄封装。以convert_datetime.pyx为例(见 convert_datetime.pyx),函数体遵循统一模式:通过column_view读取输入列、调用cpp_convert_datetime.to_timestamps(...)执行 GPU 内核、再用Column.from_libcudf把结果包装回 Python 对象,全程with nogil释放 GIL。
通用参数约定:stream 与 mr
所有转换函数都接受两个可选参数:
stream: CudaStreamLike | None:指定 CUDA 流,默认使用默认流;mr: DeviceMemoryResource | None:指定 RMM 设备内存资源,默认使用当前设备资源。
内部通过_get_stream与_get_memory_resource归一化(参见 convert_datetime.pyx),返回的Column也会绑定本次使用的流与内存资源。在多流编程或自定义内存池场景下,这两参数是控制执行与分配的关键入口。
整数与十六进制转换:convert_integers
convert_integers提供 6 个函数,覆盖十进制与十六进制两条转换路径,接口定义在 convert_integers.pyx。
十进制整数
to_integers(input, output_type):把字符串列解析为指定整数类型的新列,output_type可为 int8/16/32/64、uint8/16/32/64 等;from_integers(integers):把整数列格式化为字符串列;is_integer(input, int_type=None):返回布尔列,标记每个字符串是否全部由合法整数字符组成。int_type可选:传入时还会检查下溢/上溢,默认不检查。
is_integer的两种模式在 test_string_convert_integers.py 中有直接对比:字符串["1", "-1", "1.2", "A", None]在默认模式下结果为[True, True, False, False, None];而当传入uint8类型后,"-1"因超出无符号范围变为False。可见int_type参数让合法性校验与目标类型强绑定。
十六进制转换
hex_to_integers(input, output_type):解析十六进制字符串(如"0xff"、"0x2a")为整数;is_hex(input):判断字符串是否为合法十六进制(允许0x前缀,如"0xff"与"123"均为合法);integers_to_hex(input):把整数列转为大写十六进制字符串。
注意方向差异:hex_to_integers要求提供output_type,而integers_to_hex直接输出字符串。测试用例(test_string_convert_integers.py)展示了255 -> "FF"、-42 -> "FFFFFFFFFFFFFFD6"(64 位补码表示),NULL 在往返转换中保持 NULL。
浮点转换:convert_floats
convert_floats提供to_floats、from_floats、is_float三个函数(见 convert_floats.pyi)。其 C++ 规范在 convert_floats.hpp 中定义:
to_floats只识别[0-9]、前缀-/+、小数点.,并额外支持科学计数法(如"-1.78e+5");输入类型必须为 float 类型,否则抛出logic_error;from_floats以十进制输出,负数带-前缀;当有效数字超过 10 位时自动转为科学计数法(如"-1.78e+15");is_float只要字符串包含至少一个[-+0-9eE.]字符即判为True,例如["-1.23", "1", "1.2.3", "A", None]得到[True, True, False, False, None]。
测试用例(test_string_convert_floats.py)验证了往返一致性:浮点-1.23格式化为"-1.23",1格式化为"1.0"。
定点小数转换:convert_fixed_point
定点小数(fixed-point / DECIMAL 类型)适合需要精确十进制语义的金融等场景。convert_fixed_point提供三个函数,C++ 规范见 convert_fixed_point.hpp。
解析规则与 scale 语义
to_fixed_point(input, output_type)期望格式为[sign][integer][.][fraction]:符号可省略或为-/+,小数点可有可无,整数与小数部分由[0-9]组成。输出类型的scale决定小数位。头文件给出了权威示例:
s = ['123', '-876', '543.2', '-0.12'] datatype = {DECIMAL32, scale=-2} fp = to_fixed_point(s, datatype) # [123400, -87600, 54320, -12]即 scale=-2 表示以 10^-2 为单位存储,"543.2" 变为 54320。若output_type不是定点类型则抛出logic_error;溢出不检查。
反向与校验
from_fixed_point(input):按列的 scale 放置小数点,负 scale 会补充尾部零。例如fp=[110,222,3330,-440,-1](scale=-2)输出['1.10','2.22','33.30','-4.40','-0.01'];is_fixed_point(input, decimal_type=None):校验字符串格式(符号与指数可选、小数点最多一次),并通过decimal_type的 scale 检查整数部分是否溢出存储上限。decimal_type默认为DECIMAL64。文档示例中['123','-456','','1.2.3','+17E30','12.34','.789','-0.005']对应结果为[true,true,false,false,true,true,true,true]——空串与重复小数点不合法,但科学计数法+17E30与-0.005合法。
对应 Python 测试见 test_string_convert_fixed_point.py:["123", "1.23", "1.2.3", "", None] -> [True, True, False, False, None]。
布尔转换:convert_booleans
convert_booleans提供两个方向相反的 API(见 convert_booleans.pyx):
to_booleans(input, true_string):字符串列 → BOOL8 列。true_string为标量,只有与其完全匹配的字符串解析为True,其余一律为False(C++ 规范见 convert_booleans.hpp);from_booleans(booleans, true_string, false_string):BOOL8 列 → 字符串列,True写为true_string、False写为false_string;若输入列不是 BOOL8 类型则抛logic_error。
两个true_string/false_string参数都是Scalar对象,需用plc.Scalar.from_arrow(...)构造。测试(test_string_convert_booleans.py)演示了[True, None, False]配合"A"/"B"输出["A", None, "B"],NULL 行保持 NULL。
时间戳转换:convert_datetime
convert_datetime是字符串转换中最常用的模块,提供to_timestamps、from_timestamps、is_timestamp三个函数,完整格式规则见 C++ 头文件 convert_datetime.hpp。
to_timestamps:字符串 → 时间戳
to_timestamps(input, timestamp_type, format)按format模式解析字符串,输出timestamp_type指定的时间戳列(支持 s/ms/us/ns)。支持以下格式符:
| 格式符 | 含义 |
|---|---|
%d | 月中的日:01-31 |
%m | 月:01-12 |
%y | 不带世纪的年:00-99,其中 [0,68] 映射到 [2000,2068],[69,99] 映射到 [1969,1999] |
%Y | 带世纪的年:0001-9999 |
%H | 24 小时制:00-23 |
%I | 12 小时制:01-12 |
%M | 分:00-59 |
%S | 秒:00-59(不支持闰秒,且不做范围检查) |
%f | 6 位微秒:000000-999999;可带精度,%3f/%6f/%9f分别对应毫秒/微秒/纳秒 |
%z | UTC 偏移 ±HHMM,如 +0500 |
%j | 年中的日:001-366 |
%p | 仅识别 'AM'/'PM'/'am'/'pm' |
%W | 周一为一周起点的周序号:00-53 |
%w | 星期几:0-6 = 周日-周六 |
%U | 周日为一周起点的周序号:00-53 |
%u | 星期几:1-7 = 周一-周日 |
要点:
- 输出时间戳单位完全由
timestamp_type决定,与%f解析出的位数无关; - 若同时指定
%W/%w(或%U/%u)与%m/%d,周值优先于月/日参与日期计算; - 无效格式不检查——字符串含意外或不足字符时该行结果未定义,建议先用
is_timestamp校验; timestamp_type非时间戳类型时抛logic_error;- 所有 NULL 输入行对应 NULL 输出行。
from_timestamps:时间戳 → 字符串
from_timestamps(timestamps, format, input_strings_names)反向格式化。除上述格式符外,还支持%Z(恒输出 "UTC")、%V(ISO-8601 周序号 01-53)、%G(ISO-8601 周年 0000-9999),以及需要借助input_strings_names列提供名称表的%a/%A(星期缩写/全称)与%b/%B(月份缩写/全称)。测试中传入空字符串列作为名称表(test_string_convert_datetime.py)。
is_timestamp:格式合法性校验
is_timestamp(input, format)返回 BOOL8 列,True表示该字符串可按给定格式成功解析。与to_timestamps不同,它会主动校验:格式串为空或包含不支持的格式符时抛出std::invalid_argument,因此适合作为转换前的安全预检。测试(test_string_convert_datetime.py)显示格式"%Y-%m-%dT%H:%M:%S"下"2020-01-01T01:01:01"为True,而"2020-01-01"为False。
时长转换:convert_durations
convert_durations处理timedelta类的时长列,其格式符体系独立于时间戳,C++ 规范见 convert_durations.hpp:
| 格式符 | 含义 | 范围 |
|---|---|---|
%% | 字面% | - |
%n | 换行符 | - |
%t | 水平制表符 | - |
%D | 天数 | -2,147,483,648 ~ 2,147,483,647 |
%H | 24 小时 | 00-23 |
%I | 12 小时 | 00-11 |
%M | 分 | 00-59 |
%S | 秒 | 00-59.999999999 |
%OH/%OI/%OM/%OS | 对应不带符号的变体 | 同上 |
%p | AM/PM 标记 | 'AM' 或 'PM' |
%R | 等价%H:%M | - |
%T | 等价%H:%M:%S | - |
%r | 等价%OI:%OM:%OS %p | - |
两个 API:
to_durations(input, duration_type, format):字符串 → 时长列,duration_type必须是时长类型否则抛logic_error;from_durations(durations, format=None):时长列 → 字符串列,默认格式为"%D days %H:%M:%S"(见 convert_durations.pyx)。
格式化细节:输入列的时间单位决定秒的小数位数——毫秒 3 位、微秒 6 位、纳秒 9 位;负时长只输出一个负号,带符号的格式符为%H,%I,%M,%S,%R,%T;格式化行为尽量对齐std::formatter<std::chrono::duration>。测试覆盖 ns/us/ms/s 四种时长类型(test_string_convert_durations.py)。
IPv4 转换:convert_ipv4
convert_ipv4提供 IP 字符串与整数互转(C++ 规范见 convert_ipv4.hpp):
ipv4_to_integers(input):把123.45.67.890形式的 IPv4 字符串转为 UINT32 列,按位拼接:i0.i1.i2.i3 -> (i0 << 24) | (i1 << 16) | (i2 << 8) | (i3)。不校验格式,非法字符串结果未定义;integers_to_ipv4(integers):反向把 UINT32 拆成 4 个 8 位段并渲染为点分字符串;输入非 UINT32 抛logic_error;is_ipv4(input):校验字符串是否为xxx.xxx.xxx.xxx且每段在 0-255。测试(test_string_convert_ipv4.py)显示"0.0.0.1"为True、"1.2.34"与"A"为False。
列表格式化:convert_lists
convert_lists.format_list_column(input, na_rep=None, separators=None)把"字符串列表列"(LIST 类型的列,子元素为 STRING)格式化为字符串列,C++ 规范见 convert_lists.hpp。
separators:一个含3 个字符串元素的列,顺序为:元素分隔符(默认,)、左包围符(默认[)、右包围符(默认]);na_rep:NULL 元素的替换字符串,默认空串。
头文件示例:
l1 = { [[a,b,c], [d,e]], [[f,g], [h]] } s1 = format_list_column(l1) # ["[[a,b,c],[d,e]]", "[[f,g],[h]]"] l2 = { [[a,b,c], [d,e]], [NULL], [[f,g], NULL, [h]] } s2 = format_list_column(l2, '-', [':', '{', '}']) s2 # ["{{a:b:c}:{d:e}}", "{-}", "{{f:g}:-:{h}}"]注意第二个示例:NULL 元素在嵌套列表[NULL]中被替换为-,外层再由{/}包围。输入必须为 LIST 且子列为 STRING,否则抛logic_error。Python 测试见 test_string_convert_lists.py,其中separators用pa.array([",", "[", "]"])构造,na_rep默认None时等价于空串。
URL 编码转换:convert_urls
convert_urls提供两个函数(C++ 规范见 convert_urls.hpp):
url_encode(input):对每个字符串做 URL(百分号)编码;url_decode(input):把%XX形式的转义序列还原为对应字节字符。
测试(test_string_convert_urls.py)与 Python 标准库urllib.parse.quote/unquote对齐:"/home/nfs"编码为"%2Fhome%2Fnfs",反向解码还原,NULL 行保持 NULL。
从测试看行为契约:NULL 传播与 pyarrow 互操作
pylibcudf 的字符串转换测试集中在 python/pylibcudf/tests/ 目录,按子模块拆分(test_string_convert.py、test_string_convert_booleans.py、test_string_convert_datetime.py、test_string_convert_durations.py、test_string_convert_fixed_point.py、test_string_convert_floats.py、test_string_convert_integers.py、test_string_convert_ipv4.py、test_string_convert_lists.py、test_string_convert_urls.py)。这些测试揭示了几条贯穿所有 API 的行为契约:
- NULL 传播:输入列的任意 NULL 元素在输出列中保持 NULL,且不参与转换;
- pyarrow 互操作:通过
plc.Column.from_arrow(...)从 Arrow 数组构造输入、用assert_column_eq与pyarrow.compute.strptime/cast等结果逐元素比对,验证与 Arrow 生态的语义一致性; - 类型校验严格:输出类型参数非法时抛
logic_error(如to_integers非整数类型、to_floats非浮点类型、from_booleans输入非 BOOL8); - is_系列先验校验*:
is_integer/is_float/is_fixed_point/is_ipv4/is_timestamp等函数让"先校验再转换"成为可靠的工作流,避免to_*系列对非法格式"结果未定义"的坑。
使用建议:构造一条健壮的转换流水线
综合以上 API 语义,推荐在实际数据清洗中遵循"校验 → 转换 → 处理 NULL"三步:
- 对目标列先运行对应的
is_*函数,配合布尔过滤剔除或标记非法行,尤其是to_timestamps/to_durations/ipv4_to_integers这类"无效格式结果未定义"的转换; - 调用
to_*时显式指定输出DataType(如plc.DataType(plc.TypeId.TIMESTAMP_SECONDS)),并注意定点数的scale会改变数值语义; - 转换结果与输入等长且 NULL 位置对齐,可放心与原始列拼接使用;需要控制执行位置与内存时,为每个调用传入
stream与mr。
整套模块从 API 文档到 Cython 封装再到 C++ 内核三层一一对应,是理解 cuDF 字符串处理体系的理想入口。
- 数据分析
- 数据工程
- 机器学习
【免费下载链接】cudf
cuDF - GPU DataFrame Library
相关推荐
OpenCut贡献指南:4条参与路径与首个PR的完整流程
OpenCut贡献指南:4条参与路径与首个PR的完整流程 这是一份 OpenCut 贡献指南。OpenCut 是一款开源的 CapCut 替代视频编辑器,目前正
数据分析数据工程机器学习cuDF pylibcudf 字符串字符类型(char_types)模块:字符分类位掩码、全类型校验与过滤实战指南
cuDF pylibcudf 字符串字符类型(char_types)模块:字符分类位掩码、全类型校验与过滤实战指南 本文围绕 cuDF(GPU DataFram
数据分析数据工程机器学习cuDF 字符串与 Duration 互转全解析:pylibcudf 的 `convert_durations` 模块实战指南
cuDF 字符串与 Duration 互转全解析:pylibcudf 的 convert_durations 模块实战指南 导读 本文聚焦 cuDF(GPU D
数据分析数据工程机器学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考