mirror of
https://github.com/gonum/gonum.git
synced 2025-10-25 00:00:24 +08:00
example implementation of pure go covariancematrix
This commit is contained in:
@@ -5,18 +5,113 @@
|
|||||||
package stat
|
package stat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
// "runtime"
|
||||||
|
|
||||||
"github.com/gonum/matrix/mat64"
|
"github.com/gonum/matrix/mat64"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type covMatElem struct {
|
||||||
|
i, j int
|
||||||
|
v float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type covMatSlice struct {
|
||||||
|
i, j int
|
||||||
|
x, y []float64
|
||||||
|
}
|
||||||
|
|
||||||
// CovarianceMatrix calculates a covariance matrix (also known as a
|
// CovarianceMatrix calculates a covariance matrix (also known as a
|
||||||
// variance-covariance matrix) from a matrix of data.
|
// variance-covariance matrix) from a matrix of data.
|
||||||
func CovarianceMatrix(x mat64.Matrix) *mat64.Dense {
|
func CovarianceMatrix(x mat64.Matrix) *mat64.Dense {
|
||||||
|
|
||||||
// matrix version of the two pass algorithm. This doesn't use
|
// matrix version of the two pass algorithm. This doesn't use
|
||||||
// the correction found in the Covariance and Variance functions.
|
// the correction found in the Covariance and Variance functions.
|
||||||
|
r, c := x.Dims()
|
||||||
|
|
||||||
|
if x, ok := x.(mat64.Vectorer); ok {
|
||||||
|
cols := make([][]float64, c)
|
||||||
|
// perform the covariance or variance as required
|
||||||
|
blockSize := 1024
|
||||||
|
if blockSize > c {
|
||||||
|
blockSize = c
|
||||||
|
}
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(c)
|
||||||
|
for j := 0; j < c; j++ {
|
||||||
|
go func(j int) {
|
||||||
|
// pull the columns out and subtract the means
|
||||||
|
cols[j] = make([]float64, r)
|
||||||
|
x.Col(cols[j], j)
|
||||||
|
mean := Mean(cols[j], nil)
|
||||||
|
for i := range cols[j] {
|
||||||
|
cols[j][i] -= mean
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}(j)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
colCh := make(chan covMatSlice, blockSize)
|
||||||
|
resCh := make(chan covMatElem, blockSize)
|
||||||
|
|
||||||
r, _ := x.Dims()
|
wg.Add(blockSize)
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(resCh)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for i := 0; i < blockSize; i++ {
|
||||||
|
go func(in <-chan covMatSlice, out chan<- covMatElem) {
|
||||||
|
for {
|
||||||
|
xy, more := <-in
|
||||||
|
if !more {
|
||||||
|
wg.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if xy.i == xy.j {
|
||||||
|
out <- covMatElem{
|
||||||
|
i: xy.i,
|
||||||
|
j: xy.j,
|
||||||
|
v: centeredVariance(xy.x),
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out <- covMatElem{
|
||||||
|
i: xy.i,
|
||||||
|
j: xy.j,
|
||||||
|
v: centeredCovariance(xy.x, xy.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(colCh, resCh)
|
||||||
|
}
|
||||||
|
go func(out chan<- covMatSlice) {
|
||||||
|
for i := 0; i < c; i++ {
|
||||||
|
for j := 0; j <= i; j++ {
|
||||||
|
out <- covMatSlice{
|
||||||
|
i: i,
|
||||||
|
j: j,
|
||||||
|
x: cols[i],
|
||||||
|
y: cols[j],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(out)
|
||||||
|
}(colCh)
|
||||||
|
// create the output matrix
|
||||||
|
m := mat64.NewDense(c, c, nil)
|
||||||
|
for {
|
||||||
|
c, more := <-resCh
|
||||||
|
if !more {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
m.Set(c.i, c.j, c.v)
|
||||||
|
if c.i != c.j {
|
||||||
|
m.Set(c.j, c.i, c.v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// determine the mean of each of the columns
|
// determine the mean of each of the columns
|
||||||
b := ones(1, r)
|
b := ones(1, r)
|
||||||
b.Mul(b, x)
|
b.Mul(b, x)
|
||||||
@@ -52,3 +147,19 @@ func ones(r, c int) *mat64.Dense {
|
|||||||
}
|
}
|
||||||
return mat64.NewDense(r, c, x)
|
return mat64.NewDense(r, c, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func centeredVariance(x []float64) float64 {
|
||||||
|
var ss float64
|
||||||
|
for _, xv := range x {
|
||||||
|
ss += xv * xv
|
||||||
|
}
|
||||||
|
return ss / float64(len(x)-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func centeredCovariance(x, y []float64) float64 {
|
||||||
|
var ss float64
|
||||||
|
for i, xv := range x {
|
||||||
|
ss += xv * y[i]
|
||||||
|
}
|
||||||
|
return ss / float64(len(x)-1)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user