使用pyspark.mllib.recommendation做推荐案例-实现流程

经典案例:对user-movie-rating数据建模,用户获得可能喜爱的电影推荐,电影获得潜在观看用户以做营销推广。

【另一篇博文介绍 如何用评分数据进行电影和用户的聚类分析

movie数据下载地址: http://files.grouplens.org/datasets/ movielens/ml-100k.zip

解压后可以看到主要的三个数据文件,用户信息数据 u.user , 电影信息数据 u.item , 以及用户对电影的评分数据 u.data。

  1. 初始化PySpark
    #Initializing PySpark
    from pyspark import SparkContext, SparkConf
    conf = SparkConf().setMaster('local[4]').setAppName('movies_app')
    sc = SparkContext(conf=conf)
    import matplotlib.pyplot as plt
    import numpy as np

     

  2. 加载数据,并做数据统计、绘制分布直方图、查看数据整体分布情况
    #加载数据
    user_data = sc.textFile("/Users/gao/Desktop/Toby/5Spark-JDK/data/ml-100k/u.user") 
    user_data.first()
    #统计数据
    user_fields = user_data.map(lambda line: line.split("|"))
    num_users = user_fields.map(lambda fields: fields[0]).count()
    num_genders = user_fields.map(lambda fields:fields[2]).distinct().count()
    num_occupations = user_fields.map(lambda fields:fields[3]).distinct().count()
    num_zipcodes = user_fields.map(lambda fields:fields[4]).distinct().count()
    print ("Users: %d, genders: %d, occupations: %d, ZIP codes: %d" % (num_users, num_genders, num_occupations, num_zipcodes))
    
    #建立分布直方图做统计
    ages = user_fields.map(lambda x: int(x[1])).collect()
    fig = plt.gcf()
    fig.set_size_inches(8, 6)
    plt.hist(ages, bins=20, color='lightblue', normed=True)
    plt.title('histogram of ages')

    #建立职业的饼图,使用 Map-Reduce的方法做统计
    count_by_occupation2 = user_fields.map(lambda fields: fields[3]).countByValue()
    x_axis1 = []
    y_axis1 = []
    for k,v in count_by_occupation2.items():
    	x_axis1.append(k)
    	y_axis1.append(v)
    arg_sort = np.argsort(y_axis1)
    x_axis = np.array(x_axis1)[arg_sort]
    y_axis = np.array(y_axis1)[arg_sort]
    #绘制图形
    pos = np.arange(len(x_axis))
    width = 1.0
    fig = plt.gcf()
    fig.set_size_inches(12, 8)
    ax = plt.axes()
    ax.set_xticks(pos + (width / 2))
    ax.set_xticklabels(x_axis)
    plt.bar(pos, y_axis, width, color='lightblue')
    plt.xticks(rotation=30)
    plt.title('distribution of occupations')
    

       

    #探索下评分数据
    rating_data_raw = sc.textFile("/Users/gao/Desktop/Toby/5Spark-JDK/data/ml-100k/u.data") 
    print (rating_data.first())
    num_ratings = rating_data.count()
    print ("Ratings: %d" % num_ratings)
    rating_data = rating_data_raw.map(lambda line: line.split("\t"))
    ratings = rating_data.map(lambda fields: int(fields[2]))
    max_rating = ratings.reduce(lambda x, y: max(x, y))
    min_rating = ratings.reduce(lambda x, y: min(x, y))
    mean_rating = ratings.reduce(lambda x, y: x + y) / num_ratings
    median_rating = np.median(ratings.collect())
    ratings_per_user = num_ratings / num_users
    ratings_per_movie = num_ratings / num_movies
    print ("Min rating: %d" % min_rating)
    print ("Max rating: %d" % max_rating)
    print ("Average rating: %2.2f" % mean_rating)
    print ("Median rating: %d" % median_rating)
    print ("Average # of ratings per user: %2.2f" % ratings_per_user)
    print ("Average # of ratings per movie: %2.2f" % ratings_per_movie)

       

  3. 缺失值填充
     # 读取movie数据
    movie_data = sc.textFile("/Users/gao/Desktop/data/ml-100k/u.item")
    
    def convert_year(x):
    	try:
    		return int(x[-4:])
    	except:
    		return 1900 # 把没有年份数据的电影年份标记成1900
    
    movie_fields = movie_data.map(lambda line:line.split('|'))
    years_pre_processed = movie_fields.map(lambda fields: fields[2]).map(lambda x: convert_year(x)).collect()
    years_pre_processed_array = np.array(years_pre_processed)
    
     # 去掉年份未知的数据
    years_not_1900_index = years_pre_processed_array!=1900
    
    mean_year = np.mean(years_pre_processed_array[years_not_1900_index])
    median_year = np.median(years_pre_processed_array[years_not_1900_index])
    
    index_bad_data = [index for index in np.where(years_pre_processed_array==1900)[0]]
    years_pre_processed_array[index_bad_data] = median_year
    print ("Mean year of release: %d" % mean_year)
    print ("Median year of release: %d" % median_year)
    print ("Index of '1900' after assigning median: %s" % np.where(years_pre_processed_array == 1900)[0])
    

     

  4. 训练、评价模型
    #使用推荐模型接口
    from pyspark.mllib.recommendation import ALS,Rating
    rawData = sc.textFile("/Users/gao/Desktop/Toby/5Spark-JDK/data/ml-100k/u.data") 
    rawRatings = rawData.map(lambda line:line.split("\t")[:3])
    #构造user-item-rating 数据
    ratings = rawRatings.map(lambda line:Rating(user=int(line[0]),product=int(line[1]),rating=float(line[2])))
    
    #模型训练
    model = ALS.train(ratings, rank=50, iterations=10, lambda_=0.01)
    
    #在训练集上评价模型
    from pyspark.mllib.evaluation import RegressionMetrics
    testdata = ratings.map(lambda p:(p.user,p.product))
    predictions = model.predictAll(testdata).map(lambda r: ((r.user, r.product), r.rating) )
    ratesAndPreds = ratings.map(lambda r: ((r.user, r.product), r.rating)).join(predictions)
    predictedAndTrue = ratesAndPreds.map(lambda r:r[1])
    regressionMetrics = RegressionMetrics(predictedAndTrue)
    
    print('explainedVariance is {:.5f}'.format(regressionMetrics.explainedVariance))
    print('meanAbsoluteError is {:.5f}'.format(regressionMetrics.meanAbsoluteError))
    print('meanSquaredError is {:.5f}'.format(regressionMetrics.meanSquaredError))
    print('r2 is {:.5f}'.format(regressionMetrics.r2))
    print('rootMeanSquaredError is {:.5f}'.format(regressionMetrics.rootMeanSquaredError))
    
    

    注:这里只为演示流程,没有对模型调参,直接效果不好。

  5. 为用户推荐电影
    #整理电影ID和名称数据,将推荐的电影ID翻译成电影名称
    movies = sc.textFile("/Users/gao/Desktop/Toby/5Spark-JDK/data/ml-100k/u.item")
    movie_titles = movies.map(lambda line:line.split('|')[:2]).map(lambda line:(int(line[0]),line[1])).collectAsMap()
    
    #为用户 userId = 800寻找 K = 10个推荐点用
    userId = 800
    K = 10
    #方法一:为每个用户推荐K个电影,为每个电影推荐K个对它感兴趣的用户
    products_for_users = model.recommendProductsForUsers(K)  #为每个用户推荐K个电影
    users_for_products = model.recommendUsersForProducts(K)  #每个电影推荐K个对它感兴趣的用户
    products_for_users.lookup(userId)  #查看给userId推荐的电影评分情况
    
    #方法二:模型自带的给用户user推荐Top K商品的使用方法
    topKRecs = model.recommendProducts(user=userId,num=K) 
    print('Top {} moives recommended for user {} are:'.format(K,userId))
    for rec in topKRecs:
    	print(movie_titles[rec.product],rec.rating)  #查看给用户推荐的商品及得分
    
    

  6. 寻找相似电影
    #计算商品的相似性 使用cosine相似性度量
    def cosineSimilarity(vec1, vec2): 
    	return float(np.dot(vec1, vec2))/(np.linalg.norm(vec1, ord=2) * np.linalg.norm(vec2, ord=2))
    
    #计算物品A、B的相似性
    itemIdA = 567
    K = 50
    itemFactorA = np.array(model.productFeatures().lookup(itemIdA)[0])
    
    #找到与物品A 最相似的top-K 个物品
    itemFactorA_bcast = sc.broadcast(itemFactorA)
    sim = model.productFeatures().map(lambda factor:(factor[0],cosineSimilarity(np.array(factor[1]),itemFactorA_bcast.value)))
    sim_sort=sim.sortBy(keyfunc=(lambda x:x[1]), ascending=False).take(K+1) #自定义按照相似性进行降序排序
    
    print('Top-50 similar movies to {} are:'.format(movie_titles[itemIdA]))
    for (itemid,simlarity) in sim_sort[1:]:
    	print('{},{:.3f}'.format(movie_titles[itemid],simlarity) ) #打印出查看相似度高的电影名称
    

  7. 保存模型
    #保存模型、可供下次调用
    model.save(sc, "target/tmp/myCollaborativeFilter")

     

Done

 



 

### PySpark 实际应用案例 #### 电商平台销售预测 在电商业务场景下,使用PySpark进行大规模数据分析能够有效提升销售预测精度。通过集成历史交易记录、季节性因素以及市场趋势等多维度特征,构建基于回归模型的预测系统[^2]。 ```python from pyspark.sql import SparkSession from pyspark.ml.regression import LinearRegression spark = SparkSession.builder.appName('sales_prediction').getOrCreate() # 加载训练数据集 data = spark.read.format("libsvm").load("/path/to/sales_data.txt") lr = LinearRegression(maxIter=10, regParam=0.3, elasticNetParam=0.8) # 训练线性回归模型 model = lr.fit(data) # 使用测试集评估模型表现 test_results = model.evaluate(testData) print(f"Coefficients: {str(model.coefficients)} Intercept: {str(model.intercept)}") ``` 此代码片段展示了如何加载数据并创建一个简单的线性回归模型来进行商品销量预估。实际操作中可能还需要考虑更多影响因子,并采用更复杂的方法如随机森林或梯度提升树来获得更好的拟合效果。 #### 用户行为分析与个性化推荐 针对海量用户日志文件,借助于PySpark的强大处理能力可快速完成对用户兴趣偏好的挖掘工作。具体来说就是先解析原始访问记录得到各个页面停留时间统计表;再结合协同过滤技术为每位顾客提供定制化的内容推送服务[^3]。 ```python import numpy as np from pyspark.mllib.recommendation import ALS, MatrixFactorizationModel, Rating sc = SparkContext() ratings_RDD = sc.textFile('/path/to/user_ratings.csv') \ .map(lambda line: line.split(','))\ .map(lambda fields:(int(fields[0]), int(fields[1]), float(fields[2]))) rank = 10 numIterations = 10 model = ALS.train(ratings_RDD, rank, numIterations) testdata = ratings_RDD.map(lambda p: (p[0], p[1])) predictions = model.predictAll(testdata).collect() for prediction in predictions: print(prediction) ``` 上述脚本实现了基础版矩阵分解算法——ALS(Alternating Least Squares),用于生成电影评分预测结果。为了进一步增强系统的实用价值,还可以引入隐语义模型(SVD++)或者深度神经网络架构(DNNs)作为改进方向之一。 #### 社交媒体舆情监测 随着社交平台影响力的不断扩大,越来越多的企业开始重视起品牌口碑管理方面的工作。此时如果能充分利用好微博、推特这类公开资源,则有助于及时掌握公众情绪变化情况从而采取相应措施加以应对。而这一切都离不开高效的数据抓取技术和实时流式计算的支持[^5]。 ```python from pyspark.streaming.kafka import KafkaUtils from pyspark.streaming import StreamingContext ssc = StreamingContext(sc, batchDuration=10) kafkaStream = KafkaUtils.createDirectStream(ssc, ['topic_name'], {'metadata.broker.list': 'localhost:9092'}) parsed = kafkaStream.flatMap(lambda v: json.loads(v[1]).split()) wordCounts = parsed.countByValue() wordCounts.pprint() ssc.start() ssc.awaitTermination() ``` 这里给出了一段简易版本Kafka消息队列接入实例,它可以从指定主题订阅最新发布的帖子内容并对其中关键词频率简单汇总输出。当然,在真实环境中往往还会涉及到自然语言处理(NLP)环节比如分词去重、情感倾向判断等功能模块的设计开发。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值