SAS 到 Python:真正的代价

这次搜索的多数结果是从 SAS 源码生成 Python 的工具,其中几个做得不错。这一页从更早一步开始:这次迁移对你的代码库究竟合不合适,验证结果要花多少代价,以及答案是否定时该怎么办。

简短的答案

从一个 SAS 代码库出去的路有四条,不是两条:交给自动工具、由人重写、在不是 SAS 的东西上原样运行 SAS 程序,或者什么都不动。哪条正确几乎只取决于两个问题——代码有多少,以及是否有人必须复现它从前的输出。下面写的就是每条路的代价。

什么时候 Python 才是正确答案

Python 是更好的目的地,这种情况比这类页面通常承认的要多。四个条件让选择变得清楚:代码库小到一个人一周能读完,团队本来就每天写 Python,分析反正要重做,以及下游没有任何环节要求新数字和旧数字严格一致。四条都成立时,重写比任何兼容层都便宜,最后留下的是团队不用背第二种语言就能维护的代码。

四条路,各自的代价

这里的每个选项对某些人来说都是正确答案。没有一个是不付代价的,而贵的部分从来不是语法。

自动转换工具

网页工具、厂商服务和大语言模型会接过 .sas 源码并返回 Python,通常把 DATA 步映射到 pandas,把常用过程映射到 statsmodels 或 scikit-learn。对几百行直白的数据处理,这是真正的捷径,几分钟就能拿到一个能读的起点。账单稍后才到:输出的每一行都需要一个同时懂两种语言的人去读。

由人重写

有人读完 SAS 程序,弄清它本来要做什么,再用 Python 写出来。起步更慢,而且这是唯一一条最后得到的代码像 Python、而不像披着 Python 外衣的 SAS 的路。两年后仍然对 Python 满意的团队,大多是这样走过来的,通常让旧程序在旁边继续跑,直到数字对上。

按原样运行程序——100 个过程

对比页面跳过的那条路。Jenner 是 SAS 9.4 语言的净室实现,用 Rust 写成:它直接读取 SAS7BDAT 文件,按原样执行 .sas 源码,因此没有生成的代码需要复查,团队也不必多扛一种语言。它做不到的是覆盖整个 SAS 语言,覆盖范围逐个过程公开,你可以在依赖之前先查自己的那些。

留在原地

什么都不做是一个真实的决定,而且常常是对的。如果代码稳定,运行它的环境今年不会消失,也没有人要求改变,那么你不做的这次迁移就是这一页上回报最高的选择。等平台搬迁、审计或者招人困难把这个问题逼到面前时,再回来看。

信任转换后的代码要花多少

自动转换的失败方式不是语法错误,语法错误第一次运行就会露面。是那种安静的数值差异。SAS 用空格填补字符值的右端而 Python 不会;SAS 从 1960 年 1 月 1 日开始数日期,pandas 从 1970 年 1 月 1 日开始;DATA 步的 MERGE 在键于两侧重复时,行为也不同于 pandas 的 merge。这些都不会报任何东西。它给出的是一个几乎正确的数字,而这是最糟的一种错。所以真实的价格,是由同时精通两种语言的人逐行阅读,加上一段让新旧在同样输入上并排运行、直到输出一致的时间;这个价格随代码的数量增长,而不是随它的巧妙程度。

常见问题

可以,而且工具比从前好。网页转换器和厂商服务会接收一个 .sas 文件并返回 Python,大语言模型(LLM)也能在聊天窗口里做同样的事。它们都擅长语法,也都没法告诉你数字是否还对得上。把输出当成一份初稿,作者从没见过你的数据。

不是。这一页由 Jenner 发布,它是 SAS 9.4 语言的独立净室实现,用 Rust 写成。它按写好的样子运行 .sas 程序,读取你已经有的 SAS7BDAT 文件。不会有任何东西被输出成另一种语言,所以没有生成的源码需要谁去复查。

通常是每个 SAS 程序一个 Python 文件:DATA 步变成 pandas 操作,PROC SQL 变成 pandas 连接或经数据库驱动的 SQL,统计过程在有对应物时映射到 statsmodels、scipy 或 scikit-learn。没有对应物的地方——宏功能的大部分、ODS 输出、许多格式与输入格式——工具会留下一条注释或它最好的猜测。复查的时间就花在这个缝隙里。

有不错的,而且它们都有一个值得在依赖之前知道的共同界限。速查表把 PROC MEANS 对到 pandas 的 describe,把 PROC FREQ 对到 value_counts 或交叉表,把 PROC SORT 对到 sort_values,把 DATA 步对到一串赋值。那是语法层,而语法不是难的部分。任何表格都翻译不了的是底下的语义——缺失值的处理、BY 分组处理、字符比较里的尾部空格、日期的起点——悄悄出错的地方正是那里。

能,而且对短程序来说,这往往是拿到初稿的最短路径。难处和所有转换器一样,只是被流利程度放大了:无论对错,LLM 写出的代码读起来都很有说服力,遇到它不认识的过程选项,它会造一个看着合理的等价物。解决办法不是更好的提示词。是给模型一条能运行两个版本并比较输出的途径,让检查变成机械动作,而不是取决于答案听起来有多自信。

从外面没人说得准,给你一个数字的页面是在猜。真正起作用的变量有两个:有多少行代码,以及新输出必须与旧输出一致这条要求有多硬。几千行、没有复现要求,是一个小团队能做完的项目;一个过往结果必须可复现的已验证代码库,则是一个带着测试预算的工程,写代码只是其中很小的一部分。

当输出必须复现旧程序产生的东西,而且团队之外会有人来核对时。当代码库大到没有人读过全部时。当理解这项分析的人不是写 Python 的人时。其中任何一条,都会把编码的活变成验证的活,而让这类项目超支的正是验证。

不用 SAS 来运行 SAS 程序。SAS 语言的独立实现会执行你已经有的 .sas 源码,也就是说没有生成的代码需要复查,屋里也不会多出第二种语言。Jenner 是其中之一。Altair SLC,从前的 WPS,是另一个,而且做这件事的时间长得多。当离开的理由是平台或许可证、而不是语言本身时,这条路值得算一笔账。

能。SAS7BDAT 文件被直接读取,所以不必先导出成 CSV。这件事比听上去更重要。一次以把所有数据集倒成文本开头的迁移,会在代码本身的差异之上再继承一组差异——编码、数值精度、日期解析——之后就没人分得清一处不一致是从哪一层来的了。

不覆盖整个 SAS 语言,这是要和上面所有内容放在一起权衡的诚实界限。每个已实现的过程都有公开的参考页,所以某个具体的 PROC 是否支持,可以在依赖之前查清楚,而不是事后才发现。依赖冷门过程选项、ODS 版式或外部数据库引擎的程序,是首先该看的地方。实用的检验是跑自己的程序并比较日志;花一个下午,比这类页面上的任何说法都更能把问题定下来。

Altair SLC,也就是从前的 WPS,不用 SAS 就能运行 SAS 语言的程序,而且比我们做得久得多。在一片规模不小的资产上,如果别人早已撞上你的边角情况并让它被修好,那段历史是真金白银。把两者都放到你自己的代码面前,比较日志。答案通常一天之内就清楚了,而且不总是我们。

这是常见的结局,也是一个合理的结局。新的分析用 Python 写,因为团队和库本来就在那边;旧的已验证程序则原样继续跑,直到有理由去动它们。这避开了这个决定最糟的版本:把没人有预算重新验证的代码一次性重写。两边只需要在边界上一致——也就是彼此交出的数据——而不是逐行一致。

用你自己的程序来定

你的代码、你的数据,日志并排放着。决定这件事的就是这个对比,而且没人能替你跑。

开始免费试用