ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

小白学SAS基础教程:从数据整理到作图制表与踩坑排查

小白学SAS基础教程:从数据整理到作图制表与踩坑排查

简介:《小白学SAS基础教程》面向零基础的数据分析与统计初学者,也适合曾被SAS繁杂命令劝退、希望系统入门的人群。全书采用对话体,以“小白”的学习视角串联数据集建立、常用函数、数据清洗、绘图和制表等基础内容,强调以解决实际问题为导向,而非简单罗列语法命令。资源包共1个PDF文件,大小约1.76MB,便于下载后直接阅读与检索;内容聚焦基础入门,并延伸至缺失值、异常值、重复值处理及规范报表输出等实用环节。目前已有709人学习。读者可从中获得一条较清晰的学习路径,理解每步操作背后的逻辑与用途,掌握用SAS完成数据整理、图形呈现和报表生成的基本思路,适合作为案头参考并配合练习逐步消化。

1. 从打开软件到跑通第一段程序:SAS 基础入门真正卡住新手的地方

很多人对 SAS 基础入门的第一印象是命令太多、帮助文档太厚,买本书翻两页就放下了。这份《小白学SAS基础教程》换了条路:不按软件菜单逐条讲语法,而是用对话把数据整理、作图、制表三件事串起来,主人公小白遇到的问题,基本就是新手第一天会撞上的。它适合零基础、被 SAS Help 劝退、又必须马上处理数据的人;如果你已经有 SAS 底子,想找统计建模的进阶内容,这份资源不是给你准备的。

2. 程序骨架与数据集落地:data/input/cards 三件套和 Work 库的生死问题

SAS 的程序结构其实比多数人想的简单。一个 data 步负责把数据弄进来,一个 proc 步负责对数据做动作,中间靠 run 隔开。新手最容易犯的错误不是写不出复杂逻辑,而是连这个骨架都没立住就开始抄函数,结果日志里红字一片。先把最小闭环跑通,后面所有内容才有落点。

2.1 三个窗口的分工要先弄清楚

打开 SAS 9.4 中文版,界面看着眼花,实际只要盯住三块:编辑器、日志、输出。编辑器写程序,日志记录运行过程,输出放结果。菜单和工具栏用得不多,绝大多数数据管理和统计动作都在编辑器里敲代码完成,菜单更多是保存、导入导出这类辅助操作。结果查看器会额外生成一份排版更整齐的结果,代价是多花一点运行时间,介意的话可以在参数选择里把「创建 HTML」勾掉。

程序提交之后的第一动作永远是看日志,不是看输出。日志里没有 ERROR 和 WARNING,结果才有讨论价值;日志里有红字,输出窗口里那些数字一个都不能信。这个习惯听起来废话,但我见过太多人拿着带 ERROR 的结果去做汇报。

2.2 data、input、cards 的最小可用写法

先用一段能跑通的程序把骨架立起来,这段代码同时包含数据步和程序步:

/* 数据步:建立数据集 */ data score; input gender $ score; cards; M 88 F 92 M 75 F 96 ; run; /* 程序步:对数据做描述统计 */ proc means data=score n mean std; class gender; var score; run;

逻辑说明:data score;给数据集起名,名字只能由字母、数字、下划线组成,首字符不能是数字,长度不超过 32 个字符,不能带空格和中文。input gender $ score;声明变量,$表示后面这个变量是字符型,变量之间用空格分隔,SAS 默认以空格作为字段边界。cards;告诉 SAS 下面开始是数据行,数据行结束后分号必须单独占一行,不能紧跟在最后一个数据后面。run;表示这一步结束,可以执行了。

参数说明:class gender;指定分组变量,SAS 会按性别各算一遍;var score;指定分析变量;n mean std是要输出的统计量,不加的话默认输出会更多。写程序步时,proc后面跟过程名,过程名后面跟选项,具体语句用分号断开,这套格式和数据步是两套东西,别混着记。

字符型变量里的中文要留意编码,如果数据行里出现中文而日志提示编码转换问题,优先检查会话编码设置,而不是怀疑语法。

2.3 Work 库为什么第二天就空了

建好的数据集默认落在逻辑库的 Work 目录下,这是 SAS 留给用户的临时空间。Work 的特点是会话一关就自动清空,所以里面的数据集叫临时数据集。SAS 自带的几个库各有用途:Maps 系列放地图数据,Sashelp 放帮助和示例数据,Sasuser 放练习数据,都不适合塞自己的东西。

要留住数据,就得建永久逻辑库,把数据集指到一个真实存在的磁盘目录:

/* 建立指向本地目录的永久逻辑库 */ libname proj 'D:\sasproj'; /* 把临时数据集转存到永久库 */ data proj.score; set work.score; run;

逻辑说明:libname语句把库名proj绑定到一个已经存在的文件夹,之后所有proj.xxx形式的数据集都会落到这个目录里,关闭软件也不会消失。set work.score;是读取临时库里的数据,再写一份到永久库,相当于另存为。

参数说明:路径必须真实存在,SAS 不会帮你创建文件夹;路径里尽量别用中文和空格,某些版本下会有解析问题。libname是会话级的,每次重新打开 SAS 都要再执行一次,嫌麻烦可以写进启动配置里自动加载。库名同样遵循数据集命名规则,别起个my-lib这种带横线的名字。

2.4 从 Excel 导入:proc import 的参数怎么设才不翻车

数据量大的时候没人会在编辑器里手敲,常规做法是先在其他工具里录好,再导入 SAS。proc import是最省事的一条路:

proc import datafile='D:\sasproj\sales.xlsx' out=work.sales dbms=xlsx replace; getnames=yes; mixed=yes; guessingrows=max; run;

逻辑说明:datafile指源文件,out指落地后的数据集,dbms声明文件类型,replace允许覆盖同名数据集,避免重复运行时反复报错。getnames=yes表示把第一行当作变量名,不加这行 SAS 会自己造 column1、column2 这种名字。

参数说明:dbms的取值跟着文件走,xlsx 对应新版 Excel,xls 对应老格式,csv 对应文本文件。mixed=yes和guessingrows=max是重点:SAS 判断列类型时只看前若干行,如果前几行恰好为空或者混了非数字字符,整列会被判成字符型,后面的数值全部变成缺失。让它多扫描一些行、允许混合类型,能挡掉大部分这类问题。代价是导入变慢,数据量特别大时可以先把guessingrows设成 10000 这种具体数字,而不是 max。

导入完别急着分析,先跑一句proc contents data=work.sales; run;看变量类型和长度,类型不对就回头调参数,这一步能省掉后面大量的排查时间。

3. 格式、新变量与清洗:informat/format 怎么分工,retain 和数组各解决什么问题

这一章是整份资源里信息密度最高的部分,也是新手从「能建数据集」跨到「能处理数据」的分水岭。书里没按函数字典的方式罗列语法,而是按「你要解决什么问题」来组织:读进来的日期显示成数字、想把连续变量自动分组、想找出哪些行有缺失、想把重复记录清掉。每个需求对应一组具体写法,下面按这个顺序拆。

3.1 informat 和 format:一个管读进来,一个管显示出去

这两个东西名字像,作用完全相反。informat 负责解析输入,告诉 SAS「这一列长这样,请按这个规则读」;format 负责控制显示,告诉 SAS「存的是这个值,但请按这个样子呈现给用户」。原始值不会因为 format 改变,它只影响你眼睛看到的东西。

data birth; informat d yymmdd10.; format d yymmdd10. score 8.2; input id d score; cards; 1 1990-05-12 88.5 2 1995-11-03 92.25 ; run;

逻辑说明:informat d yymmdd10.;让 SAS 把1990-05-12这种写法的字符串解析成日期值,存进数据集时是一个天数数值;format d yymmdd10.;让这个天数在输出时重新显示成年月日。两个都写,才能做到「读得对、看得懂」。score 8.2表示总宽度 8 位、保留 2 位小数。

参数说明:日期类 informat 常见的还有mmddyy10.、date9.,要和数据里的实际写法对上,对不上就是缺失值,而且日志不会报错,静默出错最坑。数值格式里8.2的 8 是总宽度,别设得比整数位还小,否则显示会变成星号。

自定义分组用proc format更省事,把连续变量切成几档,比写一长串 if-then 干净:

proc format; value grp low - 59 = '不及格' 60 - 79 = '及格' 80 - high = '优秀'; picture pct low-high = '009.9%'; run; data scored; set score; format score grp.; run;

逻辑说明:value grp定义了一个命名格式,按区间映射成标签;picture pct定义的是显示模板,009.9%里 9 代表数字位、0 代表补零位,用来把 0.856 显示成 085.6% 这种效果。用的时候在 data 步里写format 变量 格式名.;,注意格式名后面那个点不能漏。

参数说明:区间写法必须覆盖完整,low和high是关键字,别写成-999。format 默认存在 work.formats 里,会话一关就没了。要在多个项目里复用,加library=proj.formats存到永久库,再用options fmtsearch=(work proj);告诉 SAS 去哪找。

3.2 造新变量的四条路:表达式、if-then、retain、do 循环

新变量无非四个来源,选哪条路取决于你要不要跨行累积、要不要按条件分支。

data newvar; set raw; /* 路径一:表达式直接算 */ total = math + english; /* 路径二:if-then 做分支 */ if total >= 180 then level = 'A'; else if total >= 150 then level = 'B'; else level = 'C'; /* 路径三:retain 做跨行累积 */ retain cum 0; cum = cum + total; /* 路径四:do 循环 + 数组 */ array s{2} math english; cnt = 0; do i = 1 to 2; if s{i} >= 90 then cnt + 1; end; drop i; run;

逻辑说明:set raw;逐行读入,每读一行,后面的赋值语句执行一次。表达式那条最直白。if-then-else是有顺序的,SAS 从上往下判断,第一个成立就跳出,所以条件要从严格往宽松写。retain cum 0;声明这个变量在迭代之间保留值,不写 retain 的话每行都会重置成缺失。cum = cum + total;还有一种简写cum + total;,累加语句自带 retain 效果。

参数说明:数组array s{2} math english;把两个变量打包,s{i}按位置取值,drop i;把循环计数器从数据集里去掉,不然会多出一列没用的 i。数组维度要和变量个数对上,对不上直接报错。if和where的区别后面单独说,这里先用 if。

有个思路值得单独提:round函数不只是四舍五入。把数值除以 10 再 round 再乘回去,就能实现按十位自动分段,比写十几个 if 分支清爽得多。这类「函数换个用法」的思路,比记住函数本身有用。

3.3 数组和自动变量:写一个查缺失的万能程序

缺失值检查是每个数据集的必经流程。手写if x = . then ...遇到几十个变量就废了,正确做法是用自动变量列表配合数组:

data miss_check; set raw; array nv _numeric_; array cv _character_; miss_n = 0; miss_c = 0; do i = 1 to dim(nv); if missing(nv[i]) then miss_n + 1; end; do i = 1 to dim(cv); if missing(cv[i]) then miss_c + 1; end; drop i; run;

逻辑说明:_numeric_和_character_是 SAS 的自动变量列表,分别代表当前数据集里所有数值型和字符型变量,不用一个个写名字。dim(nv)返回数组元素个数,循环从头走到尾。missing()函数对数值缺失(.)和字符缺失(空串)都返回真,是唯一能同时处理两种类型的判断方式。

参数说明:这段程序可以直接抄走,改set后面的数据集名就行。miss_n和miss_c分别是数值缺失个数和字符缺失个数,跑完看一眼分布就知道这份数据能不能用。drop i;别忘,否则每次运行都会多一列。

配套的还有first.和last.两个临时变量,配合by语句用,专门处理分组内的首行和末行。取每个 ID 的最新记录:

proc sort data=raw; by id date; run; data latest; set raw; by id date; if last.id; run;

逻辑说明:by id date;要求数据已按这两个变量排好序,last.id在某个 id 的最后一行取值为 1,其余为 0,if last.id;就是只保留每组最后一行。这两个变量是临时的,不会出现在结果数据集里。

参数说明:不排序直接用 by 会报错「BY 变量未按顺序排列」,这是最高频的翻车点之一。first.id取首行,last.id取末行,两个都写就是每组首末各留一条。

3.4 去重、找异常、填补:清洗三件套的具体写法

重复值最省事的处理方式是排序时直接去重:

proc sort data=raw out=dedup nodupkey dupout=dups; by id; run;

逻辑说明:nodupkey按 by 变量判重,保留第一条,其余丢掉;dupout=dups把被丢掉的记录单独存一份,方便回头核对是不是误删。by 后面跟多个变量时,判的是组合键,不是单列。

参数说明:nodupkey和nodup不是一回事,前者按 by 变量整体判重,后者按所有变量判重。真要按全字段去重,用noduprecs。删之前一定先看 dups,血泪经验是有些人把「同一个人多次就诊」当成重复记录删了。

异常值用 if 和 where 的差别要先搞清:

/* where 在读取阶段过滤,效率高 */ data sub1; set raw; where score > 60; run; /* if 在读取之后过滤,能用新变量 */ data sub2; set raw; if score > 60; run;

逻辑说明:where作用在读取阶段,不满足条件的观测根本不会进入 PDV,所以快;if是读进来之后再判断,如果条件里用到刚刚算出来的新变量,只能用 if。反过来,where里不能引用 data 步里新建的变量。

参数说明:where还能用在 proc 步里做子集,if不行。数据量大、只是简单条件筛选时优先 where。

缺失值填补要看场景,别默认用均值:

proc stdize data=raw out=filled reponly method=mean; var score income; run;

逻辑说明:reponly表示只替换缺失值,非缺失的原始值保持不动,不加这个选项会对所有值做标准化,那就不是填补了。method=mean用均值填,也可以换成 median、midrange。

参数说明:均值填补会压缩方差,做严谨分析时要考虑多重填补,这里只是工程上的快速处理。分类变量的缺失通常单独设一个「未知」类,比硬填更稳。

3.5 函数的使用思路:别只记语法,记它能干什么

count谁都会用,但用它统计一条商品评价里出现了几次关键词,就是另一回事。scan按分隔符取第 n 段,配合循环可以拆开任意结构的字符串。lag取上一行值,dif直接算差值,做同比环比的时候比自连接快得多:

data trend; set sales; by month; prev = lag(amount); diff = dif(amount); if first.month then prev = .; run;

逻辑说明:lag(amount)返回上一行的 amount,dif(amount)等价于amount - lag(amount)。注意 lag 是在队列里排队取值,如果中间有 if 跳过的行,取到的可能不是你以为的上一行,这是它的经典陷阱。

参数说明:if first.month then prev = .;用来把每组的第一个观测的上一期值清掉,避免跨组串数据。月份数据一定要先排序再 by。

4. 作图与制表:sgplot 双坐标轴、tabulate 三线表和 ODS 输出

SAS 的绘图在过去是弱项,从 9.3 开始补强,到 9.4 已经能覆盖绝大多数常规和非常规图形。这份资源在绘图和制表上花的篇幅明显多于同类基础书,原因很实际:分析做完要交出去,图和表是最先被看到的东西。这一章按「先出图、再出表、最后送出去」的顺序讲。

4.1 sgplot 的骨架:图形类型选错,后面全白搭

proc sgplot的基本结构是「一个 proc 语句 + 若干绘图语句 + 若干坐标轴语句」。绘图语句决定画什么,坐标轴语句负责修饰。

proc sgplot data=sales; vbar month / response=amount stat=sum datalabel group=region; xaxis label='月份' fitpolicy=rotate; yaxis label='销售额' grid; run;

逻辑说明:vbar画柱状图,response=amount指定柱子高度由哪个变量决定,stat=sum表示按月汇总求和,不写 stat 默认是频数。datalabel在柱顶标数值,group=region按地区分色堆叠。xaxis和yaxis是坐标轴修饰,fitpolicy=rotate让标签太挤时自动倾斜。

参数说明:常用的绘图语句还有series(折线,适合时间序列)、scatter(散点,看相关性)、vbox(箱线,看分布和异常值)、band(置信带)。选型的判断标准很简单:看趋势用 series,看构成用 vbar,看关系用 scatter,看离群用 vbox。

双坐标轴是高频需求,写法上靠y2axis指定哪条线走右轴:

proc sgplot data=ts; series x=month y=sales / y2axis lineattrs=(color=blue); series x=month y=rate / lineattrs=(color=red) markerattrs=(size=4); yaxis label='销售额'; y2axis label='增长率'; run;

逻辑说明:y2axis只能挂在一个绘图语句上,挂了两个会报错。左轴和右轴各自用yaxis/y2axis修饰,标签分开写。lineattrs和markerattrs控制线型和点的大小,比改模板省事。

参数说明:两条线的量纲差得越远,双轴越容易误导读图的人,用之前想清楚是不是真的需要。刻度范围可以手动设values=(0 to 100 by 20),自动刻度有时候会很别扭。

4.2 非常规图:template、雷达图和地图各自的前提

书里提到的瀑布图、气泡图、风险图、森林图、卡通图,靠的都是proc template定义图形模板,再用proc sgrender渲染。这条路能画出 sgplot 内置语句覆盖不到的图形,代价是要写 GTL 语法:

proc template; define statgraph pie_demo; begingraph; layout region; piechart category=type response=amount / datalabelattrs=(size=9); endlayout; endgraph; end; run; proc sgrender data=sales template=pie_demo; run;

逻辑说明:define statgraph定义模板名,begingraph到endgraph之间是图形结构,layout region是布局容器,piechart是具体图形元素。模板定义一次可以反复用,换数据只改sgrender的 data 参数。

参数说明:模板名不能和已有模板重名,重名会报错;想覆盖就加statgraph前面的 define 时用store=指定库。GTL 的报错信息不太友好,写的时候一行一行加,别一次写完再调。

雷达图走proc gradar,前提是数据已经是「分类 + 数值」的宽表;地图走proc gmap,前提是地图数据集可用,SAS 自带的 maps 库在新版本里路径有变化,用之前先proc contents确认一下。地图这块还有一层:自带地图文件和 shape 文件是两套坐标系,混用会画错位置,这一点书里在对应章节有说明。

4.3 tabulate 和 report:三线表怎么真正落地

proc tabulate是出统计表的首选,维度放在 class 里,指标放在 var 里,表格结构用 table 语句描述:

proc tabulate data=cls; class gender; var score; table gender='性别', score='得分'*(n='例数' mean='均值' std='标准差'); run;

逻辑说明:table语句里逗号左边是行维度,右边是列维度,*表示嵌套,=后面是显示标签。n、mean、std是统计量关键字,还可以用pctn算百分比、minmax算极值。

参数说明:三线表的样式靠 ODS 的 style 控制基本出不来精细效果,常见做法是把结果输出成 RTF 后用文字处理软件微调,或者用proc template定义表模板。书里给的思路是后者:先定义表模板,再让 tabulate 套用,这样每次运行格式一致,不用手工调。

proc report更适合做明细报表,column定列顺序,define逐个声明角色:

proc report data=sales nowd; column region month amount; define region / group '地区'; define month / group '月份'; define amount / analysis sum '销售额'; run;

逻辑说明:group表示按此列分组,analysis sum表示此列参与汇总计算。nowd关掉窗口模式,结果直接进输出。

参数说明:order、across、display是另外几种常用角色,用错了会报「变量角色冲突」。report 的列宽和换行靠style(column)=控制,细节多,先用默认样式跑通再调。

4.4 ODS 把结果送出去:RTF/PDF/Excel 的打开和关闭

结果最终要交出去,ODS 负责把输出重定向到文件:

ods rtf file='report.rtf' style=journal; proc tabulate data=cls; class gender; var score; table gender, score*(n mean std); run; ods rtf close;

逻辑说明:ods rtf file=打开一个输出目标,中间所有 proc 步的结果都写进这个文件,ods rtf close;关闭。style=journal是常用的简洁样式,比默认样式更适合正式报表。换成ods pdf file='report.pdf';或ods tagsets.excelxp file='report.xml';就是另一种格式。

参数说明:close必须写,漏了的话文件会一直被占用,打开就是空白或者报损坏。中途程序报错导致 close 没执行,可以在开头加一句ods _all_ close;兜底。输出到 Excel 时,options(sheet_name='表1')可以给每个 proc 结果指定工作表名,否则全挤在一张表里。

5. 踩坑排查:日志红字、merge 错位、Work 清空这五类翻车怎么定位

SAS 的报错信息不算友好,但排查有章法。这一章把实际使用中最高频的几类问题按「现象 → 原因 → 解决」列出来,都是可以直接对号入座的。看日志的顺序永远是:先找第一条 ERROR,往上翻一条语句,八成问题就在那里;WARNING 单独看,它不会中断程序,但会让结果悄悄变形。

5.1 语法与日志类翻车

现象一:日志报ERROR 180-322: 语句无效或使用顺序不当,位置指向一条看起来完全正确的语句。

原因:SAS 是按分号断句的,上一条语句漏了分号,解析器会把两条语句连起来读,报错点就漂到了下一行。数据行后面那个分号没另起一行,也会造成同样的效果。

解决:从报错行往上找最近的一个分号,确认每条语句都以英文分号结尾,cards;后面的数据结尾分号单独占一行。中文分号也是高频原因,肉眼几乎看不出来,把输入法切回英文再敲一遍。另外run;漏写不会立刻报错,但上一步没结束,下一步的行为会莫名其妙。

现象二:程序跑完没报错,但输出里一个观测都没有。

原因:where条件写错,或者字符变量比较时大小写、首尾空格不一致。SAS 的字符比较是区分大小写和空格的,'M'和'M '不相等。

解决:先用proc freq看一眼变量的实际取值分布,再改条件。字符变量比较前统一strip()去空格,或者用upcase()转大写。数值和字符混比较时,SAS 会隐式转换并给 WARNING,别忽略这条警告。

5.2 数据逻辑类翻车

现象三:两个数据集 merge 之后行数暴涨,本来一万行变成三万行。

原因:by 变量在其中一张表里不唯一。merge 遇到一对多时会把多的那几条都匹配上去,行数就翻了。

解决:merge 之前对两张表分别跑一次去重检查,proc sort nodupkey或者proc freq看 by 变量有没有重复值。确实是业务上的一对多,就先在多的那张表里按 by 变量汇总成一条,再 merge。另外 merge 前必须各自排序,不排序会直接报错,不会静默出错,这一点反而好办。

现象四:字符型变量的缺失值用if x = . then判断,永远判不到。

原因:数值缺失是.,字符缺失是空串'',两种类型的缺失表示完全不同。用数值比较去判字符变量,SAS 会做隐式转换,结果不可预测。

解决:统一用missing(x)函数,它对两种类型都有效。批量检查就用第 3 章那段数组程序,别一个个手写。

5.3 环境与输出类翻车

现象五:ODS 生成的 RTF 文件打不开,或者打开是空白。

原因:ods rtf close;没执行。程序中途报错、或者把 close 写在了 run 之前,文件就一直处于打开状态,内容没有落盘。

解决:在程序开头加ods _all_ close;清掉可能残留的输出目标,结尾确认 close 在最后一步 run 之后。养成习惯:只要写了ods xxx file=,写完立刻把对应的 close 补上,再往里填内容。

现象六:昨天建好的数据集今天打开软件就没了。

原因:数据集落在 Work 库,这是临时库,会话结束自动清空。这不是 bug,是设计如此。

解决:建永久逻辑库,用libname指向固定目录,数据集写成库名.数据集名。libname 是会话级的,写进自动执行文件就不用每次手动敲。

还有一个容易被忽略的:proc format定义的格式也存在 work 库,会话结束就丢。跨项目复用的格式要加library=存到永久库,再配options fmtsearch=指定搜索路径,否则第二天运行会报「格式未找到」,而且这个错误经常被当成数据问题查半天。

6. 进阶用法:把清洗程序打包成宏,再用一个小数据集验证它

书里附录提到两件事值得单独拎出来练:一是把重复使用的清洗逻辑写成宏,二是在 SAS 里调用 R 补上统计图形方面的短板。宏这部分最实用,第 3 章那段查缺失的程序,每次改数据集名很烦,包一层就一劳永逸:

%macro miss_report(dsn=, out=); data &out; set &dsn; array nv _numeric_; array cv _character_; miss_n = 0; miss_c = 0; do i = 1 to dim(nv); if missing(nv[i]) then miss_n + 1; end; do i = 1 to dim(cv); if missing(cv[i]) then miss_c + 1; end; drop i; run; %mend; %miss_report(dsn=work.raw, out=work.miss_flag);

&dsn和&out是宏参数,调用时用参数名=传值,宏展开后就是一段普通 data 步。参数名后面留空表示必填,漏传会报错,比传错好。宏定义本身不执行,只登记,%mend结束定义,真正跑起来是最后那行调用。

写完别急着上真实数据,先造一个已知答案的小数据集验证:三行数据、两列数值、一列字符,手动数出应该有 2 个缺失,跑一遍看miss_n加起来是不是 2。答案对不上,说明_numeric_把不该算的 ID 列也包进去了,改成显式列出变量名重新验证。这个习惯看着笨,但比在几万行数据里找差异快得多。

SAS 调 R 的前提是本机装了 R 且版本匹配,启动选项里开启集成后,用proc iml的submit / R; ... endsubmit;块把 R 代码嵌进去,R 侧算完的结果可以回传给 SAS 做后续处理。不同版本开启方式有差异,9.4 常见做法是options RLANG;,较新版本走另一套开关,跑之前先用一句最简单的 R 语句试通,再往上叠逻辑。调不通的时候先怀疑环境,不要怀疑代码,这一步的顺序搞反会浪费一整天。

从那以后我每次拿到一份新数据,第一件事永远是先跑一遍缺失检查和重复检查,再谈分析和作图。这两步花不了五分钟,但能挡掉后面百分之八十的返工。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表