All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.maizegenetics.stats.linearmodels.SweepFastLinearModel Maven / Gradle / Ivy

package net.maizegenetics.stats.linearmodels;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.maizegenetics.matrixalgebra.Matrix.DoubleMatrix;
import net.maizegenetics.matrixalgebra.Matrix.DoubleMatrixFactory;

public class SweepFastLinearModel {
	SweepFast sf;
	ArrayList modelEffects;
	int[] dimX;
	double[] y;
	ArrayList incrementalss;
	ArrayList incrementaldf;
	double totalSS;
	double modeldf;
	
	public SweepFastLinearModel(ArrayList effects, double[] data) {
		modelEffects = effects;
		y = data;
		init();
	}
	
	public SweepFastLinearModel(List effects, double[] data) {
	    if (effects instanceof ArrayList) modelEffects = (ArrayList) effects;
	    else modelEffects = new ArrayList<>(effects);
	    y = data;
	    init();
	}
	
	public SweepFastLinearModel(ArrayList effects, DoubleMatrix[][] xtx, DoubleMatrix[] xty, double[] data) {
		modelEffects = effects;
		y = data;
		init(xtx, xty);
	}
	
	private void init() {
    	int neffects = modelEffects.size();
    	DoubleMatrix[][] xtx = new DoubleMatrix[neffects][neffects];
    	DoubleMatrix[] xty = new DoubleMatrix[neffects];
    	
    	for (int i = 0; i < neffects; i++) {
    		xty[i] = modelEffects.get(i).getXty(y);
    		xtx[i][i] = modelEffects.get(i).getXtX();
    		for (int j = i + 1; j < neffects; j++) {
    			xtx[i][j] = ModelEffectUtils.getXtY(modelEffects.get(i), modelEffects.get(j));
    		}
    	}
    	
    	init(xtx, xty);
	}
	
	private void init(DoubleMatrix[][] xtx, DoubleMatrix[] xty) {
		incrementalss = new ArrayList();
		incrementaldf = new ArrayList();
		
    	int neffects = xtx.length;
    	dimX = new int[neffects];
    	for (int i = 0; i < neffects; i++) {
    		dimX[i] = xtx[i][i].numberOfColumns();
    	}
    	
    	double sum = 0;
    	double sumsq = 0;
    	for (double d:y) {
    		sum += d;
    		sumsq += d * d;
    	}
    	totalSS = sumsq;
    	sf = new SweepFast(xtx, xty, totalSS);
    	
    	modeldf = 0;
    	double thisdf = 0;
    	int count = 0;
    	for (int i = 0; i < dimX[0]; i++) {
    		if (sf.revg2sweep(count++)) {
    			thisdf++;
    			modeldf++;
    		}
    	}
    	
    	double previousErrorSS = sf.getResidualSS();
    	incrementalss.add(new Double(totalSS - previousErrorSS));
    	incrementaldf.add(new Double(thisdf));
    	sf.setDminFromA();
    	
    	for (int i = 1; i < neffects; i++) {
    		thisdf = 0;
    		for (int j = 0; j < dimX[i]; j++) {
    			if (sf.revg2sweep(count++)) {
    		    	thisdf++;
    				modeldf++;
    			}
    		}
    		double newErrorSS = sf.getResidualSS();
    		incrementalss.add(new Double(previousErrorSS - newErrorSS));
    		incrementaldf.add(new Double(thisdf));
    		previousErrorSS = newErrorSS;
    	}
	}

	public double[] getMarginalSSdf(int effect) {
		int start = 0;
		for (int i = 0; i < effect; i++) start += dimX[i];
		int end = start + dimX[effect];
		
		double df = 0;
		
		for (int i = start; i < end; i++) sf.revg2sweep(i);
		sf.sweepSingularColumns();
		
		double reducedModelSS = sf.getResidualSS();
		for (int i = start; i < end; i++) {
			if (sf.revg2sweep(i)) df++;
		}

		return new double[]{reducedModelSS - sf.getResidualSS(), df};
	}
	
	public double[] getIncrementalSSdf(int effect) {
		return new double[]{incrementalss.get(effect), incrementaldf.get(effect)};
	}
	
	public double[] getResidualSSdf() {
		double ss = sf.getResidualSS();
		double df = y.length - modeldf;
		return new double[]{ss, df};
	}
	
	public double[] getFullModelSSdf() {
		double ss = totalSS - sf.getResidualSS(); 
		double df = 0;
		for (Double effectdf:incrementaldf) df += effectdf;
		return new double[]{ss, df};
	}
	
	public double[] getModelcfmSSdf() {
		double ss = totalSS - incrementalss.get(0) - sf.getResidualSS(); 
		double df = 0;
		int n = incrementaldf.size();
		for (int i = 1; i < n; i++) df += incrementaldf.get(i);
		return new double[]{ss, df};
	}
	
	public double[] getBeta() {
		return sf.getBeta();
	}
	
	public double[] getBlues(int effect, boolean restricted) {
		//only valid for factor model effects
		if (modelEffects == null) return null;
		if (!(modelEffects.get(effect) instanceof FactorModelEffect)) return null;
		double[] blues;
		double mean = 0;
		int neffects = modelEffects.size();
		double[] beta = getBeta();
		
		int startIndex = 0;
		int startIndexForEffect = 0;
		for (int i = 0; i < neffects; i++) {
			double effectAverage = 0;
			if (i != effect && (modelEffects.get(effect) instanceof FactorModelEffect) ) {
				FactorModelEffect fme = (FactorModelEffect) modelEffects.get(effect);
				for (int j = 0; j < dimX[i]; j++) {
					effectAverage += beta[startIndex + j];
				}
				if (restricted && effect > 0) effectAverage /= dimX[i] + 1; //effect 0 is the mean and is always not restricted
				else effectAverage /= dimX[i];
			} else if (i == effect) {
				startIndexForEffect = startIndex;
			}
			startIndex += dimX[effect];
			mean += effectAverage;
		}
		
		if (restricted) {
			blues = new double[dimX[effect] + 1];
		} else {
			blues = new double[dimX[effect]];
		}
		
		for (int i = 0; i < dimX[effect]; i++) {
			blues[i] = mean + beta[startIndexForEffect + i];
		}
		
		if (restricted) blues[blues.length - 1] = mean;
		
		return blues;
	}
	
	public DoubleMatrix getInverseOfXtX() {
		DoubleMatrix A = sf.getA();
		int n = A.numberOfRows();
		int[] ndx = new int[n - 1];
		for (int i = 0; i < n - 1; i++) ndx[i] = i;
		return A.getSelection(ndx, ndx);
	}

	public DoubleMatrix getPredictedValues() {
	
		if (modelEffects == null) return null;
		int numberOfEffects = modelEffects.size();
		if (numberOfEffects == 0) return null;
		double[] beta = getBeta();
		int start = 0;
		ModelEffect me = modelEffects.get(0);
		int effectSize = me.getEffectSize();
		double[] thisbeta = Arrays.copyOfRange(beta, start, start + effectSize);
		DoubleMatrix p = me.getyhat(thisbeta);
		start += effectSize;
		for (int i = 1; i < numberOfEffects; i++) {
			me = modelEffects.get(i);
			effectSize = me.getEffectSize();
			thisbeta = Arrays.copyOfRange(beta, start, start + effectSize);
			p.plusEquals(me.getyhat(thisbeta));
			start += effectSize;
		}
		return p;
	}
	
	public DoubleMatrix getResiduals() {
		DoubleMatrix r = DoubleMatrixFactory.DEFAULT.make(y.length, 1, y);
		r.minusEquals(getPredictedValues());
		return r;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy