/*******************************************************************************
* Copyright 2007, 2009 Stephen O'Rourke (stephen.orourke@sydney.edu.au)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package tml.vectorspace.factorisation;
import tml.utils.DistanceLib;
import tml.utils.DistanceLib.DistanceMeasure;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import Jama.EigenvalueDecomposition;
import Jama.Matrix;
/**
* Principal Coordinate Analysis
*
* @author Stephen O'Rourke
*/
public class PrincipalCoordinateAnalysis {
public static final int X = 0; // attribute Y
public static final int Y = 1; // attribute X
private static final int p = 2; // number of dimensions
private DistanceMeasure distanceMeasure = DistanceMeasure.EUCLIDEAN;
public Instances scale(Instances instances) {
// number of points
int n = instances.numInstances();
// distance matrix
Matrix d = new Matrix(n, n);
Matrix G = new Matrix(n, n);
// points instances
FastVector attributes = new FastVector(p);
attributes.addElement(new Attribute("X"));
attributes.addElement(new Attribute("Y"));
Instances x = new Instances("PCO", attributes, instances.numInstances());
// calculate distance matrix
for (int j = 0; j < n; j++) {
for (int i = 0; i < j; i++) {
double distance = this.distance(instances.instance(i), instances.instance(j));
d.set(i, j, distance);
d.set(j, i, distance);
}
}
// create centered matrix G by centering the elements of A
Matrix A = d.arrayTimes(d).times((double) -1 / 2);
Matrix B = Matrix.identity(n, n).minus(new Matrix(n, n, 1).times((double) 1 / n));
G = B.times(A).times(B);
// eigenvalue decomposition
EigenvalueDecomposition eig = G.eig();
Matrix eigenvalues = eig.getD();
Matrix eigenvectors = eig.getV();
// output eigenvectors as the principal coordinate axes, and normalise
// them by dividing by the square root of their corresponding eigenvalue.
for (int i = 0; i < n; i++) {
Instance instance = new Instance(p);
instance.setValue(X, eigenvectors.get(i, X) / Math.copySign(Math.sqrt(Math.abs(eigenvalues.get(X, X))), eigenvalues.get(X, X)));
instance.setValue(Y, eigenvectors.get(i, Y) / Math.copySign(Math.sqrt(Math.abs(eigenvalues.get(Y, Y))), eigenvalues.get(Y, Y)));
x.add(instance);
}
return x;
}
protected double distance(Instance inst1, Instance inst2) {
double distance = Math.sqrt(1 - DistanceLib.distance(distanceMeasure, inst1, inst2));
return distance;
}
public DistanceMeasure getDistanceMeasure() {
return distanceMeasure;
}
public void setDistanceMeasure(DistanceMeasure distanceMeasure) {
this.distanceMeasure = distanceMeasure;
}
}