出家如初,成佛有余

R语言常用统计分布的蒙特卡洛模拟

Posted in 技术相关 by chuanliang on 2017/12/23

为加深对各种常用统计分布的理解,更好掌握R语言对应的各类分布的概率函数(d、p、q、r族)以及广义线性模型的使用,研究了一下常用统计分布数据的模拟生成方法,收获颇多。

各类常用统计分布蒙特卡洛模拟数据生成的大致思路:

1、构造自变量x的均匀分布
2、根据对应分布的均值函数,构造x变量对应的均值。(广义线性模型的link 函数参考
https://en.wikipedia.org/wiki/Generalized_linear_model#Link_function
3、将均值代入,R中对应分布的随机变量生成函数,得到因变量y(例如正态分布为rnorm、泊松分布为rpois)

代码:

#norm distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0+beta1*runif(n=num,-1,1)
y=rnorm(num,mean=x,sd=1)
model=glm(y~x,,family=gaussian(link=’identity’))

#possion distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
lambda=exp(x)
y=rpois(n=num, lambda=lambda)
model = glm(y~x, family=poisson(link = log))

#Exponential/Gamma distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
y=rexp(num,rate=exp(-x))
model=glm(y~x,,family=Gamma(link=’log’))
#使用nls模拟
df=data.frame(x,y)
model=nls(y~exp(a+b*x),data=df,start = list(a=0,b=0))

#logistic/probit distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
#logistic distribution logit=log(odds)=log(p/(1-p))
odds=exp(x)
probs=odds/(1+odds)
#probit distribution probit=Cumulative normal pdf
#probs=pnorm(x)

y=rbinom(n=num,size=1,prob=probs)
model=glm(y~x1+x2,family = binomial(link="logit"))

#bionimal/Categorical/Multinomial distribution simulation
library(nnet)
y=rbinom(n=num,size=3,prob=probs)
model <- multinom(y ~ x1 + x2)

代码下载


参考资料:《 Monte Carlo Simulation and Resampling Methods for Social Science》

https://www.sagepub.com/sites/default/files/upm-binaries/57233_Chapter_6.pdf

Advertisements

R中fitted()与predict()函数关系以及predict type参数解析

Posted in 技术相关 by chuanliang on 2017/12/17

R文档对fitted()、predict()函数以及predict函数type参数取值的具体含义说得很不清楚,网上也没有清晰的解释。总结一下。

一、说明

目的一、R中fitted和predict的关系
目的二、以logistic为例,解析predict中type参数不同取值的关系

1、R中fitted和predict的关系
fitted对无link函数模型(例如线性回归),fitted值和predict的值相同
对有link函数的模型(例如logistic、Binomial),
fitted是link函数作用前(或者link逆函数inverse of the link function作用后)的预测值
predict是link函数作用后(或link逆函数inverse of the link function作用前)的预测值
link function  https://en.wikipedia.org/wiki/Generalized_linear_modelLink_function

2、logistic中predict中type参数不同取值的关系
predict中type参数的可选项有:default, type="link",type="response",type="terms"

假设log(odds)=log(p/(1-p))=alpha+beta1*x1+beta2*x2+…+betan*xn
a.、type="link",type为缺省值
  type="link"为缺省值,给出logit线性函数预测值,link=alpha+beta1*x1+beta2*x2+…+betan*xn

b、 type="response"
  type="response" 给出概率预测值。
  response=predict(model,type = "response"),则
  log(response/(1-response))=alpha+beta1*x1+beta2*x2+…+betan*xn=link,或:link=exp(response)/(1+response)

c、type="terms"
  type="terms"表示各个变量的预测值(包括前面参数在模型中的值)。
  terms=predict(model, newdata = traindata,type = "terms")的结果为各个变量term的值
  term1=beta1*x1,term2=beta2*x2, …
  sum(term1,…,termn)+attr(terms,"constant")=log(odds)=log(response/(1-response))
  attr(terms,"constant")的含义 http://blog.minitab.com/blog/adventures-in-statistics-2/regression-analysis-how-to-interpret-the-constant-y-intercept

二、代码

代码下载

#fitted和predict的关系演示
#linear regression
#no link function
num=100
x1=rnorm(num)
x2=rnorm(num)
lr=1+2*x1+3*x2
model=lm(y~x+x2)

fit=fitted(model)
pred=predict(model)
print(all.equal(fit, pred))
#对无link函数的模型,fitted值与predict值相同

#possion
#link=log
num=100
x=rnorm(num)
y=rpois(num,lambda = exp(x))
model = glm(y~x, family="poisson")
fit=fitted(model)
pred=predict(model)
print(all.equal(log(fit),pred))
print(all.equal(fit,exp(pred)))
#对有link函数的模型,fitted值为link函数作用前的值,predict为link作用后的值

#logistic
#link=logit=log(p/(1-p))
num=100
x1=rnorm(num)
x2=rnorm(num)
lo=1+2*x1+3*x2
odds=exp(lo)
probs=odds/(1+odds)
y=rbinom(n=num,size=1,prob=probs)
model=glm(y~x1+x2,family = binomial(link="logit"))

fit=fitted(model)
pred=predict(model)
print(all.equal(log(fit/(1-fit)),pred))
print(all.equal(fit,exp(pred)/(1+exp(pred))))
#对有link函数的模型,fitted值为link函数作用前的值,predict为link作用后的值

#以logistic模型为例子,验证predict中type为缺省值,type="link",type="response",type="terms"关系
#predict中type="link"时的fitted及predict
link=predict(model,type="link")
print(link)
print(all.equal(pred,link))
#type=link为缺省值

#predict中type="response"时的fitted及predict
response=predict(model,type="response")
print(response)
print(all.equal(fit,response))
print(all.equal(pred,log(response/(1-response))))

#type="terms"时的fitted及predict
terms<- predict(model,type="terms")
term=terms[,1]+terms[,2]+attr(terms,"constant")
print(term)
print(all.equal(link,term))
print(all.equal(response,exp(term)/(1+exp(term))))

参考资料:

https://stackoverflow.com/questions/12201439/is-there-a-difference-between-the-r-functions-fitted-and-predict

R语言信用评分卡模型(脑图、代码)

Posted in 技术相关 by chuanliang on 2017/12/13

在消费金融中,风险模型组(申请评分卡、行为评分卡、催收评分卡、失联概率、违约概率PD模型等)、营销模型组(客户分层模型、客户响应模型、客户流失模型)、反欺诈模型组等都涉及了信用评分卡模型的应用。关于信用评分卡模型的使用及代码实现,网上公开的完整资料较少,且大都写得语焉不详。基于R语言做了一个完整例子,算是对最近一段时间工作总结。

分为两部分:

1、评分卡模型使用总结脑图

2、评分卡模型R语言代码

1、评分卡模型使用总结脑图(完整脑图点击下载)

2017-12-13_205830

《评分卡模型使用总结脑图》下载

2、R语言代码

scorecard.r

服务器部署Session Draining支持方案

Posted in 技术相关 by chuanliang on 2016/02/24

 

支付系统对账算法优化方案

Posted in 电子商务&互联网金融, 技术相关 by chuanliang on 2015/06/09

一、目前对账的算法:

1、从上游渠道(银行、银联等金融机构)获取对账文件,程序逐行解析入库

2、在存储过程中,以上游对账文件的表为基准,程序逐行读取并与我们系统的交易记录/账务记录(有账务系统情况下,合理方案应该是于账务记录)对比,查找出差异记录。

3、以我们系统的交易记录/账务记录为基准,程序逐行读取与上游对账文件对比,查找出差异记录

 

二、目前对账算法问题:

1、使用存储过程,对账过程都在数据库端完成,对数据库性能影响较大,而且对账逻辑扩展极为麻烦

2、逐行比对算法效率较低,但算法上并无好的优化余地。如果采用数据库INTERSECT、MINUS对数据库压力也高。

3、在业务量大的情况下(例如有上百家上游渠道需要对,每一家都有几十万条交易记录),对账服务器及数据库服务器负荷较高。即便采用读写分离,对账时候使用读库,压力一样很大。

4、导入批量文件,逐行入库效率较为低下(每一次都需要建立网络连接、关闭连接)

 

三、对账算法优化思路:

1、涉及网络传输的,尽量采用批量方式操作,减少网络消耗及时间消耗

2、使用Redis等NOSQL数据库,降低数据库服务器的压力。同时在扩展上也容易,一台Redis服务器不够,可以无限制增加用于对账用的服务器。

3、使用Redis的set集合的sdiff功能,利用Redis sdiff算法的高性能,比对上游记录和我方记录的差异

 

四、对账算法说明:

1、利用Oracle/Mysql的load data infile将对账文件批量导入到数据库

2、程序读取上游账务记录表,对上游账户记录执行select  concat(channel_id, “:” , order_id , “:” , HASH_MD5(channel_id , order_id , amount , status , timestamp1 , timestamp2 ,…) )  as hashid from table ,得到对应的SET集合。

这里思路是将需要对账的记录拼成格式为:channel_id:order_id:hashid形式的串,以便作为Redis SET集合的item。

其中channel_id和order_id用于标识对应的渠道及订单,只是例子,根据实际需要补充。之所以要在hashid前面带上channel_id和order_id,主要目的是在sdiff后,能够作为主键,根据set结合的item查找出对应的数据库记录。

3、对我方的交易记录表/账户历史表采用上一步的类似算法,得到对应的SET结合

4、采用Redis的pipeline功能(Redis的各种客户端,包括java客户端jedis 都提供此功能),将上游账务记录SET集合和我方的交易记录/账务历史记录SET集分别批量执行sadd插入Redis,得到两个SET集合。

由于单条记录sadd 插入Redis效率较差(每一次都涉及网络open、close、传输消耗),因此使用Redis的pipeline功能,已实现批量入库功能。

可以参考:http://redis.io/topics/mass-insert

5、利用redis的sdiff功能查找出上游账务集合与我方记录集合的差值

6、从sdiff 集合中channel_id:order_id:hash,定位对应的数据库记录,更新对账状态。

具体性能及实现可以在实现后测试对比一下,应该会有大幅的性能提升。

高并发交易驱动系统方案

Posted in 电子商务&互联网金融, 技术相关 by chuanliang on 2015/01/25

我在知乎就《现在有这样一个需求,在一秒中有3万的支付订单请求,有什么比较好的解决方案吗?》做的回答。

从交易角度来看,各种高并发系统可以粗略分为两大类:交易驱动的系统,内容驱动的系统。其中:
交易驱动的系统:包括支付系统、电信计费系统、银行核心交易系统等,此类系统强调数据库事务的ACID原则。
内容驱动的系统:包括SNS、微博、门户、视频、搜索引擎等系统,此类系统对数据库事务ACID的关注不是第一位的,更强调CAP原则:Consistency(一致性), Availability(可用性),Partition tolerance(分区容错性)。
与此对应,交易驱动的系统与内容驱动的系统在系统优化方法最大的差异在于:
交易驱动的系统:强 调事务的ACID,按照CAP原则做选择,更强调CA(Consistency(一致性)和Availability(可用性);因此交易驱动的系统一般 在核心交易上选择关系型数据库(包括采用内存数据库、缓存等涉及事务问题),当然这就导致交易系统最大的瓶颈一般都在关系数据库上。
内容驱动的系统:可以在CAP之间根据业务需要做选择三选二,因此一般选择NOSQL为主、RDBMS为辅的方案。
在优化策略上,内容驱动的系统采用的诸多优化手段交易驱动的系统也可以采用,上面各位回答都有所提及,这里重点说一下因事务导致的业务复杂性的处理。
3万笔/每秒这个级别的交易订单这个量级说实话挺大,但即便如此,也有诸多可优化的空间。由于题主未对具体场景说明,只能假定是典型的交易驱动系统,一些思考点:
1、3万笔/每秒是峰值最大交易量还是持续交易量?
2、3万笔/每秒是同一类型的订单还是诸多种类型的订单?
3、业务能否做拆分,例如从功能、从区域、从优先级等角度?
4、支付订单是实时交易还是非实时交易,能否延时入库?
5、支付订单能否延时批量处理?
6、支付订单是否涉及热点账户问题,也即对同一账户会有多个并发请求对其属性(例如账户余额)进行操作?
由此可以展开诸多优化策略,不在此处细述。
以前写过一篇 交易系统“热点账户”处理 ,供参考

知乎回答原文链接:http://www.zhihu.com/question/27590048/answer/38025567

交易系统和风控系统的架构怎么设计?

Posted in 电子商务&互联网金融, 技术相关, 产品管理 by chuanliang on 2015/01/19

我在知乎就《交易系统和风控系统的架构怎么设计?》做的回答。

交易系统和风控系统从架构角度设计,是应该设计成两个单独的系统,题主提到的问题,本质在于交易系统和风控系统之间数据共享及服务调用的问题。
一般通过如下几个层面来降低交易系统、风控系统的耦合度,提升系统性能和扩展性:读写分离、缓存/内存数据库、SOA架构、复合事件处理
数据库读写分离机制:在初期,风控系统一般都极为简单,此时侯一般通过数据库主从复制/读写分离/Sharding等机制来保证交易系统的数据库和风控系统数据的同步及读写分离。风控系统对所需要的客户/账户数据、交易数据一般都只进行读操作。
缓存/内存数据库机制:不 管是交易系统还是风控系统,高效的缓存系统是提升性能的大杀器,一般会把频繁使用的数据存放到Redis等缓存系统中。例如对风控系统,包括诸如风控规 则、风控案例库、中间结果集、黑白名单、预处理结果等数据;对交易系统而言,包括诸如交易参数、计费模板、清结算规则、分润规则、银行路由策略等。对一些 高频交易中,基于性能考虑,会采用内存数据库(一般会结合SSD硬盘)。
RPC/SOA架构:要降低交易系统和风控系统的 耦合度,在初期系统服务较少的情况下,一般直接采用RabbitMQ/ActiveMQ之类的消息中间件或RPC方式来实现系统间服务的调用。如果系统服 务较多,存在服务治理问题,会采用Dubbo之类的SOA中间件来实现系统服务调用。
复合事件处理(CEP):对实时/准实时交易风险控制,相对于纯基于规则的处理模式,采用复合事件处理(CEP)模式,性能及扩展性更好,开源的方案包括Esper、Storm、Spark等。
从风控系统构建角度,对应所谓的事前、事中、事后风险控制,作为风控系统最核心的风控引擎分为实时风控引擎、准实时风控引擎、定时风控引擎三种:
1、实时风控引擎&准实时风控引擎
实时风控主要在交易过程对交易过程进行实时监控,一个典型应用场景是甄别钓鱼、盗卡风险。
准实时风控典型应用场景是在T+1结算时候,对商户洗钱、跑路进行甄别。
实时/准实时风控引擎一般采用规则引擎+复杂事件处理(CEP)。
2、定时风控引擎
主要定时对支付/交易/账务等数据进行定时ETL、深度挖掘等处理,建立对应的风控模型,一个典型应用场景是商户的信用等级模型。此时侯一般采用Hadoop、ML等技术进行大数据建模
以前写过两篇关于第三方支付风控系统建设的文章,供参考
支付系统风控系统建设思考
复杂事件处理(Complex Event Processing)入门1

 

知乎回答原文链接:http://www.zhihu.com/question/20860347/answer/36328342

开发一个业务逻辑复杂的系统,应该怎么样设计才能使项目的扩展性更好?

Posted in 技术相关, 产品管理 by chuanliang on 2014/11/24

我在知乎关于《开发一个业务逻辑复杂的系统,应该怎么样设计才能使项目的扩展性更好?》做的回答。

既然业务逻辑复杂,那意味着项目前期的业务建模、需求分析、分析设计极为重要,直接抛开这几个阶段进入技术实施开发阶段,不管套用什么设计模式、架构模式,系统的扩展性肯定难以保证。
项目的扩展性虽然最终体现为系统架构、技术实现的扩展性,但系统扩展性的根源在于系统业务架构及业务模型的扩展性。大家经常骂xx系统烂、扩展性差,大都将原因归结为技术实现烂,但总结那些成功的大型项目或产品的最佳实践,原因都会有:某某是业务专家,对xx业务很熟悉,能够衔接业务与技术。因此一个好的项目角色中,应该有行业专家/领域专家、业务过程分析师、系统分析师、软件架构师等角色,从业务架构、信息架构、技术架构保证系统的扩展性。

具体怎样进行业务建模,搭建良好的业务架构和业务模型,从而为技术架构、信息架构、技术实现奠定良好基础,有一些较为成熟的软件开发过程可供参考。例如 RUP(Rational Unified Process,统一软件开发过程)。一个标准的RUP工作流程包括:业务建模,需求分析,分析设计,实施开发,测试,部署,配置和变更管理,项目管理,环境。当然RUP只是一个方法论,且过于庞大,大部分项目很难完整执行其过程,需要根据实际情况进行裁剪,但其方法论对于复杂业务逻辑系统的建设具有指导意义。像互联网产品设计中常用的用例分析技术就源于RUP。

因此对于题主描述的一个复杂系统,标准的过程应当在业务建模,需求分析,分析设计,实施开发,测试,部署完整过程的分析设计(与开发语言无关)或实施开发(分析设计的成果映射为具体语言,例如Java、.NET等)阶段才考虑设计模式、架构模式的引入。设计模式的使用会经历僵化->固化->优化的阶段,类似禅修中“看山是山、看水是水”的三个阶段,才能体会模式的运用之妙。

值得强调的是:如果是偏交易(例如支付、金融)的系统,在考虑扩展性时候,一定要将信息架构、信息模型的扩展性纳入到考虑范围,此类系统数据模型至关重要,也不可能频繁变动。

上面描述方法的特别适用与传统软件、系统集成等需求偏稳定的项目,对于互联网偏创新性的项目就不一定完全适用了,此类项目的现实情况如下:业务模式不确定,会不停试错,验证模式;需求不停变化,要求能够快速响应;全新的行业,没有行业专家,没有行业标杆可借鉴(至多有跨界标杆可参考);此时候,类似精益创业、Scrum之类的敏捷开发模式更适合,但对于复杂的业务而言,业务建模->需求分析->分析设计的理念仍然值得参考借鉴。

最后,最最重要的是:完美系统的架构和扩展性是管理出来的、持续重构出来的。正如各大城市马路不停翻了再修、修了再翻的命运一样,中国大部分公司后任会不停否定掉前任的架构、系统,推倒再来一遍,然后等新系统刚开发出来不久,尚未上线或上线运营一段时间后,再换一帮人继续折腾,然后。。。

总结这么多年的经历,深刻体会到:再烂的系统和架构,如果能够强化管理、持续积累、持续重构、持续完善,都能够有机会成为完美的系统,完美的系统不在于其架构的牛逼和完美,而在于:符合公司的业务模式,能够完美支撑公司业务的高速发展和市场需求的快速响应。

 

http://www.zhihu.com/question/26731781/answer/33906943

手机密号的原理是什么?

Posted in 移动互联网, 技术相关 by chuanliang on 2014/11/24

在知乎就《手机密号的原理是什么? 之前有安卓和微信版本,现在又有苹果版本了,它的实现原理是什么呢?》做的回答。

手机密号的功能并无太多新颖的东西,像58同城、赶集等也推过类似服务。这里大致说一下自己理解的主要技术,做过呼叫中心、VOIP的比较擅长。
类似服务一般涉及用户、互联网服务提供商、云呼叫中心服务提供商、电信运营商几个角色。
1、 互联网服务提供商:例如58同城之类,由于专业分工原因,互联网服务提供商一般是采用第三方云呼叫中心服务提供商提供的VOIP服务。像手机密号的功能, 诸如注册、微信绑定等功能属于互联网服务提供商的业务功能,而临时性虚拟号码的分配、外呼是由云呼叫中心服务提供商提供的,当然。
2、 云呼叫中心服务提供商:一般采用类似asterisk之类的VOIP及软交换开源项目进行改造,对外提供云呼叫中心服务。与传统呼叫中心基于语音+PBX 不同,一般采用IP+软交换方案。可以参考一下合力金桥、讯鸟的方案。当然云呼叫中心服务提供商也可以扮演互联网服务提供商角色。
3、运营商:为云呼叫中心提供号码池、外呼中继等相关服务。在运营商那端有一堆主叫号码池和外呼中继,这样使用手机密号用户注册绑定后会从不同的主叫池中选择分配(或者动态分配)一个不同的主叫号码并外呼出去。没错,与VOIP透传之类的套路一样。

 

http://www.zhihu.com/question/24816198/answer/29088983

PHP, Python, Node.js 哪个比较适合写爬虫?

Posted in 技术相关 by chuanliang on 2014/06/03

我在知乎关于《PHP, Python, Node.js 哪个比较适合写爬虫? 》做的回答

主要看你定义的“爬虫”干什么用。
1、如果是定向爬取几个页面,做一些简单的页面解析,爬取效率不是核心要求,那么用什么语言差异不大。
当然要是页面结构复杂,正则表达式写得巨复杂,尤其是用过那些支持xpath的类库/爬虫库后,就会发现此种方式虽然入门门槛低,但扩展性、可维护性等都奇差。因此此种情况下还是推荐采用一些现成的爬虫库,诸如xpath、多线程支持还是必须考虑的因素。
2、如果是定向爬取,且主要目标是解析js动态生成的内容
此时候,页面内容是有js/ajax动态生成的,用普通的请求页面->解析的方法就不管用了,需要借助一个类似firefox、chrome浏览器的js引擎来对页面的js代码做动态解析。
此种情况下,推荐考虑casperJS+phantomjs或slimerJS+phantomjs ,当然诸如selenium之类的也可以考虑。
3、如果爬虫是涉及大规模网站爬取,效率、扩展性、可维护性等是必须考虑的因素时候
大规模爬虫爬取涉及诸多问题:多线程并发、I/O机制、分布式爬取、消息通讯、判重机制、任务调度等等,此时候语言和所用框架的选取就具有极大意义了。
PHP对多线程、异步支持较差,不建议采用。
NodeJS:对一些垂直网站爬取倒可以,但由于分布式爬取、消息通讯等支持较弱,根据自己情况判断。
Python:强烈建议,对以上问题都有较好支持。尤其是Scrapy框架值得作为第一选择。优点诸多:支持xpath;基于twisted,性能不错;有较好的调试工具;
此种情况下,如果还需要做js动态内容的解析,casperjs就不适合了,只有基于诸如chrome V8引擎之类自己做js引擎。
至于C、C++虽然性能不错,但不推荐,尤其是考虑到成本等诸多因素;对于大部分公司还是建议基于一些开源的框架来做,不要自己发明轮子,做一个简单的爬虫容易,但要做一个完备的爬虫挺难的。
像我搭建的微信公众号内容聚合的网站
http://lewuxian.com就是基于Scrapy做的,当然还涉及消息队列等。可以参考下图:


23b58ecfcd42d2f0b26931b660ede44f_m


具体内容可以参考
一个任务调度分发服务的架构

 

地址:http://www.zhihu.com/question/23643061/answer/26322652

Tagged with: , , ,