Spark中的PCA异常检测

时间:2018-03-28 09:06:21

标签: apache-spark apache-spark-sql apache-spark-mllib pca anomaly-detection

我阅读了以下文章

Anomaly detection with Principal Component Analysis (PCA)

在文章中写道如下:

•PCA算法基本上将现有坐标系中的数据读数转换为新的坐标系。

•数据读数越接近新坐标系的中心,这些读数越接近最佳值。

•使用读数与所有读数的平均值之间的马哈拉诺比斯距离计算异常分数,该读数是变换坐标系的中心。

有人能更详细地描述一下使用PCA进行异常检测(使用PCA分数和马哈拉诺比斯距离)吗?我感到困惑,因为PCA的定义是:PCA是一种统计程序,它使用正交变换将可能相关变量的一组观察值转换为线性不相关变量的一组值“。当变量之间没有更多的相关性时,如何使用马哈拉诺比斯距离?

有人可以解释我如何在Spark中执行此操作吗? pca.transform函数是否返回得分,我应该计算每次读到中心的马哈拉诺比斯距离?

1 个答案:

答案 0 :(得分:2)

让我们假设你有一个三维点的数据集。 每个点都有坐标(x, y, z)。 那些(x, y, z)是维度。 点由三个值e表示。 G。 (8, 7, 4)。它叫输入向量。

当您应用PCA算法时,您基本上将输入向量转换为新向量。它可以表示为转换(x, y, z) => (v, w).

的函数

示例:(8, 7, 4) => (-4, 13)

现在你收到了一个矢量,一个较短的矢量(减少了一个维数),但你的点仍然有坐标,即(v, w)。这意味着您可以使用Mahalanobis测量计算两点之间的距离。与平均坐标距离较远的点实际上是异常。

示例解决方案:

import breeze.linalg.{DenseVector, inv}
import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.feature.{PCA, StandardScaler, VectorAssembler}
import org.apache.spark.ml.linalg.{Matrix, Vector}
import org.apache.spark.ml.stat.Correlation
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
import org.apache.spark.sql.functions._

object SparkApp extends App {
  val session = SparkSession.builder()
    .appName("spark-app").master("local[*]").getOrCreate()
  session.sparkContext.setLogLevel("ERROR")
  import session.implicits._

  val df = Seq(
    (1, 4, 0),
    (3, 4, 0),
    (1, 3, 0),
    (3, 3, 0),
    (67, 37, 0) //outlier
  ).toDF("x", "y", "z")
  val vectorAssembler = new VectorAssembler().setInputCols(Array("x", "y", "z")).setOutputCol("vector")
  val standardScalar = new StandardScaler().setInputCol("vector").setOutputCol("normalized-vector").setWithMean(true)
    .setWithStd(true)

  val pca = new PCA().setInputCol("normalized-vector").setOutputCol("pca-features").setK(2)

  val pipeline = new Pipeline().setStages(
    Array(vectorAssembler, standardScalar, pca)
  )

  val pcaDF = pipeline.fit(df).transform(df)

  def withMahalanobois(df: DataFrame, inputCol: String): DataFrame = {
    val Row(coeff1: Matrix) = Correlation.corr(df, inputCol).head

    val invCovariance = inv(new breeze.linalg.DenseMatrix(2, 2, coeff1.toArray))

    val mahalanobois = udf[Double, Vector] { v =>
      val vB = DenseVector(v.toArray)
      vB.t * invCovariance * vB
    }

    df.withColumn("mahalanobois", mahalanobois(df(inputCol)))
  }

  val withMahalanobois: DataFrame = withMahalanobois(pcaDF, "pca-features")

  session.close()
}