Using The findAll() Function

Most SPSS Modeler scripts include code that locates an existing node e.g.:

stream = modeler.script.stream()
typenode = stream.findByType("type", None)

However, some scripts need to search for all nodes – maybe by node type but also matching some other criteria. The Modeler scripting API documentation (PDF) mentions a findAll() function:

d.findAll(filter, recursive): Collection
filter (NodeFilter) : the node filter
recursive (boolean) : if True then composite nodes should be recursively searched

Returns a collection of all nodes accepted by the specified filter. If the recursive flag is True then any SuperNodes within this diagram are also searched.

Unfortunately, the NodeFilter definition is not specified. NodeFilter is a base class defined in the modeler.api module that requires a single function definition called accept(). The accept() function takes the node to be checked and returns a Boolean that specifies whether the node should be included in the collection of nodes returned by findAll(). Node filters can be created by defining classes that extend the NodeFilter class and implement the accept() function.

A Simple Node Filter

A very basic node filter might look like:

import modeler.api

class AllNodeFilter(modeler.api.NodeFilter):
    """A node filter for all nodes."""

    def accept(this, node):
        return True

The script can create an instance of the filter and pass it to the findAll() function:

stream = modeler.script.stream()
allFilter = AllNodeFilter()
allnodes = stream.findAll(allFilter, True)

It’s not a very useful filter because it accepts every node passed to it. The next section will define a more useful filter.

A Node Type Filter

A more useful filter might look like:

class NodeTypeFilter(modeler.api.NodeFilter):
    """A node filter for a specific node type"""

    def __init__(this, typename):
        this._typename = typename
	
    def accept(this, node):
        return node.getTypeName() == this._typename

This filter can be passed a specific node type name and return True for any node with that type name. For example:

deriveFilter = NodeTypeFilter("derive")
derivenodes = stream.findAll(deriveFilter, True)

This will search the whole stream for derive nodes, including any that are in super nodes.

Filtering By Class

Sometimes a script will need to search for nodes with a general category rather than an explicit type. The following example is a node filter that finds all supernodes:

class SuperNodeFilter(modeler.api.NodeFilter):
    """A node filter for super nodes"""

    def accept(this, node):
        return isinstance(node, modeler.api.SuperNode)

This is slightly different from the previous node filter because it checks the class of the node rather than checking the type name.
Another example is a node filter that will find all model applier nodes, regardless of which specific algorithm they are built with:

class ModelApplierFilter(modeler.api.NodeFilter):
    """A node filter for ModelApplier nodes"""

    def accept(this, node):
        return isinstance(node, modeler.api.ModelApplier)

This can be used to find all model applier nodes however deeply nested they are within the stream:

modelfilter = ModelApplierFilter()
modelnodes = stream.findAll(modelfilter, True)

>>> print modelnodes
["Drug":applyc50[node@id4BPSX4ZKJ7C], "Drug":applyneuralnetwork[node@id84TT8IZPIJJ]]

Iterating Through The Results From findAll()

One thing to be aware of is that the value returned by findAll() is actually a set rather than a list. This means a script will need to iterate over the result. For example:

modelfilter = ModelApplierFilter()
models = stream.findAll(modelfilter, True)


# Either
for item in models:
    print item

# Or
items = models.iterator()
while items.hasNext():
    print items.next()


Output:
"Drug":applyc50[node@id4BPSX4ZKJ7C]
"Drug":applyneuralnetwork[node@id84TT8IZPIJJ]

Thanks to Suharto Anggono for suggested updates.

7 comments on"Searching For Nodes Using SPSS Modeler Scripting"

  1. Suharto Anggono May 10, 2017

    Instead of
    str(node.getProcessorType()) ,
    node.getTypeName()
    could also be used.

    Python-style iterating works, too.
    for item in model: print item

  2. Thank you for the explanation on using NodeFilters.

    A small suggestion to correct a typo: The comment for the class, ModelApplierFilter, should read
    “””A node filter for ModelApplier nodes”””

    to avoid any confusion.

    • JulianClinton February 26, 2019

      Hi Vasu, thanks for the comment – I’ve updated the description in the ModelApplierFilter.

  3. Is there a way I can isolate the Predictor Importance chart output from the Neural Net model nugget and have it output separately? Possibly using R script if needed?

    • JulianClinton April 08, 2019

      Hi Nipa, there isn’t a way of grabbing the Predictor Importance chart directly through scripting. However, you can access the underlying values in the neural network model using the following script fragment (I’ve checked this using SPSS Modeler 18.1.1):

      # Assumes there's only one neural network model in the stream...
      applyneuralnetwork_node = modeler.script.stream().findByType("applyneuralnetwork", None)
      pmmlContent = applyneuralnetwork_node.getContentModel("PMML")
      predictorImportance = pmmlContent.getValuesList("//MiningField[@importance]", ["name", "importance"], False)
      print predictorImportance
      # should show the something like the following in the script Debug tab:
      # [[Age, 0.141895985825845], [BP, 0.177722383402711], [Cholesterol, 0.0909105166299858], [Na_to_K, 0.551842481110767], [Sex, 0.0376286330306916]]

      Hope that helps.

Join The Discussion

Your email address will not be published. Required fields are marked *