WYY's Blog

JUST DO IT


  • Home

  • About

  • Tags

  • Categories

  • Archives

风控建模

Posted on 2018-04-17 | In Data Analysis

模型评估指标

混淆矩阵 Confusion matrix

预测1 预测0 合计
实际1 TP(True Positive) FN(False Negative) Actual Positive
实际0 FP(False Positive) TN(True Negative) Actual Negative
合计 Predicted Positive Predicted Negative All
  • Recall(召回率), Sensitivity(敏感性): TP / (TP + FN)
  • Precision(精确率): TP / (TP + FP)
  • Specificity(特异性): TN / (TN + FP)
  • Accuracy(准确率): (TP + TN) / (TP + FP + FN + TN)
  • F值:F-measure = 2 (Recall Precision) / (Recall + Precision)
    • 加权调和平均数,假设Precision和Recall同样重要

ROC和AUC

ROC(Receiver Operating Characteristic)曲线和AUC(Area Under Curve)常被用来评价一个二值分类器(binary classifier)的优劣。

ROC

ROC曲线的横坐标为false positive rate(FPR),纵坐标为true positive rate(TPR)。

FPR = 1- Specificity = FP / N = FP / (TN + FP)

TPR = Recall = Sensitivity = TP / P = TP / (TP + FN)

roc_curve

  • (0,1):FPR=0,TPR=1,即FP和FN都为0,所有分类都正确。
  • (1,0):FPR=1,TPR=0,即FP和FN都为1,所有分类都错误。
  • (0,0):FPR=0,TPR=0,即FP为0,FN为1,所有分类预测为负样本。
  • (1,1):FPR=1,TPR=1,即FP为1,FN为0,所有分类预测为正样本。
  • y=x线上:采用随机分类的分类器。
  • ROC曲线越接近左上角,该分类器性能越好。

ROC曲线的优点:当测试集中的正负样本的分布变化的时候,ROC曲线能够保持不变。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。

AUC

AUC(Area Under Curve)被定义为ROC曲线下的面积。由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围在0.5和1之间。

The AUC value is equivalent to the probability that a randomly chosen positive example is ranked higher than a randomly chosen negative example.

AUC值越大,当前分类算法越可能将正样本排在负样本之前,即能更好的分类。

Lift

Lift = [TP/(TP+FP)] / [(TP+FN)/(TP + FP + TN + FN)]

用于衡量与不利用模型相比,模型预测能力的提升度。Lift越大,模型效果越好。

在不使用模型时(baseline model),需要在整个样本中挑选,挑选的准确率是(TP+FN)/(TP + FP + TN + FN)。

在使用模型时,,只在预测为positive的样例中挑选,挑选的准确率是TP/(TP+FP)。lift

当阈值越大,越少的观测值会归为正例,但这部分越具有正例特征(以银行向客户推荐信用卡的例子来看,这一部分人群对推荐的反应最为活跃),所以在这个设置下,对应的lift值最大。当阈值越小,越多的观测值会归为正例,这时分类的效果就跟baseline model差不多了,相对应的lift值就接近于1。

Gain

增益图与提升图的区别在于纵坐标。它的纵坐标是TP/(TP+FP)。

增益图是描述整体精准率的指标。按照模型预测出的概率从高到低排列,将每一个百分位数内的精准率指标标注在图形区域内,就形成了非累积的增益图。如果对每一个百分位及其之前的精准率求和,并将值标注在图形区域内,则形成累积的增益图。

201800426gain

K-S

正样本洛伦兹曲线记为f(x),负样本洛伦兹曲线记为g(x),K-S曲线实际上是f(x)与g(x)的差值曲线。K-S曲线的最高点(最大值)定义为KS值,KS值越大,模型分值的区分度越好,KS值为0代表是最没有区分度的随机模型。准确的来说,K-S是用来度量阳性与阴性分类区分程度的。

K-S曲线的纵坐标是TPR与FPR。

20180426k-s

参考资料

ROC和AUC介绍以及如何计算AUC

如何评估一个机器学习模型

人行报告专业版

Posted on 2018-03-20 | In Loan

样本

个人信用报告(银行专业版)样本

基础信息

  • 查询时间:央行系统收到查申请人提出查询申请的时间
  • 报告时间:系统收到查询申请后,生成查询人的信用报告的时间
  • 账户数:名下分别有几个信用卡账户、几笔住房贷款、几笔其他贷款
  • 未销户账户数:查询人名下未销户(含正在使用和尚未激活)的信用卡账户数量
  • 未结清账户数:查询人名下未结清住房贷款和其他贷款的账户数量
  • 透支余额:准贷记卡欠银行钱的数量(包含本金和利息)
  • 已使用额度:贷记卡欠银行钱的数量(包含本金和利息)
  • 逾期金额:截至还款日的最后期限,仍未按时或足额偿还的金额,以及由此产生的利息(含罚息)和费用(包括超限费和滞纳金)
  • 公共记录:含最近5年内的欠税记录、法院民事判决记录、强制执行记录、行政处罚记录、电信欠费记录
  • 查询记录:何机构或何人在何时以何种理由查询过此人的信用报告

进阶信息

账户数

账户数不等同于信用卡张数,而是等于信用卡记录数

同币种信用卡合并显示

民生银行(持有十张卡)

  • 都是人民币账户:信用报告上显示1条关于民生银行信用卡的记录
  • 都是双币账户:信用报告上显示2条关于民生银行信用卡的记录
  • 都是N币账户:信用报告上显示N条关于民生银行信用卡的记录

同币种信用卡不合并显示

工商银行(持有十张卡):

  • 都是人民币账户:信用报告上显示10条关于工商银行信用卡的记录
  • 都是双币账户:信用报告上显示20条关于工商银行信用卡的记录
  • 都是N币账户:信用报告上显示N0条关于工商银行信用卡的记录

合并账单

广发银行(持有十张卡):

显示为1条信用记录,包含10张卡的消费记录,10张卡的账单日和还款日一致

不合并账单

中国银行(持有十张卡):

显示为10条信用记录,每条包含1张卡的消费记录,10张卡的账单日和还款日可以不一致

还款不需要每张卡分别还

浦发银行(持有十张卡):

还款只需要还其中1张即可,还清了其中1张卡的账单,即还清所有卡的账单了。

###还款需要每张卡分别还

农业银行(持有十张卡):

还款需要还每一张的信用卡,把每一张信用卡的账单都还清,才还清所有卡的账单。

报告的延迟性

  • 如果某人申请了新的信用卡,或者办理了新的贷款,信报上并不会第一时间显示出查询记录、信用卡记录、贷款记录
  • 信用卡的已使用额度和账单并不是实时的,一般银行会每一个月或者每两个月上报数据,也就意味着个人征信报告的信用卡数据一般一到两个月更新一次。
  • 银行贷款和其他贷款机构的贷款记录一般会在1个星期甚至1个月以上的时间才会上报,并在信报上体现出来。

中文地址清洗

Posted on 2017-11-21 | In Loan

中文分词的基本原则

  • 颗粒度越大越好

分词结果的颗粒度越大(即单词的字数越多),所能表示的含义越确切。如:“公安局长”可以分为“公安 局长”、“公安局 长”、“公安局长”,但是要用于语义分析,则“公安局长”的分词结果最好(前提是所使用的词典中有这个词)。

  • 切分结果中非词典词越少越好,单字词典词数越少越好
    • 非词典词:不包含在词典中的单字
    • 单字词典词:可以独立运用的单字,如:的、了、和、你、我、他

如:“技术和服务”,可以分为“技术 和服 务”以及“技术 和 服务”。“务”字无法独立成词(即词典中没有),但“和”字可以单独成词(词典中要包含),因此“技术 和服 务”有1个非词典词,而“技术 和 服务”有0个非词典词,因此选用后者。

  • 总体词数越少越好

在相同字数的情况下,总词数越少,说明语义单元越少,那么相对的单个语义单元的权重会越大,因此准确性会越高。

匹配算法

最大匹配算法

最大匹配是指以词典为依据,取词典中最长单词为第一个次取字数量的扫描串,在词典中进行扫描(为提升扫描效率,还可以跟据字数多少设计多个字典,然后根据字数分别从不同字典中进行扫描)。例如:词典中最长词为“中华人民共和国”共7个汉字,则最大匹配起始字数为7个汉字。然后逐字递减,在对应的词典中进行查找。

正向最大匹配算法

以“我们在野生动物园”为例,词典中最长词为“中华人民共和国”。

正向即从前往后取词,从7->1,每次减一个字,直到词典命中或剩下1个单字。

第1轮第1次:7字词典中扫描“我们在野生动物”,无;

第1轮第2次:6字词典中扫描“我们在野生动”,无;

第1轮第3次:5字词典中扫描“我们在野生”,无;

第1轮第4次:4字词典中扫描“我们在野”,无;

第1轮第5次:3字词典中扫描“我们在”,无;

第1轮第6次:2字词典中扫描“我们”,有;

扫描中止,输出第1个词为“我们”,去除第1个词后开始第2轮扫描。

第2轮第1次:7字词典中扫描“在野生动物园玩”,无;

第2轮第2次:6字词典中扫描“在野生动物园”,无;

第2轮第3次:5字词典中扫描“在野生动物”,无;

第2轮第4次:4字词典中扫描“在野生动”,无;

第2轮第5次:3字词典中扫描“在野生”,无;

第2轮第6次:2字词典中扫描“在野”,有;

扫描中止,输出第2个词为“在野”,去除第2个词后开始第3轮扫描。

第3轮第1次:5字词典中扫描“生动物园玩”,无;

第3轮第2次:4字词典中扫描“生动物园”,无;

第3轮第3次:3字词典中扫描“生动物”,无;

第3轮第4次:2字词典中扫描“生动”,有;

扫描中止,输出第3个词为“生动”,去除第3个词后开始第4轮扫描。

第4轮第1次:3字词典中扫描“物园玩”,无;

第4轮第2次:2字词典中扫描“物园”,无;

第4轮第3次:1字词典中扫描“物”,无;

扫描中止,输出第4个词为“物”,非词典词数加1,去除第4个词后开始第5轮扫描。

第5轮第1次:2字词典中扫描“园玩”,无;

第5轮第2次:1字词典中扫描“园”,有;

扫描中止,输出第5个词为“园”,单字词典词数加1,去除第5个词后开始第6轮扫描。

第6轮第1次:1字词典中扫描“玩”,有;

扫描中止,输出第6个词为“园”,单字词典词数加1,扫描结束。

最终切分结果为:“我们/在野/生动/物/园/玩”,其中,单字词典词数为2,非词典词数为1。

逆向最大匹配算法

以“我们在野生动物园”为例,词典中最长词为“中华人民共和国”。

逆向即从后往前取词,从7->1,每次减一个字,直到词典命中或剩下1个单字。

第1轮第1次:7字词典中扫描“在野生动物园玩”,无;

第1轮第2次:6字词典中扫描“野生动物园玩”,无;

第1轮第3次:5字词典中扫描“生动物园玩”,无;

第1轮第4次:4字词典中扫描“动物园玩”,无;

第1轮第5次:3字词典中扫描“物园玩”,无;

第1轮第6次:2字词典中扫描“园玩”,无;

第1轮第7次:1字词典中扫描“玩”,有;

扫描中止,输出第1个词为“玩”,单字词典词数加1,去除第1个词后开始第2轮扫描。

第2轮第1次:7字词典中扫描“们在野生动物园”,无;

第2轮第2次:6字词典中扫描“在野生动物园”,无;

第2轮第3次:5字词典中扫描“野生动物园”,有;

扫描中止,输出第2个词为“动物”,去除第2个词后开始第3轮扫描。

第3轮第1次:3字词典中扫描“我们在”,无;

第3轮第2次:2字词典中扫描“们在”,无;

第3轮第3次:1字词典中扫描“在”,有;

扫描中止,输出第3个词为“玩”,单字词典词数加1,去除第3个词后开始第4轮扫描。

第4轮第1次:2字词典中扫描“我们”,有;

扫描中止,输出第4个词为“我们”,扫描结束。

最终切分结果为:“我们/在/野生动物园/玩”,其中,单字词典词数为2,非词典词数为0。

双向最大匹配算法

正向、逆向两种算法都切一遍,然后根据大颗粒度词越多越好,非词典词和单字词越少越好的原则,选取其中一种分词结果输出。

  • 非词典词数:越少越好
  • 单字词典词数:越少越好
  • 总词数:越少越好

《SAS编程演义》笔记(9-10章)

Posted on 2017-09-25 | In SAS

拙中藏巧混天成:统计表格

医药科研

  • 基线信息表格:介绍人群基本情况
  • 危险因素表格:会在表格中给出事件频数和百分比、粗的效应值及其95%CI和P值
  • 结局效应表格:横款目为终点指标,纵款目除了分组信息,还有效应量
  • 亚组分析表格:最重要的信息是需要提供交互作用校验的结果,通常以森林图的形式展示

统计汇总过程

一个统计过程中只能获得一种变量(分类、连续)的统计数据,款目形式不便统一。

  • RTF(Rich Text File)可直接用Word打开编辑
  • journal3a是最贴近三线表的样式
1
2
3
4
5
6
7
8
9
10
11
12
ods tagsets.rtf file="table.rtf" style=journal3a; /**/
proc freq data=sashelp.heart;
table bp_status*sex / nopercent norow;
run;
ods tagsets.rtf close;
ods tagsets.etf file="table2.rtf" style=journal3a;
proc means data=sashelp.heart mean std maxdec=2;
class sex;
var height;
run;
ods tagsets.rtf close;

PROC TABULATE

能一次性实现多种变量的统计需求,也能比较灵活的组合表格形式,但是仍达不到标准三线表的要求,而且也无法计算统计量和P值。

  • CLASS语句申明分类变量
  • VAR语句申明分析变量
  • TABLE语句设置表格形式,逗号“,”作为页、行、列等纬度的间隔符,星号“*”作为变量与其显示格式、统计关键字的关联符,括号“()”用来强制分组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ods tagsets.rtf file="table4.rtf" style=journal3a;
title "Table 1. Blood Pressure and Height by Sex";
proc tabulate data=sashelp.heart;
class sex bp_status;
var height;
table sex, bp_status*(n rowpctn) height*(mean std);
run;
ods tagsets.rtf cloase;
ods tagsets.rtf file="table5.rtf" style=journal3a;
title "Table 1. Blood Pressure and Height by Sex";
proc tabulate data=sashelp.heart;
class sex bp_status;
var height;
table bp_status*(n colpctn) height*(mean std), sex;
run;
ods tagsets.rtf cloase;

PROC REPORT

纵款目无法用分组变量,横款目值没有缩进,统计变量之间没有连字符,无法获得检验统计量和P值。

1
2
3
4
5
6
7
8
9
10
ods tagsets.rtf file="table6.rtf" style=journal3a;
ods escapechar='^';
title "Table 6, Height and Weight by Gender";
proc report data=sashelp.class nowd;
column sex height, ("^R'\brdrb\brdrs'" mean std) weight, ("^R'\brdrb\brdrs'" mean std);
define sex/group;
define height/analysis format=5.2;
define weight/analysis format=5.2;
run;
ods tagsets.rtf close;

完美三线图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*1 血压状态数据整理*/
/*1.1 获取频数百分比*/
proc freq data=sashelp.heart;
table bp_status*sex /missing nopercent outpct out=desc1;
run;
data desc1;
set desc1;
length value $25;
value = compress(put(count, 6.)) || ' (' || compress (put(pct_col, 4.1)) ||')';
run;
/*1.2 转置,性别作为列*/
proc transpose data=desc1 out=desc1(drop=_name_) prefix=col;
var value;
by bp_status;
id sex;
run;
/*1.3 获取卡方检验P值*/
proc freq data=sashelp.heart;
table bp_status*sex / norow nocol nopercent chisq;
output out=pvalue1(keep=p_pchi rename=(p_pchi=pvalue)) pchi;
run;
/*1.4 合并变量标签,描述数据,P值*/
data dslabel1;
set pvalue1;
length label $ 85;
label=cats("^S={font_weight=bold}", "Blood presure status"); /*RTF代码,加粗标签*/
run;
data merge1(keep=label col: pvalue);
set dslabel1 desc1;
if _n_>1 then label="^{nbspace 6}" || bp_status; /*RTF代码,增加缩进*/
run;
/*2 身高数据整理*/
/*2.1 获取描述数据*/
ods output summary=desc2;
proc means data=sashelp.heart mean std;
class sex;
var height;
run;
data desc2(keep=sex meanstd);
set desc2;
meanstd = cats(put(height_mean,12.1), "±", put(height_stddev,12.1));
run;
/*2.2 转置,性别作为列*/
proc transpose data=desc2 out=desc2 prefix=col;
var meanstd;
id sex;
run;
/*2.3 判断方差齐性,获取t检验p值*/
ods output equality=eql ttests=ttl;
proc ttest data=sashelp.heart plots=non;
class sex;
var height;
run;
data pvalue2(keep=Probt rename=(Probt=Pvalue));
retain equV;
set eql ttl;
if ProbF<0.05 then equV=0;
else equV=1;
if (equV=1 and variances="Equal") or (equV=0 and variances="Unequal");
run;
/*2.4 合并变量标签,描述数据,p值*/
data merge2(keep=label col: pvalue);
length label $85;
merge desc2 pvalue2;
label=cats("^S={font_weight=bold}", "Height (in)"); /*RTF代码,加粗标签*/
run;
/*3 合并数据*/
data dsreport;
set merge:;
run;
/*4 Report输出*/
options nodate nonumber missing=' ';
ods tagsets.rtf file="table6.rtf" style=journal3a;
ods escapecha='^';
title "Table 1.Blood Presure and Height by Sex";
proc report data=dsreport nowd;
column label colfemale colmale pvalue;
define label / display "Variables";
define colfemale / display "Female" right;
define colmale / display "Male" right;
define pvalue / analysis "P Value" f=pvalue6.4;
run;
footnote1 j=center height=10pt "^{nbspace}Note: This is a demo";
ods tagsets.rtf close;

一缕檀烟万佛名:宏中奥秘

###宏

SAS宏由宏语言和宏处理器构成。宏语言是与宏处理器沟通的语言。宏语言中以&开头的是宏变量,以%开头的是SAS宏程序或宏函数。当SAS遇到&或%开头的宏语言时,便触发宏处理器,执行宏操作。

创建宏变量

  • %LET语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*文本*/
%let bookname1=Romance of SAS Program;
%let bookname2=SAS编程演义;
%let address1=%str(Author%'s address);
%let address2=%nrstr(ShanghaiTech&SMMU);
/*数字*/
%let phone1=13800137000;
%let phone2=;
/*算术表达式*/
%let ex1=99+1;
%let ex2=99.9+0.1;
/*计算算术表达式*/
%let ex3=%eval(99+1);
%let ex4=%sysevalf(99.9+0.1);
/*程序*/
%let prg=%str(proc print data=sashelp.classr;run;);
/*查看结果*/
%put &bookname1 &bookname2 &address1 &address2 &phone1 &phone2 &ex1 &ex2 &ex3 &ex4 &prg;
  • %GLOBAL申明一个全局宏变量(无法赋值),既可以在宏程序内部,也可以在外部。
  • %LOCAL申明一个局部宏变量(无法赋值),只能在宏程序内部。
    • 确保宏程序内部定义的宏变量不会因为同名重写全局宏变量的值
    • 确保宏程序执行完毕后,这些宏变量立即消逝
  • SQL里SELECT语句的INTO从句,可产生一个或一系列宏变量
1
2
3
4
5
6
7
8
9
10
11
/*单个宏变量*/
proc sql noprint;
select count(name) into:nname from sashelp.class;
quit;
%put &nname;
/*宏变量列表*/
proc sql noprint;
select name into:namelist separated by "," from sashelp.class;
quit;
%put &namelist;
  • DATA步的SYMPUT和SYMPUTX(去除首尾空格)语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
/*单个宏变量*/
data _null_;
set sashelp.class end=last;
if last then call symput('nname',_n_);
run;
%put &nname;
/*宏变量列表*/
data _nuul_;
set sashelp.calss;
call symputx(cats('name',_n_),name);
run;
%put &namelist;
  • 宏程序的宏参数会创建局部宏变量
  • %WINDOWS语句
  • 宏程序中的%DO语句
  • ODS OUTPUT语句的MATCH_ALL选项

宏符号表与作用域

宏符号表(Macro Symbol Table)存储着宏变量与其对应的值。

  • 全局宏符号表,SAS启动时,系统自动创建,其中存储的内容有:
    • 系统自带的宏变量和值
    • open code(宏程序外)环境下,用%LET语句创建的宏变量
    • 宏程序定义中,用%GLOBAL申明的宏变量
    • DATA步中CALL SYMPUTX语句中申明了全局符号表
    • PROC SQL中SELECT语句的INTO从句创建的宏变量
  • 局部宏符号表,SAS执行宏程序时,系统自动创建,其中存储的内容有:
    • 由宏程序的宏参数创建的宏变量
    • 宏程序中由%LET定义的宏变量,且在全局宏变量中没有同名宏变量
    • 宏程序中由%LOCAL定义的宏变量
  • 判断是全局还是局部
    • 采用%PUT语句的选项_USER_、_LOCAL_、_GLOBAL_查看符号表
    • 采用系统自带的宏函数%SYMLOCAL、%SYMGLOBAL进行判定
1
2
3
4
5
6
7
8
9
10
11
12
%macro testMacroVar(a=, b=);
%put 所有自定义宏变量;
%put _user_;
%put 所有局部宏变量;
%put _local_;
%put 所有全局宏变量;
%put _global_;
%put sysver是否全局宏变量: %symglobl(sysver);
%put a是否全局宏变量: %symglobl(a);
%put b是否局部宏变量: %symlocal(b);
%mend;
%testMacroVar(a=Stats, b=Thinking)

掩蔽宏变量

掩蔽(masking):将符号当作普通的文本对待,不使用其特殊含义,有的文档也称为引用(quoting)。

  • 需要掩蔽的符号:
    • 运算符:如+ - * / < > = ¬ ^ ~ |
    • 助记符:如 AND OR NOT EQ NE LE LT GE GT IN
    • 其他:bank , ; “ “ ‘ ’ ( ) #
  • 没有配对的符号,如 “ ‘ ( ),使用%B系列的函数掩蔽
  • 宏触发器 & %,使用%NR系列的引用函数
  • 移除掩蔽主要发生在程序编译后、程序运行后、%UNQUOTE函数后

显示宏变量值

  • 系统选项SYMBOLGEN
  • %PUT语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
options symbolgen;
%let title1=SAS编程演义;
%let title2=数据整理与图表呈现;
%let title=&title1.:&title2;
options nosymbolgen;
%let title1=SAS编程演义;
%let title2=数据整理与图表呈现;
%let title=&title1.:&title2;
%put title1和title2合并后的title解析为:&title;
%put _all_; /*显示所有宏变量*/
%put _automatic_; /*显示所有自动宏变量*/
%put _user_; /*显示所有自定义宏变量*/
%put _global_; /*显示所有全局宏变量*/
%put _local_; /*显示所有局部宏变量*/

引用宏变量

  • 直接引用

如果是用宏变量给DATA步变量赋具体的值,需用引号引起来。

1
2
3
4
5
6
%let bookname2017=SAS编程演义;
%let year=2017;
data tmp;
name="&bookname2017";
year=&year;
run;
  • 间接引用

SAS在解析时,会将两个连续的&&解析为一个&,然后再次进行解析,知道&全被解析完

1
2
3
4
5
6
7
8
9
10
11
%let bookname2017=SAS编程演义;
%let year=2017;
data tmp;
name="&bookname&&year";
run;
%let L1=L2;
%let L2=L3;
%put &L1; /*L2*/
%put &&L1; /*&L1 -> L2*/
%put &&&L1; /*&L2 -> L3*/
  • 合并宏变量与普通文本

宏变量后面带一个点号,用以标识宏变量的结束

1
2
3
4
5
6
%let bookname2017=SAS编程演义;
%let lib=sashelp;
data class;
set &lib..class;
bookname="&bookname2017.:数据整理与图表呈现";
run;

宏程序定义与调用

%macro macro_name <parameter_list> </option(s)\>

​ <macro_text>

%mend <macro_name>;

%macro_name <parameter_list>

  • macro_name:宏程序名称,需要符合SAS命名规范,不能以SYS、AF、DM开头,不能用SAS的保留字,以免冲突
  • parameter_list:宏参数,通过宏程序定义的局部变量,便于在宏文本中应用。参数通过逗号隔开
    • 位置宏参数:按位置顺序定义识别 <positional-parameter-1><, positional-parameter-2…>
    • 关键字宏参数:按名字=识别 <keyword-parameter=<value> <, keyword-parameter-2=<value> …>>
  • option(s):比如加密选项secure,存储选项store
  • macro_text:宏文本是宏的主体,里面包括宏语句、DATA步语句、PROC语句等
  • 宏参数不是必需的,位置宏参数和关键字宏参数可以混用,但位置宏参数必须在关键字宏参数前。
  • 宏参数中如有特殊字符如&、%、不配对的括号或引号、其他运算符等,需要做好宏变量的掩蔽。
  • %mend之后的宏程序名非必需。
  • 调用宏程序时,末尾不需要分号结尾。

宏程序的存储加密

如果为了保护知识产权,想给他人使用宏程序但又不希望他人看到自己开发的宏程序源代码,可以将编译好的宏给别人,且设置为不显示宏的源代码。

1
2
3
4
5
6
7
8
9
options mstored sasmstore=demo /*指定存储位置为demo永久库*/
%macro printds(dataset, obs=5) / store;
options nomprint nosource; /*不显示源代码*/
proc print data=&dataset(obs=&obs);
run;
%mend printds;
options mstored sasmstore=demo;
%printds(sashelp.class, obs=5)

%IF-%THEN-%ELSE选择语句

1
2
3
4
5
6
7
8
%macro printds(dataset, sex=F, obs=5,);
%if &sex eq F %then %str(title "First &obs record for female";);
%else %if &sex eq M %then %str(title "First &obs record for male";);
%else %str(title "Wrong gender"; %abort;);
proc print data=&dataset(obs=&obs where=(sex="&sex"));
run;
%medn printde;
%printde(sashelp.class,sex=M,obs=5)

%DO组语句

1
2
3
%do
语句;
%end

%DO循环语句

1
2
3
4
5
6
7
8
%macro importcsv;
%do i=1 %to 100;
proc import out=csv&i datafile="d:\data\casv&i.csv" dbms=csv replace;
run;
%end;
%mend;
%importcsv

%DO-%WHILE语句

1
2
3
4
5
6
7
8
9
10
%macro importcsv;
%let i=1;
%do %while(&i<=100);
proc import out=csv&i datafile="d:\data\casv&i.csv" dbms=csv replace;
run;
%let i=&i+1;
%end;
%mend;
%importcsv

%DO-%UNTIL语句

1
2
3
4
5
6
7
8
9
10
%macro importcsv;
%let i=1;
%do %until(&i>100);
proc import out=csv&i datafile="d:\data\casv&i.csv" dbms=csv replace;
run;
%let i=&i+1;
%end;
%mend;
%importcsv

宏函数

类别 宏函数 作用
字符宏函数 %index 返回字符串第一次出现的位置
%length 返回字符串长度
%scan %qscan 按字符串中的位置截取单词
%substr %qsubstr 截取子字符串
%upcase %qupcase 转为大写字符
计算函数 %eval 使用整数运算计算表达式结果
%sysevalf 使用浮点运算计算表达式结果
引用函数 %str 编译时掩蔽特殊字符及助记符
%nrstr %str 外加宏触发器字符
%quote 执行时掩蔽特殊、助记、其他字符
%nrquote %quote 外加宏触发器字符
%bquote 执行时掩蔽特殊、助记、其他字符和没有配对的符号
%nrbquote %bquote 外加宏触发器字符
%superq 执行时掩蔽所有字符,且对结果保持
%unquote 执行时去掉所有特殊、助记字符的掩蔽
SYS系函数 %sysmacexect 返回宏执行状态
%sysmacexist 判断宏程序是否已经定义
%sysmexecdepth 返回宏嵌套的深度
%sysmexecname 返回指定宏嵌套的深度的宏名称
%sysfunc %qsysfunc 使用data步函数
%sysget 返回环境变量的值
%sysprod 判断SAS产品是否已经授权
SYM系函数 %symexist 判断宏变量是否已经存在
%symglobl 判断是否属于全局宏变量
%symlocal 判断是否属于局部宏变量

宏开发

  1. 硬代码实现:先不用任何宏代码,实现具体的任务
  2. 移除上一步中的硬代码,该用宏变量、宏参数,如有必要,增加宏语句如以及宏函数
  3. 宏代码测试优化:给宏变量赋值,逐步测试宏代码,优化宏代码。

规则引擎与Drools

Posted on 2017-09-19 | In Loan

1 简介

1.1 规则

  • 每条规则都是一组条件决定的一系列结果
  • 一条规则可能与其他规则共同决定最终结果
  • 可能存在条件互相交叉的规则,此时有必要规定规则的优先级

规则作为一种知识,其典型运用就是通过实际情况,根据给定的一组规则,得出结论。这个结论可能是某种静态的结果,也可能是需要进行的一组操作。

规则语言可以分为结构化的(Structured)和基于标记的(Markup,通常为xml)。

常见的结构化的规则描述语言:

  • srl(Structured Rule Language)
  • drl(Drools Rule Language)

常见的基于标记的规则描述语言:

  • RuleML(Rule Markup Language)
  • SRML(Simple Rule Markup Language)
  • BRML(Business Rules Markup Language)
  • SWRL(A Semantic Web Rule Language)

1.2 推理机

运用过程叫做推理。如果由程序来处理推理过程,那么这个程序就叫做推理机/推理引擎(Inference Engine)。推理机是专家系统(专家系统是人工智能的一个分支)的核心模块。

推理引擎根据知识表示的不同采取的控制策略也是不同的,常见的类型包括基于神经网络、基于案例和基于规则的推理机。

1.3 规则引擎

基于规则的推理机易于理解、易于获取、易于管理,被广泛采用。这种推理引擎被称为“规则引擎”。

在规则引擎中,将知识表达为规则(rules),要分析的情况定义为事实(facts)。二者在内存中的存储分别称为Production Memory和Working Memory。

  • rules和facts:规则引擎接受的输入参数
  • Pattern Matcher:根据facts找到匹配的rules
    • 正向推理(Forward-Chaining):正向推理也叫演绎法,由事实驱动,从 一个初始的事实出发,不断地应用规则得出结论。首先在候选队列中选择一条规则作为启用规则进行推理,记录其结论作为下一步推理时的证据。如此重复这个过程,直到再无可用规则可被选用或者求得了所要求的解为止。
    • 反向推理(Backward-Chaining):反向推理也叫归纳法,由目标驱动,首先提出某个假设,然后寻找支持该假设的证据,若所需的证据都能找到,说明原假设是正确的;若无论如何都找不到所需要的证据,则说明原假设不成立,此时需要另做新的假设。
  • Agenda:管理PatternMatcher挑选出来的规则的执行次序
  • Execution Engine:在外围负责根据Agenda输出的rules执行具体的操作

1.4 规则引擎的作用

规则引擎可以将规则的定义从代码中分离出来,将推理过程封装到规则引擎内部进行处理,这带来几个好处:

  • 规则外部化,即有利于规则知识的复用,也可避免改变规则时带来的代码变更问题
  • 由规则引擎使用某种算法进行推理过程,不需要编写复杂晦涩的逻辑判断代码
  • 开发人员的不需要过多关注逻辑判断,可以专注于逻辑处理

2 Drools

DROOLS - SAMPLE DROOLS PROGRAM

2.1 概览

完整的drl文件包含以下几个部分:package,import,declares,globals,functions,queries,rules。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.sample
import com.sample.DroolsTest.Message;
rule "Hello World"
when
m : Message(status == Message.HELLO, myMessage : message)
then
System.out.println(myMessage);
m.setMessage("Goodbye cruel world");
m.setStatus(Message.GOODBYE);
update(m);
end
rule "GoodBye"
when
Message(status==Message.GOODBYE, myMessage:message)
then
System.out.println(myMessage);
end

2.2 package和import

与Java类似,drools头部必须要有一个package声明和import声明,且package声明必须放在规则文件的第一行。

2.3 规则定义

一个规则通常包含三个部分:attribute(属性),LHS(条件部分),RHS(结果部分)。

1
2
3
4
5
6
7
rule "name"
attributes
when
LHS
then
RHS
end

2.3.1 LHS(条件部分)

  • 可以包含多个条件,若条件部分为空的话,引擎自动添加一个eval(true)的条件。
  • 多个条件之间可使用and或or连接,默认是and关系。
  • 条件的语法:[绑定变量名:]\Object([field约束])
    • 绑定变量名:可在该LHS后续的条件中引用
    • field约束:当前对象里相关字段的条件限制,多个约束之间用”&&”(and),”||”(or)和”,”(and)连接。约束中可使用的比较操作符包括:>, >=, <, <=, ==, !=, contains, not contains, memberof, not memberof, matches, not matchers
1
2
3
4
5
6
7
8
9
10
11
12
when
order:Order();
then
...
when
$room : Room( ) #变量名可以是$开头
$sprinkler : Sprinkler( room == $room, on == true )
not Fire( room == $room )
then
modify( $sprinkler ) { setOn( false ) };
System.out.println( "Turn off the sprinkler for room " + $room.getName() );

2.3.2 RHS(结果部分)

  • RHS部分定义了当LHS满足时要进行的操作
  • RHS中可以编写代码,可以使用LHS部分中定义的绑定变量名以及drl头部定义的全局变量。
  • 虽然可以在RHS中直接写java代码,但不建议代码中有条件判断,否则就违背了使用规则的初衷。
2.3.2.1 使用宏函数

RHS中可以使用宏函数对工作空间进行操作。当调用宏函数后,所有为设置“no-loop”属性的规则都会呗重新分配,符合条件的重新触发。

宏函数都是StatefulSession中定义的方法,包括:

  • insert:将一个Fact对象插入到当前的Working Memory
  • update:对当前Working Memory中的Fact进行更新
  • retract:从Working Memory中删除某个Fact对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
when
...
then
Customer cus=new Customer();
cus.setName("张三");
insert(cus);
when
$customer:Customer(name=="张三", age<10)
then
$customer.setAge(customer.getAge()+1);
update(customer);
when
$customer:Customer(name=="张三",age<10)
then
Customer customer=new Customer();
customer.setName("张三");
customer.setAge($customer.getAge()+1);
# 用新对象替换Working Memory中的旧对象
update(drools.getWorkingMemory().getFactHandleByIdentity($customer),customer);
when
$customer:Customer(name=="张三")
then
retract($customer);
2.3.2.2 modify代码块

modify代码块用于快速修改并更新(update)某个 Fact 对象的多个属性。

1
2
3
4
5
6
7
8
9
10
11
12
modify(fact-expression){
<修改 Fact 属性的表达式>[,<修改 Fact 属性的表达式>*]
}
when
$customer:Customer(name=="张三",age==20);
then
modify($customer){
setId("super man"),
setAge(30)
}
2.3.2.3 drools宏对象

通过使用drools宏对象可以实现在规则文件里直接访问 Working Memory,从而获取对当前的 Working Memory的更多控制。

drools宏对象的常用方法包括:

  • drools.getWorkingMemory():获取当前的 WorkingMemory对象
  • drools.halt():在当前规则执行完成后,不再执行 其它未执行的规则
  • drools.getRule():得到当前的规则对象
  • drools.insert(new Object):向当前的WorkingMemory 当中插入指定的对象,功能与宏函数insert相同
  • drools.update(new Object):更新当前的WorkingMemory中指定的对象,功能与宏函数update相同
  • drools.update(FactHandle Object):更新当前的WorkingMemory中指定的对象,功能与宏函数update相同
  • drools.retract(new Object):从当前的WorkingMemory中删除指 定的对象,功能与宏函数retract相同
2.3.2.4 kcontext宏对象

用来得到当前的KnowledgeRuntime对象,KnowledgeRuntime对象可以实现与引擎的各种交互。

2.3.3 规则属性

  • salience:设置规则执行的优先级,默认值为0。数字越大越先执行,可以设置为负数,数字相同的使用随机顺序。设置该属性salience 10.
  • no-loop:默认为false。设置为true时,表示该规则只会被引擎检查一次。引擎内部对Fact更新时,忽略本规则的再次检查。
  • date-effective:设置规则的开始生效日期,默认接受“dd-MMM-yyyy”格式的字符串。修改日期格式:System.setProperty("drools.dateformat","yyyy-MM-dd")
  • data-expires:设置规则的过期日期,默认接受“dd-MMM-yyyy”格式的字符串。修改日期格式:System.setProperty("drools.dateformat","yyyy-MM-dd")。
  • enabled:设置规则是否可用,默认为true。
  • dialect:设置规则中使用的编程语言,默认为java,可设置为mvel。获取该属性的设置:drools.getRule().getDialect(),设置该属性dialect mvel
  • duration:指定延迟时间,在另一个线程中触发规则,单位为毫秒。
  • activation-group:为规则划指定一个活动组(组名为字符串)。同一个活动组中的规则只执行一个,根据优先级(salience)来决定执行哪一个规则。
  • agenda-group:为规则指定一个议程(agenda)组。指定了议程组的规则只有在该议程组得到焦点时才被触发。
  • auto-focus:指定了auto-focus属性为true,则该规则自动得到焦点。
  • ruleflow-group:指定规则流组。
  • lock-on-active:当在规则上使用ruleflow-group属性或agenda-group属性的时候,将lock-on-action属性 的值设置为 true,可避免因某些 Fact 对象被修改而使已经执行过的规则再次被激活执行。
  • when

2.4 注释

  • 多行注释:/*注释*/
  • 单行注视:#注释或 //注释

2.5 类型声明

todo

2.6 全局变量

todo

2.7 函数和import function

2.7.1 函数的定义和使用

函数是定义在规则文件中的一段代码,用于将规则文件中会被若干个规则复用的业务操作封装起来,减少规则编写的工作量。函数的可见范围是规则函数所在的规则文件。

函数以function定义。可以是void,也可以有返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package test
import java.util.List;
import java.util.ArrayList;
function void setOrder(Customer customer, int orderSize) {
List ls = new ArrayList();
for (int i=0; i<orderSize; i++){
Order order=new Order();
ls.add(order);
}
customer.setOrder(ls);
}
rule "rule1"
when
$customer:Customer()
then
setOrder($customer,5);
System.out.println("rule 1 customer has order size:"+$customer.getOrders().size());
end
rule "rule2"
when
$customer :Customer()
then
setOrder($customer,10);
System.out.println("rule 2 customer has order size:"+$customer.getOrders().size());
end

2.7.2 引入静态方法

实际应用当中,可以考虑使用在java类当中定义静态方法的办法来替代在规则文件当中定义函数。

Drools 提供了一个特殊的 import 语句:import function。通过该 import 语句,可以实现将一个java类中静态方法引入到一个规则文件当中,使得该文件当中的规则可以像使用普通的Drools函数一样来使用java类中某个静态方法。

2.8 查询定义

查询用于根据条件在当前的 WorkingMemory 当中查找 Fact。

Drools 当中查询可分为两种:

  • 不需要外部传入参数
  • 需要外部传入参数
1
2
3
4
5
6
7
query "testQuery"
customer:Customer(age>30,orders.size >10)
end
query "testQuery2"(int $age,String $gender)
customer:Customer(age>$age,gender==$gender)
end
1234…6

Yuanyi Wu

朝闻道 夕死可矣

29 posts
9 categories
30 tags
GitHub FB Page
© 2019 Yuanyi Wu
Powered by Hexo
|
Theme — NexT.Mist v5.1.2