package de.lmu.ifi.dbs.elki.math.linearalgebra; /* This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures Copyright (C) 2011 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 . */ import de.lmu.ifi.dbs.elki.data.NumberVector; import de.lmu.ifi.dbs.elki.database.ids.DBID; import de.lmu.ifi.dbs.elki.database.relation.Relation; import de.lmu.ifi.dbs.elki.utilities.DatabaseUtil; /** * Class to compute the centroid of some data. * * Note: this class abstracts the efficient and numerical stable computation of * centroids. * * See {@link de.lmu.ifi.dbs.elki.utilities.DatabaseUtil DatabaseUtil} for * easier to use APIs. * * @author Erich Schubert */ public class Centroid extends Vector { /** * Serial version */ private static final long serialVersionUID = 1L; /** * The current weight */ protected double wsum; /** * Constructor. * * @param dim Dimensionality */ public Centroid(int dim) { super(dim); this.wsum = 0; } /** * Add a single value with weight 1.0 * * @param val Value */ public void put(double[] val) { assert (val.length == elements.length); wsum += 1.0; for(int i = 0; i < elements.length; i++) { final double delta = val[i] - elements[i]; elements[i] += delta / wsum; } } /** * Add data with a given weight. * * @param val data * @param weight weight */ public void put(double val[], double weight) { assert (val.length == elements.length); final double nwsum = weight + wsum; for(int i = 0; i < elements.length; i++) { final double delta = val[i] - elements[i]; final double rval = delta * weight / nwsum; elements[i] += rval; } wsum = nwsum; } /** * Add a single value with weight 1.0 * * @param val Value */ public final void put(Vector val) { put(val.getArrayRef()); } /** * Add data with a given weight. * * @param val data * @param weight weight */ public final void put(Vector val, double weight) { put(val.getArrayRef(), weight); } /** * Add a single value with weight 1.0 * * @param val Value */ public void put(NumberVector val) { assert (val.getDimensionality() == elements.length); wsum += 1.0; for(int i = 0; i < elements.length; i++) { final double delta = val.doubleValue(i + 1) - elements[i]; elements[i] += delta / wsum; } } /** * Add data with a given weight. * * @param val data * @param weight weight */ public void put(NumberVector val, double weight) { assert (val.getDimensionality() == elements.length); final double nwsum = weight + wsum; for(int i = 0; i < elements.length; i++) { final double delta = val.doubleValue(i + 1) - elements[i]; final double rval = delta * weight / nwsum; elements[i] += rval; } wsum = nwsum; } /** * Get the data as vector * * @return the data */ public > F toVector(Relation relation) { return DatabaseUtil.assumeVectorField(relation).getFactory().newInstance(elements); } /** * Static Constructor from an existing matrix columns. * * @param mat Matrix to use the columns from. */ public static Centroid make(Matrix mat) { Centroid c = new Centroid(mat.getRowDimensionality()); int n = mat.getColumnDimensionality(); for(int i = 0; i < n; i++) { // TODO: avoid constructing the vector objects? c.put(mat.getColumnVector(i)); } return c; } /** * Static constructor from an existing relation. * * @param relation Relation to use * @return Centroid of relation */ public static Centroid make(Relation> relation) { Centroid c = new Centroid(DatabaseUtil.dimensionality(relation)); for(DBID id : relation.iterDBIDs()) { c.put(relation.get(id)); } return c; } /** * Static constructor from an existing relation. * * @param relation Relation to use * @param ids IDs to use */ public static Centroid make(Relation> relation, Iterable ids) { Centroid c = new Centroid(DatabaseUtil.dimensionality(relation)); for(DBID id : ids) { c.put(relation.get(id)); } return c; } }