fixed bug with heteroscedastic z-score in Variance Ratio Test

This commit is contained in:
mrFendel 2023-04-18 19:16:10 +03:00
parent e6da61c52a
commit 98781c83ad
2 changed files with 15 additions and 17 deletions

View File

@ -5,11 +5,11 @@
package space.kscience.kmath.series package space.kscience.kmath.series
import space.kscience.kmath.operations.DoubleBufferOps.Companion.map
import space.kscience.kmath.operations.DoubleField.pow import space.kscience.kmath.operations.DoubleField.pow
import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.algebra
import space.kscience.kmath.operations.bufferAlgebra import space.kscience.kmath.operations.bufferAlgebra
import space.kscience.kmath.operations.fold import space.kscience.kmath.operations.fold
import space.kscience.kmath.structures.slice
// TODO: add p-value with formula: 2*(1 - cdf(|zScore|)) // TODO: add p-value with formula: 2*(1 - cdf(|zScore|))
@ -22,7 +22,7 @@ public data class VarianceRatioTestResult(val varianceRatio: Double, val zScore:
public fun varianceRatioTest(series: Series<Double>, shift: Int, homoscedastic: Boolean=true): VarianceRatioTestResult { public fun varianceRatioTest(series: Series<Double>, shift: Int, homoscedastic: Boolean=true): VarianceRatioTestResult {
/** /**
* Calculate the Z statistic and the p-value for the Lo and MacKinlay's Variance Ratio test (1987) * Calculates the Z-statistic and the p-value for the Lo and MacKinlay's Variance Ratio test (1987)
* under Homoscedastic or Heteroscedstic assumptions * under Homoscedastic or Heteroscedstic assumptions
* https://ssrn.com/abstract=346975 * https://ssrn.com/abstract=346975
* **/ * **/
@ -50,13 +50,12 @@ public fun varianceRatioTest(series: Series<Double>, shift: Int, homoscedastic:
// calculating asymptotic variance // calculating asymptotic variance
val phi = if (homoscedastic) { // under homoscedastic null hypothesis val phi = if (homoscedastic) { // under homoscedastic null hypothesis
2 * (2 * shift - 1.0) * (shift - 1.0) / (3 * shift * series.size) 2 * (2 * shift - 1.0) * (shift - 1.0) / (3 * shift * series.size)
} else { // under homoscedastic null hypothesis } else { // under heteroscedastic null hypothesis
var accumulator = 0.0 var accumulator = 0.0
var shiftedProd = demeanedSquares
for (j in 1..<shift) { for (j in 1..<shift) {
shiftedProd = shiftedProd.zip(demeanedSquares.moveTo(j)) { v1, v2 -> v1 * v2 } var temp = demeanedSquares
val delta = series.size * shiftedProd.fold(0.0, sum) / variance.pow(2) val delta = series.size * temp.zipWithShift(j) { v1, v2 -> v1 * v2 }.fold(0.0, sum) / variance.pow(2)
accumulator += delta * 4 * (shift - j) * (shift - j) / shift / shift // TODO: refactor with square accumulator += delta * 4 * (shift - j).toDouble().pow(2) / shift.toDouble().pow(2)
} }
accumulator accumulator
} }

View File

@ -13,7 +13,6 @@ import kotlin.test.assertEquals
class TestVarianceRatioTest { class TestVarianceRatioTest {
// TODO: refactor Heteroscedastic zScore
@Test @Test
fun monotonicData() { fun monotonicData() {
with(Double.algebra.bufferAlgebra.seriesAlgebra()) { with(Double.algebra.bufferAlgebra.seriesAlgebra()) {
@ -22,9 +21,9 @@ class TestVarianceRatioTest {
assertEquals(1.818181, resultHomo.varianceRatio, 1e-6) assertEquals(1.818181, resultHomo.varianceRatio, 1e-6)
// homoscedastic zScore // homoscedastic zScore
assertEquals(2.587318, resultHomo.zScore, 1e-6) assertEquals(2.587318, resultHomo.zScore, 1e-6)
// val resultHetero = varianceRatioTest(monotonicData, 2, homoscedastic = false) val resultHetero = varianceRatioTest(monotonicData, 2, homoscedastic = false)
// // heteroscedastic zScore // heteroscedastic zScore
// assertEquals(3.253248, resultHetero.zScore, 1e-6) assertEquals(0.819424, resultHetero.zScore, 1e-6)
} }
} }
@ -36,9 +35,9 @@ class TestVarianceRatioTest {
assertEquals(0.0, resultHomo.varianceRatio, 1e-6) assertEquals(0.0, resultHomo.varianceRatio, 1e-6)
// homoscedastic zScore // homoscedastic zScore
assertEquals(-3.162277, resultHomo.zScore, 1e-6) assertEquals(-3.162277, resultHomo.zScore, 1e-6)
// val resultHetero = varianceRatioTest(volatileData, 2, homoscedastic = false) val resultHetero = varianceRatioTest(volatileData, 2, homoscedastic = false)
// // heteroscedastic zScore // heteroscedastic zScore
// assertEquals(-3.535533, resultHetero.zScore, 1e-6) assertEquals(-1.0540925, resultHetero.zScore, 1e-6)
} }
} }
@ -50,9 +49,9 @@ class TestVarianceRatioTest {
assertEquals(1.240031, resultHomo.varianceRatio, 1e-6) assertEquals(1.240031, resultHomo.varianceRatio, 1e-6)
// homoscedastic zScore // homoscedastic zScore
assertEquals(0.509183, resultHomo.zScore, 1e-6) assertEquals(0.509183, resultHomo.zScore, 1e-6)
// val resultHetero = varianceRatioTest(negativeData, 3, homoscedastic = false) val resultHetero = varianceRatioTest(negativeData, 3, homoscedastic = false)
// // heteroscedastic zScore // heteroscedastic zScore
// assertEquals(0.661798, resultHetero.zScore, 1e-6) assertEquals(0.209202, resultHetero.zScore, 1e-6)
} }
} }