001/*
002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.tribuo.regression.impl;
018
019import org.tribuo.Example;
020import org.tribuo.ImmutableFeatureMap;
021import org.tribuo.ImmutableOutputInfo;
022import org.tribuo.Model;
023import org.tribuo.Prediction;
024import org.tribuo.math.la.SparseVector;
025import org.tribuo.provenance.ModelProvenance;
026import org.tribuo.regression.Regressor;
027
028import java.util.Arrays;
029
030/**
031 * A {@link Model} which wraps n independent regression models, where n is the
032 * size of the MultipleRegressor domain. Each model independently predicts
033 * a single regression dimension.
034 */
035public abstract class SkeletalIndependentRegressionModel extends Model<Regressor> {
036    private static final long serialVersionUID = 1L;
037
038    protected final String[] dimensions;
039
040    /**
041     * models.size() must equal labelInfo.getDomain().size()
042     * @param name Model name.
043     * @param dimensions Dimension names.
044     * @param modelProvenance The model provenance.
045     * @param featureMap The feature domain used in training.
046     * @param outputInfo The output domain used in training.
047     */
048    protected SkeletalIndependentRegressionModel(String name, String[] dimensions, ModelProvenance modelProvenance, ImmutableFeatureMap featureMap, ImmutableOutputInfo<Regressor> outputInfo) {
049        super(name,modelProvenance,featureMap,outputInfo,false);
050        this.dimensions = Arrays.copyOf(dimensions,dimensions.length);
051    }
052
053    @Override
054    public Prediction<Regressor> predict(Example<Regressor> example) {
055        SparseVector features = createFeatures(example);
056
057        Regressor.DimensionTuple[] outputs = new Regressor.DimensionTuple[dimensions.length];
058
059        for (int i = 0; i < dimensions.length; i++) {
060            outputs[i] = scoreDimension(i,features);
061        }
062
063        return new Prediction<>(new Regressor(outputs),features.numActiveElements(),example);
064    }
065
066    /**
067     * Creates the feature vector. Does not include a bias term.
068     * <p>
069     * Designed to be overridden.
070     * @param example The example to convert.
071     * @return The feature vector.
072     */
073    protected SparseVector createFeatures(Example<Regressor> example) {
074        return SparseVector.createSparseVector(example,featureIDMap,false);
075    }
076
077    /**
078     * Makes a prediction for a single dimension.
079     * @param dimensionIdx The dimension index to predict.
080     * @param features The features to use.
081     * @return A single dimension prediction.
082     */
083    protected abstract Regressor.DimensionTuple scoreDimension(int dimensionIdx, SparseVector features);
084}