【pyspark】Word2vec的算法尝试

背景

word2vec用于推荐对象item的相似度的计算,虽然一般是设计到embedding层,但也可以单独作为一个模块训练。

计算流程

  • 用户操作清单清洗
    一般需要筛选出最偏好的X个item,需要针对时间衰减,用户操作次数,不同的操作入口等给出不同打分。
    如果要更细致评分,可类似用营销效果模型的夏普利值归因分析, 评估每个操作对收入或者活跃的贡献。这个就比较复杂了。
    最终的数据形态,是比较简单的不定长数组,每一行都是一个用户的操作itemlist:
    为了能够测试效果,item拆分为1-10和11-20两组,每个用户只操作其中一组,则预期最终item的相似度,同一组的相似度很高,不同组很低才符合预期。
    数据形态样例
  • pyspark包的导入和初始化
import pyspark 
from pyspark.sql import SparkSession
from pyspark.storagelevel import StorageLevel 
from pyspark.ml.feature import Tokenizer,HashingTF
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import MulticlassClassificationEvaluator,BinaryClassificationEvaluator
from pyspark.ml import Pipeline,PipelineModel
from pyspark.ml.linalg import Vector
from pyspark.sql import Row

#SparkSQL的许多功能封装在SparkSession的方法接口中

spark = SparkSession.builder \
        .appName("dbscan") \
        .config("master","local[4]") \
        .enableHiveSupport() \
        .getOrCreate()

sc = spark.sparkContext
  • 读取CSV文件
    使用标准的spark方法读取本地文件,同时指定了列名。
    如果是在平台上测试,则读取hive库表:
#读取csv文件
dftmp = spark.read.option("header","False") \
 .option("inferSchema","true") \
 .option("delimiter", " ") \
 .csv("XXXXXXXXXX/testw2v5.csv")
df=dftmp.withColumnRenamed("_c0", "trainlist")
df.show(5)
df.printSchema()
  • 数据预处理
    把数据拆分成数组存储到新的字段里:
from pyspark.sql.functions import split, explode, concat, concat_ws
df_split = df.withColumn("split_trainlist", split(df['trainlist'], ","))
df_split.show()
  • 使用word2vec训练
    整体训练代码如下,指定列的数量,mincount就不指定了,并得到模型:
    所有的item无论编号多少,统一当成字符串处理,训练时统一编码,因为一般itemid都不是从0开始编号,把编号当编码反而会增加onehot编码空间,增加计算量(如果很长时间算不出结果,就要关注这点了):
word2Vec = Word2Vec(vectorSize=3, minCount=0, inputCol="split_trainlist", outputCol="result")
model = word2Vec.fit(df_split)
  • 结果预测
    本质上训练,还是要得到每个item的词向量,并用于计算相似度:
    这里采用偷懒的方法遍历了测试数据的所有item,再进行预测:
df_test = spark.createDataFrame([
    ("1".split(" "), ),
    ("2".split(" "), ),
    ("3".split(" "), ),
    ("4".split(" "), ),
    ("5".split(" "), ),
    ("6".split(" "), ),
    ("7".split(" "), ),
    ("8".split(" "), ),
    ("9".split(" "), ),
    ("10".split(" "), ),
    ("11".split(" "), ),
    ("12".split(" "), ),
    ("13".split(" "), ),
    ("14".split(" "), ),
    ("15".split(" "), ),
    ("16".split(" "), ),
    ("17".split(" "), ),
    ("18".split(" "), ),
    ("19".split(" "), ),
    ("20".split(" "), )
], ["split_trainlist"])
df_vector = model.transform(df_test)
  • 效果验证
    • item两两笛卡尔积:
#计算相似度
#笛卡尔积
df_vector_join=df_vector.withColumn("birthyear",df_vector["split_trainlist"])
rdd_vector=df_vector.rdd.map(lambda p: p)
rdd_vector_join=rdd_vector.cartesian(rdd_vector)
    • 相似度函数定义
import math

def cos_cal(v_x,v_y,v_cnt):
    """计算余弦相似度"""
    
    dotxy=0
    len2_x=0
    len2_y=0
    
    for i in range(v_cnt):
        dotxy=dotxy+v_x[i]*v_y[i]
        len2_x=len2_x+v_x[i]*v_x[i]
        len2_y=len2_y+v_y[i]*v_y[i]

    return dotxy*1.0/(math.sqrt(len2_x)*math.sqrt(len2_y))
    • 相似度计算
rdd_vector_res=rdd_vector_join.map(lambda x:(x[0][0][0],x[1][0][0],x[0][1],x[1][1],float(cos_cal(x[0][1],x[1][1],3))))
from pyspark.sql import functions as F 
df_vector_res=rdd_vector_res.toDF(["key1","key2","vec1","vec2","simcos"])
df_vector_res.where("key1>10 and key2<=10").show(5)
    • 计算不同组和相同组的相似度
      最终结果符合预期,不同组之间相似度不一样:
df_vector_res.where("key1<=10 and key2<=10").agg({"simcos":"avg"}).show()
df_vector_res.where("key1>10 and key2<=10").agg({"simcos":"avg"}).show()
df_vector_res.where("key1<=10 and key2>10").agg({"simcos":"avg"}).show()
df_vector_res.where("key1>10 and key2>10").agg({"simcos":"avg"}).show()

后记

可以看到整体代码量很少,真正word2vec训练的就2行代码,封装的相当好了。大部分工作量还是在方案的设计,预处理,结果分析。
要评估一个算法方案工作量,需要关注整体宏观分析,而不只是看到代码的一点点。
所以一个算法工具的建设,如果只是在测试数据上跑通过流程,基本相当于耍流氓,不能算是算法做好了。只有在真实数据上计算并产生效果,才算是做好了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值