We would like to assume you would like to implement a learner that learns a certain model from the data and that you would subsequently like to have a predictor node that uses the learned model in order to classify new data. To accomplish this, you need a facility to pass the learned model from the learner to the predictor. The KNIME framework provides this functionality using the ModelPort concept. To roughly explain this concept we will now create the learned model for our numeric binner and write the interval bounds for every bin into a model. For this purpose it is necessary to overwrite the
The interval simply stores the lower bound upper bound pair. In addition the model provides some methods to add intervals and retrieve the intervals:
Now, we have to fill the model in the for-loop of the
Once the model has been filled with the information about the intervals it is possible to save it in the
Since we now provide an external model of our node we have to add a
Having adapted your constructor in this way you will notice the following error the next time you start your workbench:
saveModelContent
method of the NodeModel
. If we had a node with a ModelInport we would have to overwrite the loadModelContent
method in order to be able to load the model when it is connected to the inport. Although it is possible to write your model directly to the ModelContent
object it is good practice and highly recommended to have an object that represents the external model of your node and which is solely responsible for the loading from and saving to the ModelContent
. In our case we create a class NumericBinModel
. It is then very easy to share your model with other nodes. To increase the usability of the model we store the lower and upper bound as an interval for every bin. Since we only have a ModelOutport
we only have to implement the saveTo
method, as can be seen below:
/** * Saves this model to the model content * @param modelContent the model content to save to. */public void
saveTo(final
ModelContentWO modelContent) { modelContent.addInt(NUMBER_OF_BINS, m_intervals.size());int
intervalNr = 0;for
(Interval interval : m_intervals) { ModelContentWO intervalModel = modelContent.addModelContent( INTERVAL + intervalNr++); intervalModel.addDouble(LOWER_BOUND, interval.getLowerBound()); intervalModel.addDouble(UPPER_BOUND, interval.getUpperBound()); } }
/** * * @param binNumber the number of the bin for which the lower bound * should be returned * @return the lower bound of the specified interval. */public double
getLowerBoundForInterval(final int
binNumber) {return
m_intervals.get(binNumber).getLowerBound(); } /** * * @param binNumber the number of the bin for which the upper bound * should be returned * @return the upper bound of the specified interval. */public double
getUpperBoundForInterval(final int
binNumber) {return
m_intervals.get(binNumber).getUpperBound(); } /** * * @return the number of bins, i.e. intervals. */public int
getNumberOfBins() {return
m_intervals.size(); } /** * Adds an interval to this model. * @param lowerBound the lower bound of the interval * @param upperBound the upper bound of the interval */public void
addInterval(final double
lowerBound,final double
upperBound) { Interval interval =new
Interval(lowerBound, upperBound); m_intervals.add(interval); }
NodeModel
's execute
method:
...double
intervalUpperBound = lowerBound; // create the external model m_model =new
NumericBinModel();double
intervalLowerBound = lowerBound;for
(int
i = 0; i < m_numberOfBins.getIntValue(); i++) { intervalLowerBound = intervalUpperBound; intervalUpperBound += interval; // fill the external model m_model.addInterval(intervalLowerBound, intervalUpperBound); splitPoints.add(intervalUpperBound); // fill the bins with empty representations m_bins[i] =new
NumericBin(); } ...
saveModelContent
method of the NodeModel
:
/** * Only the saveModelContent method has to be overwritten, since there is * only a ModelOutport. * * @see de.unikn.knime.core.node.NodeModel#saveModelContent(int, * de.unikn.knime.core.node.ModelContentWO) */ @Overrideprotected void
saveModelContent(final int
index,final
ModelContentWO modelContent)throws
InvalidSettingsException { m_model.saveTo(modelContent); }
ModelOutport
. This is completed in the constructor of the NodeModel
, where the number of DataIn- and Outports is defined with the first two parameters and the number of ModelIn- and Outports with the last two parameters. Since we have no ModelInport and one ModelOutport the resulting new constructor looks like this:
/** * Constructor for the node model. */protected
NumericBinnerNodeModel() { // we have one inport for the numeric data to bin // and two outports: // one for the original data with the binning information appended // and one for the bins and their used interval bounds.super
(1, 1, 0, 1); }
ERROR NumericBinnerNodeFactory CODING PROBLEM Missing or surplus predictor output port nameTo avoid this you have to adapt your node description, which is explained in the next section.