如何将类型Row转换为Vector以提供给KMeans

时间:2016-03-21 22:39:31

标签: apache-spark pyspark k-means apache-spark-mllib pyspark-sql

当我尝试将df2提供给kmeans时,我收到以下错误

clusters = KMeans.train(df2, 10, maxIterations=30,
                        runs=10, initializationMode="random")

我得到的错误:

Cannot convert type <class 'pyspark.sql.types.Row'> into Vector

df2是按以下方式创建的数据框:

df = sqlContext.read.json("data/ALS3.json")
df2 = df.select('latitude','longitude')

df2.show()


     latitude|       longitude|

   60.1643075|      24.9460844|
   60.4686748|      22.2774728|

如何将这两列转换为Vector并将其提供给KMeans?

2 个答案:

答案 0 :(得分:10)

ML

问题在于您错过了documentation's example,并且非常清楚方法train需要DataFrameVector作为功能。< / p>

要修改您当前的数据结构,您可以使用VectorAssembler。在你的情况下,它可能是这样的:

from pyspark.sql.functions import *

vectorAssembler = VectorAssembler(inputCols=["latitude", "longitude"],
                                  outputCol="features")

# For your special case that has string instead of doubles you should cast them first.
expr = [col(c).cast("Double").alias(c) 
        for c in vectorAssembler.getInputCols()]

df2 = df2.select(*expr)
df = vectorAssembler.transform(df2)

此外,您还应该使用课程MinMaxScaler规范化features以获得更好的效果。

MLLib

要使用MLLib实现此目的,您需要先使用地图功能,将所有string值转换为Double,然后将它们合并到DenseVector中}。

rdd = df2.map(lambda data: Vectors.dense([float(c) for c in data]))

在此之后,您可以使用rdd变量训练MLlib's KMeans model

答案 1 :(得分:3)

PySpark 2.3.1 KMeans上执行DataFrame,如下所示:

  1. 编写要包含在群集分析中的列的列表:
  2. feat_cols = ['latitude','longitude']`
    
    1. 您需要所有列都是数值
    2. expr = [col(c).cast("Double").alias(c) for c in feat_cols]
      df2 = df2.select(*expr)
      
      1. 使用mllib.linalg.Vectors
      2. 创建功能向量
        from pyspark.ml.feature import VectorAssembler
        assembler = VectorAssembler(inputCols=feat_cols, outputCol="features")
        df3 = assembler.transform(df2).select('features')
        
        1. 您应该规范化您的功能,因为并非总是需要规范化,但很少会受到伤害(more about this here):
        2. from pyspark.ml.feature import StandardScaler
          scaler = StandardScaler(
              inputCol="features",
              outputCol="scaledFeatures",
              withStd=True,
              withMean=False)
          scalerModel = scaler.fit(df3)
          df4 = scalerModel.transform(df3).drop('features')\
                               .withColumnRenamed('scaledFeatures', 'features')
          
          1. 将您的DataFrame对象df4变为密集的向量RDD
          2. from pyspark.mllib.linalg import Vectors
            data5 = df4.rdd.map(lambda row: Vectors.dense([x for x in row['features']]))
            
            1. 使用获得的RDD对象作为KMeans培训的输入:
            2. from pyspark.mllib.clustering import KMeans
              model = KMeans.train(data5, k=3, maxIterations=10)
              
              1. 示例:在向量空间中对点 p 进行分类:
              2. prediction = model.predict(p)