/* * 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.operations; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.process.spatialstatistics.core.FeatureTypes; import org.geotools.process.spatialstatistics.operations.PearsonOperation.PearsonResult.PropertyName; import org.geotools.process.spatialstatistics.operations.PearsonOperation.PearsonResult.PropertyName.PearsonItem; import org.geotools.util.logging.Logging; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.expression.Expression; import org.opengis.parameter.InvalidParameterValueException; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamImplicit; /** * Calculates Pearson correlation coefficient * * @author Minpa Lee, MangoSystem * * @source $URL$ */ public class PearsonOperation extends GeneralOperation { protected static final Logger LOGGER = Logging.getLogger(PearsonOperation.class); public PearsonOperation() { } public PearsonResult execute(SimpleFeatureCollection inputFeatures, String inputFields) { PearsonResult result = new PearsonResult(); // inputFields = A, B, C, D, E List<String> fieldList = parseFields(inputFeatures.getSchema(), inputFields); if (fieldList.size() < 2) { throw new InvalidParameterValueException("Invalid parameters", "inputFields", inputFields); } // calculate double[][] values = new double[fieldList.size()][fieldList.size()]; for (int firstIndex = 0; firstIndex < fieldList.size(); firstIndex++) { String firstField = fieldList.get(firstIndex); for (int secondIndex = firstIndex + 1; secondIndex < fieldList.size(); secondIndex++) { String secondField = fieldList.get(secondIndex); double pearson = execute(inputFeatures, firstField, secondField); // firstIndex, secondIndex values[firstIndex][secondIndex] = pearson; values[secondIndex][firstIndex] = pearson; } } // result for (int firstIndex = 0; firstIndex < fieldList.size(); firstIndex++) { String firstField = fieldList.get(firstIndex); PropertyName property = new PropertyName(firstField); for (int secondIndex = 0; secondIndex < fieldList.size(); secondIndex++) { String secondField = fieldList.get(secondIndex); PearsonItem item = new PearsonItem(secondField); if (firstIndex != secondIndex) { double value = values[firstIndex][secondIndex]; item.setValue(new Double(value)); } property.getItems().add(item); } result.getProeprtyNames().add(property); } return result; } private double execute(SimpleFeatureCollection inputFeatures, String fieldName1, String fieldName2) { double sumX = 0.0; double sumY = 0.0; double sumXSq = 0.0; double sumYSq = 0.0; double pSum = 0.0; int rowCount = 0; Expression obsExpression = ff.property(fieldName1); Expression popExpression = ff.property(fieldName2); SimpleFeatureIterator featureIter = inputFeatures.features(); try { while (featureIter.hasNext()) { SimpleFeature feature = featureIter.next(); // evaluate and validate Double dxVal = obsExpression.evaluate(feature, Double.class); Double dyVal = popExpression.evaluate(feature, Double.class); if (dxVal == null || dyVal == null) { continue; } double dx = dxVal.doubleValue(); double dy = dyVal.doubleValue(); if (Double.isNaN(dx) || Double.isInfinite(dx) || Double.isNaN(dy) || Double.isInfinite(dy)) { continue; } sumX += dx; sumY += dy; sumXSq += Math.pow(dx, 2.0); sumYSq += Math.pow(dy, 2.0); pSum += dx * dy; rowCount++; } } finally { featureIter.close(); } if (rowCount == 0) { return 0; } double x = (sumXSq - Math.pow(sumX, 2) / rowCount); double y = (sumYSq - Math.pow(sumY, 2) / rowCount); double den = Math.pow(x * y, 0.5); if (den == 0) { return 0; } double num = pSum - ((sumX * sumY) / rowCount); return num / den; } private List<String> parseFields(SimpleFeatureType schema, String inputFields) { List<String> fieldList = new ArrayList<String>(); // comma separated fields String[] fields = inputFields.split(","); for (int k = 0; k < fields.length; k++) { String fieldName = FeatureTypes.validateProperty(schema, fields[k].trim()); if (schema.indexOf(fieldName) != -1 && !fieldList.contains(fieldName)) { fieldList.add(fieldName); } } return fieldList; } public static final class PearsonResult { @XStreamImplicit List<PropertyName> proeprtyNames = new ArrayList<PropertyName>(); public List<PropertyName> getProeprtyNames() { return proeprtyNames; } public void setProeprtyNames(List<PropertyName> proeprtyNames) { this.proeprtyNames = proeprtyNames; } @Override public String toString() { final String separator = System.getProperty("line.separator"); StringBuffer sb = new StringBuffer(); for (PropertyName proeprtyName : proeprtyNames) { sb.append(proeprtyName.toString()).append(separator); } return sb.toString(); } public static class PropertyName { @XStreamAsAttribute String name; @XStreamImplicit List<PearsonItem> items = new ArrayList<PearsonItem>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public List<PearsonItem> getItems() { return items; } public void setItems(List<PearsonItem> items) { this.items = items; } public PropertyName(String name) { this.name = name; } @Override public String toString() { final String separator = System.getProperty("line.separator"); StringBuffer sb = new StringBuffer(); sb.append("Name: ").append(name).append(separator); for (PearsonItem pearsonItem : items) { sb.append(" ").append(pearsonItem.toString()).append(separator); } return sb.toString(); } // version 1.4.2 @XStreamConverter(value=ToAttributedValueConverter.class, // strings={"value"}) public static class PearsonItem { @XStreamAsAttribute String name; Double value = Double.valueOf(1d); public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getValue() { return value; } public void setValue(Double value) { this.value = value; } public PearsonItem(String name) { this.name = name; } @Override public String toString() { final String separator = System.getProperty("line.separator"); StringBuffer sb = new StringBuffer(); sb.append(" Name: ").append(name).append(separator); sb.append(" Value: ").append(value).append(separator); return sb.toString(); } } } } }