Machine learning 通过Spark MLlib回归估计数值

Machine learning 通过Spark MLlib回归估计数值,machine-learning,pyspark,regression,apache-spark-mllib,apache-spark-ml,Machine Learning,Pyspark,Regression,Apache Spark Mllib,Apache Spark Ml,我正在培训Spark MLlib线性回归器,但我相信我不了解库的部分实际使用 我有一个功能(NameItem)和一个输出(累加器)。 第一种是分类的(速度、温度等),第二种是双精度数字 训练集由数百万个条目组成,它们不是线性相关的(我用热图和相关指数检查) 问题:我想通过线性回归估计给定NameItem值的累加器值,但我认为这不是我实际要做的 问题:我怎么做 我首先将数据集划分为训练集和数据集: (trainDF,testDF)=df.randomspilt((0.80,0.20),seed=4

我正在培训Spark MLlib线性回归器,但我相信我不了解库的部分实际使用

我有一个功能(
NameItem
)和一个输出(
累加器
)。 第一种是分类的(速度、温度等),第二种是双精度数字

训练集由数百万个条目组成,它们不是线性相关的(我用热图和相关指数检查)

问题:我想通过线性回归估计给定
NameItem
值的
累加器
值,但我认为这不是我实际要做的

问题:我怎么做

我首先将数据集划分为
训练集
数据集

(trainDF,testDF)=df.randomspilt((0.80,0.20),seed=42)

之后,我尝试了管道方法,正如大多数教程所示:

1) 我将名称项编入索引

indexer = StringIndexer(inputCol="NameItem", outputCol="CategorizedItem", handleInvalid = "keep")
2) 然后我把它编码了

encoderInput = [indexer.getOutputCol()]
encoderOutput = ["EncodedItem"]
encoder = OneHotEncoderEstimator(inputCols=encoderInput, outputCols=encoderOutput)
3) 而且还组装了它

assemblerInput = encoderOutput
assembler = VectorAssembler(inputCols=assemblerInput, outputCol="features")
之后,我继续进行有效的培训

lr = LinearRegression(labelCol="Accumulator")
pipeline = Pipeline(stages=[indexer, encoder, assembler, lr])
lrModel = pipeline.fit(trainDF)
predictions = lrModel.transform(testDF).show(5, False)
这就是我在测试集上应用预测时得到的结果:

lr = LinearRegression(labelCol="Accumulator")
pipeline = Pipeline(stages=[indexer, encoder, assembler, lr])
lrModel = pipeline.fit(trainDF)
predictions = lrModel.transform(testDF).show(5, False)
对于相同的分类特征(例如
Temp
),我怎么可能得到3种不同的预测

尽管它们非常接近预期值,但我觉得有点不对劲

对于相同的分类特征(例如
Temp
),我怎么可能得到3种不同的预测

这是因为不知何故,您的输出
累加器
已经进入了
特性
(当然不应该是这样),因此模型只是“预测”(基本上复制)输入的这一部分;这就是为什么预测如此“准确”

似乎
矢量汇编程序把事情搞砸了。事实上,这里并不真正需要
vectorsembler
,因为实际上您只有一个“单一”功能(EncodedItem
中的一个热编码稀疏向量)。这可能就是为什么
VectorAssembler
在这里的行为是这样的(它被要求“组装”单个功能),但在任何情况下,这都是一个bug

因此,我建议去掉
矢量汇编程序
,直接将
编码数据项
重命名为
功能
,即:

indexer = StringIndexer(inputCol="NameItem", outputCol="CategorizedItem", handleInvalid = "keep")

encoderInput = [indexer.getOutputCol()]
encoderOutput = ["features"]  # 1st change
encoder = OneHotEncoderEstimator(inputCols=encoderInput, outputCols=encoderOutput)

lr = LinearRegression(labelCol="Accumulator")
pipeline = Pipeline(stages=[indexer, encoder, lr])  # 2nd change
lrModel = pipeline.fit(trainDF)
更新(在评论中反馈后)

我的Spark版本是1.4.4

不幸的是,我无法重现这个问题,因为我无法访问您正在使用的Spark 1.4.4。但我已经证实,它在Spark2.4.4的最新版本中工作正常,这使我更倾向于相信v1.4中确实存在一些bug,但后来这些bug已经得到了解决

下面是Spark 2.4.4中的一个复制品,使用了一些类似于您的虚拟数据:

spark.version
# '2.4.4'

from pyspark.ml.feature import VectorAssembler, OneHotEncoderEstimator, StringIndexer
from pyspark.ml.regression import LinearRegression
from pyspark.ml import Pipeline

# dummy data resembling yours:

df = spark.createDataFrame([['Speed', 44000], 
                            ['Temp', 23000], 
                            ['Temp', 5000], 
                            ['Speed', 75000], 
                            ['Weight', 5300], 
                            ['Height', 34500], 
                            ['Weight', 6500]], 
                            ['NameItem', 'Accumulator'])

df.show()
# result:
+--------+-----------+
|NameItem|Accumulator|
+--------+-----------+
|   Speed|      44000|
|    Temp|      23000|
|    Temp|       5000|
|   Speed|      75000|
|  Weight|       5300|
|  Height|      34500|
|  Weight|       6500|
+--------+-----------+

indexer = StringIndexer(inputCol="NameItem", outputCol="CategorizedItem", handleInvalid = "keep")

encoderInput = [indexer.getOutputCol()]
encoderOutput = ["EncodedItem"]
encoder = OneHotEncoderEstimator(inputCols=encoderInput, outputCols=encoderOutput)

assemblerInput = encoderOutput
assembler = VectorAssembler(inputCols=assemblerInput, outputCol="features")

lr = LinearRegression(labelCol="Accumulator")

pipeline = Pipeline(stages=[indexer, encoder, assembler, lr])
lrModel = pipeline.fit(df) 
lrModel.transform(df).show() # predicting on the same df, for simplicity
最后一次
转换的结果是

+--------+-----------+---------------+-------------+-------------+------------------+
|NameItem|Accumulator|CategorizedItem|  EncodedItem|     features|        prediction|
+--------+-----------+---------------+-------------+-------------+------------------+
|   Speed|      44000|            2.0|(4,[2],[1.0])|(4,[2],[1.0])|           59500.0|
|    Temp|      23000|            1.0|(4,[1],[1.0])|(4,[1],[1.0])|14000.000000000004|
|    Temp|       5000|            1.0|(4,[1],[1.0])|(4,[1],[1.0])|14000.000000000004|
|   Speed|      75000|            2.0|(4,[2],[1.0])|(4,[2],[1.0])|           59500.0|
|  Weight|       5300|            0.0|(4,[0],[1.0])|(4,[0],[1.0])| 5900.000000000004|
|  Height|      34500|            3.0|(4,[3],[1.0])|(4,[3],[1.0])|           34500.0|
|  Weight|       6500|            0.0|(4,[0],[1.0])|(4,[0],[1.0])| 5900.000000000004|   
+--------+-----------+---------------+-------------+-------------+------------------+
从这里您可以看到:

  • 功能
    现在不包括输出变量
    累加器的值,因为它实际上应该是这样的;事实上,正如我前面所说,
    特性
    现在与
    编码数据项
    相同,这使得
    矢量汇编程序
    变得多余,这正是我们所期望的,因为我们只有一个特性
  • 现在,
    预测
    值对于
    名称项
    的相同值是相同的,这也是我们所期望的,而且它们不太准确,因此更真实

  • 因此,最确定的是,您的问题与您正在使用的过时的Spark版本1.4.4有关。自从V1.4以来,SCAP已经飞跃了,你应该认真考虑更新……/P>你真的有688个类别在<代码> NameItem > /Cord>?现在没有时间深入调查,所以请尝试下面的答案,留下反馈,明天下午我可能会回来深入调查(你的Spark版本是什么?)。我的Spark版本是1.4.4