package de.lmu.ifi.dbs.elki.math.linearalgebra.pca;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see
* Key: {@code -pca.weight} *
*/ public static final OptionID WEIGHT_ID = new OptionID("pca.weight", "Weight function to use in weighted PCA."); /** * Holds the weight function. */ protected WeightFunction weightfunction; /** * Holds the distance function used for weight calculation. */ private PrimitiveDistanceFunction super NumberVector> weightDistance = EuclideanDistanceFunction.STATIC; /** * Constructor. * * @param weightfunction Weighting function */ public WeightedCovarianceMatrixBuilder(WeightFunction weightfunction) { super(); this.weightfunction = weightfunction; } /** * Weighted Covariance Matrix for a set of IDs. Since we are not supplied any * distance information, we'll need to compute it ourselves. Covariance is * tied to Euclidean distance, so it probably does not make much sense to add * support for other distance functions? * * @param ids Database ids to process * @param relation Relation to process * @return Covariance matrix */ @Override public Matrix processIds(DBIDs ids, Relation extends NumberVector> relation) { final int dim = RelationUtil.dimensionality(relation); final CovarianceMatrix cmat = new CovarianceMatrix(dim); final Vector centroid = Centroid.make(relation, ids); // find maximum distance double maxdist = 0.0; double stddev = 0.0; { for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { NumberVector obj = relation.get(iter); double distance = weightDistance.distance(centroid, obj); stddev += distance * distance; if(distance > maxdist) { maxdist = distance; } } if(maxdist == 0.0) { maxdist = 1.0; } // compute standard deviation. stddev = Math.sqrt(stddev / ids.size()); } for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { NumberVector obj = relation.get(iter); double distance = weightDistance.distance(centroid, obj); double weight = weightfunction.getWeight(distance, maxdist, stddev); cmat.put(obj, weight); } return cmat.destroyToNaiveMatrix(); } /** * Compute Covariance Matrix for a QueryResult Collection. * * By default it will just collect the ids and run processIds * * @param results a collection of QueryResults * @param database the database used * @param k number of elements to process * @return Covariance Matrix */ @Override public Matrix processQueryResults(DoubleDBIDList results, Relation extends NumberVector> database, int k) { final int dim = RelationUtil.dimensionality(database); final CovarianceMatrix cmat = new CovarianceMatrix(dim); // avoid bad parameters if(k > results.size()) { k = results.size(); } // find maximum distance double maxdist = 0.0; double stddev = 0.0; { int i = 0; for(DoubleDBIDListIter it = results.iter(); it.valid() && i < k; it.advance(), k++) { final double dist = it.doubleValue(); stddev += dist * dist; if(dist > maxdist) { maxdist = dist; } } if(maxdist == 0.0) { maxdist = 1.0; } stddev = Math.sqrt(stddev / k); } // calculate weighted PCA int i = 0; for(DoubleDBIDListIter it = results.iter(); it.valid() && i < k; it.advance(), k++) { final double dist = it.doubleValue(); NumberVector obj = database.get(it); double weight = weightfunction.getWeight(dist, maxdist, stddev); cmat.put(obj, weight); } return cmat.destroyToNaiveMatrix(); } /** * Parameterization class. * * @author Erich Schubert * * @apiviz.exclude */ public static class Parameterizer extends AbstractParameterizer { /** * Weight function. */ protected WeightFunction weightfunction = null; @Override protected void makeOptions(Parameterization config) { super.makeOptions(config); ObjectParameter