/ / Apache Spark - Dwupróbkowy test Kołmogorowa-Smirnowa - scala, apache-spark, pyspark

Apache Spark - Dwupróbkowy test Kołmogorowa-Smirnowa - scala, apache-spark, pyspark

Mam dwa zestawy danych (nazwijmy je d1, d2)w Spark. Chciałbym wykonać dwu-próbny test Kołmogorowa-Smirnowa, aby przetestować, czy ich podstawowa funkcja dystrybucji poplation jest inna. Czy MLLib może Statistics.kolmogorovSmirnovTest Zrób to?

Dokumentacja zawiera następujący przykład:

import org.apache.spark.mllib.stat.Statistics

val data: RDD[Double] = ... // an RDD of sample data

// perform a KS test using a cumulative distribution function of our making
val myCDF: Double => Double = ...
val testResult2 = Statistics.kolmogorovSmirnovTest(data, myCDF)

Próbowałem obliczać empiryczną skumulowaną funkcję rozkładu d2 (zbierając ją jako Mapę) i porównując ją z d1.

Statistics.kolmogorovSmirnovTest(d1, ecdf_map)

Test działa, ale wyniki są błędne.

czy robię coś źle? Czy można to zrobić? Jakieś pomysły?

Dziękuję za pomoc!

Odpowiedzi:

2 dla odpowiedzi № 1

W Spark Mllib KolmogorovSmirnovTest jest jednoobiektowe i dwustronne. Więc jeśli chcesz konkretnie wariancie z dwoma próbkami, nie jest to możliwe w tej bibliotece, ale możesz nadal porównywać zbiory danych, obliczając empiryczną funkcję dystrybuującą (znalazłem bibliotekę, aby to zrobić, więc zaktualizuję tę odpowiedź, jeśli wyniki będą bądź dobry) lub stosując odchylenia od normalnej dystrybucji. W tym przykładzie pójdę z późniejszym.

Porównywanie zestawów danych według statystyk KST z rozkładem normalnym

Do celów tego testu wygenerowałem 3 dystrybucje: 2 trójkątny które wyglądają podobnie i wykładniczy jeden, aby pokazać dużą różnicę w statystykach.

Uwaga: Nie mogłem znaleźć żadnych prac naukowych opisujących tę metodę jako możliwych do porównania dystrybucji, więc pomysł jest w większości empiryczny.

Dla każdej dystrybucji najbardziej możliwe jest znalezienie kopii lustrzanej z taką samą globalną maksymalną odległością między jej CDF a rozkładem normalnym.

Kolejnym krokiem było uzyskanie wyników KS z rozkładem normalnym z podanym średnim i standardowym odchyleniem. Wizualizowałem je, aby uzyskać lepszy obraz:

wizualizacja bryzy dla rozkładów i wyniki ich badań KS

Jak widać, wyniki (statystyki KS ip-value) dla dystrybucji triangualnych są blisko siebie, podczas gdy wykładnicza jest daleko. Jak już wspomniałem w notatce, można łatwo oszukać tę metodę, lustrując zestaw danych, ale dla prawdziwych danych światowych może być w porządku.

import org.apache.spark._
import org.apache.spark.rdd.RDD
import org.apache.spark.mllib.stat.Statistics

import org.apache.commons.math3.distribution.{ ExponentialDistribution, TriangularDistribution }

import breeze.plot._
import breeze.linalg._
import breeze.numerics._

object Main {

def main( args: Array[ String ] ): Unit = {

val conf =
new SparkConf()
.setAppName( "SO Spark" )
.setMaster( "local[*]" )
.set( "spark.driver.host", "localhost" )

val sc = new SparkContext( conf )

// Create similar distributions
val triDist1 = new TriangularDistribution( -3, 5, 7 )
val triDist2 = new TriangularDistribution( -3, 7, 7 )

// Exponential distribution to show big difference
val expDist1 = new ExponentialDistribution( 0.6 )

// Sample data from the distributions and parallelize it
val n = 100000
val sampledTriDist1 = sc.parallelize( triDist1.sample( n ) )
val sampledTriDist2 = sc.parallelize( triDist2.sample( n ) )
val sampledExpDist1 = sc.parallelize( expDist1.sample( n ) )

// KS tests
val resultTriDist1 = Statistics
.kolmogorovSmirnovTest( sampledTriDist1,
"norm",
sampledTriDist1.mean,
sampledTriDist1.stdev )

val resultTriDist2 = Statistics
.kolmogorovSmirnovTest( sampledTriDist2,
"norm",
sampledTriDist2.mean,
sampledTriDist2.stdev )

val resultExpDist1 = Statistics
.kolmogorovSmirnovTest( sampledExpDist1,
"norm",
sampledExpDist1.mean,
sampledExpDist1.stdev )

// Results
val statsTriDist1 =
"Tri1: ( " +
resultTriDist1.statistic +
", " +
resultTriDist1.pValue +
" )"

val statsTriDist2 =
"Tri2: ( " +
resultTriDist2.statistic +
", " +
resultTriDist2.pValue +
" )"

val statsExpDist1 =
"Exp1: ( " +
resultExpDist1.statistic +
", " +
resultExpDist1.pValue +
" )"

println( statsTriDist1 )
println( statsTriDist2 )
println( statsExpDist1 )

// Visualize
val graphCanvas = Figure()

val mainPlot =
graphCanvas
.subplot( 0 )

mainPlot.legend = true

val x = linspace( 1, n, n )

mainPlot += plot( x,
sampledTriDist1.sortBy( x => x ).take( n ),
name = statsTriDist1 )

mainPlot += plot( x,
sampledTriDist2.sortBy( x => x ).take( n ),
name = statsTriDist2 )

mainPlot += plot( x,
sampledExpDist1.sortBy( x => x ).take( n ),
name = statsExpDist1 )

mainPlot.xlabel = "x"
mainPlot.ylabel = "sorted sample"

mainPlot.title = "KS results for 2 Triangular and 1 Exponential Distributions"

graphCanvas.saveas( "ks-sample.png", 300 )

sc.stop()
}
}