淘宝数据竞赛总结和程序
起因
刚刚过去的一个月参加了淘宝的数据挖掘比赛,虽然成绩不是很理想也没进入第二轮但是还是有不少收获的,这里总结一下,做个回顾。
比赛简介
这个大家可以参考淘宝的网页,其实简单来说就是淘宝公开一部分自己的加密后的竞赛数据然后请大家来进行数据挖掘。 这里简单的回顾下要点:
提供的原始文件有大约4M左右,涉及1千左右天猫用户,几千个天猫品牌,总共10万多条的行为记录。用户4种行为类型(Type)对应代码分别为: 点击:0;购买:1;收藏:2;购物车:3 每条记录包括:user_id,Time,Brand_id,Type 本届赛题的任务就是根据用户4个月在天猫的行为日志,建立用户的品牌偏好,并预测他们在将来一个月内对品牌下商品的购买行为。
总结
怎么更加好的使用数据挖掘方法
当然,客观的评价这个数据集并不是特别合适,你没有什么简单的方法套用已经存在的数据进行训练。各种数据挖掘技术往往以来训练集的质量和可靠程度,但是对于未来一个月做预测,同时我们不太确定什么样的用户是确定购买的,所以这个竞赛的难度,现在看来就在于怎么样定义一个训练集的准确度。
我采用的这个方法比较简单粗暴:所有购买和进入购物车的的用户认为会继续购买,收藏的用户也会有一个概率购买。其实最后的我检验发现该模型的准确率大概是4.5%左右,所以其实我的准确率就这样被限制住了。当然这个问题也是可以克服的,比如有的同学谈到可以用小样本用户慢慢逼近,因为淘宝开放了检测接口,其实你可以合理提高训练集的质量。当然这个问题是我最后思考得到,已经错过了时间。不过能够得到这个体会还是挺高兴地。
R语言的思考
虽然plyr这个包被很多人说成是速度很慢的不太理想的解决方案,但是我的体会是这个方法才是触摸到R的灵魂——分割,计算,汇总!所以如果可以的话还是尽量使用plyr的方法吧! 这里推荐一个好的介绍教程:
对于提问的思考
统计之都是个好地方无论是用户活跃程度还是提问回答的积极度,推荐新手经常进去逛逛或者提问。事实上如果你不去和别人交流很难得到提高。这次的第一点思考还是我在最后几天看比赛 BBS看到的方法,确实是点出了直接套用数据挖掘算法的致命缺点。
对于作弊的思考
我的看法是,其实作弊也是一种能力,世界上没有不透风的墙最后的结果总归是可以被发现。就像在科学的共同体研究中总是有那么几个造假的,但是不代表我们就不去科研了一样。我们其实也要从中思考某些方法。作弊也是个技术活。基本上所有的坏蛋都是聪明人,你见过智商很低的骗子么?
程序
这里是我们最后参赛的程序,大部分都有注释,大家参考。其实成绩不好,大家不要误会了。
library(plyr)
library(randomForest)
library(e1071) #贝叶斯分类方法
#使用pylr包分组处理数据统一处理数据
tao<-read.csv("t_data.csv",header=T);
tao$visit_datetime<-as.Date(tao$visit_datetime,format='%m/%d');
#user<-unique(tao[,1])
#数据整理
##目标:将时间数据转化成时间间隔
duration<-function(x){
x$visit_datetime<-x$visit_datetime-min(x$visit_datetime);
x[,4]<-as.integer(x[,4]);
return(x);
}
dat<-ddply(tao,.(user_id,brand_id),.fun=duration)
###判断是不是不购买买家,在原来数据基础上增加buyer指示项
##认为购买用户和购物车用户都是商品喜爱者概率百分之一百
##收藏用户有80%概率是商品喜爱者
judge<-function(x){
for (i in x){
if((i==1)||(i==3)){
return(1);
break;
}
}
for (j in x){
if(j==2){
k<-runif(1);
if(k>=0.05){
return(1);
break;
}
}
}
return(0);
}
#建立测试数据集group
#group作为测试数组
#group<-dat[1:1000,]
#使用概率方法统计不同访问的性质
probk<-function(g,k){
y<-0;
L<-length(g);
for (i in g){
if(i==k){y<-y+1;}
}
py<-y/L;
return(py);
}
numk<-function(g,k){
y<-0;
for (i in g){
if (i==k){y<-y+1;}
}
return(y);
}
dayprobk<-function(g,k){
y<-0;
L<-length(g);
for (i in g){
if(i<=k & i>=(k-30)){y<-y+1;}
}
py<-y/L;
return(py);
}
daynumk<-function(g,k){
y<-0;
for (i in g){
if (i<=k & i>=(k-30)){y<-y+1;}
}
return(y);
}
#groupcal<-ddply(group,.(user_id,brand_id),summarize,buyers=judge(type),px=probk(type,0),py=probk(type,2),pz=probk(type,3),pb=probk(type,1))
#生成最终使用数据集datcal
#datcal<-ddply(dat,.(user_id,brand_id),summarize,buyers=judge(type),totalvisit=length(type),nx=numk(type,0),px=probk(type,0),ny=numk(type,2),py=probk(type,2),nz=numk(type,3),pz=probk(type,3),nb=numk(type,1),pb=probk(type,1),dp3=dayprobk(visit_datetime,3),dn3=daynumk(visit_datetime,3),dp5=dayprobk(visit_datetime,5),dn5=daynumk(visit_datetime,5),dp10=dayprobk(visit_datetime,10),dn10=daynumk(visit_datetime,10),dp20=dayprobk(visit_datetime,20),dn20=daynumk(visit_datetime,20),dp30=dayprobk(visit_datetime,30),dn30=daynumk(visit_datetime,30),dp60=dayprobk(visit_datetime,60),dn60=daynumk(visit_datetime,60),dp90=dayprobk(visit_datetime,90),dn90=daynumk(visit_datetime,90),dp120=dayprobk(visit_datetime,120),dn120=daynumk(visit_datetime,120),dp150=dayprobk(visit_datetime,150),dn150=daynumk(visit_datetime,150))
#新的一套算法
datcal<-ddply(dat,.(user_id,brand_id),summarize,buyers=judge(type),totalvisit=length(type),nx=numk(type,0),px=probk(type,0),ny=numk(type,2),py=probk(type,2),nz=numk(type,3),pz=probk(type,3),nb=numk(type,1),pb=probk(type,1),dp3=dayprobk(visit_datetime,3),dn3=daynumk(visit_datetime,3),dp5=dayprobk(visit_datetime,5),dn5=daynumk(visit_datetime,5),dp10=dayprobk(visit_datetime,10),dn10=daynumk(visit_datetime,10),dp20=dayprobk(visit_datetime,20),dn20=daynumk(visit_datetime,20),dp30=dayprobk(visit_datetime,30),dn30=daynumk(visit_datetime,30),dp60=dayprobk(visit_datetime,60),dn60=daynumk(visit_datetime,60),dp90=dayprobk(visit_datetime,90),dn90=daynumk(visit_datetime,90),dp120=dayprobk(visit_datetime,120),dn120=daynumk(visit_datetime,120),dp150=dayprobk(visit_datetime,150),dn150=daynumk(visit_datetime,150))
datcal$buyers<-factor(datcal$buyers)
#逻辑斯蒂回归
reg1<glm(buyers~nx+px+ny+py+nb+totalvisit+pb+dp30+dn30+dp60+dn60+dp90+dn90+dp120+dn120+dp150+dn150,family=binomial,datcal)
reg2<-step(reg1)
summary(reg2)
p<-predict(reg2,datacal)
#50: glm.fit:拟合機率算出来是数值零或一
#
#随机森林分类
#test = datcal[ c(1:4000, 10000:10400, 17000:17400), ]
train1 =datcal[c(1:4000, 10000:10400, 17000:17400), ]
test1 = datcal[c(4050:8000,21000:25000,45000:50000),]
r = randomForest(buyers~nx+px+ny+py+nb+totalvisit+pb+dp3+dn3+dp5+dn5+dp10+dn10+dp20+dn20+dp30+dn30+dp60+dn60+dp90+dn90+dp120+dn120, data=train1, importance=TRUE, proximity=TRUE)
p = predict(r, test1)
t = table(observed=test1[,'buyers'], predict=p)
prop.table(t, 1)
#另一次检验
test2 = datcal[c(9000:18000,27000:29000,95000:100000),]
r = randomForest(buyers~nx+px+ny+py+nb+totalvisit+pb+dp3+dn3+dp5+dn5+dp10+dn10+dp20+dn20+dp30+dn30+dp60+dn60+dp90+dn90+dp120+dn120, data=test2, importance=TRUE, proximity=TRUE)
p2 = predict(r, test2)
t2 = table(observed=test2[,'buyers'], predict=p2)
prop.table(t2, 1)
#Bagging
p2 <- bagging(buyers ~ ., data = datcal, coob = T)
#赋值得到所有的随机森林分类结果并且返回赋值
p3 = predict(r, datcal)
datcal$buyers<-p3
#贝叶斯
m <- naiveBayes(buyers ~ ., datcal)
predict<-predict(m, datcal[, -3])
true=datcal[,3]
table(predict, true)
#赋值给预测数组
#改进算法
datcal$buyers<-predict
#输出函数
cat(file="result.txt")
d_ply(.data=datcal,.(user_id),function(x){
cat(x[1,1],"\t",file="result.txt",append="True")
recommend<-list();
for (i in 1:length(x$buyers)){
if (x[i,3] == 1){
if(length(recommend)==0){recommend<-paste(recommend,x[i,2]);}
else{
recommend<-paste(recommend,x[i,2],sep=",");
}
}
}
#cat(x,file="result.txt",append="True");
#browser();
cat(recommend,"\n",file="result.txt",append="True")
})
##测试算法指标是否准确
datindex<-ddply(dat,.(user_id,brand_id),summarize,buyers=judge(type))