net.maizegenetics.stats.linearmodels.FactorModelEffect Maven / Gradle / Ivy
package net.maizegenetics.stats.linearmodels;
import java.util.Arrays;
import net.maizegenetics.matrixalgebra.Matrix.DoubleMatrix;
import net.maizegenetics.matrixalgebra.Matrix.DoubleMatrixFactory;
public class FactorModelEffect implements ModelEffect {
private Object id;
private final int[] levels;
private final int[] levelCounts;
private final int size;
private final int numberOfLevels;
private boolean restricted = false;
public FactorModelEffect(int[] levels, boolean restricted) {
this.levels = levels;
size = levels.length;
this.restricted = restricted;
int maxLevel = 0;
for (int level : levels) {
maxLevel = Math.max(maxLevel, level);
}
numberOfLevels = maxLevel + 1;
int[] counts = new int[numberOfLevels];
for (int level : levels) {
counts[level]++;
}
levelCounts = counts;
}
public FactorModelEffect(int[] levels, boolean restricted, Object id) {
this(levels, restricted);
this.id = id;
}
private FactorModelEffect(Object id, int[] levels, int[] levelCounts, int size,
int numberOfLevels, boolean restricted) {
this.id = id;
this.levels = Arrays.copyOf(levels, levels.length);
this.levelCounts = Arrays.copyOf(levelCounts, levelCounts.length);
this.size = size;
this.numberOfLevels = numberOfLevels;
this.restricted = restricted;
}
@Override
public Object getID() {
return id;
}
@Override
public int getSize() {
return size;
}
@Override
public DoubleMatrix getX() {
if (restricted)
return getX_restricted();
return getX_unrestricted();
}
@Override
public DoubleMatrix getXtX() {
if (restricted)
return getXtX_restricted();
return getXtX_unrestricted();
}
@Override
public DoubleMatrix getXty(double[] y) {
if (restricted)
return getXty_restricted(y);
return getXty_unrestricted(y);
}
@Override
public void setID(Object id) {
this.id = id;
}
/**
* @param fme a FactorModelEffect
* @return the matrix product of this ModelEffect transposed and fme
*/
public DoubleMatrix getXtX2(FactorModelEffect fme) {
int n1 = numberOfLevels;
if (restricted)
n1--;
int n2 = fme.numberOfLevels;
if (fme.restricted)
n2--;
DoubleMatrix xtx2 = DoubleMatrixFactory.DEFAULT.make(n1, n2, 0);
for (int i = 0; i < size; i++) {
int row = levels[i];
int col = fme.levels[i];
if (row < n1 && col < n2)
xtx2.set(row, col, xtx2.get(row, col) + 1);
}
return xtx2;
}
@Override
public DoubleMatrix getyhat(DoubleMatrix beta) {
if (restricted)
return getyhat_restricted(beta);
return getyhat_unrestricted(beta);
}
@Override
public DoubleMatrix getyhat(double[] beta) {
if (restricted)
return getyhat_restricted(beta);
return getyhat_unrestricted(beta);
}
/**
* @return the level of each observation for this factor
*/
public int[] getLevels() {
return levels;
}
public boolean getRestricted() {
return restricted;
}
public void setRestricted(boolean restricted) {
this.restricted = restricted;
}
public int getNumberOfLevels() {
return numberOfLevels;
}
@Override
public int[] getLevelCounts() {
return levelCounts;
}
//private methods
private DoubleMatrix getX_unrestricted() {
DoubleMatrix X = DoubleMatrixFactory.DEFAULT.make(size, numberOfLevels, 0);
for (int i = 0; i < size; i++) {
X.set(i, levels[i], 1);
}
return X;
}
private DoubleMatrix getX_restricted() {
DoubleMatrix X = DoubleMatrixFactory.DEFAULT.make(size, numberOfLevels - 1, 0);
for (int i = 0; i < size; i++) {
if (levels[i] < numberOfLevels - 1)
X.set(i, levels[i], 1);
}
return X;
}
private DoubleMatrix getXtX_unrestricted() {
double[] counts = new double[numberOfLevels];
for (int i = 0; i < numberOfLevels; i++)
counts[i] = (int) levelCounts[i];
DoubleMatrix xtx = DoubleMatrixFactory.DEFAULT.diagonal(counts);
return xtx;
}
private DoubleMatrix getXtX_restricted() {
double[] counts = new double[numberOfLevels - 1];
for (int i = 0; i < numberOfLevels - 1; i++)
counts[i] = (int) levelCounts[i];
DoubleMatrix xtx = DoubleMatrixFactory.DEFAULT.diagonal(counts);
return xtx;
}
private DoubleMatrix getXty_unrestricted(double[] y) {
double[] sums = new double[numberOfLevels];
for (int i = 0; i < size; i++) {
sums[levels[i]] += y[i];
}
return DoubleMatrixFactory.DEFAULT.make(numberOfLevels, 1, sums);
}
private DoubleMatrix getXty_restricted(double[] y) {
double[] sums = new double[numberOfLevels - 1];
for (int i = 0; i < size; i++) {
if (levels[i] < numberOfLevels - 1)
sums[levels[i]] += y[i];
}
return DoubleMatrixFactory.DEFAULT.make(numberOfLevels - 1, 1, sums);
}
private DoubleMatrix getyhat_unrestricted(DoubleMatrix beta) {
if (beta.numberOfRows() != numberOfLevels)
throw new IllegalArgumentException("Number of factor levels is not the same as the size of beta.");
double[] yhat = new double[size];
for (int i = 0; i < size; i++)
yhat[i] = beta.get(levels[i], 0);
return DoubleMatrixFactory.DEFAULT.make(size, 1, yhat);
}
private DoubleMatrix getyhat_restricted(DoubleMatrix beta) {
if (beta.numberOfRows() != numberOfLevels - 1)
throw new IllegalArgumentException("Number of factor levels is not the same as the size of beta.");
double[] yhat = new double[size];
for (int i = 0; i < size; i++) {
if (levels[i] < numberOfLevels - 1)
yhat[i] = beta.get(levels[i], 0);
}
return DoubleMatrixFactory.DEFAULT.make(size, 1, yhat);
}
private DoubleMatrix getyhat_unrestricted(double[] beta) {
if (beta.length != numberOfLevels)
throw new IllegalArgumentException("Number of factor levels is not the same as the size of beta.");
double[] yhat = new double[size];
for (int i = 0; i < size; i++)
yhat[i] = beta[levels[i]];
return DoubleMatrixFactory.DEFAULT.make(size, 1, yhat);
}
private DoubleMatrix getyhat_restricted(double[] beta) {
if (beta.length != numberOfLevels - 1)
throw new IllegalArgumentException("Number of factor levels is not the same as the size of beta.");
double[] yhat = new double[size];
for (int i = 0; i < size; i++) {
if (levels[i] < numberOfLevels - 1)
yhat[i] = beta[levels[i]];
}
return DoubleMatrixFactory.DEFAULT.make(size, 1, yhat);
}
@Override
public ModelEffect getCopy() {
return new FactorModelEffect(id,
Arrays.copyOf(levels, levels.length),
Arrays.copyOf(levelCounts, levelCounts.length),
size,
numberOfLevels,
restricted);
}
@Override
public ModelEffect getSubSample(int[] sample) {
int numberOfSamples = sample.length;
int[] sampleLevels = new int[numberOfSamples];
for (int i = 0; i < numberOfSamples; i++) {
sampleLevels[i] = levels[sample[i]];
}
//adjust in case a level is not used
return new FactorModelEffect(ModelEffectUtils.getIntegerLevels(sampleLevels), restricted, id);
}
@Override
public int getEffectSize() {
if (restricted)
return numberOfLevels - 1;
else
return numberOfLevels;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy