【spark ML系列】Vectors上进行矢量化统计的工具点击这里看全文
文章目录
一、原理
Spark的Summarizer
源码是用于在MLlib Vectors上进行矢量化统计的工具。它提供了一组方法,用于计算给定列的摘要统计信息。
首先,Summarizer
中的metrics
方法接受一组指标,并返回一个构建器对象SummaryBuilder
。该构建器对象用于计算列的指标。
在SummaryBuilder
中,根据用户请求的指标,调用summary
方法返回一个聚合列,包含所请求指标的列的摘要统计信息。summary
方法使用MetricsAggregate
实现聚合操作,并返回一个Column
对象。
MetricsAggregate
是一个TypedImperativeAggregate
的实现类,负责执行具体的统计计算。它根据用户请求的指标和计算度量,在输入数据上进行聚合计算,并将结果封装成InternalRow
对象。
SummarizerBuffer
是一个用于存储和更新统计数据的辅助类。它包含各种变量和方法,用于计算并存储每个指标的结果。在每次添加新样本或合并多个SummarizerBuffer
时,都会更新统计数据。
最后,用户可以根据需要选择性地调用Summarizer
中提供的方法,获取特定指标的统计结果。
总体而言,Summarizer
源码通过组合和调用不同的类和方法,实现了在MLlib Vectors上进行矢量化统计的功能。它提供了灵活和高效的统计计算方法,方便用户对数据进行摘要分析。
二、功能用法
1.SummaryBuilder
用于提供有关给定列的摘要统计信息的构建器对象。
用户不应直接创建这样的构建器,而应使用Summarizer
中的方法之一。
2.Summarizer
用于在MLlib Vectors上进行矢量化统计的工具。
该包中的方法为DataFrames中包含的Vectors提供了各种统计数据。
此类使用户可以选择他们想要从给定列提取的统计信息。以下是Scala中的示例:
import org.apache.spark.ml.linalg._
import org.apache.spark.sql.Row
val dataframe = ... // 包含特征列和权重列的DataFrame
val multiStatsDF = dataframe.select(
Summarizer.metrics("min", "max", "count").summary($"features", $"weight")
val Row(minVec, maxVec, count) = multiStatsDF.first()
如果只想获取单个指标,则还提供了快捷方式:
val meanDF = dataframe.select(Summarizer.mean($"features"))
val Row(meanVec) = meanDF.first()
注意:当前,使用此接口的性能约为使用RDD接口的2倍至3倍。
3.metrics
给定一组指标,提供一个构建器,用于计算列的指标。
请参阅Summarizer
的文档以获取示例。
接受以下指标(区分大小写):
- mean: 包含按系数求平均值的向量。
- sum: 包含按系数求和的向量。
- variance: 包含按系数求方差的向量。
- std: 包含按系数求标准差的向量。
- count: 观察到的向量总数。
- numNonzeros: 每个系数的非零数量向量
- max: 每个系数的最大值。
- min: 每个系数的最小值。
- normL2: 每个系数的欧几里德范数。
- normL1: 每个系数的L1范数(绝对值之和)。
4.mean
获取给定列的平均值。
5.sum
获取给定列的总和。
6.variance
获取给定列的方差。
7.std
获取给定列的标准差。
8.count
获取给定列的观察到的向量总数。
9.numNonZeros
获取给定列中每个系数的非零数量。
10.max
获取给定列中每个系数的最大值。
11.min
获取给定列中每个系数的最小值。
12.normL1
获取给定列中每个系数的L1范数(绝对值之和)。
13.normL2
获取给定列中每个系数的欧几里德范数。
三、示例
package org.example.spark
import org.apache.spark.ml.stat.Summarizer
import org.apache.spark.sql.functions.lit
import org.apache.spark.sql.{
Row, SparkSession}
object VectorStatExample {
def main(args: Array[String]): Unit = {
// 创建SparkSession
val spark = SparkSession.builder()
.appName("VectorStatExample")
.master("local[*]")
.getOrCreate()
// 加载数据集
val vecData = spark.read.format("libsvm")
.load("D:\\work\\src\\sparkall\\spark-2.4.0\\spark-2.4.0\\data\\mllib\\sample_linear_regression_data.txt")
.withColumn("weight",lit(1.0))
import org.apache.spark.sql.functions.col
/**
* 获取单个指标
*/
val meanDF = vecData.select(Summarizer.mean(col("features")).alias( "vec_mean"))
val Row(meanVec) = meanDF.first()
println("meanVec="+meanVec)
/**
* 从给定向量列提取的统计信息
*/
val multiStatsDF = vecData.select(
Summarizer.metrics("min", "max", "count").summary(col("features"),col("weight") ).alias("vec_stat")
).select("vec_stat.min","vec_stat.max","vec_stat.count")
val Row(minVec , maxVec, count) = multiStatsDF.first()
println("minVec="+minVec+"\n maxVec="+maxVec+"\ncount="+count)
// 关闭SparkSession
spark.stop()
}
}
//meanVec=[0.018333248314819788,0.028086075973169845,0.018246937236849677,0.057697144268681534,-0.023457518227654153,-0.023676137051387665,0.012449307729786111,0.024422549927171893,-0.00822425472262257,0.022538317316159982]
//minVec=[-0.9919593184325572,-0.9981936663594053,-0.9993240281686275,-0.9982007415355478,-0.9950315917350652,-0.9996126872234177,-0.994819896842561,-0.9942304127133292,-0.9975425877998279,-0.9992933613402135]
//maxVec=[0.9990215581592679,0.9990094335332504,0.9949216290375054,0.9917728248530817,0.9974035542095165,0.9993906921393696,0.9992936758550379,0.9995670294711712,0.9938658554834845,0.9917688731048739]
//count=501
四、源码分析
SummaryBuilder
/**
* 用于计算列的摘要统计信息的构建器对象。
*
* 用户不应直接创建此类的实例,而应使用`Summarizer`中的方法之一。
*/
@Since("2.3.0")
sealed abstract class SummaryBuilder {
/**
* 返回一个聚合对象,其中包含具有所请求指标的列的摘要统计信息。
*
* @param featuresCol 包含特征向量对象的列。
* @param weightCol 包含权重值的列。默认权重为1.0。
* @return 一个包含统计信息的聚合列。此结构的确切内容在构建器创建过程中确定。
*/
@Since("2.3.0")
def summary(featuresCol: Column, weightCol: Column): Column
/**
* 使用默认权重值调用`summary`方法。
*
* @param featuresCol 包含特征向量对象的列。
* @return 一个包含统计信息的聚合列。此结构的确切内容在构建器创建过程中确定。
*/
@Since("2.3.0")
def summary(featuresCol: Column): Column = summary(featuresCol, lit(1.0))
}
object Summarizer
/**
* 用于对MLlib向量进行向量化统计的工具。
*
* 这个类允许用户选择他们想要提取的给定列的统计信息。
以下是一个示例:
* {
{
{
* import org.apache.spark.ml.linalg._
* import org.apache.spark.sql.Row
* val dataframe = ... // 一个包含特征列和权重列的DataFrame
* val multiStatsDF = dataframe.select(
* Summarizer.metrics("min", "max", "count").summary($"features", $"weight")
* val Row(minVec, maxVec, count) = multiStatsDF.first()
* }}}
*
* 如果只想获取单个统计指标,也可以使用快捷方式:
* {
{
{
* val meanDF = dataframe.select(Summarizer.mean($"features"))
* val Row(meanVec) = meanDF.first()
* }}}
*
* 注意:目前,使用此接口的性能约为RDD接口的2倍到3倍。
*/
@Since("2.3.0")
object Summarizer extends Logging {
import SummaryBuilderImpl._
/**
* 给定一组指标,提供一个构建器,用于计算列的指标。
*
* 可以提供以下指标(区分大小写):
* - mean: 包含逐个系数的均值向量。
* - sum: 包含逐个系数的求和向量。
* - variance: 包含逐个系数的方差向量。
* - std: 包含逐个系数的标准差向量。
* - count: 观察到的向量数量。
* - numNonzeros: 每个系数的非零值数量的向量。
* - max: 每个系数的最大值。
* - min: 每个系数的最小值。
* - normL2: 每个系数的欧氏范数。
* - normL1: 每个系数的L1范数(绝对值之和)。
*
* @param metrics 可以提供的指标。
* @return 一个构建器。
* @throws IllegalArgumentException 如果其中一个指标名称无法识别。
*/
@Since("2.3.0")
@scala.annotation.varargs
def metrics(metrics: String*): SummaryBuilder = {
require(metrics.nonEmpty, "至少应包含一个指标")
val (typedMetrics, computeMetrics) = getRelevantMetrics(metrics)
new SummaryBuilderImpl(typedMetrics, computeMetrics)
}
@Since("2.3.0")
def mean(col: Column, weightCol: Column): Column = {
getSingleMetric(col, weightCol, "mean")
}
@Since("2.3.0")
def mean(col: Column): Column = mean(col, lit(1.0))
@Since("3.0.0")
def sum(col: Column, weightCol: Column): Column = {
getSingleMetric(col, weightCol, "sum")
}
@Since("3.0.0")
def sum(col: Column): Column = sum(col, lit(1.0))
@Since("2.3.0")
def variance(col: Column, weightCol: Column): Column = {
getSingleMetric(col, weightCol, "variance")
}
@Since("2.3.0")
def variance(col: Column): Column = variance(col, lit(1.0))
@Since("3.0.0")
def std(col: Column, weightCol: Column): Column = {
getSingleMetric(col, weightCol, "std")
}
@Since("3.0.0")
def std(col: Column): Column = std(col, lit(1.0))
@Since("2.3.0")
def count(col: Column, weightCol: Column): Column = {
getSingleMetric(col, weightCol, "count")
}
@Since("2.3.0")
def count(col: Column): Column = count(col, lit(1.0))
@Since("2.3.0")
def numNonZeros(col: Column, weightCol: Column): Column = {
getSingleMetric(col, weightCol, "numNonZeros")
}
@Since("2.3.0")
def numNonZeros(col: Column)