我有以下Python测试代码(ALS.train
的参数在别处定义):
r1 = (2, 1)
r2 = (3, 1)
test = sc.parallelize([r1, r2])
model = ALS.train(ratings, rank, numIter, lmbda)
predictions = model.predictAll(test)
print test.take(1)
print predictions.count()
print predictions
哪个有效,因为它对预测变量和输出的计数为1:
[(2, 1)]
1
ParallelCollectionRDD[2691] at parallelize at PythonRDD.scala:423
但是,当我尝试使用RDD
我使用以下代码创建自己时,它似乎不再起作用了:
model = ALS.train(ratings, rank, numIter, lmbda)
validation_data = validation.map(lambda xs: tuple(int(x) for x in xs))
predictions = model.predictAll(validation_data)
print validation_data.take(1)
print predictions.count()
print validation_data
哪个输出:
[(61, 3864)]
0
PythonRDD[4018] at RDD at PythonRDD.scala:43
如您所见,predictAll
在传递映射的RDD
时返回空。进入的值都是相同的格式。我能看到的唯一值得注意的差异是第一个示例使用parallelize并生成ParallelCollectionRDD
,而第二个示例只使用生成PythonRDD
的映射。 predictAll
仅在传递某种类型的RDD
时才有效吗?如果是这样,是否可以在RDD
类型之间进行转换?我不确定如何让这个工作。
答案 0 :(得分:14)
MatrixFactorizationMode.predictAll
有两个基本条件可能会返回一个项目数少于输入数的RDD:
您可以轻松地重现此行为,并检查它是否与RDD的创建方式无关。首先,让我们使用示例数据来构建模型:
from pyspark.mllib.recommendation import ALS, MatrixFactorizationModel, Rating
def parse(s):
x, y, z = s.split(",")
return Rating(int(x), int(y), float(z))
ratings = (sc.textFile("data/mllib/als/test.data")
.map(parse)
.union(sc.parallelize([Rating(1, 5, 4.0)])))
model = ALS.train(ratings, 10, 10)
接下来,我们可以看到培训数据中包含哪些产品和用户:
set(ratings.map(lambda r: r.product).collect())
## {1, 2, 3, 4, 5}
set(ratings.map(lambda r: r.user).collect())
## {1, 2, 3, 4}
现在让我们创建测试数据并检查预测:
valid_test = sc.parallelize([(2, 5), (1, 4), (3, 5)])
valid_test
## ParallelCollectionRDD[434] at parallelize at PythonRDD.scala:423
model.predictAll(valid_test).count()
## 3
到目前为止一切顺利。接下来让我们使用与代码中相同的逻辑映射它:
valid_test_ = valid_test.map(lambda xs: tuple(int(x) for x in xs))
valid_test_
## PythonRDD[497] at RDD at PythonRDD.scala:43
model.predictAll(valid_test_).count()
## 3
还好。接下来让我们创建无效数据并重复实验:
invalid_test = sc.parallelize([
(2, 6), # No product in the training data
(6, 1) # No user in the training data
])
invalid_test
## ParallelCollectionRDD[500] at parallelize at PythonRDD.scala:423
model.predictAll(invalid_test).count()
## 0
invalid_test_ = invalid_test.map(lambda xs: tuple(int(x) for x in xs))
model.predictAll(invalid_test_).count()
## 0
正如预期的那样,无法预测无效输入。
最后,你可以通过使用完全独立于Python代码的训练/预测的ML模型来确认这是真的:
from pyspark.ml.recommendation import ALS as MLALS
model_ml = MLALS(rank=10, maxIter=10).fit(
ratings.toDF(["user", "item", "rating"])
)
model_ml.transform((valid_test + invalid_test).toDF(["user", "item"])).show()
## +----+----+----------+
## |user|item|prediction|
## +----+----+----------+
## | 6| 1| NaN|
## | 1| 4| 1.0184212|
## | 2| 5| 4.0041084|
## | 3| 5|0.40498763|
## | 2| 6| NaN|
## +----+----+----------+
正如您所看到的,训练数据中没有相应的用户/项目意味着没有预测。