ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Polars SQL 三角函数完全指南:SIN/COS/TAN/COT、反三角函数与度/弧度转换函数的用法与实现解析

Polars SQL 三角函数完全指南:SIN/COS/TAN/COT、反三角函数与度/弧度转换函数的用法与实现解析 Polars SQL 三角函数完全指南SIN/COS/TAN/COT、反三角函数与度/弧度转换函数的用法与实现解析【免费下载链接】polarsExtremely fast Query Engine for DataFrames, written in Rust项目地址: https://gitcode.com/GitHub_Trending/po/polarsPolars 在 SQL 接口df.sql()与pl.SQLContext中内置了 19 个三角函数覆盖正弦、余弦、正切、余切及其反函数并同时提供以 D 结尾的角度制degrees变体以及DEGREES/RADIANS单位换算。本文以官方 SQL 函数参考文档 trigonometry.rst 为主线逐一对每个函数给出可直接运行的 SQL 示例与精确输出并结合 functions.rs 与 trigonometry.rs 等源码讲清「度制函数如何被翻译为弧度制内核」「整型参数如何被处理」「ATAN2 的长度校验规则」等底层细节。读完你可以直接在 DataFrame 上写出正确、可预测的三角 SQL 查询也能在数据含inf、NaN、整型列时预判结果。一、函数一览表以下 19 个函数是 Polars SQL 对三角函数TrigonometricFunction的完整支持面名称均不区分大小写函数含义输入/输出单位参数个数SIN正弦输入弧度输出为比值1COS余弦输入弧度1TAN正切输入弧度1COT余切1/tan输入弧度1SIND正弦输入角度制degrees1COSD余弦输入角度制1TAND正切输入角度制1COTD余切输入角度制1ASIN反正弦输出弧度1ACOS反余弦输出弧度1ATAN反正切输出弧度1ASIND反正弦输出角度制1ACOSD反余弦输出角度制1ATAND反正切输出角度制1ATAN2四象限反正切atan2(y, x)输出弧度2ATAN2D四象限反正切输出角度制2DEGREES弧度 → 度—1RADIANS度 → 弧度—1正函数接受任意数值列含整型反函数与单位换算函数同理所有结果列类型均为f64浮点具体规则见「参数类型与空值语义」一节。二、调用方式两种 SQL 入口这些函数有两种调用入口等价。入口一DataFrame.sql()在查询中以self引用表自身。import polars as pl df pl.DataFrame({rads: [-1.0, -0.5, 0.5, 1.0]}) df.sql(SELECT rads, ACOS(rads) AS acos FROM self)入口二pl.SQLContext注册多个 DataFrame 后执行查询。ctx pl.SQLContext(dfdf) ctx.execute(SELECT rads, ACOS(rads) AS acos FROM df, eagerTrue)函数名大小写不敏感官方文档中的示例一律大写如ACOS而仓库测试 test_trigonometric.py 中又全部使用小写如acos(...)、cos(...)两种写法均可执行。建议在文章/日志里统一使用大写以贴合 SQL 惯例。三、正函数SIN / COS / TAN / COT 及其角度制变体这四组函数直接对应正弦、余弦、正切、余切。弧度制版本无后缀要求输入为弧度以D 结尾的版本要求输入为角度degree。例如SIND(90)等于1.0而SIN(1.570796...)才等于1.0。3.1 SIN 与 SINDimport math df pl.DataFrame({rads: [0.0, 1/4 * math.pi, 1/2 * math.pi, 3/4 * math.pi]}) df.sql(SELECT rads, SIN(rads) AS sin FROM self)radssin0.00.00.7853980.7071071.5707961.02.3561940.707107角度制版本输入为整型也可以列会自动转换为浮点参与计算df pl.DataFrame({degs: [0, 90, 225, 270]}) df.sql(SELECT degs, SIND(degs) AS sind FROM self)degsi64sindf6400.0901.0225-0.707107270-1.03.2 COS 与 COSDdf pl.DataFrame({rads: [-2.0, -1.0, 0.0, 1.0, 2.0]}) df.sql(SELECT rads, COS(rads) AS cos FROM self)radscos-2.0-0.416147-1.00.5403020.01.01.00.5403022.0-0.416147df pl.DataFrame({degs: [0, 45, 180, 225]}) df.sql(SELECT degs, COSD(degs) AS cosd FROM self)degsi64cosdf6401.0450.707107180-1.0225-0.7071073.3 TAN 与 TANDimport math df pl.DataFrame({rads: [0.0, 1/4 * math.pi, 3/4 * math.pi]}) df.sql(SELECT rads, TAN(rads) AS tan FROM self)radstan0.00.00.7853981.02.356194-1.0df pl.DataFrame({degs: [0, 45, 135, 225]}) df.sql(SELECT degs, TAND(degs) AS tand FROM self)degsi64tandf6400.0451.0135-1.02251.03.4 COT 与 COTD余切即1/tan。注意在0弧度处tan(0)0因此COT(0.0)结果为inf而不是报错df pl.DataFrame({rads: [-2.0, -1.0, 0.0, 1.0, 2.0]}) df.sql(SELECT rads, COT(rads) AS cot FROM self)radscot-2.00.457658-1.0-0.6420930.0inf1.00.6420932.0-0.457658df pl.DataFrame({degs: [30, 45, 60]}) df.sql(SELECT degs, COTD(degs) AS cotd FROM self)degsi64cotdf64301.732051451.0600.57735COT 系列计算的是tan的倒数。底层实现trigonometry.rs写的是v.tan().powi(-1)即「先求 tan再取 -1 次幂」这与1/tan(x)一致并在tan(x)0时自然得到 IEEE 浮点的±inf。四、反三角函数ASIN / ACOS / ATAN 及其角度制变体反三角函数输出的是角度值无后缀版本输出弧度范围与数学约定一致D 版本输出角度。输入必须落在函数定义域内越界行为见第六节。4.1 ASIN 与 ASINDdf pl.DataFrame({rads: [-1.0, -0.75, -0.0, 0.5]}) df.sql(SELECT rads, ASIN(rads) AS asin FROM self)radsasin-1.0-1.570796-0.75-0.848062-0.0-0.00.50.523599df pl.DataFrame({degs: [-0.5, 0.0, 0.5]}) df.sql(SELECT degs, ASIND(degs) AS asind FROM self)degsasind-0.5-30.00.00.00.530.0可以看到ASIND的输出直接就是「度」asin(0.5) ≈ 0.523599 弧度 ≈ 30°二者一致。4.2 ACOS 与 ACOSDdf pl.DataFrame({rads: [-1.0, -0.5, 0.5, 1.0]}) df.sql(SELECT rads, ACOS(rads) AS acos FROM self)radsacos-1.03.141593-0.52.0943950.51.0471981.00.0df pl.DataFrame({degs: [-0.5, 0.0, 0.5]}) df.sql(SELECT degs, ACOSD(degs) AS acosd FROM self)degsacosd-0.5120.00.090.00.560.0acos(-1)π≈3.141593 弧度而acosd(-1)180°两者是同一角度在不同单位下的表示。4.3 ATAN 与 ATANDdf pl.DataFrame({rads: [-1.0, 0.0, 1.0, 2.0]}) df.sql(SELECT rads, ATAN(rads) AS atan FROM self)radsatan-1.0-0.7853980.00.01.00.7853982.01.107149df pl.DataFrame({degs: [-1.0, 0.0, 1.0]}) df.sql(SELECT degs, ATAND(degs) AS atand FROM self)degsatand-1.0-45.00.00.01.045.0atan是单参数版本输出范围约在-π/2 ~ π/2即-90° ~ 90°之间无法区分输入实际所处的象限。需要区分象限时使用双参数的ATAN2。五、双参数反正切ATAN2 与 ATAN2DATAN2(y, x)计算y/x的反正切并依据 y、x 的符号判断结果所在象限因此输出覆盖完整的(-π, π]或(-180°, 180°]。它与普通反正切的关键差异是atan2(-1, 1)与atan2(1, -1)虽然y/x同为-1结果却分别是-π/4与3π/4。弧度制版本df pl.DataFrame( { a: [-2.0, -1.0, 1.0, 2.0], b: [1.5, 1.0, 0.5, 0.0], } ) df.sql(SELECT a, b, ATAN2(a, b) AS atan2_ab FROM self)abatan2_ab-2.01.5-0.927295-1.01.0-0.7853981.00.51.1071492.00.01.570796角度制版本df pl.DataFrame( { a: [-1.0, 0.0, 1.0, 1.0], b: [1.0, 1.0, 0.0, -1.0], } ) df.sql(SELECT a, b, ATAN2D(a, b) AS atan2d_ab FROM self)abatan2d_ab-1.01.0-45.00.01.00.01.00.090.01.0-1.0135.0注意这里第四行atan2(1, -1)落在第二象限角度制结果为135°而不是-45°这正是四象限反正切的价值所在。仓库测试 test_arctan2 使用(±√2/2, ±√2/2)四组坐标验证了四个象限的输出45° / -45° / 135° / -135°同时用「先构造角度制结果再.radians()得到弧度值」的方式交叉校验ATAN2D与ATAN2结果一致。ATAN2 的两列长度要求从源码 apply_arctan2 可以看出ATAN2(y, x)对两个参数列有长度约束两个参数长度相等逐元素计算或者其中一个是长度为 1 的标量执行广播否则抛出计算错误y shape: {n} in arctan2 expression does not match that of x: {m}。这符合 SQL 中「按行逐元素计算」的语义避免因列长不一致产生歧义。六、单位换算DEGREES 与 RADIANSDEGREES(x)把弧度换算成度等价于乘以180/πRADIANS(x)把度换算成弧度等价于乘以π/180。import math df pl.DataFrame({rads: [0.0, math.pi/2, math.pi, 3*math.pi/2]}) df.sql(SELECT rads, DEGREES(rads) AS degs FROM self)radsdegs0.00.01.57079690.03.141593180.04.712389270.0df pl.DataFrame({degs: [0, 90, 180, 270]}) df.sql(SELECT degs, RADIANS(degs) AS rads FROM self)degsi64radsf6400.0901.5707961803.1415932704.712389注意第二个例子输入是整型列[0, 90, 180, 270]输出仍是浮点列。其底层实现直接调用 Rust 浮点 trait 的to_degrees()与to_radians()见 trigonometry.rs因此精度完全取决于 IEEE-754 双精度浮点本身。七、参数类型、空值与特殊值语义这一节所有结论都可以在 dispatch 层源码 trigonometry.rs 中核实整型自动转 f64。dispatch 入口apply_trigonometric_function对输入列类型做分支Float32/Float64以及开启dtype-f16特性后的Float16直接按原精度计算其余原始数值类型Int8/16/32/64、UInt 等先cast到Float64再计算。所以上述文档示例中整型输入如degs: [0, 90, 225]的输出类型统一为f64结果列的格式为浮点小数。空值保留。三角函数通过 ChunkedArray 的按值映射apply_values实现空值null所在位置在结果中仍为空值不会被填充或参与计算。若你的列含 null直接使用这些函数即可无需先清洗。定义域越界产生 NaN 而非报错。数学上asin/acos定义域为[-1, 1]。仓库测试 test_trigonometric.py 中刻意对1/0inf求acos(inf)、asin(inf)得到的是float(nan)说明越界输入在 Polars 中遵循浮点 IEEE 语义返回 NaN查询本身不会中断。正切/余切的奇异点。tan(π/2kπ)理论值无定义浮点实现会给出极大值cot(0)inf已由官方文档示例证实。测试中tan在接近奇异点时同样返回极大的有限值或 NaN见 test_trigonometric.py这类数据在后续排序、聚合前需要自行决定是否过滤。八、底层实现一个 SQL 函数名如何变成向量化浮点运算把这 19 个函数串起来看是一条「SQL 名称 → 逻辑计划表达式 → 物理执行」的清晰调用链。第 1 步SQL 函数注册与名称匹配。在 functions.rs 的SQLFunction枚举中三角函数被单独编组为「Trig functions」段约 L192-L304每个变体带一段SELECT xxx(col) FROM df的 SQL 文档注释名称匹配表约 L817-L993把大小写归一化后的字符串如acos、atan2、cosd映射到对应变体。第 2 步转换为 Expr核心设计D 版本是组合出来的。在 SQL 表达式翻译处functions.rs可以看到每种函数的真实构造方式Acos self.visit_unary(Expr::arccos), AcosD self.visit_unary(|e| e.arccos().degrees()), Cos self.visit_unary(Expr::cos), CosD self.visit_unary(|e| e.radians().cos()), Cot self.visit_unary(Expr::cot), CotD self.visit_unary(|e| e.radians().cot()), Degrees self.visit_unary(Expr::degrees), Radians self.visit_unary(Expr::radians), Atan2 self.visit_binary(Expr::arctan2), Atan2D self.visit_binary(|e, s| e.arctan2(s).degrees()),关键结论是核心三角函数引擎只认识弧度。以 D 结尾的角度制函数并不是独立的底层原语而是在 SQL 层通过两步 DSL 表达式「拼装」出来的正向度制函数先做一次radians()把度转弧度再调用内核函数例如COSD(x)cos(radians(x))、SIND/TAND/COTD同理反向度制函数先调用内核反函数结果自然是弧度再做一次degrees()转成度例如ACOSD(x)degrees(arccos(x))、ASIND/ATAND/ATAN2D同理单参数反函数Acos/Asin/Atan、双参数的Atan2、换算函数Degrees/Radians则直接映射到Expr上的同名方法这些方法定义于 arithmetic.rs 的 L88-L172例如fn degrees(self)、fn arctan2(self, x)。这解释了为什么COTD的输入是度、输出却与数学上cot完全一致它先被换算成弧度cot本身「根本不知道」角度制的存在。第 3 步逻辑计划统一为 IR 枚举。DSL 层的FunctionExpr::Trigonometry在逻辑计划转换中映射为统一的IRTrigonometricFunction见 dsl_to_ir/functions.rs其中包含Degrees、Radians、ArcCos等变体。与此同时function_expr/trigonometry.rs 定义了表达式引擎层的函数枚举与展示名称。需要留意的是表达式内核还额外提供双曲函数族Cosh/Sinh/Tanh/ArcCosh/ArcSinh/ArcTanh见该文件 L6-L22但 SQL 注册表只暴露了本文表中的 19 个函数SQL 中目前查不到COSH/SINH这类名字需要双曲运算时应改用 DataFrame 表达式 API如pl.col(x).cosh()。第 4 步物理执行。最终在 dispatch/trigonometry.rs 中按列数据类型分派浮点列逐值调用 num-traits 的Floattrait 方法v.sin()、v.acos()、v.to_degrees()等cot通过v.tan().powi(-1)实现arctan2通过broadcast_binary_elementwise逐元素调用atan2保证与ChunkedArray的块结构兼容。整条链上没有任何逐行的 Python 循环这也是它能保持向量化吞吐的原因Polars 的向量化引擎在此不逐 Python 值解释。九、实用建议与易错点小结综合官方文档示例、源码约束与仓库测试可归纳出几条实际使用时的要点注意默认单位是弧度。SIN/COS/TAN/COT输入弧度若你的数据列存的是「度」要么先套RADIANS(col)要么直接使用SIND/COSD/TAND/COTD反函数输出同理想要「度」的结果请用 D 后缀变体。ATAN2的象限语义。需要从(x, y)坐标求方位角时应使用ATAN2输出范围(-π, π]且两个参数列长度必须相等或其一为标量否则报错。整型参数无需手工转换引擎自动cast到f64SELECT COTD(degs)中degs即使为i64也能直接使用。越界不报错产生NaNACOS(1.5)、ASIN(2.0)等返回NaNCOT(0)返回inf。涉及后续运算比较、排序、均值时要留意这些特殊值可在 SQL 中用IS NOT NULL与IS NOT NANPolars SQL 的IS NOT NAN谓词先行过滤。结果精度为双精度浮点。文档输出中的0.707107、3.141593只是默认格式化后的 6 位小数展示真实结果保留完整f64精度测试中所有断言都采用abs_tol1e-5容差说明浮点结果的精确比对应使用assert_frame_equal(..., abs_tol...)而不是逐位相等。十、在哪里验证与继续深挖函数全集的官方参考入口trigonometry.rst本文所有示例与输出均源于此SQL 层函数枚举、注册与翻译 crates/polars-sql/src/functions.rsTrig functions 段落见 L192-L304、名称映射见 L817-L993、表达式构造见 L1201-L1221逻辑计划层的三角函数枚举crates/polars-plan/src/dsl/function_expr/trigonometry.rs物理执行与数据类型分发crates/polars-expr/src/dispatch/trigonometry.rsDSL 侧arccos/arctan2/degrees/radians等方法定义crates/polars-plan/src/dsl/arithmetic.rs覆盖全部 19 个函数、含四个象限与inf/NaN用例的 Python 测试py-polars/tests/unit/sql/test_trigonometric.py。如果你想在自己的数据上快速实验最省事的方式是在 Python 中构造一个 DataFrame然后用df.sql(SELECT SIN(rads), COSD(degs), ATAN2(y, x) ... FROM self)直接查看结果——所有示例代码均可原样复制运行。【免费下载链接】polarsExtremely fast Query Engine for DataFrames, written in Rust项目地址: https://gitcode.com/GitHub_Trending/po/polars创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表