Skip to content

Commit

Permalink
Added support for the 'lgb.Booster' model type. Fixes jpmml/r2pmml#75
Browse files Browse the repository at this point in the history
  • Loading branch information
vruusmann committed Jul 30, 2024
1 parent fa85aed commit 79139d3
Show file tree
Hide file tree
Showing 16 changed files with 1,313 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ Java library and command-line application for converting [R](https://www.r-proje
* `cv.glmnet` - Cross-validated GLMNet regression and calculation
* [`IsolationForest`](https://r-forge.r-project.org/R/?group_id=479) package:
* `iForest` - Isolation Forest (IF) anomaly detection
* [`lightgbm`](https://cran.r-project.org/package=lightgbm) package:
* `lgb.Booster` - LightGBM regression and classification.
* [`mlr`](https://cran.r-project.org/package=mlr) package:
* `WrappedModel` - Selected JPMML-R model types.
* [`neuralnet`](https://cran.r-project.org/package=neuralnet) package:
Expand Down
4 changes: 4 additions & 0 deletions pmml-rexp-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
<groupId>org.jpmml</groupId>
<artifactId>pmml-rexp</artifactId>
</dependency>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-rexp-lightgbm</artifactId>
</dependency>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-rexp-xgboost</artifactId>
Expand Down
48 changes: 48 additions & 0 deletions pmml-rexp-lightgbm/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.jpmml</groupId>
<artifactId>jpmml-r</artifactId>
<version>1.6-SNAPSHOT</version>
</parent>

<groupId>org.jpmml</groupId>
<artifactId>pmml-rexp-lightgbm</artifactId>
<packaging>jar</packaging>

<name>JPMML R LightGBM converter</name>
<description>JPMML R LightGBM to PMML converter</description>

<licenses>
<license>
<name>GNU Affero General Public License (AGPL) version 3.0</name>
<url>http://www.gnu.org/licenses/agpl-3.0.html</url>
<distribution>repo</distribution>
</license>
</licenses>

<dependencies>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-rexp</artifactId>
</dependency>

<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-evaluator-testing</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-lightgbm</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 Villu Ruusmann
*
* This file is part of JPMML-R
*
* JPMML-R is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JPMML-R is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with JPMML-R. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jpmml.rexp.lightgbm;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;

import org.dmg.pmml.PMML;
import org.jpmml.lightgbm.GBDT;
import org.jpmml.lightgbm.LightGBMUtil;
import org.jpmml.rexp.Converter;
import org.jpmml.rexp.REnvironment;
import org.jpmml.rexp.RExpEncoder;
import org.jpmml.rexp.RRaw;

public class LightGBMConverter extends Converter<REnvironment> {

public LightGBMConverter(REnvironment environment){
super(environment);
}

@Override
public PMML encodePMML(RExpEncoder encoder){
REnvironment environment = getObject();

RRaw raw = (RRaw)environment.findVariable("raw");
if(raw == null){
throw new IllegalArgumentException();
}

GBDT gbdt;

try(InputStream is = new ByteArrayInputStream(raw.getValue())){
gbdt = LightGBMUtil.loadGBDT(is);
} catch(IOException ioe){
throw new IllegalArgumentException(ioe);
}

return gbdt.encodePMML(Collections.emptyMap(), null, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lgb.Booster = org.jpmml.rexp.lightgbm.LightGBMConverter
51 changes: 51 additions & 0 deletions pmml-rexp-lightgbm/src/test/R/lightgbm.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
library("lightgbm")

source("util.R")

auto = loadAutoCsv("Auto")

auto_X = auto[, -ncol(auto)]
auto_y = auto[, ncol(auto)]

auto.matrix = as.matrix(auto_X)

auto.dset = lgb.Dataset(auto.matrix, label = auto_y)

generateLightGBMAuto = function(){
auto.lgbm = lgb.train(params = list(objective = "regression"), data = auto.dset, nrounds = 31)

mpg = predict(auto.lgbm, auto.matrix)

storeRds(auto.lgbm, "LightGBMAuto")
storeCsv(data.frame("_target" = mpg), "LightGBMAuto")
}

set.seed(42)

generateLightGBMAuto()

iris = loadIrisCsv("Iris")

iris_X = iris[, -ncol(iris)]
iris_y = iris[, ncol(iris)]

# Convert from factor to integer[0, num_class]
iris_y = (as.integer(iris_y) - 1)

iris.matrix = as.matrix(iris_X)

iris.dset = lgb.Dataset(iris.matrix, label = iris_y)

generateLightGBMIris = function(){
iris.lgbm = lgb.train(params = list(objective = "multiclass", num_class = 3, max_depth = 3), data = iris.dset, nrounds = 5)

probabilities = predict(iris.lgbm, iris.matrix)
species = max.col(probabilities) - 1

storeRds(iris.lgbm, "LightGBMIris")
storeCsv(data.frame("_target" = species, "probability(0)" = probabilities[, 1], "probability(1)" = probabilities[, 2], "probability(2)" = probabilities[, 3], check.names = FALSE), "LightGBMIris")
}

set.seed(42)

generateLightGBMIris()
1 change: 1 addition & 0 deletions pmml-rexp-lightgbm/src/test/R/util.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source("../../../../pmml-rexp/src/test/R/util.R")
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 Villu Ruusmann
*
* This file is part of JPMML-R
*
* JPMML-R is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JPMML-R is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with JPMML-R. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jpmml.rexp.lightgbm.testing;

import org.jpmml.converter.testing.Datasets;
import org.jpmml.rexp.testing.RExpEncoderBatchTest;
import org.junit.Test;

public class LightGBMConverterTest extends RExpEncoderBatchTest implements Datasets {

public LightGBMConverterTest(){
super();
}

@Test
public void evaluateAuto() throws Exception {
evaluate("LightGBM", AUTO);
}

@Test
public void evaluateIris() throws Exception {
evaluate("LightGBM", IRIS);
}
}
Loading

0 comments on commit 79139d3

Please sign in to comment.