画笔寻枝遍

V1

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 + 1for _ in range(n + 1)]
ans = []
for i in range(17):  
    dice[1][i] = 1  # 初始化公式
for i in range(2, n + 1):  #  n 枚骰子
    for j in range(i, 6 * i + 1): 
        for k in range(17):
            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

画笔寻枝遍,奈何秋风剪。


欢迎扫码关注

分类:

其他

标签:

医学

作者介绍

画笔寻枝遍
V1