Evaluate R-Expressions in Groovy (in Optimization)

When a partition is set up with R-access (you need to create a Support ticket for that), you can evaluate R code in a Pricefx logic.

As usual, you will need to write a Model Logic, and set up a Model to use that logic:

This sample logic is going to query PA data, and run a linear regression on it in R. To expose the regression as a Calculation Step in the Optimization module, we need to define the calculationStepsEntry. Here we define just one step: Regression.

This materialized in the Optimization UI as a tab in Step 2. We will not define any inputs to the model, and will have a look at the Results further down. Calculating the model (top-left Calculate button) results in the elements with Calculation Context = 'Calculation' to be executed. The results then show up in the Results pane on the right, but you will need to click the Refresh button in the top button bar first.

Now we can focus on the actual logic. We have defined a generic lm() function in the Lib element, acting as a gateway to the real lm() function in R. We are getting the PA data, and calling the lm() function, passing in the linear model formula and data, in the Regression element. The Fit element only serves to show the familiar output in R. Here is some sample code:

Lib
def lm(r, formula, factors, data) { script = """ summary <- summary(fit) coeffs <- summary\$coefficients[,1] stderrs <- summary\$coefficients[,2] pvalues <- summary\$coefficients[,4] r2 <- summary\$r.squared """ r.assign("data", data) if (factors) { factors.forEach{ name, values -> def levels = values.collect{ "\"$it\"" }.join(",") r.eval("data <- transform(data, $name = factor($name, levels = c($levels)))" as String) } } r.eval("fit <- lm($formula, data)" as String) r.eval(script) def rcoeffs = r.get("coeffs") def rparams = rcoeffs.getAttribute("names") // in the case that we only get an Intercept (i.e. avg of one of the regression params // (due to lack of variation in the data), then for some reason we are not getting // any names back. def params = rparams? rparams.asStrings() as List : ["(Intercept)"] def coeffs = rcoeffs.asDoubles() def stderrs = r.get("stderrs").asDoubles() def pvalues = r.get("pvalues").asDoubles() def r2 = r.get("r2").asDouble() api.logInfo("lm.result", r.print("summary")) api.logInfo("lm.params", params) api.logInfo("lm.coeffs", coeffs.toString()) api.logInfo("lm.stderrs", stderrs.toString()) api.logInfo("lm.pvalues", pvalues.toString()) api.logInfo("lm.R2", r2) return [ params: params, coeffs: coeffs, stderrs: stderrs, pvalues: pvalues, R2:r2 ] }
Regression
if (api.isSyntaxCheck()) return def r = model.getRContext() def dmCtx = api.getDatamartContext() def dm = dmCtx.getDatamart("Transaction DM") def query = dmCtx.newQuery(dm, false) query.select("brand_name", "brand") query.select("proprietary_brand_flag", "proprietary") query.select("footwear_order_flag", "footwear") query.select("hardgood_order_flag", "hardgood") query.select("margin_percent", "margin") def data = dmCtx.executeQuery(query)?.data r.assign("data", data) def result = Lib.lm(r, "margin ~ brand + proprietary + footwear + hardgood", null, data) def fit = r.print("fit") api.local.fit = fit return result

The Fit element then merely returns api.local.fit, resulting in the following (regression parameters, coefficients etc. are shown in expandable tree nodes):

Finally, a link to the tiny R-API:  https://developer.pricefx.eu/pricefx-api/groovy/master/net/pricefx/formulaengine/scripting/RContext.html

Found an issue in documentation? Write to us.