/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2014, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.process.spatialstatistics.autocorrelation;
import java.util.logging.Logger;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.process.spatialstatistics.core.SSUtils;
import org.geotools.process.spatialstatistics.core.SSUtils.StatEnum;
import org.geotools.process.spatialstatistics.core.SpatialEvent;
import org.geotools.process.spatialstatistics.core.WeightMatrixBuilder;
import org.geotools.process.spatialstatistics.enumeration.DistanceMethod;
import org.geotools.process.spatialstatistics.enumeration.SpatialConcept;
import org.geotools.process.spatialstatistics.enumeration.StandardizationMethod;
import org.geotools.util.logging.Logging;
/**
* Measures the degree of clustering for either high values or low values using the Getis-Ord General G statistic.
*
* @author Minpa Lee, MangoSystem
*
* @source $URL$
*/
public class GlobalGStatisticOperation extends AbstractStatisticsOperation {
protected static final Logger LOGGER = Logging.getLogger(GlobalGStatisticOperation.class);
public GlobalGStatisticOperation() {
// Default Setting
this.setDistanceType(DistanceMethod.Euclidean);
this.setSpatialConceptType(SpatialConcept.InverseDistance);
this.setStandardizationType(StandardizationMethod.None);
}
public GeneralG execute(SimpleFeatureCollection inputFeatures, String inputField,
double distanceBand) {
this.setDistanceBand(distanceBand);
this.setSpatialConceptType(SpatialConcept.InverseDistance);
return execute(inputFeatures, inputField);
}
public GeneralG execute(SimpleFeatureCollection inputFeatures, String inputField) {
swMatrix = new WeightMatrixBuilder(getSpatialConceptType(), getStandardizationType());
swMatrix.setDistanceMethod(getDistanceType());
swMatrix.setDistanceBandWidth(getDistanceBand());
swMatrix.setSelfNeighbors(isSelfNeighbors());
swMatrix.buildWeightMatrix(inputFeatures, inputField);
double wijSum = 0.0; // sum of all weights (wij)
double tpSum = 0.0;
double npSum = 0.0;
double sumS1 = 0.0;
double s2 = 0.0;
double n = swMatrix.getEvents().size();
for (SpatialEvent source : swMatrix.getEvents()) {
double jwijSum = 0.0;
double jwjiSum = 0.0;
for (SpatialEvent target : swMatrix.getEvents()) {
if (!isSelfNeighbors() && source.id == target.id) {
continue;
}
tpSum += source.xVal * target.xVal;
double wij = swMatrix.getWeight(source, target);
double wji = wij;
wij = swMatrix.standardizeWeight(source, wij);
wji = swMatrix.standardizeWeight(target, wji);
if (wij == 0) {
continue;
}
npSum += wij * source.xVal * target.xVal;
wijSum += wij;
sumS1 += Math.pow(wij + wji, 2.0);
jwijSum += wij;
jwjiSum += wji;
}
s2 += Math.pow(jwijSum + jwjiSum, 2.0);
}
// calculate B and S working variables needed to calculate variance.
double s1 = 0.5 * sumS1;
double wijSum2 = Math.pow(wijSum, 2.0);
double b0 = ((Math.pow(n, 2.0) + (-3.0 * n) + 3.0) * s1) - (n * s2) + (3.0 * wijSum2);
double b1 = -1.0 * (((Math.pow(n, 2.0) - n) * s1) - (2.0 * n * s2) + (6.0 * wijSum2));
double b2 = -1.0 * ((2.0 * n * s1) - ((n + 3.0) * s2) + (6.0 * wijSum2));
double b3 = (4.0 * (n - 1.0) * s1) - (2.0 * (n + 1.0) * s2) + (8.0 * wijSum2);
double b4 = s1 - s2 + wijSum2;
// Calculate Observed G, Expected G and Z Score.
double dExpected = wijSum / (n * (n - 1.0));
double sumX = swMatrix.sumX;
double sumX2 = swMatrix.sumX2;
double sumX3 = swMatrix.sumX3;
double sumX4 = swMatrix.sumX4;
double zVariance = (((b0 * Math.pow(sumX2, 2.0)) + (b1 * sumX4)
+ (b2 * Math.pow(sumX, 2.0) * sumX2) + (b3 * sumX * sumX3) + (b4 * Math.pow(sumX,
4.0))) / (Math.pow((Math.pow(sumX, 2.0) - sumX2), 2.0) * (n * (n - 1.0) * (n - 2.0) * (n - 3.0))))
- Math.pow(dExpected, 2.0);
if (tpSum <= 0.0) {
GeneralG generalG = new GeneralG(0d, dExpected, zVariance);
generalG.setConceptualization(getSpatialConceptType());
generalG.setDistanceMethod(getDistanceType());
generalG.setRowStandardization(getStandardizationType());
generalG.setDistanceThreshold(swMatrix.getDistanceBandWidth());
return generalG;
}
double dObserved = npSum / tpSum;
// finally build result
GeneralG generalG = new GeneralG(dObserved, dExpected, zVariance);
generalG.setConceptualization(getSpatialConceptType());
generalG.setDistanceMethod(getDistanceType());
generalG.setRowStandardization(getStandardizationType());
generalG.setDistanceThreshold(swMatrix.getDistanceBandWidth());
return generalG;
}
public static final class GeneralG {
double observedGeneralG = 0.0;
double expectedGeneralG = 0.0;
double zVariance = 0.0;
SpatialConcept conceptualization = SpatialConcept.InverseDistance;
DistanceMethod distanceMethod = DistanceMethod.Euclidean;
StandardizationMethod rowStandardization = StandardizationMethod.None;
double distanceThreshold = 0.0;
public GeneralG() {
}
public GeneralG(double observedGeneralG, double expectedGeneralG, double zVariance) {
setObservedIndex(observedGeneralG);
setExpectedIndex(expectedGeneralG);
setZVariance(zVariance);
}
public void setObservedIndex(double observedGeneralG) {
this.observedGeneralG = observedGeneralG;
}
public double getObservedIndex() {
return observedGeneralG;
}
public void setExpectedIndex(double expectedGeneralG) {
this.expectedGeneralG = expectedGeneralG;
}
public double getExpectedIndex() {
return expectedGeneralG;
}
public void setZVariance(double zVariance) {
this.zVariance = zVariance;
}
public double getZVariance() {
return zVariance;
}
public double getZScore() {
double dX = observedGeneralG - expectedGeneralG;
double dY = Math.pow(getZVariance(), 0.5);
if (dY == 0) {
return 0.0;
}
return dX / dY;
}
public double getPValue() {
return SSUtils.zProb(this.getZScore(), StatEnum.BOTH);
}
public SpatialConcept getConceptualization() {
return conceptualization;
}
public void setConceptualization(SpatialConcept conceptualization) {
this.conceptualization = conceptualization;
}
public DistanceMethod getDistanceMethod() {
return distanceMethod;
}
public void setDistanceMethod(DistanceMethod distanceMethod) {
this.distanceMethod = distanceMethod;
}
public StandardizationMethod getRowStandardization() {
return rowStandardization;
}
public void setRowStandardization(StandardizationMethod rowStandardization) {
this.rowStandardization = rowStandardization;
}
public double getDistanceThreshold() {
return distanceThreshold;
}
public void setDistanceThreshold(double distanceThreshold) {
this.distanceThreshold = distanceThreshold;
}
}
}