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  }