【博学谷学习记录】超强总结,用心分享|大数据之Spark 特征工程相关API

文章介绍了在机器学习任务中特征工程的重要性,特别是使用SparkMLlib库进行数据预处理,包括将类别型特征转换为数值型的StringIndexer和OneHotEncoder,以及如何通过VectorAssembler将多列特征组合成单一特征向量。此外,还详细阐述了KMeans聚类模型的工作原理,强调了选择合适K值的重要性,并展示了KMeans在Spark中的使用示例。
摘要由CSDN通过智能技术生成

特征工程相关API

机器学习任务中, 特征工程作用类似于大数据任务中ETL作用

  • 类别型特征→数值型特征
  • 数值型特征, 做特征缩放
  • 特征组合(交叉)/特征筛选/特征衍生 数据处理的基本API
    • 特征组合(交叉) 性别, 年龄, 职业, 活跃时段
    • 特征衍生 原始数据 经过一些计算, 比如做分组聚合 得到新的特征
  • Spark MLlib 特征拼接, 训练模型之前, 所有的特征必须放在一列中

1.1 StringIndexer

当特征/目标 是类别型的数据, 需要转换成数值型, StringIndexer是其中一种转换方式, 编码成 0,1,2… 出现次数最多的类别会编码成0 , 以此类推

from pyspark.ml.feature import StringIndexer
from pyspark.sql.types import StructField, StructType, StringType, LongType

from pyspark.sql import SparkSession
import os
# 2-服务器路径
SPARK_HOME = '/export/server/spark'
PYSPARK_PYTHON = '/root/anaconda3/envs/pyspark_env/bin/python'
# 导入路径
os.environ['SPARK_HOME'] = SPARK_HOME
os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON

if __name__ == '__main__':
    spark = SparkSession.builder.master('local[*]').appName('ml_test').getOrCreate()
    df = spark.createDataFrame(
        [(0, "a"), (1, "b"), (2, "c"), (3, "a"), (4, "a"), (5, "c")],
        ["id", "category"])

    df.show()
    # inputCol 要处理数据的输入列, 列名,   outputCol 处理之后结果保存的列名
    str_indexer = StringIndexer(inputCol='category',outputCol='output')
    # StringIndexer 是Estimator 的子类
    indexer_model = str_indexer.fit(df)
    # 调用fit方法, 是统计每个类别出现的次数, 找到类别和编码之间的对应关系 a →0 b → 2   c → 1
    indexed_result_df = indexer_model.transform(df)
    #indexer_model StringIndexer对象调用了fit方法之后 会返回一个StringIndexerModel对象, 它是一个Transformer (变换器)
    # transform 方法执行了之后, 才会处理数据, 把变换的结果放到数据集中

    indexed_result_df.show()

1.2 One hot encoder

性别 男性, 女性, 未知 0,1,2

1,0,0

0,1,0

0,0,1

spark 做one-hot 默认的实现 [0,0] 男性 [1,0] 女性 [0,1]未知 droplast参数 默认设置为True 用两列来表示3个状态, [0,0] 也算一个状态

代码实现

from pyspark.ml.feature import StringIndexer, OneHotEncoder
from pyspark.sql.types import StructField, StructType, StringType, LongType

from pyspark.sql import SparkSession
import os
# 2-服务器路径
SPARK_HOME = '/export/server/spark'
PYSPARK_PYTHON = '/root/anaconda3/envs/pyspark_env/bin/python'
# 导入路径
os.environ['SPARK_HOME'] = SPARK_HOME
os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON

if __name__ == '__main__':
    spark = SparkSession.builder.master('local[*]').appName('ml_test').getOrCreate()
    df = spark.createDataFrame(
        [(0, "a"), (1, "b"), (2, "c"), (3, "a"), (4, "a"), (5, "c")],
        ["id", "category"])

    df.show()
    # inputCol 要处理数据的输入列, 列名,   outputCol 处理之后结果保存的列名
    str_indexer = StringIndexer(inputCol='category',outputCol='output')
    # StringIndexer 是Estimator 的子类
    indexer_model = str_indexer.fit(df)
    # 调用fit方法, 是统计每个类别出现的次数, 找到类别和编码之间的对应关系 a →0 b → 2   c → 1
    indexed_result_df = indexer_model.transform(df)
    #indexer_model StringIndexer对象调用了fit方法之后 会返回一个StringIndexerModel对象, 它是一个Transformer (变换器)
    # transform 方法执行了之后, 才会处理数据, 把变换的结果放到数据集中

    indexed_result_df.show()

    indexed_result_df.printSchema()
    #  OneHotEncoder 它的输入必须是数值型
    # 创建一个OneHotEncoder对象 dropLast 默认是True 3个类别的onehot 默认用两列来表示 [0,0] 也表示一个类别
    # 设置为False 3个类别的onehot 用三列(3个开关)来表示
    one_hot_encoder = OneHotEncoder(inputCol='output',outputCol='one_hot_output',dropLast=False)
    one_hot_df = one_hot_encoder.transform(indexed_result_df)
    one_hot_df.show()
    # 返回的结果是一个稀疏向量 描述了向量的列数 非零元素的位置, 非零元素的值
    one_hot_df.printSchema()
    
    # requirement failed: Input column must be of type numeric but got string 
    # one_hot_encoder = OneHotEncoder(inputCol='category', outputCol='one_hot_output', dropLast=False)
    # one_hot_df = one_hot_encoder.transform(df)
    # one_hot_df.show()

如果数值是类别型, 非数值型 先走StringIndexer 再走OneHotEncoder SparkMLlib 这一点跟 单机机器学习框架 比如sklearn不同的地方

1.3 VectorAssembler

为什么要用VectorAssembler

SparkMLlib 要求, 在训练模型的时候, 所有模型的API接受的传入特征的参数, 只能传一列, 如果我们有多列数据要作为特征输入给模型对象, 需要先通过VectorAssembler 拼成一列向量, 才能做后续的计算. 这里也是SparkMLlib 和其它机器学习框架有区别的地方

怎么用

from pyspark.ml.feature import StringIndexer, OneHotEncoder, VectorAssembler
from pyspark.ml.linalg import Vectors
from pyspark.sql.types import StructField, StructType, StringType, LongType

from pyspark.sql import SparkSession
import os
# 2-服务器路径
SPARK_HOME = '/export/server/spark'
PYSPARK_PYTHON = '/root/anaconda3/envs/pyspark_env/bin/python'
# 导入路径
os.environ['SPARK_HOME'] = SPARK_HOME
os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON

if __name__ == '__main__':
    spark = SparkSession.builder.master('local[*]').appName('ml_test').getOrCreate()
    dataset = spark.createDataFrame(
        [(0, 18, 1.0, Vectors.dense([0.0, 10.0, 0.5]), 1.0)],
        ["id", "hour", "mobile", "userFeatures", "clicked"])
    dataset.printSchema()
    dataset.show()
    
    # 创建VectorAssembler 对象 指定输入列 inputCols 不是 inputCol 说明这里接收一个列表, 可以传入多列, 用于模型训练的所有的列都放在这里
    # 输出列 outputCol
    assembler = VectorAssembler(inputCols=['hour','mobile','userFeatures'],outputCol='features')
    # VectorAssembler 是一个Transformer对象, 直接调用transform 方法
    vec_df = assembler.transform(dataset)
    vec_df.printSchema()
    vec_df.show(truncate=False)

2. KMeans 模型原理

KMeans 是一个无监督聚类模型, 典型的应用场景就是做用户的分群

2.1 聚类算法概念

一种典型的 无监督 学习算法,主要用于将相似的样本自动归到一个类别中

聚类跟分类之前的异同

  • 相似的地方, 都是把数据分成不同的类别
  • 不同点
    • 分类算法是监督学习算法, 要求数据有目标值, 分类的结果在数据的目标值中已经确定好了
    • 聚类算法是无监督学习算法, 数据中没有目标值, 聚类之后, 究竟聚成几个类别是最合适的, 只有聚类之后才知道

2.2 KMeans 聚类

K 聚类的数量, 究竟聚成几个类别, 这个值可以调整

Means 平均

基本原理: 离得近的样本聚到一个类别中, 离得远的样本聚到不同类别中

K-means聚类实现流程

  • 事先 确定常数K ,常数K意味着最终的聚类类别数;
  • 随机 选定初始点为质心 ,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相似的类中,
  • 接着,重新计算 每个类的质心(means 同一个类别的点, 每个维度计算平均值, 得到均值对应的坐标点,即为类中心),重复这样的过程,直到 质心不再改变
  • 最终就确定了每个样本所属的类别以及每个类的质心(聚类中心点)。
  • 注意:由于每次都要计算所有的样本与每一个质心之间的相似度,故在大规模的数据集上,K-Means算法的收敛速度比较慢。

K-means效果的评价

K的取值: 同一份数据 究竟聚成几类效果最好, 可以通过轮廓系数的大小来判断

a: 样本i到同一簇内其它点不相似程度(欧式距离)的平均值

b: 样本i到其它簇内的点(欧式距离)平均值的最小值

轮廓系数的取值范围 -1,1 值越大越好

K取不同的值, 计算轮廓系数, 选择轮廓系数比较大的聚类结果对应的K值

在这里插入图片描述

2.3 KMeans 的api

from pyspark.ml.clustering import KMeans
from pyspark.ml.evaluation import ClusteringEvaluator
from pyspark.ml.feature import StringIndexer, OneHotEncoder, VectorAssembler
from pyspark.ml.linalg import Vectors
from pyspark.sql.types import StructField, StructType, StringType, LongType

from pyspark.sql import SparkSession
import os
# 2-服务器路径
SPARK_HOME = '/export/server/spark'
PYSPARK_PYTHON = '/root/anaconda3/envs/pyspark_env/bin/python'
# 导入路径
os.environ['SPARK_HOME'] = SPARK_HOME
os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON

if __name__ == '__main__':
    spark = SparkSession.builder.master('local[*]').appName('ml_test').getOrCreate()
    dataset = spark.read.format('csv').option('header',True).option('inferSchema',True).\
        load('file:///root/tmp/user_profile/test/medium.txt')
    dataset.printSchema()
    dataset.show()
    # 特征组装
    assember = VectorAssembler(inputCols=['Weightindex','PH值'],outputCol='features')
    vec_df = assember.transform(dataset)
    #  featuresCol: str = 'features', 特征列
    #  predictionCol: str = 'prediction', 输出结果列
    #  k: int = 2,  聚成几类
    # initMode: str = 'k-means||',  kmeans++ 随机选择K个初始值点的时候, 为了避免这些点离得太近, 第一个随机选,
    # 从第二个点开始找离第一个点尽可能远的点
    # seed: Optional[int] = None, 随机数种子 可以传入一个整数值, 取值的大小没有意义, 每次执行代码的时候, seed一样是有影响的,
    # 当数据不变, 参数一致, seed也给一样的值, 每次聚类结果是可以复现的
    kmeans = KMeans(k=2,featuresCol='features',predictionCol='prediction')
    kmeans_model = kmeans.fit(vec_df) # 使用kmeans 对象 fit 训练模型
    kmeans_result_df = kmeans_model.transform(vec_df)
    kmeans_result_df.show()

    # predictionCol 'prediction'
    # featuresCol: features
    # metricName: "silhouette"
    evaluator = ClusteringEvaluator()
    silhouette_score = evaluator.evaluate(kmeans_result_df)
    print(silhouette_score)
    
    # 聚类中心点
    centers = kmeans_model.clusterCenters()
    print(centers)

3 KMeans做RFM标签基本思路

KMeans 在数据挖掘中的应用场景就是做聚类(用户聚类, 用户分群)

  • RFM三个维度分组聚合

  • RFM三个维度打分

使用KMeans 把R/F/M 三个维度的分数传进去, 让Kmeans将分数差不多的用户聚到一起

聚类的过程比较简单, 但是对于结果的处理相对复杂

  • 要给每一个类别一个业务含义, 我们要区分, 聚类之后的结果, 那个类别价值比较高, 那个类别价值比较低

通过聚类中心来判断每个类别的价值

R/F/M 三个维度放进去 聚类之后返回的聚类中心, 每个类别也是3个维度, 我们可以用聚类中心点三个值的大小判断那个类别价值高, 那个类别价值低

最简单的办法, 聚类中心点相加, 比大小 , 聚类中心点求和比较大的类别, 就是高价值, 聚类中心点求和比较小的, 就是相对低价值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值