在pyspark中转换ALS的输入数据

时间:2015-11-15 18:07:09

标签: python pyspark apache-spark-mllib apache-spark-ml collaborative-filtering

我推荐的输入数据如下:

[(u'97990079', u'18_34', 2),
 (u'585853655', u'11_8', 1),
 (u'1398696913', u'6_20', 1),
 (u'612168869', u'7_16', 1),
 (u'2272846159', u'11_17', 2)]

格式为(user_id, item_id, score)

如果我理解正确,火花中的ALS必须在训练前将user_iditem_id转换为整数?如果是这样,我现在能想到的唯一解决方案是使用词典并将每个user_iditem_id映射到整数,如

dictionary for item_id : {'18_34': 1, '18_35':2, ...}
dictionary for user_id : {'97990079':1, '585853655':2, ...}

但我想知道是否还有其他优雅的方法呢?谢谢!

1 个答案:

答案 0 :(得分:6)

您可以使用ML变换器的一种方法。首先,我们将您的数据转换为DataFrame:

ratings_df = sqlContext.createDataFrame([
    (u'97990079', u'18_34', 2), (u'585853655', u'11_8', 1),
    (u'1398696913', u'6_20', 1), (u'612168869', u'7_16', 1),
    (u'2272846159', u'11_17', 2)],
    ("user_id", "item_id_str", "rating"))

接下来我们需要StringIndexer

from pyspark.ml.feature import StringIndexer

indexer = StringIndexer(inputCol="item_id_str", outputCol="item_id")

最后让我们使用索引器转换DataFrame:

from pyspark.sql.functions import col

transformed = (indexer
    .fit(ratings_df)
    .transform(ratings_df)
    .withColumn("user_id", col("user_id").cast("integer"))
    .select("user_id", "item_id", "rating"))

并转换为RDD[Rating]

from pyspark.mllib.recommendation import Rating

ratings_rdd = transformed.map(lambda r: Rating(r.user_id, r.item_id, r.rating))

在较新版本的Spark中,您可以跳过转换,并直接使用ml.recommendation.ALS

from pyspark.ml.recommendation import ALS

als = (ALS(userCol="user_id", itemCol="item_id", ratingCol="rating")
  .fit(transformed))