go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/mathutil/correlation.go (about) 1 /* 2 3 Copyright (c) 2024 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package mathutil 9 10 import ( 11 "math/big" 12 ) 13 14 // Correlation computes the r^2 correlation from a given set of actual 15 // values to a given set of prediction values. 16 // 17 // An r^2 of +1.0 means perfectly correlated, and 0 means completely uncorrelated. 18 // 19 // Because the r^2 is "squared" you will detect inverse and positive correlation with the same output value. 20 func Correlation[T Operatable](actual, prediction []T) float64 { 21 if len(actual) == 0 { 22 return 0 23 } 24 if len(actual) != len(prediction) { 25 return 0 26 } 27 28 actualMeanAccum := zeroBig() 29 predictionMeanAccum := zeroBig() 30 for x := 0; x < len(actual); x++ { 31 actualMeanAccum = addBig(actualMeanAccum, valBig(actual[x])) 32 predictionMeanAccum = addBig(predictionMeanAccum, valBig(prediction[x])) 33 } 34 actualMean := divBig(actualMeanAccum, valBig(len(actual))) 35 predictionMean := divBig(predictionMeanAccum, valBig(len(prediction))) 36 37 numerator := zeroBig() 38 denominatorActual := zeroBig() 39 denominatorPrediction := zeroBig() 40 41 for x := 0; x < len(actual); x++ { 42 actualValue := valBig(actual[x]) 43 predictionValue := valBig(prediction[x]) 44 45 actualVariance := subBig(actualValue, actualMean) 46 predictionVariance := subBig(predictionValue, predictionMean) 47 48 numerator = addBig(numerator, mulBig(actualVariance, predictionVariance)) 49 50 denominatorActual = addBig(denominatorActual, mulBig(actualVariance, actualVariance)) 51 denominatorPrediction = addBig(denominatorPrediction, mulBig(predictionVariance, predictionVariance)) 52 } 53 54 r := divBig(numerator, sqrtBig(mulBig(denominatorActual, denominatorPrediction))) 55 r2, _ := mulBig(r, r).Float64() 56 return r2 57 } 58 59 func zeroBig() *big.Float { 60 output := big.NewFloat(0) 61 return output 62 } 63 64 func valBig[T Operatable](value T) *big.Float { 65 output := big.NewFloat(float64(value)) 66 return output 67 } 68 69 func addBig(a, b *big.Float) *big.Float { 70 output := zeroBig() 71 return output.Add(a, b) 72 } 73 74 func subBig(a, b *big.Float) *big.Float { 75 output := zeroBig() 76 return output.Sub(a, b) 77 } 78 79 func mulBig(a, b *big.Float) *big.Float { 80 output := zeroBig() 81 return output.Mul(a, b) 82 } 83 84 func divBig(a, b *big.Float) *big.Float { 85 output := zeroBig() 86 return output.Quo(a, b) 87 } 88 89 func sqrtBig(a *big.Float) *big.Float { 90 output := zeroBig() 91 return output.Sqrt(a) 92 }