├── .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 extends ConfigObject> 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 extends ConfigObject> 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 |
--------------------------------------------------------------------------------