- 什么是PMML
PMML 是一种事实标准语言,用于呈现数据挖掘模型。预测分析模型 和数据挖掘模型 是指代数学模型的术语,这些模型采用统计技术了解大量历史数据中隐藏的模式。预测分析模型采用定型过程中获取的知识来预测新数据中是否有已知模式。PMML 允许您在不同的应用程序之间轻松共享预测分析模型。因此,您可以在一个系统中定型一个模型,在 PMML 中对其进行表达,然后将其移动到另一个系统中,并在该系统中使用上述模型预测机器失效的可能性等。(来自互联网)
个人的理解:pmml文件的好处在于跨平台的使用,比如你用python训练好的模型想在Java平台上调用,pmml的形式就是很好的解决方案,且可以在线调用,运行速度也是可以的(比较大的模型没有尝试过)。pmml文档相当于把模型的离线状态和在线状态进行巧妙的连接,上图吧,比较清楚。
离线部分负责模型训练和导出模型,线上导入模型并且做预测。当然特征工程部分主要做特征变换
2. PMML文档如何生成
https://blog.csdn.net/sjtulgl/article/details/90913165可以参照此博客
3.需要准备的环境
3.1 IDEA(个人习惯)和JDK
关于IDEA和JDK的环境配置网上有各种教程
3.2 maven配置
关于为什么要用到maven,因为在Java在用PMML文档时要使用到很多的jar的包,自己下载很繁琐,通过maven添加依赖的方式很方便,你也可以通过互联网下载更新到本地仓库中。
4. 具体的过程
4.1 pmml文档长什么样
其实,就是一个xml格式的文档,这是利用python写的预测模型生成的pmml文档
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PMML xmlns="http://www.dmg.org/PMML-4_3" xmlns:data="http://jpmml.org/jpmml-model/InlineTable" version="4.3">
<Header>
<Application name="JPMML-SkLearn" version="1.5.19"/>
<Timestamp>2019-07-29T06:54:19Z</Timestamp>
</Header>
<DataDictionary>
<DataField name="x1" optype="continuous" dataType="double"/>
<DataField name="x2" optype="continuous" dataType="double"/>
<DataField name="x3" optype="continuous" dataType="double"/>
<DataField name="x4" optype="continuous" dataType="double"/>
<DataField name="x5" optype="continuous" dataType="double"/>
</DataDictionary>
<ClusteringModel functionName="clustering" modelClass="centerBased" numberOfClusters="5">
<MiningSchema>
<MiningField name="x1"/>
<MiningField name="x2"/>
<MiningField name="x3"/>
<MiningField name="x4"/>
<MiningField name="x5"/>
</MiningSchema>
<Output>
<OutputField name="Cluster" optype="categorical" dataType="string"/>
<OutputField name="affinity(0)" optype="continuous" dataType="double" feature="affinity" value="0"/>
<OutputField name="affinity(1)" optype="continuous" dataType="double" feature="affinity" value="1"/>
<OutputField name="affinity(2)" optype="continuous" dataType="double" feature="affinity" value="2"/>
<OutputField name="affinity(3)" optype="continuous" dataType="double" feature="affinity" value="3"/>
<OutputField name="affinity(4)" optype="continuous" dataType="double" feature="affinity" value="4"/>
</Output>
<ComparisonMeasure kind="distance">
<squaredEuclidean/>
</ComparisonMeasure>
<ClusteringField field="x1"/>
<ClusteringField field="x2"/>
<ClusteringField field="x3"/>
<ClusteringField field="x4"/>
<ClusteringField field="x5"/>
<Cluster id="0" size="26">
<Array type="real">39.67012174 162.57454692 101.34089982 68.47192959 66.88498207</Array>
</Cluster>
<Cluster id="1" size="15">
<Array type="real">52.728115 74.04934207 60.84869082 112.54995374 61.39071014</Array>
</Cluster>
<Cluster id="2" size="20">
<Array type="real">77.0520582 47.55334507 83.44254898 75.7063976 165.07051147</Array>
</Cluster>
<Cluster id="3" size="17">
<Array type="real">129.86987259 43.84990711 107.28876375 48.75162931 62.41432643</Array>
</Cluster>
<Cluster id="4" size="29">
<Array type="real">141.1866564 100.64500126 114.10774063 109.14582033 55.33371883</Array>
</Cluster>
</ClusteringModel>
</PMML>
通过pmml文档可知,输入为x1-x5,一个五维的向量,输出为0-4。数据类型均为double。
4.2 pom添加依赖
首先建立一个maven的项目,在IDEA中,file-new project-maven,每一个maven项目均有pom.xml文档,在pom.xml中添加依赖,此处以pmml-evaluator为例进行说明。
<dependencies>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-evaluator</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
<dependencies> </dependencies>中间是添加依赖的地方,要先在网上确定出version和artifactId,版本号不符合要求或者错误很影响下拉。
在添加完后可在Terminal中查看maven项目,如图。
在下拉本地成功后,会显示如上的效果。在此过程中,其实是有问题的,在添加后,Dependencies会出现红色的波浪线,提示依赖未找到,如果此时本地没有,则进行更新;如果本地存在,则需要把pom文件中的依赖删除,执行clean命令,然后再重新添加。
4.3 Java代码部分
配置完依赖后,在maven项目的Test下新建Java的包和类,然后进行Java的pmml调用。此处先把代码放上,便于理解。
import org.dmg.pmml.FieldName;
import org.dmg.pmml.PMML;
import org.jpmml.evaluator.*;
import org.jpmml.evaluator.Evaluator;
import org.jpmml.evaluator.InputField;
import org.jpmml.evaluator.ModelEvaluatorFactory;
import javax.xml.bind.JAXBException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class PmmlDemo<main> {
private Evaluator loadPmml()//加载pmml文件
{
PMML pmml = new PMML();
InputStream inputStream = null;
try
{
inputStream = new FileInputStream("F:\\pmmllearn\\src\\test\\Resources\\KM-MS.pmml");
}catch(IOException e)
{
e.printStackTrace();
}
if(inputStream == null){
return null;
}
InputStream is = inputStream;
try {
pmml = org.jpmml.model.PMMLUtil.unmarshal(is);}
catch(org.xml.sax.SAXException e1) {
e1.printStackTrace();
}
catch(javax.xml.bind.JAXBException e2) {
e2.printStackTrace();
}
finally {
//关闭输入流
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
ModelEvaluatorFactory modelEvaluatorFactory = ModelEvaluatorFactory.newInstance();
Evaluator evaluator = modelEvaluatorFactory.newModelEvaluator(pmml);
pmml=null;
return evaluator;
}
private void predict (Evaluator evaluator,double a, double b, double c, double d ,double e)throws Exception{//五维的特征输入
String real=null;//初始值为-1,不代表任何的状态
Map<String,Double> inputvector=new HashMap<String ,Double>();
inputvector.put("x1",a);
inputvector.put("x2",b);
inputvector.put("x3",c);
inputvector.put("x4",d);
inputvector.put("x5",e);//数据的输入,适用于单维数据的测试
List<InputField> inputFields = evaluator.getInputFields();
Map<FieldName, FieldValue> arguments = new LinkedHashMap<FieldName, FieldValue>();
for (InputField inputField : inputFields) {
FieldName inputFieldName = inputField.getName();
Object rawValue = inputvector.get(inputFieldName.getValue());
FieldValue inputFieldValue = inputField.prepare(rawValue);
arguments.put(inputFieldName, inputFieldValue);
}//5维数据完成读入
Map<FieldName, ?> results = evaluator.evaluate(arguments);
List<OutputField> outputFields = evaluator.getOutputFields();
for (OutputField outputField : outputFields) {
FieldName outputFieldName = outputField.getName();
Object outputFieldValue = results.get(outputFieldName);
System.out.println("target: " + outputFieldName.getValue() + " value: " + outputFieldValue);
if(outputFieldName.getValue().equals("Cluster")){
real=(String)outputFieldValue;
}
}
int result=Integer.parseInt(real);
System.out.println(a + " " + b + " " + c + " " + d +" "+ e+" "+"健康状态等级"+":" +(result+1));
/* OutputField outputField = outputFields.get(1);
FieldName outputFieldName = outputField.getName();
Object targetFieldValue = results.get(outputFieldName);
System.out.println("target: " + outputFieldName.getValue() + " value: " + targetFieldValue);
if (targetFieldValue instanceof Computable) {
Computable computable = (Computable) targetFieldValue;
real = (Integer)computable.getResult();
}
System.out.println(a + " " + b + " " + c + " " + d +" "+ e+":" + real);
// return real;*/
}
public static void main(String [] args)throws Exception
{
PmmlDemo pd=new PmmlDemo();
Evaluator ev=pd.loadPmml();
//数据测试
pd.predict(ev,11.22, 171.46, 72.03, 39.36, 56.37);//取出最小的结果最为最终的类别
pd.predict(ev,27.92, 130.25,113.69, 165.72, 25.66);
}
特别说明:
evaluator在图一中就出现过,它到底是什么,其实在读取完pmml文档后,pmml文档中的所有和模型有关的信息全部都存在了Evaluator类中,相当于把内容从硬盘读到了内存中,看一下具体有什么,理解了Evaluator也就明白了代码中map和list的作用。
4.4 结果显示
target: Cluster value: 0
target: affinity(0) value: 2705.5588441013183
target: affinity(1) value: 16718.75842296069
target: affinity(2) value: 32953.82710934807
target: affinity(3) value: 31730.045077284823
target: affinity(4) value: 28547.766676661755
11.22 171.46 72.03 39.36 56.37 健康状态等级:1
Process finished with exit code 0
4.5 感想
以上就是整个demo的过程,刚一入手比较困难,希望可以对大家有所帮助,有不对的地方还请留言指出。