These operators creates a connection that "pipes" data from the source g1
into the sink g2
.
Both source and sink can either be
a Graph
or a PipeOp
(or an object that can be automatically converted into a Graph
or PipeOp
, see as_graph()
and as_pipeop()
).
%>>%
and %>>!%
try to automatically match output channels of g1
to input channels of g2
; this is only possible if either
the number of output channels of
g1
(as given byg1$output
) is equal to the number of input channels ofg2
(as given byg2$input
), org1
has only one output channel (i.e.g1$output
has one line), org2
has only one input channel, which is a vararg channel (i.e.g2$input
has one line, withname
entry"..."
).
Connections between channels are created in the
order in which they occur in g1
and g2
, respectively: g1
's output channel 1 is connected to g2
's input
channel 1, channel 2 to 2 etc.
%>>%
always creates deep copies of its input arguments, so they cannot be modified by reference afterwards.
To access individual PipeOp
s after composition, use the resulting Graph
's $pipeops
list.
%>>!%
, on the other hand, tries to avoid cloning its first argument: If it is a Graph
, then this Graph
will be modified in-place.
When %>>!%
fails, then it leaves g1
in an incompletely modified state. It is therefore usually recommended to use
%>>%
, since the very marginal gain of performance from
using %>>!%
often does not outweigh the risk of either modifying objects by-reference that should not be modified or getting
graphs that are in an incompletely modified state. However,
when creating long Graph
s, chaining with %>>!%
instead of %>>%
can give noticeable performance benefits
because %>>%
makes a number of clone()
-calls that is quadratic in chain length, %>>!%
only linear.
concat_graphs(g1, g2, in_place = FALSE)
is equivalent to g1 %>>% g2
. concat_graphs(g1, g2, in_place = TRUE)
is equivalent to g1 %>>!% g2
.
Both arguments of %>>%
are automatically converted to Graph
s using as_graph()
; this means that objects on either side may be objects
that can be automatically converted to PipeOp
s (such as Learner
s or Filter
s), or that can
be converted to Graph
s. This means, in particular, list
s of Graph
s, PipeOp
s or objects convertible to that, because
as_graph()
automatically applies gunion()
to list
s. See examples. If the first argument of %>>!%
is not a Graph
, then
it is cloned just as when %>>%
is used; %>>!%
only avoids clone()
if the first argument is a Graph
.
Note that if g1
is NULL
, g2
converted to a Graph
will be returned.
Analogously, if g2
is NULL
, g1
converted to a Graph
will be returned.
Arguments
- g1
(
Graph
|PipeOp
|Learner
|Filter
|list
|...
)Graph
/PipeOp
/ object-convertible-to-PipeOp
to put in front ofg2
.- g2
(
Graph
|PipeOp
|Learner
|Filter
|list
|...
)Graph
/PipeOp
/ object-convertible-to-PipeOp
to put afterg1
.- in_place
(
logical(1)
)
Whether to try to avoid cloningg1
. Ifg1
is not aGraph
, then it is cloned regardless.
See also
Other Graph operators:
as_graph()
,
as_pipeop()
,
assert_graph()
,
assert_pipeop()
,
chain_graphs()
,
greplicate()
,
gunion()
,
mlr_graphs_greplicate
Examples
o1 = PipeOpScale$new()
o2 = PipeOpPCA$new()
o3 = PipeOpFeatureUnion$new(2)
# The following two are equivalent:
pipe1 = o1 %>>% o2
pipe2 = Graph$new()$
add_pipeop(o1)$
add_pipeop(o2)$
add_edge(o1$id, o2$id)
# Note automatical gunion() of lists.
# The following three are equivalent:
graph1 = list(o1, o2) %>>% o3
graph2 = gunion(list(o1, o2)) %>>% o3
graph3 = Graph$new()$
add_pipeop(o1)$
add_pipeop(o2)$
add_pipeop(o3)$
add_edge(o1$id, o3$id, dst_channel = 1)$
add_edge(o2$id, o3$id, dst_channel = 2)
pipe1 %>>!% o3 # modify pipe1 in-place
#> Graph with 3 PipeOps:
#> ID State sccssors prdcssors
#> <char> <char> <char> <char>
#> scale <<UNTRAINED>> pca
#> pca <<UNTRAINED>> featureunion scale
#> featureunion <<UNTRAINED>> pca
pipe1 # contains o1, o2, and o3 now.
#> Graph with 3 PipeOps:
#> ID State sccssors prdcssors
#> <char> <char> <char> <char>
#> scale <<UNTRAINED>> pca
#> pca <<UNTRAINED>> featureunion scale
#> featureunion <<UNTRAINED>> pca
o1 %>>!% o2
#> Graph with 2 PipeOps:
#> ID State sccssors prdcssors
#> <char> <char> <char> <char>
#> scale <<UNTRAINED>> pca
#> pca <<UNTRAINED>> scale
o1 # not changed, becuase not a Graph.
#> PipeOp: <scale> (not trained)
#> values: <robust=FALSE>
#> Input channels <name [train type, predict type]>:
#> input [Task,Task]
#> Output channels <name [train type, predict type]>:
#> output [Task,Task]