伪代码转换为SAS宏代码

时间:2018-03-05 04:56:03

标签: sas sas-macro

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

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

选择不同的变量:进入numVarList,用'from 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每天都在更改每行及其列名:变量,开始,结束,祸患,未更改。我需要更新表customerScore中的列得分,并且得分是根据表Map_num。如果表customerScore中的A列值为688567,那么它是89756< 688567< 897452,那么socre将会更新:得分=得分+( - 1.2)* 3 ......对您来说是否清楚?! 它是我理解的使用SAS宏的嵌套循环。

2 个答案:

答案 0 :(得分:0)

首先让我们从一组有用的数据开始,这样我们就可以使用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;

答案 1 :(得分:0)

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

SQL方式

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

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/id_toolbar_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="scroll|exitUntilCollapsed" />
    </android.support.design.widget.AppBarLayout>

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:elevation="0dp">

            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_scrollFlags="scroll">

                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="100dp"
                    android:background="@color/colorAccent">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:gravity="center"
                        android:text="@string/app_name"
                        android:textColor="@android:color/white"
                        android:textSize="24sp" />
                </FrameLayout>
            </android.support.design.widget.CollapsingToolbarLayout>

        </android.support.design.widget.AppBarLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <android.support.design.widget.AppBarLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <android.support.design.widget.TabLayout
                    android:id="@+id/tab_layout"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:tabSelectedTextColor="#ffffff"
                    app:tabTextColor="#afffffff" />

            </android.support.design.widget.AppBarLayout>

            <ru.kgdev.ecohelper.ui.widget.NoScrollViewPager
                android:id="@+id/view_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </LinearLayout>
    </android.support.design.widget.CoordinatorLayout>
</LinearLayout>

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

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

你应该看到一个宏可以确定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 的不同map_num值,用于构建一个相当冗长的SQL表达式,搜索适当的woe和beta产品以应用于customerScore中的每一行。

宏和SQL更新语句可能类似于

variable

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

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

%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)

检查&#39; mapplication&#39;数据可能有助于诊断错误的map_num数据。