画笔寻枝遍
2022/11/12阅读:79主题:橙心
杂谈1
微信公众号:奈何秋风剪。 本人为拖延症晚期患者,欢迎一起交流学习。有任何问题或建议,请公众号留言。
SAS和Python学习记录 (一)
1. 为什么突然开这个公众号?
纯属心血来潮。之前统计软件接触SAS比较多(SPSS:那我呢,ZN!),确实体会到了SAS在医药和金融数据处理领域的冷门强大,但是毕竟是付费软件,万一毕业没能找到相关工作,那就凉凉了。于是本人抱着求稳心态,在自学Python。作为一名拖延症和懒癌晚期患者,自学真是一件痛苦的事情。之前SAS还能和某人一起互相监督学习,现在某人忙于其他事,我深感没什么动力......
So,我开了这个公众号,准备开个专栏,分享一些我日常SAS和Python(统计:那我呢,ZN!)的学习心得,和大家分享交流,也以此督促自己不断实践、学习进步。不然完全躺平了,等毕业时候估计就被卷死了。
2. 公众号推送主要是什么主题?
按照我目前较为粗浅的规划,学习Python过程中,我会将其和SAS做对比。比如实现某个具体功能,SAS和python有什么异同?有什么是Python能做到,SAS做不到的?(这多了去了啊哈哈哈)有什么是SAS实现比较方便的?之前学习的SAS代码怎么用Python复现?诸如此类。此外,单纯的SAS/python/统计相关学习心得也在考虑范围内。 当然,既然有了公众号,偶尔可能更新和某人的日常生活也不是没可能。
3. 本期推送主要内容是啥?
本期推送的内容可以概括为:论Python和SAS做简单算法题 Python的学习,我主要使用的是教程是:Python - 100天从新手到大师。刚入门是从最简单的循环、分支、数学运算等学起的,练习题包括了一些简单的数学题。看着这些题目,我就会不自觉地思考,这用SAS可以实现吗?于是就有了本期推送。 接下来就以几道简单的题目为例子,分别用Python和SAS实现。
斐波那契数列
斐波那契数列(Fibonacci sequence),这就不用多描述了吧,简简单单。
Python
#生成斐波那契数列的前N个数。
n = int(input('请输入N'))
a = 0
b = 1
for _ in range(n):
a, b = b, a + b
print(a, end=' ')
运行结果
SAS
不得不吐槽一番,没有针对SAS的代码块主题,所以没有语法高亮,凑合看吧。
%macro fibonacci(n=);
data Fibonacci;
format order 8. fib_num best12.;
retain fib_num 1 x 0;
do order=1 to &n;
x=lag(fib_num);
if order le 2 then
fib_num=1;
else fib_num=x+fib_num;
output;
end;
drop x;
run;
proc print;
run;
%mend;
%fibonacci(n=20);
结果
正整数反转
实现将一个正整数反转,例如:将12345变成54321。
Python
orig_n = int(input('请输入一个正整数:'))
rever_n = 0
while orig_n > 0:
rever_n = rever_n * 10 + orig_n % 10
orig_n // = 10
print(rever_n)
结果
SAS
*方法一:和Python一样的思路;
%macro reverse(orig_n=);
data reversed;
orig_n=&orig_n;
run;
data reversed;
set reversed;
retain revers_n 0 orig_n;
do while(orig_n gt 0);
revers_n=revers_n*10+mod(orig_n,10);
orig_n=round(orig_n,10)/10;
output;
end;
run;
proc sql;
select max(revers_n) as reversed_n format best12.
from reversed;
quit;
%mend;
%reverse(orig_n=342454568);
*方法二:直接利用reverse函数(SAS的data步,数值变量可以自动转成字符变量);
%macro reverse(orig_n=);
data reverse;
a=&orig_n;
revers_n=input(reverse(a),best12.);
drop a;
run;
proc print;
run;
%mend;
%reverse(orig_n=342454568);
结果
看代码长度就知道,SAS因为以数据集(dataset)为操作对象,是不好弄这些东西的......
剑指Offer 60: 骰子点数和
题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。 这道题目是我前段时间遇到的,难点不在于怎么用程序实现,而在于解题思路。简单来说,就是把n个骰子分成n-1个骰子和一个骰子,比如5个骰子,和为10,那么就是在第五个骰子是1-6的情况下,前四个骰子和为9-4的可能性。一个公式概括:记 为n个骰子时点数总和s出现的次数。则有:
其中 ,且有初始状态 。废话不多说,直接程序求解。
Python
n=int(input('请输入'))
dice = [[0] * (6 * n + 1) for _ in range(n + 1)]
ans = []
for i in range(1, 7):
dice[1][i] = 1 # 初始化公式
for i in range(2, n + 1): # n 枚骰子
for j in range(i, 6 * i + 1):
for k in range(1, 7):
if j > k:
dice[i][j] += dice[i-1][j-k] # 求 n 枚骰子之和
total = 6 ** n # 点数的总次数
for j in range(n, 6 * n + 1): # 求每个点数出现的概率
ans.append([j, dice[-1][j] / total])
print(ans) # 输出s对应的概率
结果
SAS
%macro dice_sum(n=);
*初始化状态;
data dice_sum;
array dice{*} dice1-dice&n;
do total=1 to 6*&n;
if total<=6 then
do;
dice1=1;
output;
end;
else
do;
dice1=0;
output;
end;
end;
run;
*利用数组和lag函数计算;
data dice_sum;
set dice_sum;
array dice{*} dice1-dice&n;
do i=2 to &n;
tmp=lag(dice{i-1});
tmp2=lag2(dice{i-1});
tmp3=lag3(dice{i-1});
tmp4=lag4(dice{i-1});
tmp5=lag5(dice{i-1});
tmp6=lag6(dice{i-1});
if total lt i then dice{i}=.;
if total=i then dice{i}=1;
if total=i+1 then dice{i}=tmp+tmp2;
if total=i+2 then dice{i}=tmp+tmp2+tmp3;
if total=i+3 then dice{i}=tmp+tmp2+tmp3+tmp4;
if total=i+4 then dice{i}=tmp+tmp2+tmp3+tmp4+tmp5;
if total ge i+5 then dice{i}=tmp+tmp2+tmp3+tmp4+tmp5+tmp6;
end;
prob=dice&n./(6**(&n.));
if not missing(prob);
format prob percent8.2;
drop i tmp--tmp6 dice1-dice%sysevalf(&n.-1);
run;
proc print;
run;
%mend;
%dice_sum(n=4);
结果
总结
总的来说,同样的思路,SAS想要实现,确实大多都更为复杂一些。尤其是骰子问题,在sas里实现递归太麻烦了,因为SAS是一条一条观测进行运算的,除非指定了retain语句,不然变量的值无法保留到下一行观测。而且SAS的 函数也是个大坑,刚学习时候总天真以为它就是用来获取变量前n个赋值的神器。后来深入了解才知道,它仅仅是返回上一次LAG函数运行时的实参。即 。听起来有点绕,但是呢,一般来说,简单理解为滞后n阶取值也没有关系......
4. 闲谈
注释太少
本文涉及到的代码注释很少,主要原因是我懒......虽然深知加注释是必须养成的良好习惯,但是一般代码不长的话,都不想加,烦请大家凑合看吧。
排版太丑
虽然经常用秀米做推送排版,但本系列推送会涉及公式和代码,所以随便找了个markdown编辑器就开写了,比较简陋,大家将就看吧。 PS:如果有在排版中支持SAS语法高亮的途径,请教教我这个苦命的孩子,必将感激不尽!!!
下一期?
呃,你能指望一个拖延症晚期患者有一个明确的时间完成一件事吗?
5. The End
画笔寻枝遍,奈何秋风剪。

作者介绍