使用 JPMML 评估 SAS 生成的 PMML 文件时出现 FMTWIDTH 错误
FMTWIDTH error while using JPMML to evaluate a SAS produced PMML file
我有一个从 SAS Miner 生成的 PMML,我无法使用 JPMML 1.1.4 对其进行正确评估。 JPMML 1.1.4 表示它支持 PMML 4.2,而 PMML 表示它是 PMML 4.2 版。
下面函数中的 FMTWIDTH "SAS-EM-String-Normalize" PMML 语法是否正确?
知道为什么我不能使用 JPMML 评估这个函数吗?
我的 TransformationDictionary 中的函数看起来像,
<TransformationDictionary>
<DefineFunction name="SAS-EM-String-Normalize" optype="categorical" dataType="string">
<ParameterField name="FMTWIDTH" optype="continuous"/>
<ParameterField name="AnyCInput" optype="categorical"/>
<Apply function="trimBlanks">
<Apply function="uppercase">
<Apply function="substring">
<FieldRef field="AnyCInput"/>
<Constant>1</Constant>
<Constant>FMTWIDTH</Constant>
</Apply>
</Apply>
</Apply>
</DefineFunction>
</TransformationDictionary>
我得到以下异常,
Exception in thread "main" org.jpmml.evaluator.TypeCheckException:
Expected INTEGER, but got STRING (FMTWIDTH) at
org.jpmml.evaluator.FieldValue.asInteger(FieldValue.java:125) at
org.jpmml.evaluator.FunctionRegistry.evaluate(FunctionRegistry.java:463)
at org.jpmml.evaluator.FunctionUtil.evaluate(FunctionUtil.java:38)
at
org.jpmml.evaluator.ExpressionUtil.evaluateApply(ExpressionUtil.java:203)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:91)
at org.jpmml.evaluator.FunctionUtil.evaluate(FunctionUtil.java:76)
at org.jpmml.evaluator.FunctionUtil.evaluate(FunctionUtil.java:43)
at
org.jpmml.evaluator.ExpressionUtil.evaluateApply(ExpressionUtil.java:203)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:91)
at
org.jpmml.evaluator.ExpressionUtil.evaluateApply(ExpressionUtil.java:188)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:91)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:58)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:45)
at
org.jpmml.evaluator.ExpressionUtil.evaluateMapValues(ExpressionUtil.java:169)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:87)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:58)
at
org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:45)
at
org.jpmml.evaluator.RegressionModelEvaluator.evaluateRegressionTable(RegressionModelEvaluator.java:150)
at
org.jpmml.evaluator.RegressionModelEvaluator.evaluateClassification(RegressionModelEvaluator.java:107)
at
org.jpmml.evaluator.RegressionModelEvaluator.evaluate(RegressionModelEvaluator.java:57)
at
org.jpmml.evaluator.ModelEvaluator.evaluate(ModelEvaluator.java:65)
at
ValidPMMLTesterRandomScores.randomEvaluation(ValidPMMLTesterRandomScores.java:116)
at
ValidPMMLTesterRandomScores.printModelInformation(ValidPMMLTesterRandomScores.java:94)
at
ValidPMMLTesterRandomScores.readModelFromFile(ValidPMMLTesterRandomScores.java:142)
at
ValidPMMLTesterRandomScores.main(ValidPMMLTesterRandomScores.java:160)
根据formal definition of the PMML built-in function "substring",它需要一个字符串参数和两个整数参数。 SAS EM 生成的 PMML 代码尝试使用字符串参数、整数参数和另一个字符串参数 substring($AnyCInput, 1, "FMTWIDTH")
.
调用此函数
可以通过使用 FieldRef
元素访问 "FMTWIDTH" 参数的值来修复此 PMML 片段:
<Apply function="substring">
<FieldRef field="AnyCInput"/>
<Constant>1</Constant>
<FieldRef field="FMTWIDTH"/>
</Apply>
总之,JPMML 正确,SAS EM 错误。
可以通过重新排列 PMML class 模型对象即时更正无效的 PMML 文档。 JPMML-Model library 的访客 API 正是为此目的而设计的:
PMML pmml = loadSasEmPMML()
Visitor invalidSubstringCorrector = new AbstractVisitor(){
@Override
public VisitorAction visit(Apply apply){
if(isInvalidSubstring(apply)){
List<Expression> expressions = apply.getExpressions();
expressions.set(2, new FieldRef(new FieldName("FMTWIDTH")));
}
return super.visit(apply);
}
private boolean isInvalidSubstring(Apply apply){
if(("substring").equals(apply.getFunction())){
List<Expression> expressions = apply.getExpressions();
Expression lengthArgument = expressions.get(2);
if(lengthArgument instanceof Constant){
Constant constant = (Constant)lengthArgument;
return ("FMTWIDTH").equals(constant.getValue());
}
}
return false;
}
};
invalidSubstringCorrector.applyTo(pmml);
目前,方法 isInvalidSubstring(Apply)
通过仅检查第三个表达式元素是否为字符串常量 "FMTWIDTH" 来识别有问题的 Apply 元素。如果需要额外确定,那么也可以添加关于第一个和第二个表达式元素的正确断言。
我有一个从 SAS Miner 生成的 PMML,我无法使用 JPMML 1.1.4 对其进行正确评估。 JPMML 1.1.4 表示它支持 PMML 4.2,而 PMML 表示它是 PMML 4.2 版。
下面函数中的 FMTWIDTH "SAS-EM-String-Normalize" PMML 语法是否正确?
知道为什么我不能使用 JPMML 评估这个函数吗?
我的 TransformationDictionary 中的函数看起来像,
<TransformationDictionary>
<DefineFunction name="SAS-EM-String-Normalize" optype="categorical" dataType="string">
<ParameterField name="FMTWIDTH" optype="continuous"/>
<ParameterField name="AnyCInput" optype="categorical"/>
<Apply function="trimBlanks">
<Apply function="uppercase">
<Apply function="substring">
<FieldRef field="AnyCInput"/>
<Constant>1</Constant>
<Constant>FMTWIDTH</Constant>
</Apply>
</Apply>
</Apply>
</DefineFunction>
</TransformationDictionary>
我得到以下异常,
Exception in thread "main" org.jpmml.evaluator.TypeCheckException: Expected INTEGER, but got STRING (FMTWIDTH) at org.jpmml.evaluator.FieldValue.asInteger(FieldValue.java:125) at org.jpmml.evaluator.FunctionRegistry.evaluate(FunctionRegistry.java:463) at org.jpmml.evaluator.FunctionUtil.evaluate(FunctionUtil.java:38) at org.jpmml.evaluator.ExpressionUtil.evaluateApply(ExpressionUtil.java:203) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:91) at org.jpmml.evaluator.FunctionUtil.evaluate(FunctionUtil.java:76) at org.jpmml.evaluator.FunctionUtil.evaluate(FunctionUtil.java:43) at org.jpmml.evaluator.ExpressionUtil.evaluateApply(ExpressionUtil.java:203) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:91) at org.jpmml.evaluator.ExpressionUtil.evaluateApply(ExpressionUtil.java:188) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:91) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:58) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:45) at org.jpmml.evaluator.ExpressionUtil.evaluateMapValues(ExpressionUtil.java:169) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:87) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:58) at org.jpmml.evaluator.ExpressionUtil.evaluate(ExpressionUtil.java:45) at org.jpmml.evaluator.RegressionModelEvaluator.evaluateRegressionTable(RegressionModelEvaluator.java:150) at org.jpmml.evaluator.RegressionModelEvaluator.evaluateClassification(RegressionModelEvaluator.java:107) at org.jpmml.evaluator.RegressionModelEvaluator.evaluate(RegressionModelEvaluator.java:57) at org.jpmml.evaluator.ModelEvaluator.evaluate(ModelEvaluator.java:65) at ValidPMMLTesterRandomScores.randomEvaluation(ValidPMMLTesterRandomScores.java:116) at ValidPMMLTesterRandomScores.printModelInformation(ValidPMMLTesterRandomScores.java:94) at ValidPMMLTesterRandomScores.readModelFromFile(ValidPMMLTesterRandomScores.java:142) at ValidPMMLTesterRandomScores.main(ValidPMMLTesterRandomScores.java:160)
根据formal definition of the PMML built-in function "substring",它需要一个字符串参数和两个整数参数。 SAS EM 生成的 PMML 代码尝试使用字符串参数、整数参数和另一个字符串参数 substring($AnyCInput, 1, "FMTWIDTH")
.
可以通过使用 FieldRef
元素访问 "FMTWIDTH" 参数的值来修复此 PMML 片段:
<Apply function="substring">
<FieldRef field="AnyCInput"/>
<Constant>1</Constant>
<FieldRef field="FMTWIDTH"/>
</Apply>
总之,JPMML 正确,SAS EM 错误。
可以通过重新排列 PMML class 模型对象即时更正无效的 PMML 文档。 JPMML-Model library 的访客 API 正是为此目的而设计的:
PMML pmml = loadSasEmPMML()
Visitor invalidSubstringCorrector = new AbstractVisitor(){
@Override
public VisitorAction visit(Apply apply){
if(isInvalidSubstring(apply)){
List<Expression> expressions = apply.getExpressions();
expressions.set(2, new FieldRef(new FieldName("FMTWIDTH")));
}
return super.visit(apply);
}
private boolean isInvalidSubstring(Apply apply){
if(("substring").equals(apply.getFunction())){
List<Expression> expressions = apply.getExpressions();
Expression lengthArgument = expressions.get(2);
if(lengthArgument instanceof Constant){
Constant constant = (Constant)lengthArgument;
return ("FMTWIDTH").equals(constant.getValue());
}
}
return false;
}
};
invalidSubstringCorrector.applyTo(pmml);
目前,方法 isInvalidSubstring(Apply)
通过仅检查第三个表达式元素是否为字符串常量 "FMTWIDTH" 来识别有问题的 Apply 元素。如果需要额外确定,那么也可以添加关于第一个和第二个表达式元素的正确断言。