Cov.java

/*
 * $Id: Cov.java,v 1.18 2008/07/16 15:40:00 koga Exp $
 * 
 * Copyright (C) 2004 Koga Laboratory. All rights reserved.
 */
package org.mklab.tool.matrix;

import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.scalar.DoubleNumber;


/**
 * 分散を求めるクラスです。
 * 
 * <p>Covariance
 * 
 * @author koga
 * @version $Revision: 1.18 $
 * @see org.mklab.tool.matrix.Corrcoef
 */
public class Cov {

  /**
   * ベクトル <code>x</code> の成分の分散を求めます。
   * 
   * @param x データ
   * @return 自己分散 (Covariance)
   */
  public static DoubleNumber cov(DoubleMatrix x) {
    return covColumnWise(x.reshape(1, x.getRowSize() * x.getColumnSize())).getElement(1, 1);
  }

  /**
   * cov([x y])を返します。
   * 
   * @param x データ1
   * @param y データ2
   * @return 共分散 (Covariance)
   */
  public static DoubleNumber cov(DoubleMatrix x, DoubleMatrix y) {
    DoubleMatrix z = Makecolv.makecolv(x).appendRight(Makecolv.makecolv(y));
    return covColumnWise(z.reshape(1, z.getRowSize() * z.getColumnSize())).getElement(1, 1);
  }

  /**
   * もし<code>x</code> が行毎データが並ぶ行列なら、分散行列を返します。
   * 
   * <p><code>diag_vec(cov_col(x))</code> は、各列の分散が並ぶベクトルであり、 <code>sqrt(diag_vec(cov_col(x)))</code> は、標準偏差です。
   * 
   * @param x データ
   * @return 自己分散 (Covariance)
   */
  public static DoubleMatrix covColumnWise(DoubleMatrix x) {
    int rowSize = x.getRowSize();
    int columnSize = x.getColumnSize();

    DoubleMatrix X;
    if (Math.min(rowSize, columnSize) == 1) {
      X = Makecolv.makecolv(x);
    } else {
      X = x;
    }

    rowSize = X.getRowSize();
    X = X.subtract(x.createOnes(rowSize, 1).multiply(X.sumColumnWise().divide(rowSize)));

    DoubleMatrix cv;
    if (rowSize == 1) {
      cv = x.createZero(1, 1);
    } else {
      cv = X.conjugateTranspose().multiply(X).divide(rowSize - 1);
    }
    return cv;
  }

  /**
   * @param x データ1
   * @param y データ2
   * @return 共分散 (Covariance)
   */
  public static DoubleMatrix covColumnWise(DoubleMatrix x, DoubleMatrix y) {
    int rowSize = x.getRowSize();
    int columnSize = x.getColumnSize();

    if (rowSize != y.getRowSize() || columnSize != y.getColumnSize()) {
      throw new IllegalArgumentException(Messages.getString("Cov.0")); //$NON-NLS-1$
    }

    if (rowSize != 1 && columnSize != 1) {
      throw new IllegalArgumentException(Messages.getString("Cov.1")); //$NON-NLS-1$
    }

    DoubleMatrix X = Makecolv.makecolv(x).appendRight(Makecolv.makecolv(y));

    rowSize = X.getRowSize();
    X = X.subtract(x.createOnes(rowSize, 1).multiply(X.sumColumnWise().divide(rowSize)));

    if (rowSize == 1) {
      return x.createZero(1, 1);
    }

    return X.conjugateTranspose().multiply(X).divide(rowSize - 1);
  }

  /**
   * もし <code>x</code> が、列毎にデータ並ぶ行列なら、分散行列を返します。
   * 
   * <p><code>diag_vec(cov_row(x))</code> は、各行の分散が並ぶベクトルであり、 <code>sqrt(diag_vec(cov_row(x)))</code> は、標準偏差です。
   * 
   * @param x データ
   * @return 自己分散 (Covariance)
   */
  public static DoubleMatrix covRowWise(DoubleMatrix x) {
    return covColumnWise(x.transpose()).transpose();
  }

  /**
   * @param x データ1
   * @param y データ2
   * @return 共分散 (Covariance)
   */
  public static DoubleMatrix covRowWise(DoubleMatrix x, DoubleMatrix y) {
    return covColumnWise(x, y).transpose();
  }

}