spark机器学习笔记:(七)用Spark Python构建聚类模型


声明:版权所有,转载请联系作者并注明出处  
http://blog.csdn.net/u013719780?viewmode=contents


博主简介:风雪夜归子(英文名:Allen),机器学习算法攻城狮,喜爱钻研Meachine Learning的黑科技,对Deep Learning和Artificial Intelligence充满兴趣,经常关注Kaggle数据挖掘竞赛平台,对数据、Machine Learning和Artificial Intelligence有兴趣的童鞋可以一起探讨哦,个人CSDN博客:http://blog.csdn.net/u013719780?viewmode=contents




1 从数据中提取正确的特征


类似大多数机器学习模型,K-均值聚类需要数值向量作为输入,于是用于分类和回归的特征提取和变换方法也适用于聚类。
K-均值和最小方差回归一样使用方差函数作为优化目标,因此容易受到离群值(outlier)和较大方差的特征影响。对于回归和分类问题来说,上述问题可以通过特征的归一化和标准化来解决,同时可能有助于提升性能。但是某些情况我们可能不希望数据被标准化,比如根据某个特定的特征找到对应的类簇。

从MovieLens数据集提取特征
本文中,我们继续使用博文 http://blog.csdn.net/u013719780/article/details/51775047 中的电影打分数据集,这个数据集主要分为三个部分:第一个是电影打分的数据集(在u.data文件中), 第二个是用户数据(u.user),第三个是电影数据(u.item)。除此之外,我们从题材文件中获取了每个电影的题材(u.genre)。

查看电影数据集
movies = sc.textFile('/Users/youwei.tan/ml-100k/u.item')
print movies.take(1)


输出结果:
[u'1|Toy Story (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)|0|0|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0']

到目前为止,我们既知道电影的名称,也将电影按题材分类。那为什么还需要对电影数据进行聚类呢?具体原因有两个。
 第一,因为我们知道每部电影的题材标签,所以可以用这些标签评估聚类模型的性能。
 第二,我们希望基于其他属性或特征对电影进行分类,而不单单是题材。

本例中,除了题材和标题,我们还有打分数据用于聚类。之前,我们已经根据打分数据建立了一个矩阵分解模型,这个模型由一系列用户和电影因素向量组成。
我们可以思考怎样在一个新的隐式特征空间中用电影相关的因素表示一部电影,反过来说就是用隐式特征表示打分矩阵中一些特定形式的结构。每个隐式特征无法直接解释,因为它们表示一些可以影响用户对电影打分行为的隐式结构。可用的因素有用户对题材的偏好、演员和导演或者电影的主题等。因此,如果将电影的相关因素向量表示作为聚类模型的输入,我们可以得到基于用户实际打分行为的分类而不是人工的题材分类。同样,我们可以在打分行为的隐式特征空间中用用户相关因素表示一个用户,因此对用户向量进行聚类,就得到了基于用户打分行为的聚类结果。





1.1 提取电影的题材标签


在进一步处理之前,我们先从u.genre文件中提取题材的映射关系。根据之前对数据集的输出结果来看,需要将题材的数字编号映射到可读的文字版本。查看u.genre开始几行数据:

genres = sc.textFile('/Users/youwei.tan/ml-100k/u.genre')
print genres.take(5)

for line in genres.take(5):
    print line


输出结果:
[u'unknown|0', u'Action|1', u'Adventure|2', u'Animation|3', u"Children's|4"]
unknown|0
Action|1
Adventure|2
Animation|3
Children's|4

上面输出的数字表示相关题材的索引,比如0是unknown的索引。索引对应了每部电影关于题材的特征二值子向量(即前面数据中的0和1)。
为了提取题材的映射关系,我们对每一行数据进行分割,得到具体的<题材,索引>键值对。注意处理过程中需要处理最后的空行,不然会抛出异常(见代码中高亮部分):

#为电影题材编码
genre_map = genres.filter(lambda x: len(x) > 0).\
                   map(lambda line : line.split('|')).\
                   map(lambda x:(x[1],x[0])).collectAsMap()
print '构造出的电影题材的编码字典:',genre_map


输出结果:
构造出的电影题材的编码字典: {u'11': u'Horror', u'10': u'Film-Noir', u'13': u'Mystery', u'12': u'Musical', u'15': u'Sci-Fi', u'14': u'Romance', u'17': u'War', u'16': u'Thriller', u'18': u'Western', u'1': u'Action', u'0': u'unknown', u'3': u'Animation', u'2': u'Adventure', u'5': u'Comedy', u'4': u"Children's", u'7': u'Documentary', u'6': u'Crime', u'9': u'Fantasy', u'8': u'Drama'}

接下来,我们需要为电影数据和题材映射关系创建新的RDD,其中包含电影ID、标题和题材。当我们用聚类模型评估每个电影的类别时,可以用生成的RDD得到可读的输出。
接下来的代码中,我们对每部电影提取相应的题材(是Strings形式而不是Int索引)。



提取电影的title和genres:

movies=sc.textFile('/Users/youwei.tan/ml-100k/u.item')
print '电影数据集的第一条数据:',movies.first()

#查看电影的标题
movies_title  = movies.map(lambda x: x.split('|')).map(lambda x: x[1])
print '电影标题:',movies_title.take(5)

#查看电影的题材, 0表示不属于该题材, 1表示属于该题材
movies_genre = movies.map(lambda x: x.split('|')).map(lambda x: x[5:])
print '电影的题材:'
print movies_genre.take(5)


输出结果:
电影数据集的第一条数据: 1|Toy Story (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)|0|0|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0
电影标题: [u'Toy Story (1995)', u'GoldenEye (1995)', u'Four Rooms (1995)', u'Get Shorty (1995)', u'Copycat (1995)']
电影的题材:
[[u'0', u'0', u'0', u'1', u'1', u'1', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0'], [u'0', u'1', u'1', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'1', u'0', u'0'], [u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'1', u'0', u'0'], [u'0', u'1', u'0', u'0', u'0', u'1', u'0', u'0', u'1', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0'], [u'0', u'0', u'0', u'0', u'0', u'0', u'1', u'0', u'1', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'1', u'0', u'0']]


根据电影的题材编码字典genre_map,从上述结果可以知道,第一部电影属于Animation,Children's,Comedy题材.

def func(rdd):
    genres = rdd[5:]     #提取题材特征
    genres_assigned = zip(genres, range(len(genres)))
    index = []           #存储题材特征数值为1的特征索引号
    for genre,idx in genres_assigned:
        if genre=='1':
            index.append(idx)
    index_val = [genre_map[str(i)] for i in index]   #根据编码字典找出索引的相应题材名
    index_val_str = ','.join(index_val)
    return (int(rdd[0]),rdd[1]+','+index_val_str)
titles_and_genres = movies.map(lambda x: x.split('|')).map(lambda x:func(x))
print '前5部电影的标题和相应的题材类型:',titles_and_genres.take(5)


输出结果:
前5部电影的标题和相应的题材类型: [(1, u"Toy Story (1995),Animation,Children's,Comedy"), (2, u'GoldenEye (1995),Action,Adventure,Thriller'), (3, u'Four Rooms (1995),Thriller'), (4, u'Get Shorty (1995),Action,Comedy,Drama'), (5, u'Copycat (1995),Crime,Drama,Thriller')]




1.2 训练推荐模型



要获取用户和电影的因素向量,首先需要训练一个新的推荐模型。我们在博文   用Spark Python构建推荐系统  中做过类似的事情,因此接下来使用相同的步骤:

from pyspark.mllib.recommendation import ALS
from pyspark.mllib.recommendation import Rating

raw_data = sc.textFile("/Users/youwei.tan/ml-100k/u.data")
#数据集u.data中四个字段分别表示用户ID, 电影ID, 评分, 时间戳
print 'raw data sample:', raw_data.map(lambda x : x.split('\t')).take(3)

raw_ratings = raw_data.map(lambda x:x.split('\t')[:3])
ratings = raw_ratings.map(lambda x: Rating(x[0], x[1], x[2]))
ratings.cache()
print 'rating data sample:',ratings.take(3)

#训练推荐模型
als_model = ALS.train(ratings,50,5,0.1)


输出结果
raw data sample: [[u'196', u'242', u'3', u'881250949'], [u'186', u'302', u'3', u'891717742'], [u'22', u'377', u'1', u'878887116']]
rating data sample: [Rating(user=196, product=242, rating=3.0), Rating(user=186, product=302, rating=3.0), Rating(user=22, product=377, rating=1.0)]


from pyspark.mllib.linalg import Vectors

print 'productFeatures的第一条数据:',als_model.productFeatures().take(1)

movie_factors = als_model.productFeatures().map(lambda (id,factor): (id,Vectors.dense(factor)))
print 'movie_factors的第一条数据:',movie_factors.first()
movie_vectors = movie_factors.map(lambda (id,vec):vec)

user_factors = als_model.userFeatures().map(lambda (id,factor):(id,Vectors.dense(factor)))
print 'user_factors的第一条数据:',user_factors.first()
user_vectors = user_factors.map(lambda (id, vec):vec)


输出结果:
productFeatures的第一条数据: [(4, array('d', [-0.25364574790000916, 0.1965579390525818, -0.010804139077663422, 0.18130534887313843, 0.19064882397651672, -0.688933789730072, 0.2703670263290405, 0.2450348287820816, 0.04271795228123665, 0.06376508623361588, -0.10085047781467438, 0.14721041917800903, -0.186862513422966, -0.03862190246582031, 0.22592301666736603, 0.4475729167461395, -0.06261929869651794, -0.33085519075393677, -0.17093169689178467, 0.0065758004784584045, -0.09590368717908859, -0.020839834585785866, -0.33823490142822266, 0.17909930646419525, -0.3050488233566284, 0.017226755619049072, -0.2866823673248291, -0.37014031410217285, 0.2290325164794922, -0.5270513892173767, 0.11399126052856445, -0.16211742162704468, -0.12764166295528412, -0.10635107010602951, -0.11531693488359451, -0.08600226044654846, -0.295471727848053, -0.09224160015583038, 0.07585407048463821, -0.22940267622470856, -0.09108887612819672, -0.37131789326667786, 0.0054631903767585754, -0.3760491907596588, 0.12734010815620422, 0.2783116102218628, 0.5568009614944458, -0.14109675586223602, -0.04276394471526146, 0.08389943838119507]))]
movie_factors的第一条数据: (4, DenseVector([-0.2536, 0.1966, -0.0108, 0.1813, 0.1906, -0.6889, 0.2704, 0.245, 0.0427, 0.0638, -0.1009, 0.1472, -0.1869, -0.0386, 0.2259, 0.4476, -0.0626, -0.3309, -0.1709, 0.0066, -0.0959, -0.0208, -0.3382, 0.1791, -0.305, 0.0172, -0.2867, -0.3701, 0.229, -0.5271, 0.114, -0.1621, -0.1276, -0.1064, -0.1153, -0.086, -0.2955, -0.0922, 0.0759, -0.2294, -0.0911, -0.3713, 0.0055, -0.376, 0.1273, 0.2783, 0.5568, -0.1411, -0.0428, 0.0839]))
user_factors的第一条数据: (4, DenseVector([-0.4545, 0.3919, -0.3194, -0.4114, -0.0362, -0.7812, 0.5728, 0.8531, -0.1006, 0.0799, 0.0442, -0.0544, 0.0688, -0.1198, 0.0998, 0.7738, -0.2748, -0.4775, -0.4801, -0.3676, 0.0882, -0.5152, -0.47, 0.7984, -0.158, 0.0298, 0.2694, -0.7995, 0.1633, -0.9575, 0.1051, -0.5222, 0.4569, 0.3014, -0.0691, -0.0043, -1.0819, 0.1802, -0.3621, 0.1659, -0.3126, -0.4778, -0.2319, -0.1191, -0.0486, 0.223, 0.341, -0.7563, -0.1962, -0.3569]))





1.3 归一化



在训练聚类模型之前,有必要观察一下输入数据的相关因素特征向量的分布,这可以告诉我们是否需要对训练数据进行归一化。具体做法和第5章一样,我们使用MLlib中的RowMatrix进行各种统计,代码实现如下:

from pyspark.mllib.linalg.distributed import RowMatrix

moive_matrix = RowMatrix(movie_vectors)
user_matrix = RowMatrix(user_vectors)

from pyspark.mllib.stat import MultivariateStatisticalSummary
desc_moive_matrix = MultivariateStatisticalSummary(moive_matrix.rows)
desc_user_matrix = MultivariateStatisticalSummary(user_matrix.rows)
print 'Movie factors mean:',desc_moive_matrix.mean()
print 'Movie factors variance:',desc_user_matrix.mean()
print 'User factors mean:',desc_moive_matrix.variance()
print 'User factors variance:',desc_user_matrix.variance()


输出结果:
Movie factors mean: [ -2.42438916e-01   1.25892015e-01  -1.01128287e-01   6.81537394e-02
  -4.90188997e-02  -3.84744613e-01   1.92715832e-01   3.00776967e-01
   7.85692380e-03   6.22808723e-02  -1.30065157e-01   1.65411243e-01
  -3.56316963e-02   6.99312749e-03   1.84715494e-01   2.68042047e-01
  -1.23106967e-01  -1.57173516e-01  -1.73252956e-01  -1.67818381e-01
  -8.31478515e-02  -1.85641149e-01  -2.54993702e-01   3.27601579e-01
  -2.13352103e-01  -7.15934799e-02   2.86090419e-04  -3.56040676e-01
   1.19933207e-01  -3.53707917e-01   1.77226424e-01  -1.23331462e-01
   7.33759908e-02  -3.67910947e-02  -7.12374086e-02  -2.09321015e-02
  -4.06088135e-01  -1.06893385e-02   1.01656729e-02  -4.59759580e-02
  -1.32920241e-01  -8.58630392e-02  -5.94274147e-02  -1.37866147e-01
   9.29171377e-02   1.91635158e-02   3.06964813e-01  -1.77468166e-01
  -1.00145879e-01  -1.30844215e-01]
Movie factors variance: [-0.44167016  0.25435563 -0.1727202   0.13731355 -0.06623893 -0.69970225
  0.33315295  0.45628591  0.02300619  0.06396109 -0.23282097  0.24830023
 -0.1042916   0.02167495  0.27280814  0.44542788 -0.22764165 -0.30479719
 -0.33563422 -0.26558353 -0.17754534 -0.29847609 -0.50030339  0.55008739
 -0.36819538 -0.15328011 -0.02316416 -0.61410146  0.22868754 -0.61511877
  0.34477867 -0.25042202  0.15898724 -0.00547614 -0.10669204 -0.01282096
 -0.69631875  0.0220296   0.0087616  -0.0980786  -0.28781575 -0.11271467
 -0.08193858 -0.31459483  0.14087784  0.0606273   0.52389416 -0.34927602
 -0.1358626  -0.2620565 ]
User factors mean: [ 0.02123215  0.04154274  0.02419521  0.02631427  0.03025208  0.03693836
  0.02973717  0.02724385  0.03341776  0.02623281  0.03691471  0.02950037
  0.04198097  0.02823345  0.02335817  0.03085507  0.03495941  0.03404106
  0.02343747  0.03185638  0.0229145   0.02562004  0.02714542  0.02722446
  0.03443216  0.02616262  0.02865667  0.02888377  0.02322707  0.04355441
  0.05698518  0.03019456  0.03062282  0.02753087  0.03353758  0.02110459
  0.03247938  0.03605873  0.02572534  0.03752665  0.03782459  0.0260555
  0.03343828  0.02744762  0.02572257  0.02936925  0.0325904   0.02638102
  0.02341373  0.03448836]
User factors variance: [ 0.03036875  0.0540869   0.02849067  0.03537828  0.03111662  0.03866784
  0.03417626  0.03567199  0.05292328  0.0367134   0.04849576  0.03611785
  0.04584948  0.03788201  0.03320176  0.03600616  0.04439234  0.036413
  0.02882943  0.03115991  0.03443816  0.03650265  0.03431651  0.04108162
  0.03814361  0.02883841  0.03880702  0.03916495  0.03114326  0.04674307
  0.07481666  0.03203164  0.04224502  0.03617045  0.04427324  0.03279789
  0.03442555  0.04636376  0.03548539  0.04429447  0.03160161  0.03143084
  0.04056352  0.03459579  0.03164808  0.03531451  0.03728178  0.02570473
  0.02921107  0.04301201]

从结果来看,没有发现特别的离群点会影响聚类结果,因此本例中没有必要进行归一化。




2 训练聚类模型



在MLlib中训练K-均值的方法和其他模型类似,只要把包含训练数据的RDD传入KMeans对象的train方法即可。注意,因为聚类不需要标签,所以不用LabeledPoint实例,而是使用特征向量接口,即RDD的Vector数组即可。

用MovieLens数据集训练聚类模型

MLlib的K-均值提供了随机和K-means||两种初始化方法,后者是默认初始化。因为两种方法都是随机选择,所以每次模型训练的结果都不一样。
K-均值通常不能收敛到全局最优解,所以实际应用中需要多次训练并选择最优的模型。MLlib提供了完成多次模型训练的方法。经过损失函数的评估,将性能最好的一次训练选定为最终的模型。

from pyspark.mllib.clustering import KMeans
num_clusters = 5
num_iterations = 20
num_runs =3
movie_cluster_model = KMeans.train(movie_vectors,num_clusters, num_iterations, num_runs)
movie_cluster_model_coverged = KMeans.train(movie_vectors,num_clusters,100)
user_cluster_model = KMeans.train(user_vectors,num_clusters,num_iterations, num_runs)
predictions = movie_cluster_model.predict(movie_vectors)
print '对前十个样本的预测标签为:'+",".join([str(i) for i in predictions.take(10)])


输出结果:
对前十个样本的预测标签为:4,4,4,3,4,3,1,3,0,2


print 'movie_factors的第一条数据:',movie_factors.first()
print '========================'
print 'titles_and_genres的第一条数据:',titles_and_genres.first()

titles_factors = titles_and_genres.join(movie_factors)
print '========================'
print 'titles_factors的第一条数据:',titles_factors.first()


输出结果:
movie_factors的第一条数据: (4, DenseVector([-0.2536, 0.1966, -0.0108, 0.1813, 0.1906, -0.6889, 0.2704, 0.245, 0.0427, 0.0638, -0.1009, 0.1472, -0.1869, -0.0386, 0.2259, 0.4476, -0.0626, -0.3309, -0.1709, 0.0066, -0.0959, -0.0208, -0.3382, 0.1791, -0.305, 0.0172, -0.2867, -0.3701, 0.229, -0.5271, 0.114, -0.1621, -0.1276, -0.1064, -0.1153, -0.086, -0.2955, -0.0922, 0.0759, -0.2294, -0.0911, -0.3713, 0.0055, -0.376, 0.1273, 0.2783, 0.5568, -0.1411, -0.0428, 0.0839]))
========================
titles_and_genres的第一条数据: (1, u"Toy Story (1995),Animation,Children's,Comedy")
========================
titles_factors的第一条数据: (1536, (u'Aiqing wansui (1994),Drama', DenseVector([-0.2953, -0.2653, -0.0394, 0.1022, -0.0061, -0.8327, 0.2372, 0.4489, -0.0279, 0.2955, -0.086, 0.2009, -0.1806, -0.0905, 0.1349, 0.4077, -0.1397, -0.4622, -0.2987, -0.4978, -0.0521, -0.3738, -0.2074, 0.3197, -0.5649, -0.0483, 0.0624, -0.1967, 0.1172, -0.3913, -0.3867, -0.0565, -0.131, -0.1507, -0.1108, 0.1695, -0.4871, 0.0319, 0.2411, -0.3772, -0.2846, -0.1636, -0.3747, -0.0247, -0.1281, -0.0738, 0.2859, -0.1743, -0.1477, 0.0836])))




#对每个电影计算其特征向量与类簇中心向量的距离
def func2(rdd):
    id,(name_genres,vec) = rdd
    pred = movie_cluster_model.predict(vec)
    cluster_center = movie_cluster_model.clusterCenters[pred]
    cluster_center_vec = Vectors.dense(cluster_center)
    dist = vec.squared_distance(cluster_center_vec)
    return u'电影' + str(id) + u'的题材类型是' + name_genres + ',' + u'聚类模型预测的标签是' + str(pred)+ ',' + \
           u'与聚类所属类别中心的距离是' + str(dist)

movies_assigned = titles_factors.map(lambda x:func2(x))  
for i in movies_assigned.take(5):
    print i


输出结果:
电影1536的题材类型是Aiqing wansui (1994),Drama,聚类模型预测的标签是4,与聚类所属类别中心的距离是1.2383822505
电影1026的题材类型是Lay of the Land, The (1997),Comedy,Drama,聚类模型预测的标签是2,与聚类所属类别中心的距离是1.35769832103
电影516的题材类型是Local Hero (1983),Comedy,聚类模型预测的标签是4,与聚类所属类别中心的距离是1.43910597622
电影6的题材类型是Shanghai Triad (Yao a yao yao dao waipo qiao) (1995),Drama,聚类模型预测的标签是4,与聚类所属类别中心的距离是2.39286392316
电影1032的题材类型是Little Big League (1994),Children's,Comedy,聚类模型预测的标签是2,与聚类所属类别中心的距离是1.15536400768






3 评估聚类模型的性能



3.1 内部评价指标


通用的内部评价指标包括WCSS(我们之前提过的K-元件的目标函数)、Davies-Bouldin指数、Dunn指数和轮廓系数(silhouette coefficient)。所有这些度量指标都是使类簇内部的样本距离尽可能接近,不同类簇的样本相对较远。




3.2 外部评价指标


因为聚类被认为是无监督分类,如果有一些带标注的数据,便可以用这些标签来评估聚类模型。可以使用聚类模型预测类簇(类标签),使用分类模型中类似的方法评估预测值和真实标签的误差(即真假阳性率和真假阴性率)。
具体方法包括Rand measure、F-measure、雅卡尔系数(Jaccard index)等。




3.3 在MovieLens数据集计算性能


movie_cost = movie_cluster_model.computeCost(movie_vectors)
user_cost = user_cluster_model.computeCost(user_vectors)
print "WCSS for movies: %f"%movie_cost
print "WCSS for users: %f"%user_cost


输出结果:
WCSS for movies: 2131.824110
WCSS for users: 1487.797814




4 聚类模型参数调优


不同于以往的模型,K-均值模型只有一个可以调的参数,就是K,即类中心数目。通过交叉验证选择K
类似分类和回归模型,我们可以应用交叉验证来选择模型最优的类中心数目。这和监督学习的过程一样。需要将数据集分割为训练集和测试集,然后在训练集上训练模型,在测试集上评估感兴趣的指标的性能。如下代码用60/40划分得到训练集和测试集,并使用MLlib内置的WCSS类方法评估聚类模型的性能:

train_test_split_movies = movie_vectors.randomSplit([0.6,0.4],123)
train_movies = train_test_split_movies[0]
test_movies = train_test_split_movies[1]
for k in [2,3,4,5,10,20]:
    k_model = KMeans.train(train_movies, num_iterations, k, num_runs)
    cost = k_model.computeCost(test_movies)
    print 'WCSS for k=%d : %f'%(k,cost)


输出结果:
WCSS for k=2 : 766.646663
WCSS for k=3 : 769.816755
WCSS for k=4 : 770.081729
WCSS for k=5 : 763.681320
WCSS for k=10 : 761.307839
WCSS for k=20 : 760.734158

从结果可以看出,随着类中心数目增加,WCSS值会出现下降,然后又开始增大。另外一个现象,K-均值在交叉验证的情况,WCSS随着K的增大持续减小,但是达到某个值后,下降的速率突然会变得很平缓。这时的K通常为最优的K值(这称为拐点)。根据预测结果,我们选择最优的K=10。需要说明是,模型计算的类簇需要人工解释(比如前面提到的电影或者顾客聚类的例子),并且会影响K的选择。尽管较大的K值从数学的角度可以得到更优的解,但是类簇太多就会变得难以理解和解释。为了实验的完整性,我们还计算了用户聚类在交叉验证下的性能:

train_test_split_movies = user_vectors.randomSplit([0.6,0.4],123)
train_users = train_test_split_movies[0]
test_users = train_test_split_movies[1]
for k in [2,3,4,5,10,20]:
    k_model = KMeans.train(train_users,num_iterations,k,num_runs)
    cost = k_model.computeCost(test_users)
    print 'WCSS for k=%d : %f'%(k,cost)


输出结果:
WCSS for k=2 : 569.221509
WCSS for k=3 : 569.650019
WCSS for k=4 : 558.117543
WCSS for k=5 : 568.013497
WCSS for k=10 : 560.014328
WCSS for k=20 : 567.601320



5 小结


本文中,我们研究了一种新的模型, 它可以在无标注数据中进行学习,即无监督学习。我们学习了如何处理需要的输入数据、特征提取,以及如何将一个模型(我们用的是推荐模型)的输出作为另外一个模型(K-均值聚类模型)的输入。最后,我们评估聚类模型的性能时,不仅进行了类簇人工解释,也使用具体的数学方法进行性能度量。

下一篇博文,我们将讨论其他类型的无监督学习,在数据中选择保留最重要的特征或者应用其他降维模型。






你可能感兴趣的:(spark机器学习笔记)