接着上一篇文章常见算法的mapreduce案例(1)继续挖坑,本文涉及到算法的基本原理,文中会大概讲讲,但具体有关公式的推导还请你们去查阅相关的文献文章。下面涉及到的数据挖掘算法会有:Logistict 回归,SVM算法,关联规则apriori算法,SlopeOne推荐算法,二度人脉社交
推荐算法
logistict regression的
map-reduce
逻辑回归做为经典的分类算法,工业界也是应用的很是普遍(
点击率预估,广告投放等
),貌似大部分互联网公司都会用吧,关于logistict regression的应用研究主要分两块:1)用什么样的正则(L2,L1); 2)使用什么优化算法;关于第一点,若是维度超级多选L1较好,L1自然具备特征选择的优点,另外经常使用的优化算法有:梯度降低,LBFGS、随机梯度降低,以及微软针对L1提出的OWLQN算法;本来的logisitc回归,是针对线性可分的的,业界的一淘企业的工程师扩展了Logistic回归,用它来处理非线性的问题。
针对多种优化算法,梯度降低,LBFGS,OWLQN都是能够无损的并行化(执行结果与串行的同样),而基于随机梯度降低的只能进行有损的并行化。
以梯度降低为例:梯度降低的核心步骤
,每一次迭代的个过程能够转换成一个map-reduce过程,按行或者按列拆分数据,分配到N各节点上,每一个节点再经过计算,最后,输出到reduce,进行合并更新W权重系数,完成一次迭代过程。下图文献1中也提到LR的并行,不过用的优化方法是
Newton-Raphson,节点须要计算海森矩阵。
针对随机梯度的并行,下图文献2中提到
算法1是基本的SGD算法,算法2,3是并行的SGD,
能够看出每台worker分配T个数据,利用这些数据来SGD优化更新W,而后输出W由reduce端进行归约。
SVM的
map-reduce
支持向量机,最近十五年机器学习界的明星算法,学术界也是各类研究,现今已经达到一个瓶颈,屋漏偏逢连夜雨,随着深度学习的雄起,SVM弄的一我的走茶凉的境遇(也许正是90年代神经网络的感觉吧,呵呵),如今讲一讲关于SVM的并行,因为原算法较难应用并行策略,而它的另外一个算法变种-pegasos 适合并行,下面是该算法的过程。
初始化W=0(向量形式)
for i in t:
随机选择K个样本
for j in K:
if 第j个样本分错
利用该样本更新权重
累加W的更新
end for
下面是基于mrjob的map-reduce版
1 class MRsvm(MRJob):
2
3 DEFAULT_INPUT_PROTOCOL = 'json_value'
4
5 #一些参数的设置
6
7 def __init__(self, *args, **kwargs):
8
9 super(MRsvm, self).__init__(*args, **kwargs)
10
11 self.data = pickle.load(open('data_path'))
12
13 self.w = 0
14
15 self.eta = 0.69 #学习率
16
17 self.dataList = [] #用于收集样本的列表
18
19 self.k = self.options.batchsize
20
21 self.numMappers = 1
22
23 self.t = 1 # 迭代次数
24
25
26 def map(self, mapperId, inVals):
27
28 #<key,value> 对应着 <机器mapperID,W值或者样本特征跟标签>
29
30 if False: yield
31
32 #判断value是属于W仍是样本ID
33
34 if inVals[0]=='w':
35
36 self.w = inVals[1]
37
38 elif inVals[0]=='x':
39
40 self.dataList.append(inVals[1])
41
42 elif inVals[0]=='t': self.t = inVals[1]
43
44
45 def map_fin(self):
46
47 labels = self.data[:,-1]; X=self.data[:,0:-1]#解析样本数据
48
49 if self.w == 0: self.w = [0.001]*shape(X)[1] #初始化W
50
51 for index in self.dataList:
52
53 p = mat(self.w)*X[index,:].T #分类该样本
54
55 if labels[index]*p < 1.0:
56
57 yield (1, ['u', index])#这是错分样本id,记录该样本的id
58
59 yield (1, ['w', self.w]) #map输出该worker的w
60
61 yield (1, ['t', self.t])
62
63
64 def reduce(self, _, packedVals):
65
66 for valArr in packedVals: #解析数据,错分样本ID,W,迭代次数
67
68 if valArr[0]=='u': self.dataList.append(valArr[1])
69
70 elif valArr[0]=='w': self.w = valArr[1]
71
72 elif valArr[0]=='t': self.t = valArr[1]
73
74 labels = self.data[:,-1]; X=self.data[:,0:-1]
75
76 wMat = mat(self.w); wDelta = mat(zeros(len(self.w)))
77
78 for index in self.dataList:
79
80 wDelta += float(labels[index])*X[index,:] #更新W
81
82 eta = 1.0/(2.0*self.t) #更新学习速率
83
84 #累加对W的更新
85
86 wMat = (1.0 - 1.0/self.t)*wMat + (eta/self.k)*wDelta
87
88 for mapperNum in range(1,self.numMappers+1):
89
90 yield (mapperNum, ['w', wMat.tolist()[0] ])
91
92 if self.t < self.options.iterations:
93
94 yield (mapperNum, ['t', self.t+1])
95
96 for j in range(self.k/self.numMappers):
97
98 yield (mapperNum, ['x', random.randint(shape(self.data)[0]) ])
99
100
101 def steps(self):
102
103 return ([self.mr(mapper=self.map, reducer=self.reduce,
104
105 mapper_final=self.map_fin)]*self.options.iterations)
关联规则Apriori的
map-reduce
啤酒跟尿布的传奇案例,相信你们都应该很是熟悉了,可是很悲剧的是这个案例貌似是假的,呵呵,超市的管理者通常会把这两个放在相差很远的位置上摆放,拉长顾客光顾时间,或许就不止买尿布跟啤酒了。前段时间看到一个东北笑话也许会更容易理解关联规则,“一天,一只小鸡问小猪说:主人去哪了? 小猪回答说:去买蘑菇去了;小鸡听完后,立马撒腿就跑了,小猪说你走这么急干啥,小鸡回头说:主人若是买粉条回来,你也照样急。。。。”很形象生动的讲述了关联规则,好了,又扯远了了,如今回到关联规则的并行上来吧,下面以一个例子简述并行的过程。
假设有一下4条数据
id,交易记录
1,[A,B]
2,[A,B,C]
3,[A,D]
4,[B,D]
首先,把数据按行拆分,搞到每一个worker上面,key=交易id,value=交易记录(假设1,2在第一个mapper上,3,4在第二个mapper上)
其次,每一个worker,计算频次(第一个mapper生成<A,1>,<B,1>,<A,1>,<B,1>,<C,1> ;第二个mapper 就会生成<A,1>,<D,1>,<B,1>,<D,1>)
接着,进行combine操做(减轻reduce的压力)
(第一个mapper生成<A,2>,<B,2>,<C,1> ;第二个mapper 就会生成<A,1>,<B,1>,<D,2>)
最后,送到reduce上面进行归约,获得1-频繁项集
而后再重复上面的动做,知道K-频繁项集
总结:这是对
Apriori的并行实现,可是该算法的一个缺点是须要屡次扫描数据,性能是个问题,对此,韩教授设计了另一个更巧妙的数据结构fp-tree,这个在mahout里面是有实现的(0.9的版本里面貌似把这算法给kill了。。),整体来讲关联规则这个算法是一个听起来是一个很实用的算法,实际操做过程当中要仔细调节支持度、置信度等参数,否则会挖掘出不少不少的价值低的规则。
SlopeOne推荐算法的
map-reduce
例如一个评分矩数据(用户,物品,评分)以下所示
A,one ,2
A,two ,3
A,three,1
B,one ,3
B,two ,5
C,one ,4
C,three,2
首先把该数据集打成{用户,[(物品1,评分),(物品2,评分),....,(物品n,评分)]}形式,很简单的一个map-reduce操做
物品one
物品two
物品three
用户A 2 3 1
用户B 3 5 ?
用户C 4 ? 2
固然真是的数据集确定是很是稀疏的,这里只为讲清原理,接着对数据分片,分到不一样的worker里面,这里假设3个,输入是[A,(one,2)
,(two,3)
,(three,1)
],
[B,(one,3)
,(two,5)
],
[C,(one,4)
,
(three,2)
]。
每个map的操做输出<key,value> 对应了<(物品1,物品2),(评分1-评分2,1)> 最后面的1,是为了对
(物品1,物品2)
计数1,上面第1个节点<(one,two),(-1,1)>,
<(one,three),(1,1)>,
<(two,three),(1,1)>;
第2个节点
<(one,two),(-2,1)>,
<(one,
three
),(2,3,1)>;
第3个节点
<(one,
three
),(2,1)>。
接着能够进行一下combine操做,把key相同的value,评分差值相加,计数相加
最后进行reduce操做,获得物品跟物品之间的评分差
总结:slopeone在mahout0.9版本里面也被kill掉了,悲剧,难道太简单啦??关于该算法有另一个变种就是weighted
slopeone,其实就是在计算物品跟物品之间评分差的时候,进行了加权平均。
人脉二度推荐的
map-reduce
最近社交类网站很是流行的给你推荐朋友/感兴趣的人,利用好社交关系,就不愁找不到好的推荐理由了,举个例子,假设A的好友是B,C,D,然而B的好友有E,C的好友有F,D的好友有E,那么若是要给A推荐好友的话,那么就会首推E了,由于B,C跟E都是好友,而F只是和C好友(有点关联规则里面支持度的味道)。OK,下面详解给A用户推荐好友的map-reduce过程
首先输入文件每行是两个id1,id2,假设id1认识id2,可是id2不认识id1,若是是好友的话,得写两行记录(方便记录单项社交关系)
A,B //A认识B
B,A //B认识A
A,C
C,A
A,D
D,A
B,E
E,B
C,F
F,C
D,E
E,D
第一轮map-reduce(为简单书写,下面只对与A有关的行为进行演示)
输入上面数据,输出<id,[(该id认识的人集合),(认识该id的人集合)]>
输出:<B,[(A),(E)]>,
<C,[(A),(E)]>,
<D,[(A),(F)]>
第二轮map-reduce
map输入上面数据,输出<[
(该id认识的人),(认识该id的人)],id
>
输出:
<[(A),(E)],B>,
<[(A),(E)],C>,
<[(A),(F)],D>
reduce输入上面数据,输出
<[
(该id认识的人),(认识该id的人)],[id集合]
>
输出:
<[(A),(E)],[B,C]>
,
<[(A),(F)],[D]>
OK这样算法挖完了,id集合的长度做为二度人脉的支持度,能够从上面看到,A认识E,比A认识F更靠谱一点。
总结:还有不少其余的推荐算法诸如基于近邻的CF,模型的CF(矩阵分解),关于矩阵分解的,前段时间,LibSvm团队发表的Libmf,针对矩阵分解的并行化方面作出了很是好的贡献
参考资料:
1,《Parallelized Stochastic Gradient Descent》Martin A. Zinkevich、Markus Weimer、Alex Smola and Lihong Li
2,《Map-Reduce for Machine Learning on Multicore NG的一篇nips文章》
5,Pegasos:primal estimated sub-gradient solver for svm
6,machine learning in action
7,http://my.oschina.net/BreathL/blog/60725