├── .DS_Store ├── .gitignore ├── README.md ├── pom.xml ├── spark-ctr-models.iml └── src └── main ├── java └── org │ └── jeemy │ ├── feature │ ├── FeatureConf.java │ ├── FeatureMaker.java │ └── SparseVector.java │ ├── models │ ├── GBDTLRModel.java │ ├── LRParser.java │ └── XGBoostParser.java │ └── tree │ ├── DecisionTree.java │ ├── NodeType.java │ ├── TreeNode.java │ └── TreePath.java ├── resources ├── featureConf └── model.conf └── scala └── org └── jeemy ├── Test.scala ├── feature └── FeatureDiscretizer.scala ├── models ├── BaseModel.scala ├── FM.scala ├── LR.scala ├── XGBoost.scala ├── XGBoostFM.scala └── XGBoostLR.scala └── utils └── SchemaParser.scala /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeemyJohn/spark-ctr-models/323a1321683fa4cc74270685f6e9647d31f97ad6/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | target/ 3 | *.jar 4 | *.war 5 | *.iml 6 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spark-ctr-models 2 | CTR prediction models based on spark. Easy to use and we realized most common models for CTR prediction. The most difference is that we not only implement model trains,but also make it easy to parse the trained models and deploy them to the Online Server with Java interface. 3 | 4 | The main algorithms we realized: 5 | 6 | - [x] LR 7 | 8 | - [x] FM 9 | 10 | - [x] XGBoost 11 | 12 | - [x] XGBoostLR 13 | 14 | - [x] XGBoostFM 15 | 16 | # 1. java 17 | Java interfaces mainly used for parse and deploy the models trained by spark platform to the Online Server. 18 | 19 | # 2. scala 20 | Scala module trained models and save them as a specific format which java interface can parse them for predict in Online Server. 21 | 22 | # 3. Feature Engineering. 23 | - [x] FeatureConf: 24 | - [x] FeatureMaker: 25 | - [x] SparseVector: 26 | 27 | # 4. Example code. 28 | Throughout the project, we will write a main function for every class to show the example code of the detail usage of them. This make you clear and easy to test the functions of the class. -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.apache.jeemy 8 | spark-ctr-models 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 1.8 14 | 2.11.12 15 | 2.4.3 16 | 2.7.4 17 | 0.82 18 | 1.2.1 19 | 20 | 21 | 22 | 23 | 24 | org.apache.spark 25 | spark-core_2.11 26 | ${spark.version} 27 | 28 | 29 | 30 | org.apache.spark 31 | spark-sql_2.11 32 | ${spark.version} 33 | 34 | 35 | org.apache.spark 36 | spark-hive_2.11 37 | ${spark.version} 38 | 39 | 40 | org.apache.spark 41 | spark-mllib_2.11 42 | ${spark.version} 43 | 44 | 45 | 46 | ml.dmlc 47 | xgboost4j-spark 48 | ${xgboost.version} 49 | 50 | 51 | 52 | 53 | org.scala-lang 54 | scala-library 55 | ${scala.version} 56 | 57 | 58 | org.scala-lang 59 | scala-compiler 60 | ${scala.version} 61 | 62 | 63 | org.scala-lang 64 | scala-reflect 65 | ${scala.version} 66 | 67 | 68 | 69 | 70 | com.typesafe 71 | config 72 | ${config.version} 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-compiler-plugin 82 | 3.7.0 83 | 84 | ${java.version} 85 | ${java.version} 86 | 87 | 88 | 89 | 90 | 91 | maven-assembly-plugin 92 | 93 | 94 | jar-with-dependencies 95 | 96 | 97 | 98 | Test 99 | 100 | 101 | 102 | 103 | 104 | make-assembly 105 | package 106 | 107 | single 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | net.alchim31.maven 116 | scala-maven-plugin 117 | 3.2.2 118 | 119 | ${scala.version} 120 | 121 | 122 | 123 | 124 | compile 125 | testCompile 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /spark-ctr-models.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/feature/FeatureConf.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.feature; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * @User: zhanghuayan 10 | * @Date: 2020/4/20 2:14 下午 11 | * @Desc: 单个特征区间信息封装类 12 | */ 13 | public class FeatureConf { 14 | // 特征名 15 | public String name; 16 | 17 | // 特征类型(discrete、continuous) 18 | public String type; 19 | 20 | // 特征离散化区间信息 21 | public List listInfo; 22 | 23 | // OneHot后特征向量维度空间 24 | public int dimSize; 25 | 26 | // 连续特征分桶区间数组 27 | public List splitBins = null; 28 | 29 | // 离散特征字典映射Map 30 | public Map featMap = null; 31 | 32 | /** 33 | * 特征类型静态标记 34 | */ 35 | public static String DISCRETE = "discrete"; 36 | public static String CONTINUOUS = "continuous"; 37 | 38 | /** 39 | * 构造函数 40 | */ 41 | public FeatureConf(String name, String type, List listInfo) { 42 | this.name = name; 43 | this.type = type; 44 | this.listInfo = listInfo; 45 | 46 | // 根据特征类型,判断编码空间大小,并进行不同的处理 47 | if (type.equals(DISCRETE)) { 48 | dimSize = listInfo.size(); 49 | featMap = new HashMap<>(); 50 | for (int i = 0; i < listInfo.size(); i++) { 51 | String[] splits = listInfo.get(i).split(":"); 52 | featMap.put(Double.parseDouble(splits[0]), Double.parseDouble(splits[1])); 53 | } 54 | } else { 55 | dimSize = listInfo.size() - 1; 56 | splitBins = new ArrayList<>(); 57 | for (int i = 0; i < listInfo.size(); i++) { 58 | Double val = Double.parseDouble(listInfo.get(i)); 59 | splitBins.add(val); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/feature/FeatureMaker.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.feature; 2 | 3 | import com.typesafe.config.Config; 4 | import com.typesafe.config.ConfigFactory; 5 | import com.typesafe.config.ConfigObject; 6 | 7 | import java.io.File; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * @User: zhanghuayan 13 | * @Date: 2020/4/18 4:30 下午 14 | */ 15 | public class FeatureMaker { 16 | // 特征离散化信息列表 17 | private List featureConfList = new ArrayList<>(); 18 | 19 | /** 20 | * 构造函数:特征离散化信息列表初始化 21 | */ 22 | public FeatureMaker(Config conf) { 23 | // 获取特征对象数组 24 | List objs = conf.getObjectList("feature"); 25 | // 依次解析各个特征 26 | for (ConfigObject obj : objs) { 27 | Config config = obj.toConfig(); 28 | String name = config.getString("name"); 29 | String type = config.getString("type"); 30 | List values = config.getStringList("values"); 31 | featureConfList.add(new FeatureConf(name, type, values)); 32 | } 33 | } 34 | 35 | /** 36 | * 构造函数:特征离散化信息列表初始化 37 | */ 38 | public FeatureMaker(String confFile) { 39 | // 加载配置文件 40 | Config conf = ConfigFactory.parseFile(new File(confFile)); 41 | // 获取特征对象数组 42 | List objs = conf.getObjectList("feature"); 43 | // 依次解析各个特征 44 | for (ConfigObject obj : objs) { 45 | Config config = obj.toConfig(); 46 | String name = config.getString("name"); 47 | String type = config.getString("type"); 48 | List values = config.getStringList("values"); 49 | featureConfList.add(new FeatureConf(name, type, values)); 50 | } 51 | } 52 | 53 | /** 54 | * 原始特征离散化获取稀疏特征,LR前半部分使用 55 | */ 56 | public SparseVector trans2SparseVector(double[] denseFeature) { 57 | int size = 0; 58 | int[] indices = new int[featureConfList.size()]; 59 | double[] values = new double[featureConfList.size()]; 60 | 61 | // 根据特征类型解析每个特征内部索引 62 | int startIndex = 0; 63 | for (int i = 0; i < denseFeature.length; i++) { 64 | FeatureConf featureConf = featureConfList.get(i); 65 | size += featureConf.dimSize; 66 | indices[i] = startIndex + getInnerIndex(denseFeature[i], featureConf); 67 | values[i] = 1.0; 68 | startIndex = size; 69 | } 70 | 71 | return new SparseVector(size, indices, values); 72 | } 73 | 74 | /** 75 | * 获取特征OneHot编码值:离散值是字典匹配,连续值是区间匹配的方式 76 | */ 77 | private int getInnerIndex(double value, FeatureConf featureConf) { 78 | if (featureConf.type.equals(FeatureConf.DISCRETE)) { 79 | return featureConf.featMap.get(value).intValue(); 80 | } else if (featureConf.type.equals(FeatureConf.CONTINUOUS)) { 81 | for (int i = 0; i < featureConf.splitBins.size() - 1; i++) { 82 | double lValue = featureConf.splitBins.get(i); 83 | double rValue = featureConf.splitBins.get(i + 1); 84 | // 分桶区间前闭后开 85 | if (value >= lValue && value < rValue) { 86 | return i; 87 | } 88 | } 89 | } 90 | // 没匹配到,返回默认值 91 | return 0; 92 | } 93 | 94 | /** 95 | * 类功能测试 96 | */ 97 | public static void main(String[] args) { 98 | FeatureMaker featureMaker = new FeatureMaker("/Users/jeemy/IdeaProjects/spark-ctr-models/src/main/resources/model.conf"); 99 | 100 | double[] feature = {2.0, 34.0}; 101 | SparseVector vector = featureMaker.trans2SparseVector(feature); 102 | System.out.println(vector.toString()); 103 | 104 | feature = new double[]{-2.0, 7.0}; 105 | vector = featureMaker.trans2SparseVector(feature); 106 | System.out.println(vector.toString()); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/feature/SparseVector.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.feature; 2 | 3 | /** 4 | * @User: zhanghuayan 5 | * @Date: 2020/4/18 6:52 下午 6 | */ 7 | public class SparseVector { 8 | /** 9 | * 稀疏编码总维度 10 | */ 11 | public int size; 12 | 13 | /** 14 | * 非零特征对应的索引值 15 | */ 16 | public int[] indices; 17 | 18 | /** 19 | * 非零特征对应的值 20 | */ 21 | public double[] values; 22 | 23 | /** 24 | * 默认构造函数 25 | * 26 | * @param size 稀疏向量总空间树 27 | * @param indices 非零特征对应的索引值 28 | * @param values 非零特征的取值 29 | */ 30 | public SparseVector(int size, int[] indices, double[] values) { 31 | // 参数合法性验证 32 | try { 33 | for (int i = 0; i < indices.length - 1; i++) { 34 | if (indices[i] < 0 || indices[i + 1] < 0 || indices[i] >= indices[i + 1]) { 35 | System.out.println("index" + i + ":" + indices[i] + ",index" + (i + 1) + ":" + indices[i + 1]); 36 | throw new Exception("Invalid parameter indices: all number should be non-negative integer from 0, and in ascending order!"); 37 | } 38 | } 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | this.size = size; 43 | this.indices = indices; 44 | this.values = values; 45 | } 46 | 47 | /** 48 | * 将两个稀疏向量合并成一个稀疏向量,并返回 49 | * 50 | * @param vector1 第一个稀疏向量 51 | * @param vector2 第二个稀疏向量 52 | * @return 合并后的稀疏向量 53 | */ 54 | public static SparseVector merge(SparseVector vector1, SparseVector vector2) { 55 | int size = vector1.size + vector2.size; 56 | int nonZeroNum = vector1.indices.length + vector2.indices.length; 57 | int[] indices = new int[nonZeroNum]; 58 | double[] values = new double[nonZeroNum]; 59 | 60 | // 合并vecotr1 61 | for (int i = 0; i < vector1.indices.length; i++) { 62 | indices[i] = vector1.indices[i]; 63 | values[i] = vector1.values[i]; 64 | } 65 | 66 | // 合并vecotr2 67 | int startIndex = vector1.size; 68 | for (int i = 0; i < vector2.indices.length; i++) { 69 | indices[vector1.indices.length + i] = startIndex + vector2.indices[i]; 70 | values[vector1.indices.length + i] = vector2.values[i]; 71 | } 72 | 73 | return new SparseVector(size, indices, values); 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | StringBuffer ans = new StringBuffer(); 79 | 80 | ans.append("[" + size + ",("); 81 | for (int i = 0; i < indices.length - 1; i++) { 82 | ans.append(indices[i] + ","); 83 | } 84 | 85 | ans.append(indices[indices.length - 1] + "),("); 86 | for (int i = 0; i < values.length - 1; i++) { 87 | ans.append(values[i] + ","); 88 | } 89 | ans.append(values[values.length - 1] + ")]"); 90 | 91 | return ans.toString(); 92 | 93 | } 94 | 95 | public static void main(String[] args) { 96 | // 逻辑验证 97 | SparseVector vector1 = new SparseVector(50, new int[]{1, 30, 45}, new double[]{1, 2, 3}); 98 | SparseVector vector2 = new SparseVector(50, new int[]{0, 20, 49}, new double[]{4, 5, 6}); 99 | System.out.println("vector1: " + vector1.toString()); 100 | System.out.println("vector2: " + vector2.toString()); 101 | System.out.println("vector3: " + merge(vector1, vector2).toString()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/models/GBDTLRModel.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.models; 2 | 3 | import com.typesafe.config.Config; 4 | import com.typesafe.config.ConfigFactory; 5 | import org.jeemy.feature.FeatureConf; 6 | import org.jeemy.feature.FeatureMaker; 7 | import org.jeemy.feature.SparseVector; 8 | 9 | import java.io.File; 10 | import java.util.List; 11 | 12 | /** 13 | * @User: zhanghuayan 14 | * @Date: 2020/4/20 11:28 上午 15 | */ 16 | public class GBDTLRModel { 17 | /** 18 | * LR模型解析类 19 | */ 20 | private LRParser lrParser; 21 | 22 | /** 23 | * XGBoost模型解析类 24 | */ 25 | private XGBoostParser xgbParser; 26 | 27 | /** 28 | * 特征离散化功能类 29 | */ 30 | private FeatureMaker featureMaker; 31 | 32 | /** 33 | * 构造函数 34 | * 35 | * @param modelConf 模型配置文件 36 | */ 37 | public GBDTLRModel(String modelConf) { 38 | // 加载配置文件 39 | Config conf = ConfigFactory.parseFile(new File(modelConf)); 40 | 41 | // 解析LR模型 42 | List lrWeights = conf.getDoubleList("lr_model_weights"); 43 | lrParser = new LRParser(lrWeights); 44 | 45 | // 解析XGBoost模型 46 | String xgbModelPath = conf.getString("xgb_model_path"); 47 | xgbParser = new XGBoostParser(xgbModelPath); 48 | 49 | // 解析特征离散化功能类 50 | featureMaker = new FeatureMaker(conf); 51 | } 52 | 53 | /** 54 | * 批量打分预测 55 | */ 56 | public double[] predict(double[][] features) { 57 | double[] scores = new double[features.length]; 58 | for (int i = 0; i < features.length; i++) { 59 | scores[i] = predict(features[i]); 60 | } 61 | return scores; 62 | } 63 | 64 | /** 65 | * 预测结果值 66 | */ 67 | public double predict(double[] denseFeature) { 68 | // 特征离散化 69 | SparseVector feature = trans2SparseVector(denseFeature); 70 | // 获取预测值 71 | return lrParser.predict(feature); 72 | } 73 | 74 | /** 75 | * 获取最终的稀疏编码特征向量:原始特征离散化SparseCode + XGBoost离散化SparseCode 76 | */ 77 | public SparseVector trans2SparseVector(double[] denseFeature) { 78 | // 原始特征离散化 79 | SparseVector vec1 = featureMaker.trans2SparseVector(denseFeature); 80 | 81 | // XGBoost特征离散化 82 | SparseVector vec2 = xgbParser.trans2SparseVector(denseFeature); 83 | 84 | // 特征合并并返回 85 | return SparseVector.merge(vec1, vec2); 86 | } 87 | 88 | /** 89 | * 保存特征属性及其离散化分桶信息,更新到model.conf 90 | */ 91 | public void saveAsModelConf(List featureConfList) { 92 | // TODO 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/models/LRParser.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.models; 2 | 3 | import org.jeemy.feature.SparseVector; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.InputStreamReader; 9 | import java.util.List; 10 | 11 | /** 12 | * @User: zhanghuayan 13 | * @Date: 2020/4/18 4:31 下午 14 | */ 15 | public class LRParser { 16 | // LR weights,Bias保存在第一位 17 | private List lrWeights; 18 | 19 | /** 20 | * LR 构造函数 21 | */ 22 | public LRParser(String lrModelPath) { 23 | try { 24 | File file = new File(lrModelPath); 25 | InputStreamReader streamReader = new InputStreamReader(new FileInputStream(file)); 26 | BufferedReader reader = new BufferedReader(streamReader); 27 | String line = reader.readLine(); 28 | 29 | String[] valSplits = line.trim().split(","); 30 | for (int i = 0; i < valSplits.length; i++) { 31 | Double weight = Double.parseDouble(valSplits[i]); 32 | lrWeights.add(weight); 33 | } 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | /** 39 | * LR 模型预估打分 40 | */ 41 | public double predict(SparseVector feature) { 42 | // 进行参数合法性验证 43 | try { 44 | if (lrWeights.size() - 1 != feature.size) { 45 | System.out.println("\nlrWeights size: " + lrWeights.size() + "\nfeature size: " + feature.size); 46 | throw new Exception("Sparse feature size not match, please check..."); 47 | } 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | 52 | // 计算预估值 53 | double score = lrWeights.get(0); 54 | for (int i = 0; i < feature.indices.length; i++) { 55 | double value = feature.values[i]; 56 | int index = feature.indices[i] + 1; 57 | score += value * lrWeights.get(index); 58 | } 59 | score = 1.0 / (1.0 + Math.exp(-score)); 60 | return score; 61 | } 62 | 63 | 64 | public List getLrWeights() { 65 | return lrWeights; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/models/XGBoostParser.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.models; 2 | 3 | import org.jeemy.feature.SparseVector; 4 | import org.jeemy.tree.*; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.InputStreamReader; 10 | import java.util.*; 11 | 12 | /** 13 | * @User: zhanghuayan 14 | * @Date: 2020/4/16 11:31 上午 15 | */ 16 | public class XGBoostParser { 17 | /** 18 | * XGBoost所有决策树 19 | */ 20 | private List trees = new ArrayList<>(); 21 | 22 | /** 23 | * 重建XGBoost模型 24 | */ 25 | public XGBoostParser(String path) { 26 | List> listLines = loadModelFile(path); 27 | for (int i = 0; i < listLines.size(); i++) { 28 | DecisionTree tree = parseTree(listLines.get(i)); 29 | trees.add(tree); 30 | } 31 | } 32 | 33 | /** 34 | * 获取特征向量的XGBoost离散化的结果 35 | */ 36 | public SparseVector trans2SparseVector(double[] denseFeature) { 37 | // 稀疏向量 38 | int size = 0; 39 | int[] indices = new int[trees.size()]; 40 | double[] values = new double[trees.size()]; 41 | 42 | // 构建稀疏向量 43 | int[] leafIndexes = getPredictLeafs(denseFeature); 44 | for (int i = 0; i < trees.size(); i++) { 45 | indices[i] = size + leafIndexes[i]; 46 | values[i] = 1.0; 47 | // 更新稀疏向量大小 48 | size += trees.get(i).leafNum; 49 | } 50 | return new SparseVector(size, indices, values); 51 | } 52 | 53 | /** 54 | * 获取特征向量预测结果在所有决策树上的叶子节点编号 55 | */ 56 | public int[] getPredictLeafs(double[] feature) { 57 | // 叶子节点数与树的棵数一致 58 | int[] leafIndexes = new int[trees.size()]; 59 | 60 | for (int i = 0; i < trees.size(); i++) { 61 | TreeNode node = trees.get(i).rootNode; 62 | int featureIndex = Integer.parseInt(node.splitFeature.substring(1)); 63 | double featureValue = feature[featureIndex]; 64 | 65 | // 只要是内部节点就继续(叶子节点或者默认节点结束) 66 | while (node.nodeType == NodeType.INNER_NODE) { 67 | if (featureValue < node.splitValue) { 68 | node = node.lNode; 69 | } else { 70 | node = node.rNode; 71 | } 72 | 73 | // 内部节点和叶子节点展示信息不一样 74 | if (node.nodeType == NodeType.INNER_NODE) { 75 | featureIndex = Integer.parseInt(node.splitFeature.substring(1)); 76 | featureValue = feature[featureIndex]; 77 | } else if (node.nodeType == NodeType.LEAF_NODE) { 78 | // 叶子节点索引保存 79 | leafIndexes[i] = (node.index - trees.get(i).minLeafIndex); 80 | } 81 | } 82 | } 83 | return leafIndexes; 84 | } 85 | 86 | /** 87 | * 根据特征实例样本输出所有决策树上的预测路径,isSort为true按照分值倒序输出 88 | */ 89 | public void showPredictPaths(double[] feature, boolean isSort) { 90 | List treePaths = new ArrayList<>(); 91 | 92 | for (int i = 0; i < trees.size(); i++) { 93 | TreeNode node = trees.get(i).rootNode; 94 | int featureIndex = Integer.parseInt(node.splitFeature.substring(1)); 95 | double featureValue = feature[featureIndex]; 96 | 97 | StringBuffer sb = new StringBuffer(); 98 | sb.append(String.format("Path %d: (%s,%.4f,%.4f)", i, node.splitFeature, featureValue, node.splitValue)); 99 | // 只要是内部节点就继续(叶子节点或者默认节点结束) 100 | while (node.nodeType == NodeType.INNER_NODE) { 101 | if (featureValue < node.splitValue) { 102 | node = node.lNode; 103 | } else { 104 | node = node.rNode; 105 | } 106 | 107 | // 内部节点和叶子节点展示信息不一样 108 | if (node.nodeType == NodeType.INNER_NODE) { 109 | featureIndex = Integer.parseInt(node.splitFeature.substring(1)); 110 | featureValue = feature[featureIndex]; 111 | sb.append(String.format(" —> (%s,%.4f,%.4f)", node.splitFeature, featureValue, node.splitValue)); 112 | } else if (node.nodeType == NodeType.LEAF_NODE) { 113 | sb.append(String.format(" —> (score: %.4f)", node.splitValue)); 114 | // 叶子节点说明该决策树路径已经结束 115 | treePaths.add(new TreePath(node.splitValue, sb.toString())); 116 | } 117 | } 118 | } 119 | 120 | // 判断是否需要按照分值倒序排序 121 | if (isSort == true) { 122 | Collections.sort(treePaths); 123 | } 124 | 125 | // 依次打印各条路径 126 | for (TreePath treePath : treePaths) { 127 | System.out.println(treePath.path); 128 | } 129 | } 130 | 131 | /** 132 | * 根据特征实例样本输出所有决策树上的预测路径 133 | */ 134 | public void showPredictPaths(double[] feature) { 135 | showPredictPaths(feature, false); 136 | } 137 | 138 | /** 139 | * 根据字符串列表解析单颗决策树 140 | */ 141 | private DecisionTree parseTree(List lines) { 142 | Map treeNodeMap = new HashMap<>(); 143 | 144 | // 解析每个节点数据 145 | for (String line : lines) { 146 | TreeNode node = parseLine(line); 147 | treeNodeMap.put(node.index, node); 148 | } 149 | 150 | // 叶子节点数 leafNum = maxLeafIndex - minLeafIndex + 1 151 | int minLeafIndex = Integer.MAX_VALUE; 152 | int maxLeafIndex = Integer.MIN_VALUE; 153 | 154 | // 构建决策树 155 | for (TreeNode node : treeNodeMap.values()) { 156 | // 只有内部节点需要寻找孩子节点,叶子节点不需要处理 157 | if (node.nodeType == NodeType.INNER_NODE) { 158 | node.lNode = treeNodeMap.get(node.lNodeIndex); 159 | node.rNode = treeNodeMap.get(node.rNodeIndex); 160 | } 161 | 162 | // 更新minLeafIndex/maxLeafIndex 163 | if (node.nodeType == NodeType.LEAF_NODE) { 164 | if (maxLeafIndex < node.index) { 165 | maxLeafIndex = node.index; 166 | } 167 | 168 | if (minLeafIndex > node.index) { 169 | minLeafIndex = node.index; 170 | } 171 | } 172 | } 173 | 174 | // 索引为零的节点就是根节点 175 | int leafNum = maxLeafIndex - minLeafIndex + 1; 176 | return new DecisionTree(treeNodeMap.get(0), leafNum, minLeafIndex, maxLeafIndex); 177 | } 178 | 179 | /** 180 | * 将单行字符串解析成单个决策树节点 181 | */ 182 | private TreeNode parseLine(String line) { 183 | TreeNode node = new TreeNode(); 184 | 185 | // 根据当前节点是否为叶子节点进行不同的解析 186 | String[] strs; 187 | if (line.contains("leaf")) { 188 | strs = line.trim().split(":leaf="); 189 | node.nodeType = NodeType.LEAF_NODE; 190 | node.index = Integer.parseInt(strs[0]); 191 | node.splitValue = Double.parseDouble(strs[1]); 192 | } else { 193 | strs = line.trim().split(":\\[|<|\\] yes=|,no=|,missing="); 194 | node.nodeType = NodeType.INNER_NODE; 195 | node.index = Integer.parseInt(strs[0]); 196 | node.splitFeature = strs[1]; 197 | node.splitValue = Double.parseDouble(strs[2]); 198 | node.lNodeIndex = Integer.parseInt(strs[3]); 199 | node.rNodeIndex = Integer.parseInt(strs[4]); 200 | node.defaultIndex = Integer.parseInt(strs[5]); 201 | } 202 | return node; 203 | } 204 | 205 | /** 206 | * 读取path指向的模型文件,将其转化成一系列字符串数组 207 | */ 208 | private List> loadModelFile(String path) { 209 | List> listLines = new ArrayList<>(); 210 | List lines = new ArrayList<>(); 211 | 212 | // 按行读取文件 213 | try { 214 | File file = new File(path); 215 | InputStreamReader streamReader = new InputStreamReader(new FileInputStream(file)); 216 | BufferedReader reader = new BufferedReader(streamReader); 217 | String line = reader.readLine(); 218 | while (line != null) { 219 | line = line.trim(); 220 | if (line.startsWith("booster") && lines.size() > 0) { 221 | listLines.add(lines); 222 | lines = new ArrayList<>(); 223 | } else if (!line.startsWith("booster")) { 224 | lines.add(line); 225 | } 226 | line = reader.readLine(); 227 | } 228 | 229 | // 最后一棵树 230 | if (lines.size() > 0) { 231 | listLines.add(lines); 232 | } 233 | } catch (Exception e) { 234 | e.printStackTrace(); 235 | } 236 | return listLines; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/tree/DecisionTree.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.tree; 2 | 3 | /** 4 | * @User: zhanghuayan 5 | * @Date: 2020/4/18 6:26 下午 6 | */ 7 | public class DecisionTree { 8 | // 决策树根节点 9 | public TreeNode rootNode; 10 | 11 | // 决策树叶子节点数 12 | public int leafNum; 13 | 14 | // 决策树最小叶子节点编号 15 | public int minLeafIndex; 16 | 17 | // 决策树最大叶子节点编号 18 | public int maxLeafIndex; 19 | 20 | /** 21 | * 构造函数 22 | */ 23 | public DecisionTree() { 24 | rootNode = null; 25 | leafNum = 0; 26 | minLeafIndex = 0; 27 | maxLeafIndex = 0; 28 | } 29 | 30 | /** 31 | * 构造函数 32 | */ 33 | public DecisionTree(TreeNode rootNode, int leafNum, int minLeafIndex, int maxLeafIndex) { 34 | this.rootNode = rootNode; 35 | this.leafNum = leafNum; 36 | this.minLeafIndex = minLeafIndex; 37 | this.maxLeafIndex = maxLeafIndex; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/tree/NodeType.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.tree; 2 | 3 | /** 4 | * @User: zhanghuayan 5 | * @Date: 2020/4/16 11:40 上午 6 | */ 7 | public enum NodeType { 8 | DEFAULT_NODE("默认节点", 0), 9 | LEAF_NODE("叶子节点", 1), 10 | INNER_NODE("内部节点", 2); 11 | 12 | private String name; 13 | private int index; 14 | 15 | private NodeType(String name, int index) { 16 | this.name = name; 17 | this.index = index; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public int getIndex() { 29 | return index; 30 | } 31 | 32 | public void setIndex(int index) { 33 | this.index = index; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/tree/TreeNode.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.tree; 2 | 3 | /** 4 | * @User: zhanghuayan 5 | * @Date: 2020/4/16 11:16 上午 6 | */ 7 | public class TreeNode { 8 | // 节点索引号 9 | public int index; 10 | // 节点类型 11 | public NodeType nodeType; 12 | // 节点分裂特征名 13 | public String splitFeature; 14 | // 节点分裂值(如果是叶子节点,那就是预测值) 15 | public double splitValue; 16 | 17 | // 左右孩子节点索引号以及默认孩子索引号 18 | public int lNodeIndex; 19 | public int rNodeIndex; 20 | public int defaultIndex; 21 | 22 | // 左右孩子节点 23 | public TreeNode lNode; 24 | public TreeNode rNode; 25 | 26 | public TreeNode() { 27 | this.index = 0; 28 | this.nodeType = NodeType.DEFAULT_NODE; 29 | this.splitFeature = ""; 30 | this.splitValue = 0.0; 31 | this.lNodeIndex = 0; 32 | this.rNodeIndex = 0; 33 | this.defaultIndex = 0; 34 | this.lNode = null; 35 | this.rNode = null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/jeemy/tree/TreePath.java: -------------------------------------------------------------------------------- 1 | package org.jeemy.tree; 2 | 3 | /** 4 | * @User: zhanghuayan 5 | * @Date: 2020/4/18 5:00 下午 6 | */ 7 | public class TreePath implements Comparable { 8 | // 在当前决策树路径下的预测结果值 9 | public double score; 10 | // 预测路径字符串 11 | public String path; 12 | 13 | public TreePath() { 14 | this.score = 0; 15 | this.path = ""; 16 | } 17 | 18 | public TreePath(double score, String path) { 19 | this.score = score; 20 | this.path = path; 21 | } 22 | 23 | @Override 24 | public int compareTo(TreePath o) { 25 | // 倒序排序 26 | if (o.score > this.score) { 27 | return 1; 28 | } else if (o.score < this.score) { 29 | return -1; 30 | } 31 | return 0; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/resources/featureConf: -------------------------------------------------------------------------------- 1 | # Feature schema example 2 | label, double, other 3 | u_age, int, continuous 4 | u_salary, double, continuous 5 | u_gender, string, discrete 6 | u_city, string, discrete 7 | i_age, int, continuous 8 | i_salary, double, continuous 9 | i_gender, string, discrete 10 | i_city, string, discrete -------------------------------------------------------------------------------- /src/main/resources/model.conf: -------------------------------------------------------------------------------- 1 | lr_model_path = "lr_model.dat" 2 | 3 | xgb_model_path = "xgb_model.dat" 4 | 5 | feature = [ 6 | { 7 | name = b_age 8 | type = continuous 9 | values = [-2147483647.0, 2.0, 20.0, 23.0, 25.0, 27.0, 29.0, 30.0, 32.0, 34.0, 37.0, 42.0, 2147483647.0] 10 | } 11 | { 12 | name = b_cit 13 | type = discrete 14 | values = ["1.0:0.0", "7.0:1.0", "34.0:2.0", "12.0:3.0", "49.0:4.0", "105.0:5.0", "50.0:6.0", "28.0:7.0", "42.0:8.0", "40.0:9.0", "156.0:10.0", "9.0:11.0", "111.0:12.0", "2.0:13.0", "88.0:14.0", "41.0:15.0", "96.0:16.0", "15.0:17.0", "167.0:18.0", "59.0:19.0", "51.0:20.0", "135.0:21.0", "53.0:22.0", "163.0:23.0", "32.0:24.0", "75.0:25.0", "55.0:26.0", "91.0:27.0", "85.0:28.0", "14.0:29.0", "66.0:30.0", "106.0:31.0", "148.0:32.0", "155.0:33.0", "198.0:34.0", "98.0:35.0", "209.0:36.0", "166.0:37.0", "70.0:38.0", "37.0:39.0", "8.0:40.0", "140.0:41.0", "181.0:42.0", "18.0:43.0", "173.0:44.0", "177.0:45.0", "65.0:46.0", "5.0:47.0", "63.0:48.0", "57.0:49.0", "116.0:50.0", "81.0:51.0", "388.0:52.0", "90.0:53.0", "337.0:54.0", "31.0:55.0", "152.0:56.0", "124.0:57.0", "175.0:58.0", "120.0:59.0", "137.0:60.0", "44.0:61.0", "101.0:62.0", "68.0:63.0", "184.0:64.0", "136.0:65.0", "45.0:66.0", "150.0:67.0", "119.0:68.0", "323.0:69.0", "61.0:70.0", "108.0:71.0", "261.0:72.0", "38.0:73.0", "129.0:74.0", "113.0:75.0", "77.0:76.0", "93.0:77.0", "128.0:78.0", "149.0:79.0", "370.0:80.0", "109.0:81.0", "121.0:82.0", "64.0:83.0", "165.0:84.0", "268.0:85.0", "83.0:86.0", "373.0:87.0", "343.0:88.0", "72.0:89.0", "13.0:90.0", "242.0:91.0", "30.0:92.0", "100.0:93.0", "29.0:94.0", "368.0:95.0", "205.0:96.0", "145.0:97.0", "92.0:98.0", "143.0:99.0", "369.0:100.0", "138.0:101.0", "132.0:102.0", "169.0:103.0", "36.0:104.0", "16.0:105.0", "33.0:106.0", "4.0:107.0", "62.0:108.0", "19.0:109.0", "183.0:110.0", "157.0:111.0", "139.0:112.0", "387.0:113.0", "274.0:114.0", "231.0:115.0", "82.0:116.0", "21.0:117.0", "99.0:118.0", "122.0:119.0", "384.0:120.0", "376.0:121.0", "285.0:122.0", "153.0:123.0", "237.0:124.0", "444.0:125.0", "162.0:126.0", "405.0:127.0", "69.0:128.0", "103.0:129.0", "363.0:130.0", "329.0:131.0", "195.0:132.0", "357.0:133.0", "134.0:134.0", "131.0:135.0", "6.0:136.0", "312.0:137.0", "203.0:138.0", "354.0:139.0", "463.0:140.0", "23.0:141.0", "161.0:142.0", "146.0:143.0", "130.0:144.0", "27.0:145.0", "71.0:146.0", "355.0:147.0", "118.0:148.0", "374.0:149.0", "336.0:150.0", "259.0:151.0", "56.0:152.0", "84.0:153.0", "180.0:154.0", "54.0:155.0", "67.0:156.0", "416.0:157.0", "164.0:158.0", "17.0:159.0", "11.0:160.0", "280.0:161.0", "330.0:162.0", "442.0:163.0", "194.0:164.0", "358.0:165.0", "328.0:166.0", "142.0:167.0", "265.0:168.0", "234.0:169.0", "395.0:170.0", "402.0:171.0", "191.0:172.0", "278.0:173.0", "441.0:174.0", "321.0:175.0", "78.0:176.0", "327.0:177.0", "123.0:178.0", "170.0:179.0", "133.0:180.0", "428.0:181.0", "263.0:182.0", "379.0:183.0", "260.0:184.0", "60.0:185.0", "464.0:186.0", "125.0:187.0", "284.0:188.0", "322.0:189.0", "315.0:190.0", "141.0:191.0", "43.0:192.0", "275.0:193.0", "409.0:194.0", "391.0:195.0", "279.0:196.0", "325.0:197.0", "159.0:198.0", "389.0:199.0", "144.0:200.0", "380.0:201.0", "35.0:202.0", "115.0:203.0", "204.0:204.0", "117.0:205.0", "282.0:206.0", "352.0:207.0", "158.0:208.0", "102.0:209.0", "417.0:210.0", "22.0:211.0", "316.0:212.0", "80.0:213.0", "76.0:214.0", "58.0:215.0", "20.0:216.0", "448.0:217.0", "446.0:218.0", "411.0:219.0", "291.0:220.0", "199.0:221.0", "269.0:222.0", "311.0:223.0", "317.0:224.0", "200.0:225.0", "39.0:226.0", "392.0:227.0", "147.0:228.0", "410.0:229.0", "127.0:230.0", "240.0:231.0", "239.0:232.0", "0.0:233.0", "26.0:234.0", "95.0:235.0", "393.0:236.0", "324.0:237.0", "160.0:238.0", "371.0:239.0", "383.0:240.0", "447.0:241.0", "399.0:242.0", "89.0:243.0", "326.0:244.0", "413.0:245.0", "443.0:246.0", "154.0:247.0", "201.0:248.0", "408.0:249.0", "74.0:250.0", "210.0:251.0", "440.0:252.0", "318.0:253.0", "394.0:254.0", "186.0:255.0", "73.0:256.0", "310.0:257.0", "433.0:258.0", "319.0:259.0", "10.0:260.0", "197.0:261.0", "375.0:262.0", "174.0:263.0", "465.0:264.0", "431.0:265.0", "390.0:266.0", "202.0:267.0", "25.0:268.0", "241.0:269.0", "308.0:270.0", "309.0:271.0", "94.0:272.0", "432.0:273.0", "276.0:274.0", "238.0:275.0", "196.0:276.0", "97.0:277.0", "262.0:278.0", "266.0:279.0", "445.0:280.0", "396.0:281.0", "338.0:282.0", "235.0:283.0", "86.0:284.0", "436.0:285.0", "288.0:286.0", "449.0:287.0", "367.0:288.0", "270.0:289.0", "114.0:290.0", "87.0:291.0", "359.0:292.0", "356.0:293.0", "364.0:294.0", "386.0:295.0", "406.0:296.0", "361.0:297.0", "382.0:298.0", "110.0:299.0", "438.0:300.0", "290.0:301.0", "435.0:302.0", "362.0:303.0", "430.0:304.0", "434.0:305.0", "439.0:306.0", "151.0:307.0", "494.0:308.0", "320.0:309.0", "437.0:310.0", "503.0:311.0", "474.0:312.0", "427.0:313.0", "232.0:314.0", "471.0:315.0", "498.0:316.0", "490.0:317.0", "313.0:318.0", "476.0:319.0", "473.0:320.0", "475.0:321.0", "425.0:322.0", "481.0:323.0", "46.0:324.0", "460.0:325.0", "487.0:326.0", "385.0:327.0", "478.0:328.0", "486.0:329.0"] 15 | } 16 | { 17 | name = b_ckc 18 | type = discrete 19 | values = ["60001.0:0.0", "60011.0:1.0", "60003.0:2.0", "60016.0:3.0", "60013.0:4.0", "60027.0:5.0", "60010.0:6.0", "60008.0:7.0", "60033.0:8.0", "60004.0:9.0", "60028.0:10.0", "60030.0:11.0", "60002.0:12.0", "60017.0:13.0", "60023.0:14.0", "60025.0:15.0", "60031.0:16.0", "60015.0:17.0", "60009.0:18.0", "60022.0:19.0", "60032.0:20.0", "60005.0:21.0", "60014.0:22.0", "60007.0:23.0", "60020.0:24.0", "60019.0:25.0", "60021.0:26.0", "60029.0:27.0", "60024.0:28.0", "60018.0:29.0", "60006.0:30.0", "60012.0:31.0", "2.0:32.0", "0.0:33.0", "60026.0:34.0"] 20 | } 21 | { 22 | name = b_cs 23 | type = discrete 24 | values = ["80001.0:0.0", "80002.0:1.0", "80003.0:2.0", "80004.0:3.0", "80005.0:4.0", "80006.0:5.0", "2.0:6.0", "0.0:7.0"] 25 | } 26 | { 27 | name = b_gen 28 | type = discrete 29 | values = ["0.0:0.0", "2.0:1.0", "1.0:2.0"] 30 | } 31 | { 32 | name = b_hom 33 | type = discrete 34 | values = ["0.0:0.0", "7.0:1.0", "12.0:2.0", "1.0:3.0", "34.0:4.0", "105.0:5.0", "9.0:6.0", "111.0:7.0", "49.0:8.0", "2.0:9.0", "38.0:10.0", "41.0:11.0", "156.0:12.0", "128.0:13.0", "50.0:14.0", "118.0:15.0", "268.0:16.0", "88.0:17.0", "261.0:18.0", "42.0:19.0", "181.0:20.0", "69.0:21.0", "373.0:22.0", "165.0:23.0", "91.0:24.0", "51.0:25.0", "36.0:26.0", "31.0:27.0", "15.0:28.0", "242.0:29.0", "5.0:30.0", "3.0:31.0", "368.0:32.0", "167.0:33.0", "40.0:34.0", "122.0:35.0", "83.0:36.0", "145.0:37.0", "53.0:38.0", "149.0:39.0", "113.0:40.0", "139.0:41.0", "280.0:42.0", "16.0:43.0", "44.0:44.0", "209.0:45.0", "343.0:46.0", "72.0:47.0", "325.0:48.0", "85.0:49.0", "68.0:50.0", "116.0:51.0", "28.0:52.0", "99.0:53.0", "93.0:54.0", "11.0:55.0", "331.0:56.0", "336.0:57.0", "357.0:58.0", "419.0:59.0", "63.0:60.0", "370.0:61.0", "328.0:62.0", "55.0:63.0", "164.0:64.0", "166.0:65.0", "35.0:66.0", "75.0:67.0", "81.0:68.0", "77.0:69.0", "48.0:70.0", "388.0:71.0", "315.0:72.0", "387.0:73.0", "322.0:74.0", "82.0:75.0", "32.0:76.0", "281.0:77.0", "18.0:78.0", "66.0:79.0", "418.0:80.0", "327.0:81.0", "134.0:82.0", "389.0:83.0", "330.0:84.0", "231.0:85.0", "96.0:86.0", "444.0:87.0", "159.0:88.0", "442.0:89.0", "67.0:90.0", "379.0:91.0", "285.0:92.0", "275.0:93.0", "130.0:94.0", "143.0:95.0", "448.0:96.0", "98.0:97.0", "354.0:98.0", "329.0:99.0", "183.0:100.0", "109.0:101.0", "446.0:102.0", "62.0:103.0", "409.0:104.0", "119.0:105.0", "120.0:106.0", "70.0:107.0", "402.0:108.0", "384.0:109.0", "263.0:110.0", "59.0:111.0", "367.0:112.0", "37.0:113.0", "144.0:114.0", "65.0:115.0", "195.0:116.0", "278.0:117.0", "132.0:118.0", "76.0:119.0", "155.0:120.0", "337.0:121.0", "363.0:122.0", "61.0:123.0", "161.0:124.0", "184.0:125.0", "163.0:126.0", "13.0:127.0", "17.0:128.0", "33.0:129.0", "60.0:130.0", "14.0:131.0", "237.0:132.0", "142.0:133.0", "312.0:134.0", "127.0:135.0", "186.0:136.0", "131.0:137.0", "29.0:138.0", "289.0:139.0", "175.0:140.0", "8.0:141.0", "148.0:142.0", "19.0:143.0", "355.0:144.0", "339.0:145.0", "157.0:146.0", "202.0:147.0", "74.0:148.0", "30.0:149.0", "56.0:150.0", "57.0:151.0", "335.0:152.0", "194.0:153.0", "431.0:154.0", "73.0:155.0", "350.0:156.0", "205.0:157.0", "4.0:158.0", "162.0:159.0", "284.0:160.0", "416.0:161.0", "380.0:162.0", "180.0:163.0", "369.0:164.0", "92.0:165.0", "71.0:166.0", "171.0:167.0", "173.0:168.0", "90.0:169.0", "199.0:170.0", "260.0:171.0", "198.0:172.0", "104.0:173.0", "169.0:174.0", "274.0:175.0", "123.0:176.0", "64.0:177.0", "441.0:178.0", "135.0:179.0", "101.0:180.0", "374.0:181.0", "395.0:182.0", "269.0:183.0", "117.0:184.0", "106.0:185.0", "262.0:186.0", "153.0:187.0", "443.0:188.0", "432.0:189.0", "138.0:190.0", "190.0:191.0", "137.0:192.0", "115.0:193.0", "10.0:194.0", "351.0:195.0", "152.0:196.0", "23.0:197.0", "436.0:198.0", "323.0:199.0", "102.0:200.0", "20.0:201.0", "121.0:202.0", "136.0:203.0", "177.0:204.0", "174.0:205.0", "421.0:206.0", "129.0:207.0", "282.0:208.0", "103.0:209.0", "39.0:210.0", "447.0:211.0", "21.0:212.0", "140.0:213.0", "146.0:214.0", "6.0:215.0", "196.0:216.0", "265.0:217.0", "158.0:218.0", "449.0:219.0", "151.0:220.0", "311.0:221.0", "411.0:222.0", "358.0:223.0", "43.0:224.0", "45.0:225.0", "279.0:226.0", "236.0:227.0", "391.0:228.0", "133.0:229.0", "334.0:230.0", "95.0:231.0", "188.0:232.0", "393.0:233.0", "201.0:234.0", "234.0:235.0", "52.0:236.0", "463.0:237.0", "191.0:238.0", "147.0:239.0", "100.0:240.0", "371.0:241.0", "58.0:242.0", "150.0:243.0", "114.0:244.0", "124.0:245.0", "412.0:246.0", "160.0:247.0", "399.0:248.0", "259.0:249.0", "204.0:250.0", "406.0:251.0", "232.0:252.0", "290.0:253.0", "326.0:254.0", "413.0:255.0", "420.0:256.0", "405.0:257.0", "417.0:258.0", "94.0:259.0", "410.0:260.0", "352.0:261.0", "425.0:262.0", "440.0:263.0", "392.0:264.0", "428.0:265.0", "381.0:266.0", "54.0:267.0", "154.0:268.0", "427.0:269.0", "80.0:270.0", "356.0:271.0", "464.0:272.0", "264.0:273.0", "97.0:274.0", "108.0:275.0", "318.0:276.0", "438.0:277.0", "362.0:278.0", "317.0:279.0", "168.0:280.0", "435.0:281.0", "89.0:282.0", "309.0:283.0", "433.0:284.0", "239.0:285.0", "386.0:286.0", "238.0:287.0", "22.0:288.0", "187.0:289.0", "308.0:290.0", "125.0:291.0", "200.0:292.0", "288.0:293.0", "84.0:294.0", "197.0:295.0", "189.0:296.0", "276.0:297.0", "408.0:298.0", "87.0:299.0", "185.0:300.0", "112.0:301.0", "266.0:302.0", "78.0:303.0", "319.0:304.0", "206.0:305.0", "321.0:306.0", "426.0:307.0", "390.0:308.0", "474.0:309.0", "27.0:310.0", "430.0:311.0", "382.0:312.0", "461.0:313.0", "25.0:314.0", "361.0:315.0", "210.0:316.0", "465.0:317.0", "86.0:318.0", "429.0:319.0", "141.0:320.0", "170.0:321.0", "324.0:322.0", "403.0:323.0", "445.0:324.0", "383.0:325.0", "394.0:326.0", "203.0:327.0", "407.0:328.0", "235.0:329.0", "243.0:330.0", "341.0:331.0", "376.0:332.0", "434.0:333.0", "452.0:334.0", "422.0:335.0", "126.0:336.0", "375.0:337.0", "110.0:338.0", "439.0:339.0", "460.0:340.0", "24.0:341.0", "372.0:342.0", "396.0:343.0", "404.0:344.0", "477.0:345.0", "310.0:346.0", "366.0:347.0", "208.0:348.0", "240.0:349.0", "397.0:350.0", "313.0:351.0", "437.0:352.0", "338.0:353.0", "291.0:354.0", "107.0:355.0", "316.0:356.0", "475.0:357.0", "241.0:358.0", "307.0:359.0", "476.0:360.0", "454.0:361.0", "400.0:362.0", "364.0:363.0", "192.0:364.0", "415.0:365.0", "26.0:366.0", "306.0:367.0", "267.0:368.0", "277.0:369.0", "333.0:370.0", "340.0:371.0", "270.0:372.0", "494.0:373.0", "283.0:374.0", "233.0:375.0", "487.0:376.0", "271.0:377.0", "172.0:378.0", "493.0:379.0", "451.0:380.0", "305.0:381.0", "314.0:382.0", "453.0:383.0", "342.0:384.0", "359.0:385.0", "471.0:386.0", "495.0:387.0", "466.0:388.0", "473.0:389.0", "176.0:390.0", "480.0:391.0", "455.0:392.0", "486.0:393.0", "179.0:394.0", "468.0:395.0", "182.0:396.0", "491.0:397.0", "46.0:398.0"] 35 | } 36 | { 37 | name = b_app 38 | type = discrete 39 | values = ["1.0:0.0", "0.0:1.0", "3.0:2.0", "2.0:3.0", "4.0:4.0", "5.0:5.0", "6.0:6.0"] 40 | } 41 | { 42 | name = b_p_age 43 | type = continuous 44 | values = [-2147483647.0, 22.0, 23.0, 24.0, 24.25, 25.25, 26.333333333333332, 26.5, 27.125, 28.0, 28.928571428571427, 29.0, 29.833333333333332, 30.875, 31.5, 32.3125, 33.75, 35.0, 2147483647.0] 45 | } 46 | { 47 | name = b_p_deg 48 | type = continuous 49 | values = [-2147483647.0, 1.0, 1.5, 2.0, 3.25, 4.0, 4.5, 5.0, 5.666666666666667, 6.0, 8.0, 2147483647.0] 50 | } 51 | { 52 | name = b_p_sal 53 | type = continuous 54 | values = [-2147483647.0, 2690.0, 3183.3333333333335, 3500.0, 3800.0, 4000.0, 4250.0, 4500.0, 4714.285714285715, 5000.0, 5450.0, 6000.0, 6125.0, 6500.0, 7271.428571428572, 7500.0, 8500.0, 9500.0, 10666.666666666666, 12375.0, 2147483647.0] 55 | } 56 | { 57 | name = b_p_wky 58 | type = continuous 59 | values = [-2147483647.0, 1.0, 1.5, 2.0, 2.5, 3.5714285714285716, 2147483647.0] 60 | } 61 | { 62 | name = b_b_a_0d 63 | type = continuous 64 | values = [-2147483647.0, 1.0, 2.0, 3.0, 2147483647.0] 65 | } 66 | { 67 | name = b_b_d_0d 68 | type = continuous 69 | values = [-2147483647.0, 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 9.0, 11.0, 15.0, 20.0, 29.0, 48.0, 2147483647.0] 70 | } 71 | { 72 | name = b_b_e_0d 73 | type = continuous 74 | values = [-2147483647.0, 2.0, 3.0, 4.0, 6.0, 9.0, 12.0, 15.0, 19.0, 24.0, 30.0, 37.0, 47.0, 60.0, 77.0, 104.0, 152.0, 260.0, 2147483647.0] 75 | } 76 | { 77 | name = b_reg_d 78 | type = continuous 79 | values = [-2147483647.0, 0.0, 1.0, 4.0, 7.0, 12.0, 18.0, 26.0, 37.0, 54.0, 110.0, 147.0, 185.0, 224.0, 268.0, 330.0, 408.0, 548.0, 732.0, 989.0, 2147483647.0] 80 | } 81 | { 82 | name = b_reg_di_m 83 | type = continuous 84 | values = [-2147483647.0, 613.0, 2740.0, 6022.0, 11349.0, 17601.0, 26646.0, 37691.0, 53389.0, 77785.0, 158371.0, 212397.0, 266356.0, 321701.0, 385767.0, 473843.0, 587852.0, 794702.0, 1053543.0, 1419382.0, 2147483647.0] 85 | } 86 | { 87 | name = b_j_deg_h 88 | type = continuous 89 | values = [-2147483647.0, 1.0, 2.0, 5.0, 8.0, 2147483647.0] 90 | } 91 | { 92 | name = b_j_deg_l 93 | type = continuous 94 | values = [-2147483647.0, 1.0, 2.0, 3.0, 5.0, 8.0, 2147483647.0] 95 | } 96 | { 97 | name = b_j_deg_m 98 | type = continuous 99 | values = [-2147483647.0, 1.0, 1.5, 2.0, 3.25, 4.0, 4.5, 5.0, 5.666666666666667, 6.0, 8.0, 2147483647.0] 100 | } 101 | { 102 | name = b_j_exp_h 103 | type = continuous 104 | values = [-2147483647.0, 1.0, 2.0, 3.0, 4.0, 2147483647.0] 105 | } 106 | { 107 | name = b_j_exp_l 108 | type = continuous 109 | values = [-2147483647.0, 1.0, 3.0, 2147483647.0] 110 | } 111 | { 112 | name = b_j_exp_m 113 | type = continuous 114 | values = [-2147483647.0, 1.0, 1.5, 2.0, 2.5, 3.5714285714285716, 2147483647.0] 115 | } 116 | { 117 | name = b_j_a_h 118 | type = continuous 119 | values = [-2147483647.0, 26.0, 28.0, 30.0, 32.0, 35.0, 38.0, 40.0, 45.0, 50.0, 55.0, 2147483647.0] 120 | } 121 | { 122 | name = b_j_a_l 123 | type = continuous 124 | values = [-2147483647.0, 18.0, 20.0, 21.0, 2147483647.0] 125 | } 126 | { 127 | name = b_j_a_m 128 | type = continuous 129 | values = [-2147483647.0, 22.0, 23.0, 24.0, 24.25, 25.25, 26.333333333333332, 26.5, 27.125, 28.0, 28.928571428571427, 29.0, 29.833333333333332, 30.875, 31.5, 32.3125, 33.75, 35.0, 2147483647.0] 130 | } 131 | { 132 | name = b_j_sal_h 133 | type = continuous 134 | values = [-2147483647.0, 3500.0, 4000.0, 4500.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0, 12000.0, 14000.0, 15000.0, 20000.0, 2147483647.0] 135 | } 136 | { 137 | name = b_j_sal_l 138 | type = continuous 139 | values = [-2147483647.0, 100.0, 1500.0, 2500.0, 2800.0, 3000.0, 3200.0, 3500.0, 3800.0, 4000.0, 4500.0, 5000.0, 6000.0, 8000.0, 2147483647.0] 140 | } 141 | { 142 | name = b_j_sal_m 143 | type = continuous 144 | values = [-2147483647.0, 2690.0, 3183.3333333333335, 3500.0, 3800.0, 4000.0, 4250.0, 4500.0, 4714.285714285715, 5000.0, 5450.0, 6000.0, 6125.0, 6500.0, 7271.428571428572, 7500.0, 8500.0, 9500.0, 10666.666666666666, 12375.0, 2147483647.0] 145 | } 146 | { 147 | name = b_j_welcnt_h 148 | type = continuous 149 | values = [-2147483647.0, 1.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 11.0, 2147483647.0] 150 | } 151 | { 152 | name = b_j_welcnt_l 153 | type = continuous 154 | values = [-2147483647.0, 1.0, 2.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 2147483647.0] 155 | } 156 | { 157 | name = b_j_welcnt_m 158 | type = continuous 159 | values = [-2147483647.0, 1.0, 3.0, 4.0, 5.0, 5.333333333333333, 6.0, 7.0, 8.0, 8.5, 9.25, 2147483647.0] 160 | } 161 | { 162 | name = b_l_t 163 | type = continuous 164 | values = [-2147483647.0, 3910.0, 4471.0, 5478.0, 5796.0, 6678.0, 7103.0, 7423.0, 8380.0, 8689.0, 9558.0, 9998.0, 10340.0, 11321.0, 11663.0, 12641.0, 14041.0, 18636.0, 43089.0, 563147.0, 2147483647.0] 165 | } 166 | { 167 | name = g_age 168 | type = continuous 169 | values = [-2147483647.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 30.0, 32.0, 35.0, 2147483647.0] 170 | } 171 | { 172 | name = g_gen 173 | type = discrete 174 | values = ["1.0:0.0", "2.0:1.0", "0.0:2.0"] 175 | } 176 | { 177 | name = g_cit 178 | type = discrete 179 | values = ["1.0:0.0", "7.0:1.0", "34.0:2.0", "12.0:3.0", "49.0:4.0", "105.0:5.0", "50.0:6.0", "28.0:7.0", "42.0:8.0", "156.0:9.0", "9.0:10.0", "40.0:11.0", "111.0:12.0", "2.0:13.0", "88.0:14.0", "41.0:15.0", "96.0:16.0", "15.0:17.0", "167.0:18.0", "51.0:19.0", "53.0:20.0", "163.0:21.0", "59.0:22.0", "135.0:23.0", "32.0:24.0", "55.0:25.0", "75.0:26.0", "91.0:27.0", "85.0:28.0", "106.0:29.0", "14.0:30.0", "66.0:31.0", "198.0:32.0", "98.0:33.0", "155.0:34.0", "148.0:35.0", "209.0:36.0", "37.0:37.0", "166.0:38.0", "8.0:39.0", "70.0:40.0", "140.0:41.0", "18.0:42.0", "177.0:43.0", "65.0:44.0", "81.0:45.0", "181.0:46.0", "173.0:47.0", "63.0:48.0", "116.0:49.0", "5.0:50.0", "90.0:51.0", "120.0:52.0", "388.0:53.0", "44.0:54.0", "31.0:55.0", "124.0:56.0", "152.0:57.0", "57.0:58.0", "175.0:59.0", "137.0:60.0", "45.0:61.0", "101.0:62.0", "337.0:63.0", "68.0:64.0", "184.0:65.0", "136.0:66.0", "119.0:67.0", "61.0:68.0", "261.0:69.0", "38.0:70.0", "108.0:71.0", "150.0:72.0", "370.0:73.0", "128.0:74.0", "149.0:75.0", "93.0:76.0", "121.0:77.0", "113.0:78.0", "165.0:79.0", "64.0:80.0", "268.0:81.0", "343.0:82.0", "373.0:83.0", "83.0:84.0", "72.0:85.0", "100.0:86.0", "109.0:87.0", "77.0:88.0", "242.0:89.0", "132.0:90.0", "205.0:91.0", "4.0:92.0", "145.0:93.0", "183.0:94.0", "143.0:95.0", "369.0:96.0", "323.0:97.0", "36.0:98.0", "33.0:99.0", "62.0:100.0", "139.0:101.0", "16.0:102.0", "129.0:103.0", "29.0:104.0", "368.0:105.0", "153.0:106.0", "405.0:107.0", "92.0:108.0", "19.0:109.0", "169.0:110.0", "82.0:111.0", "138.0:112.0", "387.0:113.0", "122.0:114.0", "285.0:115.0", "444.0:116.0", "274.0:117.0", "363.0:118.0", "157.0:119.0", "203.0:120.0", "162.0:121.0", "231.0:122.0", "21.0:123.0", "384.0:124.0", "6.0:125.0", "357.0:126.0", "329.0:127.0", "30.0:128.0", "69.0:129.0", "312.0:130.0", "146.0:131.0", "161.0:132.0", "27.0:133.0", "195.0:134.0", "134.0:135.0", "354.0:136.0", "130.0:137.0", "13.0:138.0", "237.0:139.0", "23.0:140.0", "131.0:141.0", "374.0:142.0", "118.0:143.0", "336.0:144.0", "54.0:145.0", "56.0:146.0", "180.0:147.0", "259.0:148.0", "164.0:149.0", "11.0:150.0", "71.0:151.0", "376.0:152.0", "84.0:153.0", "17.0:154.0", "358.0:155.0", "280.0:156.0", "191.0:157.0", "194.0:158.0", "355.0:159.0", "99.0:160.0", "442.0:161.0", "402.0:162.0", "330.0:163.0", "67.0:164.0", "395.0:165.0", "123.0:166.0", "463.0:167.0", "321.0:168.0", "142.0:169.0", "416.0:170.0", "133.0:171.0", "441.0:172.0", "103.0:173.0", "260.0:174.0", "263.0:175.0", "327.0:176.0", "170.0:177.0", "78.0:178.0", "265.0:179.0", "60.0:180.0", "159.0:181.0", "328.0:182.0", "284.0:183.0", "428.0:184.0", "315.0:185.0", "322.0:186.0", "464.0:187.0", "325.0:188.0", "125.0:189.0", "409.0:190.0", "35.0:191.0", "380.0:192.0", "275.0:193.0", "144.0:194.0", "158.0:195.0", "234.0:196.0", "278.0:197.0", "379.0:198.0", "43.0:199.0", "389.0:200.0", "115.0:201.0", "80.0:202.0", "411.0:203.0", "316.0:204.0", "282.0:205.0", "204.0:206.0", "0.0:207.0", "22.0:208.0", "102.0:209.0", "200.0:210.0", "352.0:211.0", "279.0:212.0", "448.0:213.0", "141.0:214.0", "58.0:215.0", "76.0:216.0", "20.0:217.0", "291.0:218.0", "417.0:219.0", "446.0:220.0", "461.0:221.0", "317.0:222.0", "383.0:223.0", "117.0:224.0", "269.0:225.0", "199.0:226.0", "240.0:227.0", "74.0:228.0", "26.0:229.0", "239.0:230.0", "311.0:231.0", "147.0:232.0", "127.0:233.0", "410.0:234.0", "324.0:235.0", "39.0:236.0", "393.0:237.0", "160.0:238.0", "392.0:239.0", "154.0:240.0", "399.0:241.0", "371.0:242.0", "89.0:243.0", "326.0:244.0", "413.0:245.0", "95.0:246.0", "447.0:247.0", "391.0:248.0", "318.0:249.0", "440.0:250.0", "73.0:251.0", "408.0:252.0", "319.0:253.0", "433.0:254.0", "197.0:255.0", "310.0:256.0", "443.0:257.0", "25.0:258.0", "201.0:259.0", "375.0:260.0", "10.0:261.0", "174.0:262.0", "186.0:263.0", "210.0:264.0", "432.0:265.0", "430.0:266.0", "465.0:267.0", "394.0:268.0", "309.0:269.0", "308.0:270.0", "241.0:271.0", "262.0:272.0", "87.0:273.0", "202.0:274.0", "97.0:275.0", "390.0:276.0", "396.0:277.0", "94.0:278.0", "196.0:279.0", "276.0:280.0", "445.0:281.0", "436.0:282.0", "338.0:283.0", "431.0:284.0", "367.0:285.0", "361.0:286.0", "238.0:287.0", "480.0:288.0", "114.0:289.0", "235.0:290.0", "449.0:291.0", "86.0:292.0", "288.0:293.0", "270.0:294.0", "491.0:295.0", "386.0:296.0", "290.0:297.0", "494.0:298.0", "266.0:299.0", "435.0:300.0", "406.0:301.0", "356.0:302.0", "437.0:303.0", "438.0:304.0", "471.0:305.0", "451.0:306.0", "364.0:307.0", "359.0:308.0", "382.0:309.0", "404.0:310.0", "434.0:311.0", "439.0:312.0", "151.0:313.0", "271.0:314.0", "362.0:315.0", "320.0:316.0", "477.0:317.0", "232.0:318.0", "487.0:319.0", "493.0:320.0", "474.0:321.0", "427.0:322.0", "467.0:323.0", "476.0:324.0", "489.0:325.0", "110.0:326.0", "478.0:327.0", "490.0:328.0", "473.0:329.0", "499.0:330.0", "498.0:331.0", "466.0:332.0", "460.0:333.0", "469.0:334.0", "313.0:335.0", "340.0:336.0", "46.0:337.0", "481.0:338.0", "486.0:339.0", "475.0:340.0", "495.0:341.0", "407.0:342.0", "425.0:343.0", "385.0:344.0", "397.0:345.0", "462.0:346.0", "484.0:347.0", "168.0:348.0", "483.0:349.0", "426.0:350.0", "472.0:351.0", "496.0:352.0"] 180 | } 181 | { 182 | name = g_deg 183 | type = discrete 184 | values = ["2.0:0.0", "5.0:1.0", "4.0:2.0", "1.0:3.0", "8.0:4.0", "6.0:5.0", "3.0:6.0", "7.0:7.0", "0.0:8.0"] 185 | } 186 | { 187 | name = g_hom 188 | type = discrete 189 | values = ["0.0:0.0", "12.0:1.0", "9.0:2.0", "7.0:3.0", "105.0:4.0", "111.0:5.0", "34.0:6.0", "1.0:7.0", "38.0:8.0", "268.0:9.0", "118.0:10.0", "156.0:11.0", "41.0:12.0", "128.0:13.0", "69.0:14.0", "149.0:15.0", "167.0:16.0", "44.0:17.0", "139.0:18.0", "88.0:19.0", "357.0:20.0", "261.0:21.0", "32.0:22.0", "275.0:23.0", "384.0:24.0", "49.0:25.0", "15.0:26.0", "83.0:27.0", "31.0:28.0", "237.0:29.0", "448.0:30.0", "373.0:31.0", "2.0:32.0", "72.0:33.0", "50.0:34.0", "330.0:35.0", "165.0:36.0", "231.0:37.0", "368.0:38.0", "442.0:39.0", "109.0:40.0", "327.0:41.0", "36.0:42.0", "85.0:43.0", "5.0:44.0", "51.0:45.0", "91.0:46.0", "325.0:47.0", "82.0:48.0", "436.0:49.0", "81.0:50.0", "74.0:51.0", "53.0:52.0", "285.0:53.0", "209.0:54.0", "181.0:55.0", "116.0:56.0", "122.0:57.0", "66.0:58.0", "42.0:59.0", "132.0:60.0", "322.0:61.0", "77.0:62.0", "388.0:63.0", "113.0:64.0", "242.0:65.0", "55.0:66.0", "328.0:67.0", "446.0:68.0", "35.0:69.0", "93.0:70.0", "130.0:71.0", "145.0:72.0", "389.0:73.0", "343.0:74.0", "444.0:75.0", "40.0:76.0", "315.0:77.0", "184.0:78.0", "370.0:79.0", "60.0:80.0", "96.0:81.0", "387.0:82.0", "99.0:83.0", "280.0:84.0", "186.0:85.0", "63.0:86.0", "379.0:87.0", "336.0:88.0", "409.0:89.0", "3.0:90.0", "11.0:91.0", "68.0:92.0", "75.0:93.0", "76.0:94.0", "18.0:95.0", "164.0:96.0", "80.0:97.0", "65.0:98.0", "62.0:99.0", "312.0:100.0", "354.0:101.0", "166.0:102.0", "143.0:103.0", "4.0:104.0", "183.0:105.0", "59.0:106.0", "67.0:107.0", "447.0:108.0", "202.0:109.0", "28.0:110.0", "195.0:111.0", "13.0:112.0", "329.0:113.0", "281.0:114.0", "102.0:115.0", "194.0:116.0", "402.0:117.0", "432.0:118.0", "20.0:119.0", "284.0:120.0", "48.0:121.0", "441.0:122.0", "73.0:123.0", "98.0:124.0", "61.0:125.0", "146.0:126.0", "33.0:127.0", "205.0:128.0", "64.0:129.0", "45.0:130.0", "29.0:131.0", "16.0:132.0", "449.0:133.0", "461.0:134.0", "337.0:135.0", "155.0:136.0", "153.0:137.0", "144.0:138.0", "120.0:139.0", "30.0:140.0", "8.0:141.0", "142.0:142.0", "463.0:143.0", "352.0:144.0", "78.0:145.0", "159.0:146.0", "318.0:147.0", "19.0:148.0", "374.0:149.0", "169.0:150.0", "119.0:151.0", "157.0:152.0", "395.0:153.0", "162.0:154.0", "37.0:155.0", "17.0:156.0", "263.0:157.0", "14.0:158.0", "265.0:159.0", "274.0:160.0", "180.0:161.0", "464.0:162.0", "56.0:163.0", "326.0:164.0", "57.0:165.0", "134.0:166.0", "278.0:167.0", "416.0:168.0", "363.0:169.0", "269.0:170.0", "90.0:171.0", "163.0:172.0", "431.0:173.0", "131.0:174.0", "335.0:175.0", "331.0:176.0", "445.0:177.0", "175.0:178.0", "177.0:179.0", "282.0:180.0", "89.0:181.0", "117.0:182.0", "138.0:183.0", "92.0:184.0", "355.0:185.0", "127.0:186.0", "70.0:187.0", "380.0:188.0", "124.0:189.0", "260.0:190.0", "129.0:191.0", "152.0:192.0", "405.0:193.0", "323.0:194.0", "199.0:195.0", "240.0:196.0", "311.0:197.0", "160.0:198.0", "154.0:199.0", "58.0:200.0", "173.0:201.0", "115.0:202.0", "174.0:203.0", "204.0:204.0", "232.0:205.0", "367.0:206.0", "108.0:207.0", "358.0:208.0", "418.0:209.0", "196.0:210.0", "71.0:211.0", "101.0:212.0", "106.0:213.0", "23.0:214.0", "351.0:215.0", "417.0:216.0", "198.0:217.0", "262.0:218.0", "121.0:219.0", "460.0:220.0", "137.0:221.0", "443.0:222.0", "148.0:223.0", "324.0:224.0", "392.0:225.0", "288.0:226.0", "161.0:227.0", "135.0:228.0", "136.0:229.0", "419.0:230.0", "158.0:231.0", "147.0:232.0", "410.0:233.0", "279.0:234.0", "317.0:235.0", "369.0:236.0", "10.0:237.0", "259.0:238.0", "334.0:239.0", "133.0:240.0", "197.0:241.0", "371.0:242.0", "308.0:243.0", "376.0:244.0", "190.0:245.0", "22.0:246.0", "201.0:247.0", "428.0:248.0", "43.0:249.0", "95.0:250.0", "54.0:251.0", "123.0:252.0", "171.0:253.0", "411.0:254.0", "151.0:255.0", "433.0:256.0", "393.0:257.0", "386.0:258.0", "421.0:259.0", "406.0:260.0", "200.0:261.0", "191.0:262.0", "103.0:263.0", "21.0:264.0", "94.0:265.0", "440.0:266.0", "150.0:267.0", "187.0:268.0", "203.0:269.0", "6.0:270.0", "140.0:271.0", "399.0:272.0", "188.0:273.0", "425.0:274.0", "413.0:275.0", "309.0:276.0", "289.0:277.0", "394.0:278.0", "350.0:279.0", "168.0:280.0", "366.0:281.0", "427.0:282.0", "84.0:283.0", "276.0:284.0", "234.0:285.0", "112.0:286.0", "383.0:287.0", "39.0:288.0", "310.0:289.0", "435.0:290.0", "375.0:291.0", "339.0:292.0", "125.0:293.0", "361.0:294.0", "438.0:295.0", "97.0:296.0", "185.0:297.0", "391.0:298.0", "319.0:299.0", "100.0:300.0", "206.0:301.0", "170.0:302.0", "236.0:303.0", "426.0:304.0", "239.0:305.0", "27.0:306.0", "407.0:307.0", "474.0:308.0", "189.0:309.0", "238.0:310.0", "321.0:311.0", "412.0:312.0", "381.0:313.0", "87.0:314.0", "420.0:315.0", "208.0:316.0", "408.0:317.0", "462.0:318.0", "430.0:319.0", "356.0:320.0", "307.0:321.0", "390.0:322.0", "465.0:323.0", "25.0:324.0", "210.0:325.0", "277.0:326.0", "52.0:327.0", "313.0:328.0", "290.0:329.0", "114.0:330.0", "26.0:331.0", "266.0:332.0", "439.0:333.0", "172.0:334.0", "362.0:335.0", "126.0:336.0", "466.0:337.0", "264.0:338.0", "382.0:339.0", "364.0:340.0", "359.0:341.0", "396.0:342.0", "404.0:343.0", "403.0:344.0", "451.0:345.0", "192.0:346.0", "291.0:347.0", "316.0:348.0", "241.0:349.0", "434.0:350.0", "305.0:351.0", "267.0:352.0", "243.0:353.0", "86.0:354.0", "333.0:355.0", "283.0:356.0", "141.0:357.0", "320.0:358.0", "24.0:359.0", "271.0:360.0", "338.0:361.0", "452.0:362.0", "454.0:363.0", "306.0:364.0", "400.0:365.0", "233.0:366.0", "179.0:367.0", "385.0:368.0", "176.0:369.0", "422.0:370.0", "235.0:371.0", "503.0:372.0", "270.0:373.0", "341.0:374.0", "104.0:375.0", "340.0:376.0", "372.0:377.0", "471.0:378.0", "429.0:379.0", "437.0:380.0", "107.0:381.0", "79.0:382.0", "110.0:383.0", "415.0:384.0", "473.0:385.0", "193.0:386.0", "491.0:387.0", "424.0:388.0", "353.0:389.0", "450.0:390.0", "314.0:391.0", "46.0:392.0", "401.0:393.0", "470.0:394.0", "456.0:395.0", "342.0:396.0", "469.0:397.0", "453.0:398.0", "467.0:399.0", "500.0:400.0", "498.0:401.0", "468.0:402.0", "182.0:403.0", "495.0:404.0", "496.0:405.0", "475.0:406.0", "505.0:407.0", "397.0:408.0", "497.0:409.0", "504.0:410.0", "455.0:411.0", "494.0:412.0", "472.0:413.0", "458.0:414.0"] 190 | } 191 | { 192 | name = g_lat 193 | type = continuous 194 | values = [-2147483647.0, 22.649887084960938, 22.825477600097656, 23.03529930114746, 23.135456085205078, 24.678014755249023, 27.784299850463867, 29.60841178894043, 30.528146743774414, 30.680221557617188, 31.136241912841797, 31.231687545776367, 31.3029842376709, 31.730152130126953, 32.939579010009766, 34.323455810546875, 36.07111740112305, 39.07590866088867, 39.886905670166016, 39.99720764160156, 2147483647.0] 195 | } 196 | { 197 | name = g_lon 198 | type = continuous 199 | values = [-2147483647.0, 103.99596405029297, 104.14286041259766, 108.25238800048828, 109.00425720214844, 113.09742736816406, 113.28012084960938, 113.41010284423828, 113.78079986572266, 114.02523040771484, 114.39362335205078, 116.30425262451172, 116.46229553222656, 116.95520782470703, 118.18887329101562, 120.03211975097656, 120.50778198242188, 121.1069564819336, 121.41738891601562, 121.5149154663086, 2147483647.0] 200 | } 201 | { 202 | name = g_pic_n 203 | type = discrete 204 | values = ["1.0:0.0", "0.0:1.0", "2.0:2.0", "3.0:3.0", "4.0:4.0", "6.0:5.0", "5.0:6.0", "9.0:7.0", "7.0:8.0", "8.0:9.0", "10.0:10.0", "11.0:11.0"] 205 | } 206 | { 207 | name = g_sal_h 208 | type = continuous 209 | values = [-2147483647.0, 0.0, 3800.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 10000.0, 2147483647.0] 210 | } 211 | { 212 | name = g_sal_l 213 | type = continuous 214 | values = [-2147483647.0, 0.0, 9.0, 2700.0, 3000.0, 3500.0, 4000.0, 4200.0, 5000.0, 6000.0, 2147483647.0] 215 | } 216 | { 217 | name = g_sta 218 | type = discrete 219 | values = ["70001.0:0.0", "0.0:1.0", "70002.0:2.0", "70003.0:3.0"] 220 | } 221 | { 222 | name = g_wan_cnt 223 | type = discrete 224 | values = ["5.0:0.0", "1.0:1.0", "4.0:2.0", "3.0:3.0", "2.0:4.0", "6.0:5.0", "7.0:6.0", "8.0:7.0", "9.0:8.0", "11.0:9.0", "13.0:10.0", "10.0:11.0"] 225 | } 226 | { 227 | name = g_wky 228 | type = discrete 229 | values = ["12004.0:0.0", "12005.0:1.0", "12003.0:2.0", "12006.0:3.0", "12013.0:4.0", "12001.0:5.0", "12007.0:6.0", "12002.0:7.0", "12008.0:8.0", "12009.0:9.0", "12010.0:10.0", "12012.0:11.0", "12011.0:12.0"] 230 | } 231 | { 232 | name = g_don_cnt 233 | type = discrete 234 | values = ["1.0:0.0", "2.0:1.0", "3.0:2.0", "4.0:3.0", "5.0:4.0", "6.0:5.0", "7.0:6.0", "10.0:7.0", "8.0:8.0", "9.0:9.0", "11.0:10.0"] 235 | } 236 | { 237 | name = g_hel 238 | type = discrete 239 | values = ["0.0:0.0", "1.0:1.0"] 240 | } 241 | { 242 | name = g_b_is_c_m 243 | type = discrete 244 | values = ["1.0:0.0", "0.0:1.0"] 245 | } 246 | { 247 | name = g_act_d 248 | type = discrete 249 | values = ["0.0:0.0", "1.0:1.0", "2.0:2.0", "3.0:3.0", "4.0:4.0", "5.0:5.0", "6.0:6.0", "7.0:7.0", "8.0:8.0", "9.0:9.0", "10.0:10.0", "11.0:11.0", "12.0:12.0", "13.0:13.0", "15.0:14.0", "14.0:15.0", "16.0:16.0", "17.0:17.0", "18.0:18.0", "20.0:19.0", "19.0:20.0", "22.0:21.0", "23.0:22.0", "24.0:23.0", "21.0:24.0", "25.0:25.0", "27.0:26.0", "26.0:27.0", "28.0:28.0", "29.0:29.0", "50.0:30.0", "284.0:31.0", "653.0:32.0", "337.0:33.0", "199.0:34.0", "110.0:35.0", "112.0:36.0", "165.0:37.0", "318.0:38.0", "42.0:39.0", "140.0:40.0", "33.0:41.0", "315.0:42.0", "349.0:43.0", "129.0:44.0", "339.0:45.0", "325.0:46.0", "32.0:47.0", "303.0:48.0", "287.0:49.0", "340.0:50.0", "35.0:51.0", "244.0:52.0", "40.0:53.0", "316.0:54.0", "141.0:55.0", "192.0:56.0", "53.0:57.0", "196.0:58.0", "355.0:59.0", "220.0:60.0", "438.0:61.0", "54.0:62.0", "34.0:63.0", "95.0:64.0", "427.0:65.0", "254.0:66.0", "142.0:67.0", "552.0:68.0", "326.0:69.0", "30.0:70.0", "309.0:71.0", "207.0:72.0", "724.0:73.0", "706.0:74.0", "104.0:75.0", "672.0:76.0", "247.0:77.0", "31.0:78.0", "48.0:79.0", "36.0:80.0", "39.0:81.0", "612.0:82.0", "51.0:83.0", "341.0:84.0", "365.0:85.0", "57.0:86.0", "297.0:87.0", "221.0:88.0", "392.0:89.0", "814.0:90.0", "139.0:91.0", "313.0:92.0", "278.0:93.0", "118.0:94.0", "202.0:95.0", "257.0:96.0", "121.0:97.0", "126.0:98.0", "344.0:99.0", "52.0:100.0", "317.0:101.0", "310.0:102.0", "264.0:103.0", "55.0:104.0", "58.0:105.0", "45.0:106.0", "47.0:107.0", "259.0:108.0", "66.0:109.0", "56.0:110.0", "476.0:111.0", "343.0:112.0", "372.0:113.0", "231.0:114.0", "338.0:115.0", "195.0:116.0", "93.0:117.0", "362.0:118.0", "44.0:119.0", "186.0:120.0", "37.0:121.0", "255.0:122.0", "46.0:123.0", "670.0:124.0", "149.0:125.0", "282.0:126.0", "138.0:127.0", "113.0:128.0", "94.0:129.0", "80.0:130.0", "187.0:131.0", "188.0:132.0", "783.0:133.0", "428.0:134.0", "232.0:135.0", "268.0:136.0", "145.0:137.0", "420.0:138.0", "153.0:139.0", "85.0:140.0", "204.0:141.0", "785.0:142.0", "122.0:143.0", "361.0:144.0", "157.0:145.0", "107.0:146.0", "417.0:147.0", "72.0:148.0", "111.0:149.0", "274.0:150.0", "554.0:151.0", "640.0:152.0", "432.0:153.0", "62.0:154.0", "38.0:155.0", "687.0:156.0", "132.0:157.0", "88.0:158.0", "391.0:159.0", "360.0:160.0", "164.0:161.0", "320.0:162.0", "652.0:163.0", "357.0:164.0", "184.0:165.0", "437.0:166.0", "565.0:167.0", "583.0:168.0", "163.0:169.0", "41.0:170.0", "492.0:171.0", "477.0:172.0", "333.0:173.0", "651.0:174.0", "611.0:175.0", "120.0:176.0", "189.0:177.0", "304.0:178.0", "527.0:179.0", "43.0:180.0", "76.0:181.0", "96.0:182.0", "367.0:183.0", "508.0:184.0", "230.0:185.0", "223.0:186.0", "169.0:187.0", "74.0:188.0", "654.0:189.0", "131.0:190.0", "335.0:191.0", "307.0:192.0", "409.0:193.0", "311.0:194.0", "251.0:195.0", "384.0:196.0", "152.0:197.0", "397.0:198.0", "84.0:199.0", "109.0:200.0", "105.0:201.0", "176.0:202.0", "421.0:203.0", "252.0:204.0", "387.0:205.0", "595.0:206.0", "348.0:207.0", "374.0:208.0", "108.0:209.0", "155.0:210.0", "86.0:211.0", "156.0:212.0", "818.0:213.0", "485.0:214.0", "280.0:215.0", "170.0:216.0", "262.0:217.0", "290.0:218.0", "172.0:219.0", "536.0:220.0", "83.0:221.0", "127.0:222.0", "319.0:223.0", "87.0:224.0", "412.0:225.0", "385.0:226.0", "376.0:227.0", "117.0:228.0", "293.0:229.0", "234.0:230.0", "815.0:231.0", "130.0:232.0", "161.0:233.0", "424.0:234.0", "379.0:235.0", "751.0:236.0", "249.0:237.0", "306.0:238.0", "162.0:239.0", "299.0:240.0", "673.0:241.0", "305.0:242.0", "631.0:243.0", "168.0:244.0", "789.0:245.0", "63.0:246.0", "377.0:247.0", "60.0:248.0", "496.0:249.0", "519.0:250.0", "81.0:251.0", "426.0:252.0", "712.0:253.0", "370.0:254.0", "809.0:255.0", "263.0:256.0", "388.0:257.0", "279.0:258.0", "422.0:259.0", "378.0:260.0", "399.0:261.0", "217.0:262.0", "368.0:263.0", "203.0:264.0", "465.0:265.0", "215.0:266.0", "201.0:267.0", "794.0:268.0", "626.0:269.0", "79.0:270.0", "214.0:271.0", "568.0:272.0", "124.0:273.0", "779.0:274.0", "410.0:275.0", "359.0:276.0", "250.0:277.0", "256.0:278.0", "589.0:279.0", "475.0:280.0", "292.0:281.0", "133.0:282.0", "69.0:283.0", "210.0:284.0", "334.0:285.0", "233.0:286.0", "435.0:287.0", "780.0:288.0", "613.0:289.0", "430.0:290.0", "381.0:291.0", "289.0:292.0", "431.0:293.0", "1262.0:294.0", "694.0:295.0", "925.0:296.0", "97.0:297.0", "75.0:298.0", "123.0:299.0", "545.0:300.0", "363.0:301.0", "181.0:302.0", "298.0:303.0", "462.0:304.0", "1386.0:305.0", "398.0:306.0", "353.0:307.0", "645.0:308.0", "49.0:309.0", "147.0:310.0", "212.0:311.0", "938.0:312.0", "167.0:313.0", "776.0:314.0", "98.0:315.0", "354.0:316.0", "59.0:317.0", "102.0:318.0", "134.0:319.0", "225.0:320.0", "332.0:321.0", "418.0:322.0", "408.0:323.0"] 250 | } 251 | { 252 | name = g_act_di_m 253 | type = continuous 254 | values = [-2147483647.0, 0.0, 1.0, 2.0, 3.0, 6.0, 9.0, 13.0, 18.0, 25.0, 34.0, 46.0, 61.0, 82.0, 112.0, 163.0, 271.0, 503.0, 941.0, 2147483647.0] 255 | } 256 | { 257 | name = g_cre_d 258 | type = continuous 259 | values = [-2147483647.0, 0.0, 1.0, 5.0, 11.0, 20.0, 34.0, 62.0, 141.0, 199.0, 261.0, 328.0, 401.0, 542.0, 767.0, 2147483647.0] 260 | } 261 | { 262 | name = g_cre_di_m 263 | type = continuous 264 | values = [-2147483647.0, 20.0, 52.0, 109.0, 234.0, 623.0, 1191.0, 2813.0, 7061.0, 15600.0, 29110.0, 48788.0, 89139.0, 202601.0, 286557.0, 377298.0, 472150.0, 579104.0, 775467.0, 1105848.0, 2147483647.0] 265 | } 266 | { 267 | name = g_b_l_d 268 | type = discrete 269 | values = ["0.0:0.0", "1.0:1.0", "2.0:2.0", "3.0:3.0", "4.0:4.0", "5.0:5.0", "6.0:6.0", "7.0:7.0", "8.0:8.0", "9.0:9.0", "10.0:10.0", "11.0:11.0", "13.0:12.0", "15.0:13.0", "12.0:14.0", "14.0:15.0", "17.0:16.0", "16.0:17.0", "18.0:18.0", "21.0:19.0", "19.0:20.0", "24.0:21.0", "20.0:22.0", "27.0:23.0", "26.0:24.0", "22.0:25.0", "37.0:26.0", "23.0:27.0", "33.0:28.0", "28.0:29.0", "38.0:30.0"] 270 | } 271 | { 272 | name = g_bdet_d 273 | type = discrete 274 | values = ["0.0:0.0", "1.0:1.0", "2.0:2.0", "3.0:3.0", "4.0:4.0", "5.0:5.0", "6.0:6.0", "7.0:7.0", "8.0:8.0", "9.0:9.0", "10.0:10.0", "11.0:11.0", "12.0:12.0", "13.0:13.0", "14.0:14.0", "15.0:15.0", "16.0:16.0", "18.0:17.0", "19.0:18.0", "17.0:19.0", "20.0:20.0", "25.0:21.0", "23.0:22.0", "30.0:23.0", "21.0:24.0", "22.0:25.0"] 275 | } 276 | { 277 | name = g_expo_1d 278 | type = continuous 279 | values = [-2147483647.0, 0.0, 2.0, 8.0, 21.0, 47.0, 100.0, 2147483647.0] 280 | } 281 | { 282 | name = g_expo_3d 283 | type = continuous 284 | values = [-2147483647.0, 0.0, 1.0, 8.0, 22.0, 41.0, 69.0, 114.0, 202.0, 2147483647.0] 285 | } 286 | { 287 | name = g_expo_5d 288 | type = continuous 289 | values = [-2147483647.0, 0.0, 1.0, 8.0, 23.0, 41.0, 65.0, 100.0, 153.0, 277.0, 2147483647.0] 290 | } 291 | { 292 | name = g_expo_7d 293 | type = continuous 294 | values = [-2147483647.0, 0.0, 5.0, 18.0, 35.0, 55.0, 83.0, 123.0, 185.0, 321.0, 2147483647.0] 295 | } 296 | { 297 | name = g_expo_14d 298 | type = continuous 299 | values = [-2147483647.0, 0.0, 4.0, 15.0, 29.0, 45.0, 66.0, 92.0, 127.0, 180.0, 269.0, 461.0, 2147483647.0] 300 | } 301 | { 302 | name = g_det_1d 303 | type = continuous 304 | values = [-2147483647.0, 0.0, 1.0, 2.0, 5.0, 2147483647.0] 305 | } 306 | { 307 | name = g_det_3d 308 | type = continuous 309 | values = [-2147483647.0, 0.0, 1.0, 3.0, 5.0, 11.0, 2147483647.0] 310 | } 311 | { 312 | name = g_det_5d 313 | type = continuous 314 | values = [-2147483647.0, 0.0, 1.0, 2.0, 4.0, 7.0, 15.0, 2147483647.0] 315 | } 316 | { 317 | name = g_det_7d 318 | type = continuous 319 | values = [-2147483647.0, 0.0, 1.0, 2.0, 3.0, 5.0, 9.0, 17.0, 2147483647.0] 320 | } 321 | { 322 | name = g_det_14d 323 | type = continuous 324 | values = [-2147483647.0, 0.0, 1.0, 2.0, 3.0, 5.0, 8.0, 13.0, 24.0, 2147483647.0] 325 | } 326 | { 327 | name = g_add_1d 328 | type = continuous 329 | values = [-2147483647.0, 0.0, 1.0, 3.0, 2147483647.0] 330 | } 331 | { 332 | name = g_add_3d 333 | type = continuous 334 | values = [-2147483647.0, 0.0, 1.0, 2.0, 3.0, 6.0, 2147483647.0] 335 | } 336 | { 337 | name = g_add_5d 338 | type = continuous 339 | values = [-2147483647.0, 0.0, 1.0, 2.0, 4.0, 8.0, 2147483647.0] 340 | } 341 | { 342 | name = g_add_7d 343 | type = continuous 344 | values = [-2147483647.0, 0.0, 1.0, 2.0, 3.0, 5.0, 10.0, 2147483647.0] 345 | } 346 | { 347 | name = g_add_14d 348 | type = continuous 349 | values = [-2147483647.0, 0.0, 1.0, 2.0, 3.0, 5.0, 8.0, 14.0, 2147483647.0] 350 | } 351 | { 352 | name = g_det_r1d 353 | type = continuous 354 | values = [-2147483647.0, 0.0, 0.025, 0.0333, 0.0382, 0.0465, 0.0676, 2147483647.0] 355 | } 356 | { 357 | name = g_det_r3d 358 | type = continuous 359 | values = [-2147483647.0, 0.0, 0.0154, 0.0256, 0.0323, 0.037, 0.0433, 0.0553, 0.0717, 2147483647.0] 360 | } 361 | { 362 | name = g_det_r5d 363 | type = continuous 364 | values = [-2147483647.0, 0.0, 0.0116, 0.0226, 0.0293, 0.0345, 0.0385, 0.0467, 0.0577, 0.0732, 2147483647.0] 365 | } 366 | { 367 | name = g_det_r7d 368 | type = continuous 369 | values = [-2147483647.0, 0.0, 0.0177, 0.0251, 0.0309, 0.0357, 0.04, 0.0485, 0.0588, 0.0736, 2147483647.0] 370 | } 371 | { 372 | name = g_det_r14d 373 | type = continuous 374 | values = [-2147483647.0, 0.0, 0.0156, 0.0221, 0.027, 0.0315, 0.0357, 0.0385, 0.0446, 0.0521, 0.0611, 0.0757, 2147483647.0] 375 | } 376 | { 377 | name = g_add_r1d 378 | type = continuous 379 | values = [-2147483647.0, 0.0, 0.0147, 0.0201, 0.0233, 0.0244, 0.0379, 2147483647.0] 380 | } 381 | { 382 | name = g_add_r3d 383 | type = continuous 384 | values = [-2147483647.0, 0.0, 0.0089, 0.0147, 0.019, 0.0222, 0.0244, 0.0317, 0.0435, 2147483647.0] 385 | } 386 | { 387 | name = g_add_r5d 388 | type = continuous 389 | values = [-2147483647.0, 0.0, 0.0066, 0.0128, 0.0168, 0.0204, 0.0233, 0.0267, 0.0342, 0.0454, 2147483647.0] 390 | } 391 | { 392 | name = g_add_r7d 393 | type = continuous 394 | values = [-2147483647.0, 0.0, 0.01, 0.0143, 0.0179, 0.0212, 0.0238, 0.0282, 0.0355, 0.0459, 2147483647.0] 395 | } 396 | { 397 | name = g_add_r14d 398 | type = continuous 399 | values = [-2147483647.0, 0.0, 0.0087, 0.0127, 0.0157, 0.0185, 0.0213, 0.0238, 0.0267, 0.0318, 0.0385, 0.0488, 2147483647.0] 400 | } 401 | { 402 | name = g_l_t 403 | type = continuous 404 | values = [-2147483647.0, 2959.0, 3911.0, 4321.0, 4662.0, 5531.0, 5783.0, 6069.0, 6948.0, 7210.0, 7499.0, 8346.0, 8638.0, 8941.0, 9809.0, 10120.0, 10643.0, 11337.0, 11644.0, 12466.0, 2147483647.0] 405 | } 406 | { 407 | name = g_j_dis_h 408 | type = continuous 409 | values = [-2147483647.0, 1.5, 2.4, 3.2, 3.9, 4.6, 5.4, 6.3, 7.2, 8.2, 9.3, 10.6, 12.2, 14.1, 16.2, 19.1, 22.5, 27.4, 33.9, 42.7, 2147483647.0] 410 | } 411 | { 412 | name = g_j_dis_l 413 | type = continuous 414 | values = [-2147483647.0, 1.5, 2.3, 3.0, 3.8, 4.5, 5.3, 6.1, 6.9, 7.9, 9.0, 10.3, 11.9, 13.6, 15.8, 18.4, 21.7, 26.3, 32.9, 41.2, 2147483647.0] 415 | } 416 | { 417 | name = g_j_dis_m 418 | type = continuous 419 | values = [-2147483647.0, 1.5, 2.4, 3.2, 3.9, 4.6, 5.4, 6.2, 7.1, 8.1, 9.2, 10.6, 12.1, 13.8, 16.1, 18.7, 22.2, 26.9, 33.4, 42.0, 2147483647.0] 420 | } 421 | { 422 | name = g_j_age_dis_h 423 | type = continuous 424 | values = [-2147483647.0, 2.0, 4.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 15.0, 16.0, 17.0, 19.0, 20.0, 22.0, 24.0, 26.0, 30.0, 2147483647.0] 425 | } 426 | { 427 | name = g_j_age_dis_l 428 | type = continuous 429 | values = [-2147483647.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 16.0, 2147483647.0] 430 | } 431 | { 432 | name = g_j_age_dis_m 433 | type = continuous 434 | values = [-2147483647.0, -12.0, -10.083, -9.0, -7.899, -7.0, -6.13, -5.5, -4.833, -4.0, -3.5, -3.0, -2.444, -1.722, -1.0, -0.111, 0.666, 1.9, 3.5, 6.625, 2147483647.0] 435 | } 436 | { 437 | name = g_j_deg_dis_h 438 | type = continuous 439 | values = [-2147483647.0, 4.9E-324, 1.0, 2.0, 3.0, 4.0, 5.0, 2147483647.0] 440 | } 441 | { 442 | name = g_j_deg_dis_l 443 | type = continuous 444 | values = [-2147483647.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, 0.0, 1.0, 2.0, 3.0, 4.0, 2147483647.0] 445 | } 446 | { 447 | name = g_j_deg_dis_m 448 | type = continuous 449 | values = [-2147483647.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.444, -1.666, -1.0, 0.0, 1.0, 1.4, 2.333, 3.0, 4.0, 2147483647.0] 450 | } 451 | { 452 | name = g_j_m_ages 453 | type = discrete 454 | values = ["1.0:0.0", "3.0:1.0", "2.0:2.0", "4.0:3.0", "0.0:4.0", "5.0:5.0", "6.0:6.0", "7.0:7.0", "10.0:8.0", "8.0:9.0", "9.0:10.0", "23.0:11.0", "18.0:12.0", "21.0:13.0", "15.0:14.0", "16.0:15.0", "11.0:16.0", "17.0:17.0", "20.0:18.0", "13.0:19.0", "19.0:20.0", "22.0:21.0", "35.0:22.0", "14.0:23.0", "12.0:24.0", "32.0:25.0", "24.0:26.0", "33.0:27.0", "34.0:28.0", "28.0:29.0", "30.0:30.0", "25.0:31.0", "27.0:32.0", "43.0:33.0", "29.0:34.0", "26.0:35.0", "31.0:36.0", "37.0:37.0", "40.0:38.0"] 455 | } 456 | { 457 | name = g_j_m_sals 458 | type = discrete 459 | values = ["0.0:0.0", "1.0:1.0", "2.0:2.0", "3.0:3.0", "4.0:4.0", "5.0:5.0", "6.0:6.0", "7.0:7.0", "10.0:8.0", "8.0:9.0", "9.0:10.0", "23.0:11.0", "15.0:12.0", "18.0:13.0", "16.0:14.0", "21.0:15.0", "13.0:16.0", "14.0:17.0", "11.0:18.0", "17.0:19.0", "19.0:20.0", "12.0:21.0", "22.0:22.0", "20.0:23.0", "32.0:24.0", "35.0:25.0", "24.0:26.0", "33.0:27.0", "30.0:28.0", "31.0:29.0", "25.0:30.0", "29.0:31.0", "34.0:32.0", "28.0:33.0", "26.0:34.0", "27.0:35.0", "43.0:36.0", "37.0:37.0"] 460 | } 461 | { 462 | name = g_j_p_num 463 | type = discrete 464 | values = ["0.0:0.0", "1.0:1.0", "2.0:2.0", "3.0:3.0", "4.0:4.0", "5.0:5.0", "6.0:6.0", "7.0:7.0", "10.0:8.0", "8.0:9.0", "9.0:10.0", "11.0:11.0", "12.0:12.0", "15.0:13.0", "16.0:14.0", "14.0:15.0", "13.0:16.0", "17.0:17.0", "20.0:18.0", "19.0:19.0", "18.0:20.0", "24.0:21.0", "21.0:22.0", "23.0:23.0", "25.0:24.0", "29.0:25.0", "27.0:26.0", "22.0:27.0"] 465 | } 466 | { 467 | name = g_b_j_sim 468 | type = continuous 469 | values = [-2147483647.0, 0.0, 0.07, 0.116, 0.146, 0.185, 0.222, 0.266, 0.311, 0.358, 0.41, 0.48, 0.53, 0.589, 0.66, 0.728, 0.865, 1.34, 2147483647.0] 470 | } 471 | { 472 | name = is_read 473 | type = discrete 474 | values = ["0.0:0.0", "1.0:1.0"] 475 | } 476 | { 477 | name = r_hour 478 | type = discrete 479 | values = ["10.0:0.0", "9.0:1.0", "11.0:2.0", "3.0:3.0", "4.0:4.0", "2.0:5.0", "1.0:6.0", "8.0:7.0", "5.0:8.0", "0.0:9.0", "7.0:10.0", "6.0:11.0"] 480 | } 481 | { 482 | name = r_week 483 | type = discrete 484 | values = ["3.0:0.0", "2.0:1.0", "1.0:2.0", "7.0:3.0", "4.0:4.0", "6.0:5.0", "5.0:6.0"] 485 | } 486 | ] 487 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/Test.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy 2 | 3 | object Test { 4 | def main(args: Array[String]): Unit = { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/feature/FeatureDiscretizer.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.feature 2 | 3 | import org.apache.spark.SparkConf 4 | import org.apache.spark.ml.feature.{QuantileDiscretizer, StringIndexer} 5 | import org.apache.spark.sql.SparkSession 6 | import org.apache.spark.storage.StorageLevel 7 | import org.jeemy.utils.SchemaParser 8 | 9 | /** 10 | * @User: zhanghuayan 11 | * @Date: 2020/4/30 7:06 下午 12 | * @DESC: 特征离散化功能类 13 | */ 14 | object FeatureDiscretizer { 15 | val spark = SparkSession.builder().config(new SparkConf()).enableHiveSupport().getOrCreate() 16 | 17 | def main(args: Array[String]): Unit = { 18 | // 参数初始化 19 | val featureConf = args(0) 20 | val dataPath = args(1) 21 | val SPLIT_BIN_NUM = args(2).toInt 22 | 23 | println("\n\n" + featureConf) 24 | println(dataPath + "\n\n") 25 | 26 | // 读取特征Schema 27 | val schema = SchemaParser.readSchema(featureConf) 28 | 29 | var inputCols = SchemaParser.getContinuousFeatures(featureConf) 30 | var outputCols = SchemaParser.getOutputCols(inputCols) 31 | 32 | println(inputCols.mkString("[", ",", "]")) 33 | println(outputCols.mkString("[", ",", "]")) 34 | 35 | // 读取原始数据 36 | val dataDF = spark.read.schema(schema).csv(dataPath) 37 | .drop("deal_type", "lid", "rank") 38 | .persist(StorageLevel.MEMORY_AND_DISK) 39 | 40 | /** ************************** 连续特征处理 *******************************/ 41 | 42 | // 计算特征分位数 43 | val discretizer = new QuantileDiscretizer() 44 | .setInputCols(inputCols) 45 | .setOutputCols(outputCols) 46 | .setNumBuckets(SPLIT_BIN_NUM) 47 | .setHandleInvalid("skip") 48 | val model = discretizer.fit(dataDF) 49 | val splitsArray = model.getSplitsArray 50 | 51 | // 输出分桶数组 52 | println("\n\n") 53 | for (i <- 0 until splitsArray.length) { 54 | val splits = splitsArray(i) 55 | println(inputCols(i) + ":\n\t\t" + splits.mkString("[", ",", "]") + "\n") 56 | } 57 | 58 | /** ************************** 离散特征处理 *******************************/ 59 | println("\n\n") 60 | inputCols = SchemaParser.getDiscreteFeatures(featureConf) 61 | outputCols = SchemaParser.getOutputCols(inputCols) 62 | for (i <- 0 until inputCols.length) { 63 | val indexer = new StringIndexer() 64 | .setInputCol(inputCols(i)) 65 | .setOutputCol(outputCols(i)) 66 | .setHandleInvalid("skip") 67 | .fit(dataDF) 68 | 69 | val indexed = indexer.transform(dataDF) 70 | .select(inputCols(i), outputCols(i)) 71 | .orderBy(outputCols(i)) 72 | .distinct() 73 | 74 | // 输出离散值映射map 75 | val ansMap = indexed.take(10000).map { 76 | row => 77 | val srcVal = row.getDouble(0) 78 | val dstVal = row.getDouble(1) 79 | srcVal + ":" + dstVal 80 | }.mkString("[", ",", "]") 81 | println(inputCols(i) + ":\n\t\t" + ansMap + "\n") 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/models/BaseModel.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.models 2 | 3 | import org.apache.spark.sql.{DataFrame, SparkSession} 4 | import org.jeemy.utils.SchemaParser 5 | 6 | /** 7 | * @User: zhanghuayan 8 | * @Date: 2020/4/29 5:06 下午 9 | * @DESC: 封装所有模型的公共基础接口 10 | */ 11 | trait BaseModel { 12 | /** 13 | * spark对象初始化 14 | */ 15 | val spark = SparkSession.builder().enableHiveSupport().getOrCreate() 16 | 17 | /** 18 | * 预测函数接口 19 | */ 20 | def predict(feature: Array[Double]): Double 21 | 22 | /** 23 | * 训练函数接口 24 | */ 25 | def fit(trainData: DataFrame): BaseModel 26 | 27 | /** 28 | * 模型保存 29 | */ 30 | def saveModel(): Unit 31 | 32 | /** 33 | * 模型加载 34 | */ 35 | def loadModel(modelPath: String): BaseModel 36 | 37 | /** 38 | * 从HDFS路径读取数据 39 | */ 40 | def readData(path: String, featureConf: String): DataFrame = { 41 | // 读取数据schema 42 | val schema = SchemaParser.readSchema(featureConf) 43 | // 读取HDFS数据为指定schema 44 | val dataDF: DataFrame = spark.read.schema(schema).csv(path) 45 | dataDF 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/models/FM.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.models 2 | 3 | import org.apache.spark.sql.DataFrame 4 | 5 | /** 6 | * @User: zhanghuayan 7 | * @Date: 2020/4/29 5:06 下午 8 | * @DESC: Spark FM CTR预测模型实现 9 | */ 10 | class FM extends BaseModel { 11 | /** 12 | * 预测函数接口 13 | */ 14 | def predict(feature: Array[Double]): Double = { 15 | val score = 0.0 16 | // TODO 17 | score 18 | } 19 | 20 | /** 21 | * 训练函数接口 22 | */ 23 | def fit(trainData: DataFrame): BaseModel = { 24 | val fm: FM = null 25 | // TODO 26 | fm 27 | } 28 | 29 | /** 30 | * 模型保存 31 | */ 32 | def saveModel(): Unit = { 33 | // TODO 34 | } 35 | 36 | /** 37 | * 模型加载 38 | */ 39 | def loadModel(modelPath: String): BaseModel = { 40 | val fm: FM = null; 41 | // TODO 42 | fm 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/models/LR.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.models 2 | 3 | import org.apache.spark.ml.classification.LogisticRegression 4 | import org.apache.spark.sql.DataFrame 5 | 6 | import scala.collection.mutable.ArrayBuffer 7 | 8 | /** 9 | * @User: zhanghuayan 10 | * @Date: 2020/4/29 5:45 下午 11 | * @DESC: Spark LR CTR预测模型实现 12 | */ 13 | class LR extends BaseModel { 14 | /** 15 | * LR weights参数,第1位存储Bias 16 | */ 17 | private var weights: Array[Double] = null 18 | 19 | /** 20 | * 构造函数 21 | */ 22 | def this(weights: Array[Double]) { 23 | this() 24 | this.weights = weights 25 | } 26 | 27 | /** 28 | * 预测函数接口 29 | */ 30 | def predict(feature: Array[Double]): Double = { 31 | // 异常检查,预测之前模型必须初始化 32 | try { 33 | if (weights == null) { 34 | throw new Exception("LR weights need be initialized before predict!") 35 | } 36 | } catch { 37 | case ex: Exception => 38 | ex.printStackTrace() 39 | return 0.0 40 | } 41 | 42 | // 计算预测分值并返回 43 | var score = weights(0) 44 | for (i <- 0 until feature.length) { 45 | score += feature(i) * weights(i + 1) 46 | } 47 | score = 1.0 / (1.0 + math.exp(-score)) 48 | score 49 | } 50 | 51 | /** 52 | * 训练函数接口 53 | */ 54 | def fit(trainData: DataFrame): BaseModel = { 55 | val lr = new LogisticRegression() 56 | .setMaxIter(10) 57 | .setRegParam(0.1) 58 | .setElasticNetParam(0.8) 59 | .setFeaturesCol("features") 60 | .setLabelCol("label") 61 | val lrModel = lr.fit(trainData) 62 | 63 | // 获取训练好的LR模型参数 64 | val weights = new ArrayBuffer[Double]() 65 | weights += lrModel.intercept 66 | weights ++= lrModel.coefficients.toArray 67 | 68 | // 返回LR模型 69 | new LR(weights.toArray) 70 | } 71 | 72 | /** 73 | * 模型保存 74 | */ 75 | def saveModel(): Unit = { 76 | // TODO 77 | } 78 | 79 | /** 80 | * 模型加载 81 | */ 82 | def loadModel(modelPath: String): BaseModel = { 83 | val lr: LR = null; 84 | // TODO 85 | lr 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/models/XGBoost.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.models 2 | 3 | import org.apache.spark.sql.DataFrame 4 | 5 | /** 6 | * @User: zhanghuayan 7 | * @Date: 2020/4/29 5:06 下午 8 | * @DESC: Spark XGBoost CTR预测模型实现 9 | */ 10 | class XGBoost extends BaseModel { 11 | /** 12 | * 预测函数接口 13 | */ 14 | def predict(feature: Array[Double]): Double = { 15 | val score = 0.0 16 | // TODO 17 | score 18 | } 19 | 20 | /** 21 | * 训练函数接口 22 | */ 23 | def fit(trainData: DataFrame): BaseModel = { 24 | val xgboost: XGBoost = null 25 | // TODO 26 | xgboost 27 | } 28 | 29 | /** 30 | * 模型保存 31 | */ 32 | def saveModel(): Unit = { 33 | // TODO 34 | } 35 | 36 | /** 37 | * 模型加载 38 | */ 39 | def loadModel(modelPath: String): BaseModel = { 40 | val xgboost: XGBoost = null 41 | // TODO 42 | xgboost 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/models/XGBoostFM.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.models 2 | 3 | import org.apache.spark.sql.DataFrame 4 | 5 | /** 6 | * @User: zhanghuayan 7 | * @Date: 2020/4/29 5:27 下午 8 | * @DESC: Spark XGBoostFM CTR预测模型实现 9 | */ 10 | class XGBoostFM extends BaseModel { 11 | /** 12 | * 预测函数接口 13 | */ 14 | def predict(feature: Array[Double]): Double = { 15 | val score = 0.0 16 | // TODO 17 | score 18 | } 19 | 20 | /** 21 | * 训练函数接口 22 | */ 23 | def fit(trainData: DataFrame): BaseModel = { 24 | val xgbFm: XGBoostFM = null 25 | // TODO 26 | xgbFm 27 | } 28 | 29 | /** 30 | * 模型保存 31 | */ 32 | def saveModel(): Unit = { 33 | // TODO 34 | } 35 | 36 | /** 37 | * 模型加载 38 | */ 39 | def loadModel(modelPath: String): BaseModel = { 40 | val xgbFm: XGBoostFM = null 41 | // TODO 42 | xgbFm 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/models/XGBoostLR.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.models 2 | 3 | import ml.dmlc.xgboost4j.scala.spark.XGBoostClassificationModel 4 | import org.apache.spark.ml.classification.LogisticRegressionModel 5 | import org.apache.spark.sql.DataFrame 6 | 7 | /** 8 | * @User: zhanghuayan 9 | * @Date: 2020/4/29 5:06 下午 10 | * @DESC: Spark XGBoostLR CTR预测模型实现 11 | */ 12 | class XGBoostLR extends BaseModel { 13 | val xgbModel: XGBoostClassificationModel = null 14 | val lrModel: LogisticRegressionModel = null 15 | 16 | /** 17 | * 预测函数接口 18 | */ 19 | def predict(feature: Array[Double]): Double = { 20 | val score = 0.0 21 | // TODO 22 | score 23 | } 24 | 25 | /** 26 | * 训练函数接口 27 | */ 28 | def fit(trainData: DataFrame): BaseModel = { 29 | val xgbLr: XGBoostLR = null 30 | 31 | xgbLr 32 | } 33 | 34 | /** 35 | * 模型保存 36 | */ 37 | def saveModel(): Unit = { 38 | // TODO 39 | } 40 | 41 | /** 42 | * 模型加载 43 | */ 44 | def loadModel(modelPath: String): BaseModel = { 45 | val xgbLr: XGBoostLR = null 46 | // TODO 47 | xgbLr 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/scala/org/jeemy/utils/SchemaParser.scala: -------------------------------------------------------------------------------- 1 | package org.jeemy.utils 2 | 3 | import org.apache.spark.sql.types._ 4 | 5 | /** 6 | * @User: zhanghuayan 7 | * @Date: 2020/4/30 6:18 下午 8 | * @DESC: 根据特征配置文件解析训练数据的Schema 9 | */ 10 | object SchemaParser { 11 | val SCHEMA_PARTS = 3 12 | 13 | /** 14 | * 读取训练数据的特征Schema(FeatureName, DataType, FeatureType) 15 | */ 16 | def readSchema(featureConf: String): StructType = { 17 | val structArray = scala.io.Source.fromFile(featureConf).getLines().toArray.filter { 18 | line => line.trim.length > 0 && !line.trim.charAt(0).equals('#') 19 | }.map { 20 | line => line.split(",") 21 | }.filter { 22 | parts => parts.length == SCHEMA_PARTS 23 | }.map { 24 | parts => 25 | val featName = parts(0).trim 26 | val dataType = parts(1).trim 27 | val featType = parts(2).trim 28 | (featName, dataType, featType) 29 | }.map { 30 | case (featName, dataType, featType) => 31 | dataType match { 32 | case "double" => StructField(featName, DoubleType, true) 33 | case "string" => StructField(featName, StringType, true) 34 | case "int" => StructField(featName, IntegerType, true) 35 | case _ => StructField(featName, StringType, true) 36 | } 37 | } 38 | 39 | val schema = new StructType(structArray) 40 | schema 41 | } 42 | 43 | /** 44 | * 获取所有列名 45 | */ 46 | def getFeatures(featureConf: String): Array[String] = { 47 | val features = scala.io.Source.fromFile(featureConf).getLines().toArray.filter { 48 | line => line.trim.length > 0 && !line.trim.charAt(0).equals('#') 49 | }.map { 50 | line => line.split(",").map(x => x.trim) 51 | }.filter { 52 | parts => parts.length == SCHEMA_PARTS 53 | }.map { 54 | parts => 55 | val featName = parts(0).trim 56 | featName 57 | } 58 | 59 | features 60 | } 61 | 62 | /** 63 | * 获取连续特征列 64 | */ 65 | def getDiscreteFeatures(featureConf: String): Array[String] = { 66 | scala.io.Source.fromFile(featureConf).getLines().toArray.filter { 67 | line => line.trim.length > 0 && !line.trim.charAt(0).equals('#') 68 | }.map { 69 | line => line.split(",").map(x => x.trim) 70 | }.filter { 71 | parts => parts.length == SCHEMA_PARTS && parts(2).equals("discrete") 72 | }.map { 73 | parts => 74 | val featName = parts(0).trim 75 | featName 76 | } 77 | } 78 | 79 | /** 80 | * 获取离散特征列 81 | */ 82 | def getContinuousFeatures(featureConf: String): Array[String] = { 83 | scala.io.Source.fromFile(featureConf).getLines().toArray.filter { 84 | line => line.trim.length > 0 && !line.trim.charAt(0).equals('#') 85 | }.map { 86 | line => line.split(",").map(x => x.trim) 87 | }.filter { 88 | parts => parts.length == SCHEMA_PARTS && parts(2).equals("continuous") 89 | }.map { 90 | parts => 91 | val featName = parts(0).trim 92 | featName 93 | } 94 | } 95 | 96 | /** 97 | * 获取输出列列名 98 | */ 99 | def getOutputCols(inputCols: Array[String]): Array[String] = { 100 | val outputCols = inputCols.map(col => col + "_out") 101 | outputCols 102 | } 103 | } 104 | --------------------------------------------------------------------------------