mirror of
https://github.com/gonum/gonum.git
synced 2025-10-05 23:26:52 +08:00

Changes made in dsp/fourier/internal/fftpack break the formatting used there, so these are reverted. There will be complaints in CI. [git-generate] gofmt -w . go generate gonum.org/v1/gonum/blas go generate gonum.org/v1/gonum/blas/gonum go generate gonum.org/v1/gonum/unit go generate gonum.org/v1/gonum/unit/constant go generate gonum.org/v1/gonum/graph/formats/dot go generate gonum.org/v1/gonum/graph/formats/rdf go generate gonum.org/v1/gonum/stat/card git checkout -- dsp/fourier/internal/fftpack
163 lines
4.1 KiB
Go
163 lines
4.1 KiB
Go
// Copyright ©2017 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package spatial
|
|
|
|
import (
|
|
"math"
|
|
|
|
"gonum.org/v1/gonum/mat"
|
|
"gonum.org/v1/gonum/stat"
|
|
)
|
|
|
|
// TODO(kortschak): Implement weighted routines.
|
|
|
|
// GetisOrdGStar returns the Local Getis-Ord G*i statistic for element of the
|
|
// weighted data using the provided locality matrix. The returned value is a z-score.
|
|
//
|
|
// G^*_i = num_i / den_i
|
|
//
|
|
// num_i = \sum_j (w_{ij} x_j) - \bar X \sum_j w_{ij}
|
|
// den_i = S \sqrt(((n \sum_j w_{ij}^2 - (\sum_j w_{ij})^2))/(n - 1))
|
|
// \bar X = (\sum_j x_j) / n
|
|
// S = \sqrt((\sum_j x_j^2)/n - (\bar X)^2)
|
|
//
|
|
// GetisOrdGStar will panic if locality is not a square matrix with dimensions the
|
|
// same as the length of data or if i is not a valid index into data.
|
|
//
|
|
// See doi.org/10.1111%2Fj.1538-4632.1995.tb00912.x.
|
|
//
|
|
// Weighted Getis-Ord G*i is not currently implemented and GetisOrdGStar will
|
|
// panic if weights is not nil.
|
|
func GetisOrdGStar(i int, data, weights []float64, locality mat.Matrix) float64 {
|
|
if weights != nil {
|
|
panic("spatial: weighted data not yet implemented")
|
|
}
|
|
r, c := locality.Dims()
|
|
if r != len(data) || c != len(data) {
|
|
panic("spatial: data length mismatch")
|
|
}
|
|
|
|
n := float64(len(data))
|
|
mean, std := stat.MeanStdDev(data, weights)
|
|
var dwd, dww, sw float64
|
|
if doer, ok := locality.(mat.RowNonZeroDoer); ok {
|
|
doer.DoRowNonZero(i, func(_, j int, w float64) {
|
|
sw += w
|
|
dwd += w * data[j]
|
|
dww += w * w
|
|
})
|
|
} else {
|
|
for j, v := range data {
|
|
w := locality.At(i, j)
|
|
sw += w
|
|
dwd += w * v
|
|
dww += w * w
|
|
}
|
|
}
|
|
s := std * math.Sqrt((n-1)/n)
|
|
|
|
return (dwd - mean*sw) / (s * math.Sqrt((n*dww-sw*sw)/(n-1)))
|
|
}
|
|
|
|
// GlobalMoransI performs Global Moran's I calculation of spatial autocorrelation
|
|
// for the given data using the provided locality matrix. GlobalMoransI returns
|
|
// Moran's I, Var(I) and the z-score associated with those values.
|
|
// GlobalMoransI will panic if locality is not a square matrix with dimensions the
|
|
// same as the length of data.
|
|
//
|
|
// See https://doi.org/10.1111%2Fj.1538-4632.2007.00708.x.
|
|
//
|
|
// Weighted Global Moran's I is not currently implemented and GlobalMoransI will
|
|
// panic if weights is not nil.
|
|
func GlobalMoransI(data, weights []float64, locality mat.Matrix) (i, v, z float64) {
|
|
if weights != nil {
|
|
panic("spatial: weighted data not yet implemented")
|
|
}
|
|
if r, c := locality.Dims(); r != len(data) || c != len(data) {
|
|
panic("spatial: data length mismatch")
|
|
}
|
|
mean := stat.Mean(data, nil)
|
|
|
|
doer, isDoer := locality.(mat.RowNonZeroDoer)
|
|
|
|
// Calculate Moran's I for the data.
|
|
var num, den, sum float64
|
|
for i, xi := range data {
|
|
zi := xi - mean
|
|
den += zi * zi
|
|
if isDoer {
|
|
doer.DoRowNonZero(i, func(_, j int, w float64) {
|
|
sum += w
|
|
zj := data[j] - mean
|
|
num += w * zi * zj
|
|
})
|
|
} else {
|
|
for j, xj := range data {
|
|
w := locality.At(i, j)
|
|
sum += w
|
|
zj := xj - mean
|
|
num += w * zi * zj
|
|
}
|
|
}
|
|
}
|
|
i = (float64(len(data)) / sum) * (num / den)
|
|
|
|
// Calculate Moran's E(I) for the data.
|
|
e := -1 / float64(len(data)-1)
|
|
|
|
// Calculate Moran's Var(I) for the data.
|
|
// http://pro.arcgis.com/en/pro-app/tool-reference/spatial-statistics/h-how-spatial-autocorrelation-moran-s-i-spatial-st.htm
|
|
// http://pro.arcgis.com/en/pro-app/tool-reference/spatial-statistics/h-global-morans-i-additional-math.htm
|
|
var s0, s1, s2 float64
|
|
var var2, var4 float64
|
|
for i, v := range data {
|
|
v -= mean
|
|
v *= v
|
|
var2 += v
|
|
var4 += v * v
|
|
|
|
var p2 float64
|
|
if isDoer {
|
|
doer.DoRowNonZero(i, func(i, j int, wij float64) {
|
|
wji := locality.At(j, i)
|
|
|
|
s0 += wij
|
|
|
|
v := wij + wji
|
|
s1 += v * v
|
|
|
|
p2 += v
|
|
})
|
|
} else {
|
|
for j := range data {
|
|
wij := locality.At(i, j)
|
|
wji := locality.At(j, i)
|
|
|
|
s0 += wij
|
|
|
|
v := wij + wji
|
|
s1 += v * v
|
|
|
|
p2 += v
|
|
}
|
|
}
|
|
s2 += p2 * p2
|
|
}
|
|
s1 *= 0.5
|
|
|
|
n := float64(len(data))
|
|
a := n * ((n*n-3*n+3)*s1 - n*s2 + 3*s0*s0)
|
|
c := (n - 1) * (n - 2) * (n - 3) * s0 * s0
|
|
d := var4 / (var2 * var2)
|
|
b := d * ((n*n-n)*s1 - 2*n*s2 + 6*s0*s0)
|
|
|
|
v = (a-b)/c - e*e
|
|
|
|
// Calculate z-score associated with Moran's I for the data.
|
|
z = (i - e) / math.Sqrt(v)
|
|
|
|
return i, v, z
|
|
}
|