伪代码转换为SAS宏代码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了伪代码转换为SAS宏代码相关的知识,希望对你有一定的参考价值。

我不熟悉SAS基础和宏语言语法,我的代码一直出错。有人提供了我的伪代码的SAS宏代码。

1.创建一个宏数组来存储表Map_num中的所有不同变量;

选择不同的变量:into numVarList,用''从Map_num中分隔;

放弃;

2.for循环宏数组numVarList并循环每个元素的每个值

(1)拿起第i个元素

(2)for循环第i个元素的所有值,

(3)如果客户的价值(来自customerScore表)在“开始”和“结束”的范围内,那么更新得分=得分+哇* beta

例如:

customerScore表是:

+--------+--------+---------+---------+----------+---------+---------+---------+---------+---------+---------+---------+-------+
| cst_id |   A    |    B    |    C    |    D     |    E    |    F    |    G    |    H    |    I    |    J    |    K    | score |
+--------+--------+---------+---------+----------+---------+---------+---------+---------+---------+---------+---------+-------+
|      1 | 688567 |     873 |  134878 |   546546 |    3123 |       6 |    5345 |  768678 |  348957 | -921839 |   -8217 |     0 |
|      2 |   3198 |   54667 | 9789867 | 53456756 |   78978 |    6456 |     645 |     534 |    -219 |   13312 |    4543 |     0 |
|      3 |  35324 | 6456568 |      43 |    56756 |   -8217 |  688567 |     873 |  134878 |      12 |   89173 |  213142 |     0 |
|      4 | 348957 | -921839 |   -8217 |     5345 |  434534 |    3198 |   54667 | 9789867 |   -8217 |   -8217 | 8908102 |     0 |
|      5 |   -219 |   13312 |    4543 |     4234 |   54667 |   35324 | 6456568 |      43 |  213142 |  213142 |     213 |     0 |
|      6 |     12 |   89173 |  213142 |    23234 |  348957 | -921839 |   -8217 |  688567 |     873 |  134878 |   23424 |     0 |
|      7 | 688567 |   89173 |  213142 |    -8217 |    -219 |   13312 |    4543 |    3198 |   54667 | 9789867 |    3434 |     0 |
|      8 |   3198 |   -8217 |   21313 |    -8217 |      12 |   89173 |  213142 |   35324 | 6456568 |      43 |    3123 |     0 |
|      9 |  35324 |   -8217 |  688567 |   688567 |     873 |  134878 |  688567 |     873 |  134878 |   -8217 |      11 |     0 |
|     10 | 348957 |   89173 |  213142 |     3198 |   54667 | 9789867 |    3198 |   54667 | 9789867 |   -8217 |    3198 |     0 |
|     11 |   -219 | -921839 |   -8217 |    35324 | 6456568 |      43 |   35324 | 6456568 |      43 | -921839 |   -8217 |     0 |
|     12 |     12 |   13312 |    4543 |    89173 |    4234 |    3198 |  688567 |     873 |  134878 |   13312 |    4543 |     0 |
|     13 |     12 |   89173 |  213142 |   348957 | -921839 |   -8217 |    3198 |   54667 | 9789867 |   89173 |  213142 |     0 |
|     14 |      2 |   89173 |  213142 |     -219 |   13312 |    4543 |   35324 | 6456568 |      43 |   54667 |    4543 |     0 |
|     15 | 348957 | -921839 |   -8217 |       12 |   89173 |  213142 |   13312 |    4543 |   89173 |    4234 |    4543 |     0 |
|     16 |   -219 |   13312 |   35324 |  6456568 |      43 |  213142 |   89173 |  213142 |  348957 | -921839 |   -8217 |     0 |
|     17 |     12 |   89173 | -921839 |    -8217 |  688567 |     873 |   89173 |  213142 |    -219 |   13312 |    4543 |     0 |
|     18 | 688567 |     873 |   13312 |     4543 |    3198 |   54667 | -921839 |   -8217 |      12 |   89173 |  213142 |     0 |
|     19 |   3198 |   54667 | 9789867 |   688567 |     873 |  134878 |      43 |  213142 |  213142 |     213 | 9789867 |     0 |
|     20 |  35324 | 6456568 |      43 |       43 |  213142 |  213142 |     213 |   89173 |    4234 |    3198 |  688567 |     0 |
+--------+--------+---------+---------+----------+---------+---------+---------+---------+---------+---------+---------+-------+

如果表Map_num在下面,则cst_id得分更新:得分= 0 +( - 1.2)* 3 + 2 * 3 +(0.1)* 3 + 7 * 3

+----------+------------+------------+------+------+
| variable |   start    |    end     | woe  | beta |
+----------+------------+------------+------+------+
| A        | -999999999 |      57853 |   -1 |    3 |
| A        |      57853 |      89756 | -1.1 |    3 |
| A        |      89756 |     897452 | -1.2 |    3 |
| A        |     897452 | 9999999999 | -1.3 |    3 |
| B        | -999999999 |       4235 |    2 |    3 |
| B        |       4235 |      65785 |    3 |    3 |
| B        |      65785 | 9999999999 |    4 |    3 |
| C        | -999999999 |       9673 |  3.1 |    3 |
| C        |       9673 |      75341 |  2.1 |    3 |
| C        |      75341 |      98543 |  1.1 |    3 |
| C        |      98543 |     567864 |  0.1 |    3 |
| C        |     567864 | 9999999999 |   -1 |    3 |
| D        | -999999999 |       8376 |    5 |    3 |
| D        |       8376 |      93847 |    6 |    3 |
| D        |      93847 | 9999999999 |    7 |    3 |
+----------+------------+------------+------+------+

如果表Map_num在下面,则cst_id得分更新:得分= 0 + 3 * 2 + 5 * 2 + 0 * 2 + 7 * 2 + 3 * 2

+----------+------------+------------+-----+------+
| variable |   start    |    end     | woe | beta |
+----------+------------+------------+-----+------+
| E        | -999999999 |          3 |   1 |    2 |
| E        |          3 |     500000 |   3 |    2 |
| E        |     500000 |     800000 |   2 |    2 |
| E        |     800000 | 9999999999 |   4 |    2 |
| A        | -999999999 |       6700 |   6 |    2 |
| A        |     590000 |     680000 |   4 |    2 |
| A        |     680000 | 9999999999 |   5 |    2 |
| C        | -999999999 |      89678 |   9 |    2 |
| C        |      89678 |     566757 |   0 |    2 |
| C        |     566757 |     986785 | 2.8 |    2 |
| C        |     986785 | 9999999999 | 1.1 |    2 |
| K        | -999999999 |       7865 |   7 |    2 |
| K        |       7865 |      25637 |   9 |    2 |
| K        |      25637 |      65742 |   8 |    2 |
| K        |      65742 | 9999999999 | 0.2 |    2 |
| B        | -999999999 |      56753 |   3 |    2 |
| B        |      56753 |    5465624 |   4 |    2 |
| B        |    5465624 | 9999999999 |   1 |    2 |
+----------+------------+------------+-----+------+

提前致谢!

表customerScore和Map_num每天都在更改每行及其列名:变量,开始,结束,呃,beta都没有更改。我需要更新表customerScore中的列分数,分数是根据表Map_num.If列表customerScore中的值为688567,因此它是89756 <688567 <897452,因此socre将更新:score = score +( - 1.2)* 3 ...对您来说是否清楚?!它是我理解的使用SAS宏的嵌套循环。

答案

不幸的是,customerScore不是一种容易与简单的SQL计算对齐的形式。

SQL方式

一个重要的方面是从map_num中识别出每个得分部分的地图和祸害的选择可以在SQL中相对容易地完成,但处理各个变量必须通过宏“哄骗”

仅考虑第一个map_num中的变量A作为示例。

select (
  map_num.woe * map_num.beta 
  from map_num  
  where map_num.variable="A"
    and map_num.start < customerScore.A <= mapnum.end
 ) as A_contribution_to_score
from 
  customerScore

现在考虑添加到整个表达式的B贡献

select (
  map_num.woe * map_num.beta 
  from map_num  
  where map_num.variable="A"
    and map_num.start < customerScore.A <= mapnum.end
  )
+ 
select (
  map_num.woe * map_num.beta 
  from map_num  
  where map_num.variable="B"
    and map_num.start < customerScore.B <= mapnum.end
  )
from 
  customerScore

您应该看到一个宏可以确定variable的不同map_num值,用于构建一个相当冗长的SQL表达式,该表达式搜索适当的woe和beta产品以应用于customerScore中的每一行。

宏和SQL更新语句可能是这样的

%macro updateScore (data=, map=);

  %local i n_var;

  proc sql noprint;
    select distinct variable into :variable1- from &map;
    %let N_var = &sqlobs;

    update &data as OUTER
    set score = score
    %do I = 1 %to &N_var;
      %let variable = &&variable&i;
      +
      ( select 
        INNER.woe * INNER.beta
        from &map as INNER
        where INNER.variable="&variable"
          and INNER.start < OUTER.&variable <= INNER.end
      )
    %end;
    ; /* end of update statement */
  quit;
%mend;

%updateScore(data=customerScore, map=map_num)

如果您希望通过map_num进行的分数更新是可逆的(即能够应用撤消操作),则您的数据结构需要一些工作。

如果跟踪地图选择很重要,您可能需要宏中的其他类似查询,以创建记录地图数据选择的重要方面的表

    create table mapplication as 
    select cst_id
    %do I = 1 %to &N_var;
      %let variable = &&variable&i;
      %let innerness = from &map as INNER where INNER.variable="&variable" and INNER.start < OUTER.&variable <= INNER.end;
      , &variable
      , ( select INNER.woe &innerness ) as &variable._woe
      , ( select INNER.beta &innerness ) as &variable._beta
      , ( select INNER.start &innerness ) as &variable._start
      , ( select INNER.end &innerness ) as &variable._end
    %end;
    from &data as OUTER;

检查'mapplication'数据可能有助于诊断错误的map_num数据。

另一答案

首先让我们从一组有用的数据开始,这样我们就可以使用SAS代码。

data cust ;
  input cst_id A B ;
cards;
1 688567   873
2   3198 54667
;
data map_data ;
  input variable :$32. start end woe beta ;
cards;
A  -999999999      57853   -1  3
A       57853      89756 -1.1  3
A       89756     897452 -1.2  3
A      897452 9999999999 -1.3  3
B  -999999999       4235    2  3
B        4235      65785    3  3
B       65785 9999999999    4  3
;

如果要将第一个表与第二个表合并,则需要对其进行转置。

proc transpose data=cust out=cust_data(rename=(col1=value)) name=variable  ;
  by cst_id ;
run;

我们的小例子的结果看起来像这样。

Obs    cst_id    variable     value
 1        1         A        688567
 2        1         B           873
 3        2         A          3198
 4        2         B         54667

由于转置已将变量名称移动到数据值而不是元数据值,因此我们现在可以轻松地将客户数据与地图数据相关联。

我假设你只想要变量值落在STARTEND变量之间的情况。

proc sql ;
  create table want as 
    select * 
    from cust_data a
    inner join map_data b
    on a.variable = b.variable
    and a.value between b.start and b.end 
    order by 1,2
  ;
quit;

对于这个小样本,这将是这些数据。

Obs    cst_id    variable     value         start      end      woe    beta
 1        1         A        688567         89756    897452    -1.2      3
 2        1         B           873    -999999999      4235     2.0      3
 3        2         A          3198    -999999999     57853    -1.0      3
 4        2         B         54667          4235     65785     3.0      3

此时,如果您可以解释公式是什么,那么您现在可以使用某些内容来计算分数。

因此,假设您想要获取WOE * BETA的总和,那么您的SQL查询应该看起来像这样。

proc sql ;
  create table scores as 
    select a.cst_id,sum(woe*beta) as score 
    from cust_data a
    inner join map_data b
    on a.variable = b.variable
    and a.value between b.start and b.end 
    group by 1
    order by 1
  ;
quit;

哪个有这个结果。

Obs    cst_id    score
 1        1       2.4
 2        2       6.0

不确定宏代码或循环可以帮助解决这个问题。如果输入数据集的名称不同,则可以使用宏变量来保存名称,但输入数据集名称在此代码中仅使用一次。

例如,您可以创建宏变量CUST,MAP和OUT。

%let cust=work.cust;
%let map=work.map_data;
%let out=work.scores;

然后用宏变量引用替换代码中的数据集名称。

proc transpose data=&cust. out=cust_data(rename=(col1=value)) name=variable  ;
  by cst_id ;
run;
proc sql ;
  create table &out. as 
    select a.cst_id,sum(woe*beta) as score 
    from cust_data a
    inner join &map. b
    on a.variable = b.variable
    and a.value between b.start and b.end 
    group by 1
    order by 1
  ;
quit;

以上是关于伪代码转换为SAS宏代码的主要内容,如果未能解决你的问题,请参考以下文章

SAS:使用热键执行 SAS 代码

我想将此代码从 SAS 转换为 ECL(HPCC)

在宏内部使用变量内部数据集名称时,SAS语法错误22和200

SAS代码错误地将宏变量的值作为输出中的新列/变量传递

SAS:包括输出中的宏参考? [重复]

SAS Proc Datasets - 使用宏变量更改数据集名称