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

hex.gam.MetricBuilderGAM Maven / Gradle / Ivy

There is a newer version: 3.46.0.6
Show newest version
package hex.gam;

import hex.*;
import hex.glm.GLMModel;
import water.fvec.Frame;
import water.fvec.Vec;
import water.util.ArrayUtils;
import water.util.MathUtils;

import static hex.glm.GLMModel.GLMParameters.Family.*;

public class MetricBuilderGAM extends ModelMetricsSupervised.MetricBuilderSupervised {
  double _residual_deviance;
  double _null_deviance;
  long _nobs;
  double _log_likelihood;
  double _aic;
  private double _aic2;
  final GLMModel.GLMWeightsFun _glmf;
  ModelMetrics.MetricBuilder _metricBuilder;  // point to generic model metric classes
  final boolean _intercept;
  private final double[] _ymu;
  final boolean _computeMetrics;
  final private int _rank;
  int _nclass;

  public MetricBuilderGAM(String[] domain, double[] ymu, GLMModel.GLMWeightsFun glmf, int rank, boolean computeMetrics, boolean intercept, int nclass, MultinomialAucType aucType) {
    super(domain==null?0:domain.length, domain);
    _intercept = intercept;
    _computeMetrics = computeMetrics;
    _glmf = glmf;
    _rank = rank;
    _nclass = nclass;
    _ymu = ymu;
    switch (_glmf._family) {
      case binomial:
      case quasibinomial:
      case fractionalbinomial:
        _metricBuilder = new ModelMetricsBinomial.MetricBuilderBinomial(domain); break;
      case multinomial:
        _metricBuilder = new ModelMetricsMultinomial.MetricBuilderMultinomial(nclass, domain, aucType); break;
      case ordinal:
        _metricBuilder = new ModelMetricsOrdinal.MetricBuilderOrdinal(nclass, domain); break;
      default:
        _metricBuilder = new ModelMetricsRegression.MetricBuilderRegression(); // everything else goes back regression
    } 
  }
  
  @Override
  public double[] perRow(double[] ds, float[] yact, double weight, double offset, Model m) {
    if (weight == 0) return ds;
    _metricBuilder.perRow(ds, yact, weight, offset, m); // grab the generic terms
    if (_glmf._family.equals(GLMModel.GLMParameters.Family.negativebinomial))
      _log_likelihood += m.likelihood(weight, yact[0], ds[0]);
    if (!ArrayUtils.hasNaNsOrInfs(ds) && !ArrayUtils.hasNaNsOrInfs(yact)) {
      if (_glmf._family.equals(GLMModel.GLMParameters.Family.multinomial) || _glmf._family.equals(GLMModel.GLMParameters.Family.ordinal))
        add2(yact[0], ds[0], weight, offset);
      else if (_glmf._family.equals(binomial) || _glmf._family.equals(quasibinomial) ||
             _glmf._family.equals(fractionalbinomial))
        add2(yact[0], ds[2], weight, offset);
      else
        add2(yact[0], ds[0], weight, offset);
    }
    return ds;
  }
  
  private void add2(double yresp, double ypredict, double weight, double offset) {
    _wcount += weight;
    ++_nobs;
    if (!_glmf._family.equals(multinomial) && !_glmf._family.equals(ordinal)) {
      _residual_deviance += weight * _glmf.deviance(yresp, ypredict);
      if (offset == 0)
        _null_deviance += weight * _glmf.deviance(yresp, _ymu[0]);
      else
        _null_deviance += weight * _glmf.deviance(yresp, _glmf.linkInv(offset + _glmf.link(_ymu[0])));
    }
    if (_glmf._family.equals(poisson)) {  // AIC for poisson
      long y = Math.round(yresp);
      double logfactorial = MathUtils.logFactorial(y);
      _aic2 += weight*(yresp*Math.log(ypredict)-logfactorial-ypredict);
    }
  }
  
  public void reduce(MetricBuilderGAM other) {
    if (_computeMetrics)
      _metricBuilder.reduce(other._metricBuilder);
    _residual_deviance += other._residual_deviance;
    _null_deviance += other._null_deviance;
    if (_glmf._family.equals(negativebinomial))
      _log_likelihood += other._log_likelihood;
    _nobs += other._nobs;
    _aic2 += other._aic2;
    _wcount += other._wcount;
  }
  
  public final double residualDeviance() { return _residual_deviance;}
  public final long nullDOF() { return _nobs-(_intercept?1:0);}
  public final long resDOF() {
    if (_glmf._family.equals(ordinal))
      return _nobs-(_rank/(_nclasses-1)+_nclasses-2);
    else
      return _nobs-_rank;
  }

  protected void computeAIC(){
    _aic = 0;
    switch( _glmf._family) {
      case gaussian:
        _aic =  _nobs * (Math.log(_residual_deviance / _nobs * 2 * Math.PI) + 1) + 2;
        break;
      case quasibinomial:
      case fractionalbinomial:
      case binomial:
        _aic = _residual_deviance;
        break;
      case poisson:
        _aic = -2*_aic2;
        break; // AIC is set during the validation task
      case gamma:
        _aic = Double.NaN;
        break;
      case ordinal:
      case tweedie:
      case multinomial:
        _aic = Double.NaN;
        break;
      case negativebinomial:
        _aic = 2* _log_likelihood;
        break;
      default:
        assert false : "missing implementation for family " + _glmf._family;
    }
    _aic += 2*_rank;
  }
  
  @Override
  public double[] perRow(double[] ds, float[] yact, Model m) {
    return perRow(ds, yact, 1, 0, m);
  }
  
  @Override
  public ModelMetrics makeModelMetrics(Model m, Frame f, Frame adaptedFrame, Frame preds) {
    GAMModel gamM = (GAMModel) m;
    computeAIC();
    ModelMetrics mm=_metricBuilder.makeModelMetrics(gamM, f, null, null);
    if (_glmf._family.equals(GLMModel.GLMParameters.Family.binomial) || _glmf._family.equals(quasibinomial) ||
    _glmf._family.equals(fractionalbinomial)) {
      ModelMetricsBinomial metricsBinomial = (ModelMetricsBinomial) mm;
      GainsLift gl = null;
      if (preds != null) {
        Vec resp = f.vec(gamM._parms._response_column);
        Vec weights = f.vec(gamM._parms._weights_column);
        if (resp != null && fractionalbinomial != _glmf._family) {
          gl = new GainsLift(preds.lastVec(), resp, weights);
          gl.exec(gamM._output._job);
        }
      }
      mm = new ModelMetricsBinomialGLM(m, f, mm._nobs, mm._MSE, _domain, metricsBinomial._sigma, 
              metricsBinomial._auc, metricsBinomial._logloss, residualDeviance(), _null_deviance, _aic, nullDOF(), 
              resDOF(), gl, _customMetric);
    } else if (_glmf._family.equals(multinomial)) {
      ModelMetricsMultinomial metricsMultinomial = (ModelMetricsMultinomial) mm;
      mm = new ModelMetricsBinomialGLM.ModelMetricsMultinomialGLM(m, f, metricsMultinomial._nobs, 
              metricsMultinomial._MSE, metricsMultinomial._domain, metricsMultinomial._sigma, metricsMultinomial._cm, 
              metricsMultinomial._hit_ratios, metricsMultinomial._logloss, residualDeviance(),_null_deviance, _aic, 
              nullDOF(), resDOF(), metricsMultinomial._auc,  _customMetric);
    } else if (_glmf._family == GLMModel.GLMParameters.Family.ordinal) { // ordinal should have a different resDOF()
      ModelMetricsOrdinal metricsOrdinal = (ModelMetricsOrdinal) mm;
      mm = new ModelMetricsBinomialGLM.ModelMetricsOrdinalGLM(m, f, metricsOrdinal._nobs, metricsOrdinal._MSE, 
              metricsOrdinal._domain, metricsOrdinal._sigma, metricsOrdinal._cm, metricsOrdinal._hit_ratios, 
              metricsOrdinal._logloss, residualDeviance(), _null_deviance, _aic, nullDOF(), resDOF(), _customMetric);
    } else {
      ModelMetricsRegression metricsRegression = (ModelMetricsRegression) mm;
      mm = new ModelMetricsRegressionGLM(m, f, metricsRegression._nobs, metricsRegression._MSE, 
              metricsRegression._sigma, metricsRegression._mean_absolute_error, 
              metricsRegression._root_mean_squared_log_error, residualDeviance(), 
              residualDeviance() / _wcount, _null_deviance, _aic, nullDOF(), resDOF(), _customMetric);
    }
    return gamM.addModelMetrics(mm);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy