将伪代码转换为 SAS 宏代码

pseudocode into SAS macro code

我不熟悉 SAS 基础和宏语言语法,我的代码总是出错..谁能提供一段我的伪代码的 SAS 宏代码。

1.create 一个宏数组,用于存储 table Map_num;

中所有不同的变量

select 不同的 variable:into numVarList 由 Map_num 分隔;

退出;

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

(1)拿起第i个元素

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

(3)如果客户的价值(来自customerScore table)在"start"和"end"的范围内,则更新score=score+woe*beta

例如:

customerScore table 是:

+--------+--------+---------+---------+----------+---------+---------+---------+---------+---------+---------+---------+-------+
| 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 |
+--------+--------+---------+---------+----------+---------+---------+---------+---------+---------+---------+---------+-------+

如果table低于Map_num,则cst_id得分为update:score=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 |
+----------+------------+------------+------+------+

如果table低于Map_num,则cst_id得分为update:score=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 |
+----------+------------+------------+-----+------+

提前致谢!

table customerScore 和 Map_num 每一行和它们的列每天都在变化 name:variable,start,end,woe,beta 不需要 changed.I 更新table customerScore 中的列得分,得分是根据 table Map_num.If table customerScore 中的列 A 值是 688567,所以它是 89756 <688567<897452,所以socre 将是 update:score=score+(-1.2 )* 3...你明白了吗?! 据我所知,这是一个使用 SAS 宏的嵌套循环。

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

data cust ;
  input cst_id A B ;
cards;
1 688567   873
2   3198 54667
;
data map_data ;
  input variable :. 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
;

如果要将第一个 table 与第二个合并,则需要转置它。

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;

不幸的是,customerScore 的形式并不适合真正简单的 SQL 计算。

SQL 方式

一个重要的方面是认识到 map_num 中每个得分部分的地图和 woe 的选择可以在 SQL 中相对容易地完成,但是处理单个变量必须 [=37] =] 通过宏

仅考虑第一个 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 进行的分数更新是可逆的(即能够应用撤消操作),则您的数据结构需要做一些工作。

如果跟踪地图选择很重要,您需要在宏中创建一个额外的类似查询,该查询创建一个 table 记录地图数据选择的重要方面

    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 数据。