1 /* 2 * This file is part of ELKI: 3 * Environment for Developing KDD-Applications Supported by Index-Structures 4 * 5 * Copyright (C) 2018 6 * ELKI Development Team 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 package de.lmu.ifi.dbs.elki.utilities.scaling.outlier; 22 23 import de.lmu.ifi.dbs.elki.database.ids.DBIDIter; 24 import de.lmu.ifi.dbs.elki.database.relation.DoubleRelation; 25 import de.lmu.ifi.dbs.elki.math.DoubleMinMax; 26 import de.lmu.ifi.dbs.elki.result.outlier.OutlierResult; 27 import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.NumberArrayAdapter; 28 import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; 29 import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; 30 import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; 31 import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; 32 import net.jafama.FastMath; 33 34 /** 35 * Scaling that can map arbitrary positive values to a value in the range of 36 * [0:1]. 37 * <p> 38 * Transformation is done by taking the square root, then doing a linear linear 39 * mapping onto 0:1 using the minimum values seen. 40 * 41 * @author Erich Schubert 42 * @since 0.3 43 */ 44 public class OutlierSqrtScaling implements OutlierScaling { 45 /** 46 * Minimum and maximum values. 47 */ 48 protected double min, max; 49 50 /** 51 * Predefined minimum and maximum values. 52 */ 53 protected Double pmin = null, pmax = null; 54 55 /** 56 * Scaling factor 57 */ 58 protected double factor; 59 60 /** 61 * Constructor. 62 * 63 * @param pmin Predefined minimum 64 * @param pmax Predefined maximum 65 */ OutlierSqrtScaling(Double pmin, Double pmax)66 public OutlierSqrtScaling(Double pmin, Double pmax) { 67 super(); 68 this.pmin = pmin; 69 this.pmax = pmax; 70 } 71 72 @Override getScaled(double value)73 public double getScaled(double value) { 74 assert (factor != 0) : "prepare() was not run prior to using the scaling function."; 75 return value <= min ? 0. : Math.min(1, (FastMath.sqrt(value - min) / factor)); 76 } 77 78 @Override prepare(OutlierResult or)79 public void prepare(OutlierResult or) { 80 if(pmin == null || pmax == null) { 81 DoubleMinMax mm = new DoubleMinMax(); 82 DoubleRelation scores = or.getScores(); 83 for(DBIDIter id = scores.iterDBIDs(); id.valid(); id.advance()) { 84 double val = scores.doubleValue(id); 85 if(!Double.isInfinite(val)) { 86 mm.put(val); 87 } 88 } 89 min = (pmin == null) ? mm.getMin() : pmin; 90 max = (pmax == null) ? mm.getMax() : pmax; 91 } 92 factor = FastMath.sqrt(max - min); 93 } 94 95 @Override prepare(A array, NumberArrayAdapter<?, A> adapter)96 public <A> void prepare(A array, NumberArrayAdapter<?, A> adapter) { 97 if(pmin == null || pmax == null) { 98 DoubleMinMax mm = new DoubleMinMax(); 99 final int size = adapter.size(array); 100 for(int i = 0; i < size; i++) { 101 double val = adapter.getDouble(array, i); 102 if(!Double.isInfinite(val)) { 103 mm.put(val); 104 } 105 } 106 min = (pmin == null) ? mm.getMin() : pmin; 107 max = (pmax == null) ? mm.getMax() : pmax; 108 } 109 factor = FastMath.sqrt(max - min); 110 } 111 112 @Override getMin()113 public double getMin() { 114 return 0.0; 115 } 116 117 @Override getMax()118 public double getMax() { 119 return 1.0; 120 } 121 122 /** 123 * Parameterization class. 124 * 125 * @author Erich Schubert 126 */ 127 public static class Parameterizer extends AbstractParameterizer { 128 /** 129 * Parameter to specify the fixed minimum to use. 130 */ 131 public static final OptionID MIN_ID = new OptionID("sqrtscale.min", "Fixed minimum to use in sqrt scaling."); 132 133 /** 134 * Parameter to specify the fixed maximum to use. 135 */ 136 public static final OptionID MAX_ID = new OptionID("sqrtscale.max", "Fixed maximum to use in sqrt scaling."); 137 138 /** 139 * Predefined minimum value. 140 */ 141 protected double min; 142 143 /** 144 * Predefined maximum value. 145 */ 146 protected double max; 147 148 @Override makeOptions(Parameterization config)149 protected void makeOptions(Parameterization config) { 150 super.makeOptions(config); 151 DoubleParameter minP = new DoubleParameter(MIN_ID) // 152 .setOptional(true); 153 if(config.grab(minP)) { 154 min = minP.getValue(); 155 } 156 DoubleParameter maxP = new DoubleParameter(MAX_ID) // 157 .setOptional(true); 158 if(config.grab(maxP)) { 159 max = maxP.getValue(); 160 } 161 } 162 163 @Override makeInstance()164 protected OutlierSqrtScaling makeInstance() { 165 return new OutlierSqrtScaling(min, max); 166 } 167 } 168 } 169