partykit/0000755000176200001440000000000014416215302012117 5ustar liggesuserspartykit/NAMESPACE0000644000176200001440000001170014402335717013345 0ustar liggesusers useDynLib(partykit, .registration = TRUE) import("stats") import("graphics") import("grid") import("Formula") import("libcoin") import("inum") import("mvtnorm") importFrom("survival", "survfit" ) importFrom("rpart", "prune" ) importFrom("grDevices", "gray.colors" ) importFrom("utils", "capture.output", "head", "tail", "setTxtProgressBar", "txtProgressBar" ) export( ## core infrastructure "party", "partynode", "partysplit", ## internal tree growing infrastructure "extree_data", "extree_fit", ## new ctree implementation "ctree", "ctree_control", "sctest.constparty", "varimp.constparty", ## new mob implementation "mob", "mob_control", "refit.modelparty", ## mobsters "lmtree", "glmtree", ## new cforest implementation "cforest", "predict.cforest", "varimp", "gettree", "varimp.cforest", "gettree.cforest", ## as/is class generics "as.party", "as.partynode", "as.constparty", "as.simpleparty", "is.constparty", "is.partynode", "is.simpleparty", ## new generics "is.terminal", "nodeapply", "nodeids", "width", "nodeprune", ## exported methods (to facilitate re-use) "plot.party", "predict.party", "print.party", "plot.modelparty", "predict.modelparty", "print.modelparty", "sctest.modelparty", "prune.modelparty", "prune.lmtree", "nodeprune.party", ## workhorse infrastructure "breaks_split", "character_split", "formatinfo_node", "data_party", "data_party.default", "edge_simple", "fitted_node", "id_node", "index_split", "info_node", "info_split", "kidids_node", "kidids_split", "kids_node", "predict_party", "predict_party.default", "prob_split", "right_split", "split_node", "surrogates_node", "varid_split", ## visualization tools "node_barplot", "node_bivplot", "node_boxplot", "node_surv", "node_ecdf", "node_mvar", "node_inner", "node_party", "node_terminal", ## coercion methods for (non-imported) external classes "as.party.Weka_tree", "as.party.rpart", "as.party.XMLNode", "as.simpleparty.XMLNode", ## misc infrastructure "pmmlTreeModel", "get_paths", "model_frame_rpart" ) ## methods for class party S3method("[", "party") S3method("[[", "party") S3method("as.simpleparty", "party") S3method("depth", "party") S3method("formula", "party") S3method("getCall", "party") S3method("getCall", "constparties") S3method("length", "party") S3method("model.frame", "party") S3method("names", "party") S3method("names<-", "party") S3method("nodeapply", "party") S3method("nodeids", "party") S3method("predict", "party") S3method("width", "party") S3method("nodeprune", "party") S3method("nodeprune", "partynode") S3method("nodeprune", "default") S3method("print", "party") S3method("plot", "party") S3method("data_party", "default") S3method("predict_party", "default") S3method("[[", "extree_data") S3method("model.frame", "extree_data") ## methods for class partynode S3method("[", "partynode") S3method("[[", "partynode") S3method("as.list", "partynode") S3method("as.partynode", "partynode") S3method("depth", "partynode") S3method("is.terminal", "partynode") S3method("length", "partynode") S3method("nodeapply", "partynode") S3method("nodeids", "partynode") S3method("print", "partynode") S3method("width", "partynode") ## methods for class constparty S3method("as.simpleparty", "constparty") S3method("plot", "constparty") S3method("predict_party", "constparty") S3method("print", "constparty") S3method("varimp", "constparty") ## methods for class simpleparty S3method("as.simpleparty", "simpleparty") S3method("plot", "simpleparty") S3method("predict_party", "simpleparty") S3method("print", "simpleparty") ## methods for class modelparty S3method("coef", "modelparty") S3method("deviance", "modelparty") S3method("fitted", "modelparty") S3method("formula", "modelparty") S3method("getCall", "modelparty") S3method("logLik", "modelparty") S3method("model.frame", "modelparty") S3method("nobs", "modelparty") S3method("residuals", "modelparty") S3method("summary", "modelparty") S3method("weights", "modelparty") S3method("predict", "modelparty") S3method("print", "modelparty") S3method("plot", "modelparty") S3method("prune", "modelparty") ## methods for class lmtree S3method("plot", "lmtree") S3method("predict", "lmtree") S3method("print", "lmtree") S3method("prune", "lmtree") ## methods for class glmtree S3method("plot", "glmtree") S3method("predict", "glmtree") S3method("print", "glmtree") ## methods for class cforest S3method("predict", "cforest") S3method("varimp", "cforest") S3method("gettree", "cforest") S3method("model.frame", "cforest") ## misc methods S3method("as.partynode", "list") S3method("as.party", "Weka_tree") S3method("as.party", "XMLNode") S3method("as.simpleparty", "XMLNode") S3method("as.party", "rpart") ## conditional registration of strucchange methods if(getRversion() >= "3.6.0") { S3method(strucchange::sctest, "constparty") S3method(strucchange::sctest, "modelparty") } partykit/demo/0000755000176200001440000000000014172227777013065 5ustar liggesuserspartykit/demo/memory-speed.R0000644000176200001440000000261414172227777015621 0ustar liggesusers### packages and data library("rpart") library("RWeka") library("partykit") data("Shuttle", package = "mlbench") ### fit rpart and J48 trees rp <- rpart(Class ~ ., data = Shuttle) j48 <- J48(Class ~ ., data = Shuttle) ### convert to party system.time(party_rp <- as.party(rp)) system.time(party_j48 <- as.party(j48)) ### check depth/width depth(party_rp) width(party_rp) depth(party_j48) width(party_j48) ### compare object sizes osize <- function(x) print(object.size(x), units = "Kb") osize(rp) ## rpart representation osize(party_rp) ## full party (with terms, fitted values) osize(node_party(party_rp)) ## only the raw partynode osize(j48) ## J48 tree in external Java pointer osize(party_j48) ## full party (with terms, fitted values) osize(node_party(party_j48)) ## only the raw partynode osize(Shuttle) ## learning data (not stored in any tree) ### set-up large prediction sample set.seed(1) nd <- Shuttle[sample(1:nrow(Shuttle), 1e6, replace = TRUE), ] ### compare predictions (speed and accuracy) system.time(p_rp <- predict(rp, newdata = nd, type = "prob")) system.time(p_party_rp <- predict(party_rp, newdata = nd, type = "prob")) all.equal(p_rp, p_party_rp) system.time(p_j48 <- predict(j48, newdata = nd)) system.time(p_party_j48 <- predict(party_j48, newdata = nd)) all.equal(p_j48, p_party_j48, check.attributes = FALSE) partykit/demo/00Index0000644000176200001440000000011714172227777014216 0ustar liggesusersmemory-speed Some memory and speed comparisons for rpart, J48, and constparty partykit/data/0000755000176200001440000000000014172230001013020 5ustar liggesuserspartykit/data/HuntingSpiders.rda0000644000176200001440000000111514172230001016454 0ustar liggesusersVM0@VU{oCeaHE?-mjx55Yז̢.Ovhzq:TMfC Eo< S5my1S't!ХA]ꗡ\Ŏ3uKYE![ۥ+v x/)?.< +&%K䠎21ڻ䕻qI_쵳,<>ud軅>!aHߘP$h7^Zn ގ9fi!,yG4tw)SmI4bV?2&g c*J B%So,' /}N=ֱQ}Rثm Ξ)&_ʪpartykit/man/0000755000176200001440000000000014415224762012703 5ustar liggesuserspartykit/man/mob.Rd0000644000176200001440000001715614172230000013737 0ustar liggesusers\name{mob} \alias{mob} \alias{modelparty} \alias{coef.modelparty} \alias{deviance.modelparty} \alias{fitted.modelparty} \alias{formula.modelparty} \alias{getCall.modelparty} \alias{logLik.modelparty} \alias{model.frame.modelparty} \alias{nobs.modelparty} \alias{plot.modelparty} \alias{predict.modelparty} \alias{print.modelparty} \alias{residuals.modelparty} \alias{summary.modelparty} \alias{weights.modelparty} \alias{refit.modelparty} \alias{sctest.modelparty} \title{Model-based Recursive Partitioning} \description{ MOB is an algorithm for model-based recursive partitioning yielding a tree with fitted models associated with each terminal node. } \usage{ mob(formula, data, subset, na.action, weights, offset, cluster, fit, control = mob_control(), \dots) } \arguments{ \item{formula}{symbolic description of the model (of type \code{y ~ z1 + \dots + zl} or \code{y ~ x1 + \dots + xk | z1 + \dots + zl}; for details see below).} \item{data, subset, na.action}{arguments controlling formula processing via \code{\link[stats]{model.frame}}.} \item{weights}{optional numeric vector of weights. By default these are treated as case weights but the default can be changed in \code{\link{mob_control}}.} \item{offset}{optional numeric vector with an a priori known component to be included in the model \code{y ~ x1 + \dots + xk} (i.e., only when \code{x} variables are specified).} \item{cluster}{optional vector (typically numeric or factor) with a cluster ID to be passed on to the \code{fit} function and employed for clustered covariances in the parameter stability tests.} \item{fit}{function. A function for fitting the model within each node. For details see below.} \item{control}{A list with control parameters as returned by \code{\link{mob_control}}.} \item{\dots}{Additional arguments passed to the \code{fit} function.} } \details{ Model-based partitioning fits a model tree using two groups of variables: (1) The model variables which can be just a (set of) response(s) \code{y} or additionally include regressors \code{x1}, \dots, \code{xk}. These are used for estimating the model parameters. (2) Partitioning variables \code{z1}, \dots, \code{zl}, which are used for recursively partitioning the data. The two groups of variables are either specified as \code{y ~ z1 + \dots + zl} (when there are no regressors) or \code{y ~ x1 + \dots + xk | z1 + \dots + zl} (when the model part contains regressors). Both sets of variables may in principle be overlapping. To fit a tree model the following algorithm is used. \enumerate{ \item \code{fit} a model to the \code{y} or \code{y} and \code{x} variables using the observations in the current node \item Assess the stability of the model parameters with respect to each of the partitioning variables \code{z1}, \dots, \code{zl}. If there is some overall instability, choose the variable \code{z} associated with the smallest \eqn{p} value for partitioning, otherwise stop. \item Search for the locally optimal split in \code{z} by minimizing the objective function of the model. Typically, this will be something like \code{\link{deviance}} or the negative \code{\link{logLik}}. \item Refit the \code{model} in both kid subsamples and repeat from step 2. } More details on the conceptual design of the algorithm can be found in Zeileis, Hothorn, Hornik (2008) and some illustrations are provided in \code{vignette("MOB")}. For specifying the \code{fit} function two approaches are possible: (1) It can be a function \code{fit(y, x = NULL, start = NULL, weights = NULL, offset = NULL, \dots)}. The arguments \code{y}, \code{x}, \code{weights}, \code{offset} will be set to the corresponding elements in the current node of the tree. Additionally, starting values will sometimes be supplied via \code{start}. Of course, the \code{fit} function can choose to ignore any arguments that are not applicable, e.g., if the are no regressors \code{x} in the model or if starting values or not supported. The returned object needs to have a class that has associated \code{\link[stats]{coef}}, \code{\link[stats]{logLik}}, and \code{\link[sandwich]{estfun}} methods for extracting the estimated parameters, the maximized log-likelihood, and the empirical estimating function (i.e., score or gradient contributions), respectively. (2) It can be a function \code{fit(y, x = NULL, start = NULL, weights = NULL, offset = NULL, \dots, estfun = FALSE, object = FALSE)}. The arguments have the same meaning as above but the returned object needs to have a different structure. It needs to be a list with elements \code{coefficients} (containing the estimated parameters), \code{objfun} (containing the minimized objective function), \code{estfun} (the empirical estimating functions), and \code{object} (the fitted model object). The elements \code{estfun}, or \code{object} should be \code{NULL} if the corresponding argument is set to \code{FALSE}. Internally, a function of type (2) is set up by \code{mob()} in case a function of type (1) is supplied. However, to save computation time, a function of type (2) may also be specified directly. For the fitted MOB tree, several standard methods are provided such as \code{print}, \code{predict}, \code{residuals}, \code{logLik}, \code{deviance}, \code{weights}, \code{coef} and \code{summary}. Some of these rely on reusing the corresponding methods for the individual model objects in the terminal nodes. Functions such as \code{coef}, \code{print}, \code{summary} also take a \code{node} argument that can specify the node IDs to be queried. Some examples are given below. More details can be found in \code{vignette("mob", package = "partykit")}. An overview of the connections to other functions in the package is provided by Hothorn and Zeileis (2015). } \value{ An object of class \code{modelparty} inheriting from \code{\link{party}}. The \code{info} element of the overall \code{party} and the individual \code{node}s contain various informations about the models. } \references{ Hothorn T, Zeileis A (2015). partykit: A Modular Toolkit for Recursive Partytioning in R. \emph{Journal of Machine Learning Research}, \bold{16}, 3905--3909. Zeileis A, Hothorn T, Hornik K (2008). Model-Based Recursive Partitioning. \emph{Journal of Computational and Graphical Statistics}, \bold{17}(2), 492--514. } \seealso{\code{\link{mob_control}}, \code{\link{lmtree}}, \code{\link{glmtree}}} \examples{ if(require("mlbench")) { ## Pima Indians diabetes data data("PimaIndiansDiabetes", package = "mlbench") ## a simple basic fitting function (of type 1) for a logistic regression logit <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { glm(y ~ 0 + x, family = binomial, start = start, ...) } ## set up a logistic regression tree pid_tree <- mob(diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age, data = PimaIndiansDiabetes, fit = logit) ## see lmtree() and glmtree() for interfaces with more efficient fitting functions ## print tree print(pid_tree) ## print information about (some) nodes print(pid_tree, node = 3:4) ## visualization plot(pid_tree) ## coefficients and summary coef(pid_tree) coef(pid_tree, node = 1) summary(pid_tree, node = 1) ## average deviance computed in different ways mean(residuals(pid_tree)^2) deviance(pid_tree)/sum(weights(pid_tree)) deviance(pid_tree)/nobs(pid_tree) ## log-likelihood and information criteria logLik(pid_tree) AIC(pid_tree) BIC(pid_tree) ## predicted nodes predict(pid_tree, newdata = head(PimaIndiansDiabetes, 6), type = "node") ## other types of predictions are possible using lmtree()/glmtree() } } \keyword{tree} partykit/man/partynode.Rd0000644000176200001440000001354114172230000015161 0ustar liggesusers\name{partynode} \alias{partynode} \alias{kidids_node} \alias{fitted_node} \alias{id_node} \alias{split_node} \alias{surrogates_node} \alias{kids_node} \alias{info_node} \alias{formatinfo_node} \title{ Inner and Terminal Nodes } \description{ A class for representing inner and terminal nodes in trees and functions for data partitioning. } \usage{ partynode(id, split = NULL, kids = NULL, surrogates = NULL, info = NULL) kidids_node(node, data, vmatch = 1:ncol(data), obs = NULL, perm = NULL) fitted_node(node, data, vmatch = 1:ncol(data), obs = 1:nrow(data), perm = NULL) id_node(node) split_node(node) surrogates_node(node) kids_node(node) info_node(node) formatinfo_node(node, FUN = NULL, default = "", prefix = NULL, \dots) } \arguments{ \item{id}{ integer, a unique identifier for a node. } \item{split}{ an object of class \code{\link{partysplit}}. } \item{kids}{ a list of \code{partynode} objects. } \item{surrogates}{ a list of \code{partysplit} objects.} \item{info}{ additional information. } \item{node}{ an object of class \code{partynode}.} \item{data}{ a \code{\link{list}} or \code{\link{data.frame}}.} \item{vmatch}{ a permutation of the variable numbers in \code{data}.} \item{obs}{ a logical or integer vector indicating a subset of the observations in \code{data}.} \item{perm}{ a vector of integers specifying the variables to be permuted prior before splitting (i.e., for computing permutation variable importances). The default \code{NULL} doesn't alter the data.} \item{FUN}{ function for formatting the \code{info}, for default see below.} \item{default}{ a character used if the \code{info} in \code{node} is \code{NULL}.} \item{prefix}{ an optional prefix to be added to the returned character. } \item{\dots}{ further arguments passed to \code{\link[utils]{capture.output}}.} } \details{ A node represents both inner and terminal nodes in a tree structure. Each node has a unique identifier \code{id}. A node consisting only of such an identifier (and possibly additional information in \code{info}) is a terminal node. Inner nodes consist of a primary split (an object of class \code{\link{partysplit}}) and at least two kids (daughter nodes). Kid nodes are objects of class \code{partynode} itself, so the tree structure is defined recursively. In addition, a list of \code{partysplit} objects offering surrogate splits can be supplied. Like \code{\link{partysplit}} objects, \code{partynode} objects aren't connected to the actual data. Function \code{kidids_node()} determines how the observations in \code{data[obs,]} are partitioned into the kid nodes and returns the number of the list element in list \code{kids} each observations belongs to (and not it's identifier). This is done by evaluating \code{split} (and possibly all surrogate splits) on \code{data} using \code{\link{kidids_split}}. Function \code{fitted_node()} performs all splits recursively and returns the identifier \code{id} of the terminal node each observation in \code{data[obs,]} belongs to. Arguments \code{vmatch}, \code{obs} and \code{perm} are passed to \code{\link{kidids_split}}. Function \code{formatinfo_node()} extracts the the \code{info} from \code{node} and formats it to a \code{character} vector using the following strategy: If \code{is.null(info)}, the \code{default} is returned. Otherwise, \code{FUN} is applied for formatting. The default function uses \code{as.character} for atomic objects and applies \code{\link[utils]{capture.output}} to \code{print(info)} for other objects. Optionally, a \code{prefix} can be added to the computed character string. All other functions are accessor functions for extracting information from objects of class \code{partynode}. } \value{ The constructor \code{partynode()} returns an object of class \code{partynode}: \item{id}{ a unique integer identifier for a node. } \item{split}{ an object of class \code{\link{partysplit}}. } \item{kids}{ a list of \code{partynode} objects. } \item{surrogates}{ a list of \code{\link{partysplit}} objects.} \item{info}{ additional information. } \code{kidids_split()} returns an integer vector describing the partition of the observations into kid nodes by their position in list \code{kids}. \code{fitted_node()} returns the node identifiers (\code{id}) of the terminal nodes each observation belongs to. } \references{ Hothorn T, Zeileis A (2015). partykit: A Modular Toolkit for Recursive Partytioning in R. \emph{Journal of Machine Learning Research}, \bold{16}, 3905--3909. } \examples{ data("iris", package = "datasets") ## a stump defined by a binary split in Sepal.Length stump <- partynode(id = 1L, split = partysplit(which(names(iris) == "Sepal.Length"), breaks = 5), kids = lapply(2:3, partynode)) ## textual representation print(stump, data = iris) ## list element number and node id of the two terminal nodes table(kidids_node(stump, iris), fitted_node(stump, data = iris)) ## assign terminal nodes with probability 0.5 ## to observations with missing `Sepal.Length' iris_NA <- iris iris_NA[sample(1:nrow(iris), 50), "Sepal.Length"] <- NA table(fitted_node(stump, data = iris_NA, obs = !complete.cases(iris_NA))) ## a stump defined by a primary split in `Sepal.Length' ## and a surrogate split in `Sepal.Width' which ## determines terminal nodes for observations with ## missing `Sepal.Length' stump <- partynode(id = 1L, split = partysplit(which(names(iris) == "Sepal.Length"), breaks = 5), kids = lapply(2:3, partynode), surrogates = list(partysplit( which(names(iris) == "Sepal.Width"), breaks = 3))) f <- fitted_node(stump, data = iris_NA, obs = !complete.cases(iris_NA)) tapply(iris_NA$Sepal.Width[!complete.cases(iris_NA)], f, range) } \keyword{tree} partykit/man/WeatherPlay.Rd0000644000176200001440000000276414172230000015406 0ustar liggesusers\name{WeatherPlay} \alias{WeatherPlay} \title{Weather Conditions and Playing a Game} \description{ Artificial data set concerning the conditions suitable for playing some unspecified game. } \usage{data("WeatherPlay")} \format{ A data frame containing 14 observations on 5 variables. \describe{ \item{outlook}{factor.} \item{temperature}{numeric.} \item{humidity}{numeric.} \item{windy}{factor.} \item{play}{factor.} } } \source{ Table 1.3 in Witten and Frank (2011). } \references{ Witten IH, Frank E (2011). \emph{Data Mining: Practical Machine Learning Tools and Techniques}. 3rd Edition, Morgan Kaufmann, San Francisco. } \seealso{\code{\link{party}}, \code{\link{partynode}}, \code{\link{partysplit}}} \examples{ ## load weather data data("WeatherPlay", package = "partykit") WeatherPlay ## construct simple tree pn <- partynode(1L, split = partysplit(1L, index = 1:3), kids = list( partynode(2L, split = partysplit(3L, breaks = 75), kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = partysplit(4L, index = 1:2), kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))) pn ## couple with data py <- party(pn, WeatherPlay) ## print/plot/predict print(py) plot(py) predict(py, newdata = WeatherPlay) ## customize printing print(py, terminal_panel = function(node) paste(": play=", info_node(node), sep = "")) } \keyword{datasets} partykit/man/mob_control.Rd0000644000176200001440000002042114172230000015464 0ustar liggesusers\name{mob_control} \alias{mob_control} \title{Control Parameters for Model-Based Partitioning} \description{ Various parameters that control aspects the fitting algorithm for recursively partitioned \code{\link{mob}} models. } \usage{ mob_control(alpha = 0.05, bonferroni = TRUE, minsize = NULL, maxdepth = Inf, mtry = Inf, trim = 0.1, breakties = FALSE, parm = NULL, dfsplit = TRUE, prune = NULL, restart = TRUE, verbose = FALSE, caseweights = TRUE, ytype = "vector", xtype = "matrix", terminal = "object", inner = terminal, model = TRUE, numsplit = "left", catsplit = "binary", vcov = "opg", ordinal = "chisq", nrep = 10000, minsplit = minsize, minbucket = minsize, applyfun = NULL, cores = NULL) } \arguments{ \item{alpha}{numeric significance level. A node is splitted when the (possibly Bonferroni-corrected) \eqn{p} value for any parameter stability test in that node falls below \code{alpha} (and the stopping criteria \code{minsize} and \code{maxdepth} are not fulfilled).} \item{bonferroni}{logical. Should \eqn{p} values be Bonferroni corrected?} \item{minsize, minsplit, minbucket}{integer. The minimum number of observations in a node. If \code{NULL}, the default is to use 10 times the number of parameters to be estimated (divided by the number of responses per observation if that is greater than 1). \code{minsize} is the recommended name and \code{minsplit}/\code{minbucket} are only included for backward compatibility with previous versions of \code{mob} and compatibility with \code{ctree}, respectively.} \item{maxdepth}{integer. The maximum depth of the tree.} \item{mtry}{integer. The number of partitioning variables randomly sampled as candidates in each node for forest-style algorithms. If \code{mtry} is greater than the number of partitioning variables, no random selection is performed. (Thus, by default all available partitioning variables are considered.)} \item{trim}{numeric. This specifies the trimming in the parameter instability test for the numerical variables. If smaller than 1, it is interpreted as the fraction relative to the current node size.} \item{breakties}{logical. Should ties in numeric variables be broken randomly for computing the associated parameter instability test?} \item{parm}{numeric or character. Number or name of model parameters included in the parameter instability tests (by default all parameters are included).} \item{dfsplit}{logical or numeric. \code{as.integer(dfsplit)} is the degrees of freedom per selected split employed when computing information criteria etc.} \item{prune}{character, numeric, or function for specifying post-pruning rule. If \code{prune} is \code{NULL} (the default), no post-pruning is performed. For likelihood-based \code{mob()} trees, \code{prune} can be set to \code{"AIC"} or \code{"BIC"} for post-pruning based on the corresponding information criteria. More general rules (also in scenarios that are not likelihood-based), can be specified by function arguments to \code{prune}, for details see below.} \item{restart}{logical. When determining the optimal split point in a numerical variable: Should model estimation be restarted with \code{NULL} starting values for each split? The default is \code{TRUE}. If \code{FALSE}, then the parameter estimates from the previous split point are used as starting values for the next split point (because in practice the difference are often not huge). (Note that in that case a \code{for} loop is used instead of the \code{applyfun} for fitting models across sample splits.)} \item{verbose}{logical. Should information about the fitting process of \code{\link{mob}} (such as test statistics, \eqn{p} values, selected splitting variables and split points) be printed to the screen?} \item{caseweights}{logical. Should weights be interpreted as case weights? If \code{TRUE}, the number of observations is \code{sum(weights)}, otherwise it is \code{sum(weights > 0)}.} \item{ytype, xtype}{character. Specification of how \code{mob} should preprocess \code{y} and \code{x} variables. Possible choice are: \code{"vector"} (for \code{y} only), i.e., only one variable; \code{"matrix"}, i.e., the model matrix of all variables; \code{"data.frame"}, i.e., a data frame of all variables.} \item{terminal, inner}{character. Specification of which additional information (\code{"estfun"}, \code{"object"}, or both) should be stored in each node. If \code{NULL}, no additional information is stored.} \item{model}{logical. Should the full model frame be stored in the resulting object?} \item{numsplit}{character indicating how splits for numeric variables should be justified. Because any splitpoint in the interval between the last observation from the left child segment and the first observation from the right child segment leads to the same observed split, two options are available in \code{mob_control}: Either, the split is \code{"left"}-justified (the default for backward compatibility) or \code{"center"}-justified using the midpoint of the possible interval.} \item{catsplit}{character indicating how (unordered) categorical variables should be splitted. By default the best \code{"binary"} split is searched (by minimizing the objective function). Alternatively, if set to \code{"multiway"}, the node is simply splitted into all levels of the categorical variable.} \item{vcov}{character indicating which type of covariance matrix estimator should be employed in the parameter instability tests. The default is the outer product of gradients (\code{"opg"}). Alternatively, \code{vcov = "info"} employs the information matrix and \code{vcov = "sandwich"} the sandwich matrix (both of which are only sensible for maximum likelihood estimation).} \item{ordinal}{character indicating which type of parameter instability test should be employed for ordinal partitioning variables (i.e., ordered factors). This can be \code{"chisq"}, \code{"max"}, or \code{"L2"}. If \code{"chisq"} then the variable is treated as unordered and a chi-squared test is performed. If \code{"L2"}, then a maxLM-type test as for numeric variables is carried out but correcting for ties. This requires simulation of p-values via \code{\link[strucchange]{catL2BB}} and requires some computation time. For \code{"max"} a weighted double maximum test is used that computes p-values via \code{\link[mvtnorm]{pmvnorm}}.} \item{nrep}{numeric. Number of replications in the simulation of p-values for the ordinal \code{"L2"} statistic (if used).} \item{applyfun}{an optional \code{\link[base]{lapply}}-style function with arguments \code{function(X, FUN, \dots)}. It is used for refitting the model across potential sample splits. The default is to use the basic \code{lapply} function unless the \code{cores} argument is specified (see below).} \item{cores}{numeric. If set to an integer the \code{applyfun} is set to \code{\link[parallel]{mclapply}} with the desired number of \code{cores}.} } \details{ See \code{\link{mob}} for more details and references. For post-pruning, \code{prune} can be set to a \code{function(objfun, df, nobs)} which either returns \code{TRUE} to signal that a current node can be pruned or \code{FALSE}. All supplied arguments are of length two: \code{objfun} is the sum of objective function values in the current node and its child nodes, respectively. \code{df} is the degrees of freedom in the current node and its child nodes, respectively. \code{nobs} is vector with the number of observations in the current node and the total number of observations in the dataset, respectively. If the objective function employed in the \code{mob()} call is the negative log-likelihood, then a suitable function is set up on the fly by comparing \code{(2 * objfun + penalty * df)} in the current and the daughter nodes. The penalty can then be set via a numeric or character value for \code{prune}: AIC is used if \code{prune = "AIC"} or \code{prune = 2} and BIC if \code{prune = "BIC"} or \code{prune = log(n)}. } \seealso{\code{\link{mob}}} \value{ A list of class \code{mob_control} containing the control parameters. } \keyword{misc} partykit/man/glmtree.Rd0000644000176200001440000000661414172230000014616 0ustar liggesusers\name{glmtree} \alias{glmtree} \alias{plot.glmtree} \alias{predict.glmtree} \alias{print.glmtree} \title{Generalized Linear Model Trees} \description{ Model-based recursive partitioning based on generalized linear models. } \usage{ glmtree(formula, data, subset, na.action, weights, offset, cluster, family = gaussian, epsilon = 1e-8, maxit = 25, method = "glm.fit", \dots) } \arguments{ \item{formula}{symbolic description of the model (of type \code{y ~ z1 + \dots + zl} or \code{y ~ x1 + \dots + xk | z1 + \dots + zl}; for details see below).} \item{data, subset, na.action}{arguments controlling formula processing via \code{\link[stats]{model.frame}}.} \item{weights}{optional numeric vector of weights. By default these are treated as case weights but the default can be changed in \code{\link{mob_control}}.} \item{offset}{optional numeric vector with an a priori known component to be included in the model \code{y ~ x1 + \dots + xk} (i.e., only when \code{x} variables are specified).} \item{cluster}{optional vector (typically numeric or factor) with a cluster ID to be employed for clustered covariances in the parameter stability tests.} \item{family, method}{specification of a family and fitting method for \code{\link[stats]{glm}}.} \item{epsilon, maxit}{control parameters passed to \code{\link[stats]{glm.control}}.} \item{\dots}{optional control parameters passed to \code{\link{mob_control}}.} } \details{ Convenience interface for fitting MOBs (model-based recursive partitions) via the \code{\link{mob}} function. \code{glmtree} internally sets up a model \code{fit} function for \code{mob}, using \code{\link[stats]{glm.fit}}. Then \code{mob} is called using the negative log-likelihood as the objective function. Compared to calling \code{mob} by hand, the implementation tries to avoid unnecessary computations while growing the tree. Also, it provides a more elaborate plotting function. } \value{ An object of class \code{glmtree} inheriting from \code{\link{modelparty}}. The \code{info} element of the overall \code{party} and the individual \code{node}s contain various informations about the models. } \references{ Zeileis A, Hothorn T, Hornik K (2008). Model-Based Recursive Partitioning. \emph{Journal of Computational and Graphical Statistics}, \bold{17}(2), 492--514. } \seealso{\code{\link{mob}}, \code{\link{mob_control}}, \code{\link{lmtree}}} \examples{ if(require("mlbench")) { ## Pima Indians diabetes data data("PimaIndiansDiabetes", package = "mlbench") ## recursive partitioning of a logistic regression model pid_tree2 <- glmtree(diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age, data = PimaIndiansDiabetes, family = binomial) ## printing whole tree or individual nodes print(pid_tree2) print(pid_tree2, node = 1) ## visualization plot(pid_tree2) plot(pid_tree2, tp_args = list(cdplot = TRUE)) plot(pid_tree2, terminal_panel = NULL) ## estimated parameters coef(pid_tree2) coef(pid_tree2, node = 5) summary(pid_tree2, node = 5) ## deviance, log-likelihood and information criteria deviance(pid_tree2) logLik(pid_tree2) AIC(pid_tree2) BIC(pid_tree2) ## different types of predictions pid <- head(PimaIndiansDiabetes) predict(pid_tree2, newdata = pid, type = "node") predict(pid_tree2, newdata = pid, type = "response") predict(pid_tree2, newdata = pid, type = "link") } } \keyword{tree} partykit/man/party-predict.Rd0000644000176200001440000001064714172230000015747 0ustar liggesusers\name{party-predict} \alias{party-predict} \alias{predict.party} \alias{predict_party} \alias{predict_party.default} \alias{predict_party.constparty} \alias{predict_party.simpleparty} \title{ Tree Predictions } \description{ Compute predictions from \code{party} objects. } \usage{ \method{predict}{party}(object, newdata = NULL, perm = NULL, \dots) predict_party(party, id, newdata = NULL, \dots) \method{predict_party}{default}(party, id, newdata = NULL, FUN = NULL, \dots) \method{predict_party}{constparty}(party, id, newdata = NULL, type = c("response", "prob", "quantile", "density", "node"), at = if (type == "quantile") c(0.1, 0.5, 0.9), FUN = NULL, simplify = TRUE, \dots) \method{predict_party}{simpleparty}(party, id, newdata = NULL, type = c("response", "prob", "node"), \dots) } \arguments{ \item{object}{ objects of class \code{\link{party}}. } \item{newdata}{ an optional data frame in which to look for variables with which to predict, if omitted, the fitted values are used.} \item{perm}{an optional character vector of variable names. Splits of nodes with a primary split in any of these variables will be permuted (after dealing with surrogates). Note that surrogate split in the \code{perm} variables will no be permuted.} \item{party}{ objects of class \code{\link{party}}. } \item{id}{ a vector of terminal node identifiers. } \item{type}{ a character string denoting the type of predicted value returned, ignored when argument \code{FUN} is given. For \code{"response"}, the mean of a numeric response, the predicted class for a categorical response or the median survival time for a censored response is returned. For \code{"prob"} the matrix of conditional class probabilities (\code{simplify = TRUE}) or a list with the conditional class probabilities for each observation (\code{simplify = FALSE}) is returned for a categorical response. For numeric and censored responses, a list with the empirical cumulative distribution functions and empirical survivor functions (Kaplan-Meier estimate) is returned when \code{type = "prob"}. \code{"node"} returns an integer vector of terminal node identifiers.} \item{FUN}{ a function to extract (\code{default} method) or compute (\code{constparty} method) summary statistics. For the \code{default} method, this is a function of a terminal node only, for the \code{constparty} method, predictions for each node have to be computed based on arguments \code{(y, w)} where \code{y} is the response and \code{w} are case weights.} \item{at}{ if the return value is a function (as the empirical cumulative distribution function or the empirical quantile function), this function is evaluated at values \code{at} and these numeric values are returned. If \code{at} is \code{NULL}, the functions themselves are returned in a list.} \item{simplify}{ a logical indicating whether the resulting list of predictions should be converted to a suitable vector or matrix (if possible).} \item{\dots}{ additional arguments. } } \details{ The \code{\link{predict}} method for \code{\link{party}} objects computes the identifiers of the predicted terminal nodes, either for new data in \code{newdata} or for the learning samples (only possible for objects of class \code{constparty}). These identifiers are delegated to the corresponding \code{predict_party} method which computes (via \code{FUN} for class \code{constparty}) or extracts (class \code{simpleparty}) the actual predictions. } \value{ A list of predictions, possibly simplified to a numeric vector, numeric matrix or factor. } \examples{ ## fit tree using rpart library("rpart") rp <- rpart(skips ~ Opening + Solder + Mask + PadType + Panel, data = solder, method = 'anova') ## coerce to `constparty' pr <- as.party(rp) ## mean predictions predict(pr, newdata = solder[c(3, 541, 640),]) ## ecdf predict(pr, newdata = solder[c(3, 541, 640),], type = "prob") ## terminal node identifiers predict(pr, newdata = solder[c(3, 541, 640),], type = "node") ## median predictions predict(pr, newdata = solder[c(3, 541, 640),], FUN = function(y, w = 1) median(y)) } \keyword{tree} partykit/man/party-plot.Rd0000644000176200001440000001076214172230000015271 0ustar liggesusers\name{party-plot} \alias{party-plot} \alias{plot.party} \alias{plot.constparty} \alias{plot.simpleparty} \title{ Visualization of Trees } \description{ \code{plot} method for \code{party} objects with extended facilities for plugging in panel functions. } \usage{ \method{plot}{party}(x, main = NULL, terminal_panel = node_terminal, tp_args = list(), inner_panel = node_inner, ip_args = list(), edge_panel = edge_simple, ep_args = list(), drop_terminal = FALSE, tnex = 1, newpage = TRUE, pop = TRUE, gp = gpar(), margins = NULL, \dots) \method{plot}{constparty}(x, main = NULL, terminal_panel = NULL, tp_args = list(), inner_panel = node_inner, ip_args = list(), edge_panel = edge_simple, ep_args = list(), type = c("extended", "simple"), drop_terminal = NULL, tnex = NULL, newpage = TRUE, pop = TRUE, gp = gpar(), \dots) \method{plot}{simpleparty}(x, digits = getOption("digits") - 4, tp_args = NULL, \dots) } \arguments{ \item{x}{ an object of class \code{party} or \code{constparty}.} \item{main}{ an optional title for the plot.} \item{type}{ a character specifying the complexity of the plot: \code{extended} tries to visualize the distribution of the response variable in each terminal node whereas \code{simple} only gives some summary information.} \item{terminal_panel}{ an optional panel function of the form \code{function(node)} plotting the terminal nodes. Alternatively, a panel generating function of class \code{"grapcon_generator"} that is called with arguments \code{x} and \code{tp_args} to set up a panel function. By default, an appropriate panel function is chosen depending on the scale of the dependent variable.} \item{tp_args}{ a list of arguments passed to \code{terminal_panel} if this is a \code{"grapcon_generator"} object.} \item{inner_panel}{ an optional panel function of the form \code{function(node)} plotting the inner nodes. Alternatively, a panel generating function of class \code{"grapcon_generator"} that is called with arguments \code{x} and \code{ip_args} to set up a panel function.} \item{ip_args}{ a list of arguments passed to \code{inner_panel} if this is a \code{"grapcon_generator"} object.} \item{edge_panel}{ an optional panel function of the form \code{function(split, ordered = FALSE, left = TRUE)} plotting the edges. Alternatively, a panel generating function of class \code{"grapcon_generator"} that is called with arguments \code{x} and \code{ip_args} to set up a panel function.} \item{ep_args}{ a list of arguments passed to \code{edge_panel} if this is a \code{"grapcon_generator"} object.} \item{drop_terminal}{ a logical indicating whether all terminal nodes should be plotted at the bottom.} \item{tnex}{a numeric value giving the terminal node extension in relation to the inner nodes.} \item{newpage}{ a logical indicating whether \code{grid.newpage()} should be called. } \item{pop}{ a logical whether the viewport tree should be popped before return. } \item{gp}{graphical parameters.} \item{margins}{numeric vector of margin sizes.} \item{digits}{number of digits to be printed.} \item{\dots}{ additional arguments passed to callies.} } \details{ This \code{plot} method for \code{party} objects provides an extensible framework for the visualization of binary regression trees. The user is allowed to specify panel functions for plotting terminal and inner nodes as well as the corresponding edges. Panel functions for plotting inner nodes, edges and terminal nodes are available for the most important cases and can serve as the basis for user-supplied extensions, see \code{\link{node_inner}}. More details on the ideas and concepts of panel-generating functions and \code{"grapcon_generator"} objects in general can be found in Meyer, Zeileis and Hornik (2005). } \references{ Meyer D, Zeileis A, Hornik K (2006). The Strucplot Framework: Visualizing Multi-Way Contingency Tables with vcd. \emph{Journal of Statistical Software}, \bold{17}(3), 1--48. \doi{10.18637/jss.v017.i03} } \seealso{\code{\link{node_inner}}, \code{\link{node_terminal}}, \code{\link{edge_simple}}, \code{\link{node_barplot}}, \code{\link{node_boxplot}}.} \keyword{hplot} partykit/man/extree_data.Rd0000644000176200001440000000466714172230000015452 0ustar liggesusers\name{extree_data} \alias{extree_data} %- Also NEED an '\alias' for EACH other topic documented here. \title{ Data Preprocessing for Extensible Trees. } \description{ A routine for preprocessing data before an extensible tree can be grown by \code{extree_fit}. } \usage{ extree_data(formula, data, subset, na.action = na.pass, weights, offset, cluster, strata, scores = NULL, yx = c("none", "matrix"), ytype = c("vector", "data.frame", "matrix"), nmax = c(yx = Inf, z = Inf), ...) } \arguments{ \item{formula}{a formula describing the model of the form \code{y1 + y2 + ... ~ x1 + x2 + ... | z1 + z2 + ...}. } \item{data}{an optional data.frame containing the variables in the model. } \item{subset}{an optional vector specifying a subset of observations to be used in the fitting process. } \item{na.action}{a function which indicates what should happen when the data contain missing values. } \item{weights}{an optional vector of weights. } \item{offset}{an optional offset vector. } \item{cluster}{an optional factor describing clusters. The interpretation depends on the specific tree algorithm. } \item{strata}{an optional factor describing strata. The interpretation depends on the specific tree algorithm. } \item{scores}{an optional named list of numeric scores to be assigned to ordered factors in the \code{z} part of the formula. } \item{yx}{a character indicating if design matrices shall be computed. } \item{ytype}{a character indicating how response variables shall be stored. } \item{nmax}{a numeric vector of length two with the maximal number of bins in the response and \code{x}-part (first element) and the \code{z} part. Use \code{Inf} to switch-off binning. } \item{\dots}{additional arguments. } } \details{ This internal functionality will be the basis of implementations of other tree algorithms in future versions. Currently, only \code{ctree} relies on this function. } \value{An object of class \code{extree_data}. } \examples{ data("iris") ed <- extree_data(Species ~ Sepal.Width + Sepal.Length | Petal.Width + Petal.Length, data = iris, nmax = c("yx" = 25, "z" = 10), yx = "matrix") ### the model.frame mf <- model.frame(ed) all.equal(mf, iris[, names(mf)]) ### binned y ~ x part model.frame(ed, yxonly = TRUE) ### binned Petal.Width ed[[4, type = "index"]] ### response ed$yx$y ### model matrix ed$yx$x } \keyword{tree} partykit/man/nodeapply.Rd0000644000176200001440000000551414172230000015150 0ustar liggesusers\name{nodeapply} \alias{nodeapply} \alias{nodeapply.party} \alias{nodeapply.partynode} \title{ Apply Functions Over Nodes } \description{ Returns a list of values obtained by applying a function to \code{party} or \code{partynode} objects. } \usage{ nodeapply(obj, ids = 1, FUN = NULL, \dots) \method{nodeapply}{partynode}(obj, ids = 1, FUN = NULL, \dots) \method{nodeapply}{party}(obj, ids = 1, FUN = NULL, by_node = TRUE, \dots) } \arguments{ \item{obj}{ an object of class \code{\link{partynode}} or \code{\link{party}}.} \item{ids}{ integer vector of node identifiers to apply over.} \item{FUN}{ a function to be applied to nodes. By default, the node itself is returned.} \item{by_node}{ a logical indicating if \code{FUN} is applied to subsets of \code{\link{party}} objects or \code{\link{partynode}} objects (default). } \item{\dots}{ additional arguments.} } \details{ Function \code{FUN} is applied to all nodes with node identifiers in \code{ids} for a \code{partynode} object. The method for \code{party} by default calls the \code{nodeapply} method on it's \code{node} slot. If \code{by_node} is \code{FALSE}, it is applied to a \code{party} object with root node \code{ids}. } \value{ A list of results of length \code{length(ids)}. } \examples{ ## a tree as flat list structure nodelist <- list( # root node list(id = 1L, split = partysplit(varid = 4L, breaks = 1.9), kids = 2:3), # V4 <= 1.9, terminal node list(id = 2L, info = "terminal A"), # V4 > 1.9 list(id = 3L, split = partysplit(varid = 5L, breaks = 1.7), kids = c(4L, 7L)), # V5 <= 1.7 list(id = 4L, split = partysplit(varid = 4L, breaks = 4.8), kids = 5:6), # V4 <= 4.8, terminal node list(id = 5L, info = "terminal B"), # V4 > 4.8, terminal node list(id = 6L, info = "terminal C"), # V5 > 1.7, terminal node list(id = 7L, info = "terminal D") ) ## convert to a recursive structure node <- as.partynode(nodelist) ## return root node nodeapply(node) ## return info slots of terminal nodes nodeapply(node, ids = nodeids(node, terminal = TRUE), FUN = function(x) info_node(x)) ## fit tree using rpart library("rpart") rp <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis) ## coerce to `constparty' rpk <- as.party(rp) ## extract nodeids nodeids(rpk) unlist(nodeapply(node_party(rpk), ids = nodeids(rpk), FUN = id_node)) unlist(nodeapply(rpk, ids = nodeids(rpk), FUN = id_node)) ## but root nodes of party objects always have id = 1 unlist(nodeapply(rpk, ids = nodeids(rpk), FUN = function(x) id_node(node_party(x)), by_node = FALSE)) } \keyword{tree} partykit/man/HuntingSpiders.Rd0000644000176200001440000000621314172230000016120 0ustar liggesusers\name{HuntingSpiders} \alias{HuntingSpiders} \title{Abundance of Hunting Spiders} \description{ Abundances for 12 species of hunting spiders along with environmental predictors, all rated on a 0--9 scale. } \usage{data("HuntingSpiders")} \format{ A data frame containing 28 observations on 18 variables (12 species abundances and 6 environmental predictors). \describe{ \item{arct.lute}{numeric. Abundance of species \emph{Arctosa lutetiana} (on a scale 0--9).} \item{pard.lugu}{numeric. Abundance of species \emph{Pardosa lugubris} (on a scale 0--9).} \item{zora.spin}{numeric. Abundance of species \emph{Zora spinimana} (on a scale 0--9).} \item{pard.nigr}{numeric. Abundance of species \emph{Pardosa nigriceps} (on a scale 0--9).} \item{pard.pull}{numeric. Abundance of species \emph{Pardosa pullata} (on a scale 0--9).} \item{aulo.albi}{numeric. Abundance of species \emph{Aulonia albimana} (on a scale 0--9).} \item{troc.terr}{numeric. Abundance of species \emph{Trochosa terricola} (on a scale 0--9).} \item{alop.cune}{numeric. Abundance of species \emph{Alopecosa cuneata} (on a scale 0--9).} \item{pard.mont}{numeric. Abundance of species \emph{Pardosa monticola} (on a scale 0--9).} \item{alop.acce}{numeric. Abundance of species \emph{Alopecosa accentuata} (on a scale 0--9).} \item{alop.fabr}{numeric. Abundance of species \emph{Alopecosa fabrilis} (on a scale 0--9).} \item{arct.peri}{numeric. Abundance of species \emph{Arctosa perita} (on a scale 0--9).} \item{water}{numeric. Environmental predictor on a scale 0--9.} \item{sand}{numeric. Environmental predictor on a scale 0--9.} \item{moss}{numeric. Environmental predictor on a scale 0--9.} \item{reft}{numeric. Environmental predictor on a scale 0--9.} \item{twigs}{numeric. Environmental predictor on a scale 0--9.} \item{herbs}{numeric. Environmental predictor on a scale 0--9.} } } \details{ The data were originally analyzed by Van der Aart and Smeenk-Enserink (1975). De'ath (2002) transformed all variables to the 0--9 scale and employed multivariate regression trees. } \source{ Package \pkg{mvpart} (currently archived, see \url{https://CRAN.R-project.org/package=mvpart}). } \references{ Van der Aart PJM, Smeenk-Enserink N (1975). Correlations between Distributions of Hunting Spiders (Lycosidae, Ctenidae) and Environmental Characteristics in a Dune Area. \emph{Netherlands Journal of Zoology}, \bold{25}, 1--45. De'ath G (2002). Multivariate Regression Trees: A New Technique for Modelling Species-Environment Relationships. \emph{Ecology}, \bold{83}(4), 1103--1117. } \examples{ ## load data data("HuntingSpiders", package = "partykit") ## fit multivariate tree for 12-dimensional species abundance ## (warnings by mvtnorm are suppressed) suppressWarnings(sptree <- ctree(arct.lute + pard.lugu + zora.spin + pard.nigr + pard.pull + aulo.albi + troc.terr + alop.cune + pard.mont + alop.acce + alop.fabr + arct.peri ~ herbs + reft + moss + sand + twigs + water, data = HuntingSpiders, teststat = "max", minsplit = 5)) plot(sptree, terminal_panel = node_barplot) } \keyword{datasets} partykit/man/panelfunctions.Rd0000644000176200001440000001770614172230000016213 0ustar liggesusers\name{panelfunctions} \alias{panelfunctions} \alias{node_inner} \alias{node_terminal} \alias{edge_simple} \alias{node_barplot} \alias{node_bivplot} \alias{node_boxplot} \alias{node_surv} \alias{node_ecdf} \alias{node_mvar} \title{ Panel-Generators for Visualization of Party Trees } \description{ The plot method for \code{party} and \code{constparty} objects are rather flexible and can be extended by panel functions. Some pre-defined panel-generating functions of class \code{grapcon_generator} for the most important cases are documented here. } \usage{ node_inner(obj, id = TRUE, pval = TRUE, abbreviate = FALSE, fill = "white", gp = gpar()) node_terminal(obj, digits = 3, abbreviate = FALSE, fill = c("lightgray", "white"), id = TRUE, just = c("center", "top"), top = 0.85, align = c("center", "left", "right"), gp = NULL, FUN = NULL, height = NULL, width = NULL) edge_simple(obj, digits = 3, abbreviate = FALSE, justmin = Inf, just = c("alternate", "increasing", "decreasing", "equal"), fill = "white") node_boxplot(obj, col = "black", fill = "lightgray", bg = "white", width = 0.5, yscale = NULL, ylines = 3, cex = 0.5, id = TRUE, mainlab = NULL, gp = gpar()) node_barplot(obj, col = "black", fill = NULL, bg = "white", beside = NULL, ymax = NULL, ylines = NULL, widths = 1, gap = NULL, reverse = NULL, rot = 0, just = c("center", "top"), id = TRUE, mainlab = NULL, text = c("none", "horizontal", "vertical"), gp = gpar()) node_surv(obj, col = "black", bg = "white", yscale = c(0, 1), ylines = 2, id = TRUE, mainlab = NULL, gp = gpar(), \dots) node_ecdf(obj, col = "black", bg = "white", ylines = 2, id = TRUE, mainlab = NULL, gp = gpar(), \dots) node_bivplot(mobobj, which = NULL, id = TRUE, pop = TRUE, pointcol = "black", pointcex = 0.5, boxcol = "black", boxwidth = 0.5, boxfill = "lightgray", bg = "white", fitmean = TRUE, linecol = "red", cdplot = FALSE, fivenum = TRUE, breaks = NULL, ylines = NULL, xlab = FALSE, ylab = FALSE, margins = rep(1.5, 4), mainlab = NULL, \dots) node_mvar(obj, which = NULL, id = TRUE, pop = TRUE, ylines = NULL, mainlab = NULL, varlab = TRUE, bg = "white", ...) } \arguments{ \item{obj}{ an object of class \code{party}.} \item{digits}{ integer, used for formating numbers. } \item{abbreviate}{ logical indicating whether strings should be abbreviated. } \item{col, pointcol, boxcol, linecol}{ a color for points and lines. } \item{fill, boxfill, bg}{ a color to filling rectangles and backgrounds. } \item{id}{ logical. Should node IDs be plotted?} \item{pval}{ logical. Should node p values be plotted (if they are available)?} \item{just}{justification of terminal panel viewport (\code{node_terminal}), or labels (\code{edge_simple}, \code{node_barplot}).} \item{justmin}{minimum average edge label length to employ justification via \code{just} in \code{edge_panel}, otherwise \code{just = "equal"} is used. Thus, by default \code{"equal"} justification is always used but other justifications could be employed for finite \code{justmin}.} \item{top}{in case of top justification, the npc coordinate at which the viewport is justified.} \item{align}{alignment of text within terminal panel viewport.} \item{ylines}{ number of lines for spaces in y-direction. } \item{widths}{ widths in barplots. } \item{boxwidth}{ width in boxplots (called \code{width} in \code{node_boxplot}). } \item{gap}{ gap between bars in a barplot (\code{node_barplot}). } \item{yscale}{ limits in y-direction} \item{ymax}{ upper limit in y-direction} \item{cex, pointcex}{character extension of points in scatter plots.} \item{beside}{ logical indicating if barplots should be side by side or stacked. } \item{reverse}{logical indicating whether the order of levels should be reversed for barplots. } \item{rot}{ arguments passed to \code{\link[grid]{grid.text}} for the x-axis labeling. } \item{gp}{graphical parameters.} \item{FUN}{function for formatting the \code{info}, passed to \code{\link{formatinfo_node}}.} \item{height, width}{ numeric, number of lines/columns for printing text. } \item{mobobj}{an object of class \code{modelparty} as computed by \code{\link{mob}}.} \item{which}{numeric or character. Optional selection of subset of regressor variables. By default one panel for each regressor variable is drawn.} \item{pop}{logical. Should the viewports in the individual nodes be popped after drawing?} \item{fitmean}{logical. Should the fitted mean function be visualized?} \item{cdplot}{logical. Should a CD plot (or a spineplot) be drawn when the response variable is categorical?} \item{fivenum}{logical. Should the five-number summary be used for splitting the x-axis in spineplots?} \item{breaks}{numeric. Optional numeric vector with breaks for the x-axis in splineplots.} \item{xlab, ylab}{character. Optional annotation for x-axis and y-axis.} \item{margins}{numeric. Margins around drawing area in viewport.} \item{mainlab}{character or function. An optional title for the plot. Either a character or a \code{function(id, nobs)}.} \item{varlab}{logical. Should the individual variable labels be attached to the \code{mainlab} for multivariate responses?} \item{text}{logical or character. Should percentage labels be drawn for each bar? The default is \code{"none"} or equivalently \code{FALSE}. Can be set to \code{TRUE} (or \code{"horizontal"}) or alternatively \code{"vertical"}.} \item{\dots}{ additional arguments passed to callies (for example to \code{\link[survival]{survfit}}).} } \details{ The \code{plot} methods for \code{party} and \code{constparty} objects provide an extensible framework for the visualization of binary regression trees. The user is allowed to specify panel functions for plotting terminal and inner nodes as well as the corresponding edges. The panel functions to be used should depend only on the node being visualized, however, for setting up an appropriate panel function, information from the whole tree is typically required. Hence, \pkg{party} adopts the framework of \code{grapcon_generator} (graphical appearance control) from the \pkg{vcd} package (Meyer, Zeileis and Hornik, 2005) and provides several panel-generating functions. For convenience, the panel-generating functions \code{node_inner} and \code{edge_simple} return panel functions to draw inner nodes and left and right edges. For drawing terminal nodes, the functions returned by the other panel functions can be used. The panel generating function \code{node_terminal} is a terse text-based representation of terminal nodes. Graphical representations of terminal nodes are available and depend on the kind of model and the measurement scale of the variables modeled. For univariate regressions (typically fitted by \code{}), \code{node_surv} returns a functions that plots Kaplan-Meier curves in each terminal node; \code{node_barplot}, \code{node_boxplot}, \code{node_hist}, \code{node_ecdf} and \code{node_density} can be used to plot bar plots, box plots, histograms, empirical cumulative distribution functions and estimated densities into the terminal nodes. For multivariate regressions (typically fitted by \code{mob}), \code{node_bivplot} returns a panel function that creates bivariate plots of the response against all regressors in the model. Depending on the scale of the variables involved, scatter plots, box plots, spinograms (or CD plots) and spine plots are created. For the latter two \code{\link[vcd]{spine}} and \code{\link[vcd]{cd_plot}} from the \pkg{vcd} package are re-used. For multivariate responses in \code{\link{ctree}}, the panel function \code{node_mvar} generates one plot for each response. } \references{ Meyer D, Zeileis A, Hornik K (2006). The Strucplot Framework: Visualizing Multi-Way Contingency Tables with vcd. \emph{Journal of Statistical Software}, \bold{17}(3), 1--48. \doi{10.18637/jss.v017.i03} } \keyword{hplot} partykit/man/party-coercion.Rd0000644000176200001440000000400614172230000016106 0ustar liggesusers\name{party-coercion} \alias{party-coercion} \alias{as.party} \alias{as.party.rpart} \alias{as.party.Weka_tree} \alias{as.party.XMLNode} \alias{as.constparty} \alias{as.simpleparty} \alias{as.simpleparty.party} \alias{as.simpleparty.simpleparty} \alias{as.simpleparty.XMLNode} \alias{as.simpleparty.constparty} \alias{pmmlTreeModel} \title{Coercion Functions} \description{ Functions coercing various objects to objects of class party. } \usage{ as.party(obj, \dots) \method{as.party}{rpart}(obj, data = TRUE, \dots) \method{as.party}{Weka_tree}(obj, data = TRUE, \dots) \method{as.party}{XMLNode}(obj, \dots) pmmlTreeModel(file, \dots) as.constparty(obj, \dots) as.simpleparty(obj, \dots) \method{as.simpleparty}{party}(obj, \dots) \method{as.simpleparty}{simpleparty}(obj, \dots) \method{as.simpleparty}{constparty}(obj, \dots) \method{as.simpleparty}{XMLNode}(obj, \dots) } \arguments{ \item{obj}{ an object of class \code{\link[rpart]{rpart}}, \code{\link[RWeka:Weka_classifier_trees]{Weka_tree}}, \code{XMLnode} or objects inheriting from \code{party}.} \item{data}{logical. Should the model frame associated with the fitted \code{obj} be included in the \code{data} of the \code{party}?} \item{file}{ a file name of a XML file containing a PMML description of a tree.} \item{\dots}{ additional arguments.} } \details{ Trees fitted using functions \code{\link[rpart]{rpart}} or \code{\link[RWeka:Weka_classifier_trees]{J48}} are coerced to \code{\link{party}} objects. By default, objects of class \code{constparty} are returned. When information about the learning sample is available, \code{\link{party}} objects can be coerced to objects of class \code{constparty} or \code{simpleparty} (see \code{\link{party}} for details). } \value{ All methods return objects of class \code{\link{party}}. } \examples{ ## fit tree using rpart library("rpart") rp <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis) ## coerce to `constparty' as.party(rp) } \keyword{tree} partykit/man/partynode-methods.Rd0000644000176200001440000000763114172230000016625 0ustar liggesusers\name{partynode-methods} \alias{partynode-methods} \alias{is.partynode} \alias{as.partynode} \alias{as.partynode.partynode} \alias{as.partynode.list} \alias{as.list.partynode} \alias{length.partynode} \alias{[.partynode} \alias{[[.partynode} \alias{is.terminal} \alias{is.terminal.partynode} \alias{depth.partynode} \alias{width} \alias{width.partynode} \alias{print.partynode} \alias{nodeprune.partynode} \title{ Methods for Node Objects} \description{ Methods for computing on \code{partynode} objects. } \usage{ is.partynode(x) as.partynode(x, \dots) \method{as.partynode}{partynode}(x, from = NULL, recursive = TRUE, \dots) \method{as.partynode}{list}(x, \dots) \method{as.list}{partynode}(x, \dots) \method{length}{partynode}(x) \method{[}{partynode}(x, i, \dots) \method{[[}{partynode}(x, i, \dots) is.terminal(x, \dots) \method{is.terminal}{partynode}(x, \dots) \method{depth}{partynode}(x, root = FALSE, \dots) width(x, \dots) \method{width}{partynode}(x, \dots) \method{print}{partynode}(x, data = NULL, names = NULL, inner_panel = function(node) "", terminal_panel = function(node) " *", prefix = "", first = TRUE, digits = getOption("digits") - 2, \dots) \method{nodeprune}{partynode}(x, ids, ...) } \arguments{ \item{x}{ an object of class \code{partynode} or \code{list}.} \item{from}{ an integer giving the identifier of the root node.} \item{recursive}{ a logical, if \code{FALSE}, only the id of the root node is checked against \code{from}. If \code{TRUE}, the ids of all nodes are checked.} \item{i}{ an integer specifying the kid to extract.} \item{root}{ a logical. Should the root count be counted in \code{depth}? } \item{data}{ an optional \code{data.frame}.} \item{names}{ a vector of names for nodes.} \item{terminal_panel}{ a panel function for printing terminal nodes.} \item{inner_panel}{ a panel function for printing inner nodes.} \item{prefix}{ lines start with this symbol.} \item{first}{ a logical.} \item{digits}{ number of digits to be printed.} \item{ids}{ a vector of node ids to be pruned-off.} \item{\dots}{ additional arguments.} } \details{ \code{is.partynode} checks if the argument is a valid \code{partynode} object. \code{is.terminal} is \code{TRUE} for terminal nodes and \code{FALSE} for inner nodes. The subset methods return the \code{partynode} object corresponding to the \code{i}th kid. The \code{as.partynode} and \code{as.list} methods can be used to convert flat list structures into recursive \code{partynode} objects and vice versa. \code{as.partynode} applied to \code{partynode} objects renumbers the recursive nodes starting with root node identifier \code{from}. \code{length} gives the number of kid nodes of the root node, \code{depth} the depth of the tree and \code{width} the number of terminal nodes. } \examples{ ## a tree as flat list structure nodelist <- list( # root node list(id = 1L, split = partysplit(varid = 4L, breaks = 1.9), kids = 2:3), # V4 <= 1.9, terminal node list(id = 2L), # V4 > 1.9 list(id = 3L, split = partysplit(varid = 1L, breaks = 1.7), kids = c(4L, 7L)), # V1 <= 1.7 list(id = 4L, split = partysplit(varid = 4L, breaks = 4.8), kids = 5:6), # V4 <= 4.8, terminal node list(id = 5L), # V4 > 4.8, terminal node list(id = 6L), # V1 > 1.7, terminal node list(id = 7L) ) ## convert to a recursive structure node <- as.partynode(nodelist) ## print raw recursive structure without data print(node) ## print tree along with the associated iris data data("iris", package = "datasets") print(node, data = iris) ## print subtree print(node[2], data = iris) ## print subtree, with root node number one print(as.partynode(node[2], from = 1), data = iris) ## number of kids in root node length(node) ## depth of tree depth(node) ## number of terminal nodes width(node) ## convert back to flat structure as.list(node) } \keyword{tree} partykit/man/prune.modelparty.Rd0000644000176200001440000000635314405111440016474 0ustar liggesusers\name{prune.modelparty} \alias{prune.modelparty} \alias{prune.lmtree} \title{Post-Prune \code{modelparty} Objects} \usage{ \method{prune}{modelparty}(tree, type = "AIC", ...) } \description{ Post-pruning of \code{modelparty} objects based on information criteria like AIC, BIC, or related user-defined criteria. } \arguments{ \item{tree}{object of class \code{modelparty}.} \item{type}{pruning type. Can be \code{"AIC"}, \code{"BIC"} or a user-defined function (details below).} \item{\dots}{additional arguments.} } \details{ In \code{\link{mob}}-based model trees, pre-pruning based on p-values is used by default and often no post-pruning is necessary in such trees. However, if pre-pruning is switched off (by using a large \code{alpha}) or does is not sufficient (e.g., possibly in large samples) the \code{prune} method can be used for subsequent post-pruning based on information criteria. The function \code{prune.modelparty} can be called directly but it is also registered as a method for the generic \code{\link[rpart]{prune}} function from the \pkg{rpart} package. Thus, if \pkg{rpart} is attached, \code{prune(tree, type = "AIC", ...)} also works (see examples below). To customize the post-pruning strategy, \code{type} can be set to a \code{function(objfun, df, nobs)} which either returns \code{TRUE} to signal that a current node can be pruned or \code{FALSE}. All supplied arguments are of length two: \code{objfun} is the sum of objective function values in the current node and its child nodes, respectively. \code{df} is the degrees of freedom in the current node and its child nodes, respectively. \code{nobs} is vector with the number of observations in the current node and the total number of observations in the dataset, respectively. For \code{"AIC"} and \code{"BIC"} \code{type} is transformed so that AIC or BIC are computed. However, this assumes that the \code{objfun} used in \code{tree} is actually the negative log-likelihood. The degrees of freedom assumed for a split can be set via the \code{dfsplit} argument in \code{\link{mob_control}} when computing the \code{tree} or manipulated later by changing the value of \code{tree$info$control$dfsplit}. } \value{ An object of class \code{modelparty} where the associated tree is either the same as the original or smaller. } \seealso{ \code{\link[rpart]{prune}}, \code{\link{lmtree}}, \code{\link{glmtree}}, \code{\link{mob}} } \examples{ set.seed(29) n <- 1000 d <- data.frame( x = runif(n), z = runif(n), z_noise = factor(sample(1:3, size = n, replace = TRUE)) ) d$y <- rnorm(n, mean = d$x * c(-1, 1)[(d$z > 0.7) + 1], sd = 3) ## glm versus lm / logLik versus sum of squared residuals fmla <- y ~ x | z + z_noise lm_big <- lmtree(formula = fmla, data = d, maxdepth = 3, alpha = 1) glm_big <- glmtree(formula = fmla, data = d, maxdepth = 3, alpha = 1) AIC(lm_big) AIC(glm_big) ## load rpart for prune() generic ## (otherwise: use prune.modelparty directly) if (require("rpart")) { ## pruning lm_aic <- prune(lm_big, type = "AIC") lm_bic <- prune(lm_big, type = "BIC") width(lm_big) width(lm_aic) width(lm_bic) glm_aic <- prune(glm_big, type = "AIC") glm_bic <- prune(glm_big, type = "BIC") width(glm_big) width(glm_aic) width(glm_bic) } } partykit/man/ctree_control.Rd0000644000176200001440000002157414172230000016023 0ustar liggesusers\name{ctree_control} \alias{ctree_control} \title{ Control for Conditional Inference Trees } \description{ Various parameters that control aspects of the `ctree' fit. } \usage{ ctree_control(teststat = c("quadratic", "maximum"), splitstat = c("quadratic", "maximum"), splittest = FALSE, testtype = c("Bonferroni", "MonteCarlo", "Univariate", "Teststatistic"), pargs = GenzBretz(), nmax = c(yx = Inf, z = Inf), alpha = 0.05, mincriterion = 1 - alpha, logmincriterion = log(mincriterion), minsplit = 20L, minbucket = 7L, minprob = 0.01, stump = FALSE, maxvar = Inf, lookahead = FALSE, MIA = FALSE, nresample = 9999L, tol = sqrt(.Machine$double.eps),maxsurrogate = 0L, numsurrogate = FALSE, mtry = Inf, maxdepth = Inf, multiway = FALSE, splittry = 2L, intersplit = FALSE, majority = FALSE, caseweights = TRUE, applyfun = NULL, cores = NULL, saveinfo = TRUE, update = NULL, splitflavour = c("ctree", "exhaustive")) } \arguments{ \item{teststat}{ a character specifying the type of the test statistic to be applied for variable selection. } \item{splitstat}{ a character specifying the type of the test statistic to be applied for splitpoint selection. Prior to version 1.2-0, \code{maximum} was implemented only.} \item{splittest}{ a logical changing linear (the default \code{FALSE}) to maximally selected statistics for variable selection. Currently needs \code{testtype = "MonteCarlo"}.} \item{testtype}{ a character specifying how to compute the distribution of the test statistic. The first three options refer to p-values as criterion, \code{Teststatistic} uses the raw statistic as criterion. \code{Bonferroni} and \code{Univariate} relate to p-values from the asymptotic distribution (adjusted or unadjusted). Bonferroni-adjusted Monte-Carlo p-values are computed when both \code{Bonferroni} and \code{MonteCarlo} are given.} \item{pargs}{ control parameters for the computation of multivariate normal probabilities, see \code{\link[mvtnorm]{GenzBretz}}.} \item{nmax}{ an integer of length two defining the number of bins each variable (in the response \code{yx} and the partitioning variables \code{z})) and is divided into prior to tree building. The default \code{Inf} does not apply any binning. Highly experimental, use at your own risk.} \item{alpha}{ a double, the significance level for variable selection.} \item{mincriterion}{ the value of the test statistic or 1 - p-value that must be exceeded in order to implement a split. } \item{logmincriterion}{ the value of the test statistic or 1 - p-value that must be exceeded in order to implement a split on the log-scale. } \item{minsplit}{ the minimum sum of weights in a node in order to be considered for splitting. } \item{minbucket}{ the minimum sum of weights in a terminal node. } \item{minprob}{ proportion of observations needed to establish a terminal node.} \item{stump}{ a logical determining whether a stump (a tree with a maximum of three nodes only) is to be computed. } \item{maxvar}{ maximum number of variables the tree is allowed to split in.} \item{lookahead}{ a logical determining whether a split is implemented only after checking if tests in both daughter nodes can be performed.} \item{MIA}{ a logical determining the treatment of \code{NA} as a category in split, see Twala et al. (2008).} \item{nresample}{ number of permutations for \code{testtype = "MonteCarlo"}.} \item{tol}{tolerance for zero variances.} \item{maxsurrogate}{ number of surrogate splits to evaluate.} \item{numsurrogate}{ a logical for backward-compatibility with party. If \code{TRUE}, only at least ordered variables are considered for surrogate splits.} \item{mtry}{ number of input variables randomly sampled as candidates at each node for random forest like algorithms. The default \code{mtry = Inf} means that no random selection takes place. If \code{\link{ctree_control}} is used in \code{\link{cforest}} this argument is ignored.} \item{maxdepth}{ maximum depth of the tree. The default \code{maxdepth = Inf} means that no restrictions are applied to tree sizes.} \item{multiway}{ a logical indicating if multiway splits for all factor levels are implemented for unordered factors.} \item{splittry}{ number of variables that are inspected for admissible splits if the best split doesn't meet the sample size constraints.} \item{intersplit}{ a logical indicating if splits in numeric variables are simply \code{x <= a} (the default) or interpolated \code{x <= (a + b) / 2}. The latter feature is experimental, see Galili and Meilijson (2016).} \item{majority}{ if \code{FALSE} (the default), observations which can't be classified to a daughter node because of missing information are randomly assigned (following the node distribution). If \code{TRUE}, they go with the majority (the default in the first implementation \code{\link[party]{ctree}}) in package party.} \item{caseweights}{ a logical interpreting \code{weights} as case weights.} \item{applyfun}{an optional \code{\link[base]{lapply}}-style function with arguments \code{function(X, FUN, \dots)}. It is used for computing the variable selection criterion. The default is to use the basic \code{lapply} function unless the \code{cores} argument is specified (see below). If \code{\link{ctree_control}} is used in \code{\link{cforest}} this argument is ignored.} \item{cores}{numeric. If set to an integer the \code{applyfun} is set to \code{\link[parallel]{mclapply}} with the desired number of \code{cores}. If \code{\link{ctree_control}} is used in \code{\link{cforest}} this argument is ignored.} \item{saveinfo}{logical. Store information about variable selection procedure in \code{info} slot of each \code{partynode}.} \item{update}{logical. If \code{TRUE}, the data transformation is updated in every node. The default always was and still is not to update unless \code{ytrafo} is a function.} \item{splitflavour}{use exhaustive search over splits instead of maximally selected statistics (\code{ctree}). This feature may change.} } \details{ The arguments \code{teststat}, \code{testtype} and \code{mincriterion} determine how the global null hypothesis of independence between all input variables and the response is tested (see \code{\link{ctree}}). The variable with most extreme p-value or test statistic is selected for splitting. If this isn't possible due to sample size constraints explained in the next paragraph, up to \code{splittry} other variables are inspected for possible splits. A split is established when all of the following criteria are met: 1) the sum of the weights in the current node is larger than \code{minsplit}, 2) a fraction of the sum of weights of more than \code{minprob} will be contained in all daughter nodes, 3) the sum of the weights in all daughter nodes exceeds \code{minbucket}, and 4) the depth of the tree is smaller than \code{maxdepth}. This avoids pathological splits deep down the tree. When \code{stump = TRUE}, a tree with at most two terminal nodes is computed. The argument \code{mtry > 0} means that a random forest like `variable selection', i.e., a random selection of \code{mtry} input variables, is performed in each node. In each inner node, \code{maxsurrogate} surrogate splits are computed (regardless of any missing values in the learning sample). Factors in test samples whose levels were empty in the learning sample are treated as missing when computing predictions (in contrast to \code{\link[party]{ctree}}. Note also the different behaviour of \code{majority} in the two implementations. } \value{ A list. } \references{ B. E. T. H. Twala, M. C. Jones, and D. J. Hand (2008), Good Methods for Coping with Missing Data in Decision Trees, \emph{Pattern Recognition Letters}, \bold{29}(7), 950--956. Tal Galili, Isaac Meilijson (2016), Splitting Matters: How Monotone Transformation of Predictor Variables May Improve the Predictions of Decision Tree Models, \url{https://arxiv.org/abs/1611.04561}. } \keyword{misc} partykit/man/cforest.Rd0000644000176200001440000003362514415223717014647 0ustar liggesusers\name{cforest} \alias{cforest} \alias{gettree} \alias{gettree.cforest} \alias{predict.cforest} \encoding{latin1} \title{Conditional Random Forests} \description{ An implementation of the random forest and bagging ensemble algorithms utilizing conditional inference trees as base learners. } \usage{ cforest(formula, data, weights, subset, offset, cluster, strata, na.action = na.pass, control = ctree_control(teststat = "quad", testtype = "Univ", mincriterion = 0, saveinfo = FALSE, \dots), ytrafo = NULL, scores = NULL, ntree = 500L, perturb = list(replace = FALSE, fraction = 0.632), mtry = ceiling(sqrt(nvar)), applyfun = NULL, cores = NULL, trace = FALSE, \dots) \method{predict}{cforest}(object, newdata = NULL, type = c("response", "prob", "weights", "node"), OOB = FALSE, FUN = NULL, simplify = TRUE, scale = TRUE, \dots) \method{gettree}{cforest}(object, tree = 1L, \dots) } \arguments{ \item{formula}{ a symbolic description of the model to be fit. } \item{data}{ a data frame containing the variables in the model. } \item{subset}{ an optional vector specifying a subset of observations to be used in the fitting process.} \item{weights}{ an optional vector of weights to be used in the fitting process. Non-negative integer valued weights are allowed as well as non-negative real weights. Observations are sampled (with or without replacement) according to probabilities \code{weights / sum(weights)}. The fraction of observations to be sampled (without replacement) is computed based on the sum of the weights if all weights are integer-valued and based on the number of weights greater zero else. Alternatively, \code{weights} can be a double matrix defining case weights for all \code{ncol(weights)} trees in the forest directly. This requires more storage but gives the user more control.} \item{offset}{ an optional vector of offset values.} \item{cluster}{ an optional factor indicating independent clusters. Highly experimental, use at your own risk.} \item{strata}{ an optional factor for stratified sampling.} \item{na.action}{a function which indicates what should happen when the data contain missing value.} \item{control}{a list with control parameters, see \code{\link{ctree_control}}. The default values correspond to those of the default values used by \code{\link[party]{cforest}} from the \code{party} package. \code{saveinfo = FALSE} leads to less memory hungry representations of trees. Note that arguments \code{mtry}, \code{cores} and \code{applyfun} in \code{\link{ctree_control}} are ignored for \code{\link{cforest}}, because they are already set.} \item{ytrafo}{an optional named list of functions to be applied to the response variable(s) before testing their association with the explanatory variables. Note that this transformation is only performed once for the root node and does not take weights into account (which means, the forest bootstrap or subsetting is ignored, which is almost certainly not a good idea). Alternatively, \code{ytrafo} can be a function of \code{data} and \code{weights}. In this case, the transformation is computed for every node and the corresponding weights. This feature is experimental and the user interface likely to change.} \item{scores}{an optional named list of scores to be attached to ordered factors.} \item{ntree}{ Number of trees to grow for the forest.} \item{perturb}{ a list with arguments \code{replace} and \code{fraction} determining which type of resampling with \code{replace = TRUE} referring to the n-out-of-n bootstrap and \code{replace = FALSE} to sample splitting. \code{fraction} is the portion of observations to draw without replacement. Honesty (experimental): If \code{fraction} has two elements, the first fraction defines the portion of observations to be used for tree induction, the second fraction defines the portion of observations used for parameter estimation. The sum of both fractions can be smaller than one but most not exceed one. Details can be found in Section 2.4 of Wager and Athey (2018).} \item{mtry}{ number of input variables randomly sampled as candidates at each node for random forest like algorithms. Bagging, as special case of a random forest without random input variable sampling, can be performed by setting \code{mtry} either equal to \code{Inf} or manually equal to the number of input variables.} \item{applyfun}{an optional \code{\link[base]{lapply}}-style function with arguments \code{function(X, FUN, \dots)}. It is used for computing the variable selection criterion. The default is to use the basic \code{lapply} function unless the \code{cores} argument is specified (see below).} \item{cores}{numeric. If set to an integer the \code{applyfun} is set to \code{\link[parallel]{mclapply}} with the desired number of \code{cores}.} \item{trace}{a logical indicating if a progress bar shall be printed while the forest grows.} \item{object}{ An object as returned by \code{cforest}} \item{newdata}{ An optional data frame containing test data.} \item{type}{ a character string denoting the type of predicted value returned, ignored when argument \code{FUN} is given. For \code{"response"}, the mean of a numeric response, the predicted class for a categorical response or the median survival time for a censored response is returned. For \code{"prob"} the matrix of conditional class probabilities (\code{simplify = TRUE}) or a list with the conditional class probabilities for each observation (\code{simplify = FALSE}) is returned for a categorical response. For numeric and censored responses, a list with the empirical cumulative distribution functions and empirical survivor functions (Kaplan-Meier estimate) is returned when \code{type = "prob"}. \code{"weights"} returns an integer vector of prediction weights. For \code{type = "where"}, a list of terminal node ids for each of the trees in the forest ist returned.} \item{OOB}{ a logical defining out-of-bag predictions (only if \code{newdata = NULL}). If the forest was fitted with honesty, this option is ignored.} \item{FUN}{ a function to compute summary statistics. Predictions for each node have to be computed based on arguments \code{(y, w)} where \code{y} is the response and \code{w} are case weights.} \item{simplify}{ a logical indicating whether the resulting list of predictions should be converted to a suitable vector or matrix (if possible).} \item{scale}{a logical indicating scaling of the nearest neighbor weights by the sum of weights in the corresponding terminal node of each tree. In the simple regression forest, predicting the conditional mean by nearest neighbor weights will be equivalent to (but slower!) the aggregation of means.} \item{tree}{ an integer, the number of the tree to extract from the forest.} \item{\dots}{ additional arguments. } } \details{ This implementation of the random forest (and bagging) algorithm differs from the reference implementation in \code{\link[randomForest]{randomForest}} with respect to the base learners used and the aggregation scheme applied. Conditional inference trees, see \code{\link{ctree}}, are fitted to each of the \code{ntree} perturbed samples of the learning sample. Most of the hyper parameters in \code{\link{ctree_control}} regulate the construction of the conditional inference trees. Hyper parameters you might want to change are: 1. The number of randomly preselected variables \code{mtry}, which is fixed to the square root of the number of input variables. 2. The number of trees \code{ntree}. Use more trees if you have more variables. 3. The depth of the trees, regulated by \code{mincriterion}. Usually unstopped and unpruned trees are used in random forests. To grow large trees, set \code{mincriterion} to a small value. The aggregation scheme works by averaging observation weights extracted from each of the \code{ntree} trees and NOT by averaging predictions directly as in \code{\link[randomForest]{randomForest}}. See Hothorn et al. (2004) and Meinshausen (2006) for a description. Predictions can be computed using \code{\link{predict}}. For observations with zero weights, predictions are computed from the fitted tree when \code{newdata = NULL}. Ensembles of conditional inference trees have not yet been extensively tested, so this routine is meant for the expert user only and its current state is rather experimental. However, there are some things available in \code{\link{cforest}} that can't be done with \code{\link[randomForest]{randomForest}}, for example fitting forests to censored response variables (see Hothorn et al., 2004, 2006a) or to multivariate and ordered responses. Using the rich \code{partykit} infrastructure allows additional functionality in \code{cforest}, such as parallel tree growing and probabilistic forecasting (for example via quantile regression forests). Also plotting of single trees from a forest is much easier now. Unlike \code{\link[party]{cforest}}, \code{cforest} is entirely written in R which makes customisation much easier at the price of longer computing times. However, trees can be grown in parallel with this R only implemention which renders speed less of an issue. Note that the default values are different from those used in package \code{party}, most importantly the default for mtry is now data-dependent. \code{predict(, type = "node")} replaces the \code{\link[party]{where}} function and \code{predict(, type = "prob")} the \code{\link[party]{treeresponse}} function. Moreover, when predictors vary in their scale of measurement of number of categories, variable selection and computation of variable importance is biased in favor of variables with many potential cutpoints in \code{\link[randomForest]{randomForest}}, while in \code{\link{cforest}} unbiased trees and an adequate resampling scheme are used by default. See Hothorn et al. (2006b) and Strobl et al. (2007) as well as Strobl et al. (2009). } \value{ An object of class \code{cforest}. } \references{ Breiman L (2001). Random Forests. \emph{Machine Learning}, \bold{45}(1), 5--32. Hothorn T, Lausen B, Benner A, Radespiel-Troeger M (2004). Bagging Survival Trees. \emph{Statistics in Medicine}, \bold{23}(1), 77--91. Hothorn T, Buehlmann P, Dudoit S, Molinaro A, Van der Laan MJ (2006a). Survival Ensembles. \emph{Biostatistics}, \bold{7}(3), 355--373. Hothorn T, Hornik K, Zeileis A (2006b). Unbiased Recursive Partitioning: A Conditional Inference Framework. \emph{Journal of Computational and Graphical Statistics}, \bold{15}(3), 651--674. Hothorn T, Zeileis A (2015). partykit: A Modular Toolkit for Recursive Partytioning in R. \emph{Journal of Machine Learning Research}, \bold{16}, 3905--3909. Meinshausen N (2006). Quantile Regression Forests. \emph{Journal of Machine Learning Research}, \bold{7}, 983--999. Strobl C, Boulesteix AL, Zeileis A, Hothorn T (2007). Bias in Random Forest Variable Importance Measures: Illustrations, Sources and a Solution. \emph{BMC Bioinformatics}, \bold{8}, 25. \doi{10.1186/1471-2105-8-25} Strobl C, Malley J, Tutz G (2009). An Introduction to Recursive Partitioning: Rationale, Application, and Characteristics of Classification and Regression Trees, Bagging, and Random Forests. \emph{Psychological Methods}, \bold{14}(4), 323--348. Stefan Wager & Susan Athey (2018). Estimation and Inference of Heterogeneous Treatment Effects using Random Forests. \emph{Journal of the American Statistical Association}, \bold{113}(523), 1228--1242. \doi{10.1080/01621459.2017.1319839} } \examples{ ## basic example: conditional inference forest for cars data cf <- cforest(dist ~ speed, data = cars) ## prediction of fitted mean and visualization nd <- data.frame(speed = 4:25) nd$mean <- predict(cf, newdata = nd, type = "response") plot(dist ~ speed, data = cars) lines(mean ~ speed, data = nd) ## predict quantiles (aka quantile regression forest) myquantile <- function(y, w) quantile(rep(y, w), probs = c(0.1, 0.5, 0.9)) p <- predict(cf, newdata = nd, type = "response", FUN = myquantile) colnames(p) <- c("lower", "median", "upper") nd <- cbind(nd, p) ## visualization with conditional (on speed) prediction intervals plot(dist ~ speed, data = cars, type = "n") with(nd, polygon(c(speed, rev(speed)), c(lower, rev(upper)), col = "lightgray", border = "transparent")) points(dist ~ speed, data = cars) lines(mean ~ speed, data = nd, lwd = 1.5) lines(median ~ speed, data = nd, lty = 2, lwd = 1.5) legend("topleft", c("mean", "median", "10\% - 90\% quantile"), lwd = c(1.5, 1.5, 10), lty = c(1, 2, 1), col = c("black", "black", "lightgray"), bty = "n") \dontrun{ ### honest (i.e., out-of-bag) cross-classification of ### true vs. predicted classes data("mammoexp", package = "TH.data") table(mammoexp$ME, predict(cforest(ME ~ ., data = mammoexp, ntree = 50), OOB = TRUE, type = "response")) ### fit forest to censored response if (require("TH.data") && require("survival")) { data("GBSG2", package = "TH.data") bst <- cforest(Surv(time, cens) ~ ., data = GBSG2, ntree = 50) ### estimate conditional Kaplan-Meier curves print(predict(bst, newdata = GBSG2[1:2,], OOB = TRUE, type = "prob")) print(gettree(bst)) } } } \keyword{tree} partykit/man/nodeids.Rd0000644000176200001440000000442214172230000014577 0ustar liggesusers\name{nodeids} \alias{nodeids} \alias{nodeids.party} \alias{nodeids.partynode} \alias{get_paths} \title{ Extract Node Identifiers } \description{ Extract unique identifiers from inner and terminals nodes of a \code{partynode} object. } \usage{ nodeids(obj, \dots) \method{nodeids}{partynode}(obj, from = NULL, terminal = FALSE, \dots) \method{nodeids}{party}(obj, from = NULL, terminal = FALSE, \dots) get_paths(obj, i) } \arguments{ \item{obj}{ an object of class \code{\link{partynode}} or \code{\link{party}}.} \item{from}{ an integer specifying node to start from.} \item{terminal}{ logical specifying if only node identifiers of terminal nodes are returned. } \item{i}{a vector of node identifiers.} \item{\dots}{ additional arguments.} } \details{ The identifiers of each node are extracted from \code{nodeids}. \code{get_paths} returns the paths for extracting the corresponding nodes using list subsets. } \value{ A vector of node identifiers. } \examples{ ## a tree as flat list structure nodelist <- list( # root node list(id = 1L, split = partysplit(varid = 4L, breaks = 1.9), kids = 2:3), # V4 <= 1.9, terminal node list(id = 2L), # V4 > 1.9 list(id = 3L, split = partysplit(varid = 1L, breaks = 1.7), kids = c(4L, 7L)), # V1 <= 1.7 list(id = 4L, split = partysplit(varid = 4L, breaks = 4.8), kids = 5:6), # V4 <= 4.8, terminal node list(id = 5L), # V4 > 4.8, terminal node list(id = 6L), # V1 > 1.7, terminal node list(id = 7L) ) ## convert to a recursive structure node <- as.partynode(nodelist) ## set up party object data("iris") tree <- party(node, data = iris, fitted = data.frame("(fitted)" = fitted_node(node, data = iris), check.names = FALSE)) tree ### ids of all nodes nodeids(tree) ### ids of all terminal nodes nodeids(tree, terminal = TRUE) ### ids of terminal nodes in subtree with root [3] nodeids(tree, from = 3, terminal = TRUE) ### get paths and extract all terminal nodes tr <- unclass(node_party(tree)) lapply(get_paths(tree, nodeids(tree, terminal = TRUE)), function(path) tr[path]) } \keyword{tree} partykit/man/extree_fit.Rd0000644000176200001440000000313514172230000015310 0ustar liggesusers\name{extree_fit} \alias{extree_fit} %- Also NEED an '\alias' for EACH other topic documented here. \title{ Fit Extensible Trees. } \description{ Basic infrastructure for fitting extensible trees. } \usage{ extree_fit(data, trafo, converged, selectfun = ctrl$selectfun, splitfun = ctrl$splitfun, svselectfun = ctrl$svselectfun, svsplitfun = ctrl$svsplitfun, partyvars, subset, weights, ctrl, doFit = TRUE) } \arguments{ \item{data}{an object of class \code{extree_data}, see \code{\link{extree_data}}. } \item{trafo}{a function with arguments \code{subset}, \code{weights}, \code{info}, \code{estfun} and \code{object}. } \item{converged}{a function with arguments \code{subset}, \code{weights}. } \item{selectfun}{an optional function for selecting variables. } \item{splitfun}{an optional function for selecting splits. } \item{svselectfun}{an optional function for selecting surrogate variables. } \item{svsplitfun}{an optional function for selecting surrogate splits. } \item{partyvars}{a numeric vector assigning a weight to each partitioning variable (\code{z} in \code{\link{extree_data}}. } \item{subset}{a sorted integer vector describing a subset. } \item{weights}{an optional vector of weights. } \item{ctrl}{control arguments. } \item{doFit}{a logical indicating if the tree shall be grown (\code{TRUE}) or not \code{FALSE}. } } \details{ This internal functionality will be the basis of implementations of other tree algorithms in future versions. Currently, only \code{ctree} relies on this function. } \value{An object of class \code{partynode}.} \keyword{tree} partykit/man/partysplit.Rd0000644000176200001440000001460214172230000015366 0ustar liggesusers\name{partysplit} \alias{partysplit} \alias{kidids_split} \alias{character_split} \alias{varid_split} \alias{breaks_split} \alias{index_split} \alias{right_split} \alias{prob_split} \alias{info_split} \title{ Binary and Multiway Splits } \description{ A class for representing multiway splits and functions for computing on splits. } \usage{ partysplit(varid, breaks = NULL, index = NULL, right = TRUE, prob = NULL, info = NULL) kidids_split(split, data, vmatch = 1:length(data), obs = NULL) character_split(split, data = NULL, digits = getOption("digits") - 2) varid_split(split) breaks_split(split) index_split(split) right_split(split) prob_split(split) info_split(split) } \arguments{ \item{varid}{ an integer specifying the variable to split in, i.e., a column number in \code{data}. } \item{breaks}{ a numeric vector of split points. } \item{index}{ an integer vector containing a contiguous sequence from one to the number of kid nodes. May contain \code{NA}s.} \item{right}{ a logical, indicating if the intervals defined by \code{breaks} should be closed on the right (and open on the left) or vice versa.} \item{prob}{ a numeric vector representing a probability distribution over kid nodes. } \item{info}{ additional information. } \item{split}{ an object of class \code{partysplit}.} \item{data}{ a \code{\link{list}} or \code{\link{data.frame}}.} \item{vmatch}{ a permutation of the variable numbers in \code{data}.} \item{obs}{ a logical or integer vector indicating a subset of the observations in \code{data}.} \item{digits}{ minimal number of significant digits.} } \details{ A split is basically a function that maps data, more specifically a partitioning variable, to a set of integers indicating the kid nodes to send observations to. Objects of class \code{partysplit} describe such a function and can be set-up via the \code{partysplit()} constructor. The variables are available in a \code{list} or \code{data.frame} (here called \code{data}) and \code{varid} specifies the partitioning variable, i.e., the variable or list element to split in. The constructor \code{partysplit()} doesn't have access to the actual data, i.e., doesn't \emph{estimate} splits. \code{kidids_split(split, data)} actually partitions the data \code{data[obs,varid_split(split)]} and assigns an integer (giving the kid node number) to each observation. If \code{vmatch} is given, the variable \code{vmatch[varid_split(split)]} is used. \code{character_split()} returns a character representation of its \code{split} argument. The remaining functions defined here are accessor functions for \code{partysplit} objects. The numeric vector \code{breaks} defines how the range of the partitioning variable (after coercing to a numeric via \code{\link{as.numeric}}) is divided into intervals (like in \code{\link{cut}}) and may be \code{NULL}. These intervals are represented by the numbers one to \code{length(breaks) + 1}. \code{index} assigns these \code{length(breaks) + 1} intervals to one of at least two kid nodes. Thus, \code{index} is a vector of integers where each element corresponds to one element in a list \code{kids} containing \code{\link{partynode}} objects, see \code{\link{partynode}} for details. The vector \code{index} may contain \code{NA}s, in that case, the corresponding values of the splitting variable are treated as missings (for example factor levels that are not present in the learning sample). Either \code{breaks} or \code{index} must be given. When \code{breaks} is \code{NULL}, it is assumed that the partitioning variable itself has storage mode \code{integer} (e.g., is a \code{\link{factor}}). \code{prob} defines a probability distribution over all kid nodes which is used for random splitting when a deterministic split isn't possible (due to missing values, for example). \code{info} takes arbitrary user-specified information. } \value{ The constructor \code{partysplit()} returns an object of class \code{partysplit}: \item{varid}{ an integer specifying the variable to split in, i.e., a column number in \code{data}, } \item{breaks}{ a numeric vector of split points, } \item{index}{ an integer vector containing a contiguous sequence from one to the number of kid nodes,} \item{right}{ a logical, indicating if the intervals defined by \code{breaks} should be closed on the right (and open on the left) or vice versa} \item{prob}{ a numeric vector representing a probability distribution over kid nodes, } \item{info}{ additional information. } \code{kidids_split()} returns an integer vector describing the partition of the observations into kid nodes. \code{character_split()} gives a character representation of the split and the remaining functions return the corresponding slots of \code{partysplit} objects. } \seealso{\code{\link{cut}}} \references{ Hothorn T, Zeileis A (2015). partykit: A Modular Toolkit for Recursive Partytioning in R. \emph{Journal of Machine Learning Research}, \bold{16}, 3905--3909. } \examples{ data("iris", package = "datasets") ## binary split in numeric variable `Sepal.Length' sl5 <- partysplit(which(names(iris) == "Sepal.Length"), breaks = 5) character_split(sl5, data = iris) table(kidids_split(sl5, data = iris), iris$Sepal.Length <= 5) ## multiway split in numeric variable `Sepal.Width', ## higher values go to the first kid, smallest values ## to the last kid sw23 <- partysplit(which(names(iris) == "Sepal.Width"), breaks = c(3, 3.5), index = 3:1) character_split(sw23, data = iris) table(kidids_split(sw23, data = iris), cut(iris$Sepal.Width, breaks = c(-Inf, 2, 3, Inf))) ## binary split in factor `Species' sp <- partysplit(which(names(iris) == "Species"), index = c(1L, 1L, 2L)) character_split(sp, data = iris) table(kidids_split(sp, data = iris), iris$Species) ## multiway split in factor `Species' sp <- partysplit(which(names(iris) == "Species"), index = 1:3) character_split(sp, data = iris) table(kidids_split(sp, data = iris), iris$Species) ## multiway split in numeric variable `Sepal.Width' sp <- partysplit(which(names(iris) == "Sepal.Width"), breaks = quantile(iris$Sepal.Width)) character_split(sp, data = iris) } \keyword{tree} partykit/man/model.frame.rpart.Rd0000644000176200001440000000104014172230000016463 0ustar liggesusers\name{model_frame_rpart} \alias{model_frame_rpart} \title{ Model Frame Method for rpart } \description{ A model.frame method for rpart objects. } \usage{ model_frame_rpart(formula, \dots) } \arguments{ \item{formula}{ an object of class \code{\link{rpart}}.} \item{\dots}{ additional arguments.} } \details{ A \code{\link{model.frame}} method for \code{\link{rpart}} objects. Because it is no longer possible to overwrite existing methods, the function name is a little different here. } \value{ A model frame. } \keyword{tree} partykit/man/party.Rd0000644000176200001440000001350614172230000014314 0ustar liggesusers\name{party} \alias{party} \alias{names.party} \alias{names<-.party} \alias{node_party} \alias{is.constparty} \alias{is.simpleparty} \alias{data_party} \alias{data_party.default} \title{ Recursive Partytioning } \description{ A class for representing decision trees and corresponding accessor functions. } \usage{ party(node, data, fitted = NULL, terms = NULL, names = NULL, info = NULL) \method{names}{party}(x) \method{names}{party}(x) <- value data_party(party, id = 1L) \method{data_party}{default}(party, id = 1L) node_party(party) is.constparty(party) is.simpleparty(party) } \arguments{ \item{node}{ an object of class \code{\link{partynode}}.} \item{data}{ a (potentially empty) \code{\link{data.frame}}.} \item{fitted}{ an optional \code{\link{data.frame}} with \code{nrow(data)} rows (only if \code{nrow(data) != 0} and containing at least the fitted terminal node identifiers as element \code{(fitted)}. In addition, weights may be contained as element \code{(weights)} and responses as \code{(response)}.} \item{terms}{ an optional \code{\link{terms}} object. } \item{names}{ an optional vector of names to be assigned to each node of \code{node}. } \item{info}{ additional information. } \item{x}{ an object of class \code{party}.} \item{party}{ an object of class \code{party}.} \item{value}{a character vector of up to the same length as \code{x}, or \code{NULL}.} \item{id}{ a node identifier.} } \details{ Objects of class \code{party} basically consist of a \code{\link{partynode}} object representing the tree structure in a recursive way and data. The \code{data} argument takes a \code{data.frame} which, however, might have zero columns. Optionally, a \code{data.frame} with at least one variable \code{(fitted)} containing the terminal node numbers of data used for fitting the tree may be specified along with a \code{\link{terms}} object or any additional (currently unstructured) information as \code{info}. Argument \code{names} defines names for all nodes in \code{node}. Method \code{names} can be used to extract or alter names for nodes. Function \code{node_party} returns the \code{node} element of a \code{party} object. Further methods for \code{party} objects are documented in \code{\link{party-methods}} and \code{\link{party-predict}}. Trees of various flavors can be coerced to \code{party}, see \code{\link{party-coercion}}. Two classes inherit from class \code{party} and impose additional assumptions on the structure of this object: Class \code{constparty} requires that the \code{fitted} slot contains a partitioning of the learning sample as a factor \code{("fitted")} and the response values of all observations in the learning sample as \code{("response")}. This structure is most flexible and allows for graphical display of the response values in terminal nodes as well as for computing predictions based on arbitrary summary statistics. Class \code{simpleparty} assumes that certain pre-computed information about the distribution of the response variable is contained in the \code{info} slot nodes. At the moment, no formal class is used to describe this information. } \value{ The constructor returns an object of class \code{party}: \item{node}{ an object of class \code{\link{partynode}}.} \item{data}{ a (potentially empty) \code{\link{data.frame}}.} \item{fitted}{ an optional \code{\link{data.frame}} with \code{nrow(data)} rows (only if \code{nrow(data) != 0} and containing at least the fitted terminal node identifiers as element \code{(fitted)}. In addition, weights may be contained as element \code{(weights)} and responses as \code{(response)}.} \item{terms}{ an optional \code{\link{terms}} object. } \item{names}{ an optional vector of names to be assigned to each node of \code{node}. } \item{info}{ additional information. } \code{names} can be used to set and retrieve names of nodes and \code{node_party} returns an object of class \code{\link{partynode}}. \code{data_party} returns a data frame with observations contained in node \code{id}. } \references{ Hothorn T, Zeileis A (2015). partykit: A Modular Toolkit for Recursive Partytioning in R. \emph{Journal of Machine Learning Research}, \bold{16}, 3905--3909. } \examples{ ### data ### ## artificial WeatherPlay data data("WeatherPlay", package = "partykit") str(WeatherPlay) ### splits ### ## split in overcast, humidity, and windy sp_o <- partysplit(1L, index = 1:3) sp_h <- partysplit(3L, breaks = 75) sp_w <- partysplit(4L, index = 1:2) ## query labels character_split(sp_o) ### nodes ### ## set up partynode structure pn <- partynode(1L, split = sp_o, kids = list( partynode(2L, split = sp_h, kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = sp_w, kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))) pn ### tree ### ## party: associate recursive partynode structure with data py <- party(pn, WeatherPlay) py plot(py) ### variations ### ## tree stump n1 <- partynode(id = 1L, split = sp_o, kids = lapply(2L:4L, partynode)) print(n1, data = WeatherPlay) ## query fitted nodes and kids ids fitted_node(n1, data = WeatherPlay) kidids_node(n1, data = WeatherPlay) ## tree with full data sets t1 <- party(n1, data = WeatherPlay) ## tree with empty data set party(n1, data = WeatherPlay[0, ]) ## constant-fit tree t2 <- party(n1, data = WeatherPlay, fitted = data.frame( "(fitted)" = fitted_node(n1, data = WeatherPlay), "(response)" = WeatherPlay$play, check.names = FALSE), terms = terms(play ~ ., data = WeatherPlay), ) t2 <- as.constparty(t2) t2 plot(t2) } \keyword{tree} partykit/man/ctree.Rd0000644000176200001440000001727614172230000014267 0ustar liggesusers\name{ctree} \alias{ctree} \alias{sctest.constparty} \title{Conditional Inference Trees} \description{ Recursive partitioning for continuous, censored, ordered, nominal and multivariate response variables in a conditional inference framework. } \usage{ ctree(formula, data, subset, weights, na.action = na.pass, offset, cluster, control = ctree_control(\dots), ytrafo = NULL, converged = NULL, scores = NULL, doFit = TRUE, \dots) } \arguments{ \item{formula}{ a symbolic description of the model to be fit. } \item{data}{ a data frame containing the variables in the model. } \item{subset}{ an optional vector specifying a subset of observations to be used in the fitting process.} \item{weights}{ an optional vector of weights to be used in the fitting process. Only non-negative integer valued weights are allowed.} \item{offset}{ an optional vector of offset values.} \item{cluster}{ an optional factor indicating independent clusters. Highly experimental, use at your own risk.} \item{na.action}{a function which indicates what should happen when the data contain missing value.} \item{control}{a list with control parameters, see \code{\link{ctree_control}}.} \item{ytrafo}{an optional named list of functions to be applied to the response variable(s) before testing their association with the explanatory variables. Note that this transformation is only performed once for the root node and does not take weights into account. Alternatively, \code{ytrafo} can be a function of \code{data} and \code{weights}. In this case, the transformation is computed for every node with corresponding weights. This feature is experimental and the user interface likely to change.} \item{converged}{an optional function for checking user-defined criteria before splits are implemented. This is not to be used and very likely to change.} \item{scores}{an optional named list of scores to be attached to ordered factors.} \item{doFit}{a logical, if \code{FALSE}, the tree is not fitted.} \item{\dots}{arguments passed to \code{\link{ctree_control}}.} } \details{ Function \code{partykit::ctree} is a reimplementation of (most of) \code{party::ctree} employing the new \code{\link{party}} infrastructure of the \pkg{partykit} infrastructure. The vignette \code{vignette("ctree", package = "partykit")} explains internals of the different implementations. Conditional inference trees estimate a regression relationship by binary recursive partitioning in a conditional inference framework. Roughly, the algorithm works as follows: 1) Test the global null hypothesis of independence between any of the input variables and the response (which may be multivariate as well). Stop if this hypothesis cannot be rejected. Otherwise select the input variable with strongest association to the response. This association is measured by a p-value corresponding to a test for the partial null hypothesis of a single input variable and the response. 2) Implement a binary split in the selected input variable. 3) Recursively repeate steps 1) and 2). The implementation utilizes a unified framework for conditional inference, or permutation tests, developed by Strasser and Weber (1999). The stop criterion in step 1) is either based on multiplicity adjusted p-values (\code{testtype = "Bonferroni"} in \code{\link{ctree_control}}) or on the univariate p-values (\code{testtype = "Univariate"}). In both cases, the criterion is maximized, i.e., 1 - p-value is used. A split is implemented when the criterion exceeds the value given by \code{mincriterion} as specified in \code{\link{ctree_control}}. For example, when \code{mincriterion = 0.95}, the p-value must be smaller than $0.05$ in order to split this node. This statistical approach ensures that the right-sized tree is grown without additional (post-)pruning or cross-validation. The level of \code{mincriterion} can either be specified to be appropriate for the size of the data set (and \code{0.95} is typically appropriate for small to moderately-sized data sets) or could potentially be treated like a hyperparameter (see Section~3.4 in Hothorn, Hornik and Zeileis, 2006). The selection of the input variable to split in is based on the univariate p-values avoiding a variable selection bias towards input variables with many possible cutpoints. The test statistics in each of the nodes can be extracted with the \code{sctest} method. (Note that the generic is in the \pkg{strucchange} package so this either needs to be loaded or \code{sctest.constparty} has to be called directly.) In cases where splitting stops due to the sample size (e.g., \code{minsplit} or \code{minbucket} etc.), the test results may be empty. Predictions can be computed using \code{\link{predict}}, which returns predicted means, predicted classes or median predicted survival times and more information about the conditional distribution of the response, i.e., class probabilities or predicted Kaplan-Meier curves. For observations with zero weights, predictions are computed from the fitted tree when \code{newdata = NULL}. By default, the scores for each ordinal factor \code{x} are \code{1:length(x)}, this may be changed for variables in the formula using \code{scores = list(x = c(1, 5, 6))}, for example. For a general description of the methodology see Hothorn, Hornik and Zeileis (2006) and Hothorn, Hornik, van de Wiel and Zeileis (2006). } \value{ An object of class \code{\link{party}}. } \references{ Hothorn T, Hornik K, Van de Wiel MA, Zeileis A (2006). A Lego System for Conditional Inference. \emph{The American Statistician}, \bold{60}(3), 257--263. Hothorn T, Hornik K, Zeileis A (2006). Unbiased Recursive Partitioning: A Conditional Inference Framework. \emph{Journal of Computational and Graphical Statistics}, \bold{15}(3), 651--674. Hothorn T, Zeileis A (2015). partykit: A Modular Toolkit for Recursive Partytioning in R. \emph{Journal of Machine Learning Research}, \bold{16}, 3905--3909. Strasser H, Weber C (1999). On the Asymptotic Theory of Permutation Statistics. \emph{Mathematical Methods of Statistics}, \bold{8}, 220--250. } \examples{ ### regression airq <- subset(airquality, !is.na(Ozone)) airct <- ctree(Ozone ~ ., data = airq) airct plot(airct) mean((airq$Ozone - predict(airct))^2) ### classification irisct <- ctree(Species ~ .,data = iris) irisct plot(irisct) table(predict(irisct), iris$Species) ### estimated class probabilities, a list tr <- predict(irisct, newdata = iris[1:10,], type = "prob") ### survival analysis if (require("TH.data") && require("survival") && require("coin") && require("Formula")) { data("GBSG2", package = "TH.data") (GBSG2ct <- ctree(Surv(time, cens) ~ ., data = GBSG2)) predict(GBSG2ct, newdata = GBSG2[1:2,], type = "response") plot(GBSG2ct) ### with weight-dependent log-rank scores ### log-rank trafo for observations in this node only (= weights > 0) h <- function(y, x, start = NULL, weights, offset, estfun = TRUE, object = FALSE, ...) { if (is.null(weights)) weights <- rep(1, NROW(y)) s <- logrank_trafo(y[weights > 0,,drop = FALSE]) r <- rep(0, length(weights)) r[weights > 0] <- s list(estfun = matrix(as.double(r), ncol = 1), converged = TRUE) } ### very much the same tree (ctree(Surv(time, cens) ~ ., data = GBSG2, ytrafo = h)) } ### multivariate responses airct2 <- ctree(Ozone + Temp ~ ., data = airq) airct2 plot(airct2) } \keyword{tree} partykit/man/varimp.Rd0000644000176200001440000001207414172230000014452 0ustar liggesusers\name{varimp} \alias{varimp} \alias{varimp.constparty} \alias{varimp.cforest} \title{ Variable Importance } \description{ Standard and conditional variable importance for `cforest', following the permutation principle of the `mean decrease in accuracy' importance in `randomForest'. } \usage{ \method{varimp}{constparty}(object, nperm = 1L, risk = c("loglik", "misclassification"), conditions = NULL, mincriterion = 0, ...) \method{varimp}{cforest}(object, nperm = 1L, OOB = TRUE, risk = c("loglik", "misclassification"), conditional = FALSE, threshold = .2, applyfun = NULL, cores = NULL, ...) } \arguments{ \item{object}{ an object as returned by \code{cforest}.} \item{mincriterion}{ the value of the test statistic or 1 - p-value that must be exceeded in order to include a split in the computation of the importance. The default \code{mincriterion = 0} guarantees that all splits are included.} \item{conditional}{ a logical determining whether unconditional or conditional computation of the importance is performed. } \item{threshold}{ the value of the test statistic or 1 - p-value of the association between the variable of interest and a covariate that must be exceeded inorder to include the covariate in the conditioning scheme for the variable of interest (only relevant if \code{conditional = TRUE}). } \item{nperm}{ the number of permutations performed.} \item{OOB}{ a logical determining whether the importance is computed from the out-of-bag sample or the learning sample (not suggested).} \item{risk}{ a character determining the risk to be evaluated.} \item{conditions}{ a list of conditions. } \item{applyfun}{an optional \code{\link[base]{lapply}}-style function with arguments \code{function(X, FUN, \dots)}. It is used for computing the variable importances for each tree. The default is to use the basic \code{lapply} function unless the \code{cores} argument is specified (see below). Extra care is needed to ensure correct seeds are used in the parallel runs (\code{RNGkind("L'Ecuyer-CMRG")} for example).} \item{cores}{numeric. If set to an integer the \code{applyfun} is set to \code{\link[parallel]{mclapply}} with the desired number of \code{cores}.} \item{\dots}{additional arguments, not used.} } \details{ NEEDS UPDATE Function \code{varimp} can be used to compute variable importance measures similar to those computed by \code{\link[randomForest]{importance}}. Besides the standard version, a conditional version is available, that adjusts for correlations between predictor variables. If \code{conditional = TRUE}, the importance of each variable is computed by permuting within a grid defined by the covariates that are associated (with 1 - p-value greater than \code{threshold}) to the variable of interest. The resulting variable importance score is conditional in the sense of beta coefficients in regression models, but represents the effect of a variable in both main effects and interactions. See Strobl et al. (2008) for details. Note, however, that all random forest results are subject to random variation. Thus, before interpreting the importance ranking, check whether the same ranking is achieved with a different random seed -- or otherwise increase the number of trees \code{ntree} in \code{\link{ctree_control}}. Note that in the presence of missings in the predictor variables the procedure described in Hapfelmeier et al. (2012) is performed. } \value{ A vector of `mean decrease in accuracy' importance scores. } \references{ Leo Breiman (2001). Random Forests. \emph{Machine Learning}, 45(1), 5--32. Alexander Hapfelmeier, Torsten Hothorn, Kurt Ulm, and Carolin Strobl (2014). A New Variable Importance Measure for Random Forests with Missing Data. \emph{Statistics and Computing}, \bold{24}(1), 21-34. \doi{10.1007/s11222-012-9349-1} Torsten Hothorn, Kurt Hornik, and Achim Zeileis (2006b). Unbiased Recursive Partitioning: A Conditional Inference Framework. \emph{Journal of Computational and Graphical Statistics}, \bold{15}(3), 651-674. \doi{10.1198/106186006X133933} Carolin Strobl, Anne-Laure Boulesteix, Thomas Kneib, Thomas Augustin, and Achim Zeileis (2008). Conditional Variable Importance for Random Forests. \emph{BMC Bioinformatics}, \bold{9}, 307. \doi{10.1186/1471-2105-8-25} } \examples{ set.seed(290875) data("readingSkills", package = "party") readingSkills.cf <- cforest(score ~ ., data = readingSkills, mtry = 2, ntree = 50) # standard importance varimp(readingSkills.cf) # conditional importance, may take a while... varimp(readingSkills.cf, conditional = TRUE) } \keyword{tree} partykit/man/party-methods.Rd0000644000176200001440000000745314172230000015761 0ustar liggesusers\name{party-methods} \alias{party-methods} \alias{length.party} \alias{print.party} \alias{print.simpleparty} \alias{print.constparty} \alias{[.party} \alias{[[.party} \alias{depth.party} \alias{width.party} \alias{getCall.party} \alias{nodeprune} \alias{nodeprune.party} \title{ Methods for Party Objects } \description{ Methods for computing on \code{party} objects. } \usage{ \method{print}{party}(x, terminal_panel = function(node) formatinfo_node(node, default = "*", prefix = ": "), tp_args = list(), inner_panel = function(node) "", ip_args = list(), header_panel = function(party) "", footer_panel = function(party) "", digits = getOption("digits") - 2, \dots) \method{print}{simpleparty}(x, digits = getOption("digits") - 4, header = NULL, footer = TRUE, \dots) \method{print}{constparty}(x, FUN = NULL, digits = getOption("digits") - 4, header = NULL, footer = TRUE, \dots) \method{length}{party}(x) \method{[}{party}(x, i, \dots) \method{[[}{party}(x, i, \dots) \method{depth}{party}(x, root = FALSE, \dots) \method{width}{party}(x, \dots) \method{nodeprune}{party}(x, ids, ...) } \arguments{ \item{x}{ an object of class \code{\link{party}}.} \item{i}{ an integer specifying the root of the subtree to extract.} \item{terminal_panel}{ a panel function for printing terminal nodes.} \item{tp_args}{ a list containing arguments to \code{terminal_panel}.} \item{inner_panel}{ a panel function for printing inner nodes.} \item{ip_args}{ a list containing arguments to \code{inner_panel}.} \item{header_panel}{ a panel function for printing the header.} \item{footer_panel}{ a panel function for printing the footer.} \item{digits}{ number of digits to be printed.} \item{header}{ header to be printed.} \item{footer}{ footer to be printed.} \item{FUN}{ a function to be applied to nodes.} \item{root}{ a logical. Should the root count be counted in \code{depth}? } \item{ids}{ a vector of node ids (or their names) to be pruned-off.} \item{\dots}{ additional arguments.} } \details{ \code{length} gives the number of nodes in the tree (in contrast to the \code{length} method for \code{\link{partynode}} objects which returns the number of kid nodes in the root), \code{depth} the depth of the tree and \code{width} the number of terminal nodes. The subset methods extract subtrees and the \code{print} method generates a textual representation of the tree. \code{nodeprune} prunes-off nodes and makes sure that the node ids of the resulting tree are in pre-order starting with root node id 1. For \code{constparty} objects, the \code{fitted} slot is also changed. } \examples{ ## a tree as flat list structure nodelist <- list( # root node list(id = 1L, split = partysplit(varid = 4L, breaks = 1.9), kids = 2:3), # V4 <= 1.9, terminal node list(id = 2L), # V4 > 1.9 list(id = 3L, split = partysplit(varid = 5L, breaks = 1.7), kids = c(4L, 7L)), # V5 <= 1.7 list(id = 4L, split = partysplit(varid = 4L, breaks = 4.8), kids = 5:6), # V4 <= 4.8, terminal node list(id = 5L), # V4 > 4.8, terminal node list(id = 6L), # V5 > 1.7, terminal node list(id = 7L) ) ## convert to a recursive structure node <- as.partynode(nodelist) ## set up party object data("iris") tree <- party(node, data = iris, fitted = data.frame("(fitted)" = fitted_node(node, data = iris), check.names = FALSE)) names(tree) <- paste("Node", nodeids(tree), sep = " ") ## number of kids in root node length(tree) ## depth of tree depth(tree) ## number of terminal nodes width(tree) ## node number four tree["Node 4"] tree[["Node 4"]] } \keyword{tree} partykit/man/lmtree.Rd0000644000176200001440000001156214172230000014445 0ustar liggesusers\name{lmtree} \alias{lmtree} \alias{plot.lmtree} \alias{predict.lmtree} \alias{print.lmtree} \title{Linear Model Trees} \description{ Model-based recursive partitioning based on least squares regression. } \usage{ lmtree(formula, data, subset, na.action, weights, offset, cluster, \dots) } \arguments{ \item{formula}{symbolic description of the model (of type \code{y ~ z1 + \dots + zl} or \code{y ~ x1 + \dots + xk | z1 + \dots + zl}; for details see below).} \item{data, subset, na.action}{arguments controlling formula processing via \code{\link[stats]{model.frame}}.} \item{weights}{optional numeric vector of weights. By default these are treated as case weights but the default can be changed in \code{\link{mob_control}}.} \item{offset}{optional numeric vector with an a priori known component to be included in the model \code{y ~ x1 + \dots + xk} (i.e., only when \code{x} variables are specified).} \item{cluster}{optional vector (typically numeric or factor) with a cluster ID to be employed for clustered covariances in the parameter stability tests.} \item{\dots}{optional control parameters passed to \code{\link{mob_control}}.} } \details{ Convenience interface for fitting MOBs (model-based recursive partitions) via the \code{\link{mob}} function. \code{lmtree} internally sets up a model \code{fit} function for \code{mob}, using either \code{\link[stats]{lm.fit}} or \code{\link[stats]{lm.wfit}} (depending on whether weights are used or not). Then \code{mob} is called using the residual sum of squares as the objective function. Compared to calling \code{mob} by hand, the implementation tries to avoid unnecessary computations while growing the tree. Also, it provides a more elaborate plotting function. } \value{ An object of class \code{lmtree} inheriting from \code{\link{modelparty}}. The \code{info} element of the overall \code{party} and the individual \code{node}s contain various informations about the models. } \references{ Zeileis A, Hothorn T, Hornik K (2008). Model-Based Recursive Partitioning. \emph{Journal of Computational and Graphical Statistics}, \bold{17}(2), 492--514. } \seealso{\code{\link{mob}}, \code{\link{mob_control}}, \code{\link{glmtree}}} \examples{ if(require("mlbench")) { ## Boston housing data data("BostonHousing", package = "mlbench") BostonHousing <- transform(BostonHousing, chas = factor(chas, levels = 0:1, labels = c("no", "yes")), rad = factor(rad, ordered = TRUE)) ## linear model tree bh_tree <- lmtree(medv ~ log(lstat) + I(rm^2) | zn + indus + chas + nox + age + dis + rad + tax + crim + b + ptratio, data = BostonHousing, minsize = 40) ## printing whole tree or individual nodes print(bh_tree) print(bh_tree, node = 7) ## plotting plot(bh_tree) plot(bh_tree, tp_args = list(which = "log(lstat)")) plot(bh_tree, terminal_panel = NULL) ## estimated parameters coef(bh_tree) coef(bh_tree, node = 9) summary(bh_tree, node = 9) ## various ways for computing the mean squared error (on the training data) mean((BostonHousing$medv - fitted(bh_tree))^2) mean(residuals(bh_tree)^2) deviance(bh_tree)/sum(weights(bh_tree)) deviance(bh_tree)/nobs(bh_tree) ## log-likelihood and information criteria logLik(bh_tree) AIC(bh_tree) BIC(bh_tree) ## (Note that this penalizes estimation of error variances, which ## were treated as nuisance parameters in the fitting process.) ## different types of predictions bh <- BostonHousing[c(1, 10, 50), ] predict(bh_tree, newdata = bh, type = "node") predict(bh_tree, newdata = bh, type = "response") predict(bh_tree, newdata = bh, type = function(object) summary(object)$r.squared) } if(require("AER")) { ## Demand for economics journals data data("Journals", package = "AER") Journals <- transform(Journals, age = 2000 - foundingyear, chars = charpp * pages) ## linear regression tree (OLS) j_tree <- lmtree(log(subs) ~ log(price/citations) | price + citations + age + chars + society, data = Journals, minsize = 10, verbose = TRUE) ## printing and plotting j_tree plot(j_tree) ## coefficients and summary coef(j_tree, node = 1:3) summary(j_tree, node = 1:3) } if(require("AER")) { ## Beauty and teaching ratings data data("TeachingRatings", package = "AER") ## linear regression (WLS) ## null model tr_null <- lm(eval ~ 1, data = TeachingRatings, weights = students, subset = credits == "more") ## main effects tr_lm <- lm(eval ~ beauty + gender + minority + native + tenure + division, data = TeachingRatings, weights = students, subset = credits == "more") ## tree tr_tree <- lmtree(eval ~ beauty | minority + age + gender + division + native + tenure, data = TeachingRatings, weights = students, subset = credits == "more", caseweights = FALSE) ## visualization plot(tr_tree) ## beauty slope coefficient coef(tr_lm)[2] coef(tr_tree)[, 2] ## R-squared 1 - deviance(tr_lm)/deviance(tr_null) 1 - deviance(tr_tree)/deviance(tr_null) } } \keyword{tree} partykit/DESCRIPTION0000644000176200001440000000426114416215302013630 0ustar liggesusersPackage: partykit Title: A Toolkit for Recursive Partytioning Date: 2023-04-11 Version: 1.2-20 Authors@R: c(person(given = "Torsten", family = "Hothorn", role = c("aut", "cre"), email = "Torsten.Hothorn@R-project.org", comment = c(ORCID = "0000-0001-8301-0471")), person(given = "Heidi", family = "Seibold", role = "ctb", email = "heidi@seibold.co", comment = c(ORCID = "0000-0002-8960-9642")), person(given = "Achim", family = "Zeileis", role = "aut", email = "Achim.Zeileis@R-project.org", comment = c(ORCID = "0000-0003-0918-3766"))) Description: A toolkit with infrastructure for representing, summarizing, and visualizing tree-structured regression and classification models. This unified infrastructure can be used for reading/coercing tree models from different sources ('rpart', 'RWeka', 'PMML') yielding objects that share functionality for print()/plot()/predict() methods. Furthermore, new and improved reimplementations of conditional inference trees (ctree()) and model-based recursive partitioning (mob()) from the 'party' package are provided based on the new infrastructure. A description of this package was published by Hothorn and Zeileis (2015) . Depends: R (>= 3.5.0), graphics, grid, libcoin (>= 1.0-0), mvtnorm Imports: grDevices, stats, utils, survival, Formula (>= 1.2-1), inum (>= 1.0-0), rpart (>= 4.1-11) Suggests: XML, pmml, rJava, sandwich, strucchange, vcd, AER, mlbench, TH.data (>= 1.0-3), coin (>= 1.1-0), RWeka (>= 0.4-19), datasets, parallel, psychotools (>= 0.3-0), psychotree, party (>= 1.3-0), randomForest LazyData: yes License: GPL-2 | GPL-3 URL: http://partykit.r-forge.r-project.org/partykit/ RoxygenNote: 6.1.1 NeedsCompilation: yes Packaged: 2023-04-11 09:36:39 UTC; hothorn Author: Torsten Hothorn [aut, cre] (), Heidi Seibold [ctb] (), Achim Zeileis [aut] () Maintainer: Torsten Hothorn Repository: CRAN Date/Publication: 2023-04-14 09:20:02 UTC partykit/build/0000755000176200001440000000000014415225041013216 5ustar liggesuserspartykit/build/vignette.rds0000644000176200001440000000111414415225041015552 0ustar liggesusersTo0Κv]˘-i>1eMU%osi;F}VΎݦaPw|GQԊڭ8x;6z*i&r=xl6͊^[Ss~Kpartykit/build/partial.rdb0000644000176200001440000000007414415224762015355 0ustar liggesusersb```b`abf" S X# 'fKM-2 Q7partykit/tests/0000755000176200001440000000000014415225047013267 5ustar liggesuserspartykit/tests/regtest-party-random.R0000644000176200001440000000131214172230000017460 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) ## packages library("partykit") library("rpart") ## data-generating process dgp <- function(n) data.frame(y = gl(4, n), x1 = rnorm(4 * n), x2 = rnorm(4 * n)) ## rpart check learn <- dgp(100) fit <- as.party(rpart(y ~ ., data = learn)) test <- dgp(100000) system.time(id <- fitted_node(node_party(fit), test)) system.time(yhat <- predict_party(fit, id = id, newdata = test)) ### predictions in info slots tmp <- data.frame(x = rnorm(100)) pfit <- party(node = partynode(1L, split = partysplit(1L, breaks = 0), kids = list(partynode(2L, info = -0.5), partynode(3L, info = 0.5))), data = tmp) pfit p <- predict(pfit, newdata = tmp) p table(p, sign(tmp$x)) partykit/tests/constparty.R0000644000176200001440000002662314172230001015613 0ustar liggesusers### R code from vignette source 'constparty.Rnw' ### test here after removal of RWeka dependent code ################################################### ### code chunk number 1: setup ################################################### options(width = 70) library("partykit") set.seed(290875) ################################################### ### code chunk number 2: Titanic ################################################### data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" ################################################### ### code chunk number 3: rpart ################################################### library("rpart") (rp <- rpart(Survived ~ ., data = ttnc, model = TRUE)) ################################################### ### code chunk number 4: rpart-party ################################################### (party_rp <- as.party(rp)) ################################################### ### code chunk number 5: rpart-plot-orig ################################################### plot(rp) text(rp) ################################################### ### code chunk number 6: rpart-plot ################################################### plot(party_rp) ################################################### ### code chunk number 7: rpart-pred ################################################### all.equal(predict(rp), predict(party_rp, type = "prob"), check.attributes = FALSE) ################################################### ### code chunk number 8: rpart-fitted ################################################### str(fitted(party_rp)) ################################################### ### code chunk number 9: rpart-prob ################################################### prop.table(do.call("table", fitted(party_rp)), 1) ################################################### ### code chunk number 10: J48 ################################################### #if (require("RWeka")) { # j48 <- J48(Survived ~ ., data = ttnc) #} else { # j48 <- rpart(Survived ~ ., data = ttnc) #} #print(j48) # # #################################################### #### code chunk number 11: J48-party #################################################### #(party_j48 <- as.party(j48)) # # #################################################### #### code chunk number 12: J48-plot #################################################### #plot(party_j48) # # #################################################### #### code chunk number 13: J48-pred #################################################### #all.equal(predict(j48, type = "prob"), predict(party_j48, type = "prob"), # check.attributes = FALSE) ################################################### ### code chunk number 14: PMML-Titantic ################################################### ttnc_pmml <- file.path(system.file("pmml", package = "partykit"), "ttnc.pmml") (ttnc_quest <- pmmlTreeModel(ttnc_pmml)) ################################################### ### code chunk number 15: PMML-Titanic-plot1 ################################################### plot(ttnc_quest) ################################################### ### code chunk number 16: ttnc2-reorder ################################################### ttnc2 <- ttnc[, names(ttnc_quest$data)] for(n in names(ttnc2)) { if(is.factor(ttnc2[[n]])) ttnc2[[n]] <- factor( ttnc2[[n]], levels = levels(ttnc_quest$data[[n]])) } ################################################### ### code chunk number 17: PMML-Titanic-augmentation ################################################### ttnc_quest2 <- party(ttnc_quest$node, data = ttnc2, fitted = data.frame( "(fitted)" = predict(ttnc_quest, ttnc2, type = "node"), "(response)" = ttnc2$Survived, check.names = FALSE), terms = terms(Survived ~ ., data = ttnc2) ) ttnc_quest2 <- as.constparty(ttnc_quest2) ################################################### ### code chunk number 18: PMML-Titanic-plot2 ################################################### plot(ttnc_quest2) ################################################### ### code chunk number 19: PMML-write ################################################### library("pmml") tfile <- tempfile() write(toString(pmml(rp)), file = tfile) ################################################### ### code chunk number 20: PMML-read ################################################### (party_pmml <- pmmlTreeModel(tfile)) all.equal(predict(party_rp, newdata = ttnc, type = "prob"), predict(party_pmml, newdata = ttnc, type = "prob"), check.attributes = FALSE) ################################################### ### code chunk number 21: mytree-1 ################################################### findsplit <- function(response, data, weights, alpha = 0.01) { ## extract response values from data y <- factor(rep(data[[response]], weights)) ## perform chi-squared test of y vs. x mychisqtest <- function(x) { x <- factor(x) if(length(levels(x)) < 2) return(NA) ct <- suppressWarnings(chisq.test(table(y, x), correct = FALSE)) pchisq(ct$statistic, ct$parameter, log = TRUE, lower.tail = FALSE) } xselect <- which(names(data) != response) logp <- sapply(xselect, function(i) mychisqtest(rep(data[[i]], weights))) names(logp) <- names(data)[xselect] ## Bonferroni-adjusted p-value small enough? if(all(is.na(logp))) return(NULL) minp <- exp(min(logp, na.rm = TRUE)) minp <- 1 - (1 - minp)^sum(!is.na(logp)) if(minp > alpha) return(NULL) ## for selected variable, search for split minimizing p-value xselect <- xselect[which.min(logp)] x <- rep(data[[xselect]], weights) ## set up all possible splits in two kid nodes lev <- levels(x[drop = TRUE]) if(length(lev) == 2) { splitpoint <- lev[1] } else { comb <- do.call("c", lapply(1:(length(lev) - 2), function(x) combn(lev, x, simplify = FALSE))) xlogp <- sapply(comb, function(q) mychisqtest(x %in% q)) splitpoint <- comb[[which.min(xlogp)]] } ## split into two groups (setting groups that do not occur to NA) splitindex <- !(levels(data[[xselect]]) %in% splitpoint) splitindex[!(levels(data[[xselect]]) %in% lev)] <- NA_integer_ splitindex <- splitindex - min(splitindex, na.rm = TRUE) + 1L ## return split as partysplit object return(partysplit(varid = as.integer(xselect), index = splitindex, info = list(p.value = 1 - (1 - exp(logp))^sum(!is.na(logp))))) } ################################################### ### code chunk number 22: mytree-2 ################################################### growtree <- function(id = 1L, response, data, weights, minbucket = 30) { ## for less than 30 observations stop here if (sum(weights) < minbucket) return(partynode(id = id)) ## find best split sp <- findsplit(response, data, weights) ## no split found, stop here if (is.null(sp)) return(partynode(id = id)) ## actually split the data kidids <- kidids_split(sp, data = data) ## set up all daugther nodes kids <- vector(mode = "list", length = max(kidids, na.rm = TRUE)) for (kidid in 1:length(kids)) { ## select observations for current node w <- weights w[kidids != kidid] <- 0 ## get next node id if (kidid > 1) { myid <- max(nodeids(kids[[kidid - 1]])) } else { myid <- id } ## start recursion on this daugther node kids[[kidid]] <- growtree(id = as.integer(myid + 1), response, data, w) } ## return nodes return(partynode(id = as.integer(id), split = sp, kids = kids, info = list(p.value = min(info_split(sp)$p.value, na.rm = TRUE)))) } ################################################### ### code chunk number 23: mytree-3 ################################################### mytree <- function(formula, data, weights = NULL) { ## name of the response variable response <- all.vars(formula)[1] ## data without missing values, response comes last data <- data[complete.cases(data), c(all.vars(formula)[-1], response)] ## data is factors only stopifnot(all(sapply(data, is.factor))) if (is.null(weights)) weights <- rep(1L, nrow(data)) ## weights are case weights, i.e., integers stopifnot(length(weights) == nrow(data) & max(abs(weights - floor(weights))) < .Machine$double.eps) ## grow tree nodes <- growtree(id = 1L, response, data, weights) ## compute terminal node number for each observation fitted <- fitted_node(nodes, data = data) ## return rich constparty object ret <- party(nodes, data = data, fitted = data.frame("(fitted)" = fitted, "(response)" = data[[response]], "(weights)" = weights, check.names = FALSE), terms = terms(formula)) as.constparty(ret) } ################################################### ### code chunk number 24: mytree-4 ################################################### (myttnc <- mytree(Survived ~ Class + Age + Gender, data = ttnc)) ################################################### ### code chunk number 25: mytree-5 ################################################### plot(myttnc) ################################################### ### code chunk number 26: mytree-pval ################################################### nid <- nodeids(myttnc) iid <- nid[!(nid %in% nodeids(myttnc, terminal = TRUE))] (pval <- unlist(nodeapply(myttnc, ids = iid, FUN = function(n) info_node(n)$p.value))) ################################################### ### code chunk number 27: mytree-nodeprune ################################################### myttnc2 <- nodeprune(myttnc, ids = iid[pval > 1e-5]) ################################################### ### code chunk number 28: mytree-nodeprune-plot ################################################### plot(myttnc2) ################################################### ### code chunk number 29: mytree-glm ################################################### logLik(glm(Survived ~ Class + Age + Gender, data = ttnc, family = binomial())) ################################################### ### code chunk number 30: mytree-bs ################################################### bs <- rmultinom(25, nrow(ttnc), rep(1, nrow(ttnc)) / nrow(ttnc)) ################################################### ### code chunk number 31: mytree-ll ################################################### bloglik <- function(prob, weights) sum(weights * dbinom(ttnc$Survived == "Yes", size = 1, prob[,"Yes"], log = TRUE)) ################################################### ### code chunk number 32: mytree-bsll ################################################### f <- function(w) { tr <- mytree(Survived ~ Class + Age + Gender, data = ttnc, weights = w) bloglik(predict(tr, newdata = ttnc, type = "prob"), as.numeric(w == 0)) } apply(bs, 2, f) ################################################### ### code chunk number 33: mytree-node ################################################### nttnc <- expand.grid(Class = levels(ttnc$Class), Gender = levels(ttnc$Gender), Age = levels(ttnc$Age)) nttnc ################################################### ### code chunk number 34: mytree-prob ################################################### predict(myttnc, newdata = nttnc, type = "node") predict(myttnc, newdata = nttnc, type = "response") predict(myttnc, newdata = nttnc, type = "prob") ################################################### ### code chunk number 35: mytree-FUN ################################################### predict(myttnc, newdata = nttnc, FUN = function(y, w) rank(table(rep(y, w)))) partykit/tests/regtest-node.R0000644000176200001440000000105214172230001015772 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") set.seed(1) mysplit <- function(x) partysplit(1L, breaks = as.double(x)) x <- vector(mode = "list", length = 5) x[[1]] <- list(id = 1L, split = mysplit(1 / 3), kids = 2:3, info = "one") x[[2]] <- list(id = 2L, info = "two") x[[3]] <- list(id = 3L, split = mysplit(2 / 3), kids = 4:5, info = "three") x[[4]] <- list(id = 4L, info = "four") x[[5]] <- list(id = 5L, info = "five") rx <- as.partynode(x) stopifnot(identical(as.list(rx), x)) dat <- data.frame(x = runif(100)) kidids_node(rx, dat) partykit/tests/regtest-ctree.R0000644000176200001440000000155714172230000016160 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) ## package library("partykit") ## iris data data("iris", package = "datasets") irisct <- ctree(Species ~ ., data = iris) print(irisct) table(fit = predict(irisct), true = iris$Species) ## airquality data data("airquality", package = "datasets") airq <- subset(airquality, !is.na(Ozone)) airqct <- ctree(Ozone ~ ., data = airq) print(airqct) sum((airq$Ozone - predict(airqct))^2) ### split in one variable only: Temp is selected freely in the root node ### but none of the other variables is allowed deeper in the tree airqct1 <- ctree(Ozone ~ ., data = airq, control = ctree_control(maxvar = 1L)) psplitids <- unique(do.call("c", nodeapply(node_party(airqct1), ids = nodeids(node_party(airqct1)), FUN = function(x) split_node(x)$varid))) stopifnot(length(psplitids) == 1L) partykit/tests/regtest-split.R0000644000176200001440000000461314172230001016206 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") set.seed(1) dat <- data.frame(v1 = as.double(1:100)) sv1 <- partysplit(as.integer(1), breaks = as.double(50)) character_split(sv1, dat) stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 > 50) + 1))) sv1 <- partysplit(as.integer(1), breaks = as.double(50), index = as.integer(c(2, 1))) character_split(sv1, dat) stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 <= 50) + 1))) sv1 <- partysplit(as.integer(1), breaks = as.double(50), right = FALSE) character_split(sv1, dat) stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 >= 50) + 1))) sv1 <- partysplit(as.integer(1), breaks = as.double(50), index = as.integer(c(2, 1)), right = FALSE) character_split(sv1, dat) stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 < 50) + 1))) sv1 <- partysplit(as.integer(1), breaks = as.double(c(25, 75))) character_split(sv1, dat) stopifnot(all(kidids_split(sv1, dat) == as.integer(cut(dat$v1, c(-Inf, 25, 75, Inf))))) sv1 <- partysplit(as.integer(1), breaks = as.double(c(25, 75)), right = FALSE) character_split(sv1, dat) stopifnot(all(kidids_split(sv1, dat) == as.integer(cut(dat$v1, c(-Inf, c(25, 75), Inf), right = FALSE)))) sv1 <- partysplit(as.integer(1), breaks = as.double(c(25, 75)), index = as.integer(3:1), right = FALSE) character_split(sv1, dat) stopifnot(all(kidids_split(sv1, dat) == (3:1)[as.integer(cut(dat$v1, c(-Inf, c(25, 75), Inf), right = FALSE))])) dat$v2 <- gl(4, 25) sv2 <- partysplit(as.integer(2), index = as.integer(c(1, 2, 1, 2))) character_split(sv2, dat) kidids_split(sv2, dat) sv2 <- partysplit(as.integer(2), breaks = as.integer(c(1, 3))) character_split(sv2, dat) kidids_split(sv2, dat) dat <- data.frame(x = gl(3, 30, labels = LETTERS[1:3]), y = rnorm(90), z = gl(9, 10, labels = LETTERS[1:9], ordered = TRUE)) csp <- partysplit(as.integer(1), index = as.integer(c(1, 2, 1))) kidids_split(csp, dat) #kidids_node(list(csp), dat) nsp <- partysplit(as.integer(2), breaks = c(-1, 0, 1), index = as.integer(c(1, 2, 1, 3))) kidids_split(nsp, dat) osp <- partysplit(as.integer(3), breaks = as.integer(c(3, 6)), index = as.integer(c(2, 1, 2))) kidids_split(osp, dat) nadat <- dat nadat$x[1:10] <- NA nadat$y[11:20] <- NA #kidids_node(list(csp, nsp, osp), nadat) character_split(csp, dat) character_split(nsp, dat) character_split(osp, dat) partykit/tests/bugfixes.Rout.save0000644000176200001440000016422414415224515016723 0ustar liggesusers R Under development (unstable) (2023-04-10 r84212) -- "Unsuffered Consequences" Copyright (C) 2023 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > set.seed(290875) > > datLB <- + structure(list(Site = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, + 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, + 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, + 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, + 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, + 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, + 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, + 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, + 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, + 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, + 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, + 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, + 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, + 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, + 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, + 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, + 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, + 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, + 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, + 9L, 9L, 9L, 9L, 9L, 9L, 9L), ID = c(1.1, 2.1, 3.1, 4.1, 5.1, + 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, 4.2, 5.2, + 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, 2.3, 3.3, + 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, 2.4, 3.4, + 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 1.6, 2.6, + 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, 13.6, 14.6, + 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7, 11.7, + 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, 11.8, + 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, 2.9, 3.9, + 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, 2.1, 3.1, 4.1, + 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, 4.2, + 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, 2.3, + 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, 2.4, + 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 1.6, + 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, 13.6, + 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7, + 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, + 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, 2.9, + 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, 2.1, 3.1, + 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, + 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, + 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, + 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, + 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, + 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, + 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, + 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, + 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, 2.1, + 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, + 3.2, 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, + 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, + 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, + 6.5, 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, + 12.6, 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, + 9.7, 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, + 9.8, 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, + 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, + 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, + 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, + 14.2, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, + 12.3, 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, + 4.5, 5.5, 6.5, 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, + 11.6, 12.6, 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, + 8.7, 9.7, 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, + 8.8, 9.8, 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, + 19.8, 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9 + ), Treat = structure(c(2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, + 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, + 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, + 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, + 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, + 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, + 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, + 1L, 1L, 2L, 2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, + 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, + 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, + 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, + 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, + 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, + 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L, + 2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, + 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, + 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, + 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, + 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, + 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, + 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, + 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, + 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, + 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, + 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, + 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, + 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, + 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 3L, 1L, 1L, + 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, + 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, + 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, + 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, + 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, + 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, + 2L, 1L, 3L, 2L, 1L, 1L, 2L), .Label = c("10000U", "5000U", "Placebo" + ), class = "factor"), Age = c(65L, 70L, 64L, 59L, 76L, 59L, 72L, + 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, 49L, 54L, + 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, 77L, 41L, + 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, 55L, 52L, + 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, 41L, 51L, + 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, 72L, 65L, + 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, 74L, 41L, + 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, 42L, 73L, + 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L, 65L, 70L, + 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, + 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, + 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, + 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, + 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, + 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, + 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, + 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, + 50L, 39L, 57L, 65L, 70L, 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, + 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, + 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, + 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, + 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, + 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, + 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, + 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, + 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L, 65L, 70L, 64L, 59L, 76L, + 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, + 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, + 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, + 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, + 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, + 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, + 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, + 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L, + 65L, 70L, 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, + 49L, 59L, 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, + 54L, 41L, 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, + 62L, 73L, 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, + 43L, 64L, 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, + 39L, 69L, 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, + 64L, 39L, 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, + 57L, 68L, 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, + 79L, 43L, 50L, 39L, 57L), W0 = c(32L, 60L, 44L, 53L, 53L, 49L, + 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, 50L, 42L, + 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, 46L, 52L, + 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, 44L, 42L, + 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, 53L, 36L, + 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, 31L, 50L, + 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, 36L, 33L, + 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, 41L, 46L, + 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, 53L, 32L, + 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, + 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, + 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, + 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, + 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, + 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, + 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, + 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, + 67L, 57L, 63L, 53L, 32L, 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, + 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, + 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, + 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, + 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, + 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, + 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, + 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, + 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, 53L, 32L, 60L, 44L, 53L, + 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, + 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, + 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, + 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, + 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, + 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, + 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, + 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, + 53L, 32L, 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, + 49L, 46L, 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, + 47L, 50L, 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, + 52L, 52L, 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, + 44L, 54L, 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, + 34L, 57L, 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, + 50L, 43L, 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, + 58L, 26L, 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, + 52L, 45L, 67L, 57L, 63L, 53L), Fem = c(1L, 1L, 1L, 1L, 1L, 1L, + 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, + 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, + 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, + 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, + 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, + 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, + 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, + 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, + 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, + 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, + 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, + 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, + 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, + 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, + 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, + 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, + 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, + 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, + 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, + 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, + 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, + 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, + 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, + 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, + 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, + 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L), Week = c(2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, + 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, + 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, + 8L, 8L, 8L, 8L, 8L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, + 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, + 16L), Total = c(30L, 26L, 20L, 61L, 35L, 34L, 32L, 33L, 32L, + 10L, 41L, 19L, 47L, 35L, 44L, 48L, 60L, 53L, 42L, 56L, 64L, 40L, + 58L, 54L, 33L, NA, 43L, 29L, 41L, 31L, 26L, 44L, 19L, 38L, 16L, + 23L, 37L, 42L, 55L, 30L, 52L, 44L, 45L, 34L, 39L, 14L, 34L, 57L, + 53L, 50L, 27L, NA, 53L, 32L, 55L, 50L, 56L, 29L, 53L, 50L, 38L, + 48L, 34L, 44L, 31L, 48L, 40L, 25L, 30L, 18L, 27L, 24L, 25L, 40L, + 48L, 45L, 47L, 42L, 24L, 39L, 30L, 27L, 15L, 32L, NA, 29L, 23L, + 22L, 46L, 25L, 46L, 26L, NA, 24L, 10L, 50L, NA, 28L, 16L, 52L, + 21L, 38L, 45L, 46L, 46L, 63L, NA, 51L, 38L, 24L, 27L, 23L, 64L, + 48L, 43L, 32L, 21L, 34L, 31L, 32L, 21L, 44L, 45L, 48L, 56L, 60L, + 52L, 43L, 52L, 65L, 32L, 55L, 52L, 25L, 54L, 51L, 27L, 33L, 29L, + 29L, 47L, 20L, 40L, 11L, 16L, 39L, 35L, 51L, 43L, 52L, 33L, 41L, + 29L, 38L, 9L, 32L, 53L, 55L, NA, 16L, 46L, 51L, 40L, 44L, 50L, + 47L, 24L, 45L, 48L, 42L, 46L, 26L, 47L, 25L, 50L, 42L, 30L, 40L, + 23L, 43L, 34L, 21L, 38L, 26L, 52L, 45L, 52L, 17L, 25L, 44L, 25L, + 16L, 31L, NA, 18L, 30L, 21L, 41L, 30L, 46L, 27L, 23L, 25L, 13L, + 22L, 41L, 29L, 18L, 61L, 29L, 50L, 36L, 36L, 33L, 71L, 36L, 46L, + NA, 37L, 41L, 26L, 62L, 49L, 48L, 43L, 27L, 35L, 32L, 35L, 24L, + 48L, 49L, 54L, 55L, 64L, 57L, 33L, 54L, 64L, 36L, NA, 48L, 29L, + 43L, 46L, 21L, 39L, 28L, 33L, 50L, 27L, 48L, 7L, 15L, 39L, 24L, + 52L, 45L, 54L, 54L, 45L, 28L, 47L, 9L, 35L, 52L, 62L, 46L, 19L, + 26L, 56L, 52L, 50L, 56L, 53L, 32L, 44L, 56L, 43L, 57L, 40L, 50L, + NA, 50L, 38L, 41L, 43L, 26L, 32L, 28L, 33L, 44L, 37L, 51L, 45L, + 60L, 37L, 15L, 46L, 30L, 17L, 27L, NA, 20L, 36L, 25L, 43L, 49L, + 50L, 22L, 18L, 37L, 16L, 28L, 41L, 30L, 25L, 68L, 30L, 53L, NA, + NA, 44L, 66L, 23L, 50L, 33L, 39L, 65L, 35L, NA, 41L, 48L, 42L, + 32L, 37L, 6L, 57L, 28L, 44L, 53L, 49L, 57L, 67L, 61L, 37L, 55L, + 62L, 42L, 56L, 52L, 32L, 46L, 49L, 22L, 37L, 33L, 45L, 50L, 29L, + 49L, 13L, 17L, 45L, 29L, 54L, 47L, 51L, 46L, 43L, 35L, 39L, 16L, + 54L, 53L, 67L, 50L, 23L, 30L, 39L, 42L, 53L, 59L, 51L, 45L, 50L, + 49L, 42L, 57L, 49L, 46L, NA, 50L, 50L, 41L, 36L, 33L, 40L, 34L, + 42L, 47L, 37L, 52L, 50L, 54L, 36L, 21L, 46L, 28L, 22L, 49L, NA, + 25L, 41L, 26L, 49L, 55L, 56L, 38L, 34L, NA, 32L, 34L, 58L, 37L, + 33L, 59L, 35L, 47L, 40L, 45L, 46L, 68L, NA, 50L, 36L, 36L, 67L, + 35L, NA, 51L, 51L, 46L, 38L, 36L, 14L, 51L, 28L, 44L, 56L, 60L, + 58L, 66L, 54L, 43L, 51L, 64L, 43L, 60L, 53L, 32L, 50L, 53L, 22L, + 37L, 38L, 56L, 49L, 32L, 44L, 21L, 29L, 43L, 42L, 57L, 46L, 57L, + 47L, 41L, 41L, 39L, 33L, 53L, 58L, NA, 57L, 26L, 34L, 9L, 47L, + 52L, 53L, 51L, 36L, 48L, 57L, 46L, 49L, 47L, 51L, NA, 49L, 56L, + 31L, 45L, 41L, 47L, 28L, 53L, 53L, 43L, 53L, 52L, 59L, 38L, 25L, + 44L, 30L, 41L, 60L, NA, 41L, 43L, 33L, 54L, 58L, 60L, 35L, 36L, + 38L, 16L, 36L, 53L, 44L, 48L, 71L, 48L, 59L, 52L, 54L, 48L, 71L, + 52L, 54L, 51L)), .Names = c("Site", "ID", "Treat", "Age", "W0", + "Fem", "Week", "Total"), class = "data.frame", row.names = c(NA, + -545L)) > > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > library("rpart") > > fac <- c(1,3,6) > for(j in 1:length(fac)) datLB[,fac[j]] <- as.factor(datLB[,fac[j]]) > dat <- subset(datLB,Week==16) > dat <- na.omit(dat) > fit <- rpart(Total ~ Site + Treat + Age + W0, + method = "anova", data = dat) > f <- as.party(fit) > plot(f,tp_args = list(id = FALSE)) > f[10]$node$split $varid [1] 3 $breaks NULL $index [1] 2 2 1 $right [1] TRUE $prob [1] 0 1 $info NULL attr(,"class") [1] "partysplit" > > ### factors with empty levels in learning sample > if (require("mlbench")) { + data("Vowel", package = "mlbench") + ct <- ctree(V2 ~ V1, data = Vowel[1:200,]) ### only levels 1:4 in V1 + try(p1 <- predict(ct, newdata = Vowel)) ### 14 levels in V1 + } Loading required package: mlbench Error in model.frame.default(delete.response(object$terms), newdata, xlev = xlev) : factor V1 has new levels 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 > > ### deal with empty levels for teststat = "quad" by > ### removing elements of the teststatistic with zero variance > ### reported by Wei-Yin Loh > tdata <- + structure(list(ytrain = structure(c(3L, 7L, 3L, 2L, 1L, 6L, 2L, + 1L, 1L, 2L, 1L, 2L, 3L, 3L, 2L, 1L, 2L, 6L, 2L, 4L, 6L, 1L, 2L, + 3L, 7L, 6L, 4L, 6L, 2L, 2L, 1L, 2L, 6L, 1L, 7L, 1L, 3L, 6L, 2L, + 1L, 7L, 2L, 7L, 2L, 3L, 2L, 1L, 1L, 3L, 1L, 6L, 2L, 2L, 2L, 2L, + 2L, 1L, 1L, 6L, 6L, 7L, 2L, 2L, 2L, 2L, 2L, 1L, 3L, 6L, 5L, 1L, + 1L, 4L, 7L, 2L, 3L, 3L, 3L, 1L, 8L, 1L, 6L, 2L, 8L, 3L, 4L, 6L, + 2L, 7L, 3L, 6L, 6L, 1L, 1L, 2L, 6L, 3L, 3L, 1L, 2L, 3L, 1L, 2L, + 7L, 2L, 3L, 6L, 2L, 5L, 2L, 2L, 2L, 1L, 3L, 3L, 7L, 3L, 2L, 3L, + 3L, 1L, 6L, 1L, 1L, 1L, 7L, 1L, 3L, 7L, 6L, 1L, 3L, 3L, 6L, 4L, + 2L, 3L, 2L, 8L, 3L, 4L, 2L, 2L, 2L, 3L, 2L, 2L, 2L, 3L, 4L, 6L, + 4L, 8L, 2L, 2L, 3L, 3L, 2L, 3L, 6L, 2L, 1L, 2L, 2L, 7L, 2L, 1L, + 1L, 7L, 2L, 7L, 6L, 6L, 6L), .Label = c("0", "1", "2", "3", "4", + "5", "6", "7"), class = "factor"), landmass = c(5L, 3L, 4L, 6L, + 3L, 4L, 1L, 2L, 2L, 6L, 3L, 1L, 5L, 5L, 1L, 3L, 1L, 4L, 1L, 5L, + 4L, 2L, 1L, 5L, 3L, 4L, 5L, 4L, 4L, 1L, 4L, 1L, 4L, 2L, 5L, 2L, + 4L, 4L, 6L, 1L, 1L, 3L, 3L, 3L, 4L, 1L, 1L, 2L, 4L, 1L, 4L, 4L, + 3L, 2L, 6L, 3L, 3L, 2L, 4L, 4L, 3L, 3L, 3L, 3L, 1L, 6L, 1L, 4L, + 4L, 2L, 1L, 1L, 5L, 3L, 3L, 6L, 5L, 5L, 3L, 5L, 3L, 4L, 1L, 5L, + 5L, 5L, 4L, 6L, 5L, 5L, 4L, 4L, 3L, 3L, 4L, 4L, 5L, 5L, 3L, 6L, + 4L, 1L, 6L, 5L, 1L, 4L, 4L, 6L, 5L, 3L, 1L, 6L, 1L, 4L, 4L, 5L, + 5L, 3L, 5L, 5L, 2L, 6L, 2L, 2L, 6L, 3L, 1L, 5L, 3L, 4L, 4L, 5L, + 4L, 4L, 5L, 6L, 4L, 4L, 5L, 5L, 5L, 1L, 1L, 1L, 4L, 2L, 3L, 3L, + 5L, 5L, 4L, 5L, 4L, 6L, 2L, 4L, 5L, 1L, 5L, 4L, 3L, 2L, 1L, 1L, + 5L, 6L, 3L, 2L, 5L, 6L, 3L, 4L, 4L, 4L), zone = c(1L, 1L, 1L, + 3L, 1L, 2L, 4L, 3L, 3L, 2L, 1L, 4L, 1L, 1L, 4L, 1L, 4L, 1L, 4L, + 1L, 2L, 3L, 4L, 1L, 1L, 4L, 1L, 2L, 1L, 4L, 4L, 4L, 1L, 3L, 1L, + 4L, 2L, 2L, 3L, 4L, 4L, 1L, 1L, 1L, 1L, 4L, 4L, 3L, 1L, 4L, 1L, + 1L, 4L, 3L, 2L, 1L, 1L, 4L, 2L, 4L, 1L, 1L, 4L, 1L, 4L, 1L, 4L, + 4L, 4L, 4L, 4L, 4L, 1L, 1L, 4L, 2L, 1L, 1L, 4L, 1L, 1L, 4L, 4L, + 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 4L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, + 1L, 4L, 4L, 1L, 1L, 4L, 4L, 2L, 2L, 1L, 1L, 4L, 2L, 4L, 1L, 1L, + 1L, 1L, 1L, 1L, 1L, 4L, 2L, 3L, 3L, 1L, 1L, 4L, 1L, 1L, 2L, 1L, + 1L, 4L, 4L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 4L, 4L, 4L, 1L, 4L, 1L, + 1L, 1L, 1L, 2L, 1L, 1L, 2L, 4L, 1L, 1L, 4L, 1L, 1L, 4L, 3L, 4L, + 4L, 1L, 2L, 1L, 4L, 1L, 3L, 1L, 2L, 2L, 2L), area = c(648L, 29L, + 2388L, 0L, 0L, 1247L, 0L, 2777L, 2777L, 7690L, 84L, 19L, 1L, + 143L, 0L, 31L, 23L, 113L, 0L, 47L, 600L, 8512L, 0L, 6L, 111L, + 274L, 678L, 28L, 474L, 9976L, 4L, 0L, 623L, 757L, 9561L, 1139L, + 2L, 342L, 0L, 51L, 115L, 9L, 128L, 43L, 22L, 0L, 49L, 284L, 1001L, + 21L, 28L, 1222L, 1L, 12L, 18L, 337L, 547L, 91L, 268L, 10L, 108L, + 249L, 0L, 132L, 0L, 0L, 109L, 246L, 36L, 215L, 28L, 112L, 1L, + 93L, 103L, 1904L, 1648L, 435L, 70L, 21L, 301L, 323L, 11L, 372L, + 98L, 181L, 583L, 0L, 236L, 10L, 30L, 111L, 0L, 3L, 587L, 118L, + 333L, 0L, 0L, 0L, 1031L, 1973L, 1L, 1566L, 0L, 447L, 783L, 0L, + 140L, 41L, 0L, 268L, 128L, 1267L, 925L, 121L, 195L, 324L, 212L, + 804L, 76L, 463L, 407L, 1285L, 300L, 313L, 9L, 11L, 237L, 26L, + 0L, 2150L, 196L, 72L, 1L, 30L, 637L, 1221L, 99L, 288L, 66L, 0L, + 0L, 0L, 2506L, 63L, 450L, 41L, 185L, 36L, 945L, 514L, 57L, 1L, + 5L, 164L, 781L, 0L, 84L, 236L, 245L, 178L, 0L, 9363L, 22402L, + 15L, 0L, 912L, 333L, 3L, 256L, 905L, 753L, 391L), population = c(16L, + 3L, 20L, 0L, 0L, 7L, 0L, 28L, 28L, 15L, 8L, 0L, 0L, 90L, 0L, + 10L, 0L, 3L, 0L, 1L, 1L, 119L, 0L, 0L, 9L, 7L, 35L, 4L, 8L, 24L, + 0L, 0L, 2L, 11L, 1008L, 28L, 0L, 2L, 0L, 2L, 10L, 1L, 15L, 5L, + 0L, 0L, 6L, 8L, 47L, 5L, 0L, 31L, 0L, 0L, 1L, 5L, 54L, 0L, 1L, + 1L, 17L, 61L, 0L, 10L, 0L, 0L, 8L, 6L, 1L, 1L, 6L, 4L, 5L, 11L, + 0L, 157L, 39L, 14L, 3L, 4L, 57L, 7L, 2L, 118L, 2L, 6L, 17L, 0L, + 3L, 3L, 1L, 1L, 0L, 0L, 9L, 6L, 13L, 0L, 0L, 0L, 2L, 77L, 0L, + 2L, 0L, 20L, 12L, 0L, 16L, 14L, 0L, 2L, 3L, 5L, 56L, 18L, 9L, + 4L, 1L, 84L, 2L, 3L, 3L, 14L, 48L, 36L, 3L, 0L, 22L, 5L, 0L, + 9L, 6L, 3L, 3L, 0L, 5L, 29L, 39L, 2L, 15L, 0L, 0L, 0L, 20L, 0L, + 8L, 6L, 10L, 18L, 18L, 49L, 2L, 0L, 1L, 7L, 45L, 0L, 1L, 13L, + 56L, 3L, 0L, 231L, 274L, 0L, 0L, 15L, 60L, 0L, 22L, 28L, 6L, + 8L), language = structure(c(10L, 6L, 8L, 1L, 6L, 10L, 1L, 2L, + 2L, 1L, 4L, 1L, 8L, 6L, 1L, 6L, 1L, 3L, 1L, 10L, 10L, 6L, 1L, + 10L, 5L, 3L, 10L, 10L, 3L, 1L, 6L, 1L, 10L, 2L, 7L, 2L, 3L, 10L, + 1L, 2L, 2L, 6L, 5L, 6L, 3L, 1L, 2L, 2L, 8L, 2L, 10L, 10L, 6L, + 1L, 1L, 9L, 3L, 3L, 10L, 1L, 4L, 4L, 1L, 6L, 1L, 1L, 2L, 3L, + 6L, 1L, 3L, 2L, 7L, 9L, 6L, 10L, 6L, 8L, 1L, 10L, 6L, 3L, 1L, + 9L, 8L, 10L, 10L, 1L, 10L, 8L, 10L, 10L, 4L, 4L, 10L, 10L, 10L, + 10L, 10L, 10L, 8L, 2L, 10L, 10L, 1L, 8L, 10L, 10L, 10L, 6L, 6L, + 1L, 2L, 3L, 10L, 10L, 8L, 6L, 8L, 6L, 2L, 1L, 2L, 2L, 10L, 5L, + 2L, 8L, 6L, 10L, 6L, 8L, 3L, 1L, 7L, 1L, 10L, 6L, 10L, 8L, 10L, + 1L, 1L, 1L, 8L, 6L, 6L, 4L, 8L, 7L, 10L, 10L, 3L, 10L, 1L, 8L, + 9L, 1L, 8L, 10L, 1L, 2L, 1L, 1L, 5L, 6L, 6L, 2L, 10L, 1L, 6L, + 10L, 10L, 10L), .Label = c("1", "2", "3", "4", "5", "6", "7", + "8", "9", "10"), class = "factor"), bars = c(0L, 0L, 2L, 0L, + 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 3L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 2L, 1L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 3L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 3L, + 1L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 0L, 3L, 3L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 2L, 0L, + 0L, 3L, 0L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 0L, + 0L, 0L, 0L, 1L, 0L, 0L, 0L, 3L, 0L, 0L, 0L, 0L, 3L, 3L, 0L, 0L, + 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 5L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 3L, 0L), stripes = c(3L, 0L, + 0L, 0L, 0L, 2L, 1L, 3L, 3L, 0L, 3L, 3L, 0L, 0L, 0L, 0L, 2L, 0L, + 0L, 0L, 5L, 0L, 0L, 0L, 3L, 2L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 2L, + 0L, 3L, 0L, 0L, 0L, 5L, 5L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 3L, 3L, + 3L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 5L, 3L, 3L, 1L, 9L, 0L, 0L, + 0L, 0L, 2L, 0L, 0L, 3L, 0L, 3L, 0L, 2L, 3L, 3L, 0L, 2L, 0L, 0L, + 0L, 0L, 3L, 0L, 5L, 0L, 3L, 2L, 0L, 11L, 2L, 3L, 2L, 3L, 14L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 5L, 3L, 0L, 3L, 1L, 0L, 3L, + 3L, 0L, 5L, 3L, 0L, 2L, 0L, 0L, 0L, 3L, 0L, 0L, 2L, 5L, 0L, 0L, + 0L, 3L, 0L, 0L, 3L, 2L, 0L, 0L, 3L, 0L, 3L, 0L, 0L, 0L, 0L, 3L, + 5L, 0L, 0L, 3L, 0L, 0L, 5L, 5L, 0L, 0L, 0L, 0L, 0L, 3L, 6L, 0L, + 9L, 0L, 13L, 0L, 0L, 0L, 3L, 0L, 0L, 3L, 0L, 0L, 7L), colours = c(5L, + 3L, 3L, 5L, 3L, 3L, 3L, 2L, 3L, 3L, 2L, 3L, 2L, 2L, 3L, 3L, 8L, + 2L, 6L, 4L, 3L, 4L, 6L, 4L, 5L, 3L, 3L, 3L, 3L, 2L, 5L, 6L, 5L, + 3L, 2L, 3L, 2L, 3L, 4L, 3L, 3L, 3L, 3L, 2L, 4L, 6L, 3L, 3L, 4L, + 2L, 4L, 3L, 3L, 6L, 7L, 2L, 3L, 3L, 3L, 4L, 3L, 3L, 3L, 2L, 3L, + 7L, 2L, 3L, 4L, 5L, 2L, 2L, 6L, 3L, 3L, 2L, 3L, 4L, 3L, 2L, 3L, + 3L, 3L, 2L, 4L, 2L, 4L, 4L, 3L, 4L, 4L, 3L, 3L, 3L, 3L, 3L, 4L, + 3L, 3L, 3L, 2L, 4L, 2L, 3L, 7L, 2L, 5L, 3L, 3L, 3L, 3L, 3L, 2L, + 3L, 2L, 3L, 4L, 3L, 3L, 2L, 3L, 4L, 6L, 2L, 4L, 2L, 3L, 2L, 7L, + 4L, 4L, 2L, 3L, 3L, 2L, 4L, 2L, 5L, 4L, 4L, 4L, 5L, 4L, 4L, 4L, + 4L, 2L, 2L, 4L, 3L, 4L, 3L, 4L, 2L, 3L, 2L, 2L, 6L, 4L, 5L, 3L, + 3L, 6L, 3L, 2L, 4L, 4L, 7L, 2L, 3L, 4L, 4L, 4L, 5L), red = c(1L, + 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, + 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, + 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, + 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, + 0L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, + 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, + 1L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), green = c(1L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, + 1L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, + 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, + 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, + 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, + 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, + 1L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 1L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, + 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, + 1L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, + 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L), blue = c(0L, + 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, + 0L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, + 1L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, + 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, + 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, + 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, + 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, + 0L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, + 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, + 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 0L), gold = c(1L, + 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, + 0L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, + 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, + 0L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, + 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, + 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, + 1L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, + 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, + 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L), white = c(1L, + 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, + 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 1L, + 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, + 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, + 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, + 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, + 1L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, + 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 1L), black = c(1L, + 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, + 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, + 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, + 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L), orange = c(0L, + 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, + 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L), mainhue = structure(c(5L, + 7L, 5L, 2L, 4L, 7L, 8L, 2L, 2L, 2L, 7L, 2L, 7L, 5L, 2L, 4L, 2L, + 5L, 7L, 6L, 2L, 5L, 2L, 4L, 7L, 7L, 7L, 7L, 4L, 7L, 4L, 2L, 4L, + 7L, 7L, 4L, 5L, 7L, 2L, 2L, 2L, 8L, 8L, 7L, 2L, 5L, 2L, 4L, 1L, + 2L, 5L, 5L, 8L, 2L, 2L, 8L, 8L, 8L, 5L, 7L, 4L, 1L, 8L, 2L, 4L, + 2L, 2L, 4L, 4L, 5L, 1L, 2L, 2L, 7L, 2L, 7L, 7L, 7L, 8L, 8L, 8L, + 8L, 5L, 8L, 1L, 7L, 7L, 7L, 7L, 7L, 2L, 7L, 7L, 7L, 7L, 7L, 7L, + 7L, 7L, 2L, 5L, 5L, 2L, 7L, 2L, 7L, 4L, 2L, 3L, 7L, 8L, 2L, 2L, + 6L, 5L, 2L, 7L, 7L, 7L, 5L, 7L, 1L, 7L, 7L, 2L, 8L, 7L, 3L, 7L, + 7L, 5L, 5L, 5L, 5L, 8L, 5L, 2L, 6L, 8L, 7L, 4L, 5L, 2L, 5L, 7L, + 7L, 2L, 7L, 7L, 7L, 5L, 7L, 5L, 7L, 7L, 7L, 7L, 2L, 5L, 4L, 7L, + 8L, 8L, 8L, 7L, 7L, 4L, 7L, 7L, 7L, 7L, 5L, 5L, 5L), .Label = c("black", + "blue", "brown", "gold", "green", "orange", "red", "white"), class = "factor"), + circles = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 1L, 0L, 1L, 4L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L), crosses = c(0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 2L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, + 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), saltires = c(0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L), quarters = c(0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, + 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 4L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, + 0L, 0L, 0L, 0L), sunstars = c(1L, 1L, 1L, 0L, 0L, 1L, 0L, + 0L, 1L, 6L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 22L, + 0L, 0L, 1L, 1L, 14L, 3L, 1L, 0L, 1L, 4L, 1L, 1L, 5L, 0L, + 4L, 1L, 15L, 0L, 1L, 0L, 0L, 0L, 1L, 10L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 7L, + 0L, 0L, 0L, 1L, 0L, 0L, 5L, 0L, 0L, 0L, 0L, 0L, 3L, 0L, 1L, + 0L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 1L, 1L, 0L, 0L, 1L, 1L, 0L, 4L, 1L, 0L, 1L, 1L, 1L, 2L, 0L, + 6L, 4L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 2L, 5L, 1L, 0L, 4L, + 0L, 1L, 0L, 2L, 0L, 2L, 0L, 1L, 0L, 5L, 5L, 1L, 0L, 0L, 1L, + 0L, 2L, 0L, 0L, 0L, 1L, 0L, 0L, 2L, 1L, 0L, 0L, 1L, 0L, 0L, + 1L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 50L, 1L, 0L, 0L, 7L, 1L, + 5L, 1L, 0L, 0L, 1L), crescent = c(0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L), triangle = c(0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L), icon = c(1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, + 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, + 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, + 1L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, + 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 1L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L), animate = c(0L, + 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, + 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, + 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, + 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L), text = c(0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, + 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, + 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L), topleft = structure(c(1L, 6L, 4L, 2L, + 2L, 6L, 7L, 2L, 2L, 7L, 6L, 2L, 7L, 4L, 2L, 1L, 6L, 4L, 7L, + 5L, 2L, 4L, 7L, 7L, 7L, 6L, 2L, 7L, 4L, 6L, 6L, 7L, 2L, 2L, + 6L, 3L, 4L, 6L, 7L, 2L, 2L, 7L, 7L, 6L, 7L, 4L, 2L, 3L, 6L, + 2L, 4L, 4L, 7L, 7L, 7L, 7L, 2L, 2L, 4L, 6L, 1L, 1L, 7L, 2L, + 6L, 6L, 2L, 6L, 6L, 1L, 1L, 2L, 7L, 6L, 2L, 6L, 4L, 6L, 4L, + 2L, 4L, 6L, 3L, 7L, 1L, 6L, 1L, 6L, 6L, 6L, 4L, 2L, 2L, 6L, + 7L, 1L, 2L, 6L, 7L, 2L, 4L, 4L, 2L, 6L, 7L, 6L, 4L, 2L, 2L, + 6L, 7L, 7L, 2L, 5L, 4L, 2L, 6L, 6L, 6L, 7L, 7L, 6L, 6L, 6L, + 2L, 7L, 6L, 7L, 2L, 6L, 4L, 4L, 4L, 4L, 6L, 2L, 2L, 5L, 7L, + 6L, 3L, 4L, 2L, 2L, 6L, 4L, 2L, 6L, 6L, 2L, 4L, 6L, 6L, 7L, + 7L, 6L, 6L, 7L, 6L, 1L, 7L, 7L, 7L, 2L, 6L, 1L, 3L, 3L, 6L, + 2L, 2L, 4L, 4L, 4L), .Label = c("black", "blue", "gold", + "green", "orange", "red", "white"), class = "factor"), botright = structure(c(5L, + 7L, 8L, 7L, 7L, 1L, 2L, 2L, 2L, 2L, 7L, 2L, 7L, 5L, 2L, 7L, + 7L, 5L, 7L, 7L, 2L, 5L, 2L, 4L, 7L, 5L, 7L, 8L, 4L, 7L, 5L, + 2L, 4L, 7L, 7L, 7L, 5L, 7L, 2L, 2L, 2L, 8L, 7L, 7L, 5L, 5L, + 2L, 7L, 1L, 2L, 7L, 7L, 8L, 2L, 2L, 8L, 7L, 7L, 2L, 5L, 4L, + 4L, 7L, 2L, 7L, 7L, 2L, 5L, 5L, 5L, 7L, 2L, 2L, 5L, 2L, 8L, + 7L, 1L, 6L, 2L, 7L, 5L, 4L, 8L, 5L, 7L, 5L, 2L, 7L, 7L, 2L, + 7L, 7L, 2L, 5L, 5L, 8L, 7L, 7L, 2L, 5L, 7L, 2L, 7L, 2L, 7L, + 4L, 2L, 2L, 2L, 8L, 2L, 2L, 5L, 5L, 2L, 1L, 7L, 5L, 5L, 8L, + 1L, 2L, 7L, 7L, 7L, 7L, 3L, 7L, 5L, 5L, 5L, 7L, 2L, 8L, 5L, + 2L, 2L, 8L, 1L, 4L, 7L, 2L, 5L, 1L, 5L, 2L, 7L, 1L, 7L, 2L, + 7L, 5L, 7L, 8L, 7L, 7L, 2L, 1L, 7L, 7L, 8L, 8L, 7L, 7L, 5L, + 8L, 7L, 7L, 7L, 7L, 5L, 3L, 5L), .Label = c("black", "blue", + "brown", "gold", "green", "orange", "red", "white"), class = "factor")), .Names = c("ytrain", + "landmass", "zone", "area", "population", "language", "bars", + "stripes", "colours", "red", "green", "blue", "gold", "white", + "black", "orange", "mainhue", "circles", "crosses", "saltires", + "quarters", "sunstars", "crescent", "triangle", "icon", "animate", + "text", "topleft", "botright"), row.names = c(NA, -174L), class = "data.frame") > tdata$language <- factor(tdata$language) > tdata$ytrain <- factor(tdata$ytrain) > > ### was: error > model <- ctree(ytrain ~ ., data = tdata, + control = ctree_control(testtype = "Univariate", splitstat = "maximum")) > > if (require("coin")) { + ### check against coin (independence_test automatically + ### removes empty levels) + p <- info_node(node_party(model))$criterion["p.value",] + p[is.na(p)] <- 0 + p2 <- sapply(names(p), function(n) + pvalue(independence_test(ytrain ~ ., + data = tdata[, c("ytrain", n)], teststat = "quad"))) + stopifnot(max(abs(p - p2)) < sqrt(.Machine$double.eps)) + + p <- info_node(node_party(model[2]))$criterion["p.value",] + p[is.na(p)] <- 0 + p2 <- sapply(names(p), function(n) + pvalue(independence_test(ytrain ~ ., + data = tdata[tdata$language != "8", c("ytrain", n)], + teststat = "quad"))) + stopifnot(max(abs(p - p2)) < sqrt(.Machine$double.eps)) + + p <- info_node(node_party(model[3]))$criterion["p.value",] + p[is.na(p)] <- 0 + p2 <- sapply(names(p), function(n) + pvalue(independence_test(ytrain ~ ., + data = tdata[!(tdata$language %in% c("2", "4", "8")), + c("ytrain", n)], + teststat = "quad"))) + stopifnot(max(abs(p - p2)) < sqrt(.Machine$double.eps)) + } Loading required package: coin Loading required package: survival > > ### check coersion of constparties to simpleparties > ### containing terminal nodes without corresponding observations > ## create party > data("WeatherPlay", package = "partykit") > py <- party( + partynode(1L, + split = partysplit(1L, index = 1:3), + kids = list( + partynode(2L, + split = partysplit(3L, breaks = 75), + kids = list( + partynode(3L, info = "yes"), + partynode(4L, info = "no"))), + partynode(5L, + split = partysplit(3L, breaks = 20), + kids = list( + partynode(6L, info = "no"), + partynode(7L, info = "yes"))), + partynode(8L, + split = partysplit(4L, index = 1:2), + kids = list( + partynode(9L, info = "yes"), + partynode(10L, info = "no"))))), + WeatherPlay) > names(py) <- LETTERS[nodeids(py)] > > pn <- node_party(py) > cp <- party(pn, + data = WeatherPlay, + fitted = data.frame( + "(fitted)" = fitted_node(pn, data = WeatherPlay), + "(response)" = WeatherPlay$play, + check.names = FALSE), + terms = terms(play ~ ., data = WeatherPlay), + ) > print(cp) [1] root | [2] outlook in sunny | | [3] humidity <= 75: yes | | [4] humidity > 75: no | [5] outlook in overcast | | [6] humidity <= 20: no | | [7] humidity > 20: yes | [8] outlook in rainy | | [9] windy in false: yes | | [10] windy in true: no > cp <- as.constparty(cp) > > nd <- data.frame(outlook = factor("overcast", levels = levels(WeatherPlay$outlook)), + humidity = 10, temperature = 10, windy = "yes") > try(predict(cp, type = "node", newdata = nd)) Error in model.frame.default(delete.response(object$terms), newdata, xlev = xlev) : factor windy has new level yes > try(predict(cp, type = "response", newdata = nd)) Error in model.frame.default(delete.response(object$terms), newdata, xlev = xlev) : factor windy has new level yes > as.simpleparty(cp) Model formula: play ~ outlook + temperature + humidity + windy Fitted party: [1] root | [2] outlook in sunny | | [3] humidity <= 75: yes (n = 2, err = 0.0%) | | [4] humidity > 75: no (n = 3, err = 0.0%) | [5] outlook in overcast | | [6] humidity <= 20: NA (n = 0, err = NA) | | [7] humidity > 20: yes (n = 4, err = 0.0%) | [8] outlook in rainy | | [9] windy in false: yes (n = 3, err = 0.0%) | | [10] windy in true: no (n = 2, err = 0.0%) Number of inner nodes: 4 Number of terminal nodes: 6 > print(cp) Model formula: play ~ outlook + temperature + humidity + windy Fitted party: [1] root | [2] outlook in sunny | | [3] humidity <= 75: yes (n = 2, err = 0.0%) | | [4] humidity > 75: no (n = 3, err = 0.0%) | [5] outlook in overcast | | [6] humidity <= 20: NA (n = 0, err = NA) | | [7] humidity > 20: yes (n = 4, err = 0.0%) | [8] outlook in rainy | | [9] windy in false: yes (n = 3, err = 0.0%) | | [10] windy in true: no (n = 2, err = 0.0%) Number of inner nodes: 4 Number of terminal nodes: 6 > > ### scores > y <- gl(3, 10, ordered = TRUE) > x <- rnorm(length(y)) > x <- ordered(cut(x, 3)) > d <- data.frame(y = y, x = x) > > ### partykit with scores > ct11 <- partykit::ctree(y ~ x, data = d) > ct12 <- partykit::ctree(y ~ x, data = d, + scores = list(y = c(1, 4, 5))) > ct13 <- partykit::ctree(y ~ x, data = d, + scores = list(y = c(1, 4, 5), x = c(1, 5, 6))) > > ### party with scores > ct21 <- party::ctree(y ~ x, data = d) > ct22 <- party::ctree(y ~ x, data = d, + scores = list(y = c(1, 4, 5))) > ct23 <- party::ctree(y ~ x, data = d, + scores = list(y = c(1, 4, 5), x = c(1, 5, 6))) > > stopifnot(all.equal(ct11$node$info$p.value, + 1 - ct21@tree$criterion$criterion, check.attr = FALSE)) > stopifnot(all.equal(ct12$node$info$p.value, + 1 - ct22@tree$criterion$criterion, check.attr = FALSE)) > stopifnot(all.equal(ct13$node$info$p.value, + 1 - ct23@tree$criterion$criterion, check.attr = FALSE)) > > ### ytrafo > y <- runif(100, max = 3) > x <- rnorm(length(y)) > d <- data.frame(y = y, x = x) > > ### partykit with scores > ct11 <- partykit::ctree(y ~ x, data = d) > ct12 <- partykit::ctree(y ~ x, data = d, + ytrafo = list(y = sqrt)) > > ### party with scores > ct21 <- party::ctree(y ~ x, data = d) > f <- function(data) coin::trafo(data, numeric_trafo = sqrt) > ct22 <- party::ctree(y ~ x, data = d, + ytrafo = f) > > stopifnot(all.equal(ct11$node$info$p.value, + 1 - ct21@tree$criterion$criterion, check.attr = FALSE)) > stopifnot(all.equal(ct12$node$info$p.value, + 1 - ct22@tree$criterion$criterion, check.attr = FALSE)) > > > ### spotted by Peter Philip Stephensen (DREAM) > ### splits x >= max(x) where possible in partykit::ctree > nAge <- 30 > d <- data.frame(Age=rep(1:nAge,2),y=c(rep(1,nAge),rep(0,nAge)), + n = rep(0,2*nAge)) > ntot <- 100 > alpha <- .5 > d[d$y==1,]$n = floor(ntot * alpha * d[d$y==1,]$Age / nAge) > d[d$y==0,]$n = ntot - d[d$y==1,]$n > d$n <- as.integer(d$n) > ctrl <- partykit::ctree_control(maxdepth=3, minbucket = min(d$n) + 1) > tree <- partykit::ctree(y ~ Age, weights=n, data=d, control=ctrl) > ## IGNORE_RDIFF_BEGIN > tree Model formula: y ~ Age Fitted party: [1] root | [2] Age <= 15 | | [3] Age <= 7 | | | [4] Age <= 4: 0.038 (n = 400, err = 14.4) | | | [5] Age > 4: 0.097 (n = 300, err = 26.2) | | [6] Age > 7 | | | [7] Age <= 11: 0.155 (n = 400, err = 52.4) | | | [8] Age > 11: 0.222 (n = 400, err = 69.2) | [9] Age > 15 | | [10] Age <= 22: 0.313 (n = 700, err = 150.5) | | [11] Age > 22 | | | [12] Age <= 26: 0.405 (n = 400, err = 96.4) | | | [13] Age > 26: 0.472 (n = 400, err = 99.7) Number of inner nodes: 6 Number of terminal nodes: 7 > ## IGNORE_RDIFF_END > > (w1 <- predict(tree, type = "node")) 4 4 4 4 5 5 5 7 7 7 7 8 8 8 8 10 10 10 10 10 10 10 12 12 12 12 4 4 4 4 5 5 5 7 7 7 7 8 8 8 8 10 10 10 10 10 10 10 12 12 12 12 13 13 13 13 4 4 4 4 5 5 5 7 7 7 7 8 8 8 8 10 10 10 10 10 10 10 13 13 13 13 4 4 4 4 5 5 5 7 7 7 7 8 8 8 8 10 10 10 10 10 10 10 12 12 12 12 13 13 13 13 12 12 12 12 13 13 13 13 > > (ct <- ctree(dist + I(dist^2) ~ speed, data = cars)) Model formula: ~dist + I(dist^2) + speed Fitted party: [1] root | [2] speed <= 12: * | [3] speed > 12 | | [4] speed <= 20: * | | [5] speed > 20: * Number of inner nodes: 2 Number of terminal nodes: 3 > predict(ct) dist I(dist^2) 1 18.20000 409.6667 2 18.20000 409.6667 3 18.20000 409.6667 4 18.20000 409.6667 5 18.20000 409.6667 6 18.20000 409.6667 7 18.20000 409.6667 8 18.20000 409.6667 9 18.20000 409.6667 10 18.20000 409.6667 11 18.20000 409.6667 12 18.20000 409.6667 13 18.20000 409.6667 14 18.20000 409.6667 15 18.20000 409.6667 16 46.28571 2423.1429 17 46.28571 2423.1429 18 46.28571 2423.1429 19 46.28571 2423.1429 20 46.28571 2423.1429 21 46.28571 2423.1429 22 46.28571 2423.1429 23 46.28571 2423.1429 24 46.28571 2423.1429 25 46.28571 2423.1429 26 46.28571 2423.1429 27 46.28571 2423.1429 28 46.28571 2423.1429 29 46.28571 2423.1429 30 46.28571 2423.1429 31 46.28571 2423.1429 32 46.28571 2423.1429 33 46.28571 2423.1429 34 46.28571 2423.1429 35 46.28571 2423.1429 36 46.28571 2423.1429 37 46.28571 2423.1429 38 46.28571 2423.1429 39 46.28571 2423.1429 40 46.28571 2423.1429 41 46.28571 2423.1429 42 46.28571 2423.1429 43 46.28571 2423.1429 44 82.85714 7272.8571 45 82.85714 7272.8571 46 82.85714 7272.8571 47 82.85714 7272.8571 48 82.85714 7272.8571 49 82.85714 7272.8571 50 82.85714 7272.8571 > > ### nodeapply was not the same for permutations of ids > ### spotted by Heidi Seibold > airq <- subset(airquality, !is.na(Ozone)) > airct <- ctree(Ozone ~ ., data = airq) > n1 <- nodeapply(airct, ids = c(3, 5, 6), function(x) x$info$nobs) > n2 <- nodeapply(airct, ids = c(6, 3, 5), function(x) x$info$nobs) > stopifnot(all.equal(n1[names(n2)], n2)) > > ### pruning got "fitted" wrong, spotted by Jason Parker > data("Titanic") > titan <- as.data.frame(Titanic) > (tree <- ctree(Survived ~ Class + Sex + Age, data = titan, weights = Freq)) Model formula: Survived ~ Class + Sex + Age Fitted party: [1] root | [2] Sex in Male | | [3] Class in 1st: No (n = 180, err = 34.4%) | | [4] Class in 2nd, 3rd, Crew | | | [5] Age in Child | | | | [6] Class in 2nd: Yes (n = 11, err = 0.0%) | | | | [7] Class in 3rd: No (n = 48, err = 27.1%) | | | [8] Age in Adult | | | | [9] Class in 2nd, 3rd | | | | | [10] Class in 2nd: No (n = 168, err = 8.3%) | | | | | [11] Class in 3rd: No (n = 462, err = 16.2%) | | | | [12] Class in Crew: No (n = 862, err = 22.3%) | [13] Sex in Female | | [14] Class in 1st, 2nd, Crew | | | [15] Class in 1st: Yes (n = 145, err = 2.8%) | | | [16] Class in 2nd, Crew: Yes (n = 129, err = 12.4%) | | [17] Class in 3rd: No (n = 196, err = 45.9%) Number of inner nodes: 8 Number of terminal nodes: 9 > ### prune off nodes 5-12 and check if the other nodes are not affected > nodeprune(tree, 4) Model formula: Survived ~ Class + Sex + Age Fitted party: [1] root | [2] Sex in Male | | [3] Class in 1st: No (n = 180, err = 34.4%) | | [4] Class in 2nd, 3rd, Crew: No (n = 1551, err = 19.7%) | [5] Sex in Female | | [6] Class in 1st, 2nd, Crew | | | [7] Class in 1st: Yes (n = 145, err = 2.8%) | | | [8] Class in 2nd, Crew: Yes (n = 129, err = 12.4%) | | [9] Class in 3rd: No (n = 196, err = 45.9%) Number of inner nodes: 4 Number of terminal nodes: 5 > > ### this gave a warning "ME is not a factor" > if (require("TH.data")) { + data("mammoexp", package = "TH.data") + a <- cforest(ME ~ PB + SYMPT, data = mammoexp, ntree = 5) + print(predict(a, newdata=mammoexp[1:3,])) + } Loading required package: TH.data Loading required package: MASS Attaching package: 'TH.data' The following object is masked from 'package:MASS': geyser 1 2 3 Never Never Never Levels: Never < Within a Year < Over a Year > > ### pruning didn't work properly > mt <- lmtree(dist ~ speed, data = cars) > mt2 <- nodeprune(mt, 2) > stopifnot(all(mt2$fitted[["(fitted)"]] %in% c(2, 3))) > > ### > a <- rep('N',87) > a[77] <- 'Y' > b <- rep(FALSE, 87) > b[c(7,10,11,33,56,77)] <- TRUE > d <- rep(1,87) > d[c(29,38,40,42,65,77)] <- 0 > dfb <- data.frame(a = as.factor(a), b = as.factor(b), d = as.factor(d)) > tr <- ctree(a ~ ., data = dfb, control = ctree_control(minsplit = 10,minbucket = 5, + maxsurrogate = 2, alpha = 0.05)) > tNodes <- node_party(tr) > ### this creates a tie on purpose and "d" should be selected > ### this check fails on M1mac > nodeInfo <- info_node(tNodes) > nodeInfo$criterion b d statistic 13.5000000000 13.5000000000 p.value 0.0004770700 0.0004770700 criterion -0.0001771838 -0.0001771838 > #stopifnot(names(nodeInfo$p.value) == "d") > #stopifnot(split_node(tNodes)$varid == 3) > > ### reported by John Ogawa, 2020-12-11 > class(dfb$a) <- c("Hansi", "factor") > tr2 <- ctree(a ~ ., data = dfb, control = ctree_control(minsplit = 10,minbucket = 5, + maxsurrogate = 2, alpha = 0.05)) > stopifnot(isTRUE(all.equal(tr, tr2, check.attributes = FALSE))) > > proc.time() user system elapsed 3.935 7.247 2.705 partykit/tests/regtest-split.Rout.save0000644000176200001440000001171614172230001017675 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > set.seed(1) > > dat <- data.frame(v1 = as.double(1:100)) > > sv1 <- partysplit(as.integer(1), breaks = as.double(50)) > character_split(sv1, dat) $name [1] "v1" $levels [1] "<= 50" "> 50" > stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 > 50) + 1))) > > sv1 <- partysplit(as.integer(1), breaks = as.double(50), + index = as.integer(c(2, 1))) > character_split(sv1, dat) $name [1] "v1" $levels [1] "> 50" "<= 50" > stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 <= 50) + 1))) > > sv1 <- partysplit(as.integer(1), breaks = as.double(50), right = FALSE) > character_split(sv1, dat) $name [1] "v1" $levels [1] "< 50" ">= 50" > stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 >= 50) + 1))) > > sv1 <- partysplit(as.integer(1), breaks = as.double(50), + index = as.integer(c(2, 1)), right = FALSE) > character_split(sv1, dat) $name [1] "v1" $levels [1] ">= 50" "< 50" > stopifnot(all(kidids_split(sv1, dat) == ((dat$v1 < 50) + 1))) > > sv1 <- partysplit(as.integer(1), breaks = as.double(c(25, 75))) > character_split(sv1, dat) $name [1] "v1" $levels [1] "(-Inf,25]" "(25,75]" "(75, Inf]" > stopifnot(all(kidids_split(sv1, dat) == + as.integer(cut(dat$v1, c(-Inf, 25, 75, Inf))))) > > sv1 <- partysplit(as.integer(1), breaks = as.double(c(25, 75)), right = FALSE) > character_split(sv1, dat) $name [1] "v1" $levels [1] "[-Inf,25)" "[25,75)" "[75, Inf)" > stopifnot(all(kidids_split(sv1, dat) == + as.integer(cut(dat$v1, c(-Inf, c(25, 75), Inf), right = FALSE)))) > > sv1 <- partysplit(as.integer(1), breaks = as.double(c(25, 75)), + index = as.integer(3:1), right = FALSE) > character_split(sv1, dat) $name [1] "v1" $levels [1] "[75, Inf)" "[25,75)" "[-Inf,25)" > stopifnot(all(kidids_split(sv1, dat) == + (3:1)[as.integer(cut(dat$v1, c(-Inf, c(25, 75), Inf), right = FALSE))])) > > > dat$v2 <- gl(4, 25) > > sv2 <- partysplit(as.integer(2), index = as.integer(c(1, 2, 1, 2))) > character_split(sv2, dat) $name [1] "v2" $levels [1] "1, 3" "2, 4" > kidids_split(sv2, dat) [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 [38] 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 [75] 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 > > sv2 <- partysplit(as.integer(2), breaks = as.integer(c(1, 3))) > character_split(sv2, dat) $name [1] "v2" $levels [1] "1" "2, 3" "4" > kidids_split(sv2, dat) [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 [38] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 [75] 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 > > > dat <- data.frame(x = gl(3, 30, labels = LETTERS[1:3]), y = rnorm(90), + z = gl(9, 10, labels = LETTERS[1:9], ordered = TRUE)) > csp <- partysplit(as.integer(1), index = as.integer(c(1, 2, 1))) > kidids_split(csp, dat) [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 [39] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 [77] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 > #kidids_node(list(csp), dat) > > nsp <- partysplit(as.integer(2), breaks = c(-1, 0, 1), index = as.integer(c(1, 2, 1, 3))) > kidids_split(nsp, dat) [1] 2 1 2 3 1 2 1 1 1 2 3 1 2 1 3 2 2 1 1 1 1 1 1 1 1 2 2 1 2 1 3 2 1 2 1 2 2 2 [39] 3 1 2 2 1 1 2 2 1 1 2 1 1 2 1 1 3 3 2 1 1 2 3 2 1 1 2 1 1 3 1 3 1 2 1 2 1 1 [77] 2 1 1 2 2 2 3 1 1 1 3 2 1 1 > > osp <- partysplit(as.integer(3), breaks = as.integer(c(3, 6)), index = as.integer(c(2, 1, 2))) > kidids_split(osp, dat) [1] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 [39] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 [77] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 > > nadat <- dat > nadat$x[1:10] <- NA > nadat$y[11:20] <- NA > #kidids_node(list(csp, nsp, osp), nadat) > > character_split(csp, dat) $name [1] "x" $levels [1] "A, C" "B" > character_split(nsp, dat) $name [1] "y" $levels [1] "(-Inf,-1] | (0,1]" "(-1,0]" "(1, Inf]" > character_split(osp, dat) $name [1] "z" $levels [1] "D, E, F" "A, B, C, G, H, I" > > > proc.time() user system elapsed 1.056 0.061 1.101 partykit/tests/regtest-glmtree.R0000644000176200001440000000761514172230001016517 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") set.seed(29) n <- 1000 x <- runif(n) z <- runif(n) y <- rnorm(n, mean = x * c(-1, 1)[(z > 0.7) + 1], sd = 3) z_noise <- factor(sample(1:3, size = n, replace = TRUE)) d <- data.frame(y = y, x = x, z = z, z_noise = z_noise) fmla <- as.formula("y ~ x | z + z_noise") fmly <- gaussian() fit <- partykit:::glmfit # versions of the data d1 <- d d1$z <- signif(d1$z, digits = 1) k <- 20 zs_noise <- matrix(rnorm(n*k), nrow = n) colnames(zs_noise) <- paste0("z_noise_", 1:k) d2 <- cbind(d, zs_noise) fmla2 <- as.formula(paste("y ~ x | z + z_noise +", paste0("z_noise_", 1:k, collapse = " + "))) d3 <- d2 d3$z <- factor(sample(1:3, size = n, replace = TRUE, prob = c(0.1, 0.5, 0.4))) d3$y <- rnorm(n, mean = x * c(-1, 1)[(d3$z == 2) + 1], sd = 3) ## check weights w <- rep(1, n) w[1:10] <- 2 (mw1 <- glmtree(formula = fmla, data = d, weights = w)) (mw2 <- glmtree(formula = fmla, data = d, weights = w, caseweights = FALSE)) ## check dfsplit (mmfluc2 <- mob(formula = fmla, data = d, fit = partykit:::glmfit)) (mmfluc3 <- glmtree(formula = fmla, data = d)) (mmfluc3_dfsplit <- glmtree(formula = fmla, data = d, dfsplit = 10)) ## check tests if (require("strucchange")) print(sctest(mmfluc3, node = 1)) # does not yet work x <- mmfluc3 (tst3 <- nodeapply(x, ids = nodeids(x), function(n) n$info$criterion)) ## check logLik and AIC logLik(mmfluc2) logLik(mmfluc3) logLik(mmfluc3_dfsplit) logLik(glm(y ~ x, data = d)) AIC(mmfluc3) AIC(mmfluc3_dfsplit) ## check pruning pr2 <- prune.modelparty(mmfluc2) AIC(mmfluc2) AIC(pr2) mmfluc_dfsplit3 <- glmtree(formula = fmla, data = d, alpha = 0.5, dfsplit = 3) mmfluc_dfsplit4 <- glmtree(formula = fmla, data = d, alpha = 0.5, dfsplit = 4) pr_dfsplit3 <- prune.modelparty(mmfluc_dfsplit3) pr_dfsplit4 <- prune.modelparty(mmfluc_dfsplit4) AIC(mmfluc_dfsplit3) AIC(mmfluc_dfsplit4) AIC(pr_dfsplit3) AIC(pr_dfsplit4) width(mmfluc_dfsplit3) width(mmfluc_dfsplit4) width(pr_dfsplit3) width(pr_dfsplit4) ## check inner and terminal options <- list(NULL, "object", "estfun", c("object", "estfun")) arguments <- list("inner", "terminal", c("inner", "terminal")) for (o in options) { print(o) x <- glmtree(formula = fmla, data = d, inner = o) str(nodeapply(x, ids = nodeids(x), function(n) n$info[c("object", "estfun")]), 2) } for (o in options) { print(o) x <- glmtree(formula = fmla, data = d, terminal = o) str(nodeapply(x, ids = nodeids(x), function(n) n$info[c("object", "estfun")]), 2) } ## check model m_mt <- glmtree(formula = fmla, data = d, model = TRUE) m_mf <- glmtree(formula = fmla, data = d, model = FALSE) dim(m_mt$data) dim(m_mf$data) ## check multiway (m_mult <- glmtree(formula = fmla2, data = d3, catsplit = "multiway", minsize = 80)) ## check parm fmla_p <- as.formula("y ~ x + z_noise + z_noise_1 | z + z_noise_2") (m_interc <- glmtree(formula = fmla_p, data = d2, parm = 1)) (m_p3 <- glmtree(formula = fmla_p, data = d2, parm = 3)) ## check trim (m_tt <- glmtree(formula = fmla, data = d, trim = 0.2)) (m_tf <- glmtree(formula = fmla, data = d, trim = 300, minsize = 300)) ## check breakties m_bt <- glmtree(formula = fmla, data = d1, breakties = TRUE) m_df <- glmtree(formula = fmla, data = d1, breakties = FALSE) all.equal(m_bt, m_df, check.environment = FALSE) unclass(m_bt)$node$info$criterion unclass(m_df)$node$info$criterion ### example from mob vignette data("PimaIndiansDiabetes", package = "mlbench") logit <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { glm(y ~ 0 + x, family = binomial, start = start, ...) } pid_formula <- diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age pid_tree <- mob(pid_formula, data = PimaIndiansDiabetes, fit = logit) pid_tree nodeapply(pid_tree, ids = nodeids(pid_tree), function(n) n$info$criterion) partykit/tests/regtest-weights.Rout.save0000644000176200001440000001170614172230001020213 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > > > ## artificial data --------------------------------------------------------------------------------- > set.seed(0) > d <- data.frame(x = seq(-1, 1, length.out = 1000), z = factor(rep(0:1, 500))) > d$y <- 0 + 1 * d$x + rnorm(nrow(d)) > d$w <- rep(1:4, nrow(d)/4) > dd <- d[rep(1:nrow(d), d$w), ] > > > ## convenience function: likelihood ratio test ----------------------------------------------------- > lrtest <- function(data, ...) { + lr <- -2 * (logLik(lm(y ~ x, data = data, ...)) - logLik(lm(y ~ x * z, data = data, ...))) + matrix( + c(lr, pchisq(lr, df = 2, lower.tail = FALSE)), + dimnames = list(c("statistic", "p.value"), "z") + ) + } > > > ## lm: case weights -------------------------------------------------------------------------------- > > ## weighted and explicitly expanded data should match exactly > lm1 <- lmtree(y ~ x | z, data = d, weights = w, maxdepth = 2) > lm2 <- lmtree(y ~ x | z, data = dd, maxdepth = 2) > all.equal(sctest.modelparty(lm1), sctest.modelparty(lm2)) [1] TRUE > > ## LR test should be similar (albeit not identical) > all.equal(sctest.modelparty(lm1), lrtest(dd), tol = 0.05) [1] TRUE > > > ## lm: proportionality weights --------------------------------------------------------------------- > > ## LR test should be similar > lm3 <- lmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE) > all.equal(sctest.modelparty(lm3), lrtest(d, weights = d$w), tol = 0.05) [1] TRUE > > ## constant factor should not change results > lm3x <- lmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE) > all.equal(sctest.modelparty(lm3), sctest.modelparty(lm3x)) [1] TRUE > > > ## glm: case weights ------------------------------------------------------------------------------- > > ## for glm different vcov are available > glm1o <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, vcov = "opg") > glm2o <- glmtree(y ~ x | z, data = dd, maxdepth = 2, vcov = "opg") > all.equal(sctest.modelparty(glm1o), sctest.modelparty(glm1o)) [1] TRUE > > glm1i <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, vcov = "info") > glm2i <- glmtree(y ~ x | z, data = dd, maxdepth = 2, vcov = "info") > all.equal(sctest.modelparty(glm1i), sctest.modelparty(glm2i)) [1] TRUE > > glm1s <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, vcov = "sandwich") > glm2s <- glmtree(y ~ x | z, data = dd, maxdepth = 2, vcov = "sandwich") > all.equal(sctest.modelparty(glm1s), sctest.modelparty(glm2s)) [1] TRUE > > ## different vcov should yield similar (albeit not identical) statistics > all.equal(sctest.modelparty(glm1o), sctest.modelparty(glm1i), tol = 0.05) [1] TRUE > all.equal(sctest.modelparty(glm1o), sctest.modelparty(glm1s), tol = 0.05) [1] TRUE > > ## LR test should be similar > all.equal(sctest.modelparty(glm1o), lrtest(dd), tol = 0.05) [1] TRUE > > > ## glm: proportionality weights -------------------------------------------------------------------- > > ## different test versions should be similar > glmFo <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE, vcov = "opg") > glmFi <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE, vcov = "info") > glmFs <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE, vcov = "sandwich") > > all.equal(sctest.modelparty(glmFo), sctest.modelparty(glmFi), tol = 0.05) [1] TRUE > all.equal(sctest.modelparty(glmFo), sctest.modelparty(glmFs), tol = 0.05) [1] TRUE > all.equal(sctest.modelparty(glmFo), lrtest(d, weights = d$w), tol = 0.05) [1] TRUE > > ## constant factor should not change results > glmFxo <- glmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE, vcov = "opg") > glmFxi <- glmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE, vcov = "info") > glmFxs <- glmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE, vcov = "sandwich") > > all.equal(sctest.modelparty(glmFo), sctest.modelparty(glmFxo)) [1] TRUE > all.equal(sctest.modelparty(glmFi), sctest.modelparty(glmFxi)) [1] TRUE > all.equal(sctest.modelparty(glmFs), sctest.modelparty(glmFxs)) [1] TRUE > > proc.time() user system elapsed 1.457 0.072 1.516 partykit/tests/regtest-cforest.R0000644000176200001440000000756214172230001016526 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") stopifnot(require("party")) set.seed(29) ### regression airq <- airquality[complete.cases(airquality),] mtry <- ncol(airq) - 1L ntree <- 25 cf_partykit <- partykit::cforest(Ozone ~ ., data = airq, ntree = ntree, mtry = mtry) w <- do.call("cbind", cf_partykit$weights) cf_party <- party::cforest(Ozone ~ ., data = airq, control = party::cforest_unbiased(ntree = ntree, mtry = mtry), weights = w) p_partykit <- predict(cf_partykit) p_party <- predict(cf_party) stopifnot(max(abs(p_partykit - p_party)) < sqrt(.Machine$double.eps)) prettytree(cf_party@ensemble[[1]], inames = names(airq)[-1]) party(cf_partykit$nodes[[1]], data = model.frame(cf_partykit)) v_party <- do.call("rbind", lapply(1:5, function(i) party::varimp(cf_party))) v_partykit <- do.call("rbind", lapply(1:5, function(i) partykit::varimp(cf_partykit))) summary(v_party) summary(v_partykit) party::varimp(cf_party, conditional = TRUE) partykit::varimp(cf_partykit, conditional = TRUE) ### classification set.seed(29) mtry <- ncol(iris) - 1L ntree <- 25 cf_partykit <- partykit::cforest(Species ~ ., data = iris, ntree = ntree, mtry = mtry) w <- do.call("cbind", cf_partykit$weights) cf_party <- party::cforest(Species ~ ., data = iris, control = party::cforest_unbiased(ntree = ntree, mtry = mtry), weights = w) p_partykit <- predict(cf_partykit, type = "prob") p_party <- do.call("rbind", treeresponse(cf_party)) stopifnot(max(abs(unclass(p_partykit) - unclass(p_party))) < sqrt(.Machine$double.eps)) prettytree(cf_party@ensemble[[1]], inames = names(iris)[-5]) party(cf_partykit$nodes[[1]], data = model.frame(cf_partykit)) v_party <- do.call("rbind", lapply(1:5, function(i) party::varimp(cf_party))) v_partykit <- do.call("rbind", lapply(1:5, function(i) partykit::varimp(cf_partykit, risk = "mis"))) summary(v_party) summary(v_partykit) party::varimp(cf_party, conditional = TRUE) partykit::varimp(cf_partykit, risk = "misclass", conditional = TRUE) ### mean aggregation set.seed(29) ### fit forest cf <- partykit::cforest(dist ~ speed, data = cars, ntree = 100) ### prediction; scale = TRUE introduced in 1.2-1 pr <- predict(cf, newdata = cars[1,,drop = FALSE], type = "response", scale = TRUE) ### this is equivalent to w <- predict(cf, newdata = cars[1,,drop = FALSE], type = "weights") stopifnot(isTRUE(all.equal(pr, sum(w * cars$dist) / sum(w), check.attributes = FALSE))) ### check if this is the same as mean aggregation ### compute terminal node IDs for first obs nd1 <- predict(cf, newdata = cars[1,,drop = FALSE], type = "node") ### compute terminal nide IDs for all obs nd <- predict(cf, newdata = cars, type = "node") ### random forests weighs lw <- cf$weights ### compute mean predictions for each tree ### and extract mean for terminal node containing ### first observation np <- vector(mode = "list", length = length(lw)) m <- numeric(length(lw)) for (i in 1:length(lw)) { np[[i]] <- tapply(lw[[i]] * cars$dist, nd[[i]], sum) / tapply(lw[[i]], nd[[i]], sum) m[i] <- np[[i]][as.character(nd1[i])] } stopifnot(isTRUE(all.equal(mean(m), sum(w * cars$dist) / sum(w)))) ### check parallel variable importance (make this reproducible) if(.Platform$OS.type == "unix") { RNGkind("L'Ecuyer-CMRG") v1 <- partykit::varimp(cf_partykit, risk = "misclass", conditional = TRUE, cores = 2) v2 <- partykit::varimp(cf_partykit, risk = "misclass", conditional = TRUE, cores = 2) stopifnot(all.equal(v1, v2)) } ### check weights argument cf_partykit <- partykit::cforest(Species ~ ., data = iris, ntree = ntree, mtry = 4) w <- do.call("cbind", cf_partykit$weights) cf_2 <- partykit::cforest(Species ~ ., data = iris, ntree = ntree, mtry = 4, weights = w) stopifnot(max(abs(predict(cf_2, type = "prob") - predict(cf_partykit, type = "prob"))) < sqrt(.Machine$double.eps)) partykit/tests/regtest-lmtree.R0000644000176200001440000000110414172230000016332 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") set.seed(29) n <- 1000 x <- runif(n) z <- runif(n) y <- rnorm(n, mean = x * c(-1, 1)[(z > 0.7) + 1], sd = 3) z_noise <- factor(sample(1:3, size = n, replace = TRUE)) d <- data.frame(y = y, x = x, z = z, z_noise = z_noise) fmla <- as.formula("y ~ x | z + z_noise") (m_mob <- mob(formula = fmla, data = d, fit = partykit:::lmfit)) (m_lm2 <- lmtree(formula = fmla, data = d)) mods <- nodeapply(m_lm2, ids = nodeids(m_lm2, terminal = TRUE), function(x) x$info$object) sum(sapply(mods, function(x) sum(x$residuals^2))) partykit/tests/regtest-node.Rout.save0000644000176200001440000000310214172230001017455 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > set.seed(1) > > mysplit <- function(x) partysplit(1L, breaks = as.double(x)) > x <- vector(mode = "list", length = 5) > x[[1]] <- list(id = 1L, split = mysplit(1 / 3), kids = 2:3, info = "one") > x[[2]] <- list(id = 2L, info = "two") > x[[3]] <- list(id = 3L, split = mysplit(2 / 3), kids = 4:5, info = "three") > x[[4]] <- list(id = 4L, info = "four") > x[[5]] <- list(id = 5L, info = "five") > > rx <- as.partynode(x) > stopifnot(identical(as.list(rx), x)) > > dat <- data.frame(x = runif(100)) > kidids_node(rx, dat) [1] 1 2 2 2 1 2 2 2 2 1 1 1 2 2 2 2 2 2 2 2 2 1 2 1 1 2 1 2 2 2 2 2 2 1 2 2 2 [38] 1 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 1 1 1 2 2 2 2 1 2 1 2 1 2 2 1 2 2 2 2 2 [75] 2 2 2 2 2 2 2 2 2 1 2 1 2 1 1 1 1 1 2 2 2 2 2 2 2 2 > > proc.time() user system elapsed 1.643 0.115 1.727 partykit/tests/regtest-party.Rout.save0000644000176200001440000012764114172230000017705 0ustar liggesusers R version 4.1.1 (2021-08-10) -- "Kick Things" Copyright (C) 2021 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > ## load package and fix seed > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > set.seed(1) > > ## rpart: kyphosis data > library("rpart") > data("kyphosis", package = "rpart") > fit <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis) > pfit <- as.party(fit) > all(predict(pfit, newdata = kyphosis, type = "node") == fit$where) [1] TRUE > > ## J48: iris data > if (require("RWeka")) { + data("iris", package = "datasets") + itree <- J48(Species ~ ., data = iris) + pitree <- as.party(itree) + stopifnot(all(predict(pitree) == predict(pitree, newdata = iris[, 3:4]))) + + print(all.equal(predict(itree, type = "prob", newdata = iris), + predict(pitree, type = "prob", newdata = iris))) + print(all.equal(predict(itree, newdata = iris), + predict(pitree, newdata = iris))) + + ## rpart/J48: GlaucomaM data + data("GlaucomaM", package = "TH.data") + w <- runif(nrow(GlaucomaM)) + fit <- rpart(Class ~ ., data = GlaucomaM, weights = w) + pfit <- as.party(fit) + print(all(predict(pfit, type = "node") == fit$where)) + tmp <- GlaucomaM[sample(1:nrow(GlaucomaM), 100),] + print(all.equal(predict(fit, type = "prob", newdata = tmp), predict(pfit, type = "prob", newdata = tmp))) + print(all.equal(predict(fit, type = "class", newdata = tmp), predict(pfit, newdata = tmp))) + itree <- J48(Class ~ ., data = GlaucomaM) + pitree <- as.party(itree) + print(all.equal(predict(itree, newdata = tmp, type = "prob"), predict(pitree, newdata = tmp, type = "prob"))) + } Loading required package: RWeka [1] TRUE [1] "names for current but not for target" [1] TRUE [1] TRUE [1] TRUE [1] TRUE > > ## rpart: airquality data > data("airquality") > aq <- subset(airquality, !is.na(Ozone)) > w <- runif(nrow(aq), max = 3) > aqr <- rpart(Ozone ~ ., data = aq, weights = w) > aqp <- as.party(aqr) > tmp <- subset(airquality, is.na(Ozone)) > all.equal(predict(aqr, newdata = tmp), predict(aqp, newdata = tmp)) [1] TRUE > > ## rpart: GBSG2 data > data("GBSG2", package = "TH.data") > library("survival") > fit <- rpart(Surv(time, cens) ~ ., data = GBSG2) > pfit <- as.party(fit) > pfit$fitted (fitted) (response) 1 6 1814 2 8 2018 3 8 712 4 8 1807 5 6 772 6 11 448 7 3 2172+ 8 5 2161+ 9 11 471 10 10 2014+ 11 10 577 12 10 184 13 5 1840+ 14 6 1842+ 15 5 1821+ 16 5 1371 17 8 707 18 5 1743+ 19 5 1781+ 20 8 865 21 6 1684 22 5 1701+ 23 6 1701+ 24 6 1693+ 25 11 379 26 5 1105 27 6 548 28 8 1296 29 6 1483+ 30 6 1570+ 31 6 1469+ 32 6 1472+ 33 5 1342+ 34 6 1349+ 35 8 1162 36 6 1342+ 37 11 797 38 8 1232+ 39 6 1230+ 40 8 1205+ 41 8 1090+ 42 8 1095+ 43 6 449 44 6 972+ 45 6 825+ 46 6 2438+ 47 6 2233+ 48 11 286 49 8 1861+ 50 8 1080 51 6 1521 52 6 1693+ 53 6 1528 54 10 169 55 8 272 56 6 731 57 8 2059+ 58 8 1853+ 59 10 1854+ 60 8 1645+ 61 11 544 62 8 1666+ 63 6 353 64 8 1791+ 65 6 1685+ 66 3 191 67 10 370 68 8 173 69 11 242 70 6 420 71 8 438 72 6 1624+ 73 10 1036 74 11 359 75 8 171 76 11 959 77 6 1351+ 78 10 486 79 11 525 80 5 762 81 10 175 82 3 1195+ 83 10 338 84 8 1125+ 85 8 916+ 86 6 972+ 87 3 867+ 88 10 249 89 11 281 90 6 758+ 91 11 377 92 6 1976+ 93 5 2539+ 94 6 2467+ 95 5 876 96 5 2132+ 97 11 426 98 5 554 99 8 1246 100 5 1926+ 101 11 1207 102 8 1852+ 103 8 1174 104 8 1250+ 105 6 530 106 10 1502+ 107 5 1364+ 108 8 1170 109 6 1729+ 110 5 1642+ 111 5 1218 112 3 1358+ 113 11 360 114 5 550 115 8 857+ 116 8 768+ 117 6 858+ 118 6 770+ 119 10 679 120 6 1164 121 6 350 122 6 578 123 6 1460 124 6 1434+ 125 6 1763 126 6 889 127 11 357 128 8 547 129 5 1722+ 130 6 2372+ 131 6 2030 132 5 1002 133 3 1280 134 8 338 135 6 533 136 6 168+ 137 5 1169+ 138 5 1675 139 6 1862+ 140 5 629+ 141 10 1167+ 142 6 495 143 5 967+ 144 5 1720+ 145 6 598 146 11 392 147 3 1502+ 148 6 229+ 149 8 310+ 150 5 1296+ 151 10 488+ 152 3 942+ 153 8 570+ 154 10 1177+ 155 8 1113+ 156 8 288 157 6 723+ 158 11 403 159 10 1225 160 8 338 161 8 1337 162 6 1420 163 8 2048+ 164 8 600 165 5 1765+ 166 8 491 167 10 305 168 6 1582+ 169 8 1771+ 170 8 960 171 10 571 172 8 675+ 173 5 285 174 8 1472+ 175 5 1279 176 6 148+ 177 6 1863+ 178 5 1933+ 179 10 358 180 5 734+ 181 6 2372 182 6 2563+ 183 5 2372+ 184 6 1989 185 8 2015 186 6 1956+ 187 8 945 188 6 2153+ 189 6 838 190 8 113 191 6 1833+ 192 8 1722+ 193 8 241 194 5 1352 195 8 1702+ 196 8 1222+ 197 6 1089+ 198 3 1243+ 199 8 579 200 8 1043 201 6 2234+ 202 5 2297+ 203 6 2014+ 204 6 518 205 6 940+ 206 6 766+ 207 11 251 208 6 1959+ 209 3 1897+ 210 11 160 211 5 970+ 212 5 892+ 213 5 753+ 214 8 348 215 10 275 216 5 1329 217 6 1193 218 10 698 219 10 436 220 6 552 221 6 564 222 6 2239+ 223 5 2237+ 224 6 529 225 3 1820+ 226 6 1756+ 227 11 515 228 11 272 229 6 891 230 6 1356+ 231 10 1352+ 232 6 1077+ 233 6 675 234 10 855+ 235 6 740+ 236 6 2551+ 237 8 754 238 8 819 239 10 1280 240 5 2388+ 241 5 2296+ 242 6 1884+ 243 6 1059 244 8 859+ 245 6 1109+ 246 6 1192 247 8 1806 248 11 500 249 10 1589 250 10 1463 251 6 1826+ 252 8 1231+ 253 5 1117+ 254 8 836 255 6 1222+ 256 8 663+ 257 10 722 258 5 322+ 259 6 1150 260 10 446 261 10 1855+ 262 10 238 263 6 1838+ 264 11 1826+ 265 6 1093 266 3 2051+ 267 10 370 268 5 861 269 10 1587 270 6 552 271 3 2353+ 272 8 2471+ 273 8 893 274 5 2093 275 10 2612+ 276 8 956 277 10 1637+ 278 5 2456+ 279 8 2227+ 280 6 1601 281 6 1841+ 282 8 2177+ 283 6 2052+ 284 11 973+ 285 3 2156+ 286 8 1499+ 287 3 2030+ 288 8 573 289 5 1666+ 290 8 1979+ 291 8 1786+ 292 8 1847+ 293 5 2009+ 294 5 1926+ 295 3 1490+ 296 11 233 297 8 1240+ 298 3 1751+ 299 8 1878+ 300 5 1171+ 301 10 1751+ 302 6 1756+ 303 8 714 304 8 1505+ 305 8 776 306 6 1443+ 307 3 1317+ 308 6 870+ 309 11 859 310 6 223 311 6 1212+ 312 5 1119+ 313 8 740+ 314 8 1062+ 315 5 8+ 316 6 936+ 317 8 740+ 318 10 632 319 5 1760+ 320 6 1013+ 321 10 779+ 322 10 375 323 8 1323+ 324 5 1233+ 325 5 986+ 326 10 650+ 327 10 628+ 328 6 1866+ 329 8 491 330 6 1918 331 10 72 332 10 1140 333 8 799 334 6 1105 335 5 548 336 11 227 337 6 1838+ 338 3 1833+ 339 6 550 340 6 426 341 8 1834+ 342 6 1604+ 343 10 772+ 344 8 1146 345 6 371 346 8 883 347 6 1735+ 348 8 554 349 11 790 350 5 1340+ 351 11 490 352 3 1557+ 353 6 594 354 10 828+ 355 8 594 356 8 841+ 357 5 695+ 358 5 2556+ 359 6 1753 360 10 417 361 6 956 362 8 1846+ 363 8 1703+ 364 6 1720+ 365 6 1355+ 366 6 1603+ 367 8 476 368 8 1350+ 369 5 1341+ 370 3 2449+ 371 8 2286 372 6 456 373 6 536 374 5 612 375 6 2034 376 6 1990 377 10 2456 378 3 2205+ 379 6 544 380 10 336 381 6 2057+ 382 8 575 383 5 2011+ 384 8 537 385 3 2217+ 386 8 1814 387 6 890 388 5 1114+ 389 10 974+ 390 6 296+ 391 8 2320+ 392 8 795 393 8 867 394 5 1703+ 395 6 670 396 8 981 397 5 1094+ 398 5 755 399 10 1388 400 6 1387 401 10 535 402 6 1653+ 403 6 1904+ 404 8 1868+ 405 3 1767+ 406 6 855 407 6 1157 408 8 1869+ 409 8 1152+ 410 6 1401+ 411 6 918+ 412 10 745 413 8 1283+ 414 6 1481 415 8 1807+ 416 6 542 417 10 1441+ 418 8 1277+ 419 8 1486+ 420 5 273+ 421 10 177 422 6 545 423 6 1185+ 424 11 631+ 425 6 995+ 426 8 1088+ 427 6 877+ 428 8 798+ 429 8 2380+ 430 5 1679 431 10 498 432 8 2138+ 433 8 2175+ 434 5 2271+ 435 6 17+ 436 6 964 437 10 540 438 11 747 439 11 650 440 11 410 441 11 624 442 10 1560+ 443 11 455 444 5 1629+ 445 8 1730+ 446 6 1483+ 447 6 687 448 6 308 449 10 563 450 5 46+ 451 6 2144+ 452 10 344 453 6 945+ 454 6 1905+ 455 11 855 456 5 2370+ 457 6 853+ 458 8 692+ 459 8 475 460 5 2195+ 461 8 758+ 462 8 648 463 3 761+ 464 8 596+ 465 11 195 466 10 473 467 5 747+ 468 5 2659+ 469 11 1977 470 6 2401+ 471 5 1499+ 472 11 1856+ 473 11 595 474 5 2148+ 475 6 2126+ 476 8 1975 477 6 1641 478 8 1717+ 479 5 1858+ 480 5 2049+ 481 8 1502 482 3 1922+ 483 5 1818+ 484 11 1100+ 485 6 1499+ 486 6 359 487 8 1645+ 488 5 1356+ 489 6 1632+ 490 6 967+ 491 6 1091+ 492 6 918 493 6 557 494 5 1219 495 6 2170+ 496 6 729 497 10 1449 498 5 991 499 6 481 500 6 1655+ 501 6 857 502 6 369 503 5 1627+ 504 5 1578+ 505 8 732 506 8 460 507 6 1208+ 508 8 730 509 8 722+ 510 6 717+ 511 8 651+ 512 5 637+ 513 6 615+ 514 10 42+ 515 11 307 516 8 983 517 11 120 518 6 1525 519 8 1680+ 520 11 1730 521 8 805 522 8 2388+ 523 6 559 524 10 1977+ 525 6 476 526 5 1514+ 527 5 1617+ 528 6 1094 529 5 784 530 10 181 531 10 415 532 8 1120 533 10 316 534 8 637 535 6 247 536 8 888+ 537 10 622 538 6 806+ 539 6 1163+ 540 5 1721+ 541 5 741+ 542 6 372 543 6 1331+ 544 8 394 545 3 652+ 546 10 657+ 547 6 567+ 548 10 429+ 549 5 566+ 550 11 15+ 551 8 98 552 5 368+ 553 5 432+ 554 5 319+ 555 10 65+ 556 8 16+ 557 10 29+ 558 8 18+ 559 8 17+ 560 10 308 561 6 1965+ 562 11 548 563 10 293 564 8 2017+ 565 10 1093+ 566 3 792+ 567 6 586 568 6 1434+ 569 8 67+ 570 8 623+ 571 6 2128+ 572 6 1965+ 573 6 2161+ 574 10 1183 575 6 1108 576 5 2065+ 577 6 1598+ 578 6 491 579 10 1366 580 6 424+ 581 11 859 582 11 180 583 5 1625+ 584 3 1938+ 585 8 1343 586 6 646 587 6 2192+ 588 6 502 589 10 1675+ 590 11 1363 591 11 420 592 8 982 593 6 1459+ 594 6 1192+ 595 6 1264+ 596 8 1095+ 597 8 1078+ 598 3 737+ 599 8 461+ 600 11 465 601 11 842 602 6 918+ 603 8 374 604 6 1089+ 605 5 1527+ 606 8 285 607 6 1306 608 10 797 609 5 1441+ 610 6 343 611 8 936+ 612 5 195+ 613 6 503 614 11 827 615 5 1427+ 616 6 854+ 617 8 177 618 10 281 619 5 205 620 8 751+ 621 8 629 622 6 526+ 623 6 463+ 624 5 529+ 625 8 623+ 626 11 546+ 627 5 213+ 628 6 276+ 629 8 2010+ 630 8 2009+ 631 3 1984+ 632 10 1981+ 633 10 624 634 10 742 635 3 1818+ 636 8 1493 637 5 1432+ 638 5 801 639 6 1182+ 640 6 71+ 641 10 114+ 642 6 63+ 643 6 1722+ 644 5 1692+ 645 6 177+ 646 5 57+ 647 5 1152+ 648 6 733+ 649 6 1459 650 5 2237+ 651 6 933+ 652 5 2056+ 653 10 1729+ 654 10 2024+ 655 5 2039 656 6 2027+ 657 6 2007+ 658 6 1253 659 6 1789+ 660 8 1707+ 661 6 1714+ 662 5 1717+ 663 6 329 664 5 1624+ 665 6 1600+ 666 5 385 667 3 1475+ 668 5 1435+ 669 11 541+ 670 5 1329+ 671 8 1357+ 672 6 1343+ 673 5 748 674 5 1090 675 6 1219+ 676 5 553+ 677 8 662 678 5 969+ 679 8 974+ 680 8 866 681 10 504 682 6 721+ 683 11 186+ 684 8 769 685 6 727 686 8 1701 > predict(pfit, newdata = GBSG2[1:100,], type = "prob") $`1` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`2` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`3` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`4` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`5` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`6` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`7` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 33 2 NA NA NA $`8` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`9` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`10` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`11` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`12` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`13` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`14` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`15` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`16` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`17` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`18` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`19` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`20` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`21` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`22` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`23` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`24` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`25` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`26` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`27` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`28` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`29` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`30` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`31` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`32` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`33` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`34` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`35` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`36` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`37` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`38` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`39` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`40` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`41` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`42` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`43` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`44` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`45` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`46` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`47` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`48` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`49` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`50` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`51` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`52` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`53` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`54` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`55` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`56` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`57` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`58` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`59` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`60` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`61` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`62` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`63` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`64` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`65` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`66` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 33 2 NA NA NA $`67` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`68` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`69` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`70` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`71` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`72` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`73` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`74` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`75` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`76` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`77` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`78` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`79` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`80` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`81` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`82` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 33 2 NA NA NA $`83` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`84` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`85` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`86` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`87` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 33 2 NA NA NA $`88` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 87 55 742 577 1366 $`89` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`90` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`91` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`92` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`93` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`94` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 221 89 1989 1641 NA $`95` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`96` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`97` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 57 48 500 426 747 $`98` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA $`99` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 $`100` Call: survfit(formula = y ~ 1, weights = w, subset = w > 0) n events median 0.95LCL 0.95UCL [1,] 122 28 NA NA NA > predict(pfit, newdata = GBSG2[1:100,], type = "response") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1989 1701 1701 1701 1989 500 Inf Inf 500 742 742 742 Inf 1989 Inf Inf 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 1701 Inf Inf 1701 1989 Inf 1989 1989 500 Inf 1989 1701 1989 1989 1989 1989 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 Inf 1989 1701 1989 500 1701 1989 1701 1701 1701 1989 1989 1989 1989 1989 500 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 1701 1701 1989 1989 1989 742 1701 1989 1701 1701 742 1701 500 1701 1989 1701 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 1989 Inf 742 1701 500 1989 1701 1989 742 500 1701 500 1989 742 500 Inf 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 742 Inf 742 1701 1701 1989 Inf 742 500 1989 500 1989 Inf 1989 Inf Inf 97 98 99 100 500 Inf 1701 Inf > > ### multiple responses > f <- fitted(pfit) > f[["(response)"]] <- data.frame(srv = f[["(response)"]], hansi = runif(nrow(f))) > mp <- party(node_party(pfit), fitted = f, data = pfit$data) > class(mp) <- c("constparty", "party") > predict(mp, newdata = GBSG2[1:10,]) srv hansi 1 1989 0.5017739 2 1701 0.4933225 3 1701 0.4933225 4 1701 0.4933225 5 1989 0.5017739 6 500 0.4823559 7 Inf 0.4662471 8 Inf 0.4839262 9 500 0.4823559 10 742 0.5108953 > > ### pruning > ## create party > data("WeatherPlay", package = "partykit") > py <- party( + partynode(1L, + split = partysplit(1L, index = 1:3), + kids = list( + partynode(2L, + split = partysplit(3L, breaks = 75), + kids = list( + partynode(3L, info = "yes"), + partynode(4L, info = "no"))), + partynode(5L, + split = partysplit(3L, breaks = 20), + kids = list( + partynode(6L, info = "no"), + partynode(7L, info = "yes"))), + partynode(8L, + split = partysplit(4L, index = 1:2), + kids = list( + partynode(9L, info = "yes"), + partynode(10L, info = "no"))))), + WeatherPlay) > names(py) <- LETTERS[nodeids(py)] > > ## print > print(py) [A] root | [B] outlook in sunny | | [C] humidity <= 75: yes | | [D] humidity > 75: no | [E] outlook in overcast | | [F] humidity <= 20: no | | [G] humidity > 20: yes | [H] outlook in rainy | | [I] windy in false: yes | | [J] windy in true: no > (py5 <- nodeprune(py, 5)) [A] root | [B] outlook in sunny | | [C] humidity <= 75: yes | | [D] humidity > 75: no | [E] outlook in overcast: * | [H] outlook in rainy | | [I] windy in false: yes | | [J] windy in true: no > nodeids(py5) [1] 1 2 3 4 5 6 7 8 > (pyH <- nodeprune(py5, "H")) [A] root | [B] outlook in sunny | | [C] humidity <= 75: yes | | [D] humidity > 75: no | [E] outlook in overcast: * | [H] outlook in rainy: * > nodeids(pyH) [1] 1 2 3 4 5 6 > > ct <- ctree(Species ~ ., data = iris) > nt <- node_party(ctree(Species ~ ., data = iris)) > (ctp <- nodeprune(ct, 4)) ### party method Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [1] root | [2] Petal.Length <= 1.9: setosa (n = 50, err = 0.0%) | [3] Petal.Length > 1.9 | | [4] Petal.Width <= 1.7: versicolor (n = 54, err = 9.3%) | | [5] Petal.Width > 1.7: virginica (n = 46, err = 2.2%) Number of inner nodes: 2 Number of terminal nodes: 3 > (ntp <- nodeprune(nt, 4)) ### partynode method [1] root | [2] V4 <= 1.9 * | [3] V4 > 1.9 | | [4] V5 <= 1.7 * | | [5] V5 > 1.7 * > > ### check if both methods do the same > p1 <- predict(party(ntp, data = model.frame(ct)), type = "node") > p2 <- predict(ctp, type = "node") > stopifnot(max(abs(p1 - p2)) == 0) > > names(ct) <- LETTERS[nodeids(ct)] > (ctp <- nodeprune(ct, "D")) Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [A] root | [B] Petal.Length <= 1.9: setosa (n = 50, err = 0.0%) | [C] Petal.Length > 1.9 | | [D] Petal.Width <= 1.7: versicolor (n = 54, err = 9.3%) | | [G] Petal.Width > 1.7: virginica (n = 46, err = 2.2%) Number of inner nodes: 2 Number of terminal nodes: 3 > > table(predict(ct, type = "node"), + predict(ctp, type = "node")) 2 4 5 2 50 0 0 5 0 46 0 6 0 8 0 7 0 0 46 > > (ct <- nodeprune(ct, names(ct)[names(ct) != "A"])) Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [A] root | [B] Petal.Length <= 1.9: setosa (n = 50, err = 0.0%) | [C] Petal.Length > 1.9: versicolor (n = 100, err = 50.0%) Number of inner nodes: 1 Number of terminal nodes: 2 > table(predict(ct, type = "node")) 2 3 50 100 > > nodeprune(ct, "B") Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [A] root | [B] Petal.Length <= 1.9: setosa (n = 50, err = 0.0%) | [C] Petal.Length > 1.9: versicolor (n = 100, err = 50.0%) Number of inner nodes: 1 Number of terminal nodes: 2 > nodeprune(ct, "C") Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [A] root | [B] Petal.Length <= 1.9: setosa (n = 50, err = 0.0%) | [C] Petal.Length > 1.9: versicolor (n = 100, err = 50.0%) Number of inner nodes: 1 Number of terminal nodes: 2 > nodeprune(ct, "A") Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [A] root: setosa (n = 150, err = 66.7%) Number of inner nodes: 0 Number of terminal nodes: 1 > > ### check different predict flavours for numeric responses > x <- runif(100) > dd <- data.frame(y = rnorm(length(x), mean = 2 * (x < .5)), x = x) > ct <- ctree(y ~ x, data = dd) > nd <- data.frame(x = (1:9) / 10) > predict(ct, newdata = nd, type = "node") 1 2 3 4 5 6 7 8 9 2 2 2 2 2 4 4 4 5 > predict(ct, newdata = nd, type = "response") 1 2 3 4 5 6 7 2.1123074 2.1123074 2.1123074 2.1123074 2.1123074 0.3779526 0.3779526 8 9 0.3779526 -0.5112136 > predict(ct, newdata = nd, type = "prob") $`1` Empirical CDF Call: ecdf(y) x[1:58] = -0.30626, -0.14847, 0.11198, ..., 3.5936, 3.8115 $`2` Empirical CDF Call: ecdf(y) x[1:58] = -0.30626, -0.14847, 0.11198, ..., 3.5936, 3.8115 $`3` Empirical CDF Call: ecdf(y) x[1:58] = -0.30626, -0.14847, 0.11198, ..., 3.5936, 3.8115 $`4` Empirical CDF Call: ecdf(y) x[1:58] = -0.30626, -0.14847, 0.11198, ..., 3.5936, 3.8115 $`5` Empirical CDF Call: ecdf(y) x[1:58] = -0.30626, -0.14847, 0.11198, ..., 3.5936, 3.8115 $`6` Empirical CDF Call: ecdf(y) x[1:26] = -1.416, -0.69778, -0.65081, ..., 1.6409, 1.7415 $`7` Empirical CDF Call: ecdf(y) x[1:26] = -1.416, -0.69778, -0.65081, ..., 1.6409, 1.7415 $`8` Empirical CDF Call: ecdf(y) x[1:26] = -1.416, -0.69778, -0.65081, ..., 1.6409, 1.7415 $`9` Empirical CDF Call: ecdf(y) x[1:16] = -2.0379, -1.6793, -1.6389, ..., 0.69065, 1.245 > predict(ct, newdata = nd, type = "quantile") 10% 50% 90% 1 1.0641709 2.1259409 3.253851 2 1.0641709 2.1259409 3.253851 3 1.0641709 2.1259409 3.253851 4 1.0641709 2.1259409 3.253851 5 1.0641709 2.1259409 3.253851 6 -0.5344305 0.3963687 1.361417 7 -0.5344305 0.3963687 1.361417 8 -0.5344305 0.3963687 1.361417 9 -1.6591116 -0.3834531 0.485164 > predict(ct, newdata = nd, type = "quantile", at = NULL) $`1` function (p, ...) quantile(y, probs = p, ...) $`2` function (p, ...) quantile(y, probs = p, ...) $`3` function (p, ...) quantile(y, probs = p, ...) $`4` function (p, ...) quantile(y, probs = p, ...) $`5` function (p, ...) quantile(y, probs = p, ...) $`6` function (p, ...) quantile(y, probs = p, ...) $`7` function (p, ...) quantile(y, probs = p, ...) $`8` function (p, ...) quantile(y, probs = p, ...) $`9` function (p, ...) quantile(y, probs = p, ...) > predict(ct, newdata = nd, type = "density") $`1` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`2` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`3` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`4` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`5` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`6` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`7` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`8` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) $`9` function (v) .approxfun(x, y, v, method, yleft, yright, f, na.rm) > predict(ct, newdata = nd, type = "density", at = (1:9) / 10) [,1] [,2] [,3] [,4] [,5] [,6] [,7] 1 0.05020125 0.04935438 0.05087955 0.05661364 0.06796655 0.08560162 0.1092080 2 0.05020125 0.04935438 0.05087955 0.05661364 0.06796655 0.08560162 0.1092080 3 0.05020125 0.04935438 0.05087955 0.05661364 0.06796655 0.08560162 0.1092080 4 0.05020125 0.04935438 0.05087955 0.05661364 0.06796655 0.08560162 0.1092080 5 0.05020125 0.04935438 0.05087955 0.05661364 0.06796655 0.08560162 0.1092080 6 0.53975912 0.57687027 0.59689413 0.59443918 0.56427527 0.50605792 0.4289844 7 0.53975912 0.57687027 0.59689413 0.59443918 0.56427527 0.50605792 0.4289844 8 0.53975912 0.57687027 0.59689413 0.59443918 0.56427527 0.50605792 0.4289844 9 0.37075877 0.34250760 0.31088903 0.27813780 0.24612980 0.21627046 0.1894201 [,8] [,9] 1 0.1376954 0.1693900 2 0.1376954 0.1693900 3 0.1376954 0.1693900 4 0.1376954 0.1693900 5 0.1376954 0.1693900 6 0.3508934 0.2908752 7 0.3508934 0.2908752 8 0.3508934 0.2908752 9 0.1658930 0.1455540 > > proc.time() user system elapsed 2.949 0.143 2.179 partykit/tests/regtest-weights.R0000644000176200001440000000755614172230001016536 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") ## artificial data --------------------------------------------------------------------------------- set.seed(0) d <- data.frame(x = seq(-1, 1, length.out = 1000), z = factor(rep(0:1, 500))) d$y <- 0 + 1 * d$x + rnorm(nrow(d)) d$w <- rep(1:4, nrow(d)/4) dd <- d[rep(1:nrow(d), d$w), ] ## convenience function: likelihood ratio test ----------------------------------------------------- lrtest <- function(data, ...) { lr <- -2 * (logLik(lm(y ~ x, data = data, ...)) - logLik(lm(y ~ x * z, data = data, ...))) matrix( c(lr, pchisq(lr, df = 2, lower.tail = FALSE)), dimnames = list(c("statistic", "p.value"), "z") ) } ## lm: case weights -------------------------------------------------------------------------------- ## weighted and explicitly expanded data should match exactly lm1 <- lmtree(y ~ x | z, data = d, weights = w, maxdepth = 2) lm2 <- lmtree(y ~ x | z, data = dd, maxdepth = 2) all.equal(sctest.modelparty(lm1), sctest.modelparty(lm2)) ## LR test should be similar (albeit not identical) all.equal(sctest.modelparty(lm1), lrtest(dd), tol = 0.05) ## lm: proportionality weights --------------------------------------------------------------------- ## LR test should be similar lm3 <- lmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE) all.equal(sctest.modelparty(lm3), lrtest(d, weights = d$w), tol = 0.05) ## constant factor should not change results lm3x <- lmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE) all.equal(sctest.modelparty(lm3), sctest.modelparty(lm3x)) ## glm: case weights ------------------------------------------------------------------------------- ## for glm different vcov are available glm1o <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, vcov = "opg") glm2o <- glmtree(y ~ x | z, data = dd, maxdepth = 2, vcov = "opg") all.equal(sctest.modelparty(glm1o), sctest.modelparty(glm1o)) glm1i <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, vcov = "info") glm2i <- glmtree(y ~ x | z, data = dd, maxdepth = 2, vcov = "info") all.equal(sctest.modelparty(glm1i), sctest.modelparty(glm2i)) glm1s <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, vcov = "sandwich") glm2s <- glmtree(y ~ x | z, data = dd, maxdepth = 2, vcov = "sandwich") all.equal(sctest.modelparty(glm1s), sctest.modelparty(glm2s)) ## different vcov should yield similar (albeit not identical) statistics all.equal(sctest.modelparty(glm1o), sctest.modelparty(glm1i), tol = 0.05) all.equal(sctest.modelparty(glm1o), sctest.modelparty(glm1s), tol = 0.05) ## LR test should be similar all.equal(sctest.modelparty(glm1o), lrtest(dd), tol = 0.05) ## glm: proportionality weights -------------------------------------------------------------------- ## different test versions should be similar glmFo <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE, vcov = "opg") glmFi <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE, vcov = "info") glmFs <- glmtree(y ~ x | z, data = d, weights = w, maxdepth = 2, caseweights = FALSE, vcov = "sandwich") all.equal(sctest.modelparty(glmFo), sctest.modelparty(glmFi), tol = 0.05) all.equal(sctest.modelparty(glmFo), sctest.modelparty(glmFs), tol = 0.05) all.equal(sctest.modelparty(glmFo), lrtest(d, weights = d$w), tol = 0.05) ## constant factor should not change results glmFxo <- glmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE, vcov = "opg") glmFxi <- glmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE, vcov = "info") glmFxs <- glmtree(y ~ x | z, data = d, weights = 2 * w, maxdepth = 2, caseweights = FALSE, vcov = "sandwich") all.equal(sctest.modelparty(glmFo), sctest.modelparty(glmFxo)) all.equal(sctest.modelparty(glmFi), sctest.modelparty(glmFxi)) all.equal(sctest.modelparty(glmFs), sctest.modelparty(glmFxs)) partykit/tests/regtest-party.R0000644000176200001440000001031114172230001016202 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) ## load package and fix seed library("partykit") set.seed(1) ## rpart: kyphosis data library("rpart") data("kyphosis", package = "rpart") fit <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis) pfit <- as.party(fit) all(predict(pfit, newdata = kyphosis, type = "node") == fit$where) ## J48: iris data if (require("RWeka")) { data("iris", package = "datasets") itree <- J48(Species ~ ., data = iris) pitree <- as.party(itree) stopifnot(all(predict(pitree) == predict(pitree, newdata = iris[, 3:4]))) print(all.equal(predict(itree, type = "prob", newdata = iris), predict(pitree, type = "prob", newdata = iris))) print(all.equal(predict(itree, newdata = iris), predict(pitree, newdata = iris))) ## rpart/J48: GlaucomaM data data("GlaucomaM", package = "TH.data") w <- runif(nrow(GlaucomaM)) fit <- rpart(Class ~ ., data = GlaucomaM, weights = w) pfit <- as.party(fit) print(all(predict(pfit, type = "node") == fit$where)) tmp <- GlaucomaM[sample(1:nrow(GlaucomaM), 100),] print(all.equal(predict(fit, type = "prob", newdata = tmp), predict(pfit, type = "prob", newdata = tmp))) print(all.equal(predict(fit, type = "class", newdata = tmp), predict(pfit, newdata = tmp))) itree <- J48(Class ~ ., data = GlaucomaM) pitree <- as.party(itree) print(all.equal(predict(itree, newdata = tmp, type = "prob"), predict(pitree, newdata = tmp, type = "prob"))) } ## rpart: airquality data data("airquality") aq <- subset(airquality, !is.na(Ozone)) w <- runif(nrow(aq), max = 3) aqr <- rpart(Ozone ~ ., data = aq, weights = w) aqp <- as.party(aqr) tmp <- subset(airquality, is.na(Ozone)) all.equal(predict(aqr, newdata = tmp), predict(aqp, newdata = tmp)) ## rpart: GBSG2 data data("GBSG2", package = "TH.data") library("survival") fit <- rpart(Surv(time, cens) ~ ., data = GBSG2) pfit <- as.party(fit) pfit$fitted predict(pfit, newdata = GBSG2[1:100,], type = "prob") predict(pfit, newdata = GBSG2[1:100,], type = "response") ### multiple responses f <- fitted(pfit) f[["(response)"]] <- data.frame(srv = f[["(response)"]], hansi = runif(nrow(f))) mp <- party(node_party(pfit), fitted = f, data = pfit$data) class(mp) <- c("constparty", "party") predict(mp, newdata = GBSG2[1:10,]) ### pruning ## create party data("WeatherPlay", package = "partykit") py <- party( partynode(1L, split = partysplit(1L, index = 1:3), kids = list( partynode(2L, split = partysplit(3L, breaks = 75), kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, split = partysplit(3L, breaks = 20), kids = list( partynode(6L, info = "no"), partynode(7L, info = "yes"))), partynode(8L, split = partysplit(4L, index = 1:2), kids = list( partynode(9L, info = "yes"), partynode(10L, info = "no"))))), WeatherPlay) names(py) <- LETTERS[nodeids(py)] ## print print(py) (py5 <- nodeprune(py, 5)) nodeids(py5) (pyH <- nodeprune(py5, "H")) nodeids(pyH) ct <- ctree(Species ~ ., data = iris) nt <- node_party(ctree(Species ~ ., data = iris)) (ctp <- nodeprune(ct, 4)) ### party method (ntp <- nodeprune(nt, 4)) ### partynode method ### check if both methods do the same p1 <- predict(party(ntp, data = model.frame(ct)), type = "node") p2 <- predict(ctp, type = "node") stopifnot(max(abs(p1 - p2)) == 0) names(ct) <- LETTERS[nodeids(ct)] (ctp <- nodeprune(ct, "D")) table(predict(ct, type = "node"), predict(ctp, type = "node")) (ct <- nodeprune(ct, names(ct)[names(ct) != "A"])) table(predict(ct, type = "node")) nodeprune(ct, "B") nodeprune(ct, "C") nodeprune(ct, "A") ### check different predict flavours for numeric responses x <- runif(100) dd <- data.frame(y = rnorm(length(x), mean = 2 * (x < .5)), x = x) ct <- ctree(y ~ x, data = dd) nd <- data.frame(x = (1:9) / 10) predict(ct, newdata = nd, type = "node") predict(ct, newdata = nd, type = "response") predict(ct, newdata = nd, type = "prob") predict(ct, newdata = nd, type = "quantile") predict(ct, newdata = nd, type = "quantile", at = NULL) predict(ct, newdata = nd, type = "density") predict(ct, newdata = nd, type = "density", at = (1:9) / 10) partykit/tests/bugfixes.R0000644000176200001440000014337314415224055015237 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) set.seed(290875) datLB <- structure(list(Site = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L), ID = c(1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2, 9.2, 10.2, 11.2, 12.2, 13.2, 14.2, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3, 12.3, 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 1.6, 2.6, 3.6, 4.6, 5.6, 6.6, 7.6, 8.6, 9.6, 10.6, 11.6, 12.6, 13.6, 14.6, 15.6, 1.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7, 11.7, 12.7, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, 11.8, 12.8, 13.8, 14.8, 15.8, 16.8, 17.8, 18.8, 19.8, 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9, 9.9, 10.9, 11.9 ), Treat = structure(c(2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 3L, 2L, 3L, 1L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 2L, 1L, 1L, 3L, 2L, 3L, 1L, 1L, 3L, 2L, 1L, 2L, 3L, 3L, 1L, 2L, 2L, 1L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 3L, 2L, 3L, 1L, 3L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 3L, 1L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 3L, 2L, 1L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 3L, 2L, 1L, 3L, 2L, 1L, 1L, 2L), .Label = c("10000U", "5000U", "Placebo" ), class = "factor"), Age = c(65L, 70L, 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L, 65L, 70L, 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L, 65L, 70L, 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L, 65L, 70L, 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L, 65L, 70L, 64L, 59L, 76L, 59L, 72L, 40L, 52L, 47L, 57L, 47L, 70L, 49L, 59L, 64L, 45L, 66L, 49L, 54L, 47L, 31L, 53L, 61L, 40L, 67L, 54L, 41L, 66L, 68L, 41L, 77L, 41L, 56L, 46L, 46L, 47L, 35L, 58L, 62L, 73L, 52L, 53L, 69L, 55L, 52L, 51L, 56L, 65L, 35L, 43L, 61L, 43L, 64L, 57L, 60L, 44L, 41L, 51L, 57L, 42L, 48L, 57L, 39L, 67L, 39L, 69L, 54L, 67L, 58L, 72L, 65L, 68L, 75L, 26L, 36L, 72L, 54L, 64L, 39L, 54L, 48L, 83L, 74L, 41L, 65L, 79L, 63L, 63L, 34L, 42L, 57L, 68L, 51L, 51L, 61L, 42L, 73L, 57L, 59L, 57L, 68L, 55L, 46L, 79L, 43L, 50L, 39L, 57L), W0 = c(32L, 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, 53L, 32L, 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, 53L, 32L, 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, 53L, 32L, 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, 53L, 32L, 60L, 44L, 53L, 53L, 49L, 42L, 34L, 41L, 27L, 48L, 34L, 49L, 46L, 56L, 59L, 62L, 50L, 42L, 53L, 67L, 44L, 65L, 56L, 30L, 47L, 50L, 34L, 39L, 43L, 46L, 52L, 38L, 33L, 28L, 34L, 39L, 29L, 52L, 52L, 54L, 52L, 47L, 44L, 42L, 42L, 44L, 60L, 60L, 50L, 38L, 44L, 54L, 54L, 56L, 51L, 53L, 36L, 59L, 49L, 50L, 46L, 55L, 46L, 34L, 57L, 41L, 49L, 42L, 31L, 50L, 35L, 38L, 53L, 42L, 53L, 46L, 50L, 43L, 46L, 41L, 33L, 36L, 33L, 37L, 24L, 42L, 30L, 42L, 49L, 58L, 26L, 37L, 40L, 33L, 41L, 46L, 40L, 40L, 61L, 35L, 58L, 49L, 52L, 45L, 67L, 57L, 63L, 53L), Fem = c(1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L), Week = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L, 16L), Total = c(30L, 26L, 20L, 61L, 35L, 34L, 32L, 33L, 32L, 10L, 41L, 19L, 47L, 35L, 44L, 48L, 60L, 53L, 42L, 56L, 64L, 40L, 58L, 54L, 33L, NA, 43L, 29L, 41L, 31L, 26L, 44L, 19L, 38L, 16L, 23L, 37L, 42L, 55L, 30L, 52L, 44L, 45L, 34L, 39L, 14L, 34L, 57L, 53L, 50L, 27L, NA, 53L, 32L, 55L, 50L, 56L, 29L, 53L, 50L, 38L, 48L, 34L, 44L, 31L, 48L, 40L, 25L, 30L, 18L, 27L, 24L, 25L, 40L, 48L, 45L, 47L, 42L, 24L, 39L, 30L, 27L, 15L, 32L, NA, 29L, 23L, 22L, 46L, 25L, 46L, 26L, NA, 24L, 10L, 50L, NA, 28L, 16L, 52L, 21L, 38L, 45L, 46L, 46L, 63L, NA, 51L, 38L, 24L, 27L, 23L, 64L, 48L, 43L, 32L, 21L, 34L, 31L, 32L, 21L, 44L, 45L, 48L, 56L, 60L, 52L, 43L, 52L, 65L, 32L, 55L, 52L, 25L, 54L, 51L, 27L, 33L, 29L, 29L, 47L, 20L, 40L, 11L, 16L, 39L, 35L, 51L, 43L, 52L, 33L, 41L, 29L, 38L, 9L, 32L, 53L, 55L, NA, 16L, 46L, 51L, 40L, 44L, 50L, 47L, 24L, 45L, 48L, 42L, 46L, 26L, 47L, 25L, 50L, 42L, 30L, 40L, 23L, 43L, 34L, 21L, 38L, 26L, 52L, 45L, 52L, 17L, 25L, 44L, 25L, 16L, 31L, NA, 18L, 30L, 21L, 41L, 30L, 46L, 27L, 23L, 25L, 13L, 22L, 41L, 29L, 18L, 61L, 29L, 50L, 36L, 36L, 33L, 71L, 36L, 46L, NA, 37L, 41L, 26L, 62L, 49L, 48L, 43L, 27L, 35L, 32L, 35L, 24L, 48L, 49L, 54L, 55L, 64L, 57L, 33L, 54L, 64L, 36L, NA, 48L, 29L, 43L, 46L, 21L, 39L, 28L, 33L, 50L, 27L, 48L, 7L, 15L, 39L, 24L, 52L, 45L, 54L, 54L, 45L, 28L, 47L, 9L, 35L, 52L, 62L, 46L, 19L, 26L, 56L, 52L, 50L, 56L, 53L, 32L, 44L, 56L, 43L, 57L, 40L, 50L, NA, 50L, 38L, 41L, 43L, 26L, 32L, 28L, 33L, 44L, 37L, 51L, 45L, 60L, 37L, 15L, 46L, 30L, 17L, 27L, NA, 20L, 36L, 25L, 43L, 49L, 50L, 22L, 18L, 37L, 16L, 28L, 41L, 30L, 25L, 68L, 30L, 53L, NA, NA, 44L, 66L, 23L, 50L, 33L, 39L, 65L, 35L, NA, 41L, 48L, 42L, 32L, 37L, 6L, 57L, 28L, 44L, 53L, 49L, 57L, 67L, 61L, 37L, 55L, 62L, 42L, 56L, 52L, 32L, 46L, 49L, 22L, 37L, 33L, 45L, 50L, 29L, 49L, 13L, 17L, 45L, 29L, 54L, 47L, 51L, 46L, 43L, 35L, 39L, 16L, 54L, 53L, 67L, 50L, 23L, 30L, 39L, 42L, 53L, 59L, 51L, 45L, 50L, 49L, 42L, 57L, 49L, 46L, NA, 50L, 50L, 41L, 36L, 33L, 40L, 34L, 42L, 47L, 37L, 52L, 50L, 54L, 36L, 21L, 46L, 28L, 22L, 49L, NA, 25L, 41L, 26L, 49L, 55L, 56L, 38L, 34L, NA, 32L, 34L, 58L, 37L, 33L, 59L, 35L, 47L, 40L, 45L, 46L, 68L, NA, 50L, 36L, 36L, 67L, 35L, NA, 51L, 51L, 46L, 38L, 36L, 14L, 51L, 28L, 44L, 56L, 60L, 58L, 66L, 54L, 43L, 51L, 64L, 43L, 60L, 53L, 32L, 50L, 53L, 22L, 37L, 38L, 56L, 49L, 32L, 44L, 21L, 29L, 43L, 42L, 57L, 46L, 57L, 47L, 41L, 41L, 39L, 33L, 53L, 58L, NA, 57L, 26L, 34L, 9L, 47L, 52L, 53L, 51L, 36L, 48L, 57L, 46L, 49L, 47L, 51L, NA, 49L, 56L, 31L, 45L, 41L, 47L, 28L, 53L, 53L, 43L, 53L, 52L, 59L, 38L, 25L, 44L, 30L, 41L, 60L, NA, 41L, 43L, 33L, 54L, 58L, 60L, 35L, 36L, 38L, 16L, 36L, 53L, 44L, 48L, 71L, 48L, 59L, 52L, 54L, 48L, 71L, 52L, 54L, 51L)), .Names = c("Site", "ID", "Treat", "Age", "W0", "Fem", "Week", "Total"), class = "data.frame", row.names = c(NA, -545L)) library("partykit") library("rpart") fac <- c(1,3,6) for(j in 1:length(fac)) datLB[,fac[j]] <- as.factor(datLB[,fac[j]]) dat <- subset(datLB,Week==16) dat <- na.omit(dat) fit <- rpart(Total ~ Site + Treat + Age + W0, method = "anova", data = dat) f <- as.party(fit) plot(f,tp_args = list(id = FALSE)) f[10]$node$split ### factors with empty levels in learning sample if (require("mlbench")) { data("Vowel", package = "mlbench") ct <- ctree(V2 ~ V1, data = Vowel[1:200,]) ### only levels 1:4 in V1 try(p1 <- predict(ct, newdata = Vowel)) ### 14 levels in V1 } ### deal with empty levels for teststat = "quad" by ### removing elements of the teststatistic with zero variance ### reported by Wei-Yin Loh tdata <- structure(list(ytrain = structure(c(3L, 7L, 3L, 2L, 1L, 6L, 2L, 1L, 1L, 2L, 1L, 2L, 3L, 3L, 2L, 1L, 2L, 6L, 2L, 4L, 6L, 1L, 2L, 3L, 7L, 6L, 4L, 6L, 2L, 2L, 1L, 2L, 6L, 1L, 7L, 1L, 3L, 6L, 2L, 1L, 7L, 2L, 7L, 2L, 3L, 2L, 1L, 1L, 3L, 1L, 6L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 6L, 6L, 7L, 2L, 2L, 2L, 2L, 2L, 1L, 3L, 6L, 5L, 1L, 1L, 4L, 7L, 2L, 3L, 3L, 3L, 1L, 8L, 1L, 6L, 2L, 8L, 3L, 4L, 6L, 2L, 7L, 3L, 6L, 6L, 1L, 1L, 2L, 6L, 3L, 3L, 1L, 2L, 3L, 1L, 2L, 7L, 2L, 3L, 6L, 2L, 5L, 2L, 2L, 2L, 1L, 3L, 3L, 7L, 3L, 2L, 3L, 3L, 1L, 6L, 1L, 1L, 1L, 7L, 1L, 3L, 7L, 6L, 1L, 3L, 3L, 6L, 4L, 2L, 3L, 2L, 8L, 3L, 4L, 2L, 2L, 2L, 3L, 2L, 2L, 2L, 3L, 4L, 6L, 4L, 8L, 2L, 2L, 3L, 3L, 2L, 3L, 6L, 2L, 1L, 2L, 2L, 7L, 2L, 1L, 1L, 7L, 2L, 7L, 6L, 6L, 6L), .Label = c("0", "1", "2", "3", "4", "5", "6", "7"), class = "factor"), landmass = c(5L, 3L, 4L, 6L, 3L, 4L, 1L, 2L, 2L, 6L, 3L, 1L, 5L, 5L, 1L, 3L, 1L, 4L, 1L, 5L, 4L, 2L, 1L, 5L, 3L, 4L, 5L, 4L, 4L, 1L, 4L, 1L, 4L, 2L, 5L, 2L, 4L, 4L, 6L, 1L, 1L, 3L, 3L, 3L, 4L, 1L, 1L, 2L, 4L, 1L, 4L, 4L, 3L, 2L, 6L, 3L, 3L, 2L, 4L, 4L, 3L, 3L, 3L, 3L, 1L, 6L, 1L, 4L, 4L, 2L, 1L, 1L, 5L, 3L, 3L, 6L, 5L, 5L, 3L, 5L, 3L, 4L, 1L, 5L, 5L, 5L, 4L, 6L, 5L, 5L, 4L, 4L, 3L, 3L, 4L, 4L, 5L, 5L, 3L, 6L, 4L, 1L, 6L, 5L, 1L, 4L, 4L, 6L, 5L, 3L, 1L, 6L, 1L, 4L, 4L, 5L, 5L, 3L, 5L, 5L, 2L, 6L, 2L, 2L, 6L, 3L, 1L, 5L, 3L, 4L, 4L, 5L, 4L, 4L, 5L, 6L, 4L, 4L, 5L, 5L, 5L, 1L, 1L, 1L, 4L, 2L, 3L, 3L, 5L, 5L, 4L, 5L, 4L, 6L, 2L, 4L, 5L, 1L, 5L, 4L, 3L, 2L, 1L, 1L, 5L, 6L, 3L, 2L, 5L, 6L, 3L, 4L, 4L, 4L), zone = c(1L, 1L, 1L, 3L, 1L, 2L, 4L, 3L, 3L, 2L, 1L, 4L, 1L, 1L, 4L, 1L, 4L, 1L, 4L, 1L, 2L, 3L, 4L, 1L, 1L, 4L, 1L, 2L, 1L, 4L, 4L, 4L, 1L, 3L, 1L, 4L, 2L, 2L, 3L, 4L, 4L, 1L, 1L, 1L, 1L, 4L, 4L, 3L, 1L, 4L, 1L, 1L, 4L, 3L, 2L, 1L, 1L, 4L, 2L, 4L, 1L, 1L, 4L, 1L, 4L, 1L, 4L, 4L, 4L, 4L, 4L, 4L, 1L, 1L, 4L, 2L, 1L, 1L, 4L, 1L, 1L, 4L, 4L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 4L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 1L, 4L, 4L, 1L, 1L, 4L, 4L, 2L, 2L, 1L, 1L, 4L, 2L, 4L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 4L, 2L, 3L, 3L, 1L, 1L, 4L, 1L, 1L, 2L, 1L, 1L, 4L, 4L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 4L, 4L, 4L, 1L, 4L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 4L, 1L, 1L, 4L, 1L, 1L, 4L, 3L, 4L, 4L, 1L, 2L, 1L, 4L, 1L, 3L, 1L, 2L, 2L, 2L), area = c(648L, 29L, 2388L, 0L, 0L, 1247L, 0L, 2777L, 2777L, 7690L, 84L, 19L, 1L, 143L, 0L, 31L, 23L, 113L, 0L, 47L, 600L, 8512L, 0L, 6L, 111L, 274L, 678L, 28L, 474L, 9976L, 4L, 0L, 623L, 757L, 9561L, 1139L, 2L, 342L, 0L, 51L, 115L, 9L, 128L, 43L, 22L, 0L, 49L, 284L, 1001L, 21L, 28L, 1222L, 1L, 12L, 18L, 337L, 547L, 91L, 268L, 10L, 108L, 249L, 0L, 132L, 0L, 0L, 109L, 246L, 36L, 215L, 28L, 112L, 1L, 93L, 103L, 1904L, 1648L, 435L, 70L, 21L, 301L, 323L, 11L, 372L, 98L, 181L, 583L, 0L, 236L, 10L, 30L, 111L, 0L, 3L, 587L, 118L, 333L, 0L, 0L, 0L, 1031L, 1973L, 1L, 1566L, 0L, 447L, 783L, 0L, 140L, 41L, 0L, 268L, 128L, 1267L, 925L, 121L, 195L, 324L, 212L, 804L, 76L, 463L, 407L, 1285L, 300L, 313L, 9L, 11L, 237L, 26L, 0L, 2150L, 196L, 72L, 1L, 30L, 637L, 1221L, 99L, 288L, 66L, 0L, 0L, 0L, 2506L, 63L, 450L, 41L, 185L, 36L, 945L, 514L, 57L, 1L, 5L, 164L, 781L, 0L, 84L, 236L, 245L, 178L, 0L, 9363L, 22402L, 15L, 0L, 912L, 333L, 3L, 256L, 905L, 753L, 391L), population = c(16L, 3L, 20L, 0L, 0L, 7L, 0L, 28L, 28L, 15L, 8L, 0L, 0L, 90L, 0L, 10L, 0L, 3L, 0L, 1L, 1L, 119L, 0L, 0L, 9L, 7L, 35L, 4L, 8L, 24L, 0L, 0L, 2L, 11L, 1008L, 28L, 0L, 2L, 0L, 2L, 10L, 1L, 15L, 5L, 0L, 0L, 6L, 8L, 47L, 5L, 0L, 31L, 0L, 0L, 1L, 5L, 54L, 0L, 1L, 1L, 17L, 61L, 0L, 10L, 0L, 0L, 8L, 6L, 1L, 1L, 6L, 4L, 5L, 11L, 0L, 157L, 39L, 14L, 3L, 4L, 57L, 7L, 2L, 118L, 2L, 6L, 17L, 0L, 3L, 3L, 1L, 1L, 0L, 0L, 9L, 6L, 13L, 0L, 0L, 0L, 2L, 77L, 0L, 2L, 0L, 20L, 12L, 0L, 16L, 14L, 0L, 2L, 3L, 5L, 56L, 18L, 9L, 4L, 1L, 84L, 2L, 3L, 3L, 14L, 48L, 36L, 3L, 0L, 22L, 5L, 0L, 9L, 6L, 3L, 3L, 0L, 5L, 29L, 39L, 2L, 15L, 0L, 0L, 0L, 20L, 0L, 8L, 6L, 10L, 18L, 18L, 49L, 2L, 0L, 1L, 7L, 45L, 0L, 1L, 13L, 56L, 3L, 0L, 231L, 274L, 0L, 0L, 15L, 60L, 0L, 22L, 28L, 6L, 8L), language = structure(c(10L, 6L, 8L, 1L, 6L, 10L, 1L, 2L, 2L, 1L, 4L, 1L, 8L, 6L, 1L, 6L, 1L, 3L, 1L, 10L, 10L, 6L, 1L, 10L, 5L, 3L, 10L, 10L, 3L, 1L, 6L, 1L, 10L, 2L, 7L, 2L, 3L, 10L, 1L, 2L, 2L, 6L, 5L, 6L, 3L, 1L, 2L, 2L, 8L, 2L, 10L, 10L, 6L, 1L, 1L, 9L, 3L, 3L, 10L, 1L, 4L, 4L, 1L, 6L, 1L, 1L, 2L, 3L, 6L, 1L, 3L, 2L, 7L, 9L, 6L, 10L, 6L, 8L, 1L, 10L, 6L, 3L, 1L, 9L, 8L, 10L, 10L, 1L, 10L, 8L, 10L, 10L, 4L, 4L, 10L, 10L, 10L, 10L, 10L, 10L, 8L, 2L, 10L, 10L, 1L, 8L, 10L, 10L, 10L, 6L, 6L, 1L, 2L, 3L, 10L, 10L, 8L, 6L, 8L, 6L, 2L, 1L, 2L, 2L, 10L, 5L, 2L, 8L, 6L, 10L, 6L, 8L, 3L, 1L, 7L, 1L, 10L, 6L, 10L, 8L, 10L, 1L, 1L, 1L, 8L, 6L, 6L, 4L, 8L, 7L, 10L, 10L, 3L, 10L, 1L, 8L, 9L, 1L, 8L, 10L, 1L, 2L, 1L, 1L, 5L, 6L, 6L, 2L, 10L, 1L, 6L, 10L, 10L, 10L), .Label = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"), class = "factor"), bars = c(0L, 0L, 2L, 0L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 2L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 3L, 1L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 0L, 3L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 2L, 0L, 0L, 3L, 0L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 3L, 0L, 0L, 0L, 0L, 3L, 3L, 0L, 0L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 5L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 3L, 0L), stripes = c(3L, 0L, 0L, 0L, 0L, 2L, 1L, 3L, 3L, 0L, 3L, 3L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 5L, 0L, 0L, 0L, 3L, 2L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 2L, 0L, 3L, 0L, 0L, 0L, 5L, 5L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 3L, 3L, 3L, 3L, 0L, 0L, 0L, 0L, 0L, 0L, 3L, 5L, 3L, 3L, 1L, 9L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 3L, 0L, 3L, 0L, 2L, 3L, 3L, 0L, 2L, 0L, 0L, 0L, 0L, 3L, 0L, 5L, 0L, 3L, 2L, 0L, 11L, 2L, 3L, 2L, 3L, 14L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 5L, 3L, 0L, 3L, 1L, 0L, 3L, 3L, 0L, 5L, 3L, 0L, 2L, 0L, 0L, 0L, 3L, 0L, 0L, 2L, 5L, 0L, 0L, 0L, 3L, 0L, 0L, 3L, 2L, 0L, 0L, 3L, 0L, 3L, 0L, 0L, 0L, 0L, 3L, 5L, 0L, 0L, 3L, 0L, 0L, 5L, 5L, 0L, 0L, 0L, 0L, 0L, 3L, 6L, 0L, 9L, 0L, 13L, 0L, 0L, 0L, 3L, 0L, 0L, 3L, 0L, 0L, 7L), colours = c(5L, 3L, 3L, 5L, 3L, 3L, 3L, 2L, 3L, 3L, 2L, 3L, 2L, 2L, 3L, 3L, 8L, 2L, 6L, 4L, 3L, 4L, 6L, 4L, 5L, 3L, 3L, 3L, 3L, 2L, 5L, 6L, 5L, 3L, 2L, 3L, 2L, 3L, 4L, 3L, 3L, 3L, 3L, 2L, 4L, 6L, 3L, 3L, 4L, 2L, 4L, 3L, 3L, 6L, 7L, 2L, 3L, 3L, 3L, 4L, 3L, 3L, 3L, 2L, 3L, 7L, 2L, 3L, 4L, 5L, 2L, 2L, 6L, 3L, 3L, 2L, 3L, 4L, 3L, 2L, 3L, 3L, 3L, 2L, 4L, 2L, 4L, 4L, 3L, 4L, 4L, 3L, 3L, 3L, 3L, 3L, 4L, 3L, 3L, 3L, 2L, 4L, 2L, 3L, 7L, 2L, 5L, 3L, 3L, 3L, 3L, 3L, 2L, 3L, 2L, 3L, 4L, 3L, 3L, 2L, 3L, 4L, 6L, 2L, 4L, 2L, 3L, 2L, 7L, 4L, 4L, 2L, 3L, 3L, 2L, 4L, 2L, 5L, 4L, 4L, 4L, 5L, 4L, 4L, 4L, 4L, 2L, 2L, 4L, 3L, 4L, 3L, 4L, 2L, 3L, 2L, 2L, 6L, 4L, 5L, 3L, 3L, 6L, 3L, 2L, 4L, 4L, 7L, 2L, 3L, 4L, 4L, 4L, 5L), red = c(1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), green = c(1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L), blue = c(0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 0L), gold = c(1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L), white = c(1L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 1L), black = c(1L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L), orange = c(0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L), mainhue = structure(c(5L, 7L, 5L, 2L, 4L, 7L, 8L, 2L, 2L, 2L, 7L, 2L, 7L, 5L, 2L, 4L, 2L, 5L, 7L, 6L, 2L, 5L, 2L, 4L, 7L, 7L, 7L, 7L, 4L, 7L, 4L, 2L, 4L, 7L, 7L, 4L, 5L, 7L, 2L, 2L, 2L, 8L, 8L, 7L, 2L, 5L, 2L, 4L, 1L, 2L, 5L, 5L, 8L, 2L, 2L, 8L, 8L, 8L, 5L, 7L, 4L, 1L, 8L, 2L, 4L, 2L, 2L, 4L, 4L, 5L, 1L, 2L, 2L, 7L, 2L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 5L, 8L, 1L, 7L, 7L, 7L, 7L, 7L, 2L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 2L, 5L, 5L, 2L, 7L, 2L, 7L, 4L, 2L, 3L, 7L, 8L, 2L, 2L, 6L, 5L, 2L, 7L, 7L, 7L, 5L, 7L, 1L, 7L, 7L, 2L, 8L, 7L, 3L, 7L, 7L, 5L, 5L, 5L, 5L, 8L, 5L, 2L, 6L, 8L, 7L, 4L, 5L, 2L, 5L, 7L, 7L, 2L, 7L, 7L, 7L, 5L, 7L, 5L, 7L, 7L, 7L, 7L, 2L, 5L, 4L, 7L, 8L, 8L, 8L, 7L, 7L, 4L, 7L, 7L, 7L, 7L, 5L, 5L, 5L), .Label = c("black", "blue", "brown", "gold", "green", "orange", "red", "white"), class = "factor"), circles = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 4L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L), crosses = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 2L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), saltires = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), quarters = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 4L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L), sunstars = c(1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 6L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 22L, 0L, 0L, 1L, 1L, 14L, 3L, 1L, 0L, 1L, 4L, 1L, 1L, 5L, 0L, 4L, 1L, 15L, 0L, 1L, 0L, 0L, 0L, 1L, 10L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 7L, 0L, 0L, 0L, 1L, 0L, 0L, 5L, 0L, 0L, 0L, 0L, 0L, 3L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 0L, 4L, 1L, 0L, 1L, 1L, 1L, 2L, 0L, 6L, 4L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 2L, 5L, 1L, 0L, 4L, 0L, 1L, 0L, 2L, 0L, 2L, 0L, 1L, 0L, 5L, 5L, 1L, 0L, 0L, 1L, 0L, 2L, 0L, 0L, 0L, 1L, 0L, 0L, 2L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 50L, 1L, 0L, 0L, 7L, 1L, 5L, 1L, 0L, 0L, 1L), crescent = c(0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), triangle = c(0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L), icon = c(1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L), animate = c(0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L, 1L), text = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), topleft = structure(c(1L, 6L, 4L, 2L, 2L, 6L, 7L, 2L, 2L, 7L, 6L, 2L, 7L, 4L, 2L, 1L, 6L, 4L, 7L, 5L, 2L, 4L, 7L, 7L, 7L, 6L, 2L, 7L, 4L, 6L, 6L, 7L, 2L, 2L, 6L, 3L, 4L, 6L, 7L, 2L, 2L, 7L, 7L, 6L, 7L, 4L, 2L, 3L, 6L, 2L, 4L, 4L, 7L, 7L, 7L, 7L, 2L, 2L, 4L, 6L, 1L, 1L, 7L, 2L, 6L, 6L, 2L, 6L, 6L, 1L, 1L, 2L, 7L, 6L, 2L, 6L, 4L, 6L, 4L, 2L, 4L, 6L, 3L, 7L, 1L, 6L, 1L, 6L, 6L, 6L, 4L, 2L, 2L, 6L, 7L, 1L, 2L, 6L, 7L, 2L, 4L, 4L, 2L, 6L, 7L, 6L, 4L, 2L, 2L, 6L, 7L, 7L, 2L, 5L, 4L, 2L, 6L, 6L, 6L, 7L, 7L, 6L, 6L, 6L, 2L, 7L, 6L, 7L, 2L, 6L, 4L, 4L, 4L, 4L, 6L, 2L, 2L, 5L, 7L, 6L, 3L, 4L, 2L, 2L, 6L, 4L, 2L, 6L, 6L, 2L, 4L, 6L, 6L, 7L, 7L, 6L, 6L, 7L, 6L, 1L, 7L, 7L, 7L, 2L, 6L, 1L, 3L, 3L, 6L, 2L, 2L, 4L, 4L, 4L), .Label = c("black", "blue", "gold", "green", "orange", "red", "white"), class = "factor"), botright = structure(c(5L, 7L, 8L, 7L, 7L, 1L, 2L, 2L, 2L, 2L, 7L, 2L, 7L, 5L, 2L, 7L, 7L, 5L, 7L, 7L, 2L, 5L, 2L, 4L, 7L, 5L, 7L, 8L, 4L, 7L, 5L, 2L, 4L, 7L, 7L, 7L, 5L, 7L, 2L, 2L, 2L, 8L, 7L, 7L, 5L, 5L, 2L, 7L, 1L, 2L, 7L, 7L, 8L, 2L, 2L, 8L, 7L, 7L, 2L, 5L, 4L, 4L, 7L, 2L, 7L, 7L, 2L, 5L, 5L, 5L, 7L, 2L, 2L, 5L, 2L, 8L, 7L, 1L, 6L, 2L, 7L, 5L, 4L, 8L, 5L, 7L, 5L, 2L, 7L, 7L, 2L, 7L, 7L, 2L, 5L, 5L, 8L, 7L, 7L, 2L, 5L, 7L, 2L, 7L, 2L, 7L, 4L, 2L, 2L, 2L, 8L, 2L, 2L, 5L, 5L, 2L, 1L, 7L, 5L, 5L, 8L, 1L, 2L, 7L, 7L, 7L, 7L, 3L, 7L, 5L, 5L, 5L, 7L, 2L, 8L, 5L, 2L, 2L, 8L, 1L, 4L, 7L, 2L, 5L, 1L, 5L, 2L, 7L, 1L, 7L, 2L, 7L, 5L, 7L, 8L, 7L, 7L, 2L, 1L, 7L, 7L, 8L, 8L, 7L, 7L, 5L, 8L, 7L, 7L, 7L, 7L, 5L, 3L, 5L), .Label = c("black", "blue", "brown", "gold", "green", "orange", "red", "white"), class = "factor")), .Names = c("ytrain", "landmass", "zone", "area", "population", "language", "bars", "stripes", "colours", "red", "green", "blue", "gold", "white", "black", "orange", "mainhue", "circles", "crosses", "saltires", "quarters", "sunstars", "crescent", "triangle", "icon", "animate", "text", "topleft", "botright"), row.names = c(NA, -174L), class = "data.frame") tdata$language <- factor(tdata$language) tdata$ytrain <- factor(tdata$ytrain) ### was: error model <- ctree(ytrain ~ ., data = tdata, control = ctree_control(testtype = "Univariate", splitstat = "maximum")) if (require("coin")) { ### check against coin (independence_test automatically ### removes empty levels) p <- info_node(node_party(model))$criterion["p.value",] p[is.na(p)] <- 0 p2 <- sapply(names(p), function(n) pvalue(independence_test(ytrain ~ ., data = tdata[, c("ytrain", n)], teststat = "quad"))) stopifnot(max(abs(p - p2)) < sqrt(.Machine$double.eps)) p <- info_node(node_party(model[2]))$criterion["p.value",] p[is.na(p)] <- 0 p2 <- sapply(names(p), function(n) pvalue(independence_test(ytrain ~ ., data = tdata[tdata$language != "8", c("ytrain", n)], teststat = "quad"))) stopifnot(max(abs(p - p2)) < sqrt(.Machine$double.eps)) p <- info_node(node_party(model[3]))$criterion["p.value",] p[is.na(p)] <- 0 p2 <- sapply(names(p), function(n) pvalue(independence_test(ytrain ~ ., data = tdata[!(tdata$language %in% c("2", "4", "8")), c("ytrain", n)], teststat = "quad"))) stopifnot(max(abs(p - p2)) < sqrt(.Machine$double.eps)) } ### check coersion of constparties to simpleparties ### containing terminal nodes without corresponding observations ## create party data("WeatherPlay", package = "partykit") py <- party( partynode(1L, split = partysplit(1L, index = 1:3), kids = list( partynode(2L, split = partysplit(3L, breaks = 75), kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, split = partysplit(3L, breaks = 20), kids = list( partynode(6L, info = "no"), partynode(7L, info = "yes"))), partynode(8L, split = partysplit(4L, index = 1:2), kids = list( partynode(9L, info = "yes"), partynode(10L, info = "no"))))), WeatherPlay) names(py) <- LETTERS[nodeids(py)] pn <- node_party(py) cp <- party(pn, data = WeatherPlay, fitted = data.frame( "(fitted)" = fitted_node(pn, data = WeatherPlay), "(response)" = WeatherPlay$play, check.names = FALSE), terms = terms(play ~ ., data = WeatherPlay), ) print(cp) cp <- as.constparty(cp) nd <- data.frame(outlook = factor("overcast", levels = levels(WeatherPlay$outlook)), humidity = 10, temperature = 10, windy = "yes") try(predict(cp, type = "node", newdata = nd)) try(predict(cp, type = "response", newdata = nd)) as.simpleparty(cp) print(cp) ### scores y <- gl(3, 10, ordered = TRUE) x <- rnorm(length(y)) x <- ordered(cut(x, 3)) d <- data.frame(y = y, x = x) ### partykit with scores ct11 <- partykit::ctree(y ~ x, data = d) ct12 <- partykit::ctree(y ~ x, data = d, scores = list(y = c(1, 4, 5))) ct13 <- partykit::ctree(y ~ x, data = d, scores = list(y = c(1, 4, 5), x = c(1, 5, 6))) ### party with scores ct21 <- party::ctree(y ~ x, data = d) ct22 <- party::ctree(y ~ x, data = d, scores = list(y = c(1, 4, 5))) ct23 <- party::ctree(y ~ x, data = d, scores = list(y = c(1, 4, 5), x = c(1, 5, 6))) stopifnot(all.equal(ct11$node$info$p.value, 1 - ct21@tree$criterion$criterion, check.attr = FALSE)) stopifnot(all.equal(ct12$node$info$p.value, 1 - ct22@tree$criterion$criterion, check.attr = FALSE)) stopifnot(all.equal(ct13$node$info$p.value, 1 - ct23@tree$criterion$criterion, check.attr = FALSE)) ### ytrafo y <- runif(100, max = 3) x <- rnorm(length(y)) d <- data.frame(y = y, x = x) ### partykit with scores ct11 <- partykit::ctree(y ~ x, data = d) ct12 <- partykit::ctree(y ~ x, data = d, ytrafo = list(y = sqrt)) ### party with scores ct21 <- party::ctree(y ~ x, data = d) f <- function(data) coin::trafo(data, numeric_trafo = sqrt) ct22 <- party::ctree(y ~ x, data = d, ytrafo = f) stopifnot(all.equal(ct11$node$info$p.value, 1 - ct21@tree$criterion$criterion, check.attr = FALSE)) stopifnot(all.equal(ct12$node$info$p.value, 1 - ct22@tree$criterion$criterion, check.attr = FALSE)) ### spotted by Peter Philip Stephensen (DREAM) ### splits x >= max(x) where possible in partykit::ctree nAge <- 30 d <- data.frame(Age=rep(1:nAge,2),y=c(rep(1,nAge),rep(0,nAge)), n = rep(0,2*nAge)) ntot <- 100 alpha <- .5 d[d$y==1,]$n = floor(ntot * alpha * d[d$y==1,]$Age / nAge) d[d$y==0,]$n = ntot - d[d$y==1,]$n d$n <- as.integer(d$n) ctrl <- partykit::ctree_control(maxdepth=3, minbucket = min(d$n) + 1) tree <- partykit::ctree(y ~ Age, weights=n, data=d, control=ctrl) ## IGNORE_RDIFF_BEGIN tree ## IGNORE_RDIFF_END (w1 <- predict(tree, type = "node")) (ct <- ctree(dist + I(dist^2) ~ speed, data = cars)) predict(ct) ### nodeapply was not the same for permutations of ids ### spotted by Heidi Seibold airq <- subset(airquality, !is.na(Ozone)) airct <- ctree(Ozone ~ ., data = airq) n1 <- nodeapply(airct, ids = c(3, 5, 6), function(x) x$info$nobs) n2 <- nodeapply(airct, ids = c(6, 3, 5), function(x) x$info$nobs) stopifnot(all.equal(n1[names(n2)], n2)) ### pruning got "fitted" wrong, spotted by Jason Parker data("Titanic") titan <- as.data.frame(Titanic) (tree <- ctree(Survived ~ Class + Sex + Age, data = titan, weights = Freq)) ### prune off nodes 5-12 and check if the other nodes are not affected nodeprune(tree, 4) ### this gave a warning "ME is not a factor" if (require("TH.data")) { data("mammoexp", package = "TH.data") a <- cforest(ME ~ PB + SYMPT, data = mammoexp, ntree = 5) print(predict(a, newdata=mammoexp[1:3,])) } ### pruning didn't work properly mt <- lmtree(dist ~ speed, data = cars) mt2 <- nodeprune(mt, 2) stopifnot(all(mt2$fitted[["(fitted)"]] %in% c(2, 3))) ### a <- rep('N',87) a[77] <- 'Y' b <- rep(FALSE, 87) b[c(7,10,11,33,56,77)] <- TRUE d <- rep(1,87) d[c(29,38,40,42,65,77)] <- 0 dfb <- data.frame(a = as.factor(a), b = as.factor(b), d = as.factor(d)) tr <- ctree(a ~ ., data = dfb, control = ctree_control(minsplit = 10,minbucket = 5, maxsurrogate = 2, alpha = 0.05)) tNodes <- node_party(tr) ### this creates a tie on purpose and "d" should be selected ### this check fails on M1mac nodeInfo <- info_node(tNodes) nodeInfo$criterion #stopifnot(names(nodeInfo$p.value) == "d") #stopifnot(split_node(tNodes)$varid == 3) ### reported by John Ogawa, 2020-12-11 class(dfb$a) <- c("Hansi", "factor") tr2 <- ctree(a ~ ., data = dfb, control = ctree_control(minsplit = 10,minbucket = 5, maxsurrogate = 2, alpha = 0.05)) stopifnot(isTRUE(all.equal(tr, tr2, check.attributes = FALSE))) partykit/tests/regtest-nmax.Rout.save0000644000176200001440000000366314172230001017507 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > > set.seed(29) > n <- 1000 > z <- runif(n) > y <- rnorm(n, mean = c(-1, 1)[(z > 0.5) + 1], sd = 3) > d <- data.frame(y = y, y2 = factor(y > median(y)), + z = z) > > c1 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = Inf, alpha = .5)) > c2 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = 25, alpha = .5)) > c3 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = nrow(d), alpha = .5)) > c4 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = 100, alpha = .5)) > > all.equal(predict(c1, type = "node"), predict(c3, type = "node")) [1] TRUE > > p1 <- predict(c1, type = "prob") > p2 <- predict(c2, type = "prob") > p3 <- predict(c3, type = "prob") > p4 <- predict(c4, type = "prob") > > ### binomial log-lik > sum(log(p1[cbind(1:nrow(d), unclass(d$y2))])) [1] -675.3508 > sum(log(p2[cbind(1:nrow(d), unclass(d$y2))])) [1] -676.0943 > sum(log(p3[cbind(1:nrow(d), unclass(d$y2))])) [1] -675.3508 > sum(log(p4[cbind(1:nrow(d), unclass(d$y2))])) [1] -676.0943 > > c1 <- ctree(y ~ z, data = d, control = ctree_control(nmax = c("yx" = Inf, "z" = 25), alpha = .5)) > > proc.time() user system elapsed 1.517 0.125 1.622 partykit/tests/regtest-honesty.R0000644000176200001440000000251714254064505016564 0ustar liggesusers library("partykit") n <- 100 x <- runif(n) y <- rnorm(n, mean = sin(x), sd = .1) s <- gl(4, n / 4) set.seed(29) ### estimate with honesty cf_ss <- cforest(y ~ x, strata = s, ntree = 5, mtry = 1, perturb = list(replace = FALSE, fraction = c(.5, .5))) ### sample used for tree induction stopifnot(sum(tapply(cf_ss$weights[[1]], s, sum)) == n / 2) ### sample used for parameter estimation stopifnot(sum(tapply(cf_ss$honest_weights[[1]], s, sum)) == n / 2) p <- predict(cf_ss) set.seed(29) ### w/o honesty cf_ss2 <- cforest(y ~ x, strata = s, ntree = 5, mtry = 1, perturb = list(replace = FALSE, fraction = .5)) stopifnot(sum(tapply(cf_ss2$weights[[1]], s, sum)) == n / 2) # random diffs also on other platforms #if (.Platform$OS.type != "windows") # stopifnot(all.equal(cf_ss$nodes, cf_ss2$nodes)) stopifnot(all.equal(cf_ss$weights, cf_ss2$weights)) stopifnot(all.equal(predict(cf_ss, type = "node"), predict(cf_ss2, type = "node"))) tmp <- cf_ss2 tmp$weights <- lapply(tmp$weights, function(x) 1L - x) pp <- predict(tmp) stopifnot(all.equal(p, pp)) ### bootstrap ignores honesty cf_bs <- cforest(y ~ x, strata = s, ntree = 5, perturb = list(replace = TRUE, fraction = c(.5, .5))) stopifnot(sum(tapply(cf_bs$weights[[1]], s, sum)) == n) stopifnot(is.null(cf_bs$honest_weights)) partykit/tests/constparty.Rout.save0000644000176200001440000004372314172230001017300 0ustar liggesusers R version 4.0.4 (2021-02-15) -- "Lost Library Book" Copyright (C) 2021 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > ### R code from vignette source 'constparty.Rnw' > > ### test here after removal of RWeka dependent code > > ################################################### > ### code chunk number 1: setup > ################################################### > options(width = 70) > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > set.seed(290875) > > > ################################################### > ### code chunk number 2: Titanic > ################################################### > data("Titanic", package = "datasets") > ttnc <- as.data.frame(Titanic) > ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] > names(ttnc)[2] <- "Gender" > > > ################################################### > ### code chunk number 3: rpart > ################################################### > library("rpart") > (rp <- rpart(Survived ~ ., data = ttnc, model = TRUE)) n= 2201 node), split, n, loss, yval, (yprob) * denotes terminal node 1) root 2201 711 No (0.6769650 0.3230350) 2) Gender=Male 1731 367 No (0.7879838 0.2120162) 4) Age=Adult 1667 338 No (0.7972406 0.2027594) * 5) Age=Child 64 29 No (0.5468750 0.4531250) 10) Class=3rd 48 13 No (0.7291667 0.2708333) * 11) Class=1st,2nd 16 0 Yes (0.0000000 1.0000000) * 3) Gender=Female 470 126 Yes (0.2680851 0.7319149) 6) Class=3rd 196 90 No (0.5408163 0.4591837) * 7) Class=1st,2nd,Crew 274 20 Yes (0.0729927 0.9270073) * > > > ################################################### > ### code chunk number 4: rpart-party > ################################################### > (party_rp <- as.party(rp)) Model formula: Survived ~ Class + Gender + Age Fitted party: [1] root | [2] Gender in Male | | [3] Age in Adult: No (n = 1667, err = 20.3%) | | [4] Age in Child | | | [5] Class in 3rd: No (n = 48, err = 27.1%) | | | [6] Class in 1st, 2nd: Yes (n = 16, err = 0.0%) | [7] Gender in Female | | [8] Class in 3rd: No (n = 196, err = 45.9%) | | [9] Class in 1st, 2nd, Crew: Yes (n = 274, err = 7.3%) Number of inner nodes: 4 Number of terminal nodes: 5 > > > ################################################### > ### code chunk number 5: rpart-plot-orig > ################################################### > plot(rp) > text(rp) > > > ################################################### > ### code chunk number 6: rpart-plot > ################################################### > plot(party_rp) > > > ################################################### > ### code chunk number 7: rpart-pred > ################################################### > all.equal(predict(rp), predict(party_rp, type = "prob"), + check.attributes = FALSE) [1] TRUE > > > ################################################### > ### code chunk number 8: rpart-fitted > ################################################### > str(fitted(party_rp)) 'data.frame': 2201 obs. of 2 variables: $ (fitted) : int 5 5 5 5 5 5 5 5 5 5 ... $ (response): Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ... > > > ################################################### > ### code chunk number 9: rpart-prob > ################################################### > prop.table(do.call("table", fitted(party_rp)), 1) (response) (fitted) No Yes 3 0.7972406 0.2027594 5 0.7291667 0.2708333 6 0.0000000 1.0000000 8 0.5408163 0.4591837 9 0.0729927 0.9270073 > > > ################################################### > ### code chunk number 10: J48 > ################################################### > #if (require("RWeka")) { > # j48 <- J48(Survived ~ ., data = ttnc) > #} else { > # j48 <- rpart(Survived ~ ., data = ttnc) > #} > #print(j48) > # > # > #################################################### > #### code chunk number 11: J48-party > #################################################### > #(party_j48 <- as.party(j48)) > # > # > #################################################### > #### code chunk number 12: J48-plot > #################################################### > #plot(party_j48) > # > # > #################################################### > #### code chunk number 13: J48-pred > #################################################### > #all.equal(predict(j48, type = "prob"), predict(party_j48, type = "prob"), > # check.attributes = FALSE) > > > ################################################### > ### code chunk number 14: PMML-Titantic > ################################################### > ttnc_pmml <- file.path(system.file("pmml", package = "partykit"), + "ttnc.pmml") > (ttnc_quest <- pmmlTreeModel(ttnc_pmml)) Loading required namespace: XML Model formula: Survived ~ Gender + Class + Age Fitted party: [1] root | [2] Gender in Female | | [3] Class in 3rd, Crew: Yes (n = 219, err = 49.8%) | | [4] Class in 1st, 2nd | | | [5] Class in 2nd: Yes (n = 106, err = 12.3%) | | | [6] Class in 1st: Yes (n = 145, err = 2.8%) | [7] Gender in Male | | [8] Class in 3rd, 2nd, Crew | | | [9] Age in Child: No (n = 59, err = 40.7%) | | | [10] Age in Adult | | | | [11] Class in 3rd, Crew | | | | | [12] Class in Crew: No (n = 862, err = 22.3%) | | | | | [13] Class in 3rd: No (n = 462, err = 16.2%) | | | | [14] Class in 2nd: No (n = 168, err = 8.3%) | | [15] Class in 1st: No (n = 180, err = 34.4%) Number of inner nodes: 7 Number of terminal nodes: 8 > > > ################################################### > ### code chunk number 15: PMML-Titanic-plot1 > ################################################### > plot(ttnc_quest) > > > ################################################### > ### code chunk number 16: ttnc2-reorder > ################################################### > ttnc2 <- ttnc[, names(ttnc_quest$data)] > for(n in names(ttnc2)) { + if(is.factor(ttnc2[[n]])) ttnc2[[n]] <- factor( + ttnc2[[n]], levels = levels(ttnc_quest$data[[n]])) + } > > > ################################################### > ### code chunk number 17: PMML-Titanic-augmentation > ################################################### > ttnc_quest2 <- party(ttnc_quest$node, + data = ttnc2, + fitted = data.frame( + "(fitted)" = predict(ttnc_quest, ttnc2, type = "node"), + "(response)" = ttnc2$Survived, + check.names = FALSE), + terms = terms(Survived ~ ., data = ttnc2) + ) > ttnc_quest2 <- as.constparty(ttnc_quest2) > > > ################################################### > ### code chunk number 18: PMML-Titanic-plot2 > ################################################### > plot(ttnc_quest2) > > > ################################################### > ### code chunk number 19: PMML-write > ################################################### > library("pmml") Loading required package: XML > tfile <- tempfile() > write(toString(pmml(rp)), file = tfile) > > > ################################################### > ### code chunk number 20: PMML-read > ################################################### > (party_pmml <- pmmlTreeModel(tfile)) Model formula: Survived ~ Class + Gender + Age Fitted party: [1] root | [2] Gender in Male | | [3] Age in Adult: No (n = 1667, err = 20.3%) | | [4] Age in Child | | | [5] Class in 3rd: No (n = 48, err = 27.1%) | | | [6] Class in 1st, 2nd: Yes (n = 16, err = 0.0%) | [7] Gender in Female | | [8] Class in 3rd: No (n = 196, err = 45.9%) | | [9] Class in 1st, 2nd, Crew: Yes (n = 274, err = 7.3%) Number of inner nodes: 4 Number of terminal nodes: 5 > all.equal(predict(party_rp, newdata = ttnc, type = "prob"), + predict(party_pmml, newdata = ttnc, type = "prob"), + check.attributes = FALSE) [1] TRUE > > > ################################################### > ### code chunk number 21: mytree-1 > ################################################### > findsplit <- function(response, data, weights, alpha = 0.01) { + + ## extract response values from data + y <- factor(rep(data[[response]], weights)) + + ## perform chi-squared test of y vs. x + mychisqtest <- function(x) { + x <- factor(x) + if(length(levels(x)) < 2) return(NA) + ct <- suppressWarnings(chisq.test(table(y, x), correct = FALSE)) + pchisq(ct$statistic, ct$parameter, log = TRUE, lower.tail = FALSE) + } + xselect <- which(names(data) != response) + logp <- sapply(xselect, function(i) mychisqtest(rep(data[[i]], weights))) + names(logp) <- names(data)[xselect] + + ## Bonferroni-adjusted p-value small enough? + if(all(is.na(logp))) return(NULL) + minp <- exp(min(logp, na.rm = TRUE)) + minp <- 1 - (1 - minp)^sum(!is.na(logp)) + if(minp > alpha) return(NULL) + + ## for selected variable, search for split minimizing p-value + xselect <- xselect[which.min(logp)] + x <- rep(data[[xselect]], weights) + + ## set up all possible splits in two kid nodes + lev <- levels(x[drop = TRUE]) + if(length(lev) == 2) { + splitpoint <- lev[1] + } else { + comb <- do.call("c", lapply(1:(length(lev) - 2), + function(x) combn(lev, x, simplify = FALSE))) + xlogp <- sapply(comb, function(q) mychisqtest(x %in% q)) + splitpoint <- comb[[which.min(xlogp)]] + } + + ## split into two groups (setting groups that do not occur to NA) + splitindex <- !(levels(data[[xselect]]) %in% splitpoint) + splitindex[!(levels(data[[xselect]]) %in% lev)] <- NA_integer_ + splitindex <- splitindex - min(splitindex, na.rm = TRUE) + 1L + + ## return split as partysplit object + return(partysplit(varid = as.integer(xselect), + index = splitindex, + info = list(p.value = 1 - (1 - exp(logp))^sum(!is.na(logp))))) + } > > > ################################################### > ### code chunk number 22: mytree-2 > ################################################### > growtree <- function(id = 1L, response, data, weights, minbucket = 30) { + + ## for less than 30 observations stop here + if (sum(weights) < minbucket) return(partynode(id = id)) + + ## find best split + sp <- findsplit(response, data, weights) + ## no split found, stop here + if (is.null(sp)) return(partynode(id = id)) + + ## actually split the data + kidids <- kidids_split(sp, data = data) + + ## set up all daugther nodes + kids <- vector(mode = "list", length = max(kidids, na.rm = TRUE)) + for (kidid in 1:length(kids)) { + ## select observations for current node + w <- weights + w[kidids != kidid] <- 0 + ## get next node id + if (kidid > 1) { + myid <- max(nodeids(kids[[kidid - 1]])) + } else { + myid <- id + } + ## start recursion on this daugther node + kids[[kidid]] <- growtree(id = as.integer(myid + 1), response, data, w) + } + + ## return nodes + return(partynode(id = as.integer(id), split = sp, kids = kids, + info = list(p.value = min(info_split(sp)$p.value, na.rm = TRUE)))) + } > > > ################################################### > ### code chunk number 23: mytree-3 > ################################################### > mytree <- function(formula, data, weights = NULL) { + + ## name of the response variable + response <- all.vars(formula)[1] + ## data without missing values, response comes last + data <- data[complete.cases(data), c(all.vars(formula)[-1], response)] + ## data is factors only + stopifnot(all(sapply(data, is.factor))) + + if (is.null(weights)) weights <- rep(1L, nrow(data)) + ## weights are case weights, i.e., integers + stopifnot(length(weights) == nrow(data) & + max(abs(weights - floor(weights))) < .Machine$double.eps) + + ## grow tree + nodes <- growtree(id = 1L, response, data, weights) + + ## compute terminal node number for each observation + fitted <- fitted_node(nodes, data = data) + ## return rich constparty object + ret <- party(nodes, data = data, + fitted = data.frame("(fitted)" = fitted, + "(response)" = data[[response]], + "(weights)" = weights, + check.names = FALSE), + terms = terms(formula)) + as.constparty(ret) + } > > > ################################################### > ### code chunk number 24: mytree-4 > ################################################### > (myttnc <- mytree(Survived ~ Class + Age + Gender, data = ttnc)) Model formula: Survived ~ Class + Age + Gender Fitted party: [1] root | [2] Gender in Male | | [3] Class in 1st | | | [4] Age in Child: Yes (n = 5, err = 0.0%) | | | [5] Age in Adult: No (n = 175, err = 32.6%) | | [6] Class in 2nd, 3rd, Crew | | | [7] Age in Child | | | | [8] Class in 2nd: Yes (n = 11, err = 0.0%) | | | | [9] Class in 3rd: No (n = 48, err = 27.1%) | | | [10] Age in Adult | | | | [11] Class in Crew: No (n = 862, err = 22.3%) | | | | [12] Class in 2nd, 3rd: No (n = 630, err = 14.1%) | [13] Gender in Female | | [14] Class in 3rd: No (n = 196, err = 45.9%) | | [15] Class in 1st, 2nd, Crew: Yes (n = 274, err = 7.3%) Number of inner nodes: 7 Number of terminal nodes: 8 > > > ################################################### > ### code chunk number 25: mytree-5 > ################################################### > plot(myttnc) > > > ################################################### > ### code chunk number 26: mytree-pval > ################################################### > nid <- nodeids(myttnc) > iid <- nid[!(nid %in% nodeids(myttnc, terminal = TRUE))] > (pval <- unlist(nodeapply(myttnc, ids = iid, + FUN = function(n) info_node(n)$p.value))) 1 2 3 6 7 0.000000e+00 2.965383e-06 1.756527e-03 6.933623e-05 8.975754e-06 10 13 2.992870e-05 0.000000e+00 > > > ################################################### > ### code chunk number 27: mytree-nodeprune > ################################################### > myttnc2 <- nodeprune(myttnc, ids = iid[pval > 1e-5]) > > > ################################################### > ### code chunk number 28: mytree-nodeprune-plot > ################################################### > plot(myttnc2) > > > ################################################### > ### code chunk number 29: mytree-glm > ################################################### > logLik(glm(Survived ~ Class + Age + Gender, data = ttnc, + family = binomial())) 'log Lik.' -1105.031 (df=6) > > > ################################################### > ### code chunk number 30: mytree-bs > ################################################### > bs <- rmultinom(25, nrow(ttnc), rep(1, nrow(ttnc)) / nrow(ttnc)) > > > ################################################### > ### code chunk number 31: mytree-ll > ################################################### > bloglik <- function(prob, weights) + sum(weights * dbinom(ttnc$Survived == "Yes", size = 1, + prob[,"Yes"], log = TRUE)) > > > ################################################### > ### code chunk number 32: mytree-bsll > ################################################### > f <- function(w) { + tr <- mytree(Survived ~ Class + Age + Gender, data = ttnc, weights = w) + bloglik(predict(tr, newdata = ttnc, type = "prob"), as.numeric(w == 0)) + } > apply(bs, 2, f) [1] -418.2675 -398.0958 -418.6230 -404.1996 -410.8889 -411.7570 [7] -374.9353 -412.6712 -421.7616 -393.9068 -400.0987 -373.6991 [13] -395.1191 -422.8247 -429.5351 -384.3696 -391.9081 -388.7349 [19] -399.7435 -409.1937 -391.9392 -409.1083 -399.7312 -391.7226 [25] -391.5488 > > > ################################################### > ### code chunk number 33: mytree-node > ################################################### > nttnc <- expand.grid(Class = levels(ttnc$Class), + Gender = levels(ttnc$Gender), Age = levels(ttnc$Age)) > nttnc Class Gender Age 1 1st Male Child 2 2nd Male Child 3 3rd Male Child 4 Crew Male Child 5 1st Female Child 6 2nd Female Child 7 3rd Female Child 8 Crew Female Child 9 1st Male Adult 10 2nd Male Adult 11 3rd Male Adult 12 Crew Male Adult 13 1st Female Adult 14 2nd Female Adult 15 3rd Female Adult 16 Crew Female Adult > > > ################################################### > ### code chunk number 34: mytree-prob > ################################################### > predict(myttnc, newdata = nttnc, type = "node") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 4 8 9 8 15 15 14 15 5 12 12 11 15 15 14 15 > predict(myttnc, newdata = nttnc, type = "response") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Yes Yes No No Yes Yes No Yes No No No No Yes Yes No Yes Levels: No Yes > predict(myttnc, newdata = nttnc, type = "prob") No Yes 1 0.0000000 1.0000000 2 0.0000000 1.0000000 3 0.7291667 0.2708333 4 0.0000000 1.0000000 5 0.0729927 0.9270073 6 0.0729927 0.9270073 7 0.5408163 0.4591837 8 0.0729927 0.9270073 9 0.6742857 0.3257143 10 0.8587302 0.1412698 11 0.8587302 0.1412698 12 0.7772622 0.2227378 13 0.0729927 0.9270073 14 0.0729927 0.9270073 15 0.5408163 0.4591837 16 0.0729927 0.9270073 > > > ################################################### > ### code chunk number 35: mytree-FUN > ################################################### > predict(myttnc, newdata = nttnc, FUN = function(y, w) + rank(table(rep(y, w)))) No Yes 1 1 2 2 1 2 3 2 1 4 2 1 5 1 2 6 1 2 7 2 1 8 1 2 9 2 1 10 2 1 11 2 1 12 2 1 13 1 2 14 1 2 15 2 1 16 1 2 > > > > proc.time() user system elapsed 3.175 0.098 3.258 partykit/tests/regtest-glmtree.Rout.save0000644000176200001440000003554614172230000020207 0ustar liggesusers R version 4.0.3 (2020-10-10) -- "Bunny-Wunnies Freak Out" Copyright (C) 2020 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > > set.seed(29) > n <- 1000 > x <- runif(n) > z <- runif(n) > y <- rnorm(n, mean = x * c(-1, 1)[(z > 0.7) + 1], sd = 3) > z_noise <- factor(sample(1:3, size = n, replace = TRUE)) > d <- data.frame(y = y, x = x, z = z, z_noise = z_noise) > > > fmla <- as.formula("y ~ x | z + z_noise") > fmly <- gaussian() > fit <- partykit:::glmfit > > # versions of the data > d1 <- d > d1$z <- signif(d1$z, digits = 1) > > k <- 20 > zs_noise <- matrix(rnorm(n*k), nrow = n) > colnames(zs_noise) <- paste0("z_noise_", 1:k) > d2 <- cbind(d, zs_noise) > fmla2 <- as.formula(paste("y ~ x | z + z_noise +", + paste0("z_noise_", 1:k, collapse = " + "))) > > > d3 <- d2 > d3$z <- factor(sample(1:3, size = n, replace = TRUE, prob = c(0.1, 0.5, 0.4))) > d3$y <- rnorm(n, mean = x * c(-1, 1)[(d3$z == 2) + 1], sd = 3) > > ## check weights > w <- rep(1, n) > w[1:10] <- 2 > (mw1 <- glmtree(formula = fmla, data = d, weights = w)) Generalized linear model tree (family: gaussian) Model formula: y ~ x | z + z_noise Fitted party: [1] root | [2] z <= 0.70311: n = 706 | (Intercept) x | -0.1447422 -0.8138701 | [3] z > 0.70311: n = 304 | (Intercept) x | 0.07006626 0.73278593 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 2 Objective function (negative log-likelihood): 2551.48 > (mw2 <- glmtree(formula = fmla, data = d, weights = w, caseweights = FALSE)) Generalized linear model tree (family: gaussian) Model formula: y ~ x | z + z_noise Fitted party: [1] root | [2] z <= 0.70311: n = 704 | (Intercept) x | -0.1447422 -0.8138701 | [3] z > 0.70311: n = 296 | (Intercept) x | 0.07006626 0.73278593 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 2 Objective function (negative log-likelihood): 2551.48 > > > > ## check dfsplit > (mmfluc2 <- mob(formula = fmla, data = d, fit = partykit:::glmfit)) Model-based recursive partitioning (partykit:::glmfit) Model formula: y ~ x | z + z_noise Fitted party: [1] root | [2] z <= 0.70311: n = 704 | (Intercept) x | -0.1619978 -0.7896293 | [3] z > 0.70311: n = 296 | (Intercept) x | 0.08683535 0.65598287 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 2 Objective function: 2551.673 > (mmfluc3 <- glmtree(formula = fmla, data = d)) Generalized linear model tree (family: gaussian) Model formula: y ~ x | z + z_noise Fitted party: [1] root | [2] z <= 0.70311: n = 704 | (Intercept) x | -0.1619978 -0.7896293 | [3] z > 0.70311: n = 296 | (Intercept) x | 0.08683535 0.65598287 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 2 Objective function (negative log-likelihood): 2551.673 > (mmfluc3_dfsplit <- glmtree(formula = fmla, data = d, dfsplit = 10)) Generalized linear model tree (family: gaussian) Model formula: y ~ x | z + z_noise Fitted party: [1] root | [2] z <= 0.70311: n = 704 | (Intercept) x | -0.1619978 -0.7896293 | [3] z > 0.70311: n = 296 | (Intercept) x | 0.08683535 0.65598287 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 2 Objective function (negative log-likelihood): 2551.673 > > > ## check tests > if (require("strucchange")) + print(sctest(mmfluc3, node = 1)) # does not yet work Loading required package: strucchange Loading required package: zoo Attaching package: 'zoo' The following objects are masked from 'package:base': as.Date, as.Date.numeric Loading required package: sandwich z z_noise statistic 2.292499e+01 0.6165335 p.value 7.780038e-04 0.9984952 > > x <- mmfluc3 > (tst3 <- nodeapply(x, ids = nodeids(x), function(n) n$info$criterion)) $`1` NULL $`2` NULL $`3` NULL > > > > > ## check logLik and AIC > logLik(mmfluc2) 'log Lik.' -2551.673 (df=7) > logLik(mmfluc3) 'log Lik.' -2551.673 (df=7) > logLik(mmfluc3_dfsplit) 'log Lik.' -2551.673 (df=16) > logLik(glm(y ~ x, data = d)) 'log Lik.' -2563.694 (df=3) > > AIC(mmfluc3) [1] 5117.347 > AIC(mmfluc3_dfsplit) [1] 5135.347 > > ## check pruning > pr2 <- prune.modelparty(mmfluc2) > AIC(mmfluc2) [1] 5117.347 > AIC(pr2) [1] 5117.347 > > mmfluc_dfsplit3 <- glmtree(formula = fmla, data = d, alpha = 0.5, dfsplit = 3) > mmfluc_dfsplit4 <- glmtree(formula = fmla, data = d, alpha = 0.5, dfsplit = 4) > pr_dfsplit3 <- prune.modelparty(mmfluc_dfsplit3) > pr_dfsplit4 <- prune.modelparty(mmfluc_dfsplit4) > AIC(mmfluc_dfsplit3) [1] 5142.774 > AIC(mmfluc_dfsplit4) [1] 5156.774 > AIC(pr_dfsplit3) [1] 5142.774 > AIC(pr_dfsplit4) [1] 5124.456 > > width(mmfluc_dfsplit3) [1] 8 > width(mmfluc_dfsplit4) [1] 8 > width(pr_dfsplit3) [1] 8 > width(pr_dfsplit4) [1] 3 > > ## check inner and terminal > options <- list(NULL, + "object", + "estfun", + c("object", "estfun")) > > arguments <- list("inner", + "terminal", + c("inner", "terminal")) > > > for (o in options) { + print(o) + x <- glmtree(formula = fmla, data = d, inner = o) + str(nodeapply(x, ids = nodeids(x), function(n) n$info[c("object", "estfun")]), 2) + } NULL List of 3 $ 1:List of 2 ..$ NA: NULL ..$ NA: NULL $ 2:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL $ 3:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL [1] "object" List of 3 $ 1:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL $ 2:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL $ 3:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL [1] "estfun" List of 3 $ 1:List of 2 ..$ NA : NULL ..$ estfun: num [1:1000, 1:2] -0.1375 -0.0583 -0.0553 0.1043 -0.0744 ... .. ..- attr(*, "dimnames")=List of 2 $ 2:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL $ 3:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL [1] "object" "estfun" List of 3 $ 1:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ estfun: num [1:1000, 1:2] -0.1375 -0.0583 -0.0553 0.1043 -0.0744 ... .. ..- attr(*, "dimnames")=List of 2 $ 2:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL $ 3:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL > > for (o in options) { + print(o) + x <- glmtree(formula = fmla, data = d, terminal = o) + str(nodeapply(x, ids = nodeids(x), function(n) n$info[c("object", "estfun")]), 2) + } NULL List of 3 $ 1:List of 2 ..$ NA: NULL ..$ NA: NULL $ 2:List of 2 ..$ NA: NULL ..$ NA: NULL $ 3:List of 2 ..$ NA: NULL ..$ NA: NULL [1] "object" List of 3 $ 1:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL $ 2:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL $ 3:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ NA : NULL [1] "estfun" List of 3 $ 1:List of 2 ..$ NA : NULL ..$ estfun: num [1:1000, 1:2] -0.1375 -0.0583 -0.0553 0.1043 -0.0744 ... .. ..- attr(*, "dimnames")=List of 2 $ 2:List of 2 ..$ NA : NULL ..$ estfun: num [1:704, 1:2] -0.1291 0.5104 -0.0603 -0.1868 -0.0981 ... .. ..- attr(*, "dimnames")=List of 2 $ 3:List of 2 ..$ NA : NULL ..$ estfun: num [1:296, 1:2] -0.1053 -0.0877 0.0544 -0.1581 0.43 ... .. ..- attr(*, "dimnames")=List of 2 [1] "object" "estfun" List of 3 $ 1:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ estfun: num [1:1000, 1:2] -0.1375 -0.0583 -0.0553 0.1043 -0.0744 ... .. ..- attr(*, "dimnames")=List of 2 $ 2:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ estfun: num [1:704, 1:2] -0.1291 0.5104 -0.0603 -0.1868 -0.0981 ... .. ..- attr(*, "dimnames")=List of 2 $ 3:List of 2 ..$ object:List of 24 .. ..- attr(*, "class")= chr [1:2] "glm" "lm" ..$ estfun: num [1:296, 1:2] -0.1053 -0.0877 0.0544 -0.1581 0.43 ... .. ..- attr(*, "dimnames")=List of 2 > > > ## check model > m_mt <- glmtree(formula = fmla, data = d, model = TRUE) > m_mf <- glmtree(formula = fmla, data = d, model = FALSE) > > dim(m_mt$data) [1] 1000 4 > dim(m_mf$data) [1] 0 4 > > > ## check multiway > (m_mult <- glmtree(formula = fmla2, data = d3, catsplit = "multiway", minsize = 80)) Generalized linear model tree (family: gaussian) Model formula: y ~ x | z + z_noise + z_noise_1 + z_noise_2 + z_noise_3 + z_noise_4 + z_noise_5 + z_noise_6 + z_noise_7 + z_noise_8 + z_noise_9 + z_noise_10 + z_noise_11 + z_noise_12 + z_noise_13 + z_noise_14 + z_noise_15 + z_noise_16 + z_noise_17 + z_noise_18 + z_noise_19 + z_noise_20 Fitted party: [1] root | [2] z in 1: n = 76 | (Intercept) x | 0.9859847 -3.2600047 | [3] z in 2: n = 537 | (Intercept) x | -0.06970187 1.12305074 | [4] z in 3: n = 387 | (Intercept) x | 0.3824392 -1.8337151 Number of inner nodes: 1 Number of terminal nodes: 3 Number of parameters per node: 2 Objective function (negative log-likelihood): 2511.927 > > > ## check parm > fmla_p <- as.formula("y ~ x + z_noise + z_noise_1 | z + z_noise_2") > (m_interc <- glmtree(formula = fmla_p, data = d2, parm = 1)) Generalized linear model tree (family: gaussian) Model formula: y ~ x + z_noise + z_noise_1 | z + z_noise_2 Fitted party: [1] root | [2] z <= 0.65035: n = 644 | (Intercept) x z_noise2 z_noise3 z_noise_1 | -0.05585503 -1.01257554 0.34044520 -0.16384987 0.24197601 | [3] z > 0.65035: n = 356 | (Intercept) x z_noise2 z_noise3 z_noise_1 | 0.06411865 0.78733976 -0.67811149 -0.14240432 -0.01239154 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 5 Objective function (negative log-likelihood): 2548.32 > > (m_p3 <- glmtree(formula = fmla_p, data = d2, parm = 3)) Generalized linear model tree (family: gaussian) Model formula: y ~ x + z_noise + z_noise_1 | z + z_noise_2 Fitted party: [1] root: n = 1000 (Intercept) x z_noise2 z_noise3 z_noise_1 -0.058855295 -0.340314311 -0.008404682 -0.109839080 0.154798281 Number of inner nodes: 0 Number of terminal nodes: 1 Number of parameters per node: 5 Objective function (negative log-likelihood): 2562.32 > > > ## check trim > (m_tt <- glmtree(formula = fmla, data = d, trim = 0.2)) Generalized linear model tree (family: gaussian) Model formula: y ~ x | z + z_noise Fitted party: [1] root | [2] z <= 0.70311: n = 704 | (Intercept) x | -0.1619978 -0.7896293 | [3] z > 0.70311: n = 296 | (Intercept) x | 0.08683535 0.65598287 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 2 Objective function (negative log-likelihood): 2551.673 > > (m_tf <- glmtree(formula = fmla, data = d, trim = 300, minsize = 300)) Generalized linear model tree (family: gaussian) Model formula: y ~ x | z + z_noise Fitted party: [1] root | [2] z <= 0.6892: n = 691 | (Intercept) x | -0.1778199 -0.7692901 | [3] z > 0.6892: n = 309 | (Intercept) x | 0.1065746 0.5562243 Number of inner nodes: 1 Number of terminal nodes: 2 Number of parameters per node: 2 Objective function (negative log-likelihood): 2552.12 > > > > ## check breakties > m_bt <- glmtree(formula = fmla, data = d1, breakties = TRUE) > m_df <- glmtree(formula = fmla, data = d1, breakties = FALSE) > > all.equal(m_bt, m_df, check.environment = FALSE) [1] "Component \"node\": Component \"kids\": Component 1: Component 5: Component 6: Mean relative difference: 0.1237503" [2] "Component \"node\": Component \"kids\": Component 2: Component 5: Component 5: Mean relative difference: 0.1746109" [3] "Component \"node\": Component \"kids\": Component 2: Component 5: Component 6: Mean relative difference: 0.0443985" [4] "Component \"node\": Component \"info\": Component \"p.value\": Mean relative difference: 1.100407" [5] "Component \"node\": Component \"info\": Component \"test\": Mean relative difference: 0.07721086" [6] "Component \"info\": Component \"call\": target, current do not match when deparsed" [7] "Component \"info\": Component \"control\": Component \"breakties\": 1 element mismatch" > > unclass(m_bt)$node$info$criterion NULL > unclass(m_df)$node$info$criterion NULL > > > ### example from mob vignette > data("PimaIndiansDiabetes", package = "mlbench") > > logit <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { + glm(y ~ 0 + x, family = binomial, start = start, ...) + } > > pid_formula <- diabetes ~ glucose | pregnant + pressure + triceps + + insulin + mass + pedigree + age > > pid_tree <- mob(pid_formula, data = PimaIndiansDiabetes, fit = logit) > pid_tree Model-based recursive partitioning (logit) Model formula: diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age Fitted party: [1] root | [2] mass <= 26.3: n = 167 | x(Intercept) xglucose | -9.95150963 0.05870786 | [3] mass > 26.3 | | [4] age <= 30: n = 304 | | x(Intercept) xglucose | | -6.70558554 0.04683748 | | [5] age > 30: n = 297 | | x(Intercept) xglucose | | -2.77095386 0.02353582 Number of inner nodes: 2 Number of terminal nodes: 3 Number of parameters per node: 2 Objective function: 355.4578 > nodeapply(pid_tree, ids = nodeids(pid_tree), function(n) n$info$criterion) $`1` NULL $`2` NULL $`3` NULL $`4` NULL $`5` NULL > > > > > proc.time() user system elapsed 20.340 0.056 20.394 partykit/tests/Rplots.pdf0000644000176200001440000007060414172230001015236 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20210303113011) /ModDate (D:20210303113011) /Title (R Graphics Output) /Producer (R 4.0.4) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 365 /Filter /FlateDecode >> stream xn0 y bԉCmHHCڨ4Mn.{%)E;THcW%S$Cf`bZ ^ƥ1ljQk zsT;E5ڈCF0P`3r[d^LT,| 4l,~T9$rh+}B 8ސԍ=Ɠ$ʋ8ץ{ϜIhuԍ?pt߆aFO:vd<C*zrgOD>&u] &~B8A.H. bX?ԀKr: o0 ٍMY,`nzx ,#/Bـendstream endobj 9 0 obj << /Type /Page /Parent 3 0 R /Contents 10 0 R /Resources 4 0 R >> endobj 10 0 obj << /Length 3705 /Filter /FlateDecode >> stream x[Mϯ8.?9Bl 8Nb*A~]dW+Y녖_?/7oۺm2}kIl-_˟_,Bkk KLir#Ne\{[\S|{ {{C(& ׍,8%f ˃EpX#9NM-8$8z9tnq.Ku%]qs\t*QSv\tnUqP zeRL+XW6\WHQyf5Mדi$Φ_Q~Dk11۸5W|ނZz-|>o본P~wJ}c>O / |q>>ŻWS_I~Ye|t_<2yyww|ڌ(>ǫi C;iƃɞ9c]Uu֐m}q#fB\rC_}zuuX3i$BMh,$'iB'|% jԨɔ%GQPbeIÒS0RB*k-n,bB];XfB e 2Y۔(FDCP`Fʢ`AI%9uXX) J .̦I+(b(p8*oPlt *+|y\85kzM5}! OTƷřHBx(VqNCny{7ě%2I^~}2tJ*=jW0m>$u{4=I-5o=w}$w=Otѩ "ہ&AMpׯpv=Y+4;=@w'>;?{E}v}l(w+Ow -fɦˇcC̿VTޛ,{!Iw;K|滋Յ7JYy$>R'S+b')A8mGُ=찃h̆2eP A(N^TRX/{#L7Awv, @:Jފ{E#zيdp]Ϧ)κ1SwD$d8ʆC6XeZ .E[fzzpM-pl~cVlpo>,FmAvܱ Bt gi8 ;~*Cs5v(.Bx}2$'6Cq?!_ktS*VCb`om WL#>2'HŦ=ϧ9}KO O?궼N{ݿW0Iw{v}POG:CK O@e'Xz 'lOzM*M ݟOR D4Nj)xx8X œ>~w?_~S| k!?/'o? s^RyRm=Yrg+n:yx]xy&rL UyX6aKS=iK\b_vnl UӅ Pi۽4y  P+VKPwQ^:di>:G!D}|x#jQ`*FQ<1c)H0뜊Y3kR}nQgV@Y[GW0=1>R?oܬ"0ZzBOL4-hD徼]R}!:>+}';~&qpqp}}x܇'K=xY>{&3g}~&aܧV/{t'OrL'ȹq[A̔ǩ'A <X͵bkmb^ +x7vE?ݜ~7vͻBf^[7;D} W\ 9- {gd(\ :uDI\( Hwf) 8S#b7Jnmw+N<#9#XSx.>\CܖC^\{p׎U#W|s9<|¹1ixSzvrƹg3:.u./`>\N-b3%²`ǫR!.wJw_R;jE.^u㾰Tu._rhRT?`Tq>>JUGTQS'PQK=xNJU{f,U}*YbC#z^>Oܟ-^+{Hf{>X> $7B>?Mr͹/xi[ ׹}>}x#Oc>ߕgq=|>L?0}$ =F~>K m0bzByl袀endstream endobj 11 0 obj << /Type /Page /Parent 3 0 R /Contents 12 0 R /Resources 4 0 R >> endobj 12 0 obj << /Length 5114 /Filter /FlateDecode >> stream x\ˎ\qW@y3s 21(-d= 0iC8Ȉb]>[yDɼO?ÿwR:ſ_<#޽)^ǻ N˫tjG=tzw7yS&]{ƿ?|||s΄ǹc^s6ҹ :goмAL_,4hRx ;Yp9xsivƣ*obZ\*^o|[eܪOݸx3 bx}!t³}f87`&?P>xppCd<$qG4%d%q`l+e}gvϵg__2V^vn!+<>K>>z|<)?0yNz>+PzG|z3|{=jy ѳS--ؓ:3[զG8lm ,<k|Jx"|ož?sk0{HχV/%5Zmy5%T_o|`3?7>2_̾wfCk|k7>01>2z`iŷGV,.ۻ׿+T_D!_]2g?˟s<_l7?Iiq dOhxŞS\}rlX2ܫ=;to<6̰ 6?`bOj.2j9LIJ싏?ϕ3\ yW"%+E8Z*"T@x:~l(nLEE;6+}pU^rl ۊۖ[ۙ`rl >"؇{걁/KbCD(M,t!ONUdU3ԒڹSƳ,h!{0?'~d`*l}Qos?q AC1Tрm!>:D/#! w|v8<~ߝb@#a;bJؑ|WWWO>T-K}Bh 5OWAܞޅSQˁa.nħKU3'`Q$ހž s<jx/3MP]CJ|J>5r.ߗ|%>? 8Gn+W/|t o?_R<>^xJ=z/CE={:y/j5rYXȇf=F$ѪtQ 2gz؟uR$bZ6׿Tk]92-;k乒5 Y7^Yiƚ\EVNKUN`[Essq1rLlX`af`|R/x|ity ݝGP?ѬW Pw %n q_ uˬ# 4akx^ / --iPxFjaxQnax=FaQk.pxC {\(N-HtYw_7{IXϻ'߯Ɠi KgO5ۏ [!nax?+l`vS/=!`8M#"`9m#?K GIh]^c~ :W~[~luV[}vyM5{2l2idg/͟iMx0Es'-Lnx45WRP-_}K{'@eoh>}#Xf|%_>_|NahGjOlWn_pGrOtWv_xLJ_;zWɎo7;z碞=eidj >w=F+y 1 Dv&6G@z^D|\Mgz6FewFQA?Y1F.Xg qpYBpB^lBKl#٥y-4A.5B%B6l!*#٥6UhAF7^P <]5xpBqiYn;ښ*4v0-Q Pm7!aB|/Ƨ2т].B؂p}'w A>86l# <]7xkK^ <]pl03!x!bW |Ƚ! g 5mNﷅ<t[B>[hT{m!RJ2[Tm!TRR5ЪX-jm!Wq ׸B5Ьhͧ-TgB.ߗ|%>? b?G'|s /§_[LJǏǗǟORO,"[Τ\0H+/:q80H?,X'>mZ; .x&YsT{b%vTH60H tRA℧|^1[xL("Rۀ;|RH&F`a=x\""%sxӢ]|~x1m<?TFSDFS'gܾ'' ?K$6 9U_4a;~Pc|Q5F0Oz.~6_(Н?UCg~â,'-7ibC8X`bc{aQЂ=S7- H-JUL ;-K|j#SR }HXy9Z.{^S}xem||B-w95ߴ6|%_>_|o+m(_m)m*m+n(_n)n*n+P|K~ǟփZ/vj=fǿ֣Zv\Գ4Ĕ&&} i;l\6O8o{4v79=FK7Nb۰uoz?(6mZ$ovek| c;K}quA%[|nA\ߠ# CI @3{MxosS-}J)/ە,;ƛ*fɞ`0.,Cpῢx*wZ3obL}*5Di}h[XZy~?(!C<>aߊz|x.ϟZ{tzvOaԾzCfV|A}hB-O 37a-%>5^b[^j_G+,,o{0l @icd= aݰ|Js}=g|ao>Wf?3c|i3>5ߚ->-~--X|Zzbm+˟z$sRYk~I$:8y>-5v1c:9N[2CdSgo%{vh!) %Nk߿0kO%0<>%'xkF^ {y49?bp%᭝V`#6yKi͝Ͽ2s }oujOXim~AAoPUVa|o8M& Dmz8dCs8gs =<?^endstream endobj 13 0 obj << /Type /Page /Parent 3 0 R /Contents 14 0 R /Resources 4 0 R >> endobj 14 0 obj << /Length 6037 /Filter /FlateDecode >> stream x]Kq.5s|5,<6Hp,9@RQԩug lv=NYVxI/sG//?[˲\@?~eKw \~F˥㺔˧^r)|{{sA-5ﮐ]{/| ҥҝJB]vMz:kvUqx㚹i)& wi-]P!8_ kk7WKgLo۪xxdצx$ƛo׊5Gc<bZs8m6pJ6t|[ǂ6WGC{^ *,e4e>^HA>Oe2<|4S~H}xS9kM>G xi95gN+i9uttn}GN<u5|~kkϺ|dm`^ZN{"\aoEj->os[%{3~Tp_n7>_õ7>2_Lw&Cӏk|k7>6061>727x`iٷGݿ}Ћf~!'o>|~.~wS">!&>e$5јlWk!9 ;zOo~ݥ,7>ry汱d,gЇ=&$4mQV RonOpFI9I c\XD| OL^7VKQk[,܇`b2JI F(`f*"ML 3,`@& "[cnNt`*v dL]Y \"˓@p0D,BWb,, Z*)n֍?/Ht.ŒCY_JG02 -/y5b͊|!| y) &80IR0[Ҕ3AQ80D&b/5M> kA ӮcZ`Hlrp*K=n6tC_ ?"g౫ߨzi$'YGwbi<  Xe"BjE(-8Zw`Y),㡨 0-BцNP ¹ `nHBbf,U5d-6ŀebI4B93[`82jq+o>8Wg%s2Q 4d\VBA.I!(ЗkAu$bt mT6rrݮ&b%=Kpk ⾰ 1IHh܍#I)ٱ@Lyc0oL򁔉b9́بLO0_/PÛ$gA7b~Jdߤ/K6kz8iva.O9]å\/9?HY>qxp)XW WaҒ2o竒 X'E)mBoʹb:eb[Vbd DkT*h%uYahzΛڣD`N`Qb|nKKz/r)$K)iY;o/팵nVjX O+ F,K_MʻK(w. 籉ŽzJ cxR)-FR3oѱRh\o~tgԲ5JVeze>RxĘx{wa#(E1ؓ$)#!,GJztpvވY*)[%F&GXƙ7 x-gq2:t.olTmpl^NXCv31Wc4Qd>?u)|~$Q>q# _d) j ACzۃ~'uSHS%OyWy_=EZ_}#EAA 9S _ۛr}׭rQrM 0_rxٯ籭{^¼6y>U^d} $wzꃰ[GI8or˞=`/{[}Gi^,L4#W{l/D{bO }bޮ՟}|wO^zx~#O|W>t(_O]ʷcks/{?n/~5}kqxg^_qsWIAWq#$R/\,.DzvyaUNuZRyN۝}șN.LET%>Du(IT'R>Ju!ZmF\O=}9| fX0=:S6\?'*^V)=H|3O],6 K./9J8z:N_ppxX -?p&Ғ0C69a+|'ET.Na/l3pFxNp>'p@|0hi pJ'S8Fo|^I l-gZƛk,o|f[;<^;Һ+*//̫/|0'|1^q))?)_)é˩?ө_۩i~ϧ} Ox0SŴ_'Ӿ%Lx4C]<{F(,Gg-2, BY4cP^CY4P^CY4:*(peLCYZ?E{(R=lh/h&APśa`,D-3U(k:) ­,wʦ_%koR6~;k , hk , CY4Tc_zo?^e,Mv/ʢ[(fʢ#E3dFk',%O/n\oe>v?+ |ld󵲒=eV2yXee-LV3}Xee5ӧLV3{ً̞gfeAG+bg+;[6n`eK+k?Yʢޮ՟}|wOo\>W.?3_|S>u*ߺ>~ݾ4}jpx_+]<{MT(?>߼/)+gWqs bs9\;  C`%P[@g@ۭppV8Y8Y@//):=X8 `@{,h xi-#c?Y8|?V8..ur@1=:S %-4r^~E]>Pyeޢo^l!(C /.wŔ*qF(#2+oF+@O9C͊؀`52ܶ*qbܸ ̩UF'c~cNm RIWeU Rqvـu㭒ʕk^1lbޑNJwWV~ *KgI{CX]0o·ECZwl79o s~%+Ok꛲ރ=T{|wSa#D7X.nn[ ej?QvW㫿|~>,|ϯ|Qr)|\ʇKןW||||Sۯo7n?4^kVyfᠬJ?_V_ʰ+3HlgaO{?ԇzA=,~؇}Lmrh򰯯fizI4oOmSO&of%}c'/13׍!@rS ,n`~TZqJ5 Ȃ ).0te˃? ,R;k WMqoeS㭺:& ޘ̇RB- 4&<0>śn}*?)ףkcobʚgʑM4F$/ F$7a L_X~נM>[dM/L>ɘ`>F&dWJW>4Fi GۘjWXߪ_ۊFRJ#g[L>2_d5ʛOlId}>͟*>^2 Z['qPyٞɭ֦'&_>şI-/%Xd.0?>? }8G.+W|Qt)~o]nn?n_n>-^Z<1xco>h0V H-J?|Lm/qvgySv̫k?匇;t74HYu D%U -[v/H{(H=:#/|EM*ۇh@z-H}| ,۔M_2?]Z{;Rcsy>}oe|gtoݢd0~hwZ"i񝶇I񝶇I񝶇/錌 ݜ/;l=w i|~[FLK9cF׌n&S~sFX5csy.n|{]Jt)o8߀F(n2nw.!1HMIMIMmrAݜ/;qz{AN{; ߍޡd/I{\{l*t.5Н'd[ΦZ)8ӝFw //^v;itNw>N۝}ҝN.tEtkuN;}QGNz?Dwx[FOmZz }lU|fGw>5oendstream endobj 15 0 obj << /Type /Page /Parent 3 0 R /Contents 16 0 R /Resources 4 0 R >> endobj 16 0 obj << /Length 6003 /Filter /FlateDecode >> stream x]MdG `c 0%z./]NWL"/Gf8~8O7wySӿ4ߥOw ~{Wtө.圧]*yN\V}g2k3ZzΧ؋ܺ`O70XzH_|SصdO ۵"y,Ϗu NRCs?5Z VP-]k<! +}~gn_;ϏϟϯϿOO̿-ߘ[>|egrGr/R)Q)6aH^zz{zOwzqlH-2?O$䉤Lsk?u.cz˕dyrŐiirۭܿQV2]$G ][`In=x-af1$^"?(NHn)ג-I҂.q7ɔSE눏eFC2%5|=&y,90֪s=MKЇ@6ͥ>6-5/֦=؃֦{aZ=7S%d'e%&9/$i I|(?Ч$ YS rJ# >]uxK<)^GxUs+(^)*+(^()޻i>p|[#W?|^J]Rkz0էzIP\ Tw'X" Fə XQ٨B <j:\|XSݫN3yV uzo}a bA;eoX ByoK=1 HIB"y 9uebVNji hÔ 4bTa!#~"llCIIa67ӊ$93 rBY&eSy# 'XK:* i+Gbn%.[~dUUK6a?,)mKNy#V0|}`KԆVA"{/m֠i XԆ%Wδ,LeH 6 M>@xd$s2| &1CP6<"}52T.!>zT ul.e~>4ke8'I3$O+^+>9ah̝S|X.>U82Ӝ)2)N}Q\$K2$w^٬|gŇ";nWw'TFo2B"̳/J@DVC[%,a+AZ E_@J-)vPY9@0u vvwwǔ~+Z{Myɪlua __єЩ"+e b,Ț,UǢMٱKBh!XبՖ߰"kJCC7xBNjG>;S='E ᥦ3˙xy ^w`R4a MPzf5H GLxV0[E޴״VF+"VL75EQoWyt!džљI"g$zηvG\oY;/vA[z{ǿx>!';N+R65g9rNL,,90Nc@B˙qiL˷h=(-"< r DZΝvpr^7r \Z.Ne)i[rLdt)|eU.}Cm'|eZ@e۵لi'?NhY13;WB|߲Vf%l'ar;m'cˍ;#-4 P  dn r4Xh6 )l̋@Z1y 4焃>Nv:pDLӉ0:N|9$ηs@N8ONO]Nn;ԘƋ3gONi98%^G1}BN  ^ 'x:Wv̿?ÿI>)bߒoK>!j&r]o/'WZ%q -7efx9o%FC9{{n{.r(%ƑBDR pgMe>]JdqDPKTlUA@@L&@K֒` w6׬28wFO*WVfKą BdEw֗@+dҷ8$Ye5d 2,1흗 * A!z+#rC~0_Uc?c i2ʹrU/"!cQS?X_q`}>p|r Y:#0-~ N"mu)x)}"-AiUgPy4w3aZ|B&{ӊ0S5{|MEIrMa dOS 417\ݜ?T~LFg@ 'ӈ6ix,/E>x,W$G/<ƗxW

{U8耗+ ~U>Kr8sU΋_rѧX㱃вNX/0[g6l1kO`;%ZzV|ZvwJ ^St;HGR:r Ipǣ m ig>+O+}VF~\!㊭㉛+|oy{^!WH{yv⼂ok?{bqSgs|m% ļU1oК'qD9֞0o {1O }`i0oxޮ<N;1O{<[a޵żι?yex9]W搃=ʴ I | 911~' ƃ/C Éh<(@AHtHi{p0/KAuVdD h<>A4NjTS4-DB&C@N4NzpBgn4&4׃&2҈EjLcr _ }Qh<(xznkdkh&6h&̟23h Yi2w4fxqNi:74G/kQ`ЌNC>"Hc*9ͩx4ӤwN*:ͪx4ӴN*;ͫx4ĊN#k>pYКO|4#5_9 g/:]MyV:xTeXҴ笶75G6f^]f*&կULl3ǭ'5wF8xå.[ܾK P/8`={wf+ǕǕvJ{Jq=qU#qy-iT]LKUXN'KUXRuUzlJU-Ki,eRiSr,UTRuZt̏m7ϛRuc:/RuWKAP4CRucLRuU_ҦT]]TX192}k} 3{X)13{Z)2*Rf6_VJ|[4+fb̟j3Rn)U4ƋxRtVNqKc|C? xxQr)}>?>>>?_?5_j>1|co6سKJ,TQ\RuiWml:&:ƙ?NHD[aMwz;Gt~FGF푍ULIrFC 8`{Fw-FWڽt{i]i)6PFwx▍.*wFW{j]wkݟOmt FsmtdNҍUe6k:Xr$=zVP%z4"ŋAO9WU }-檲;I=mwГz'L#=y VM%^Г{AOz=nO־]Yл *i|Bxòt]\ 1Rendstream endobj 17 0 obj << /Type /Page /Parent 3 0 R /Contents 18 0 R /Resources 4 0 R >> endobj 18 0 obj << /Length 2887 /Filter /FlateDecode >> stream xZMϯ pM@r`Zh YUѬvAc=ZayO?xumŏe_NU;q:.Wym:k?ӾgrZc_%Oőcu@YG$(\|@|ދ'ู|c]>x~%cwwζzM_/RO\1mm\K=R|O?o?W?3_#|i> Z-?---[f4/_a4 ,5+CZYAսpH}QT?P&:oevoe.\ e<#N4Њ/|h՚oÿ#cgVn.Asy[w #?G=Eh {F=Qs繿Ի=_0O{#O+|g>_ZO-·cks/{?9,?弰[9>伲9:Ͼ x׻oؕ(V/9^ԭygzmz+7@G&uU }WXPu)pSU^_oY~^|@'~ӖN4k!K;̗ ϛ/[B~~ɫv>y5 8\,>yy B,I2~sQBsyeY|Z{: }KYsd9+ ȅҌǍ:)/){4qF sy֋EV :2Oƕd|2G}:COgLJ~:c߱6Ih:d'e?]~&3Om߃?>@D'Oܻx޹~㯳#ǧh|D?dGCNcqhs4>i|XNԯP0nN!zvzx7QCR!1N#4>J?ĘFŸ:^= Nqhh.F_nM#04:ʥۧ\5>ǻas}5{>r68Ɓ5 {4>jo}_4>jk|pۜ8;Z^i|Ԏ5`O XQ X3NcܜƗ!k-Li|i#pe)UTơFj,`_Ѩ?UQƣP HS5$jLAiFj\`g4Ucz0 N4:'Lz^Qsw{'|aHT>2_̿wCO+|k>>S _9O4HC+K4>q9ege5>Ntgh|̤H` 4T> *kTs t۩?Yw'&^^Bue|qy_B\+w^{g@wy2@ǀe\P'ʸ1Lp 3ud@ 3&m3Ā)wM,g2>u d@Yo|z=.w(‚X=7 endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R 9 0 R 11 0 R 13 0 R 15 0 R 17 0 R ] /Count 6 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 19 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 20 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 19 0 R >> endobj xref 0 21 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000025248 00000 n 0000025365 00000 n 0000025477 00000 n 0000025510 00000 n 0000000212 00000 n 0000000292 00000 n 0000000728 00000 n 0000000809 00000 n 0000004587 00000 n 0000004669 00000 n 0000009856 00000 n 0000009938 00000 n 0000016048 00000 n 0000016130 00000 n 0000022206 00000 n 0000022288 00000 n 0000028205 00000 n 0000028463 00000 n trailer << /Size 21 /Info 1 0 R /Root 2 0 R >> startxref 28561 %%EOF partykit/tests/regtest-MIA.Rout.save0000644000176200001440000001536514172230001017154 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > set.seed(29) > > n <- 100 > x <- 1:n/n > y <- rnorm(n, mean = (x < .5) + 1) > xna <- x > xna[xna < .2] <- NA > d <- data.frame(x = x, y = y) > dna <- data.frame(x = xna, y = y) > > (t1 <- ctree(y ~ x, data = d)) Model formula: y ~ x Fitted party: [1] root | [2] x <= 0.5: 1.998 (n = 50, err = 52.5) | [3] x > 0.5: 0.743 (n = 50, err = 45.6) Number of inner nodes: 1 Number of terminal nodes: 2 > (t2 <- ctree(y ~ x, data = dna)) Model formula: y ~ x Fitted party: [1] root | [2] x <= 0.5: 2.070 (n = 37, err = 40.2) | [3] x > 0.5: 0.960 (n = 63, err = 68.5) Number of inner nodes: 1 Number of terminal nodes: 2 > (t3 <- ctree(y ~ x, data = dna, control = ctree_control(MIA = TRUE))) Model formula: y ~ x Fitted party: [1] root | [2] x <= 0.5: 1.998 (n = 50, err = 52.5) | [3] x > 0.5: 0.743 (n = 50, err = 45.6) Number of inner nodes: 1 Number of terminal nodes: 2 > > predict(t1, type = "node")[is.na(xna)] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 > predict(t2, type = "node")[is.na(xna)] 3 3 3 2 3 2 2 3 3 2 3 3 3 2 3 3 3 3 2 3 3 3 2 3 2 2 3 3 2 3 3 3 2 3 3 3 3 2 > predict(t3, type = "node")[is.na(xna)] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 > > xna <- x > xna[xna > .8] <- NA > d <- data.frame(x = x, y = y) > dna <- data.frame(x = xna, y = y) > > (t1 <- ctree(y ~ x, data = d)) Model formula: y ~ x Fitted party: [1] root | [2] x <= 0.5: 1.998 (n = 50, err = 52.5) | [3] x > 0.5: 0.743 (n = 50, err = 45.6) Number of inner nodes: 1 Number of terminal nodes: 2 > (t2 <- ctree(y ~ x, data = dna)) Model formula: y ~ x Fitted party: [1] root | [2] x <= 0.5: 1.864 (n = 61, err = 65.5) | [3] x > 0.5 | | [4] x <= 0.73: 0.755 (n = 29, err = 18.9) | | [5] x > 0.73: 0.150 (n = 10, err = 12.4) Number of inner nodes: 2 Number of terminal nodes: 3 > (t3 <- ctree(y ~ x, data = dna, control = ctree_control(MIA = TRUE))) Model formula: y ~ x Fitted party: [1] root | [2] x <= 0.5: 1.998 (n = 50, err = 52.5) | [3] x > 0.5 | | [4] x <= 0.73: 0.928 (n = 43, err = 31.9) | | [5] x > 0.73: -0.396 (n = 7, err = 3.1) Number of inner nodes: 2 Number of terminal nodes: 3 > > (n1 <- predict(t1, type = "node")) 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 > (n2 <- predict(t2, type = "node")) 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 4 2 2 5 4 4 4 2 2 5 4 2 4 2 2 2 5 2 2 2 4 2 2 5 4 4 4 2 2 5 4 2 4 2 2 2 5 2 2 2 > (n3 <- predict(t3, type = "node")) 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 > table(n1, n2) n2 n1 2 4 5 2 50 0 0 3 11 29 10 > table(n1, n3) n3 n1 2 4 5 2 50 0 0 3 0 43 7 > > d$x <- as.factor(cut(d$x, breaks = 0:5 / 5)) > dna$x <- as.factor(cut(dna$x, breaks = 0:5 / 5)) > > (t1 <- ctree(y ~ x, data = d)) Model formula: y ~ x Fitted party: [1] root | [2] x in (0,0.2], (0.2,0.4], (0.4,0.6]: 1.808 (n = 60, err = 68.1) | [3] x in (0.6,0.8], (0.8,1]: 0.714 (n = 40, err = 40.6) Number of inner nodes: 1 Number of terminal nodes: 2 > (t2 <- ctree(y ~ x, data = dna)) Model formula: y ~ x Fitted party: [1] root | [2] x in (0,0.2], (0.2,0.4], (0.4,0.6]: 1.651 (n = 75, err = 89.0) | [3] x in (0.6,0.8]: 0.529 (n = 25, err = 24.8) Number of inner nodes: 1 Number of terminal nodes: 2 > (t3 <- ctree(y ~ x, data = dna, control = ctree_control(MIA = TRUE))) Model formula: y ~ x Fitted party: [1] root | [2] x in (0.6,0.8]: 0.714 (n = 40, err = 40.6) | [3] x in (0,0.2], (0.2,0.4], (0.4,0.6]: 1.808 (n = 60, err = 68.1) Number of inner nodes: 1 Number of terminal nodes: 2 > > (n1 <- predict(t1, type = "node")) 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 > (n2 <- predict(t2, type = "node")) 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 3 2 2 3 2 2 2 2 3 2 2 2 2 3 3 2 2 2 2 2 3 2 2 3 2 2 2 2 3 2 2 2 2 3 > (n3 <- predict(t3, type = "node")) 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 > table(n1, n2) n2 n1 2 3 2 60 0 3 15 25 > table(n1, n3) n3 n1 2 3 2 0 60 3 40 0 > > proc.time() user system elapsed 1.267 0.068 1.320 partykit/tests/regtest-ctree.Rout.save0000644000176200001440000000551314172230000017641 0ustar liggesusers R version 4.0.3 (2020-10-10) -- "Bunny-Wunnies Freak Out" Copyright (C) 2020 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > ## package > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > > ## iris data > data("iris", package = "datasets") > irisct <- ctree(Species ~ ., data = iris) > print(irisct) Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [1] root | [2] Petal.Length <= 1.9: setosa (n = 50, err = 0.0%) | [3] Petal.Length > 1.9 | | [4] Petal.Width <= 1.7 | | | [5] Petal.Length <= 4.8: versicolor (n = 46, err = 2.2%) | | | [6] Petal.Length > 4.8: versicolor (n = 8, err = 50.0%) | | [7] Petal.Width > 1.7: virginica (n = 46, err = 2.2%) Number of inner nodes: 3 Number of terminal nodes: 4 > table(fit = predict(irisct), true = iris$Species) true fit setosa versicolor virginica setosa 50 0 0 versicolor 0 49 5 virginica 0 1 45 > > ## airquality data > data("airquality", package = "datasets") > airq <- subset(airquality, !is.na(Ozone)) > airqct <- ctree(Ozone ~ ., data = airq) > print(airqct) Model formula: Ozone ~ Solar.R + Wind + Temp + Month + Day Fitted party: [1] root | [2] Temp <= 82 | | [3] Wind <= 6.9: 55.600 (n = 10, err = 21946.4) | | [4] Wind > 6.9 | | | [5] Temp <= 77: 18.479 (n = 48, err = 3956.0) | | | [6] Temp > 77: 31.143 (n = 21, err = 4620.6) | [7] Temp > 82 | | [8] Wind <= 10.3: 81.633 (n = 30, err = 15119.0) | | [9] Wind > 10.3: 48.714 (n = 7, err = 1183.4) Number of inner nodes: 4 Number of terminal nodes: 5 > sum((airq$Ozone - predict(airqct))^2) [1] 46825.35 > > ### split in one variable only: Temp is selected freely in the root node > ### but none of the other variables is allowed deeper in the tree > airqct1 <- ctree(Ozone ~ ., data = airq, + control = ctree_control(maxvar = 1L)) > psplitids <- unique(do.call("c", + nodeapply(node_party(airqct1), + ids = nodeids(node_party(airqct1)), + FUN = function(x) split_node(x)$varid))) > stopifnot(length(psplitids) == 1L) > > proc.time() user system elapsed 0.987 0.037 1.013 partykit/tests/regtest-MIA.R0000644000176200001440000000226114172230001015456 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") set.seed(29) n <- 100 x <- 1:n/n y <- rnorm(n, mean = (x < .5) + 1) xna <- x xna[xna < .2] <- NA d <- data.frame(x = x, y = y) dna <- data.frame(x = xna, y = y) (t1 <- ctree(y ~ x, data = d)) (t2 <- ctree(y ~ x, data = dna)) (t3 <- ctree(y ~ x, data = dna, control = ctree_control(MIA = TRUE))) predict(t1, type = "node")[is.na(xna)] predict(t2, type = "node")[is.na(xna)] predict(t3, type = "node")[is.na(xna)] xna <- x xna[xna > .8] <- NA d <- data.frame(x = x, y = y) dna <- data.frame(x = xna, y = y) (t1 <- ctree(y ~ x, data = d)) (t2 <- ctree(y ~ x, data = dna)) (t3 <- ctree(y ~ x, data = dna, control = ctree_control(MIA = TRUE))) (n1 <- predict(t1, type = "node")) (n2 <- predict(t2, type = "node")) (n3 <- predict(t3, type = "node")) table(n1, n2) table(n1, n3) d$x <- as.factor(cut(d$x, breaks = 0:5 / 5)) dna$x <- as.factor(cut(dna$x, breaks = 0:5 / 5)) (t1 <- ctree(y ~ x, data = d)) (t2 <- ctree(y ~ x, data = dna)) (t3 <- ctree(y ~ x, data = dna, control = ctree_control(MIA = TRUE))) (n1 <- predict(t1, type = "node")) (n2 <- predict(t2, type = "node")) (n3 <- predict(t3, type = "node")) table(n1, n2) table(n1, n3) partykit/tests/regtest-cforest.Rout.save0000644000176200001440000002270514172230001020207 0ustar liggesusers R version 3.5.2 (2018-12-20) -- "Eggshell Igloo" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > suppressWarnings(RNGversion("3.5.2")) > > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > stopifnot(require("party")) Loading required package: party Loading required package: modeltools Loading required package: stats4 Loading required package: strucchange Loading required package: zoo Attaching package: 'zoo' The following objects are masked from 'package:base': as.Date, as.Date.numeric Loading required package: sandwich Attaching package: 'party' The following objects are masked from 'package:partykit': cforest, ctree, ctree_control, edge_simple, mob, mob_control, node_barplot, node_bivplot, node_boxplot, node_inner, node_surv, node_terminal, varimp > set.seed(29) > > ### regression > airq <- airquality[complete.cases(airquality),] > > mtry <- ncol(airq) - 1L > ntree <- 25 > > cf_partykit <- partykit::cforest(Ozone ~ ., data = airq, + ntree = ntree, mtry = mtry) > > w <- do.call("cbind", cf_partykit$weights) > > cf_party <- party::cforest(Ozone ~ ., data = airq, + control = party::cforest_unbiased(ntree = ntree, mtry = mtry), + weights = w) > > p_partykit <- predict(cf_partykit) > p_party <- predict(cf_party) > > stopifnot(max(abs(p_partykit - p_party)) < sqrt(.Machine$double.eps)) > > prettytree(cf_party@ensemble[[1]], inames = names(airq)[-1]) 1) Wind <= 5.7; criterion = 1, statistic = 30.75 2)* weights = 0 1) Wind > 5.7 3) Temp <= 84; criterion = 1, statistic = 30.238 4) Temp <= 77; criterion = 0.999, statistic = 10.471 5) Wind <= 9.2; criterion = 0.895, statistic = 2.632 6)* weights = 0 5) Wind > 9.2 7) Solar.R <= 112; criterion = 0.907, statistic = 2.823 8)* weights = 0 7) Solar.R > 112 9)* weights = 0 4) Temp > 77 10) Day <= 13; criterion = 0.981, statistic = 5.479 11)* weights = 0 10) Day > 13 12)* weights = 0 3) Temp > 84 13)* weights = 0 > party(cf_partykit$nodes[[1]], data = model.frame(cf_partykit)) [1] root | [2] Wind <= 5.7: * | [3] Wind > 5.7 | | [4] Temp <= 84 | | | [5] Temp <= 77 | | | | [6] Wind <= 9.2: * | | | | [7] Wind > 9.2 | | | | | [8] Solar.R <= 112: * | | | | | [9] Solar.R > 112: * | | | [10] Temp > 77 | | | | [11] Day <= 13: * | | | | [12] Day > 13: * | | [13] Temp > 84: * > > v_party <- do.call("rbind", lapply(1:5, function(i) party::varimp(cf_party))) > > v_partykit <- do.call("rbind", lapply(1:5, function(i) partykit::varimp(cf_partykit))) > > summary(v_party) Solar.R Wind Temp Month Min. :22.87 Min. :146.3 Min. :760.9 Min. :0.5159 1st Qu.:25.06 1st Qu.:152.8 1st Qu.:784.3 1st Qu.:0.5236 Median :26.11 Median :176.0 Median :806.2 Median :0.6119 Mean :26.90 Mean :171.9 Mean :813.8 Mean :0.7391 3rd Qu.:26.26 3rd Qu.:189.3 3rd Qu.:841.5 3rd Qu.:0.9886 Max. :34.18 Max. :195.1 Max. :875.9 Max. :1.0556 Day Min. :2.051 1st Qu.:2.512 Median :2.689 Mean :3.409 3rd Qu.:3.487 Max. :6.304 > summary(v_partykit) Solar.R Wind Temp Month Min. :23.35 Min. :161.7 Min. :760.8 Min. :-2.446 1st Qu.:24.81 1st Qu.:190.1 1st Qu.:763.4 1st Qu.: 2.983 Median :26.93 Median :199.4 Median :768.7 Median : 3.440 Mean :29.65 Mean :195.5 Mean :777.1 Mean : 2.662 3rd Qu.:31.46 3rd Qu.:205.0 3rd Qu.:769.2 3rd Qu.: 4.575 Max. :41.69 Max. :221.5 Max. :823.4 Max. : 4.757 Day Min. :-1.1396 1st Qu.:-0.4362 Median :24.3535 Mean :17.7578 3rd Qu.:31.8914 Max. :34.1200 > > party::varimp(cf_party, conditional = TRUE) Solar.R Wind Temp Month Day 16.7190604 100.7812597 534.9587763 -0.2538655 4.4848324 > partykit::varimp(cf_partykit, conditional = TRUE) Solar.R Wind Temp Month Day 27.520179 144.897612 476.407961 0.308407 -0.655686 > > > ### classification > set.seed(29) > mtry <- ncol(iris) - 1L > ntree <- 25 > > cf_partykit <- partykit::cforest(Species ~ ., data = iris, + ntree = ntree, mtry = mtry) > > w <- do.call("cbind", cf_partykit$weights) > > cf_party <- party::cforest(Species ~ ., data = iris, + control = party::cforest_unbiased(ntree = ntree, mtry = mtry), + weights = w) > > p_partykit <- predict(cf_partykit, type = "prob") > p_party <- do.call("rbind", treeresponse(cf_party)) > > stopifnot(max(abs(unclass(p_partykit) - unclass(p_party))) < sqrt(.Machine$double.eps)) > > prettytree(cf_party@ensemble[[1]], inames = names(iris)[-5]) 1) Petal.Length <= 1.9; criterion = 1, statistic = 86.933 2)* weights = 0 1) Petal.Length > 1.9 3) Petal.Width <= 1.6; criterion = 1, statistic = 42.075 4) Sepal.Width <= 2.5; criterion = 0.931, statistic = 3.316 5)* weights = 0 4) Sepal.Width > 2.5 6)* weights = 0 3) Petal.Width > 1.6 7) Petal.Length <= 5.1; criterion = 0.774, statistic = 1.466 8)* weights = 0 7) Petal.Length > 5.1 9)* weights = 0 > party(cf_partykit$nodes[[1]], data = model.frame(cf_partykit)) [1] root | [2] Petal.Length <= 1.9: * | [3] Petal.Length > 1.9 | | [4] Petal.Width <= 1.6 | | | [5] Sepal.Width <= 2.5: * | | | [6] Sepal.Width > 2.5: * | | [7] Petal.Width > 1.6 | | | [8] Petal.Length <= 5.1: * | | | [9] Petal.Length > 5.1: * > > v_party <- do.call("rbind", lapply(1:5, function(i) party::varimp(cf_party))) > > v_partykit <- do.call("rbind", lapply(1:5, function(i) + partykit::varimp(cf_partykit, risk = "mis"))) > > summary(v_party) Sepal.Length Sepal.Width Petal.Length Petal.Width Min. :0 Min. :0 Min. :0.3786 Min. :0.3014 1st Qu.:0 1st Qu.:0 1st Qu.:0.3807 1st Qu.:0.3029 Median :0 Median :0 Median :0.4000 Median :0.3050 Mean :0 Mean :0 Mean :0.3941 Mean :0.3111 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0.4036 3rd Qu.:0.3121 Max. :0 Max. :0 Max. :0.4079 Max. :0.3343 > summary(v_partykit) Sepal.Width Petal.Length Petal.Width Min. :0 Min. :0.3869 Min. :0.2971 1st Qu.:0 1st Qu.:0.3921 1st Qu.:0.3036 Median :0 Median :0.3966 Median :0.3057 Mean :0 Mean :0.3952 Mean :0.3117 3rd Qu.:0 3rd Qu.:0.4003 3rd Qu.:0.3179 Max. :0 Max. :0.4003 Max. :0.3343 > > party::varimp(cf_party, conditional = TRUE) Sepal.Length Sepal.Width Petal.Length Petal.Width 0.0000000 0.0000000 0.2778571 0.1014286 > partykit::varimp(cf_partykit, risk = "misclass", conditional = TRUE) Sepal.Width Petal.Length Petal.Width 0.0000000 0.2782738 0.1171429 > > ### mean aggregation > set.seed(29) > > ### fit forest > cf <- partykit::cforest(dist ~ speed, data = cars, ntree = 100) > > ### prediction; scale = TRUE introduced in 1.2-1 > pr <- predict(cf, newdata = cars[1,,drop = FALSE], type = "response", scale = TRUE) > ### this is equivalent to > w <- predict(cf, newdata = cars[1,,drop = FALSE], type = "weights") > stopifnot(isTRUE(all.equal(pr, sum(w * cars$dist) / sum(w), + check.attributes = FALSE))) > > ### check if this is the same as mean aggregation > > ### compute terminal node IDs for first obs > nd1 <- predict(cf, newdata = cars[1,,drop = FALSE], type = "node") > ### compute terminal nide IDs for all obs > nd <- predict(cf, newdata = cars, type = "node") > ### random forests weighs > lw <- cf$weights > > ### compute mean predictions for each tree > ### and extract mean for terminal node containing > ### first observation > np <- vector(mode = "list", length = length(lw)) > m <- numeric(length(lw)) > > for (i in 1:length(lw)) { + np[[i]] <- tapply(lw[[i]] * cars$dist, nd[[i]], sum) / + tapply(lw[[i]], nd[[i]], sum) + m[i] <- np[[i]][as.character(nd1[i])] + } > > stopifnot(isTRUE(all.equal(mean(m), sum(w * cars$dist) / sum(w)))) > > ### check parallel variable importance (make this reproducible) > if(.Platform$OS.type == "unix") { + RNGkind("L'Ecuyer-CMRG") + v1 <- partykit::varimp(cf_partykit, risk = "misclass", conditional = TRUE, cores = 2) + v2 <- partykit::varimp(cf_partykit, risk = "misclass", conditional = TRUE, cores = 2) + stopifnot(all.equal(v1, v2)) + } > > ### check weights argument > cf_partykit <- partykit::cforest(Species ~ ., data = iris, + ntree = ntree, mtry = 4) > w <- do.call("cbind", cf_partykit$weights) > cf_2 <- partykit::cforest(Species ~ ., data = iris, + ntree = ntree, mtry = 4, weights = w) > stopifnot(max(abs(predict(cf_2, type = "prob") - + predict(cf_partykit, type = "prob"))) < sqrt(.Machine$double.eps)) > > > proc.time() user system elapsed 5.245 0.192 5.095 partykit/tests/regtest-nmax.R0000644000176200001440000000203314172230001016010 0ustar liggesuserssuppressWarnings(RNGversion("3.5.2")) library("partykit") set.seed(29) n <- 1000 z <- runif(n) y <- rnorm(n, mean = c(-1, 1)[(z > 0.5) + 1], sd = 3) d <- data.frame(y = y, y2 = factor(y > median(y)), z = z) c1 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = Inf, alpha = .5)) c2 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = 25, alpha = .5)) c3 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = nrow(d), alpha = .5)) c4 <- ctree(y2 ~ z, data = d, control = ctree_control(nmax = 100, alpha = .5)) all.equal(predict(c1, type = "node"), predict(c3, type = "node")) p1 <- predict(c1, type = "prob") p2 <- predict(c2, type = "prob") p3 <- predict(c3, type = "prob") p4 <- predict(c4, type = "prob") ### binomial log-lik sum(log(p1[cbind(1:nrow(d), unclass(d$y2))])) sum(log(p2[cbind(1:nrow(d), unclass(d$y2))])) sum(log(p3[cbind(1:nrow(d), unclass(d$y2))])) sum(log(p4[cbind(1:nrow(d), unclass(d$y2))])) c1 <- ctree(y ~ z, data = d, control = ctree_control(nmax = c("yx" = Inf, "z" = 25), alpha = .5)) partykit/src/0000755000176200001440000000000014415225047012714 5ustar liggesuserspartykit/src/partykit-init.c0000644000176200001440000000103214172227777015700 0ustar liggesusers #include #include #include "rfweights.h" #define CALLDEF(name, n) {#name, (DL_FUNC) &name, n} #define REGCALL(name) R_RegisterCCallable("partykit", #name, (DL_FUNC) &name) static const R_CallMethodDef callMethods[] = { CALLDEF(R_rfweights, 4), {NULL, NULL, 0} }; void attribute_visible R_init_partykit ( DllInfo *dll ) { R_registerRoutines(dll, NULL, callMethods, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); REGCALL(R_rfweights); } partykit/src/partykit-win.def0000644000176200001440000000006014172227777016046 0ustar liggesusers LIBRARY partykit.dll EXPORTS R_init_partykit partykit/src/rfweights.h0000644000176200001440000000021014172227777015074 0ustar liggesusers #include #include #include SEXP R_rfweights (SEXP fdata, SEXP fnewdata, SEXP weights, SEXP scale); partykit/src/rfweights.c0000644000176200001440000000620014172227777015074 0ustar liggesusers #include "rfweights.h" SEXP R_rfweights (SEXP fdata, SEXP fnewdata, SEXP weights, SEXP scale) { SEXP ans; double *dans; int *id, *ind, *iweights, *tnsize; int Ntree = LENGTH(fdata), Ndata, Nnewdata; int OOB = LENGTH(fnewdata) == 0; if (TYPEOF(fdata) != VECSXP) error("fdata is not a list"); if (LENGTH(fdata) == 0) return(R_NilValue); if (TYPEOF(weights) != VECSXP) error("weights is not a list"); if (TYPEOF(scale) != LGLSXP || LENGTH(scale) != 1) error("scale is not a scalar logical"); if (LENGTH(weights) == 0) return(R_NilValue); Ndata = LENGTH(VECTOR_ELT(fdata, 0)); if (OOB) { Nnewdata = Ndata; fnewdata = fdata; } else { if (LENGTH(fnewdata) == 0) return(R_NilValue); if (TYPEOF(fnewdata) != VECSXP) error("fnewdata is not a list"); Nnewdata = LENGTH(VECTOR_ELT(fnewdata, 0)); } PROTECT(ans = allocMatrix(REALSXP, Ndata, Nnewdata)); dans = REAL(ans); for (int i = 0; i < Ndata * Nnewdata; i++) dans[i] = 0.0; /* sum of weights for each terminal node id because trees can be very large (terminal node size = 1) we only once allocate Ndata integers */ tnsize = Calloc(Ndata, int); for (int i = 0; i < Ndata; i++) tnsize[i] = 1; for (int b = 0; b < Ntree; b++) { if (TYPEOF(VECTOR_ELT(weights, b)) != INTSXP) error("some elements of weights are not integer"); if (LENGTH(VECTOR_ELT(weights, b)) != Ndata) error("some elements of weights have incorrect length"); if (TYPEOF(VECTOR_ELT(fnewdata, b)) != INTSXP) error("some elements of fnewdata are not integer"); if (LENGTH(VECTOR_ELT(fnewdata, b)) != Nnewdata) error("some elements of fnewdata have incorrect length"); if (TYPEOF(VECTOR_ELT(fdata, b)) != INTSXP) error("some elements of fdata are not integer"); if (LENGTH(VECTOR_ELT(fdata, b)) != Ndata) error("some elements of fdata have incorrect length"); iweights = INTEGER(VECTOR_ELT(weights, b)); ind = INTEGER(VECTOR_ELT(fnewdata, b)); id = INTEGER(VECTOR_ELT(fdata, b)); if (LOGICAL(scale)[0]) { /* reset to zero */ for (int i = 0; i < Ndata; i++) tnsize[i] = 0; /* sum of weights in each terminal node id */ for (int i = 0; i < Ndata; i++) tnsize[id[i] - 1] += iweights[i]; } /* else: tnsize == 1 */ for (int j = 0; j < Nnewdata; j++) { if (OOB & (iweights[j] > 0)) continue; for (int i = 0; i < Ndata; i++) { /* checking tnsize[id[i] - 1] > 0 is a precaution because partykit::cforest prunes-off empty terminal nodes in honest trees */ if (id[i] == ind[j] && tnsize[id[i] - 1] > 0) dans[j * Ndata + i] += (double) iweights[i] / tnsize[id[i] - 1]; } } } Free(tnsize); UNPROTECT(1); return(ans); } partykit/vignettes/0000755000176200001440000000000014415225047014135 5ustar liggesuserspartykit/vignettes/ctree.Rout.save0000644000176200001440000007355514415224553017067 0ustar liggesusers > suppressWarnings(RNGversion("3.5.2")) > options(width = 70, SweaveHooks = list(leftpar = function() par(mai = par("mai") * + c(1, 1.1, 1, 1)))) > require("partykit") Loading required package: partykit Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > require("coin") Loading required package: coin Loading required package: survival > require("strucchange") Loading required package: strucchange Loading required package: zoo Attaching package: ‘zoo’ The following objects are masked from ‘package:base’: as.Date, as.Date.numeric Loading required package: sandwich > require("coin") > require("Formula") Loading required package: Formula > require("survival") > require("sandwich") > set.seed(290875) > ctree_control(teststat = "max") $criterion [1] "p.value" $logmincriterion [1] -0.05129329 $minsplit [1] 20 $minbucket [1] 7 $minprob [1] 0.01 $maxvar [1] Inf $stump [1] FALSE $nmax yx z Inf Inf $lookahead [1] FALSE $mtry [1] Inf $maxdepth [1] Inf $multiway [1] FALSE $splittry [1] 2 $maxsurrogate [1] 0 $numsurrogate [1] FALSE $majority [1] FALSE $caseweights [1] TRUE $applyfun function (X, FUN, ...) { FUN <- match.fun(FUN) if (!is.vector(X) || is.object(X)) X <- as.list(X) .Internal(lapply(X, FUN)) } $saveinfo [1] TRUE $bonferroni [1] TRUE $update NULL $selectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $splitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svselectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svsplitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $teststat [1] "maximum" $splitstat [1] "quadratic" $splittest [1] FALSE $pargs $maxpts [1] 25000 $abseps [1] 0.001 $releps [1] 0 attr(,"class") [1] "GenzBretz" $testtype [1] "Bonferroni" $nresample [1] 9999 $tol [1] 1.490116e-08 $intersplit [1] FALSE $MIA [1] FALSE > ctree_control(teststat = "quad") $criterion [1] "p.value" $logmincriterion [1] -0.05129329 $minsplit [1] 20 $minbucket [1] 7 $minprob [1] 0.01 $maxvar [1] Inf $stump [1] FALSE $nmax yx z Inf Inf $lookahead [1] FALSE $mtry [1] Inf $maxdepth [1] Inf $multiway [1] FALSE $splittry [1] 2 $maxsurrogate [1] 0 $numsurrogate [1] FALSE $majority [1] FALSE $caseweights [1] TRUE $applyfun function (X, FUN, ...) { FUN <- match.fun(FUN) if (!is.vector(X) || is.object(X)) X <- as.list(X) .Internal(lapply(X, FUN)) } $saveinfo [1] TRUE $bonferroni [1] TRUE $update NULL $selectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $splitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svselectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svsplitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $teststat [1] "quadratic" $splitstat [1] "quadratic" $splittest [1] FALSE $pargs $maxpts [1] 25000 $abseps [1] 0.001 $releps [1] 0 attr(,"class") [1] "GenzBretz" $testtype [1] "Bonferroni" $nresample [1] 9999 $tol [1] 1.490116e-08 $intersplit [1] FALSE $MIA [1] FALSE > ctree_control(testtype = "Bonferroni") $criterion [1] "p.value" $logmincriterion [1] -0.05129329 $minsplit [1] 20 $minbucket [1] 7 $minprob [1] 0.01 $maxvar [1] Inf $stump [1] FALSE $nmax yx z Inf Inf $lookahead [1] FALSE $mtry [1] Inf $maxdepth [1] Inf $multiway [1] FALSE $splittry [1] 2 $maxsurrogate [1] 0 $numsurrogate [1] FALSE $majority [1] FALSE $caseweights [1] TRUE $applyfun function (X, FUN, ...) { FUN <- match.fun(FUN) if (!is.vector(X) || is.object(X)) X <- as.list(X) .Internal(lapply(X, FUN)) } $saveinfo [1] TRUE $bonferroni [1] TRUE $update NULL $selectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $splitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svselectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svsplitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $teststat [1] "quadratic" $splitstat [1] "quadratic" $splittest [1] FALSE $pargs $maxpts [1] 25000 $abseps [1] 0.001 $releps [1] 0 attr(,"class") [1] "GenzBretz" $testtype [1] "Bonferroni" $nresample [1] 9999 $tol [1] 1.490116e-08 $intersplit [1] FALSE $MIA [1] FALSE > ctree_control(minsplit = 20) $criterion [1] "p.value" $logmincriterion [1] -0.05129329 $minsplit [1] 20 $minbucket [1] 7 $minprob [1] 0.01 $maxvar [1] Inf $stump [1] FALSE $nmax yx z Inf Inf $lookahead [1] FALSE $mtry [1] Inf $maxdepth [1] Inf $multiway [1] FALSE $splittry [1] 2 $maxsurrogate [1] 0 $numsurrogate [1] FALSE $majority [1] FALSE $caseweights [1] TRUE $applyfun function (X, FUN, ...) { FUN <- match.fun(FUN) if (!is.vector(X) || is.object(X)) X <- as.list(X) .Internal(lapply(X, FUN)) } $saveinfo [1] TRUE $bonferroni [1] TRUE $update NULL $selectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $splitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svselectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svsplitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $teststat [1] "quadratic" $splitstat [1] "quadratic" $splittest [1] FALSE $pargs $maxpts [1] 25000 $abseps [1] 0.001 $releps [1] 0 attr(,"class") [1] "GenzBretz" $testtype [1] "Bonferroni" $nresample [1] 9999 $tol [1] 1.490116e-08 $intersplit [1] FALSE $MIA [1] FALSE > ctree_control(maxsurrogate = 3) $criterion [1] "p.value" $logmincriterion [1] -0.05129329 $minsplit [1] 20 $minbucket [1] 7 $minprob [1] 0.01 $maxvar [1] Inf $stump [1] FALSE $nmax yx z Inf Inf $lookahead [1] FALSE $mtry [1] Inf $maxdepth [1] Inf $multiway [1] FALSE $splittry [1] 2 $maxsurrogate [1] 3 $numsurrogate [1] FALSE $majority [1] FALSE $caseweights [1] TRUE $applyfun function (X, FUN, ...) { FUN <- match.fun(FUN) if (!is.vector(X) || is.object(X)) X <- as.list(X) .Internal(lapply(X, FUN)) } $saveinfo [1] TRUE $bonferroni [1] TRUE $update NULL $selectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $splitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svselectfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $svsplitfun function (model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } $teststat [1] "quadratic" $splitstat [1] "quadratic" $splittest [1] FALSE $pargs $maxpts [1] 25000 $abseps [1] 0.001 $releps [1] 0 attr(,"class") [1] "GenzBretz" $testtype [1] "Bonferroni" $nresample [1] 9999 $tol [1] 1.490116e-08 $intersplit [1] FALSE $MIA [1] FALSE > ls <- data.frame(y = gl(3, 50, labels = c("A", "B", + "C")), x1 = rnorm(150) + rep(c(1, 0, 0), c(50, 50, 50)), + x2 = runif(150)) > library("partykit") > ctree(y ~ x1 + x2, data = ls) Model formula: y ~ x1 + x2 Fitted party: [1] root | [2] x1 <= 0.82552: C (n = 96, err = 57.3%) | [3] x1 > 0.82552: A (n = 54, err = 42.6%) Number of inner nodes: 1 Number of terminal nodes: 2 > ct <- ctree(y ~ x1 + x2, data = ls) > ct Model formula: y ~ x1 + x2 Fitted party: [1] root | [2] x1 <= 0.82552: C (n = 96, err = 57.3%) | [3] x1 > 0.82552: A (n = 54, err = 42.6%) Number of inner nodes: 1 Number of terminal nodes: 2 > plot(ct) > ct[1] Model formula: y ~ x1 + x2 Fitted party: [1] root | [2] x1 <= 0.82552: C (n = 96, err = 57.3%) | [3] x1 > 0.82552: A (n = 54, err = 42.6%) Number of inner nodes: 1 Number of terminal nodes: 2 > class(ct[1]) [1] "constparty" "party" > predict(ct, newdata = ls) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 A A A A C A C A C C A A C A A A A 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 C A C A A A C A A A C C A A C A A 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 C A A C C C A A C C C C A A A A A 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 A C C C C A C C A C C C C C C A A 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 A A A C C A C A C C C C C C C C C 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 C C C A C A C A C C C C C C C C A 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 C C C A C C A C C C C C C C A C C 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 C C C C C C C C C C C C C C C C C 137 138 139 140 141 142 143 144 145 146 147 148 149 150 C A C C C C A C C A C A C A Levels: A B C > predict(ct, newdata = ls[c(1, 51, 101), ], type = "prob") A B C 1 0.5740741 0.2592593 0.1666667 51 0.5740741 0.2592593 0.1666667 101 0.1979167 0.3750000 0.4270833 > predict(ct, newdata = ls[c(1, 51, 101), ], type = "node") 1 51 101 3 3 2 > library("strucchange") > sctest(ct) $`1` x1 x2 statistic 2.299131e+01 4.0971294 p.value 2.034833e-05 0.2412193 $`2` x1 x2 statistic 2.6647107 4.3628130 p.value 0.4580906 0.2130228 $`3` x1 x2 statistic 2.1170497 2.8275567 p.value 0.5735483 0.4272879 > data("treepipit", package = "coin") > tptree <- ctree(counts ~ ., data = treepipit) > plot(tptree, terminal_panel = node_barplot) > p <- info_node(node_party(tptree))$p.value > n <- table(predict(tptree, type = "node")) > data("GlaucomaM", package = "TH.data") > gtree <- ctree(Class ~ ., data = GlaucomaM) > sp <- split_node(node_party(gtree))$varID > plot(gtree) > plot(gtree, inner_panel = node_barplot, edge_panel = function(...) invisible(), + tnex = 1) > table(predict(gtree), GlaucomaM$Class) glaucoma normal glaucoma 74 5 normal 24 93 > prob <- predict(gtree, type = "prob")[, 1] + runif(nrow(GlaucomaM), + min = -0.01, max = 0.01) > splitvar <- character_split(split_node(node_party(gtree)), + data = data_party(gtree))$name > plot(GlaucomaM[[splitvar]], prob, pch = as.numeric(GlaucomaM$Class), + ylab = "Conditional Class Prob.", xlab = splitvar) > abline(v = split_node(node_party(gtree))$breaks, lty = 2) > legend(0.15, 0.7, pch = 1:2, legend = levels(GlaucomaM$Class), + bty = "n") > data("GBSG2", package = "TH.data") > library("survival") > (stree <- ctree(Surv(time, cens) ~ ., data = GBSG2)) Model formula: Surv(time, cens) ~ horTh + age + menostat + tsize + tgrade + pnodes + progrec + estrec Fitted party: [1] root | [2] pnodes <= 3 | | [3] horTh in no: 2093.000 (n = 248) | | [4] horTh in yes: Inf (n = 128) | [5] pnodes > 3 | | [6] progrec <= 20: 624.000 (n = 144) | | [7] progrec > 20: 1701.000 (n = 166) Number of inner nodes: 3 Number of terminal nodes: 4 > plot(stree) > pn <- predict(stree, newdata = GBSG2[1:2, ], type = "node") > n <- predict(stree, type = "node") > survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == + pn[1])) Call: survfit(formula = Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[1])) n events median 0.95LCL 0.95UCL [1,] 248 88 2093 1814 NA > survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == + pn[2])) Call: survfit(formula = Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[2])) n events median 0.95LCL 0.95UCL [1,] 166 77 1701 1174 2018 > data("mammoexp", package = "TH.data") > mtree <- ctree(ME ~ ., data = mammoexp) > plot(mtree) > data("HuntingSpiders", package = "partykit") > sptree <- ctree(arct.lute + pard.lugu + zora.spin + + pard.nigr + pard.pull + aulo.albi + troc.terr + alop.cune + + pard.mont + alop.acce .... [TRUNCATED] > plot(sptree, terminal_panel = node_barplot) > plot(sptree) > library("party") Loading required package: modeltools Loading required package: stats4 Attaching package: ‘party’ The following objects are masked from ‘package:partykit’: cforest, ctree, ctree_control, edge_simple, mob, mob_control, node_barplot, node_bivplot, node_boxplot, node_inner, node_surv, node_terminal, varimp > set.seed(290875) > data("airquality", package = "datasets") > airq <- subset(airquality, !is.na(Ozone)) > (airct_party <- party::ctree(Ozone ~ ., data = airq, + controls = party::ctree_control(maxsurrogate = 3))) Conditional inference tree with 5 terminal nodes Response: Ozone Inputs: Solar.R, Wind, Temp, Month, Day Number of observations: 116 1) Temp <= 82; criterion = 1, statistic = 56.086 2) Wind <= 6.9; criterion = 0.998, statistic = 12.969 3)* weights = 10 2) Wind > 6.9 4) Temp <= 77; criterion = 0.997, statistic = 11.599 5)* weights = 48 4) Temp > 77 6)* weights = 21 1) Temp > 82 7) Wind <= 10.3; criterion = 0.997, statistic = 11.712 8)* weights = 30 7) Wind > 10.3 9)* weights = 7 > mean((airq$Ozone - predict(airct_party))^2) [1] 403.6668 > (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, + control = partykit::ctree_control(maxsurrogate = 3, numsurrogate = TRUE))) Model formula: Ozone ~ Solar.R + Wind + Temp + Month + Day Fitted party: [1] root | [2] Temp <= 82 | | [3] Wind <= 6.9: 55.600 (n = 10, err = 21946.4) | | [4] Wind > 6.9 | | | [5] Temp <= 77: 18.479 (n = 48, err = 3956.0) | | | [6] Temp > 77: 31.143 (n = 21, err = 4620.6) | [7] Temp > 82 | | [8] Wind <= 10.3: 81.633 (n = 30, err = 15119.0) | | [9] Wind > 10.3: 48.714 (n = 7, err = 1183.4) Number of inner nodes: 4 Number of terminal nodes: 5 > mean((airq$Ozone - predict(airct_partykit))^2) [1] 403.6668 > table(predict(airct_party, type = "node"), predict(airct_partykit, + type = "node")) 3 5 6 8 9 3 10 0 0 0 0 5 0 48 0 0 0 6 0 0 21 0 0 8 0 0 0 30 0 9 0 0 0 0 7 > max(abs(predict(airct_party) - predict(airct_partykit))) [1] 0 > airct_party@tree$criterion $statistic Solar.R Wind Temp Month Day 13.34761286 41.61369618 56.08632426 3.11265955 0.02011554 $criterion Solar.R Wind Temp Month Day 9.987069e-01 1.000000e+00 1.000000e+00 6.674119e-01 1.824984e-05 $maxcriterion [1] 1 > info_node(node_party(airct_partykit)) $criterion Solar.R Wind Temp Month statistic 13.347612859 4.161370e+01 5.608632e+01 3.1126596 p.value 0.001293090 5.560572e-10 3.467894e-13 0.3325881 criterion -0.001293926 -5.560572e-10 -3.467894e-13 -0.4043478 Day statistic 0.02011554 p.value 0.99998175 criterion -10.91135399 $p.value Temp 3.467894e-13 $unweighted [1] TRUE $nobs [1] 116 > (irisct_party <- party::ctree(Species ~ ., data = iris)) Conditional inference tree with 4 terminal nodes Response: Species Inputs: Sepal.Length, Sepal.Width, Petal.Length, Petal.Width Number of observations: 150 1) Petal.Length <= 1.9; criterion = 1, statistic = 140.264 2)* weights = 50 1) Petal.Length > 1.9 3) Petal.Width <= 1.7; criterion = 1, statistic = 67.894 4) Petal.Length <= 4.8; criterion = 0.999, statistic = 13.865 5)* weights = 46 4) Petal.Length > 4.8 6)* weights = 8 3) Petal.Width > 1.7 7)* weights = 46 > (irisct_partykit <- partykit::ctree(Species ~ ., data = iris, + control = partykit::ctree_control(splitstat = "maximum"))) Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [1] root | [2] Petal.Length <= 1.9: setosa (n = 50, err = 0.0%) | [3] Petal.Length > 1.9 | | [4] Petal.Width <= 1.7 | | | [5] Petal.Length <= 4.8: versicolor (n = 46, err = 2.2%) | | | [6] Petal.Length > 4.8: versicolor (n = 8, err = 50.0%) | | [7] Petal.Width > 1.7: virginica (n = 46, err = 2.2%) Number of inner nodes: 3 Number of terminal nodes: 4 > table(predict(irisct_party, type = "node"), predict(irisct_partykit, + type = "node")) 2 5 6 7 2 50 0 0 0 5 0 46 0 0 6 0 0 8 0 7 0 0 0 46 > tr_party <- treeresponse(irisct_party, newdata = iris) > tr_partykit <- predict(irisct_partykit, type = "prob", + newdata = iris) > max(abs(do.call("rbind", tr_party) - tr_partykit)) [1] 0 > data("mammoexp", package = "TH.data") > (mammoct_party <- party::ctree(ME ~ ., data = mammoexp)) Conditional inference tree with 3 terminal nodes Response: ME Inputs: SYMPT, PB, HIST, BSE, DECT Number of observations: 412 1) SYMPT <= Agree; criterion = 1, statistic = 29.933 2)* weights = 113 1) SYMPT > Agree 3) PB <= 8; criterion = 0.988, statistic = 9.17 4)* weights = 208 3) PB > 8 5)* weights = 91 > tr_party <- treeresponse(mammoct_party, newdata = mammoexp) > (mammoct_partykit <- partykit::ctree(ME ~ ., data = mammoexp)) Model formula: ME ~ SYMPT + PB + HIST + BSE + DECT Fitted party: [1] root | [2] SYMPT <= Agree: Never (n = 113, err = 15.9%) | [3] SYMPT > Agree | | [4] PB <= 8: Never (n = 208, err = 60.1%) | | [5] PB > 8: Never (n = 91, err = 38.5%) Number of inner nodes: 2 Number of terminal nodes: 3 > tr_partykit <- predict(mammoct_partykit, newdata = mammoexp, + type = "prob") > max(abs(do.call("rbind", tr_party) - tr_partykit)) [1] 0 > data("GBSG2", package = "TH.data") > (GBSG2ct_party <- party::ctree(Surv(time, cens) ~ + ., data = GBSG2)) Conditional inference tree with 4 terminal nodes Response: Surv(time, cens) Inputs: horTh, age, menostat, tsize, tgrade, pnodes, progrec, estrec Number of observations: 686 1) pnodes <= 3; criterion = 1, statistic = 56.156 2) horTh == {yes}; criterion = 0.965, statistic = 8.113 3)* weights = 128 2) horTh == {no} 4)* weights = 248 1) pnodes > 3 5) progrec <= 20; criterion = 0.999, statistic = 14.941 6)* weights = 144 5) progrec > 20 7)* weights = 166 > (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ + ., data = GBSG2)) Model formula: Surv(time, cens) ~ horTh + age + menostat + tsize + tgrade + pnodes + progrec + estrec Fitted party: [1] root | [2] pnodes <= 3 | | [3] horTh in no: 2093.000 (n = 248) | | [4] horTh in yes: Inf (n = 128) | [5] pnodes > 3 | | [6] progrec <= 20: 624.000 (n = 144) | | [7] progrec > 20: 1701.000 (n = 166) Number of inner nodes: 3 Number of terminal nodes: 4 > tr_party <- treeresponse(GBSG2ct_party, newdata = GBSG2) > tr_partykit <- predict(GBSG2ct_partykit, newdata = GBSG2, + type = "prob") > all.equal(lapply(tr_party, function(x) unclass(x)[!(names(x) %in% + "call")]), lapply(tr_partykit, function(x) unclass(x)[!(names(x) %in% + .... [TRUNCATED] [1] TRUE > (airct_partykit_1 <- partykit::ctree(Ozone ~ ., data = airq, + control = partykit::ctree_control(maxsurrogate = 3, alpha = 0.001, + nu .... [TRUNCATED] Model formula: Ozone ~ Solar.R + Wind + Temp + Month + Day Fitted party: [1] root | [2] Temp <= 82: 26.544 (n = 79, err = 42531.6) | [3] Temp > 82: 75.405 (n = 37, err = 22452.9) Number of inner nodes: 1 Number of terminal nodes: 2 > depth(airct_partykit_1) [1] 1 > mean((airq$Ozone - predict(airct_partykit_1))^2) [1] 560.2113 > (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, + control = partykit::ctree_control(maxsurrogate = 3, splittest = TRUE, + t .... [TRUNCATED] Model formula: Ozone ~ Solar.R + Wind + Temp + Month + Day Fitted party: [1] root | [2] Temp <= 82 | | [3] Wind <= 6.9: 55.600 (n = 10, err = 21946.4) | | [4] Wind > 6.9 | | | [5] Temp <= 77 | | | | [6] Solar.R <= 78: 12.533 (n = 15, err = 723.7) | | | | [7] Solar.R > 78: 21.182 (n = 33, err = 2460.9) | | | [8] Temp > 77 | | | | [9] Solar.R <= 148: 20.000 (n = 7, err = 652.0) | | | | [10] Solar.R > 148: 36.714 (n = 14, err = 2664.9) | [11] Temp > 82 | | [12] Temp <= 87 | | | [13] Wind <= 8.6: 72.308 (n = 13, err = 8176.8) | | | [14] Wind > 8.6: 45.571 (n = 7, err = 617.7) | | [15] Temp > 87: 90.059 (n = 17, err = 3652.9) Number of inner nodes: 7 Number of terminal nodes: 8 > (irisct_partykit_1 <- partykit::ctree(Species ~ ., + data = iris, control = partykit::ctree_control(splitstat = "maximum", + nmax = 25 .... [TRUNCATED] Model formula: Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width Fitted party: [1] root | [2] Petal.Width <= 0.6: setosa (n = 50, err = 0.0%) | [3] Petal.Width > 0.6 | | [4] Petal.Width <= 1.7 | | | [5] Petal.Length <= 4.8: versicolor (n = 46, err = 2.2%) | | | [6] Petal.Length > 4.8: versicolor (n = 8, err = 50.0%) | | [7] Petal.Width > 1.7: virginica (n = 46, err = 2.2%) Number of inner nodes: 3 Number of terminal nodes: 4 > table(predict(irisct_partykit), predict(irisct_partykit_1)) setosa versicolor virginica setosa 50 0 0 versicolor 0 54 0 virginica 0 0 46 > GBSG2$tgrade <- factor(GBSG2$tgrade, ordered = FALSE) > (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ + tgrade, data = GBSG2, control = partykit::ctree_control(multiway = TRUE, + alpha .... [TRUNCATED] Model formula: Surv(time, cens) ~ tgrade Fitted party: [1] root | [2] tgrade in I: Inf (n = 81) | [3] tgrade in II: 1730.000 (n = 444) | [4] tgrade in III: 1337.000 (n = 161) Number of inner nodes: 1 Number of terminal nodes: 3 > airq$month <- factor(airq$Month) > (airct_partykit_3 <- partykit::ctree(Ozone ~ Solar.R + + Wind + Temp, data = airq, cluster = month, control = partykit::ctree_control(maxsurrog .... [TRUNCATED] Model formula: Ozone ~ Solar.R + Wind + Temp Fitted party: [1] root | [2] Temp <= 82 | | [3] Temp <= 76: 18.250 (n = 48, err = 4199.0) | | [4] Temp > 76 | | | [5] Wind <= 6.9: 71.857 (n = 7, err = 15510.9) | | | [6] Wind > 6.9 | | | | [7] Temp <= 81: 32.412 (n = 17, err = 4204.1) | | | | [8] Temp > 81: 23.857 (n = 7, err = 306.9) | [9] Temp > 82 | | [10] Wind <= 10.3: 81.633 (n = 30, err = 15119.0) | | [11] Wind > 10.3: 48.714 (n = 7, err = 1183.4) Number of inner nodes: 5 Number of terminal nodes: 6 > info_node(node_party(airct_partykit_3)) $criterion Solar.R Wind Temp statistic 14.4805065501 3.299881e+01 4.783766e+01 p.value 0.0004247923 2.766464e-08 1.389038e-11 criterion -0.0004248826 -2.766464e-08 -1.389038e-11 $p.value Temp 1.389038e-11 $unweighted [1] TRUE $nobs [1] 116 > mean((airq$Ozone - predict(airct_partykit_3))^2) [1] 349.3382 > h <- function(y, x, start = NULL, weights, offset, + estfun = TRUE, object = FALSE, ...) { + if (is.null(weights)) + weights <- re .... [TRUNCATED] > partykit::ctree(Surv(time, cens) ~ ., data = GBSG2, + ytrafo = h) Model formula: Surv(time, cens) ~ horTh + age + menostat + tsize + tgrade + pnodes + progrec + estrec Fitted party: [1] root | [2] pnodes <= 3 | | [3] horTh in no: 2093.000 (n = 248) | | [4] horTh in yes: Inf (n = 128) | [5] pnodes > 3 | | [6] progrec <= 20: 624.000 (n = 144) | | [7] progrec > 20: 1701.000 (n = 166) Number of inner nodes: 3 Number of terminal nodes: 4 > h <- function(y, x, start = NULL, weights = NULL, + offset = NULL, cluster = NULL, ...) glm(y ~ 0 + x, family = gaussian(), + start = star .... [TRUNCATED] > (airct_partykit_4 <- partykit::ctree(Ozone ~ Temp | + Solar.R + Wind, data = airq, cluster = month, ytrafo = h, + control = partykit::ctre .... [TRUNCATED] Model formula: Ozone ~ Temp + (Solar.R + Wind) Fitted party: [1] root | [2] Wind <= 5.7: 98.692 (n = 13, err = 11584.8) | [3] Wind > 5.7 | | [4] Wind <= 8 | | | [5] Wind <= 6.9: 55.286 (n = 14, err = 11330.9) | | | [6] Wind > 6.9: 50.824 (n = 17, err = 15400.5) | | [7] Wind > 8: 27.306 (n = 72, err = 25705.3) Number of inner nodes: 3 Number of terminal nodes: 4 > airq$node <- factor(predict(airct_partykit_4, type = "node")) > summary(m <- glm(Ozone ~ node + node:Temp - 1, data = airq)) Call: glm(formula = Ozone ~ node + node:Temp - 1, data = airq) Coefficients: Estimate Std. Error t value Pr(>|t|) node2 300.0527 93.4828 3.210 0.001750 ** node5 -217.3416 51.3970 -4.229 4.94e-05 *** node6 -178.9333 58.1093 -3.079 0.002632 ** node7 -82.2722 17.9951 -4.572 1.29e-05 *** node2:Temp -2.2922 1.0626 -2.157 0.033214 * node5:Temp 3.2989 0.6191 5.328 5.47e-07 *** node6:Temp 2.8059 0.7076 3.965 0.000132 *** node7:Temp 1.4769 0.2408 6.133 1.45e-08 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 (Dispersion parameter for gaussian family taken to be 329.3685) Null deviance: 331029 on 116 degrees of freedom Residual deviance: 35572 on 108 degrees of freedom AIC: 1011.4 Number of Fisher Scoring iterations: 2 > mean((predict(m) - airq$Ozone)^2) [1] 306.6534 > airq_lmtree <- partykit::lmtree(Ozone ~ Temp | Solar.R + + Wind, data = airq, cluster = month) > info_node(node_party(airq_lmtree)) $coefficients (Intercept) Temp -147.64607 2.43911 $objfun [1] 62367.44 $object Call: lm(formula = Ozone ~ Temp) Coefficients: (Intercept) Temp -147.646 2.439 $nobs [1] 111 $p.value [1] 0.003498545 $test Solar.R Wind statistic 8.5761635 18.881769795 p.value 0.2771841 0.003498545 > mean((predict(airq_lmtree, newdata = airq) - airq$Ozone)^2) [1] 371.5366 > detach(package:party) *** Run successfully completed *** > proc.time() user system elapsed 5.352 7.306 4.194 partykit/vignettes/partykit.Rnw0000644000176200001440000010150114172230001016454 0ustar liggesusers\documentclass[nojss]{jss} %\VignetteIndexEntry{partykit: A Toolkit for Recursive Partytioning} %\VignetteDepends{partykit} %\VignetteKeywords{recursive partitioning, regression trees, classification trees, decision trees} %\VignettePackage{partykit} %% packages \usepackage{amstext} \usepackage{amsfonts} \usepackage{amsmath} \usepackage{thumbpdf} \usepackage{rotating} %% need no \usepackage{Sweave} %% additional commands \newcommand{\squote}[1]{`{#1}'} \newcommand{\dquote}[1]{``{#1}''} \newcommand{\fct}[1]{\texttt{#1()}} \newcommand{\class}[1]{\squote{\texttt{#1}}} %% for internal use \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} \newcommand{\readme}[1]{\emph{\marginpar{README} (#1)}} \hyphenation{Qua-dra-tic} \title{\pkg{partykit}: A Toolkit for Recursive Partytioning} \Plaintitle{partykit: A Toolkit for Recursive Partytioning} \author{Achim Zeileis\\Universit\"at Innsbruck \And Torsten Hothorn\\Universit\"at Z\"urich} \Plainauthor{Achim Zeileis, Torsten Hothorn} \Abstract{ The \pkg{partykit} package provides a flexible toolkit with infrastructure for learning, representing, summarizing, and visualizing a wide range of tree-structured regression and classification models. The functionality encompasses: (a)~Basic infrastructure for \emph{representing} trees (inferred by any algorithm) so that unified \code{print}/\code{plot}/\code{predict} methods are available. (b)~Dedicated methods for trees with \emph{constant fits} in the leaves (or terminal nodes) along with suitable coercion functions to create such tree models (e.g., by \pkg{rpart}, \pkg{RWeka}, PMML). (c)~A reimplementation of \emph{conditional inference trees} (\code{ctree}, originally provided in the \pkg{party} package). (d)~An extended reimplementation of \emph{model-based recursive partitioning} (\code{mob}, also originally in \pkg{party}) along with dedicated methods for trees with parametric models in the leaves. This vignette gives a brief overview of the package and discusses in detail the generic infrastructure for representing trees (a). Items~(b)--(d) are discussed in the remaining vignettes in the package. } \Keywords{recursive partitioning, regression trees, classification trees, decision trees} \Address{ Achim Zeileis \\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org} \\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} \\ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/} } \begin{document} \SweaveOpts{eps=FALSE, keep.source=TRUE, eval = TRUE} <>= suppressWarnings(RNGversion("3.5.2")) options(width = 70) library("partykit") set.seed(290875) @ \section{Overview} \label{sec:overview} In the more than fifty years since \cite{Morgan+Sonquist:1963} published their seminal paper on ``automatic interaction detection'', a wide range of methods has been suggested that is usually termed ``recursive partitioning'' or ``decision trees'' or ``tree(-structured) models'' etc. Particularly influential were the algorithms CART \citep[classification and regression trees,][]{Breiman+Friedman+Olshen:1984}, C4.5 \citep{Quinlan:1993}, QUEST/GUIDE \citep{Loh+Shih:1997,Loh:2002}, and CTree \citep{Hothorn+Hornik+Zeileis:2006} among many others \citep[see][for a recent overview]{Loh:2014}. Reflecting the heterogeneity of conceptual algorithms, a wide range of computational implementations in various software systems emerged: Typically the original authors of an algorithm also provide accompanying software but many software systems, e.g., including \pkg{Weka} \citep{Witten+Frank:2005} or \proglang{R} \citep{R}, also provide collections of various types of trees. Within \proglang{R} the list of prominent packages includes \pkg{rpart} \citep[implementing the CART algorithm]{rpart}, \pkg{mvpart} \citep[for multivariate CART]{mvpart}, \pkg{RWeka} \citep[containing interfaces to J4.8, M5', LMT from \pkg{Weka}]{RWeka}, and \pkg{party} \citep[implementing CTree and MOB]{party} among many others. See the CRAN task view ``Machine Learning'' \citep{ctv} for an overview. All of these algorithms and software implementations have to deal with very similar challenges. However, due to the fragmentation of the communities in which the corresponding research is published -- ranging from statistics over machine learning to various applied fields -- many discussions of the algorithms do not reuse established theoretical results and terminology. Similarly, there is no common ``language'' for the software implementations and different solutions are provided by different packages (even within \proglang{R}) with relatively little reuse of code. The \pkg{partykit} tries to address the latter point and improve the computational situation by providing a common unified infrastructure for recursive partytioning in the \proglang{R} system for statistical computing. In particular, \pkg{partykit} provides tools for representing fitted trees along with printing, plotting, and computing predictions. The design principles are: \begin{itemize} \item One `agnostic' base class (\class{party}) which can encompass an extremely wide range of different types of trees. \item Subclasses for important types of trees, e.g., trees with constant fits (\class{constparty}) or with parametric models (\class{modelparty}) in each terminal node (or leaf). \item Nodes are recursive objects, i.e., a node can contain child nodes. \item Keep the (learning) data out of the recursive node and split structure. \item Basic printing, plotting, and predicting for raw node structure. \item Customization via suitable panel or panel-generating functions. \item Coercion from existing object classes in \proglang{R} (\code{rpart}, \code{J48}, etc.) to the new class. \item Usage of simple/fast \proglang{S}3 classes and methods. \end{itemize} In addition to all of this generic infrastructure, two specific tree algorithms are implemented in \pkg{partykit} as well: \fct{ctree} for conditional inference trees \citep{Hothorn+Hornik+Zeileis:2006} and \fct{mob} for model-based recursive partitioning \citep{Zeileis+Hothorn+Hornik:2008}. This vignette (\code{"partykit"}) introduces the basic \class{party} class and associated infrastructure while three further vignettes discuss the tools built on top of it: \code{"constparty"} covers the eponymous class for constant-fit trees along with suitable coercion functions, and \code{"ctree"} and \code{"mob"} discuss the new \fct{ctree} and \fct{mob} implementations, respectively. Each of the vignettes can be viewed within \proglang{R} via \code{vignette(}\emph{``name''}\code{, package = "partykit")}. Normal users reading this vignette will typically be interested only in the motivating example in Section~\ref{sec:intro} while the remaining sections are intended for programmers who want to build infrastructure on top of \pkg{partykit}. \section{Motivating example} \label{sec:intro} \subsection{Data} To illustrate how \pkg{partykit} can be used to represent trees, we employ a simple artificial data set taken from \cite{Witten+Frank:2005}. It concerns the conditions suitable for playing some unspecified game: % <>= data("WeatherPlay", package = "partykit") WeatherPlay @ % To represent the \code{play} decision based on the corresponding weather condition variables one could use the tree displayed in Figure~\ref{fig:weather-plot}. For now, it is ignored how this tree was inferred and it is simply assumed to be given. \setkeys{Gin}{width=0.8\textwidth} \begin{figure}[t!] \centering <>= py <- party( partynode(1L, split = partysplit(1L, index = 1:3), kids = list( partynode(2L, split = partysplit(3L, breaks = 75), kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = partysplit(4L, index = 1:2), kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))), WeatherPlay) plot(py) @ \caption{\label{fig:weather-plot} Decision tree for \code{play} decision based on weather conditions in \code{WeatherPlay} data.} \end{figure} \setkeys{Gin}{width=\textwidth} To represent this tree (or recursive partition) in \pkg{partykit}, two basic building blocks are used: splits of class \class{partysplit} and nodes of class \class{partynode}. The resulting recursive partition can then be associated with a data set in an object of class \class{party}. \subsection{Splits} First, we employ the \fct{partysplit} function to create the three splits in the ``play tree'' from Figure~\ref{fig:weather-plot}. The function takes the following arguments \begin{Code} partysplit(varid, breaks = NULL, index = NULL, ..., info = NULL) \end{Code} where \code{varid} is an integer id (column number) of the variable used for splitting, e.g., \code{1L} for \code{outlook}, \code{3L} for \code{humidity}, \code{4L} for \code{windy} etc. Then, \code{breaks} and \code{index} determine which observations are sent to which of the branches, e.g., \code{breaks = 75} for the humidity split. Apart from further arguments not shown above (and just comprised under `\code{...}'), some arbitrary information can be associated with a \class{partysplit} object by passing it to the \code{info} argument. The three splits from Figure~\ref{fig:weather-plot} can then be created via % <>= sp_o <- partysplit(1L, index = 1:3) sp_h <- partysplit(3L, breaks = 75) sp_w <- partysplit(4L, index = 1:2) @ % For the numeric \code{humidity} variable the \code{breaks} are set while for the factor variables \code{outlook} and \code{windy} the information is supplied which of the levels should be associated with which of the branches of the tree. \subsection{Nodes} Second, we use these splits in the creation of the whole decision tree. In \pkg{partykit} a tree is represented by a \class{partynode} object which is recursive in that it may have ``kids'' that are again \class{partynode} objects. These can be created with the function \begin{Code} partynode(id, split = NULL, kids = NULL, ..., info = NULL) \end{Code} where \code{id} is an integer identifier of the node number, \code{split} is a \class{partysplit} object, and \code{kids} is a list of \class{partynode} objects. Again, there are further arguments not shown (\code{...}) and arbitrary information can be supplied in \code{info}. The whole tree from Figure~\ref{fig:weather-plot} can then be created via % <>= pn <- partynode(1L, split = sp_o, kids = list( partynode(2L, split = sp_h, kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = sp_w, kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))) @ % where the previously created \class{partysplit} objects are used as splits and the nodes are simply numbered (depth first) from~1 to~8. For the terminal nodes of the tree there are no \code{kids} and the corresponding \code{play} decision is stored in the \code{info} argument. Printing the \class{partynode} object reflects the recursive structure stored. % <>= pn @ % However, the displayed information is still rather raw as it has not yet been associated with the \code{WeatherPlay} data set. \subsection{Trees (or recursive partitions)} Therefore, in a third step the recursive tree structure stored in \code{pn} is coupled with the corresponding data in a \class{party} object. % <>= py <- party(pn, WeatherPlay) print(py) @ % Now, Figure~\ref{fig:weather-plot} can easily be created by % <>= plot(py) @ % In addition to \fct{print} and \fct{plot}, the \fct{predict} method can now be applied, yielding the predicted terminal node IDs. % <>= predict(py, head(WeatherPlay)) @ % In addition to the \class{partynode} and the \class{data.frame}, the function \fct{party} takes several further arguments \begin{Code} party(node, data, fitted = NULL, terms = NULL, ..., info = NULL) \end{Code} i.e., \code{fitted} values, a \code{terms} object, arbitrary additional \code{info}, and again some further arguments comprised in \code{...}. \subsection{Methods and other utilities} The main idea about the \class{party} class is that tedious tasks such as \fct{print}, \fct{plot}, \fct{predict} do not have to be reimplemented for every new kind of decision tree but can simply be reused. However, in addition to these three basic tasks (as already illustrated above) developers of tree model software also need further basic utiltities for working with trees: e.g., functions for querying or subsetting the tree and for customizing printed/plotted output. Below, various utilities provided by the \pkg{partykit} package are introduced. For querying the dimensions of the tree, three basic functions are available: \fct{length} gives the number of kid nodes of the root node, \fct{depth} the depth of the tree and \fct{width} the number of terminal nodes. % <>= length(py) width(py) depth(py) @ % As decision trees can grow to be rather large, it is often useful to inspect only subtrees. These can be easily extracted using the standard \code{[} or \code{[[} operators: % <>= py[6] @ % The resulting object is again a full valid \class{party} tree and can hence be printed (as above) or plotted (via \code{plot(py[6])}, see the left panel of Figure~\ref{fig:plot-customization}). Instead of using the integer node IDs for subsetting, node labels can also be used. By default thise are just (character versions of) the node IDs but other names can be easily assigned: % <>= py2 <- py names(py2) names(py2) <- LETTERS[1:8] py2 @ % The function \fct{nodeids} queries the integer node IDs belonging to a \class{party} tree. By default all IDs are returned but optionally only the terminal IDs (of the leaves) can be extracted. % <>= nodeids(py) nodeids(py, terminal = TRUE) @ % Often functions need to be applied to certain nodes of a tree, e.g., for extracting information. This is accomodated by a new generic function \fct{nodeapply} that follows the style of other \proglang{R} functions from the \code{apply} family and has methods for \class{party} and \class{partynode} objects. Furthermore, it needs a set of node IDs (often computed via \fct{nodeids}) and a function \code{FUN} that is applied to each of the requested \class{partynode} objects, typically for extracting/formatting the \code{info} of the node. % <>= nodeapply(py, ids = c(1, 7), FUN = function(n) n$info) nodeapply(py, ids = nodeids(py, terminal = TRUE), FUN = function(n) paste("Play decision:", n$info)) @ % Similar to the functions applied in a \fct{nodeapply}, the \fct{print}, \fct{predict}, and \fct{plot} methods can be customized through panel function that format certain parts of the tree (such as header, footer, node, etc.). Hence, the same kind of panel function employed above can also be used for predictions: <>= predict(py, FUN = function(n) paste("Play decision:", n$info)) @ As a variation of this approach, an extended formatting with multiple lines can be easily accomodated by supplying a character vector in every node: % <>= print(py, terminal_panel = function(n) c(", then the play decision is:", toupper(n$info))) @ % The same type of approach can also be used in the default \fct{plot} method (with the main difference that the panel function operates on the \code{info} directly rather than on the \class{partynode}). % <>= plot(py, tp_args = list(FUN = function(i) c("Play decision:", toupper(i)))) @ % See the right panel of Figure~\ref{fig:plot-customization} for the resulting graphic. Many more elaborate panel functions are provided in \pkg{partykit}, especially for not only showing text in the visualizations but also statistical graphics. Some of these are briefly illustrated in this and the other package vignettes. Programmers that want to write their own panel functions are advised to inspect the corresponding \proglang{R} source code to see how flexible (but sometimes also complicated) these panel functions are. \setkeys{Gin}{width=0.48\textwidth} \begin{figure}[t!] \centering <>= plot(py[6]) @ <>= <> @ \caption{\label{fig:plot-customization} Visualization of subtree (left) and tree with custom text in terminal nodes (right).} \end{figure} \setkeys{Gin}{width=\textwidth} Finally, an important utility function is \fct{nodeprune} which allows to prune \class{party} trees. It takes a vector of node IDs and prunes all of their kids, i.e., making all the indicated node IDs terminal nodes. <>= nodeprune(py, 2) nodeprune(py, c(2, 6)) @ Note that for the pruned versions of this particular \class{party} tree, the new terminal nodes are displayed with a \code{*} rather than the play decision. This is because we did not store any play decisions in the \code{info} of the inner nodes of \code{py}. We could have of course done so initially, or could do so now, or we might want to do so automatically. For the latter, we would have to know how predictions should be obtained from the data and this is briefly discussed at the end of this vignette and in more detail in \code{vignette("constparty", package = "partykit")}. \section{Technical details} \subsection{Design principles} To facilitate reading of the subsequent sections, two design principles employed in the creation of \pkg{partykit} are briefly explained. % \begin{enumerate} \item Many helper utilities are encapsulated in functions that follow a simple naming convention. To extract/compute some information \emph{foo} from splits, nodes, or trees, \pkg{partykit} provides \emph{foo}\code{_split}, \emph{foo}\code{_node}, \emph{foo}\code{_party} functions (that are applicable to \class{partysplit}, \class{partynode}, and \class{party} objects, repectively). An example for the information \emph{foo} might be \code{kidids} or \code{info}. Hence, in the printing example above using \code{info_node(n)} rather than \code{n$info} for a node \code{n} would have been the preferred syntax; at least when programming new functionality on top of \pkg{partykit}. \item As already illustrated above, printing and plotting relies on \emph{panel functions} that visualize and/or format certain aspects of the resulting display, e.g., that of inner nodes, terminal nodes, headers, footers, etc. Furthermore, arguments like \code{terminal_panel} can also take \emph{panel-generating functions}, i.e., functions that produce a panel function when applied to the \class{party} object. \end{enumerate} \subsection{Splits} \label{sec:splits} \subsubsection{Overview} A split is basically a function that maps data -- or more specifically a partitioning variable -- to daugther nodes. Objects of class \class{partysplit} are designed to represent such functions and are set up by the \fct{partysplit} constructor. For example, a binary split in the numeric partitioning variable \code{humidity} (the 3rd variable in \code{WeatherPlay}) at the breakpoint \code{75} can be created (as above) by % <>= sp_h <- partysplit(3L, breaks = 75) class(sp_h) @ % The internal structure of class \class{partysplit} contains information about the partitioning variable, the splitpoints (or cutpoints or breakpoints), the handling of splitpoints, the treatment of observations with missing values and the kid nodes to send observations to: % <>= unclass(sp_h) @ % Here, the splitting rule is \code{humidity} $\le 75$: % <>= character_split(sp_h, data = WeatherPlay) @ % This representation of splits is completely abstract and, most importantly, independent of any data. Now, data comes into play when we actually want to perform splits: % <>= kidids_split(sp_h, data = WeatherPlay) @ % For each observation in \code{WeatherPlay} the split is performed and the number of the kid node to send this observation to is returned. Of course, this is a very complicated way of saying % <>= as.numeric(!(WeatherPlay$humidity <= 75)) + 1 @ \subsubsection{Mathematical notation} To explain the splitting strategy more formally, we employ some mathematical notation. \pkg{partykit} considers a split to represent a function $f$ mapping an element $x = (x_1, \dots, x_p)$ of a $p$-dimensional sample space $\mathcal{X}$ into a set of $k$ daugther nodes $\mathcal{D} = \{d_1, \dots, d_k\}$. This mapping is defined as a composition $f = h \circ g$ of two functions $g: \mathcal{X} \rightarrow \mathcal{I}$ and $h: \mathcal{I} \rightarrow \mathcal{D}$ with index set $\mathcal{I} = \{1, \dots, l\}, l \ge k$. Let $\mu = (-\infty, \mu_1, \dots, \mu_{l - 1}, \infty)$ denote the split points ($(\mu_1, \dots, \mu_{l - 1})$ = \code{breaks}). We are interested to split according to the information contained in the $i$-th element of $x$ ($i$ = \code{varid}). For numeric $x_i$, the split points are also numeric. If $x_i$ is a factor at levels $1, \dots, K$, the default split points are $\mu = (-\infty, 1, \dots, K - 1, \infty)$. The function $g$ essentially determines, which of the intervals (defined by $\mu$) the value $x_i$ is contained in ($I$ denotes the indicator function here): \begin{eqnarray*} x \mapsto g(x) = \sum_{j = 1}^l j I_{\mathcal{A}(j)}(x_i) \end{eqnarray*} where $\mathcal{A}(j) = (\mu_{j - 1}, \mu_j]$ for \code{right = TRUE} except $\mathcal{A}(l) = (\mu_{l - 1}, \infty)$. If \code{right = FALSE}, then $\mathcal{A}(j) = [\mu_{j - 1}, \mu_j)$ except $\mathcal{A}(1) = (-\infty, \mu_1)$. Note that for a categorical variable $x_i$ and default split points, $g$ is simply the identity. Now, $h$ maps from the index set $\mathcal{I}$ into the set of daugther nodes: \begin{eqnarray*} f(x) = h(g(x)) = d_{\sigma_{g(x)}} \end{eqnarray*} where $\sigma = (\sigma_1, \dots, \sigma_l) \in \{1, \dots, k\}^l$ (\code{index}). By default, $\sigma = (1, \dots, l)$ and $k = l$. If $x_i$ is missing, then $f(x)$ is randomly drawn with $\mathbb{P}(f(x) = d_j) = \pi_j, j = 1, \dots, k$ for a discrete probability distribution $\pi = (\pi_1, \dots, \pi_k)$ over the $k$ daugther nodes (\code{prob}). In the simplest case of a binary split in a numeric variable $x_i$, there is only one split point $\mu_1$ and, with $\sigma = (1, 2)$, observations with $x_i \le \mu_1$ are sent to daugther node $d_1$ and observations with $x_i > \mu_1$ to $d_2$. However, this representation of splits is general enough to deal with more complicated set-ups like surrogate splits, where typically the index needs modification, for example $\sigma = (2, 1)$, categorical splits, i.e., there is one data structure for both ordered and unordered splits, multiway splits, and functional splits. The latter can be implemented by defining a new artificial splitting variable $x_{p + 1}$ by means of a potentially very complex function of $x$ later used for splitting. \subsubsection{Further examples} Consider a split in a categorical variable at three levels where the first two levels go to the left daugther node and the third one to the right daugther node: % <>= sp_o2 <- partysplit(1L, index = c(1L, 1L, 2L)) character_split(sp_o2, data = WeatherPlay) table(kidids_split(sp_o2, data = WeatherPlay), WeatherPlay$outlook) @ % The internal structure of this object contains the \code{index} slot that maps levels to kid nodes. % <>= unclass(sp_o2) @ % This mapping is also useful with splits in ordered variables or when representing multiway splits: % <>= sp_o <- partysplit(1L, index = 1L:3L) character_split(sp_o, data = WeatherPlay) @ % For a split in a numeric variable, the mapping to daugther nodes can also be changed by modifying \code{index}: % <>= sp_t <- partysplit(2L, breaks = c(69.5, 78.8), index = c(1L, 2L, 1L)) character_split(sp_t, data = WeatherPlay) table(kidids_split(sp_t, data = WeatherPlay), cut(WeatherPlay$temperature, breaks = c(-Inf, 69.5, 78.8, Inf))) @ \subsubsection{Further comments} The additional argument \code{prop} can be used to specify a discrete probability distribution over the daugther nodes that is used to map observations with missing values to daugther nodes. Furthermore, the \code{info} argument and slot can take arbitrary objects to be stored with the split (for example split statistics). Currently, no specific structure of the \code{info} is used. Programmers that employ this functionality in their own functions/packages should access the elements of a \class{partysplit} object by the corresponding accessor function (and not just the \code{$} operator as the internal structure might be changed/extended in future release). \subsection{Nodes} \label{sec:nodes} \subsubsection{Overview} Inner and terminal nodes are represented by objects of class \class{partynode}. Each node has a unique identifier \code{id}. A node consisting only of such an identifier (and possibly additional information in \code{info}) is a terminal node: % <>= n1 <- partynode(id = 1L) is.terminal(n1) print(n1) @ % Inner nodes have to have a primary split \code{split} and at least two daugther nodes. The daugther nodes are objects of class \class{partynode} itself and thus represent the recursive nature of this data structure. The daugther nodes are pooled in a list \code{kids}. In addition, a list of \class{partysplit} objects offering surrogate splits can be supplied in argument \code{surrogates}. These are used in case the variable needed for the primary split has missing values in a particular data set. The IDs in a \class{partynode} should be numbered ``depth first'' (sometimes also called ``infix'' or ``pre-order traversal''). This simply means that the root node has identifier 1; the first kid node has identifier 2, whose kid (if present) has identifier 3 and so on. If other IDs are desired, then one can simply set \fct{names} (see above) for the tree; however, internally the depth-first numbering needs to be used. Note that the \fct{partynode} constructor also allows to create \class{partynode} objects with other ID schemes as this is necessary for growing the tree. If one wants to assure the a given \class{partynode} object has the correct IDs, one can simply apply \fct{as.partynode} once more to assure the right order of IDs. Finally, let us emphasize that \class{partynode} objects are not directly connected to the actual data (only indirectly through the associated \class{partysplit} objects). \subsubsection{Examples} Based on the binary split \code{sp_h} defined in the previous section, we set up an inner node with two terminal daugther nodes and print this stump (the data is needed because neither split nor nodes contain information about variable names or levels): % <>= n1 <- partynode(id = 1L, split = sp_o, kids = lapply(2L:4L, partynode)) print(n1, data = WeatherPlay) @ % Now that we have defined this simple tree, we want to assign observations to terminal nodes: % <>= fitted_node(n1, data = WeatherPlay) @ % Here, the \code{id}s of the terminal node each observations falls into are returned. Alternatively, we could compute the position of these daugther nodes in the list \code{kids}: % <>= kidids_node(n1, data = WeatherPlay) @ % Furthermore, the \code{info} argument and slot takes arbitrary objects to be stored with the node (predictions, for example, but we will handle this issue later). The slots can be extracted by means of the corresponding accessor functions. \subsubsection{Methods} A number of methods is defined for \class{partynode} objects: \fct{is.partynode} checks if the argument is a valid \class{partynode} object. \fct{is.terminal} is \code{TRUE} for terminal nodes and \code{FALSE} for inner nodes. The subset method \code{[} returns the \class{partynode} object corresponding to the \code{i}-th kid. The \fct{as.partynode} and \fct{as.list} methods can be used to convert flat list structures into recursive \class{partynode} objects and vice versa. As pointed out above, \fct{as.partynode} applied to \class{partynode} objects also renumbers the recursive nodes starting with root node identifier \code{from}. Furthermore, many of the methods defined for the class \class{party} illustrated above also work for plain \class{partynode} objects. For example, \fct{length} gives the number of kid nodes of the root node, \fct{depth} the depth of the tree and \fct{width} the number of terminal nodes. \subsection{Trees} \label{sec:trees} Although tree structures can be represented by \class{partynode} objects, a tree is more than a number of nodes and splits. More information about (parts of the) corresponding data is necessary for high-level computations on trees. \subsubsection{Trees and data} First, the raw node/split structure needs to be associated with a corresponding data set. % <>= t1 <- party(n1, data = WeatherPlay) t1 @ % Note that the \code{data} may have zero rows (i.e., only contain variable names/classes but not the actual data) and all methods that do not require the presence of any learning data still work fine: % <>= party(n1, data = WeatherPlay[0, ]) @ \subsubsection{Response variables and regression relationships} Second, for decision trees (or regression and classification trees) more information is required: namely, the response variable and its fitted values. Hence, a \class{data.frame} can be supplied in \code{fitted} that has at least one variable \code{(fitted)} containing the terminal node numbers of data used for fitting the tree. For representing the dependence of the response on the partitioning variables, a \code{terms} object can be provided that is leveraged for appropriately preprocessing new data in predictions. Finally, any additional (currently unstructured) information can be stored in \code{info} again. % <>= t2 <- party(n1, data = WeatherPlay, fitted = data.frame( "(fitted)" = fitted_node(n1, data = WeatherPlay), "(response)" = WeatherPlay$play, check.names = FALSE), terms = terms(play ~ ., data = WeatherPlay), ) @ % The information that is now contained in the tree \code{t2} is sufficient for all operations that should typically be performed on constant-fit trees. For this type of trees there is also a dedicated class \class{constparty} that provides some further convenience methods, especially for plotting and predicting. If a suitable \class{party} object like \code{t2} is already available, it just needs to be coerced: % <>= t2 <- as.constparty(t2) t2 @ % \setkeys{Gin}{width=0.6\textwidth} \begin{figure}[t!] \centering <>= plot(t2, tnex = 1.5) @ \caption{\label{fig:constparty-plot} Constant-fit tree for \code{play} decision based on weather conditions in \code{WeatherPlay} data.} \end{figure} \setkeys{Gin}{width=\textwidth} % As pointed out above, \class{constparty} objects have enhanced \fct{plot} and \fct{predict} methods. For example, \code{plot(t2)} now produces stacked bar plots in the leaves (see Figure~\ref{fig:constparty-plot}) as \code{t2} is a classification tree For regression and survival trees, boxplots and Kaplan-Meier curves are employed automatically, respectively. As there is information about the response variable, the \fct{predict} method can now produce more than just the predicted node IDs. The default is to predict the \code{"response"}, i.e., a factor for a classification tree. In this case, class probabilities (\code{"prob"}) are also available in addition to the majority votings. % <>= nd <- data.frame(outlook = factor(c("overcast", "sunny"), levels = levels(WeatherPlay$outlook))) predict(t2, newdata = nd, type = "response") predict(t2, newdata = nd, type = "prob") predict(t2, newdata = nd, type = "node") @ More details on how \class{constparty} objects and their methods work can be found in the corresponding \code{vignette("constparty", package = "partykit")}. \section{Summary} This vignette (\code{"partykit"}) introduces the package \pkg{partykit} that provides a toolkit for computing with recursive partytions, especially decision/regression/classification trees. In this vignette, the basic \class{party} class and associated infrastructure are discussed: splits, nodes, and trees with functions for printing, plotting, and predicting. Further vignettes in the package discuss in more detail the tools built on top of it. \bibliography{party} \end{document} partykit/vignettes/party.bib0000644000176200001440000006537114172230001015750 0ustar liggesusers @article{Kass:1980, author = {Gordon V. Kass}, title = {An Exploratory Technique for Investigating Large Quantities of Categorical Data}, journal = {Applied Statistics}, year = {1980}, volume = 29, number = 2, pages = {119--127}, } @Book{Quinlan:1993, author = {John R. Quinlan}, title = {{C4.5}: Programs for Machine Learning}, publisher = {Morgan Kaufmann Publishers}, address = {San Mateo}, year = {1993} } @Book{Agresti:2002, author = {Alan Agresti}, title = {Categorical Data Analysis}, year = {2002}, edition = {2nd}, publisher = {John Wiley \& Sons}, address = {Hoboken} } @Article{White+Liu:1994, author = {Allan P. White and Wei Zhong Liu}, title = {Bias in Information-Based Measures in Decision Tree Induction}, journal = {Machine Learning}, year = {1994}, volume = {15}, pages = {321-329} } @Article{VanDerAart+SmeenkEnserink:1975, author = {P. J. {Van der Aart} and N. Smeenk-Enserink}, title = {Correlations between Distributions of Hunting Spiders ({L}ycosidae, {C}tenidae) and Environment Characteristics in a Dune Area}, journal = {Netherlands Journal of Zoology}, year = {1975}, volume = {25}, pages = {1-45} } @Book{Hosmer+Lemeshow:2000, author = {David W. Hosmer and Stanley Lemeshow}, title = {Applied Logistic Regression}, publisher = {John Wiley \& Sons}, address = {New York}, edition = {2nd}, year = {2000} } @Article{Mueller+Hothorn:2004, author = {J{\"o}rg M{\"u}ller and Torsten Hothorn}, title = {Maximally Selected Two-Sample Statistics as a new Tool for the Identification and Assessment of Habitat Factors with an Application to Breeding Bird Communities in Oak Forests}, year = {2004}, volume = {123}, journal = {European Journal of Forest Research}, pages = {218-228} } @Book{Westfall+Young:1993, author = {Peter H. Westfall and S. Stanley Young}, title = {Resampling-Based Multiple Testing}, publisher = {John Wiley \& Sons}, address = {New York}, year = {1993} } @Article{Noh+Song+Park:2004, author = {Hyun Gon Noh and Moon Sup Song and Sung Hyun Park}, title = {An Unbiased Method for Constructing Multilabel Classification Trees}, journal = {Computational Statistics \& Data Analysis}, volume = {47}, number = {1}, pages = {149-164}, year = {2004} } @Article{Zhang:1998, author = {Heping Zhang}, title = {Classification Trees for Multiple Binary Responses}, journal = {Journal of the American Statistical Association}, pages = {180-193}, year = {1998}, volume = {93} } @Article{Su+Fan:2004, author = {Xiaogang Su and Juanjuan Fan}, title = {Multivariate Survival Trees: A Maximum Likelihood Approach Based on Frailty Models}, journal = {Biometrics}, pages = {93-99}, year = {2004}, volume = {60} } @Article{OBrien:2004, author = {Sean M. O'Brien}, title = {Cutpoint Selection for Categorizing a Continuous Predictor}, journal = {Biometrics}, pages = {504-509}, year = {2004}, volume = {60} } @Article{Strasser+Weber:1999, author = {Helmut Strasser and Christian Weber}, title = {On the Asymptotic Theory of Permutation Statistics}, journal = {Mathematical Methods of Statistics}, pages = {220-250}, year = {1999}, volume = {8} } @Article{Shih:1999, author = {Y.S. Shih}, title = {Families of Splitting Criteria for Classification Trees}, journal = {Statistics and Computing}, pages = {309-315}, year = {1999}, volume = {9} } @Article{Mingers:1987, author = {John Mingers}, title = {Expert Systems -- {R}ule Induction with Statistical Data}, journal = {Journal of the Operations Research Society}, pages = {39-47}, year = {1987}, volume = {38}, number = {1} } @Article{Death:2002, author = {Glenn De'ath}, title = {Multivariate Regression Trees: A New Technique for Modeling Species-Environment Relationships}, journal = {Ecology}, pages = {1105-1117}, year = {2002}, volume = {83}, number = {4} } @TechReport{Dudiot+VanDerLaan:2003, author = {Sandrine Dudoit and Mark J. van der Laan}, title = {Unified Cross-Validation Methodology for Selection Among Estimators: Finite Sample Results, Asymptotic Optimality, and Applications}, institution = {Division of Biostatistics, University of California, Berkeley}, year = {2003}, address = {Berkeley}, number = {130}, url = {http://www.bepress.com/ucbbiostat/paper130} } @Article{Molinaro+Dudiot+VanDerLaan:2003, author = {Annette M. Molinaro and Sandrine Dudoit and Mark J. van der Laan}, title = {Tree-Based Multivariate Regression and Density Estimation with Right-Censored Data}, year = {2004}, journal = {Journal of Multivariate Analysis}, pages = {154-177}, volume = {90}, number = {1} } @Article{Peters+Hothorn+Lausen:2002, author = {Andrea Peters and Torsten Hothorn and Berthold Lausen}, title = {\pkg{ipred}: Improved Predictors}, journal = {\proglang{R} News}, pages = {33--36}, year = {2002}, month = {June}, volume = {2}, number = {2}, url = {http://CRAN.R-project.org/doc/Rnews/} } @Book{Breiman+Friedman+Olshen:1984, author = {Leo Breiman and Jerome H. Friedman and Richard A. Olshen and Charles J. Stone}, title = {Classification and Regression Trees}, year = {1984}, publisher = {Wadsworth}, address = {California} } @Article{Mardin+Hothorn+Peters:2003, author = {Christian Y. Mardin and Torsten Hothorn and Andrea Peters and Anselm G. J{\"u}nemann and Nhung X. Nguyen and Berthold Lausen}, title = {New Glaucoma Classification Method Based on Standard {HRT} Parameters by Bagging Classification Trees}, journal = {Journal of Glaucoma}, pages = {340--346}, year = {2003}, volume = {12}, number = {4} } @Article{Segal:1988, author = {Mark R. Segal}, title = {Regression Trees for Censored Data}, journal = {Biometrics}, pages = {35--47}, year = {1988}, volume = {44} } @Article{LeBlanc+Crowley:1992, author = {Michael LeBlanc and John Crowley}, title = {Relative Risk Trees for Censored Survival Data}, journal = {Biometrics}, pages = {411--425}, year = {1992}, volume = {48} } @InCollection{LeBlanc:2001, author = {Michael LeBlanc}, editor = {John Crowley}, title = {Tree-Based Methods for Prognostic Stratification}, booktitle = {Statistics in Oncology}, pages = {457--472}, year = {2001}, publisher = {Marcel Dekker}, address = {New York} } @InCollection{Schumacher+Hollaender+Schwarzer:2001a, author = {Martin Schumacher and Norbert Holl\"ander and Guido Schwarzer and Willi Sauerbrei}, editor = {John Crowley}, title = {Prognostic Factor Studies}, booktitle = {Statistics in Oncology}, pages = {321--378}, year = {2001}, publisher = {Marcel Dekker}, address = {New York} } @Article{Hothorn+Hornik+Zeileis:2006, author = {Torsten Hothorn and Kurt Hornik and Achim Zeileis}, title = {Unbiased Recursive Partitioning: {A} Conditional Inference Framework}, journal = {Journal of Computational and Graphical Statistics}, year = {2006}, volume = {15}, number = {3}, pages = {651--674}, doi = {10.1198/106186006X133933}, } @Article{Meyer+Leisch+Hornik:2003, author = {David Meyer and Friedrich Leisch and Kurt Hornik}, title = {The Support Vector Machine Under Test}, journal = {Neurocomputing}, pages = {169--186}, year = {2003}, volume = {55}, number = {1--2} } @Article{Breiman:1996, author = {Leo Breiman}, title = {Bagging Predictors}, journal = {Machine Learning}, pages = {123--140}, year = {1996}, volume = {24}, number = {2} } @Article{Sankar+Mammone:1993, author = {Ananth Sankar and Richard J. Mammone}, title = {Growing and Pruning Neural Tree Networks}, journal = {IEEE Transactions on Computers}, volume = {42}, pages = {291--299} } @Book{Vapnik:1996, author = {Vladimir N. Vapnik}, title = {The Nature of Statistical Learning Theory}, year = {1996}, publisher = {Springer-Verlag}, address = {New York} } @Article{Breiman:2001, author = {Leo Breiman}, title = {Random Forests}, journal = {Machine Learning}, pages = {5--32}, year = {2001}, volume = {45}, number = {1} } @Article{Buehlmann+Yu:2003, author = {Peter B{\"u}hlmann and Bin Yu}, title = {Boosting with {$L_2$} Loss: Regression and Classification}, journal = {Journal of the American Statistical Association}, pages = {324--338}, year = {2003}, volume = {98}, number = {462} } @Article{Loh+Vanichsetakul1:988, author = {Wei-Yin Loh and Nunta Vanichsetakul}, title = {Tree-Structured Classification via Generalized Discriminant Analysis}, journal = {Journal of the American Statistical Association}, pages = {715--725}, year = {1988}, volume = {83} } @Article{Kim+Loh:2001, author = {Hyunjoong Kim and Wei-Yin Loh}, title = {Classification Trees with Unbiased Multiway Splits}, journal = {Journal of the American Statistical Association}, pages = {589--604}, year = {2001}, volume = {96}, number = {454} } @Article{Loh:2002, author = {Wei-Yin Loh}, title = {Regression Trees with Unbiased Variable Selection and Interaction Detection}, journal = {Statistica Sinica}, pages = {361--386}, year = {2002}, volume = {12} } @Article{Loh+Shih:1997, author = {Wei-Yin Loh and Yu-Shan Shih}, title = {Split Selection Methods for Classification Trees}, journal = {Statistica Sinica}, pages = {815-840}, year = {1997}, volume = {7} } @Article{Morgan+Sonquist:1963, author = {James N. Morgan and John A. Sonquist}, title = {Problems in the Analysis of Survey Data, and a Proposal}, journal = {Journal of the American Statistical Association}, pages = {415--434}, year = {1963}, volume = {58} } @Article{Su+Wang+Fan:2004, author = {Xiaogang Su and Morgan Wang and Juanjuan Fan}, title = {Maximum Likelihood Regression Trees}, journal = {Journal of Computational and Graphical Statistics}, pages = {586--598}, year = {2004}, volume = {13} } @Article{Kim+Loh:2003, author = {Hyunjoong Kim and Wei-Yin Loh}, title = {Classification Trees with Bivariate Linear Discriminant Node Models}, journal = {Journal of Computational and Graphical Statistics}, pages = {512--530}, year = {2003}, volume = {12} } @Article{Chan+Loh:2004, author = {Kin-Yee Chan and Wei-Yin Loh}, title = {{LOTUS}: An Algorithm for Building Accurate and Comprehensible Logistic Regression Trees}, journal = {Journal of Computational and Graphical Statistics}, year = {2004}, volume = {13}, number = {4}, pages = {826--852} } @Article{Samarov+Spokoiny+Vial:2005, author = {Alexander Samarov and Vladimir Spokoiny and Celine Vial}, title = {Component Indentification and Estimation in Nonlinear High-Dimension Regression Models by Structural Adaptation}, journal = {Journal of the American Statistical Association}, year = {2005}, volume = {100}, number = {470}, pages = {429--445} } @Article{Gama:2004, author = {Jo{\~a}o Gama}, title = {Functional Trees}, journal = {Machine Learning}, year = {2004}, volume = {55}, pages = {219--250} } @Book{Hochberg+Tamhane:1987, author = {Yosef Hochberg and Ajit C. Tamhane}, title = {Multiple Comparison Procedures}, year = {1987}, publisher = {John Wiley \& Sons}, address = {New York} } @Article{Marcus+Peritz+Gabriel:1976, author = {Ruth Marcus and Eric Peritz and K. R. Gabriel}, title = {On Closed Testing Procedures with Special Reference to Ordered Analysis of Variance}, journal = {Biometrika}, year = {1976}, volume = {63}, number = {3}, pages = {655--660} } @Book{White:1994, author = {Halbert White}, title = {Estimation, Inference and Specification Analysis}, publisher = {Cambridge University Press}, address = {Cambridge}, year = {1994} } @Article{Zeileis+Hornik:2007, author = {Achim Zeileis and Kurt Hornik}, title = {Generalized {M}-Fluctuation Tests for Parameter Instability}, journal = {Statistica Neerlandica}, year = {2007}, volume = {61}, number = {4}, pages = {488--508}, doi = {10.1111/j.1467-9574.2007.00371.x}, } @Article{Ploberger+Kraemer:1992, author = {Werner Ploberger and Walter Kr{\"a}mer}, title = {The {CUSUM} Test with {OLS} Residuals}, journal = {Econometrica}, year = {1992}, volume = {60}, number = {2}, pages = {271--285} } @Article{Chu+Hornik+Kuan:1995, author = {Chia-Shang James Chu and Kurt Hornik and Chung-Ming Kuan}, title = {{MOSUM} Tests for Parameter Constancy}, journal = {Biometrika}, year = {1995}, volume = {82}, pages = {603--617} } @Article{Nyblom:1989, author = {Jukka Nyblom}, title = {Testing for the Constancy of Parameters over Time}, journal = {Journal of the American Statistical Association}, year = {1989}, volume = {84}, pages = {223--230} } @Article{Andrews:1993, author = {Donald W. K. Andrews}, title = {Tests for Parameter Instability and Structural Change with Unknown Change Point}, journal = {Econometrica}, year = {1993}, volume = {61}, pages = {821--856} } @Article{Andrews+Ploberger:1994, author = {Donald W. K. Andrews and Werner Ploberger}, title = {Optimal Tests When a Nuisance Parameter is Present Only Under the Alternative}, journal = {Econometrica}, year = {1994}, volume = {62}, pages = {1383--1414} } @Article{Hjort+Koning:2002, author = {Nils Lid Hjort and Alexander Koning}, title = {Tests for Constancy of Model Parameters over Time}, journal = {Nonparametric Statistics}, year = {2002}, volume = {14}, pages = {113--132} } @Article{Zeileis:2005, author = {Achim Zeileis}, title = {A Unified Approach to Structural Change Tests Based on {ML}~Scores, {$F$}~Statistics, and {OLS}~Residuals}, journal = {Econometric Reviews}, year = {2005}, volume = {24}, pages = {445--466}, doi = {10.1080/07474930500406053}, } @Article{Bai+Perron:2003, author = {Jushan Bai and Pierre Perron}, title = {Computation and Analysis of Multiple Structural Change Models}, journal = {Journal of Applied Econometrics}, year = {2003}, volume = {18}, pages = {1--22} } @Article{Hawkins:2001, author = {Douglas M. Hawkins}, title = {Fitting Multiple Change-Point Models to Data}, journal = {Computational Statistics \& Data Analysis}, year = {2001}, volume = {37}, pages = {323--341} } @Article{Chong:1995, author = {Terence Tai-Leung Chong}, title = {Partial Parameter Consistency in a Misspecified Structural Change Model}, journal = {Economics Letters}, year = {1995}, volume = {49}, pages = {351--357} } @Article{Zeileis+Kleiber+Kraemer:2003, author = {Achim Zeileis and Christian Kleiber and Walter Kr{\"a}mer and Kurt Hornik}, title = {Testing and Dating of Structural Changes in Practice}, journal = {Computational Statistics \& Data Analysis}, year = {2003}, volume = {44}, number = {1--2}, pages = {109--123}, doi = {10.1016/S0167-9473(03)00030-6}, } @Article{Muggeo:2003, author = {Vito M. R. Muggeo}, title = {Estimating Regression Models with Unknown Break-Points}, journal = {Statistics in Medicine}, year = {2003}, volume = {22}, pages = {3055--3071} } @Article{Choi+Ahn+Chen:2005, author = {Yunhee Choi and Hongshik Ahn and James J. Chen}, title = {Regression Trees for Analysis of Count Data with Extra Poisson Variation}, journal = {Computational Statistics \& Data Analysis}, year = {2005}, volume = {49}, issue = {3}, pages = {893--915} } @Article{Breiman+Friedman:1985, author = {Leo Breiman and Jerome H. Friedman}, title = {Estimating Optimal Transformations for Multiple Regression and Correlation}, journal = {Journal of the American Statistical Association}, year = {1985}, volume = {80}, number = {391}, pages = {580--598} } @Article{Hansen:1997, author = {Bruce E. Hansen}, title = {Approximate Asymptotic {$p$} Values for Structural-Change Tests}, journal = {Journal of Business \& Economic Statistics}, year = {1997}, volume = {15}, pages = {60--67} } @Article{Zeileis+Hothorn+Hornik:2008, author = {Achim Zeileis and Torsten Hothorn and Kurt Hornik}, title = {Model-Based Recursive Partitioning}, journal = {Journal of Computational and Graphical Statistics}, year = {2008}, volume = {17}, number = {2}, pages = {492--514}, doi = {10.1198/106186008X319331}, } @Article{Merkle+Zeileis:2013, author = {Edgar C. Merkle and Achim Zeileis}, title = {Tests of Measurement Invariance without Subgroups: A Generalization of Classical Methods}, journal = {Psychometrika}, year = {2013}, volume = {78}, number = {1}, pages = {59--82}, doi = {10.1007/s11336-012-9302-4}, } @Article{Merkle+Fan+Zeileis:2014, author = {Edgar C. Merkle and Jinyan Fan and Achim Zeileis}, title = {Testing for Measurement Invariance with Respect to an Ordinal Variable}, journal = {Psychometrika}, year = {2014}, volume = {79}, number = {4}, pages = {569--584}, doi = {10.1007/S11336-013-9376-7}, } @Article{Strobl+Kopf+Zeileis:2015, author = {Carolin Strobl and Julia Kopf and Achim Zeileis}, title = {Rasch Trees: A New Method for Detecting Differential Item Functioning in the Rasch Model}, journal = {Psychometrika}, year = {2015}, volume = {80}, number = {2}, pages = {289--316}, doi = {10.1007/s11336-013-9388-3}, } @Article{Strobl+Wickelmaier+Zeileis:2011, author = {Carolin Strobl and Florian Wickelmaier and Achim Zeileis}, title = {Accounting for Individual Differences in {B}radley-{T}erry Models by Means of Recursive Partitioning}, journal = {Journal of Educational and Behavioral Statistics}, year = {2011}, volume = {36}, number = {2}, pages = {135--153}, } @Article{Gruen+Kosmidis+Zeileis:2012, author = {Bettina Gr\"un and Ioannis Kosmidis and Achim Zeileis}, title = {Extended Beta Regression in \proglang{R}: Shaken, Stirred, Mixed, and Partitioned}, journal = {Journal of Statistical Software}, year = {2012}, volume = {48}, number = {11}, pages = {1--25}, doi = {10.18637/jss.v048.i11} } @Article{Rusch+Lee+Hornik:2013, author = {Thomas Rusch and Ilro Lee and Kurt Hornik and Wolfgang Jank and Achim Zeileis}, title = {Influencing Elections with Statistics: Targeting Voters with Logistic Regression Trees}, journal = {The Annals of Applied Statistics}, year = {2013}, volume = {7}, number = {3}, pages = {1612--1639}, } @Article{Hamermesh+Parker:2005, author = {Daniel S. Hamermesh and Amy Parker}, title = {Beauty in the Classroom: Instructors' Pulchritude and Putative Pedagogical Productivity}, journal = {Economics of Education Review}, year = {2005}, volume = {24}, pages = {369--376}, } @Article{Loh:2014, author = {Wei-Yin Loh}, title = {Fifty Years of Classification and Regression Trees}, journal = {International Statistical Review}, year = {2014}, volume = {82}, number = {3}, pages = {329--348}, doi = {10.1111/insr.12016} } @Book{Witten+Frank:2005, title = {Data Mining: Practical Machine Learning Tools and Techniques}, author = {Ian H. Witten and Eibe Frank}, year = {2005}, edition = {2nd}, publisher = {Morgan Kaufmann}, address = {San Francisco}, } @Article{Theussl+Zeileis:2009, author = {Stefan Theu{\ss}l and Achim Zeileis}, title = {Collaborative Software Development Using \proglang{R}-{F}orge}, journal = {The \proglang{R} Journal}, year = {2009}, volume = {1}, number = {1}, pages = {9--14}, month = {May}, url = {http://journal.R-project.org/} } @Manual{R, title = {\proglang{R}: {A} Language and Environment for Statistical Computing}, author = {{\proglang{R} Core Team}}, organization = {\proglang{R} Foundation for Statistical Computing}, address = {Vienna, Austria}, year = {2013}, url = {http://www.R-project.org/} } @Manual{mvtnorm, title = {\pkg{mvtnorm}: Multivariate Normal and $t$~Distributions}, author = {Alan Genz and Frank Bretz and Tetsuhisa Miwa and Xuefei Mi and Friedrich Leisch and Fabian Scheipl and Torsten Hothorn}, year = {2015}, note = {\proglang{R}~package version~1.0-3}, url = {http://CRAN.R-project.org/package=mvtnorm}, } @Manual{partykit, title = {\pkg{partykit}: A Toolkit for Recursive Partytioning}, author = {Torsten Hothorn and Achim Zeileis}, year = {2015}, note = {\proglang{R} package version 1.0-3}, url = {http://CRAN.R-project.org/package=partykit} } @Manual{party, title = {\pkg{party}: A Laboratory for Recursive Partytioning}, author = {Torsten Hothorn and Kurt Hornik and Carolin Strobl and Achim Zeileis}, year = {2015}, note = {\proglang{R} package version 1.0-23}, url = {http://CRAN.R-project.org/package=party} } @Manual{psychotree, title = {\pkg{psychotree}: Recursive Partitioning Based on Psychometric Models}, author = {Achim Zeileis and Carolin Strobl and Florian Wickelmaier and Basil {Abou El-Komboz} and Julia Kopf}, year = {2014}, note = {\proglang{R}~package version~0.14-0}, url = {http://CRAN.R-project.org/package=psychotree} } @Manual{C50, title = {\pkg{C50}: {C5.0} Decision Trees and Rule-Based Models}, author = {Max Kuhn and Steve Weston and Nathan Coulter and John R. Quinlan}, year = {2014}, note = {\proglang{R} package version 0.1.0-19}, url = {http://CRAN.R-project.org/package=C50} } @Manual{mvpart, title = {\pkg{mvpart}: Multivariate Partitioning}, author = {Glenn De'ath}, year = {2014}, note = {\proglang{R} package version 1.6-2}, url = {http://CRAN.R-project.org/package=mvpart} } @Manual{survival, title = {\pkg{survival}: A Package for Survival Analysis in \proglang{S}}, author = {Terry M. Therneau}, year = {2015}, note = {\proglang{R} package version 2.38-3}, url = {http://CRAN.R-project.org/package=survival}, } @TechReport{rpart, author = {Terry M. Therneau and Elizabeth J. Atkinson}, title = {An Introduction to Recursive Partitioning Using the \pkg{rpart} Routine}, year = {1997}, type = {Technical Report}, number = {61}, institution = {Section of Biostatistics, Mayo Clinic, Rochester}, url = {http://www.mayo.edu/hsr/techrpt/61.pdf} } @Article{evtree, author = {Thomas Grubinger and Achim Zeileis and Karl-Peter Pfeiffer}, title = {\pkg{evtree}: Evolutionary Learning of Globally Optimal Classification and Regression Trees in \proglang{R}}, journal = {Journal of Statistical Software}, year = {2014}, volume = {61}, number = {1}, month = {1--29}, doi = {10.18637/jss.v061.i01} } @Article{RWeka, author = {Kurt Hornik and Christian Buchta and Achim Zeileis}, title = {Open-Source Machine Learning: \proglang{R} Meets \pkg{Weka}}, journal = {Computational Statistics}, year = {2009}, volume = {24}, number = {2}, pages = {225--232}, } @Article{Formula, author = {Achim Zeileis and Yves Croissant}, title = {Extended Model Formulas in \proglang{R}: Multiple Parts and Multiple Responses}, journal = {Journal of Statistical Software}, year = {2010}, volume = {34}, number = {1}, pages = {1--13}, doi = {10.18637/jss.v034.i01} } @Article{sandwich, author = {Achim Zeileis}, title = {Object-Oriented Computation of Sandwich Estimators}, year = {2006}, journal = {Journal of Statistical Software}, volume = {16}, number = {9}, pages = {1--16}, doi = {10.18637/jss.v016.i09} } @Article{strucchange, author = {Achim Zeileis and Friedrich Leisch and Kurt Hornik and Christian Kleiber}, title = {\pkg{strucchange}: {A}n \proglang{R} Package for Testing for Structural Change in Linear Regression Models}, journal = {Journal of Statistical Software}, year = {2002}, volume = {7}, number = {2}, pages = {1--38}, doi = {10.18637/jss.v007.i02} } @Article{vcd, author = {David Meyer and Achim Zeileis and Kurt Hornik}, title = {The Strucplot Framework: Visualizing Multi-Way Contingency Tables with \pkg{vcd}}, journal = {Journal of Statistical Software}, year = {2006}, volume = {17}, number = {3}, pages = {1--48}, doi = {10.18637/jss.v017.i03} } @Book{AER, title = {Applied Econometrics with \proglang{R}}, author = {Christian Kleiber and Achim Zeileis}, year = {2008}, publisher = {Springer-Verlag}, address = {New York}, url = {http://CRAN.R-project.org/package=AER} } @Manual{modeltools, title = {\pkg{modeltools}: Tools and Classes for Statistical Models}, author = {Torsten Hothorn and Friedrich Leisch and Achim Zeileis}, year = {2013}, note = {\proglang{R} package version 0.2-21}, url = {http://CRAN.R-project.org/package=modeltools} } @Manual{mlbench, title = {\pkg{mlbench}: Machine Learning Benchmark Problems}, author = {Friedrich Leisch and Evgenia Dimitriadou}, year = {2012}, note = {\proglang{R} package version 2.1-1}, url = {http://CRAN.R-project.org/package=mlbench} } @Manual{pmml, title = {\pkg{pmml}: Generate PMML for Various Models}, author = {Graham Williams and Tridivesh Jena and Michael Hahsler and {Zementis Inc.} and Hemant Ishwaran and Udaya B. Kogalur and Rajarshi Guha}, year = {2014}, note = {\proglang{R} package version 1.4.2}, url = {http://CRAN.R-project.org/package=pmml}, } @Book{rattle, title = {Data Mining with \pkg{rattle} and \proglang{R}: The Art of Excavating Data for Knowledge Discovery}, author = {Graham Williams}, year = {2011}, publisher = {Springer-Verlag}, address = {New York}, url = {http://CRAN.R-project.org/package=rattle}, } @Misc{mlbench2, author = {K. Bache and M. Lichman}, year = {2013}, title = {{UCI} Machine Learning Repository}, url = {http://archive.ics.uci.edu/ml/}, institution = {University of California, Irvine, School of Information and Computer Sciences} } @Misc{ctv, author = {Torsten Hothorn}, title = {{CRAN} Task View: Machine Learning \& Statistical Learning}, year = {2014}, note = {Version~2014-08-30}, url = {https://CRAN.R-project.org/view=MachineLearning}, } @Misc{DMG:2014, author = {{Data Mining Group}}, title = {Predictive Model Markup Language}, year = {2014}, note = {Version~4.2}, url = {http://www.dmg.org/} } @Article{Friendly+Symanzik+Onder:2019, author = {Michael Friendly and J\"urgen Symanzik and Ortac Onder}, title = {Visualising the {T}itanic Disaster}, journal = {Significance}, year = {2019}, volume = {16}, number = {1}, pages = {14--19}, doi = {10.1111/j.1740-9713.2019.01229.x} } @Misc{Lumley:2020, author = {Thomas Lumley}, title = {Weights in Statistics}, year = {2020}, note = {Biased and Inefficient -- Blog post on 2020-08-04}, url = {https://notstatschat.rbind.io/2020/08/04/weights-in-statistics/} } partykit/vignettes/partykit.Rout.save0000644000176200001440000001641714172230001017607 0ustar liggesusers > suppressWarnings(RNGversion("3.5.2")) > options(width = 70) > library("partykit") Loading required package: grid Loading required package: libcoin Loading required package: mvtnorm > set.seed(290875) > data("WeatherPlay", package = "partykit") > WeatherPlay outlook temperature humidity windy play 1 sunny 85 85 false no 2 sunny 80 90 true no 3 overcast 83 86 false yes 4 rainy 70 96 false yes 5 rainy 68 80 false yes 6 rainy 65 70 true no 7 overcast 64 65 true yes 8 sunny 72 95 false no 9 sunny 69 70 false yes 10 rainy 75 80 false yes 11 sunny 75 70 true yes 12 overcast 72 90 true yes 13 overcast 81 75 false yes 14 rainy 71 91 true no > py <- party(partynode(1, split = partysplit(1, index = 1:3), + kids = list(partynode(2, split = partysplit(3, breaks = 75), + kids = l .... [TRUNCATED] > plot(py) > sp_o <- partysplit(1, index = 1:3) > sp_h <- partysplit(3, breaks = 75) > sp_w <- partysplit(4, index = 1:2) > pn <- partynode(1, split = sp_o, kids = list(partynode(2, + split = sp_h, kids = list(partynode(3, info = "yes"), partynode(4, + info .... [TRUNCATED] > pn [1] root | [2] V1 in (-Inf,1] | | [3] V3 <= 75 * | | [4] V3 > 75 * | [5] V1 in (1,2] * | [6] V1 in (2, Inf] | | [7] V4 <= 1 * | | [8] V4 > 1 * > py <- party(pn, WeatherPlay) > print(py) [1] root | [2] outlook in sunny | | [3] humidity <= 75: yes | | [4] humidity > 75: no | [5] outlook in overcast: yes | [6] outlook in rainy | | [7] windy in false: yes | | [8] windy in true: no > predict(py, head(WeatherPlay)) 1 2 3 4 5 6 4 4 5 7 7 8 > length(py) [1] 8 > width(py) [1] 5 > depth(py) [1] 2 > py[6] [6] root | [7] windy in false: yes | [8] windy in true: no > py2 <- py > names(py2) [1] "1" "2" "3" "4" "5" "6" "7" "8" > names(py2) <- LETTERS[1:8] > py2 [A] root | [B] outlook in sunny | | [C] humidity <= 75: yes | | [D] humidity > 75: no | [E] outlook in overcast: yes | [F] outlook in rainy | | [G] windy in false: yes | | [H] windy in true: no > nodeids(py) [1] 1 2 3 4 5 6 7 8 > nodeids(py, terminal = TRUE) [1] 3 4 5 7 8 > nodeapply(py, ids = c(1, 7), FUN = function(n) n$info) $`1` NULL $`7` [1] "yes" > nodeapply(py, ids = nodeids(py, terminal = TRUE), + FUN = function(n) paste("Play decision:", n$info)) $`3` [1] "Play decision: yes" $`4` [1] "Play decision: no" $`5` [1] "Play decision: yes" $`7` [1] "Play decision: yes" $`8` [1] "Play decision: no" > predict(py, FUN = function(n) paste("Play decision:", + n$info)) 1 2 3 "Play decision: no" "Play decision: no" "Play decision: yes" 4 5 6 "Play decision: yes" "Play decision: yes" "Play decision: no" 7 8 9 "Play decision: yes" "Play decision: no" "Play decision: yes" 10 11 12 "Play decision: yes" "Play decision: yes" "Play decision: yes" 13 14 "Play decision: yes" "Play decision: no" > print(py, terminal_panel = function(n) c(", then the play decision is:", + toupper(n$info))) [1] root | [2] outlook in sunny | | [3] humidity <= 75, then the play decision is: | | YES | | [4] humidity > 75, then the play decision is: | | NO | [5] outlook in overcast, then the play decision is: | YES | [6] outlook in rainy | | [7] windy in false, then the play decision is: | | YES | | [8] windy in true, then the play decision is: | | NO > plot(py[6]) > plot(py, tp_args = list(FUN = function(i) c("Play decision:", + toupper(i)))) > nodeprune(py, 2) [1] root | [2] outlook in sunny: * | [3] outlook in overcast: yes | [4] outlook in rainy | | [5] windy in false: yes | | [6] windy in true: no > nodeprune(py, c(2, 6)) [1] root | [2] outlook in sunny: * | [3] outlook in overcast: yes | [4] outlook in rainy: * > sp_h <- partysplit(3, breaks = 75) > class(sp_h) [1] "partysplit" > unclass(sp_h) $varid [1] 3 $breaks [1] 75 $index NULL $right [1] TRUE $prob NULL $info NULL > character_split(sp_h, data = WeatherPlay) $name [1] "humidity" $levels [1] "<= 75" "> 75" > kidids_split(sp_h, data = WeatherPlay) [1] 2 2 2 2 2 1 1 2 1 2 1 2 1 2 > as.numeric(!(WeatherPlay$humidity <= 75)) + 1 [1] 2 2 2 2 2 1 1 2 1 2 1 2 1 2 > sp_o2 <- partysplit(1, index = c(1, 1, 2)) > character_split(sp_o2, data = WeatherPlay) $name [1] "outlook" $levels [1] "sunny, overcast" "rainy" > table(kidids_split(sp_o2, data = WeatherPlay), WeatherPlay$outlook) sunny overcast rainy 1 5 4 0 2 0 0 5 > unclass(sp_o2) $varid [1] 1 $breaks NULL $index [1] 1 1 2 $right [1] TRUE $prob NULL $info NULL > sp_o <- partysplit(1, index = 1:3) > character_split(sp_o, data = WeatherPlay) $name [1] "outlook" $levels [1] "sunny" "overcast" "rainy" > sp_t <- partysplit(2, breaks = c(69.5, 78.8), index = c(1, + 2, 1)) > character_split(sp_t, data = WeatherPlay) $name [1] "temperature" $levels [1] "(-Inf,69.5] | (78.8, Inf]" "(69.5,78.8]" > table(kidids_split(sp_t, data = WeatherPlay), cut(WeatherPlay$temperature, + breaks = c(-Inf, 69.5, 78.8, Inf))) (-Inf,69.5] (69.5,78.8] (78.8, Inf] 1 4 0 4 2 0 6 0 > n1 <- partynode(id = 1) > is.terminal(n1) [1] TRUE > print(n1) [1] root * > n1 <- partynode(id = 1, split = sp_o, kids = lapply(2:4, + partynode)) > print(n1, data = WeatherPlay) [1] root | [2] outlook in sunny * | [3] outlook in overcast * | [4] outlook in rainy * > fitted_node(n1, data = WeatherPlay) [1] 2 2 3 4 4 4 3 2 2 4 2 3 3 4 > kidids_node(n1, data = WeatherPlay) [1] 1 1 2 3 3 3 2 1 1 3 1 2 2 3 > t1 <- party(n1, data = WeatherPlay) > t1 [1] root | [2] outlook in sunny: * | [3] outlook in overcast: * | [4] outlook in rainy: * > party(n1, data = WeatherPlay[0, ]) [1] root | [2] outlook in sunny: * | [3] outlook in overcast: * | [4] outlook in rainy: * > t2 <- party(n1, data = WeatherPlay, fitted = data.frame(`(fitted)` = fitted_node(n1, + data = WeatherPlay), `(response)` = WeatherPlay$play, ch .... [TRUNCATED] > t2 <- as.constparty(t2) > t2 Model formula: play ~ outlook + temperature + humidity + windy Fitted party: [1] root | [2] outlook in sunny: no (n = 5, err = 40.0%) | [3] outlook in overcast: yes (n = 4, err = 0.0%) | [4] outlook in rainy: yes (n = 5, err = 40.0%) Number of inner nodes: 1 Number of terminal nodes: 3 > plot(t2, tnex = 1.5) > nd <- data.frame(outlook = factor(c("overcast", "sunny"), + levels = levels(WeatherPlay$outlook))) > predict(t2, newdata = nd, type = "response") 1 2 yes no Levels: yes no > predict(t2, newdata = nd, type = "prob") yes no 1 1.0 0.0 2 0.4 0.6 > predict(t2, newdata = nd, type = "node") 1 2 3 2 *** Run successfully completed *** > proc.time() user system elapsed 1.502 0.068 1.564 partykit/vignettes/constparty.Rnw0000644000176200001440000007155714172230001017034 0ustar liggesusers\documentclass[nojss]{jss} %\VignetteIndexEntry{Constant Partying: Growing and Handling Trees with Constant Fits} %\VignetteDepends{partykit, rpart, RWeka, pmml, datasets} %\VignetteKeywords{recursive partitioning, regression trees, classification trees, decision trees} %\VignettePackage{partykit} %% packages \usepackage{amstext} \usepackage{amsfonts} \usepackage{amsmath} \usepackage{thumbpdf} \usepackage{rotating} %% need no \usepackage{Sweave} %% additional commands \newcommand{\squote}[1]{`{#1}'} \newcommand{\dquote}[1]{``{#1}''} \newcommand{\fct}[1]{{\texttt{#1()}}} \newcommand{\class}[1]{\dquote{\texttt{#1}}} \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} %% further commands \renewcommand{\Prob}{\mathbb{P} } \renewcommand{\E}{\mathbb{E}} \newcommand{\V}{\mathbb{V}} \newcommand{\Var}{\mathbb{V}} \hyphenation{Qua-dra-tic} \title{Constant Partying: Growing and Handling Trees with Constant Fits} \author{Torsten Hothorn\\Universit\"at Z\"urich \And Achim Zeileis\\Universit\"at Innsbruck} \Plainauthor{Torsten Hothorn, Achim Zeileis} \Abstract{ This vignette describes infrastructure for regression and classification trees with simple constant fits in each of the terminal nodes. Thus, all observations that are predicted to be in the same terminal node also receive the same prediction, e.g., a mean for numeric responses or proportions for categorical responses. This class of trees is very common and includes all traditional tree variants (AID, CHAID, CART, C4.5, FACT, QUEST) and also more recent approaches like CTree. Trees inferred by any of these algorithms could in principle be represented by objects of class \class{constparty} in \pkg{partykit} that then provides unified methods for printing, plotting, and predicting. Here, we describe how one can create \class{constparty} objects by (a)~coercion from other \proglang{R} classes, (b)~parsing of XML descriptions of trees learned in other software systems, (c)~learning a tree using one's own algorithm. } \Keywords{recursive partitioning, regression trees, classification trees, decision trees} \Address{ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/}\\ Achim Zeileis\\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org}\\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} } \begin{document} \setkeys{Gin}{width=\textwidth} \SweaveOpts{engine=R, eps=FALSE, keep.source=TRUE, eval=TRUE} <>= suppressWarnings(RNGversion("3.5.2")) options(width = 70) library("partykit") set.seed(290875) @ \section{Classes and methods} \label{sec:classes} This vignette describes the handling of trees with constant fits in the terminal nodes. This class of regression models includes most classical tree algorithms like AID \citep{Morgan+Sonquist:1963}, CHAID \citep{Kass:1980}, CART \citep{Breiman+Friedman+Olshen:1984}, FACT \citep{Loh+Vanichsetakul1:988}, QUEST \citep{Loh+Shih:1997}, C4.5 \citep{Quinlan:1993}, CTree \citep{Hothorn+Hornik+Zeileis:2006} etc. In this class of tree models, one can compute simple predictions for new observations, such as the conditional mean in a regression setup, from the responses of those learning sample observations in the same terminal node. Therefore, such predictions can easily be computed if the following pieces of information are available: the observed responses in the learning sample, the terminal node IDs assigned to the observations in the learning sample, and potentially associated weights (if any). In \pkg{partykit} it is easy to create a \class{party} object that contains these pieces of information, yielding a \class{constparty} object. The technical details of the \class{party} class are discussed in detail in Section~3.4 of \code{vignette("partykit", package = "partykit")}. In addition to the elements required for any \class{party}, a \class{constparty} needs to have: variables \code{(fitted)} and \code{(response)} (and \code{(weights)} if applicable) in the \code{fitted} data frame along with the \code{terms} for the model. If such a \class{party} has been created, its properties can be checked and coerced to class \class{constparty} by the \fct{as.constparty} function. Note that with such a \class{constparty} object it is possible to compute all kinds of predictions from the subsample in a given terminal node. For example, instead the mean response the median (or any other quantile) could be employed. Similarly, for a categorical response the predicted probabilities (i.e., relative frequencies) can be computed or the corresponding mode or a ranking of the levels etc. In case the full response from the learning sample is not available but only the constant fit from each terminal node, then a \class{constparty} cannot be set up. Specifically, this is the case for trees saved in the XML format PMML \citep[Predictive Model Markup Language,][]{DMG:2014} that does not provide the full learning sample. To also support such constant-fit trees based on simpler information \pkg{partykit} provides the \class{simpleparty} class. Inspired by the PMML format, this requires that the \code{info} of every node in the tree provides list elements \code{prediction}, \code{n}, \code{error}, and \code{distribution}. For classification trees these should contain the following node-specific information: the predicted single predicted factor, the learning sample size, the misclassification error (in \%), and the absolute frequencies of all levels. For regression trees the contents should be: the predicted mean, the learning sample size, the error sum of squares, and \code{NULL}. The function \fct{as.simpleparty} can also coerce \class{constparty} trees to \class{simpleparty} trees by computing the above summary statistics from the full response associated with each node of the tree. The remainder of this vignette consists of the following parts: In Section~\ref{sec:coerce} we assume that the trees were fitted using some other software (either within or outside of \proglang{R}) and we describe how these models can be coerced to \class{party} objects using either the \class{constparty} or \class{simpleparty} class. Emphasize is given to displaying such trees in textual and graphical ways. Subsequently, in Section~\ref{sec:mytree}, we show a simple classification tree algorithm can be easily implemented using the \pkg{partykit} tools, yielding a \class{constparty} object. Section~\ref{sec:prediction} shows how to compute predictions in both scenarios before Section~\ref{sec:conclusion} finally gives a brief conclusion. \section{Coercing tree objects} \label{sec:coerce} For the illustrations, we use the Titanic data set from package \pkg{datasets}, consisting of four variables on each of the $2201$ Titanic passengers: gender (male, female), age (child, adult), and class (1st, 2nd, 3rd, or crew) set up as follows: <>= data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" @ The response variable describes whether or not the passenger survived the sinking of the ship. \subsection{Coercing rpart objects} We first fit a classification tree by means of the the \fct{rpart} function from package \pkg{rpart} \citep{rpart} to this data set (make sure to set \code{model = TRUE}; otherwise \code{model.frame.rpart} will return the \code{rpart} object and not the data): <>= library("rpart") (rp <- rpart(Survived ~ ., data = ttnc, model = TRUE)) @ The \class{rpart} object \code{rp} can be coerced to a \class{constparty} by \fct{as.party}. Internally, this transforms the tree structure of the \class{rpart} tree to a \class{partynode} and combines it with the associated learning sample as described in Section~\ref{sec:classes}. All of this is done automatically by <>= (party_rp <- as.party(rp)) @ Now, instead of the print method for \class{rpart} objects the print method for \code{constparty} objects creates a textual display of the tree structure. In a similar way, the corresponding \fct{plot} method produces a graphical representation of this tree, see Figure~\ref{party_plot}. \begin{figure}[p!] \centering <>= plot(rp) text(rp) @ <>= plot(party_rp) @ \caption{\class{rpart} tree of Titanic data plotted using \pkg{rpart} (top) and \pkg{partykit} (bottom) infrastructure. \label{party_plot}} \end{figure} By default, the \fct{predict} method for \class{rpart} objects computes conditional class probabilities. The same numbers are returned by the \fct{predict} method for \Sexpr{class(party_rp)[1L]} objects with \code{type = "prob"} argument (see Section~\ref{sec:prediction} for more details): <>= all.equal(predict(rp), predict(party_rp, type = "prob"), check.attributes = FALSE) @ Predictions are computed based on the \code{fitted} slot of a \class{constparty} object <>= str(fitted(party_rp)) @ which contains the terminal node numbers and the response for each of the training samples. So, the conditional class probabilities for each terminal node can be computed via <>= prop.table(do.call("table", fitted(party_rp)), 1) @ Optionally, weights can be stored in the \code{fitted} slot as well. \subsection{Coercing J48 objects} The \pkg{RWeka} package \citep{RWeka} provides an interface to the \pkg{Weka} machine learning library and we can use the \fct{J48} function to fit a J4.8 tree to the Titanic data <>= if (require("RWeka")) { j48 <- J48(Survived ~ ., data = ttnc) } else { j48 <- rpart(Survived ~ ., data = ttnc) } print(j48) @ This object can be coerced to a \class{party} object using <>= (party_j48 <- as.party(j48)) @ and, again, the print method from the \pkg{partykit} package creates a textual display. Note that, unlike the \class{rpart} trees, this tree includes multiway splits. The \fct{plot} method draws this tree, see Figure~\ref{J48_plot}. \begin{sidewaysfigure} \centering <>= plot(party_j48) @ \caption{\class{J48} tree of Titanic data plotted using \pkg{partykit} infrastructure. \label{J48_plot}} \end{sidewaysfigure} The conditional class probabilities computed by the \fct{predict} methods implemented in packages \pkg{RWeka} and \pkg{partykit} are equivalent: <>= all.equal(predict(j48, type = "prob"), predict(party_j48, type = "prob"), check.attributes = FALSE) @ In addition to \fct{J48} \pkg{RWeka} provides several other tree learners, e.g., \fct{M5P} implementing M5' and \fct{LMT} implementing logistic model trees, respectively. These can also be coerced using \fct{as.party}. However, as these are not constant-fit trees this yields plain \class{party} trees with some character information stored in the \code{info} slot. \subsection{Importing trees from PMML files} The previous two examples showed how trees learned by other \proglang{R} packages can be handled in a unified way using \pkg{partykit}. Additionally, \pkg{partykit} can also be used to import trees from any other software package that supports the PMML (Predictive Model Markup Language) format. As an example, we used \proglang{SPSS} to fit a QUEST tree to the Titanic data and exported this from \proglang{SPSS} in PMML format. This file is shipped along with the \pkg{partykit} package and we can read it as follows: <>= ttnc_pmml <- file.path(system.file("pmml", package = "partykit"), "ttnc.pmml") (ttnc_quest <- pmmlTreeModel(ttnc_pmml)) @ % \begin{figure}[t!] \centering <>= plot(ttnc_quest) @ \caption{QUEST tree for Titanic data, fitted using \proglang{SPSS} and exported via PMML. \label{PMML-Titanic-plot1}} \end{figure} % The object \code{ttnc_quest} is of class \class{simpleparty} and the corresponding graphical display is shown in Figure~\ref{PMML-Titanic-plot1}. As explained in Section~\ref{sec:classes}, the full learning data are not part of the PMML description and hence one can only obtain and display the summarized information provided by PMML. In this particular case, however, we have the learning data available in \proglang{R} because we had exported the data from \proglang{R} to begin with. Hence, for this tree we can augment the \class{simpleparty} with the full learning sample to create a \class{constparty}. As \proglang{SPSS} had reordered some factor levels we need to carry out this reordering as well" <>= ttnc2 <- ttnc[, names(ttnc_quest$data)] for(n in names(ttnc2)) { if(is.factor(ttnc2[[n]])) ttnc2[[n]] <- factor( ttnc2[[n]], levels = levels(ttnc_quest$data[[n]])) } @ % Using this data all information for a \class{constparty} can be easily computed: % <>= ttnc_quest2 <- party(ttnc_quest$node, data = ttnc2, fitted = data.frame( "(fitted)" = predict(ttnc_quest, ttnc2, type = "node"), "(response)" = ttnc2$Survived, check.names = FALSE), terms = terms(Survived ~ ., data = ttnc2) ) ttnc_quest2 <- as.constparty(ttnc_quest2) @ This object is plotted in Figure~\ref{PMML-Titanic-plot2}. \begin{figure}[t!] \centering <>= plot(ttnc_quest2) @ \caption{QUEST tree for Titanic data, fitted using \proglang{SPSS}, exported via PMML, and transformed into a \class{constparty} object. \label{PMML-Titanic-plot2}} \end{figure} Furthermore, we briefly point out that there is also the \proglang{R} package \pkg{pmml} \citep{pmml}, part of the \pkg{rattle} project \citep{rattle}, that allows to export PMML files for \pkg{rpart} trees from \proglang{R}. For example, for the \class{rpart} tree for the Titanic data: <>= library("pmml") tfile <- tempfile() write(toString(pmml(rp)), file = tfile) @ Then, we can simply read this file and inspect the resulting tree <>= (party_pmml <- pmmlTreeModel(tfile)) all.equal(predict(party_rp, newdata = ttnc, type = "prob"), predict(party_pmml, newdata = ttnc, type = "prob"), check.attributes = FALSE) @ Further example PMML files created with \pkg{rattle} are the Data Mining Group web page, e.g., \url{http://www.dmg.org/pmml_examples/rattle_pmml_examples/AuditTree.xml} or \url{http://www.dmg.org/pmml_examples/rattle_pmml_examples/IrisTree.xml}. \section{Growing a simple classification tree} \label{sec:mytree} Although the \pkg{partykit} package offers an extensive toolbox for handling trees along with implementations of various tree algorithms, it does not offer unified infrastructure for \emph{growing} trees. However, once you know how to estimate splits from data, it is fairly straightforward to implement trees. Consider a very simple CHAID-style algorithm (in fact so simple that we would advise \emph{not to use it} for any real application). We assume that both response and explanatory variables are factors, as for the Titanic data set. First we determine the best explanatory variable by means of a global $\chi^2$ test, i.e., splitting up the response into all levels of each explanatory variable. Then, for the selected explanatory variable we search for the binary best split by means of $\chi^2$ tests, i.e., we cycle through all potential split points and assess the quality of the split by comparing the distributions of the response in the so-defined two groups. In both cases, we select the split variable/point with lowest $p$-value from the $\chi^2$ test, however, only if the global test is significant at Bonferroni-corrected level $\alpha = 0.01$. This strategy can be implemented based on the data (response and explanatory variables) and some case weights as follows (\code{response} is just the name of the response and \code{data} is a data frame with all variables): <>= findsplit <- function(response, data, weights, alpha = 0.01) { ## extract response values from data y <- factor(rep(data[[response]], weights)) ## perform chi-squared test of y vs. x mychisqtest <- function(x) { x <- factor(x) if(length(levels(x)) < 2) return(NA) ct <- suppressWarnings(chisq.test(table(y, x), correct = FALSE)) pchisq(ct$statistic, ct$parameter, log = TRUE, lower.tail = FALSE) } xselect <- which(names(data) != response) logp <- sapply(xselect, function(i) mychisqtest(rep(data[[i]], weights))) names(logp) <- names(data)[xselect] ## Bonferroni-adjusted p-value small enough? if(all(is.na(logp))) return(NULL) minp <- exp(min(logp, na.rm = TRUE)) minp <- 1 - (1 - minp)^sum(!is.na(logp)) if(minp > alpha) return(NULL) ## for selected variable, search for split minimizing p-value xselect <- xselect[which.min(logp)] x <- rep(data[[xselect]], weights) ## set up all possible splits in two kid nodes lev <- levels(x[drop = TRUE]) if(length(lev) == 2) { splitpoint <- lev[1] } else { comb <- do.call("c", lapply(1:(length(lev) - 2), function(x) combn(lev, x, simplify = FALSE))) xlogp <- sapply(comb, function(q) mychisqtest(x %in% q)) splitpoint <- comb[[which.min(xlogp)]] } ## split into two groups (setting groups that do not occur to NA) splitindex <- !(levels(data[[xselect]]) %in% splitpoint) splitindex[!(levels(data[[xselect]]) %in% lev)] <- NA_integer_ splitindex <- splitindex - min(splitindex, na.rm = TRUE) + 1L ## return split as partysplit object return(partysplit(varid = as.integer(xselect), index = splitindex, info = list(p.value = 1 - (1 - exp(logp))^sum(!is.na(logp))))) } @ In order to actually grow a tree on data, we have to set up the recursion for growing a recursive \class{partynode} structure: <>= growtree <- function(id = 1L, response, data, weights, minbucket = 30) { ## for less than 30 observations stop here if (sum(weights) < minbucket) return(partynode(id = id)) ## find best split sp <- findsplit(response, data, weights) ## no split found, stop here if (is.null(sp)) return(partynode(id = id)) ## actually split the data kidids <- kidids_split(sp, data = data) ## set up all daugther nodes kids <- vector(mode = "list", length = max(kidids, na.rm = TRUE)) for (kidid in 1:length(kids)) { ## select observations for current node w <- weights w[kidids != kidid] <- 0 ## get next node id if (kidid > 1) { myid <- max(nodeids(kids[[kidid - 1]])) } else { myid <- id } ## start recursion on this daugther node kids[[kidid]] <- growtree(id = as.integer(myid + 1), response, data, w) } ## return nodes return(partynode(id = as.integer(id), split = sp, kids = kids, info = list(p.value = min(info_split(sp)$p.value, na.rm = TRUE)))) } @ A very rough sketch of a formula-based user-interface sets-up the data and calls \fct{growtree}: <>= mytree <- function(formula, data, weights = NULL) { ## name of the response variable response <- all.vars(formula)[1] ## data without missing values, response comes last data <- data[complete.cases(data), c(all.vars(formula)[-1], response)] ## data is factors only stopifnot(all(sapply(data, is.factor))) if (is.null(weights)) weights <- rep(1L, nrow(data)) ## weights are case weights, i.e., integers stopifnot(length(weights) == nrow(data) & max(abs(weights - floor(weights))) < .Machine$double.eps) ## grow tree nodes <- growtree(id = 1L, response, data, weights) ## compute terminal node number for each observation fitted <- fitted_node(nodes, data = data) ## return rich constparty object ret <- party(nodes, data = data, fitted = data.frame("(fitted)" = fitted, "(response)" = data[[response]], "(weights)" = weights, check.names = FALSE), terms = terms(formula)) as.constparty(ret) } @ The call to the constructor \fct{party} sets-up a \class{party} object with the tree structure contained in \code{nodes}, the training samples in \code{data} and the corresponding \code{terms} object. Class \class{constparty} inherits all slots from class \class{party} and has an additional \code{fitted} slot for storing the terminal node numbers for each sample in the training data, the response variable(s) and case weights. The \code{fitted} slot is a \class{data.frame} containing three variables: The fitted terminal node identifiers \code{"(fitted)"}, an integer vector of the same length as \code{data}; the response variables \code{"(response)"} as a vector (or \code{data.frame} for multivariate responses) with the same number of observations; and optionally a vector of weights \code{"(weights)"}. The additional \code{fitted} slot allows to compute arbitrary summary measures for each terminal node by simply subsetting the \code{"(response)"} and \code{"(weights)"} slots by \code{"(fitted)"} before computing (weighted) means, medians, empirical cumulative distribution functions, Kaplan-Meier estimates or whatever summary statistic might be appropriate for a certain response. The \fct{print}, \fct{plot}, and \fct{predict} methods for class \class{constparty} work this way with suitable defaults for the summary statistics depending on the class of the response(s). We now can fit this tree to the Titanic data; the \fct{print} method provides us with a first overview on the resulting model <>= (myttnc <- mytree(Survived ~ Class + Age + Gender, data = ttnc)) @ % \begin{figure}[t!] \centering <>= plot(myttnc) @ \caption{Classification tree fitted by the \fct{mytree} function to the \code{ttnc} data. \label{plottree}} \end{figure} % Of course, we can immediately use \code{plot(myttnc)} to obtain a graphical representation of this tree, the result is given in Figure~\ref{plottree}. The default behavior for trees with categorical responses is simply inherited from \class{constparty} and hence we readily obtain bar plots in all terminal nodes. As the tree is fairly large, we might be interested in pruning the tree to a more reasonable size. For this purpose the \pkg{partykit} package provides the \fct{nodeprune} function that can prune back to nodes with selected IDs. As \fct{nodeprune} (by design) does not provide a specific pruning criterion, we need to determine ourselves which nodes to prune. Here, one idea could be to impose significance at a higher level than the default $10^{-2}$ -- say $10^{-5}$ to obtain a strongly pruned tree. Hence we use \fct{nodeapply} to extract the minimal Bonferroni-corrected $p$-value from all inner nodes: % <>= nid <- nodeids(myttnc) iid <- nid[!(nid %in% nodeids(myttnc, terminal = TRUE))] (pval <- unlist(nodeapply(myttnc, ids = iid, FUN = function(n) info_node(n)$p.value))) @ Then, the pruning of the nodes with the larger $p$-values can be simply carried out by % <>= myttnc2 <- nodeprune(myttnc, ids = iid[pval > 1e-5]) @ % The corresponding visualization is shown in Figure~\ref{prunetree}. \setkeys{Gin}{width=0.85\textwidth} \begin{figure}[t!] \centering <>= plot(myttnc2) @ \caption{Pruned classification tree fitted by the \fct{mytree} function to the \code{ttnc} data. \label{prunetree}} \end{figure} \setkeys{Gin}{width=\textwidth} The accuracy of the tree built using the default options could be assessed by the bootstrap, for example. Here, we want to compare our tree for the Titanic survivor data with a simple logistic regression model. First, we fit this simple GLM and compute the (in-sample) log-likelihood: <>= logLik(glm(Survived ~ Class + Age + Gender, data = ttnc, family = binomial())) @ For our tree, we set-up $25$ bootstrap samples <>= bs <- rmultinom(25, nrow(ttnc), rep(1, nrow(ttnc)) / nrow(ttnc)) @ and implement the log-likelihood of a binomal model <>= bloglik <- function(prob, weights) sum(weights * dbinom(ttnc$Survived == "Yes", size = 1, prob[,"Yes"], log = TRUE)) @ What remains to be done is to iterate over all bootstrap samples, to refit the tree on the bootstrap sample and to evaluate the log-likelihood on the out-of-bootstrap samples based on the trees' predictions (details on how to compute predictions are given in the next section): <>= f <- function(w) { tr <- mytree(Survived ~ Class + Age + Gender, data = ttnc, weights = w) bloglik(predict(tr, newdata = ttnc, type = "prob"), as.numeric(w == 0)) } apply(bs, 2, f) @ We see that the in-sample log-likelihood of the linear logistic regression model is much smaller than the out-of-sample log-likelihood found for our tree and thus we can conclude that our tree-based approach fits data the better than the linear model. \section{Predictions} \label{sec:prediction} As argued in Section~\ref{sec:classes} arbitrary types of predictions can be computed from \class{constparty} objects because the full empirical distribution of the response in the learning sample nodes is available. All of these can be easily computed in the \fct{predict} method for \class{constparty} objects by supplying a suitable aggregation function. However, as certain types of predictions are much more commonly used, these are available even more easily by setting a \code{type} argument. \begin{table}[b!] \centering \begin{tabular}{llll} \hline Response class & \code{type = "node"} & \code{type = "response"} & \code{type = "prob"} \\ \hline \class{factor} & terminal node number & majority class & class probabilities \\ \class{numeric} & terminal node number & mean & ECDF \\ \class{Surv} & terminal node number & median survival time & Kaplan-Meier \\ \hline \end{tabular} \caption{Overview on type of predictions computed by the \fct{predict} method for \class{constparty} objects. For multivariate responses, combinations thereof are returned. \label{predict-type}} \end{table} The prediction \code{type} can either be \code{"node"}, \code{"response"}, or \code{"prob"} (see Table~\ref{predict-type}). The idea is that \code{"response"} always returns a prediction of the same class as the original response and \code{"prob"} returns some object that characterizes the entire empirical distribution. Hence, for different response classes, different types of predictions are produced, see Table~\ref{predict-type} for an overview. Additionally, for \class{numeric} responses \code{type = "quantile"} and \code{type = "density"} is available. By default, these return functions for computing predicted quantiles and probability densities, respectively, but optionally these functions can be directly evaluated \code{at} given values and then return a vector/matrix. Here, we illustrate all different predictions for all possible combinations of the explanatory factor levels. <>= nttnc <- expand.grid(Class = levels(ttnc$Class), Gender = levels(ttnc$Gender), Age = levels(ttnc$Age)) nttnc @ The corresponding predicted nodes, modes, and probability distributions are: <>= predict(myttnc, newdata = nttnc, type = "node") predict(myttnc, newdata = nttnc, type = "response") predict(myttnc, newdata = nttnc, type = "prob") @ Furthermore, the \fct{predict} method features a \code{FUN} argument that can be used to compute customized predictions. If we are, say, interested in the rank of the probabilities for the two classes, we can simply specify a function that implements this feature: <>= predict(myttnc, newdata = nttnc, FUN = function(y, w) rank(table(rep(y, w)))) @ The user-supplied function \code{FUN} takes two arguments, \code{y} is the response and \code{w} is a vector of weights (case weights in this situation). Of course, it would have been easier to do these computations directly on the conditional class probabilities (\code{type = "prob"}), but the approach taken here for illustration generalizes to situations where this is not possible, especially for numeric responses. \section{Conclusion} \label{sec:conclusion} The classes \class{constparty} and \class{simpleparty} introduced here can be used to represent trees with constant fits in the terminal nodes, including most of the traditional tree variants. For a number of implementations it is possible to convert the resulting trees to one of these classes, thus offering unified methods for handling constant-fit trees. User-extensible methods for printing and plotting these trees are available. Also, computing non-standard predictions, such as the median or empirical cumulative distribution functions, is easily possible within this framework. With the infrastructure provided in \pkg{partykit} it is rather straightforward to implement a new (or old) tree algorithm and therefore a prototype implementation of fancy ideas for improving trees is only a couple lines of \proglang{R} code away. \bibliography{party} \end{document} partykit/vignettes/mob.Rnw0000644000176200001440000024212114172230001015366 0ustar liggesusers\documentclass[nojss]{jss} \usepackage{amsmath,thumbpdf} \shortcites{mvtnorm} %% commands \newcommand{\ui}{\underline{i}} \newcommand{\oi}{\overline{\imath}} \newcommand{\argmin}{\operatorname{argmin}\displaylimits} \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} \newcommand{\class}[1]{`\texttt{#1}'} %% neet no \usepackage{Sweave} \SweaveOpts{engine=R, eps=FALSE, keep.source=TRUE} <>= suppressWarnings(RNGversion("3.5.2")) library("partykit") options(prompt = "R> ", continue = "+ ", digits = 4, useFancyQuotes = FALSE) @ %\VignetteIndexEntry{Parties, Models, Mobsters: A New Implementation of Model-Based Recursive Partitioning in R} %\VignetteDepends{AER,Formula,mlbench,sandwich,strucchange,survival,TH.data,vcd,psychotools,psychotree} %\VignetteKeywords{parametric models, object-orientation, recursive partitioning} %\VignettePackage{partykit} \author{Achim Zeileis\\Universit\"at Innsbruck \And Torsten Hothorn\\Universit\"at Z\"urich} \Plainauthor{Achim Zeileis, Torsten Hothorn} \title{Parties, Models, Mobsters: A New Implementation of Model-Based Recursive Partitioning in \proglang{R}} \Plaintitle{Parties, Models, Mobsters: A New Implementation of Model-Based Recursive Partitioning in R} \Shorttitle{Model-Based Recursive Partitioning in \proglang{R}} \Keywords{parametric models, object-orientation, recursive partitioning} \Abstract{ MOB is a generic algorithm for \underline{mo}del-\underline{b}ased recursive partitioning \citep{Zeileis+Hothorn+Hornik:2008}. Rather than fitting one global model to a dataset, it estimates local models on subsets of data that are ``learned'' by recursively partitioning. It proceeds in the following way: (1)~fit a parametric model to a data set, (2)~test for parameter instability over a set of partitioning variables, (3)~if there is some overall parameter instability, split the model with respect to the variable associated with the highest instability, (4)~repeat the procedure in each of the resulting subsamples. It is discussed how these steps of the conceptual algorithm are translated into computational tools in an object-oriented manner, allowing the user to plug in various types of parametric models. For representing the resulting trees, the \proglang{R} package \pkg{partykit} is employed and extended with generic infrastructure for recursive partitions where nodes are associated with statistical models. Compared to the previously available implementation in the \pkg{party} package, the new implementation supports more inference options, is easier to extend to new models, and provides more convenience features. } \Address{ Achim Zeileis \\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org} \\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} \\ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/}\\ } \begin{document} \section{Overview} To implement the model-based recursive partitioning (MOB) algorithm of \cite{Zeileis+Hothorn+Hornik:2008} in software, infrastructure for three aspects is required: (1)~statistical ``\emph{models}'', (2)~recursive ``\emph{party}''tions, and (3)~``\emph{mobsters}'' carrying out the MOB algorithm. Along with \cite{Zeileis+Hothorn+Hornik:2008}, an implementation of all three steps was provided in the \pkg{party} package \citep{party} for the \proglang{R} system for statistical computing \citep{R}. This provided one very flexible \code{mob()} function combining \pkg{party}'s \proglang{S}4 classes for representing trees with binary splits and the \proglang{S}4 model wrapper functions from \pkg{modeltools} \citep{modeltools}. However, while this supported many applications of interest, it was somewhat limited in several directions: (1)~The \proglang{S}4 wrappers for the models were somewhat cumbersome to set up. (2)~The tree infrastructure was originally designed for \code{ctree()} and somewhat too narrowly focused on it. (3)~Writing new ``mobster'' interfaces was not easy because of using unexported \proglang{S}4 classes. Hence, a leaner and more flexible interface (based on \proglang{S}3 classes) is now provided in \pkg{partykit} \citep{partykit}: (1)~New models are much easier to provide in a basic version and customization does not require setting up an additional \proglang{S}4 class-and-methods layer anymore. (2)~The trees are built on top of \pkg{partykit}'s flexible `\code{party}' objects, inheriting many useful methods and providing new ones dealing with the fitted models associated with the tree's nodes. (3)~New ``mobsters'' dedicated to specific models, e.g., \code{lmtree()} and \code{glmtree()} for MOBs of (generalized) linear models, are readily provided. The remainder of this vignette is organized as follows: Section~\ref{sec:algorithm} very briefly reviews the original MOB algorithm of \cite{Zeileis+Hothorn+Hornik:2008} and also highlights relevant subsequent work. Section~\ref{sec:implementation} introduces the new \code{mob()} function in \pkg{partykit} in detail, discussing how all steps of the MOB algorithm are implemented and which options for customization are available. For illustration logistic-regression-based recursive partitioning is applied to the Pima Indians diabetes data set from the UCI machine learning repository \citep{mlbench2}. Section~\ref{sec:illustration} and~\ref{sec:mobster} present further illustrative examples \citep[including replications from][]{Zeileis+Hothorn+Hornik:2008} before Section~\ref{sec:conclusion} provides some concluding remarks. \section{MOB: Model-based recursive partitioning} \label{sec:algorithm} First, the theory underling the MOB (model-based recursive partitioning) is briefly reviewed; a more detailed discussion is provided by \cite{Zeileis+Hothorn+Hornik:2008}. To fix notation, consider a parametric model $\mathcal{M}(Y, \theta)$ with (possibly vector-valued) observations $Y$ and a $k$-dimensional vector of parameters $\theta$. This model could be a (possibly multivariate) normal distribution for $Y$, a psychometric model for a matrix of responses $Y$, or some kind of regression model when $Y = (y, x)$ can be split up into a dependent variable $y$ and regressors $x$. An example for the latter could be a linear regression model $y = x^\top \theta$ or a generalized linear model (GLM) or a survival regression. Given $n$ observations $Y_i$ ($i = 1, \dots, n$) the model can be fitted by minimizing some objective function $\sum_{i = 1}^n \Psi(Y_i, \theta)$, e.g., a residual sum of squares or a negative log-likelihood leading to ordinary least squares (OLS) or maximum likelihood (ML) estimation, respectively. If a global model for all $n$ observations does not fit well and further covariates $Z_1, \dots, Z_\ell$ are available, it might be possible to partition the $n$ observations with respect to these variables and find a fitting local model in each cell of the partition. The MOB algorithm tries to find such a partition adaptively using a greedy forward search. The reasons for looking at such local models might be different for different types of models: First, the detection of interactions and nonlinearities in regression relationships might be of interest just like in standard classification and regression trees \citep[see e.g.,][]{Zeileis+Hothorn+Hornik:2008}. Additionally, however, this approach allows to add explanatory variables to models that otherwise do not have regressors or where the link between the regressors and the parameters of the model is inclear \citep[this idea is pursued by][]{Strobl+Wickelmaier+Zeileis:2011}. Finally, the model-based tree can be employed as a thorough diagnostic test of the parameter stability assumption (also termed measurement invariance in psychometrics). If the tree does not split at all, parameter stability (or measurement invariance) cannot be rejected while a tree with splits would indicate in which way the assumption is violated \citep[][employ this idea in psychometric item response theory models]{Strobl+Kopf+Zeileis:2015}. The basic idea is to grow a tee in which every node is associated with a model of type $\mathcal{M}$. To assess whether splitting of the node is necessary a fluctuation test for parameter instability is performed. If there is significant instability with respect to any of the partitioning variables $Z_j$, the node is splitted into $B$ locally optimal segments (the currenct version of the software has $B = 2$ as the default and as the only option for numeric/ordered variables) and then the procedure is repeated in each of the $B$ children. If no more significant instabilities can be found, the recursion stops. More precisely, the steps of the algorithm are % \begin{enumerate} \item Fit the model once to all observations in the current node. \item Assess whether the parameter estimates are stable with respect to every partitioning variable $Z_1, \dots, Z_\ell$. If there is some overall instability, select the variable $Z_j$ associated with the highest parameter instability, otherwise stop. \item Compute the split point(s) that locally optimize the objective function $\Psi$. \item Split the node into child nodes and repeat the procedure until some stopping criterion is met. \end{enumerate} % This conceptual framework is extremely flexible and allows to adapt it to various tasks by choosing particular models, tests, and methods in each of the steps: % \begin{enumerate} \item \emph{Model estimation:} The original MOB introduction \citep{Zeileis+Hothorn+Hornik:2008} discussed regression models: OLS regression, GLMs, and survival regression. Subsequently, \cite{Gruen+Kosmidis+Zeileis:2012} have also adapted MOB to beta regression for limited response variables. Furthermore, MOB provides a generic way of adding covariates to models that otherwise have no regressors: this can either serve as a check whether the model is indeed independent from regressors or leads to local models for subsets. Both views are of interest when employing MOB to detect parameter instabilities in psychometric models for item responses such as the Bradley-Terry or the Rasch model \citep[see][respectively]{Strobl+Wickelmaier+Zeileis:2011,Strobl+Kopf+Zeileis:2015}. \item \emph{Parameter instability tests:} To assess the stability of all model parameters across a certain partitioning variable, the general class of score-based fluctuation tests proposed by \cite{Zeileis+Hornik:2007} is employed. Based on the empirical score function observations (i.e., empirical estimating functions or contributions to the gradient), ordered with respect to the partitioning variable, the fluctuation or instability in the model's parameters can be tested. From this general framework the Andrews' sup\textit{LM} test is used for assessing numerical partitioning variables and a $\chi^2$ test for categorical partitioning variables (see \citealp{Zeileis:2005} and \citealp{Merkle+Zeileis:2013} for unifying views emphasizing regression and psychometric models, respectively). Furthermore, the test statistics for ordinal partitioning variables suggested by \cite{Merkle+Fan+Zeileis:2014} have been added as further options (but are not used by default as the simulation of $p$-values is computationally demanding). \item \emph{Partitioning:} As the objective function $\Psi$ is additive, it is easy to compute a single optimal split point (or cut point or break point). For each conceivable split, the model is estimated on the two resulting subsets and the resulting objective functions are summed. The split that optimizes this segmented objective function is then selected as the optimal split. For optimally splitting the data into $B > 2$ segments, the same idea can be used and a full grid search can be avoided by employing a dynamic programming algorithms \citep{Hawkins:2001,Bai+Perron:2003} but at the moment the latter is not implemented in the software. Optionally, however, categorical partitioning variables can be split into all of their categories (i.e., in that case $B$ is set to the number of levels without searching for optimal groupings). \item \emph{Pruning:} For determining the optimal size of the tree, one can either use a pre-pruning or post-pruning strategy. For the former, the algorithm stops when no significant parameter instabilities are detected in the current node (or when the node becomes too small). For the latter, one would first grow a large tree (subject only to a minimal node size requirement) and then prune back splits that did not improve the model, e.g., judging by information criteria such as AIC or BIC \citep[see e.g.,][]{Su+Wang+Fan:2004}. Currently, pre-pruning is used by default (via Bonferroni-corrected $p$-values from the score-based fluctuation tests) but AIC/BIC-based post-pruning is optionally available (especially for large data sets where traditional significance levels are not useful). \end{enumerate} % In the following it is discussed how most of the options above are embedded in a common computational framework using \proglang{R}'s facilities for model estimation and object orientation. \section[A new implementation in R]{A new implementation in \proglang{R}} \label{sec:implementation} This section introduces a new implementation of the general model-based recursive partitioning (MOB) algorithm in \proglang{R}. Along with \cite{Zeileis+Hothorn+Hornik:2008}, a function \code{mob()} had been introduced to the \pkg{party} package \citep{party} which continues to work but it turned out to be somewhat unflexible for certain applications/extensions. Hence, the \pkg{partykit} package \citep{partykit} provides a completely rewritten (and not backward compatible) implementation of a new \code{mob()} function along with convenience interfaces \code{lmtree()} and \code{glmtree()} for fitting linear model and generalized linear model trees, respectively. The function \code{mob()} itself is intended to be the workhorse function that can also be employed to quickly explore new models -- whereas \code{lmtree()} and \code{glmtree()} will be the typical user interfaces facilitating applications. The new \code{mob()} function has the following arguments: \begin{Code} mob(formula, data, subset, na.action, weights, offset, fit, control = mob_control(), ...) \end{Code} All arguments in the first line are standard for modeling functions in \proglang{R} with a \code{formula} interface. They are employed by \code{mob()} to do some data preprocessing (described in detail in Section~\ref{sec:formula}) before the \code{fit} function is used for parameter estimation on the preprocessed data. The \code{fit} function has to be set up in a certain way (described in detail in Section~\ref{sec:fit}) so that \code{mob()} can extract all information that is needed in the MOB algorithm for parameter instability tests (see Section~\ref{sec:sctest}) and partitioning/splitting (see Section~\ref{sec:split}), i.e., the estimated parameters, the associated objective function, and the score function contributions. A list of \code{control} options can be set up by the \code{mob_control()} function, including options for pruning (see Section~\ref{sec:prune}). Additional arguments \code{...} are passed on to the \code{fit} function. The result is an object of class `\code{modelparty}' inheriting from `\code{party}'. The \code{info} element of the overall `\code{party}' and the individual `\code{node}'s contain various informations about the models. Details are provided in Section~\ref{sec:object}. Finally, a wide range of standard (and some extra) methods are available for working with `\code{modelparty}' objects, e.g., for extracting information about the models, for visualization, computing predictions, etc. The standard set of methods is introduced in Section~\ref{sec:methods}. However, as will be discussed there, it may take some effort by the user to efficiently compute certain pieces of information. Hence, convenience interfaces such as \code{lmtree()} or \code{glmtree()} can alleviate these obstacles considerably, as illustrated in Section~\ref{sec:interface}. \subsection{Formula processing and data preparation} \label{sec:formula} The formula processing within \code{mob()} is essentially done in ``the usual way'', i.e., there is a \code{formula} and \code{data} and optionally further arguments such as \code{subset}, \code{na.action}, \code{weights}, and \code{offset}. These are processed into a \code{model.frame} from which the response and the covariates can be extracted and passed on to the actual \code{fit} function. As there are possibly three groups of variables (response, regressors, and partitioning variables), the \pkg{Formula} package \citep{Formula} is employed for processing these three parts. Thus, the formula can be of type \verb:y ~ x1 + ... + xk | z1 + ... + zl: where the variables on the left of the \code{|} specify the data $Y$ and the variables on the right specify the partitioning variables $Z_j$. As pointed out above, the $Y$ can often be split up into response (\code{y} in the example above) and regressors (\code{x1}, \dots, \code{xk} in the example above). If there are no regressors and just constant fits are employed, then the formula can be specified as \verb:y ~ 1 | z1 + ... + zl:. So far, this formula representation is really just a specification of groups of variables and does not imply anything about the type of model that is to be fitted to the data in the nodes of the tree. The \code{mob()} function does not know anything about the type of model and just passes (subsets of) the \code{y} and \code{x} variables on to the \code{fit} function. Only the partitioning variables \code{z} are used internally for the parameter instability tests (see Section~\ref{sec:sctest}). As different \code{fit} functions will require the data in different formats, \code{mob_control()} allows to set the \code{ytype} and \code{xtype}. The default is to assume that \code{y} is just a single column of the model frame that is extracted as a \code{ytype = "vector"}. Alternatively, it can be a \code{"data.frame"} of all response variables or a \code{"matrix"} set up via \code{model.matrix()}. The options \code{"data.frame"} and \code{"matrix"} are also available for \code{xtype} with the latter being the default. Note that if \code{"matrix"} is used, then transformations (e.g., logs, square roots etc.) and dummy/interaction codings are computed and turned into columns of a numeric matrix while for \code{"data.frame"} the original variables are preserved. By specifying the \code{ytype} and \code{xtype}, \code{mob()} is also provided with the information on how to correctly subset \code{y} and \code{x} when recursively partitioning data. In each step, only the subset of \code{y} and \code{x} pertaining to the current node of the tree is passed on to the \code{fit} function. Similarly, subsets of \code{weights} and \code{offset} are passed on (if specified). \subsubsection*{Illustration} For illustration, we employ the popular benchmark data set on diabetes among Pima Indian women that is provided by the UCI machine learning repository \citep{mlbench2} and available in the \pkg{mlbench} package \citep{mlbench}: % <>= data("PimaIndiansDiabetes", package = "mlbench") @ % Following \cite{Zeileis+Hothorn+Hornik:2008} we want to fit a model for \code{diabetes} employing the plasma glucose concentration \code{glucose} as a regressor. As the influence of the remaining variables on \code{diabetes} is less clear, their relationship should be learned by recursive partitioning. Thus, we employ the following formula: % <>= pid_formula <- diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age @ % Before passing this to \code{mob()}, a \code{fit} function is needed and a logistic regression function is set up in the following section. \subsection{Model fitting and parameter estimation} \label{sec:fit} The \code{mob()} function itself does not actually carry out any parameter estimation by itself, but assumes that one of the many \proglang{R} functions available for model estimation is supplied. However, to be able to carry out the steps of the MOB algorithm, \code{mob()} needs to able to extract certain pieces of information: especially the estimated parameters, the corresponding objective function, and associated score function contributions. Also, the interface of the fitting function clearly needs to be standardized so that \code{mob()} knows how to invoke the model estimation. Currently, two possible interfaces for the \code{fit} function can be employed: % \begin{enumerate} \item The \code{fit} function can take the following inputs \begin{Code} fit(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ..., estfun = FALSE, object = FALSE) \end{Code} where \code{y}, \code{x}, \code{weights}, \code{offset} are (the subset of) the preprocessed data. In \code{start} starting values for the parameter estimates may be supplied and \code{...} is passed on from the \code{mob()} function. The \code{fit} function then has to return an output list with the following elements: \begin{itemize} \item \code{coefficients}: Estimated parameters $\hat \theta$. \item \code{objfun}: Value of the minimized objective function $\sum_i \Psi(y_i, x_, \hat \theta)$. \item \code{estfun}: Empirical estimating functions (or score function contributions) $\Psi'(y_i, x_i, \hat \theta)$. Only needed if \code{estfun = TRUE}, otherwise optionally \code{NULL}. \item \code{object}: A model object for which further methods could be available (e.g., \code{predict()}, or \code{fitted()}, etc.). Only needed if \code{object = TRUE}, otherwise optionally \code{NULL}. \end{itemize} By making \code{estfun} and \code{object} optional, the fitting function might be able to save computation time by only optimizing the objective function but avoiding further computations (such as setting up covariance matrix, residuals, diagnostics, etc.). \item The \code{fit} function can also of a simpler interface with only the following inputs: \begin{Code} fit(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ...) \end{Code} The meaning of all arguments is the same as above. However, in this case \code{fit} needs to return a classed model object for which methods to \code{coef()}, \code{logLik()}, and \code{estfun()} \citep[see][and the \pkg{sandwich} package]{sandwich} are available for extracting the parameter estimates, the maximized log-likelihood, and associated empirical estimating functions (or score contributions), respectively. Internally, a function of type (1) is set up by \code{mob()} in case a function of type (2) is supplied. However, as pointed out above, a function of type (1) might be useful to save computation time. \end{enumerate} % In either case the \code{fit} function can, of course, choose to ignore any arguments that are not applicable, e.g., if the are no regressors \code{x} in the model or if starting values or not supported. The \code{fit} function of type (2) is typically convenient to quickly try out a new type of model in recursive partitioning. However, when writing a new \code{mob()} interface such as \code{lmtree()} or \code{glmtree()}, it will typically be better to use type (1). Similarly, employing supporting starting values in \code{fit} is then recommended to save computation time. \subsubsection*{Illustration} For recursively partitioning the \code{diabetes ~ glucose} relationship (as already set up in the previous section), we employ a logistic regression model. An interface of type (2) can be easily set up: % <>= logit <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { glm(y ~ 0 + x, family = binomial, start = start, ...) } @ % Thus, \code{y}, \code{x}, and the starting values are passed on to \code{glm()} which returns an object of class `\code{glm}' for which all required methods (\code{coef()}, \code{logLik()}, and \code{estfun()}) are available. Using this \code{fit} function and the \code{formula} already set up above the MOB algorithm can be easily applied to the \code{PimaIndiansDiabetes} data: % <>= pid_tree <- mob(pid_formula, data = PimaIndiansDiabetes, fit = logit) @ % The result is a logistic regression tree with three terminal nodes that can be easily visualized via \code{plot(pid_tree)} (see Figure~\ref{fig:pid_tree}) and printed: <>= pid_tree @ % The tree finds three groups of Pima Indian women: \begin{itemize} \item[\#2] Women with low body mass index that have on average a low risk of diabetes, however this increases clearly with glucose level. \item[\#4] Women with average and high body mass index, younger than 30 years, that have a higher avarage risk that also increases with glucose level. \item[\#5] Women with average and high body mass index, older than 30 years, that have a high avarage risk that increases only slowly with glucose level. \end{itemize} Note that the example above is used for illustration here and \code{glmtree()} is recommended over using \code{mob()} plus manually setting up a \code{logit()} function. The same tree structure can be found via: % <>= pid_tree2 <- glmtree(diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age, data = PimaIndiansDiabetes, family = binomial) @ % However, \code{glmtree()} is slightly faster as it avoids many unnecessary computations, see Section~\ref{sec:interface} for further details. \begin{figure}[p!] \centering \setkeys{Gin}{width=0.8\textwidth} <>= plot(pid_tree) @ \caption{\label{fig:pid_tree} Logistic-regression-based tree for the Pima Indians diabetes data. The plots in the leaves report the estimated regression coefficients.} \setkeys{Gin}{width=\textwidth} <>= plot(pid_tree2, tp_args = list(ylines = 1, margins = c(1.5, 1.5, 1.5, 2.5))) @ \caption{\label{fig:pid_tree2} Logistic-regression-based tree for the Pima Indians diabetes data. The plots in the leaves give spinograms for \code{diabetes} versus \code{glucose}.} \end{figure} Here, we only point out that \code{plot(pid_tree2)} produces a nicer visualization (see Figure~\ref{fig:pid_tree2}). As $y$ is \code{diabetes}, a binary variable, and $x$ is \code{glucose}, a numeric variable, a spinogram is chosen automatically for visualization (using the \pkg{vcd} package, \citealp{vcd}). The x-axis breaks in the spinogram are the five-point summary of \code{glucose} on the full data set. The fitted lines are the mean predicted probabilities in each group. \subsection{Testing for parameter instability} \label{sec:sctest} In each node of the tree, first the parametric model is fitted to all observations in that node (see Section~\ref{sec:fit}). Subsequently it is of interest to find out whether the model parameters are stable over each particular ordering implied by the partitioning variables $Z_j$ or whether splitting the sample with respect to one of the $Z_j$ might capture instabilities in the parameters and thus improve the fit. The tests used in this step belong to the class of generalized M-fluctuation tests \citep{Zeileis:2005,Zeileis+Hornik:2007}. Depending on the class of each of the partitioning variables in \code{z} different types of tests are chosen by \code{mob()}: \begin{enumerate} \item For numeric partitioning variables (of class `\code{numeric}' or `\code{integer}') the sup\textit{LM}~statistic is used which is the maximum over all single-split \textit{LM} statistics. Associated $p$-values can be obtained from a table of critical values \citep[based on][]{Hansen:1997} stored within the package. If there are ties in the partitioning variable, the sequence of \textit{LM} statistics (and hence their maximum) is not unique and hence the results by default may depend to some degree on the ordering of the observations. To explore this, the option \code{breakties = TRUE} can be set in \code{mob_control()} which breaks ties randomly. If there are are only few ties, the influence is often negligible. If there are many ties (say only a dozen unique values of the partitioning variable), then the variable may be better treated as an ordered factor (see below). \item For categorical partitioning variables (of class `\code{factor}'), a $\chi^2$~statistic is employed which captures the fluctuation within each of the categories of the partitioning variable. This is also an \textit{LM}-type test and is asymptotically equivalent to the corresponding likelihood ratio test. However, it is somewhat cheaper to compute the \textit{LM} statistic because the model just has to be fitted once in the current node and not separately for each category of each possible partitioning variable. See also \cite{Merkle+Fan+Zeileis:2014} for a more detailed discussion. \item For ordinal partitioning variables (of class `\code{ordered}' inheriting from `\code{factor}') the same $\chi^2$ as for the unordered categorical variables is used by default \citep[as suggested by][]{Zeileis+Hothorn+Hornik:2008}. Although this test is consistent for any parameter instabilities across ordered variables, it does not exploit the ordering information. Recently, \cite{Merkle+Fan+Zeileis:2014} proposed an adapted max\textit{LM} test for ordered variables and, alternatively, a weighted double maximum test. Both are optionally availble in the new \code{mob()} implementation by setting \code{ordinal = "L2"} or \code{ordinal = "max"} in \code{mob_control()}, respectively. Unfortunately, computing $p$-values from both tests is more costly than for the default \code{ordinal = "chisq"}. For \code{"L2"} suitable tables of critical values have to be simulated on the fly using \code{ordL2BB()} from the \pkg{strucchange} package \citep{strucchange}. For \code{"max"} a multivariate normal probability has to be computed using the \pkg{mvtnorm} package \citep{mvtnorm}. \end{enumerate} All of the parameter instability tests above can be computed in an object-oriented manner as the ``\code{estfun}'' has to be available for the fitted model object. (Either by computing it in the \code{fit} function directly or by providing a \code{estfun()} extractor, see Section~\ref{sec:fit}.) All tests also require an estimate of the corresponding variance-covariance matrix of the estimating functions. The default is to compute this using an outer-product-of-gradients (OPG) estimator. Alternatively, the corrsponding information matrix or sandwich matrix can be used if: (a)~the estimating functions are actually maximum likelihood scores, and (b)~a \code{vcov()} method (based on an estimate of the information) is provided for the fitted model objects. The corresponding option in \code{mob_control()} is to set \code{vcov = "info"} or \code{vcov = "sandwich"} rather than \code{vcov = "opg"} (the default). For each of the $j = 1, \dots, \ell$ partitioning variables in \code{z} the test selected in the control options is employed and the corresponding $p$-value $p_j$ is computed. To adjust for multiple testing, the $p$ values can be Bonferroni adjusted (which is the default). To determine whether there is some overall instability, it is checked whether the minial $p$-value $p_{j^*} = \min_{j = 1, \dots, \ell} p_j$ falls below a pre-specified significance level $\alpha$ (by default $\alpha = 0.05$) or not. If there is significant instability, the variable $Z_{j^*}$ associated with the minimal $p$-value is used for splitting the node. \subsubsection*{Illustration} In the logistic-regression-based MOB \code{pid_tree} computed above, the parameter instability tests can be extracted using the \code{sctest()} function from the \pkg{strucchange} package (for \underline{s}tructural \underline{c}hange \underline{test}). In the first node, the test statistics and Bonferroni-corrected $p$-values are: % <>= library("strucchange") sctest(pid_tree, node = 1) @ % Thus, the body \code{mass} index has the lowest $p$-value and is highly significant and hence used for splitting the data. In the second node, no further significant parameter instabilities can be detected and hence partitioning stops in that branch. % <>= sctest(pid_tree, node = 2) @ % In the third node, however, there is still significant instability associated with the \code{age} variable and hence partitioning continues. % <>= sctest(pid_tree, node = 3) @ % Because no further instabilities can be found in the fourth and fifth node, the recursive partitioning stops there. \subsection{Splitting} \label{sec:split} In this step, the observations in the current node are split with respect to the chosen partitioning variable $Z_{j^*}$ into $B$ child nodes. As pointed out above, the \code{mob()} function currently only supports binary splits, i.e., $B = 2$. For deterimining the split point, an exhaustive search procedure is adopted: For each conceivable split point in $Z_{j^*}$, the two subset models are fit and the split associated with the minimal value of the objective function $\Psi$ is chosen. Computationally, this means that the \code{fit} function is applied to the subsets of \code{y} and \code{x} for each possibly binary split. The ``\code{objfun}'' values are simply summed up (because the objective function is assumed to be additive) and its minimum across splits is determined. In a search over a numeric partitioning variable, this means that typically a lot of subset models have to be fitted and often these will not vary a lot from one split to the next. Hence, the parameter estimates ``\code{coefficients}'' from the previous split are employed as \code{start} values for estimating the coefficients associated with the next split. Thus, if the \code{fit} function makes use of these starting values, the model fitting can often be speeded up. \subsubsection*{Illustration} For the Pima Indians diabetes data, the split points found for \code{pid_tree} are displayed both in the print output and the visualization (see Figure~\ref{fig:pid_tree} and~\ref{fig:pid_tree2}). \subsection{Pruning} \label{sec:prune} By default, the size of \code{mob()} trees is determined only by the significance tests, i.e., when there is no more significant parameter instability (by default at level $\alpha = 0.05$) the tree stops growing. Additional stopping criteria are only the minimal node size (\code{minsize}) and the maximum tree depth (\code{maxdepth}, by default infinity). However, for very large sample size traditional significance levels are typically not useful because even tiny parameter instabilities can be detected. To avoid overfitting in such a situation, one would either have to use much smaller significance levels or add some form of post-pruning to reduce the size of the tree afterwards. Similarly, one could wish to first grow a very large tree (using a large $\alpha$ level) and then prune it afterwards, e.g., using some information criterion like AIC or BIC. To accomodate such post-pruning strategies, \code{mob_control()} has an argument \code{prune} that can be a \code{function(objfun, df, nobs)} that either returns \code{TRUE} if a node should be pruned or \code{FALSE} if not. The arguments supplied are a vector of objective function values in the current node and the sum of all child nodes, a vector of corresponding degrees of freedom, and the number of observations in the current node and in total. For example if the objective function used is the negative log-likelihood, then for BIC-based pruning the \code{prune} function is: \code{(2 * objfun[1] + log(nobs[1]) * df[1]) < (2 * objfun[2] + log(nobs[2]) * df[2])}. As the negative log-likelihood is the default objective function when using the ``simple'' \code{fit} interface, \code{prune} can also be set to \code{"AIC"} or \code{"BIC"} and then suitable functions will be set up internally. Note, however, that for other objective functions this strategy is not appropriate and the functions would have to be defined differently (which \code{lmtree()} does for example). In the literature, there is no clear consensus as to how many degrees of freedom should be assigned to the selection of a split point. Hence, \code{mob_control()} allows to set \code{dfsplit} which by default is \code{dfsplit = TRUE} and then \code{as.integer(dfsplit)} (i.e., 1 by default) degrees of freedom per split are used. This can be modified to \code{dfsplit = FALSE} (or equivalently \code{dfsplit = 0}) or \code{dfsplit = 3} etc.\ for lower or higher penalization of additional splits. \subsubsection*{Illustration} With $n = \Sexpr{nrow(PimaIndiansDiabetes)}$ observations, the sample size is quite reasonable for using the classical significance level of $\alpha = 0.05$ which is also reflected by the moderate tree size with three terminal nodes. However, if we wished to explore further splits, a conceivable strategy could be the following: % <>= pid_tree3 <- mob(pid_formula, data = PimaIndiansDiabetes, fit = logit, control = mob_control(verbose = TRUE, minsize = 50, maxdepth = 4, alpha = 0.9, prune = "BIC")) @ This first grows a large tree until the nodes become too small (minimum node size: 50~observations) or the tree becomes too deep (maximum depth 4~levels) or the significance levels come very close to one (larger than $\alpha = 0.9$). Here, this large tree has eleven nodes which are subsequently pruned based on whether or not they improve the BIC of the model. For this data set, the resulting BIC-pruned tree is in fact identical to the pre-pruned \code{pid_tree} considered above. \subsection[Fitted `party' objects]{Fitted `\texttt{party}' objects} \label{sec:object} The result of \code{mob()} is an object of class `\code{modelparty}' inheriting from `\code{party}'. See the other vignettes in the \pkg{partykit} package \citep{partykit} for more details of the general `\code{party}' class. Here, we just point out that the main difference between a `\code{modelparty}' and a plain `\code{party}' is that additional information about the data and the associated models is stored in the \code{info} elements: both of the overall `\code{party}' and the individual `\code{node}'s. The details are exemplified below. \subsubsection*{Illustration} In the \code{info} of the overall `\code{party}' the following information is stored for \code{pid_tree}: % <>= names(pid_tree$info) @ % The \code{call} contains the \code{mob()} call. The \code{formula} and \code{Formula} are virtually the same but are simply stored as plain `\code{formula}' and extended `\code{Formula}' \citep{Formula} objects, respectively. The \code{terms} contain separate lists of terms for the \code{response} (and regressor) and the \code{partitioning} variables. The \code{fit}, \code{control} and \code{dots} are the arguments that were provided to \code{mob()} and \code{nreg} is the number of regressor variables. Furthermore, each \code{node} of the tree contains the following information: % <>= names(pid_tree$node$info) @ % The \code{coefficients}, \code{objfun}, and \code{object} are the results of the \code{fit} function for that node. In \code{nobs} and \code{p.value} the number of observations and the minimal $p$-value are provided, respectively. Finally, \code{test} contains the parameter instability test results. Note that the \code{object} element can also be suppressed through \code{mob_control()} to save memory space. \subsection{Methods} \label{sec:methods} There is a wide range of standard methods available for objects of class `\code{modelparty}'. The standard \code{print()}, \code{plot()}, and \code{predict()} build on the corresponding methods for `\code{party}' objects but provide some more special options. Furthermore, methods are provided that are typically available for models with formula interfaces: \code{formula()} (optionally one can set \code{extended = TRUE} to get the `\code{Formula}'), \code{getCall()}, \code{model.frame()}, \code{weights()}. Finally, there is a standard set of methods for statistical model objects: \code{coef()}, \code{residuals()}, \code{logLik()} (optionally setting \code{dfsplit = FALSE} suppresses counting the splits in the degrees of freedom, see Section~\ref{sec:prune}), \code{deviance()}, \code{fitted()}, and \code{summary()}. Some of these methods rely on reusing the corresponding methods for the individual model objects in the terminal nodes. Functions such as \code{coef()}, \code{print()}, \code{summary()} also take a \code{node} argument that can specify the node IDs to be queried. Two methods have non-standard arguments to allow for additional flexibility when dealing with model trees. Typically, ``normal'' users do not have to use these arguments directly but they are very flexible and facilitate writing convenience interfaces such as \code{glmtree()} (see Section~\ref{sec:interface}). \begin{itemize} \item The \code{predict()} method has the following arguments: \code{predict(object, newdata = NULL, type = "node", ...)}. The argument \code{type} can either be a function or a character string. More precisely, if \code{type} is a function it should be a \code{function (object, newdata = NULL, ...)} that returns a vector or matrix of predictions from a fitted model \code{object} either with or without \code{newdata}. If \code{type} is a character string, such a function is set up internally as \code{predict(object, newdata = newdata, type = type, ...)}, i.e., it relies on a suitable \code{predict()} method being available for the fitted models associated with the `\code{party}' object. \item The \code{plot()} method has the following arguments: \code{plot(x, terminal_panel = NULL, FUN = NULL)}. This simply calls the \code{plot()} method for `\code{party}' objects with a custom panel function for the terminal panels. By default, \code{node_terminal} is used to include some short text in each terminal node. This text can be set up by \code{FUN} with the default being the number of observations and estimated parameters. However, more elaborate terminal panel functions can be written, as done for the convenience interfaces. \end{itemize} Finally, two \proglang{S}3-style functions are provided without the corresponding generics (as these reside in packages that \pkg{partykit} does not depend on). The \code{sctest.modelparty} can be used in combination with the \code{sctest()} generic from \pkg{strucchange} as illustrated in Section~\ref{sec:sctest}. The \code{refit.modelparty} function extracts (or refits if necessary) the fitted model objects in the specified nodes (by default from all nodes). \subsubsection*{Illustration} The \code{plot()} and \code{print()} methods have already been illustrated for the \code{pid_tree} above. However, here we add that the \code{print()} method can also be used to show more detailed information about particular nodes instead of showing the full tree: % <>= print(pid_tree, node = 3) @ % Information about the model and coefficients can for example be extracted by: % <>= coef(pid_tree) coef(pid_tree, node = 1) ## IGNORE_RDIFF_BEGIN summary(pid_tree, node = 1) ## IGNORE_RDIFF_END @ % As the coefficients pertain to a logistic regression, they can be easily interpreted as odds ratios by taking the \code{exp()}: % <<>>= exp(coef(pid_tree)[,2]) @ % <>= risk <- round(100 * (exp(coef(pid_tree)[,2])-1), digits = 1) @ % i.e., the odds increase by \Sexpr{risk[1]}\%, \Sexpr{risk[2]}\% and \Sexpr{risk[3]}\% with respect to glucose in the three terminal nodes. Log-likelihoods and information criteria are available (which by default also penalize the estimation of splits): <>= logLik(pid_tree) AIC(pid_tree) BIC(pid_tree) @ % Mean squared residuals (or deviances) can be extracted in different ways: <>= mean(residuals(pid_tree)^2) deviance(pid_tree)/sum(weights(pid_tree)) deviance(pid_tree)/nobs(pid_tree) @ % Predicted nodes can also be easily obtained: % <>= pid <- head(PimaIndiansDiabetes) predict(pid_tree, newdata = pid, type = "node") @ % More predictions, e.g., predicted probabilities within the nodes, can also be obtained but require some extra coding if only \code{mob()} is used. However, with the \code{glmtree()} interface this is very easy as shown below. Finally, several methods for `\code{party}' objects are, of course, also available for `\code{modelparty}' objects, e.g., querying width and depth of the tree: % <>= width(pid_tree) depth(pid_tree) @ % Also subtrees can be easily extracted: % <>= pid_tree[3] @ % The subtree is again a completely valid `\code{modelparty}' and hence it could also be visualized via \code{plot(pid_tree[3])} etc. \subsection{Extensions and convenience interfaces} \label{sec:interface} As illustrated above, dealing with MOBs can be carried out in a very generic and object-oriented way. Almost all information required for dealing with recursively partitioned models can be encapsulated in the \code{fit()} function and \code{mob()} does not require more information on what type of model is actually used. However, for certain tasks more detailed information about the type of model used or the type of data it can be fitted to can (and should) be exploited. Notable examples for this are visualizations of the data along with the fitted model or model-based predictions in the leaves of the tree. To conveniently accomodate such specialized functionality, the \pkg{partykit} provides two convenience interfaces \code{lmtree()} and \code{glmtree()} and encourages other packages to do the same (e.g., \code{raschtree()} and \code{bttree()} in \pkg{psychotree}). Furthermore, such a convenience interface can avoid duplicated formula processing in both \code{mob()} plus its \code{fit} function. Specifically, \code{lmtree()} and \code{glmtree()} interface \code{lm.fit()}, \code{lm.wfit()}, and \code{glm.fit()}, respectively, and then provide some extra computations to return valid fitted `\code{lm}' and `\code{glm}' objects in the nodes of the tree. The resulting `\code{modelparty}' object gains an additional class `\code{lmtree}'/`\code{glmtree}' to dispatch to its enhanced \code{plot()} and \code{predict()} methods. \subsubsection*{Illustration} The \code{pid_tree2} object was already created above with \code{glmtree()} (instead of \code{mob()} as for \code{pid_tree}) to illustrate the enhanced plotting capabilities in Figure~\ref{fig:pid_tree2}. Here, the enhanced \code{predict()} method is used to obtain predicted means (i.e., probabilities) and associated linear predictors (on the logit scale) in addition to the previously available predicted nods IDs. % <<>>= predict(pid_tree2, newdata = pid, type = "node") predict(pid_tree2, newdata = pid, type = "response") predict(pid_tree2, newdata = pid, type = "link") @ \section{Illustrations} \label{sec:illustration} In the remainder of the vignette, further empirical illustrations of the MOB method are provided, including replications of the results from \cite{Zeileis+Hothorn+Hornik:2008}: \begin{enumerate} \item An investigation of the price elasticity of the demand for economics journals across covariates describing the type of journal (e.g., its price, its age, and whether it is published by a society, etc.) \item Prediction of house prices in the well-known Boston Housing data set, also taken from the UCI machine learning repository. \item Explore how teaching ratings and beauty scores of professors are associated and how this association changes across further explanatory variables such as age, gender, and native speaker status of the professors. \item Assessment of differences in the preferential treatment of women/children (``women and children first'') across subgroups of passengers on board of the ill-fated maiden voyage of the RMS Titanic. \item Modeling of breast cancer survival by capturing heterogeneity in certain (treatment) effects across patients. \item Modeling of paired comparisons of topmodel candidates by capturing heterogeneity in their attractiveness scores across participants in a survey. \end{enumerate} More details about several of the underlying data sets, previous studies exploring the data, and the results based on MOB can be found in \cite{Zeileis+Hothorn+Hornik:2008}. Here, we focus on using the \pkg{partykit} package to replicate the analysis and explore the resulting trees. The first three illustrations employ the \code{lmtree()} convenience function, the fourth is based on logistic regression using \code{glmtree()}, and the fifth uses \code{survreg()} from \pkg{survival} \citep{survival} in combination with \code{mob()} directly. The sixth and last illustration is deferred to a separate section and shows in detail how to set up new ``mobster'' functionality from scratch. \subsection{Demand for economic journals} The price elasticity of the demand for 180~economic journals is assessed by an OLS regression in log-log form: The dependent variable is the logarithm of the number of US library subscriptions and the regressor is the logarithm of price per citation. The data are provided by the \pkg{AER} package \citep{AER} and can be loaded and transformed via: % <>= data("Journals", package = "AER") Journals <- transform(Journals, age = 2000 - foundingyear, chars = charpp * pages) @ % Subsequently, the stability of the price elasticity across the remaining variables can be assessed using MOB. Below, \code{lmtree()} is used with the following partitioning variables: raw price and citations, age of the journal, number of characters, and whether the journal is published by a scientific society or not. A minimal segment size of 10~observations is employed and by setting \code{verbose = TRUE} detailed progress information about the recursive partitioning is displayed while growing the tree: % <>= j_tree <- lmtree(log(subs) ~ log(price/citations) | price + citations + age + chars + society, data = Journals, minsize = 10, verbose = TRUE) @ % \begin{figure}[t!] \centering \setkeys{Gin}{width=0.75\textwidth} <>= plot(j_tree) @ \caption{\label{fig:Journals} Linear-regression-based tree for the journals data. The plots in the leaves show linear regressions of log(subscriptions) by log(price/citation).} \end{figure} % The resulting tree just has one split and two terminal nodes for young journals (with a somewhat larger price elasticity) and old journals (with an even lower price elasticity), respectively. Figure~\ref{fig:Journals} can be obtained by \code{plot(j_tree)} and the corresponding printed representation is shown below. % <>= j_tree @ % Finally, various quantities of interest such as the coefficients, standard errors and test statistics, and the associated parameter instability tests could be extracted by the following code. The corresponding output is suppressed here. % <>= coef(j_tree, node = 1:3) summary(j_tree, node = 1:3) sctest(j_tree, node = 1:3) @ \subsection{Boston housing data} The Boston housing data are a popular and well-investigated empirical basis for illustrating nonlinear regression methods both in machine learning and statistics. We follow previous analyses by segmenting a bivariate linear regression model for the house values. The data set is available in package \pkg{mlbench} and can be obtained and transformed via: % <>= data("BostonHousing", package = "mlbench") BostonHousing <- transform(BostonHousing, chas = factor(chas, levels = 0:1, labels = c("no", "yes")), rad = factor(rad, ordered = TRUE)) @ % It provides $n = \Sexpr{NROW(BostonHousing)}$ observations of the median value of owner-occupied homes in Boston (in USD~1000) along with $\Sexpr{NCOL(BostonHousing)}$ covariates including in particular the number of rooms per dwelling (\code{rm}) and the percentage of lower status of the population (\code{lstat}). A segment-wise linear relationship between the value and these two variables is very intuitive, whereas the shape of the influence of the remaining covariates is rather unclear and hence should be learned from the data. Therefore, a linear regression model for median value explained by \verb:rm^2: and \verb:log(lstat): is employed and partitioned with respect to all remaining variables. Choosing appropriate transformations of the dependent variable and the regressors that enter the linear regression model is important to obtain a well-fitting model in each segment and we follow in our choice the recommendations of \cite{Breiman+Friedman:1985}. Monotonic transformations of the partitioning variables do not affect the recursive partitioning algorithm and hence do not have to be performed. However, it is important to distinguish between numerical and categorical variables for choosing an appropriate parameter stability test. The variable \code{chas} is a dummy indicator variable (for tract bounds with Charles river) and thus needs to be turned into a factor. Furthermore, the variable \code{rad} is an index of accessibility to radial highways and takes only 9 distinct values. Hence, it is most appropriately treated as an ordered factor. Note that both transformations only affect the parameter stability test chosen (step~2), not the splitting procedure (step~3). % Note that with splittry = 0 (according to old version of mob) there is no % split in dis <>= bh_tree <- lmtree(medv ~ log(lstat) + I(rm^2) | zn + indus + chas + nox + age + dis + rad + tax + crim + b + ptratio, data = BostonHousing) bh_tree @ % The corresponding visualization is shown in Figure~\ref{fig:BostonHousing}. It shows partial scatter plots of the dependent variable against each of the regressors in the terminal nodes. Each scatter plot also shows the fitted values, i.e., a projection of the fitted hyperplane. \setkeys{Gin}{width=\textwidth} \begin{figure}[p!] \centering <>= plot(bh_tree) @ \includegraphics[width=18cm,keepaspectratio,angle=90]{mob-BostonHousing-plot} \caption{\label{fig:BostonHousing} Linear-regression-based tree for the Boston housing data. The plots in the leaves give partial scatter plots for \code{rm} (upper panel) and \code{lstat} (lower panel).} \end{figure} From this visualization, it can be seen that in the nodes~4, 6, 7 and 8 the increase of value with the number of rooms dominates the picture (upper panel) whereas in node~9 the decrease with the lower status population percentage (lower panel) is more pronounced. Splits are performed in the variables \code{tax} (poperty-tax rate) and \code{ptratio} (pupil-teacher ratio). For summarizing the quality of the fit, we could compute the mean squared error, log-likelihood or AIC: % <>= mean(residuals(bh_tree)^2) logLik(bh_tree) AIC(bh_tree) @ \subsection{Teaching ratings data} \cite{Hamermesh+Parker:2005} investigate the correlation of beauty and teaching evaluations for professors. They provide data on course evaluations, course characteristics, and professor characteristics for 463 courses for the academic years 2000--2002 at the University of Texas at Austin. It is of interest how the average teaching evaluation per course (on a scale 1--5) depends on a standardized measure of beauty (as assessed by a committee of six persons based on photos). \cite{Hamermesh+Parker:2005} employ a linear regression, weighted by the number of students per course and adjusting for several further main effects: gender, whether or not the teacher is from a minority, a native speaker, or has tenure, respectively, and whether the course is taught in the upper or lower division. Additionally, the age of the professors is available as a regressor but not considered by \cite{Hamermesh+Parker:2005} because the corresponding main effect is not found to be significant in either linear or quadratic form. Here, we employ a similar model but use the available regressors differently. The basic model is again a linear regression for teaching rating by beauty, estimated by weighted least squares (WLS). All remaining explanatory variables are \emph{not} used as regressors but as partitioning variables because we argue that it is unclear how they influence the correlation between teaching rating and beauty. Hence, MOB is used to adaptively incorporate these further variables and determine potential interactions. First, the data are loaded from the \pkg{AER} package \citep{AER} and only the subset of single-credit courses is excluded. % <>= data("TeachingRatings", package = "AER") tr <- subset(TeachingRatings, credits == "more") @ % The single-credit courses include elective modules that are quite different from the remaining courses (e.g., yoga, aerobics, or dance) and are hence omitted from the main analysis. WLS estimation of the null model (with only an intercept) and the main effects model is carried out in a first step: % <>= tr_null <- lm(eval ~ 1, data = tr, weights = students) tr_lm <- lm(eval ~ beauty + gender + minority + native + tenure + division, data = tr, weights = students) @ % Then, the model-based tree can be estimated with \code{lmtree()} using only \code{beauty} as a regressor and all remaining variables for partitioning. For WLS estimation, we set \code{weights = students} and \code{caseweights = FALSE} because the weights are only proportionality factors and do not signal exactly replicated observations \citep[see][for a discussion of the different types of weights]{Lumley:2020}. % <>= (tr_tree <- lmtree(eval ~ beauty | minority + age + gender + division + native + tenure, data = tr, weights = students, caseweights = FALSE)) @ % \begin{figure}[t!] \setkeys{Gin}{width=\textwidth} <>= plot(tr_tree) @ \caption{\label{fig:tr_tree} WLS-based tree for the teaching ratings data. The plots in the leaves show scatterplots for teaching rating by beauty score.} \end{figure} % The resulting tree can be visualized by \code{plot(tr_tree)} and is shown in Figure~\ref{fig:tr_tree}. This shows that despite age not having a significant main effect \citep[as reported by][]{Hamermesh+Parker:2005}, it clearly plays an important role: While the correlation of teaching rating and beauty score is rather moderate for younger professors, there is a clear correlation for older professors (with the cutoff age somewhat lower for female professors). % <>= coef(tr_lm)[2] coef(tr_tree)[, 2] @ % Th $R^2$ of the tree is also clearly improved over the main effects model: % <>= 1 - c(deviance(tr_lm), deviance(tr_tree))/deviance(tr_null) @ \subsection{Titanic survival data} To illustrate how differences in treatment effects can be captured by MOB, the Titanic survival data is considered: The question is whether ``women and children first'' is applied in the same way for all subgroups of the passengers of the Titanic. Or, in other words, whether the effectiveness of preferential treatment for women/children differed across subgroups. The \code{Titanic} data is provided in base \proglang{R} as a contingency table and transformed here to a `\code{data.frame}' for use with \code{glmtree()}: % <>= data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" ttnc <- transform(ttnc, Treatment = factor( Gender == "Female" | Age == "Child", levels = c(FALSE, TRUE), labels = c("Male&Adult", "Female|Child"))) @ % The data provides factors \code{Survived} (yes/no), \code{Class} (1st, 2nd, 3rd, crew), \code{Gender} (male, female), and \code{Age} (child, adult). Additionally, a factor \code{Treatment} is added that distinguishes women/children from male adults. To investigate how the preferential treatment effect (\code{Survived ~ Treatment}) differs across the remaining explanatory variables, the following logistic-regression-based tree is considered. The significance level of \code{alpha = 0.01} is employed here to avoid overfitting and separation problems in the logistic regression. % <>= ttnc_tree <- glmtree(Survived ~ Treatment | Class + Gender + Age, data = ttnc, family = binomial, alpha = 0.01) ttnc_tree @ % \begin{figure}[t!] \setkeys{Gin}{width=\textwidth} <>= plot(ttnc_tree, tp_args = list(ylines = 1, margins = c(1.5, 1.5, 1.5, 2.5))) @ \caption{\label{fig:ttnc_tree} Logistic-regression-based tree for the Titanic survival data. The plots in the leaves give spinograms for survival status versus preferential treatment (women or children).} \end{figure} % This shows that the treatment differs strongly across passengers classes, see also the result of \code{plot(ttnc_tree)} in Figure~\ref{fig:ttnc_tree}. The treatment effect is much lower in the 3rd class where women/children still have higher survival rates than adult men but the odds ratio is much lower compared to all remaining classes. The split between the 2nd and the remaining two classes (1st, crew) is due to a lower overall survival rate (intercepts of \Sexpr{round(coef(ttnc_tree)[2, 1], digits = 2)} and \Sexpr{round(coef(ttnc_tree)[3, 1], digits = 2)}, respectively) while the odds ratios associated with the preferential treatment are rather similar (\Sexpr{round(coef(ttnc_tree)[2, 2], digits = 2)} and \Sexpr{round(coef(ttnc_tree)[3, 2], digits = 2)}, respectively). Another option for assessing the class effect would be to immediately split into all four classes rather than using recursive binary splits. This can be obtained by setting \code{catsplit = "multiway"} in the \code{glmtree()} call above. This yields a tree with just a single split but four kid nodes. \subsection{German breast cancer data} To illustrate that the MOB approach can also be used beyond (generalized) linear regression models, it is employed in the following to analyze censored survival times among German women with positive node breast cancer. The data is available in the \pkg{TH.data} package and the survival time is transformed from days to years: % <>= data("GBSG2", package = "TH.data") GBSG2$time <- GBSG2$time/365 @ % For regression a parametric Weibull regression based on the \code{survreg()} function from the \pkg{survival} package \citep{survival} is used. A fitting function for \code{mob()} can be easily set up: % <>= library("survival") wbreg <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { survreg(y ~ 0 + x, weights = weights, dist = "weibull", ...) } @ % As the \pkg{survreg} package currently does not provide a \code{logLik()} method for `\code{survreg}' objects, this needs to be added here: % <>= logLik.survreg <- function(object, ...) structure(object$loglik[2], df = sum(object$df), class = "logLik") @ % Without the \code{logLik()} method, \code{mob()} would not know how to extract the optimized objective function from the fitted model. With the functions above available, a censored Weibull-regression-tree can be fitted: The dependent variable is the censored survival time and the two regressor variables are the main risk factor (number of positive lymph nodes) and the treatment variable (hormonal therapy). All remaining variables are used for partitioning: age, tumor size and grade, progesterone and estrogen receptor, and menopausal status. The minimal segment size is set to 80. % <>= gbsg2_tree <- mob(Surv(time, cens) ~ horTh + pnodes | age + tsize + tgrade + progrec + estrec + menostat, data = GBSG2, fit = wbreg, control = mob_control(minsize = 80)) @ % \begin{figure}[p!] \centering \setkeys{Gin}{width=0.6\textwidth} <>= plot(gbsg2_tree) @ \caption{\label{fig:GBSG2} Censored Weibull-regression-based tree for the German breast cancer data. The plots in the leaves report the estimated regression coefficients.} \setkeys{Gin}{width=\textwidth} <>= gbsg2node <- function(mobobj, col = "black", linecol = "red", cex = 0.5, pch = NULL, jitter = FALSE, xscale = NULL, yscale = NULL, ylines = 1.5, id = TRUE, xlab = FALSE, ylab = FALSE) { ## obtain dependent variable mf <- model.frame(mobobj) y <- Formula::model.part(mobobj$info$Formula, mf, lhs = 1L, rhs = 0L) if(isTRUE(ylab)) ylab <- names(y)[1L] if(identical(ylab, FALSE)) ylab <- "" if(is.null(ylines)) ylines <- ifelse(identical(ylab, ""), 0, 2) y <- y[[1L]] ## plotting character and response if(is.null(pch)) pch <- y[,2] * 18 + 1 y <- y[,1] y <- as.numeric(y) pch <- rep(pch, length.out = length(y)) if(jitter) y <- jitter(y) ## obtain explanatory variables x <- Formula::model.part(mobobj$info$Formula, mf, lhs = 0L, rhs = 1L) xnam <- colnames(x) z <- seq(from = min(x[,2]), to = max(x[,2]), length = 51) z <- data.frame(a = rep(sort(x[,1])[c(1, NROW(x))], c(51, 51)), b = z) names(z) <- names(x) z$x <- model.matrix(~ ., data = z) ## fitted node ids fitted <- mobobj$fitted[["(fitted)"]] if(is.null(xscale)) xscale <- range(x[,2]) + c(-0.1, 0.1) * diff(range(x[,2])) if(is.null(yscale)) yscale <- range(y) + c(-0.1, 0.1) * diff(range(y)) ## panel function for scatter plots in nodes rval <- function(node) { ## node index nid <- id_node(node) ix <- fitted %in% nodeids(mobobj, from = nid, terminal = TRUE) ## dependent variable y <- y[ix] ## predictions yhat <- if(is.null(node$info$object)) { refit.modelparty(mobobj, node = nid) } else { node$info$object } yhat <- predict(yhat, newdata = z, type = "quantile", p = 0.5) pch <- pch[ix] ## viewport setup top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_scatterplot", nid, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = "white", col = 0)) ## main title top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) mainlab <- paste(ifelse(id, paste("Node", nid, "(n = "), ""), info_node(node)$nobs, ifelse(id, ")", ""), sep = "") grid.text(mainlab) popViewport() plot_vp <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = xscale, yscale = yscale, name = paste("node_scatterplot", nid, "plot", sep = "")) pushViewport(plot_vp) ## scatterplot grid.points(x[ix,2], y, gp = gpar(col = col, cex = cex), pch = pch) grid.lines(z[1:51,2], yhat[1:51], default.units = "native", gp = gpar(col = linecol)) grid.lines(z[52:102,2], yhat[52:102], default.units = "native", gp = gpar(col = linecol, lty = 2)) grid.xaxis(at = c(ceiling(xscale[1]*10), floor(xscale[2]*10))/10) grid.yaxis(at = c(ceiling(yscale[1]), floor(yscale[2]))) if(isTRUE(xlab)) xlab <- xnam[2] if(!identical(xlab, FALSE)) grid.text(xlab, x = unit(0.5, "npc"), y = unit(-2, "lines")) if(!identical(ylab, FALSE)) grid.text(ylab, y = unit(0.5, "npc"), x = unit(-2, "lines"), rot = 90) grid.rect(gp = gpar(fill = "transparent")) upViewport() upViewport() } return(rval) } class(gbsg2node) <- "grapcon_generator" plot(gbsg2_tree, terminal_panel = gbsg2node, tnex = 2, tp_args = list(xscale = c(0, 52), yscale = c(-0.5, 8.7))) @ \caption{\label{fig:GBSG2-scatter} Censored Weibull-regression-based tree for the German breast cancer data. The plots in the leaves depict censored (hollow) and uncensored (solid) survival time by number of positive lymph nodes along with fitted median survival for patients with (dashed line) and without (solid line) hormonal therapy.} \end{figure} % Based on progesterone receptor, a tree with two leaves is found: % <>= gbsg2_tree coef(gbsg2_tree) logLik(gbsg2_tree) @ % The visualization produced by \code{plot(gbsg2_tree)} is shown in Figure~\ref{fig:GBSG2}. A nicer graphical display using a scatter plot (with indication of censoring) and fitted regression curves is shown in Figure~\ref{fig:GBSG2-scatter}. This uses a custom panel function whose code is too long and elaborate to be shown here. Interested readers are referred to the \proglang{R} code underlying the vignette. The visualization shows that for higher progesterone receptor levels: (1)~survival times are higher overall, (2)~the treatment effect of hormonal therapy is higher, and (3)~the negative effect of the main risk factor (number of positive lymph nodes) is less severe. \section{Setting up a new mobster} \label{sec:mobster} To conclude this vignette, we present another illustration that shows how to set up new mobster functionality from scratch. To do so, we implement the Bradley-Terry tree suggested by \cite{Strobl+Wickelmaier+Zeileis:2011} ``by hand''. The \pkg{psychotree} package already provides an easy-to-use mobster called \code{bttree()} but as an implementation exercise we recreate its functionality here. The only inputs required are a suitable data set with paired comparisons (\code{Topmodel2007} from \pkg{psychotree}) and a parametric model for paired comparison data (\code{btmodel()} from \pkg{psychotools}, implementing the Bradley-Terry model). The latter optionally computes the empirical estimating functions and already comes with a suitable extractor method. <>= data("Topmodel2007", package = "psychotree") library("psychotools") @ % The Bradley-Terry (or Bradley-Terry-Luce) model is a standard model for paired comparisons in social sciences. It parametrizes the probability $\pi_{ij}$ for preferring some object $i$ over another object $j$ in terms of corresponding ``ability'' or ``worth'' parameters $\theta_i$: \begin{eqnarray*} \pi_{ij}\phantom{)} & = & \frac{\theta_i}{\theta_i + \theta_j} \\ \mathsf{logit}(\pi_{ij}) & = & \log(\theta_i) - \log(\theta_j) \end{eqnarray*} This model can be easily estimated by maximum likelihood as a logistic or log-linear GLM. This is the approach used internally by \code{btmodel()}. The \code{Topmodel2007} data provide paired comparisons of attractiveness among the six finalists of the TV show \emph{Germany's Next Topmodel~2007}: Barbara, Anni, Hana, Fiona, Mandy, Anja. The data were collected in a survey with 192~respondents at Universit{\"a}t T{\"u}bingen and the available covariates comprise gender, age, and familiarty with the TV~show. The latter is assess by three by yes/no questions: (1)~Do you recognize the women?/Do you know the show? (2)~Did you watch it regularly? (3)~Did you watch the final show?/Do you know who won? To fit the Bradley-Terry tree to the data, the available building blocks just have to be tied together. First, we set up the basic/simple model fitting interface described in Section~\ref{sec:fit}: % @ <>= btfit1 <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ...) btmodel(y, ...) @ % The function \code{btfit1()} simply calls \code{btmodel()} ignoring all arguments except \code{y} as the others are not needed here. No more processing is required because \class{btmodel} objects come with a \code{coef()}, \code{logLik()}, and \code{estfun()} method. Hence, we can call \code{mob()} now specifying the response and the partitioning variable (and no regressors because there are no regressors in this model). % <>= bt1 <- mob(preference ~ 1 | gender + age + q1 + q2 + q3, data = Topmodel2007, fit = btfit1) @ % An alternative way to fit the exact same tree somewhat more quickly would be to employ the extended interface described in Section~\ref{sec:fit}: % <>= btfit2 <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ..., estfun = FALSE, object = FALSE) { rval <- btmodel(y, ..., estfun = estfun, vcov = object) list( coefficients = rval$coefficients, objfun = -rval$loglik, estfun = if(estfun) rval$estfun else NULL, object = if(object) rval else NULL ) } @ % Still \code{btmodel()} is employed for fitting the model but the quantities \code{estfun} and \code{vcov} are only computed if they are really required. This may save some computation time -- about 20\% on the authors' machine at the time of writing -- when computing the tree: % <>= bt2 <- mob(preference ~ 1 | gender + age + q1 + q2 + q3, data = Topmodel2007, fit = btfit2) @ % The speed-up is not huge but comes almost for free: just a few additional lines of code in \code{btfit2()} are required. For other models where it is more costly to set up a full model (with variance-covariance matrix, predictions, residuals, etc.) larger speed-ups are also possible. Both trees, \code{bt1} and \code{bt2}, are equivalent (except for the details of the fitting function). Hence, in the following we only explore \code{bt2}. However, the same code can be applied to \code{bt1} as well. Many tools come completely for free and are inherited from the general \class{modelparty}/\class{party}. For example, both printing (\code{print(bt2)}) and plotting (\code{plot(bt2)}) shows the estimated parameters in the terminal nodes which can also be extracted by the \code{coef()} method: <>= bt2 coef(bt2) @ The corresponding visualization is shown in the upper panel of Figure~\ref{fig:topmodel-plot1}. In all cases, the estimated coefficients on the logit scale omitting the fixed zero reference level (Anja) are reported. To show the corresponding worth parameters $\theta_i$ including the reference level, one can simply provide a small panel function \code{worthf()}. This applies the \code{worth()} function from \pkg{psychotools} to the fitted-model object stored in the \code{info} slot of each node, yielding the lower panel in Figure~\ref{fig:topmodel-plot1}. % <>= worthf <- function(info) paste(info$object$labels, format(round(worth(info$object), digits = 3)), sep = ": ") plot(bt2, FUN = worthf) @ % \begin{figure}[p!] \centering <>= plot(bt2) @ \vspace*{0.5cm} <>= <> @ \caption{\label{fig:topmodel-plot1} Bradley-Terry-based tree for the topmodel attractiveness data. The default plot (upper panel) reports the estimated coefficients on the log scale while the adapted plot (lower panel) shows the corresponding worth parameters.} \end{figure} % To show a graphical display of these worth parameters rather than printing their numerical values, one can use a simply glyph-style plot. A simply way to generate these is to use the \code{plot()} method for \class{btmodel} objects from \pkg{partykit} and \code{nodeapply} this to all terminal nodes (see Figure~\ref{fig:topmodel-plot2}): % <>= par(mfrow = c(2, 2)) nodeapply(bt2, ids = c(3, 5, 6, 7), FUN = function(n) plot(n$info$object, main = n$id, ylim = c(0, 0.4))) @ % \begin{figure}[t!] \centering <>= <> @ \caption{\label{fig:topmodel-plot2} Worth parameters in the terminal nodes of the Bradley-Terry-based tree for the topmodel attractiveness data.} \end{figure} % Alternatively, one could set up a proper panel-generating function in \pkg{grid} that allows to create the glyphs within the terminal nodes of the tree (see Figure~\ref{fig:topmodel-plot3}). As the code for this panel-generating function \code{node_btplot()} is too complicated to display within the vignette, we refer interested readers to the underlying code. Given this panel-generating function Figure~\ref{fig:topmodel-plot3} can be generated with <>= plot(bt2, drop = TRUE, tnex = 2, terminal_panel = node_btplot(bt2, abbreviate = 1, yscale = c(0, 0.5))) @ \begin{figure}[t!] \centering <>= ## visualization function node_btplot <- function(mobobj, id = TRUE, worth = TRUE, names = TRUE, abbreviate = TRUE, index = TRUE, ref = TRUE, col = "black", linecol = "lightgray", cex = 0.5, pch = 19, xscale = NULL, yscale = NULL, ylines = 1.5) { ## node ids node <- nodeids(mobobj, terminal = FALSE) ## get all coefficients cf <- partykit:::apply_to_models(mobobj, node, FUN = function(z) if(worth) worth(z) else coef(z, all = FALSE, ref = TRUE)) cf <- do.call("rbind", cf) rownames(cf) <- node ## get one full model mod <- partykit:::apply_to_models(mobobj, node = 1L, FUN = NULL) if(!worth) { if(is.character(ref) | is.numeric(ref)) { reflab <- ref ref <- TRUE } else { reflab <- mod$ref } if(is.character(reflab)) reflab <- match(reflab, mod$labels) cf <- cf - cf[,reflab] } ## reference if(worth) { cf_ref <- 1/ncol(cf) } else { cf_ref <- 0 } ## labeling if(is.character(names)) { colnames(cf) <- names names <- TRUE } ## abbreviation if(is.logical(abbreviate)) { nlab <- max(nchar(colnames(cf))) abbreviate <- if(abbreviate) as.numeric(cut(nlab, c(-Inf, 1.5, 4.5, 7.5, Inf))) else nlab } colnames(cf) <- abbreviate(colnames(cf), abbreviate) if(index) { x <- 1:NCOL(cf) if(is.null(xscale)) xscale <- range(x) + c(-0.1, 0.1) * diff(range(x)) } else { x <- rep(0, length(cf)) if(is.null(xscale)) xscale <- c(-1, 1) } if(is.null(yscale)) yscale <- range(cf) + c(-0.1, 0.1) * diff(range(cf)) ## panel function for bt plots in nodes rval <- function(node) { ## node index id <- id_node(node) ## dependent variable setup cfi <- cf[id,] ## viewport setup top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_btplot", id, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = "white", col = 0)) ## main title top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) mainlab <- paste(ifelse(id, paste("Node", id, "(n = "), ""), info_node(node)$nobs, ifelse(id, ")", ""), sep = "") grid.text(mainlab) popViewport() ## actual plot plot_vpi <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = xscale, yscale = yscale, name = paste("node_btplot", id, "plot", sep = "")) pushViewport(plot_vpi) grid.lines(xscale, c(cf_ref, cf_ref), gp = gpar(col = linecol), default.units = "native") if(index) { grid.lines(x, cfi, gp = gpar(col = col, lty = 2), default.units = "native") grid.points(x, cfi, gp = gpar(col = col, cex = cex), pch = pch, default.units = "native") grid.xaxis(at = x, label = if(names) names(cfi) else x) } else { if(names) grid.text(names(cfi), x = x, y = cfi, default.units = "native") else grid.points(x, cfi, gp = gpar(col = col, cex = cex), pch = pch, default.units = "native") } grid.yaxis(at = c(ceiling(yscale[1] * 100)/100, floor(yscale[2] * 100)/100)) grid.rect(gp = gpar(fill = "transparent")) upViewport(2) } return(rval) } class(node_btplot) <- "grapcon_generator" plot(bt2, drop = TRUE, tnex = 2, terminal_panel = node_btplot(bt2, abbreviate = 1, yscale = c(0, 0.5))) @ \caption{\label{fig:topmodel-plot3} Bradley-Terry-based tree for the topmodel attractiveness data with visualizations of the worth parameters in the terminal nodes.} \end{figure} Finally, to illustrate how different predictions can be easily computed, we set up a small data set with three new individuals: % <>= tm <- data.frame(age = c(60, 25, 35), gender = c("male", "female", "female"), q1 = "no", q2 = c("no", "no", "yes"), q3 = "no") tm @ % For these we can easily compute (1)~the predicted node ID, (2)~the corresponding worth parameters, (3)~the associated ranks. <>= tm predict(bt2, tm, type = "node") predict(bt2, tm, type = function(object) t(worth(object))) predict(bt2, tm, type = function(object) t(rank(-worth(object)))) @ This completes the tour of fitting, printing, plotting, and predicting the Bradley-Terry tree model. Convenience interfaces that employ code like shown above can be easily defined and collected in new packages such as \pkg{psychotree}. \section{Conclusion} \label{sec:conclusion} The function \code{mob()} in the \pkg{partykit} package provides a new flexible and object-oriented implementation of the general algorithm for model-based recursive partitioning using \pkg{partykit}'s recursive partytioning infrastructure. New model fitting functions can be easily provided, especially if standard extractor functions (such as \code{coef()}, \code{estfun()}, \code{logLik()}, etc.) are available. The resulting model trees can then learned, visualized, investigated, and employed for predictions. To gain some efficiency in the computations and to allow for further customization (in particular specialized visualization and prediction methods), convenience interfaces \code{lmtree()} and \code{glmtree()} are provided for recursive partitioning based on (generalized) linear models. \bibliography{party} \end{document} partykit/vignettes/ctree.Rnw0000644000176200001440000015516214172230001015723 0ustar liggesusers\documentclass[nojss]{jss} %\VignetteIndexEntry{ctree: Conditional Inference Trees} %\VignetteDepends{coin, TH.data, survival, strucchange, Formula, sandwich, datasets} %\VignetteKeywords{conditional inference, non-parametric models, recursive partitioning} %\VignettePackage{partykit} %% packages \usepackage{amstext} \usepackage{amsfonts} \usepackage{amsmath} \usepackage{thumbpdf} \usepackage{rotating} %% need no \usepackage{Sweave} \usepackage[utf8]{inputenc} %% commands \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} \renewcommand{\Prob}{\mathbb{P} } \renewcommand{\E}{\mathbb{E}} \newcommand{\V}{\mathbb{V}} \newcommand{\Var}{\mathbb{V}} \newcommand{\R}{\mathbb{R} } \newcommand{\N}{\mathbb{N} } %%\newcommand{\C}{\mathbb{C} } \newcommand{\argmin}{\operatorname{argmin}\displaylimits} \newcommand{\argmax}{\operatorname{argmax}\displaylimits} \newcommand{\LS}{\mathcal{L}_n} \newcommand{\TS}{\mathcal{T}_n} \newcommand{\LSc}{\mathcal{L}_{\text{comb},n}} \newcommand{\LSbc}{\mathcal{L}^*_{\text{comb},n}} \newcommand{\F}{\mathcal{F}} \newcommand{\A}{\mathcal{A}} \newcommand{\yn}{y_{\text{new}}} \newcommand{\z}{\mathbf{z}} \newcommand{\X}{\mathbf{X}} \newcommand{\Y}{\mathbf{Y}} \newcommand{\sX}{\mathcal{X}} \newcommand{\sY}{\mathcal{Y}} \newcommand{\T}{\mathbf{T}} \newcommand{\x}{\mathbf{x}} \renewcommand{\a}{\mathbf{a}} \newcommand{\xn}{\mathbf{x}_{\text{new}}} \newcommand{\y}{\mathbf{y}} \newcommand{\w}{\mathbf{w}} \newcommand{\ws}{\mathbf{w}_\cdot} \renewcommand{\t}{\mathbf{t}} \newcommand{\M}{\mathbf{M}} \renewcommand{\vec}{\text{vec}} \newcommand{\B}{\mathbf{B}} \newcommand{\K}{\mathbf{K}} \newcommand{\W}{\mathbf{W}} \newcommand{\D}{\mathbf{D}} \newcommand{\I}{\mathbf{I}} \newcommand{\bS}{\mathbf{S}} \newcommand{\cellx}{\pi_n[\x]} \newcommand{\partn}{\pi_n(\mathcal{L}_n)} \newcommand{\err}{\text{Err}} \newcommand{\ea}{\widehat{\text{Err}}^{(a)}} \newcommand{\ecv}{\widehat{\text{Err}}^{(cv1)}} \newcommand{\ecvten}{\widehat{\text{Err}}^{(cv10)}} \newcommand{\eone}{\widehat{\text{Err}}^{(1)}} \newcommand{\eplus}{\widehat{\text{Err}}^{(.632+)}} \newcommand{\eoob}{\widehat{\text{Err}}^{(oob)}} \newcommand{\bft}{\mathbf{t}} \hyphenation{Qua-dra-tic} \title{\texttt{ctree}: Conditional Inference Trees} \Plaintitle{ctree: Conditional Inference Trees} \author{Torsten Hothorn\\Universit\"at Z\"urich \And Kurt Hornik\\Wirtschaftsuniversit\"at Wien \And Achim Zeileis\\Universit\"at Innsbruck} \Plainauthor{Torsten Hothorn, Kurt Hornik, Achim Zeileis} \Abstract{ This vignette describes the new reimplementation of conditional inference trees (CTree) in the \proglang{R} package \pkg{partykit}. CTree is a non-parametric class of regression trees embedding tree-structured regression models into a well defined theory of conditional inference procedures. It is applicable to all kinds of regression problems, including nominal, ordinal, numeric, censored as well as multivariate response variables and arbitrary measurement scales of the covariates. The vignette comprises a practical guide to exploiting the flexible and extensible computational tools in \pkg{partykit} for fitting and visualizing conditional inference trees. } \Keywords{conditional inference, non-parametric models, recursive partitioning} \Address{ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/}\\ Kurt Hornik \\ Institute for Statistics and Mathematics\\ WU Wirtschaftsuniversit\"at Wien\\ Welthandelsplatz 1 \\ 1020 Wien, Austria\\ E-mail: \email{Kurt.Hornik@R-project.org} \\ URL: \url{http://statmath.wu.ac.at/~hornik/}\\ Achim Zeileis \\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org} \\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} } \begin{document} <>= suppressWarnings(RNGversion("3.5.2")) options(width = 70, SweaveHooks = list(leftpar = function() par(mai = par("mai") * c(1, 1.1, 1, 1)))) require("partykit") require("coin") require("strucchange") require("coin") require("Formula") require("survival") require("sandwich") set.seed(290875) @ \setkeys{Gin}{width=\textwidth} \section{Overview} This vignette describes conditional inference trees \citep{Hothorn+Hornik+Zeileis:2006} along with its new and improved reimplementation in package \pkg{partykit}. Originally, the method was implemented in the package \pkg{party} almost entirely in \proglang{C} while the new implementation is now almost entirely in \proglang{R}. In particular, this has the advantage that all the generic infrastructure from \pkg{partykit} can be reused, making many computations more modular and easily extensible. Hence, \code{partykit::ctree} is the new reference implementation that will be improved and developed further in the future. In almost all cases, the two implementations will produce identical trees. In exceptional cases, additional parameters have to be specified in order to ensure backward compatibility. These and novel features in \code{ctree:partykit} are introduced in Section~\ref{sec:novel}. \section{Introduction} The majority of recursive partitioning algorithms are special cases of a simple two-stage algorithm: First partition the observations by univariate splits in a recursive way and second fit a constant model in each cell of the resulting partition. The most popular implementations of such algorithms are `CART' \citep{Breiman+Friedman+Olshen:1984} and `C4.5' \citep{Quinlan:1993}. Not unlike AID, both perform an exhaustive search over all possible splits maximizing an information measure of node impurity selecting the covariate showing the best split. This approach has two fundamental problems: overfitting and a selection bias towards covariates with many possible splits. With respect to the overfitting problem \cite{Mingers:1987} notes that the algorithm \begin{quote} [\ldots] has no concept of statistical significance, and so cannot distinguish between a significant and an insignificant improvement in the information measure. \end{quote} With conditional inference trees \citep[see][for a full description of its methodological foundations]{Hothorn+Hornik+Zeileis:2006} we enter at the point where \cite{White+Liu:1994} demand for \begin{quote} [\ldots] a \textit{statistical} approach [to recursive partitioning] which takes into account the \textit{distributional} properties of the measures. \end{quote} We present a unified framework embedding recursive binary partitioning into the well defined theory of permutation tests developed by \cite{Strasser+Weber:1999}. The conditional distribution of statistics measuring the association between responses and covariates is the basis for an unbiased selection among covariates measured at different scales. Moreover, multiple test procedures are applied to determine whether no significant association between any of the covariates and the response can be stated and the recursion needs to stop. \section{Recursive binary partitioning} \label{algo} We focus on regression models describing the conditional distribution of a response variable $\Y$ given the status of $m$ covariates by means of tree-structured recursive partitioning. The response $\Y$ from some sample space $\sY$ may be multivariate as well. The $m$-dimensional covariate vector $\X = (X_1, \dots, X_m)$ is taken from a sample space $\sX = \sX_1 \times \cdots \times \sX_m$. Both response variable and covariates may be measured at arbitrary scales. We assume that the conditional distribution $D(\Y | \X)$ of the response $\Y$ given the covariates $\X$ depends on a function $f$ of the covariates \begin{eqnarray*} D(\Y | \X) = D(\Y | X_1, \dots, X_m) = D(\Y | f( X_1, \dots, X_m)), \end{eqnarray*} where we restrict ourselves to partition based regression relationships, i.e., $r$ disjoint cells $B_1, \dots, B_r$ partitioning the covariate space $\sX = \bigcup_{k = 1}^r B_k$. A model of the regression relationship is to be fitted based on a learning sample $\LS$, i.e., a random sample of $n$ independent and identically distributed observations, possibly with some covariates $X_{ji}$ missing, \begin{eqnarray*} \LS & = & \{ (\Y_i, X_{1i}, \dots, X_{mi}); i = 1, \dots, n \}. \end{eqnarray*} A generic algorithm for recursive binary partitioning for a given learning sample $\LS$ can be formulated using non-negative integer valued case weights $\w = (w_1, \dots, w_n)$. Each node of a tree is represented by a vector of case weights having non-zero elements when the corresponding observations are elements of the node and are zero otherwise. The following algorithm implements recursive binary partitioning: \begin{enumerate} \item For case weights $\w$ test the global null hypothesis of independence between any of the $m$ covariates and the response. Stop if this hypothesis cannot be rejected. Otherwise select the covariate $X_{j^*}$ with strongest association to $\Y$. \item Choose a set $A^* \subset \sX_{j^*}$ in order to split $\sX_{j^*}$ into two disjoint sets $A^*$ and $\sX_{j^*} \setminus A^*$. The case weights $\w_\text{left}$ and $\w_\text{right}$ determine the two subgroups with $w_{\text{left},i} = w_i I(X_{j^*i} \in A^*)$ and $w_{\text{right},i} = w_i I(X_{j^*i} \not\in A^*)$ for all $i = 1, \dots, n$ ($I(\cdot)$ denotes the indicator function). \item Recursively repeat steps 1 and 2 with modified case weights $\w_\text{left}$ and $\w_\text{right}$, respectively. \end{enumerate} The separation of variable selection and splitting procedure into steps 1 and 2 of the algorithm is the key for the construction of interpretable tree structures not suffering a systematic tendency towards covariates with many possible splits or many missing values. In addition, a statistically motivated and intuitive stopping criterion can be implemented: We stop when the global null hypothesis of independence between the response and any of the $m$ covariates cannot be rejected at a pre-specified nominal level~$\alpha$. The algorithm induces a partition $\{B_1, \dots, B_r\}$ of the covariate space $\sX$, where each cell $B \in \{B_1, \dots, B_r\}$ is associated with a vector of case weights. \section{Recursive partitioning by conditional inference} \label{framework} In the main part of this section we focus on step 1 of the generic algorithm. Unified tests for independence are constructed by means of the conditional distribution of linear statistics in the permutation test framework developed by \cite{Strasser+Weber:1999}. The determination of the best binary split in one selected covariate and the handling of missing values is performed based on standardized linear statistics within the same framework as well. \subsection{Variable selection and stopping criteria} At step 1 of the generic algorithm given in Section~\ref{algo} we face an independence problem. We need to decide whether there is any information about the response variable covered by any of the $m$ covariates. In each node identified by case weights $\w$, the global hypothesis of independence is formulated in terms of the $m$ partial hypotheses $H_0^j: D(\Y | X_j) = D(\Y)$ with global null hypothesis $H_0 = \bigcap_{j = 1}^m H_0^j$. When we are not able to reject $H_0$ at a pre-specified level $\alpha$, we stop the recursion. If the global hypothesis can be rejected, we measure the association between $\Y$ and each of the covariates $X_j, j = 1, \dots, m$, by test statistics or $P$-values indicating the deviation from the partial hypotheses $H_0^j$. For notational convenience and without loss of generality we assume that the case weights $w_i$ are either zero or one. The symmetric group of all permutations of the elements of $(1, \dots, n)$ with corresponding case weights $w_i = 1$ is denoted by $S(\LS, \w)$. A more general notation is given in the Appendix. We measure the association between $\Y$ and $X_j, j = 1, \dots, m$, by linear statistics of the form \begin{eqnarray} \label{linstat} \T_j(\LS, \w) = \vec \left( \sum_{i=1}^n w_i g_j(X_{ji}) h(\Y_i, (\Y_1, \dots, \Y_n))^\top \right) \in \R^{p_jq} \end{eqnarray} where $g_j: \sX_j \rightarrow \R^{p_j}$ is a non-random transformation of the covariate $X_j$. The transformation may be specified using the \code{xtrafo} argument (Note: this argument is currently not implemented in \code{partykit::ctree} but is available from \code{party::ctree}). %%If, for example, a ranking \textit{both} %%\code{x1} and \code{x2} is required, %%<>= %%party:::ctree(y ~ x1 + x2, data = ls, xtrafo = function(data) trafo(data, %%numeric_trafo = rank)) %%@ %%can be used. The \emph{influence function} $h: \sY \times \sY^n \rightarrow \R^q$ depends on the responses $(\Y_1, \dots, \Y_n)$ in a permutation symmetric way. %%, i.e., $h(\Y_i, (\Y_1, \dots, \Y_n)) = h(\Y_i, (\Y_{\sigma(1)}, \dots, %%\Y_{\sigma(n)}))$ for all permutations $\sigma \in S(\LS, \w)$. Section~\ref{examples} explains how to choose $g_j$ and $h$ in different practical settings. A $p_j \times q$ matrix is converted into a $p_jq$ column vector by column-wise combination using the `vec' operator. The influence function can be specified using the \code{ytrafo} argument. The distribution of $\T_j(\LS, \w)$ under $H_0^j$ depends on the joint distribution of $\Y$ and $X_j$, which is unknown under almost all practical circumstances. At least under the null hypothesis one can dispose of this dependency by fixing the covariates and conditioning on all possible permutations of the responses. This principle leads to test procedures known as \textit{permutation tests}. The conditional expectation $\mu_j \in \R^{p_jq}$ and covariance $\Sigma_j \in \R^{p_jq \times p_jq}$ of $\T_j(\LS, \w)$ under $H_0$ given all permutations $\sigma \in S(\LS, \w)$ of the responses are derived by \cite{Strasser+Weber:1999}: \begin{eqnarray} \mu_j & = & \E(\T_j(\LS, \w) | S(\LS, \w)) = \vec \left( \left( \sum_{i = 1}^n w_i g_j(X_{ji}) \right) \E(h | S(\LS, \w))^\top \right), \nonumber \\ \Sigma_j & = & \V(\T_j(\LS, \w) | S(\LS, \w)) \nonumber \\ & = & \frac{\ws}{\ws - 1} \V(h | S(\LS, \w)) \otimes \left(\sum_i w_i g_j(X_{ji}) \otimes w_i g_j(X_{ji})^\top \right) \label{expectcovar} \\ & - & \frac{1}{\ws - 1} \V(h | S(\LS, \w)) \otimes \left( \sum_i w_i g_j(X_{ji}) \right) \otimes \left( \sum_i w_i g_j(X_{ji})\right)^\top \nonumber \end{eqnarray} where $\ws = \sum_{i = 1}^n w_i$ denotes the sum of the case weights, $\otimes$ is the Kronecker product and the conditional expectation of the influence function is \begin{eqnarray*} \E(h | S(\LS, \w)) = \ws^{-1} \sum_i w_i h(\Y_i, (\Y_1, \dots, \Y_n)) \in \R^q \end{eqnarray*} with corresponding $q \times q$ covariance matrix \begin{eqnarray*} \V(h | S(\LS, \w)) = \ws^{-1} \sum_i w_i \left(h(\Y_i, (\Y_1, \dots, \Y_n)) - \E(h | S(\LS, \w)) \right) \\ \left(h(\Y_i, (\Y_1, \dots, \Y_n)) - \E(h | S(\LS, \w))\right)^\top. \end{eqnarray*} Having the conditional expectation and covariance at hand we are able to standardize a linear statistic $\T \in \R^{pq}$ of the form (\ref{linstat}) for some $p \in \{p_1, \dots, p_m\}$. Univariate test statistics~$c$ mapping an observed multivariate linear statistic $\bft \in \R^{pq}$ into the real line can be of arbitrary form. An obvious choice is the maximum of the absolute values of the standardized linear statistic \begin{eqnarray*} c_\text{max}(\bft, \mu, \Sigma) = \max_{k = 1, \dots, pq} \left| \frac{(\bft - \mu)_k}{\sqrt{(\Sigma)_{kk}}} \right| \end{eqnarray*} utilizing the conditional expectation $\mu$ and covariance matrix $\Sigma$. The application of a quadratic form $c_\text{quad}(\bft, \mu, \Sigma) = (\bft - \mu) \Sigma^+ (\bft - \mu)^\top$ is one alternative, although computationally more expensive because the Moore-Penrose inverse $\Sigma^+$ of $\Sigma$ is involved. The type of test statistic to be used can be specified by means of the \code{ctree\_control} function, for example <>= ctree_control(teststat = "max") @ uses $c_\text{max}$ and <>= ctree_control(teststat = "quad") @ takes $c_\text{quad}$ (the default). It is important to note that the test statistics $c(\bft_j, \mu_j, \Sigma_j), j = 1, \dots, m$, cannot be directly compared in an unbiased way unless all of the covariates are measured at the same scale, i.e., $p_1 = p_j, j = 2, \dots, m$. In order to allow for an unbiased variable selection we need to switch to the $P$-value scale because $P$-values for the conditional distribution of test statistics $c(\T_j(\LS, \w), \mu_j, \Sigma_j)$ can be directly compared among covariates measured at different scales. In step 1 of the generic algorithm we select the covariate with minimum $P$-value, i.e., the covariate $X_{j^*}$ with $j^* = \argmin_{j = 1, \dots, m} P_j$, where \begin{displaymath} P_j = \Prob_{H_0^j}(c(\T_j(\LS, \w), \mu_j, \Sigma_j) \ge c(\bft_j, \mu_j, \Sigma_j) | S(\LS, \w)) \end{displaymath} denotes the $P$-value of the conditional test for $H_0^j$. So far, we have only addressed testing each partial hypothesis $H_0^j$, which is sufficient for an unbiased variable selection. A global test for $H_0$ required in step 1 can be constructed via an aggregation of the transformations $g_j, j = 1, \dots, m$, i.e., using a linear statistic of the form \begin{eqnarray*} \T(\LS, \w) = \vec \left( \sum_{i=1}^n w_i \left(g_1(X_{1i})^\top, \dots, g_m(X_{mi})^\top\right)^\top h(\Y_i, (\Y_1, \dots, \Y_n))^\top \right). %%\in \R^{\sum_j p_jq} \end{eqnarray*} However, this approach is less attractive for learning samples with missing values. Universally applicable approaches are multiple test procedures based on $P_1, \dots, P_m$. Simple Bonferroni-adjusted $P$-values (the adjustment $1 - (1 - P_j)^m$ is used), available via <>= ctree_control(testtype = "Bonferroni") @ or a min-$P$-value resampling approach (Note: resampling is currently not implemented in \code{partykit::ctree}) %<>= %party:::ctree_control(testtype = "MonteCarlo") %@ are just examples and we refer to the multiple testing literature \citep[e.g.,][]{Westfall+Young:1993} for more advanced methods. We reject $H_0$ when the minimum of the adjusted $P$-values is less than a pre-specified nominal level $\alpha$ and otherwise stop the algorithm. In this sense, $\alpha$ may be seen as a unique parameter determining the size of the resulting trees. \subsection{Splitting criteria} Once we have selected a covariate in step 1 of the algorithm, the split itself can be established by any split criterion, including those established by \cite{Breiman+Friedman+Olshen:1984} or \cite{Shih:1999}. Instead of simple binary splits, multiway splits can be implemented as well, for example utilizing the work of \cite{OBrien:2004}. However, most splitting criteria are not applicable to response variables measured at arbitrary scales and we therefore utilize the permutation test framework described above to find the optimal binary split in one selected covariate $X_{j^*}$ in step~2 of the generic algorithm. The goodness of a split is evaluated by two-sample linear statistics which are special cases of the linear statistic (\ref{linstat}). For all possible subsets $A$ of the sample space $\sX_{j^*}$ the linear statistic \begin{eqnarray*} \T^A_{j^*}(\LS, \w) = \vec \left( \sum_{i=1}^n w_i I(X_{j^*i} \in A) h(\Y_i, (\Y_1, \dots, \Y_n))^\top \right) \in \R^{q} \end{eqnarray*} induces a two-sample statistic measuring the discrepancy between the samples $\{ \Y_i | w_i > 0 \text{ and } X_{ji} \in A; i = 1, \dots, n\}$ and $\{ \Y_i | w_i > 0 \text{ and } X_{ji} \not\in A; i = 1, \dots, n\}$. The conditional expectation $\mu_{j^*}^A$ and covariance $\Sigma_{j^*}^A$ can be computed by (\ref{expectcovar}). The split $A^*$ with a test statistic maximized over all possible subsets $A$ is established: \begin{eqnarray} \label{split} A^* = \argmax_A c(\bft_{j^*}^A, \mu_{j^*}^A, \Sigma_{j^*}^A). \end{eqnarray} The statistics $c(\bft_{j^*}^A, \mu_{j^*}^A, \Sigma_{j^*}^A)$ are available for each node with %<>= %party:::ctree_control(savesplitstats = TRUE) %@ and can be used to depict a scatter plot of the covariate $\sX_{j^*}$ against the statistics (Note: this feature is currently not implemented in \pkg{partykit}). Note that we do not need to compute the distribution of $c(\bft_{j^*}^A, \mu_{j^*}^A, \Sigma_{j^*}^A)$ in step~2. In order to anticipate pathological splits one can restrict the number of possible subsets that are evaluated, for example by introducing restrictions on the sample size or the sum of the case weights in each of the two groups of observations induced by a possible split. For example, <>= ctree_control(minsplit = 20) @ requires the sum of the weights in both the left and right daughter node to exceed the value of $20$. \subsection{Missing values and surrogate splits} If an observation $X_{ji}$ in covariate $X_j$ is missing, we set the corresponding case weight $w_i$ to zero for the computation of $\T_j(\LS, \w)$ and, if we would like to split in $X_j$, in $\T_{j}^A(\LS, \w)$ as well. Once a split $A^*$ in $X_j$ has been implemented, surrogate splits can be established by searching for a split leading to roughly the same division of the observations as the original split. One simply replaces the original response variable by a binary variable $I(X_{ji} \in A^*)$ coding the split and proceeds as described in the previous part. The number of surrogate splits can be controlled using <>= ctree_control(maxsurrogate = 3) @ \subsection{Fitting and inspecting a tree} For the sake of simplicity, we use a learning sample <>= ls <- data.frame(y = gl(3, 50, labels = c("A", "B", "C")), x1 = rnorm(150) + rep(c(1, 0, 0), c(50, 50, 50)), x2 = runif(150)) @ in the following illustrations. In \code{partykit::ctree}, the dependency structure and the variables may be specified in a traditional formula based way <>= library("partykit") ctree(y ~ x1 + x2, data = ls) @ Case counts $\w$ may be specified using the \code{weights} argument. Once we have fitted a conditional tree via <>= ct <- ctree(y ~ x1 + x2, data = ls) @ we can inspect the results via a \code{print} method <>= ct @ or by looking at a graphical representation as in Figure~\ref{party-plot1}. \begin{figure}[t!] \centering <>= plot(ct) @ \caption{A graphical representation of a classification tree. \label{party-plot1}} \end{figure} Each node can be extracted by its node number, i.e., the root node is <>= ct[1] @ This object is an object of class <>= class(ct[1]) @ and we refer to the manual pages for a description of those elements. The \code{predict} function computes predictions in the space of the response variable, in our case a factor <>= predict(ct, newdata = ls) @ When we are interested in properties of the conditional distribution of the response given the covariates, we use <>= predict(ct, newdata = ls[c(1, 51, 101),], type = "prob") @ which, in our case, is a data frame with conditional class probabilities. We can determine the node numbers of nodes some new observations are falling into by <>= predict(ct, newdata = ls[c(1,51,101),], type = "node") @ Finally, the \code{sctest} method can be used to extract the test statistics and $p$-values computed in each node. The function \code{sctest} is used because for the \code{mob} algorithm such a method (for \underline{s}tructural \underline{c}hange \underline{test}s) is also provided. To make the generic available, the \pkg{strucchange} package needs to be loaded (otherwise \code{sctest.constparty} would have to be called directly). <>= library("strucchange") sctest(ct) @ Here, we see that \code{x1} leads to a significant test result in the root node and is hence used for splitting. In the kid nodes, no more significant results are found and hence splitting stops. For other data sets, other stopping criteria might also be relevant (e.g., the sample size restrictions \code{minsplit}, \code{minbucket}, etc.). In case, splitting stops due to these, the test results may also be \code{NULL}. \section{Examples} \label{examples} \subsection{Univariate continuous or discrete regression} For a univariate numeric response $\Y \in \R$, the most natural influence function is the identity $h(\Y_i, (\Y_1, \dots, \Y_n)) = \Y_i$. In case some observations with extremely large or small values have been observed, a ranking of the observations may be appropriate: $h(\Y_i, (\Y_1, \dots, \Y_n)) = \sum_{k=1}^n w_k I(\Y_k \le \Y_i)$ for $i = 1, \dots, n$. Numeric covariates can be handled by the identity transformation $g_{ji}(x) = x$ (ranks are possible, too). Nominal covariates at levels $1, \dots, K$ are represented by $g_{ji}(k) = e_K(k)$, the unit vector of length $K$ with $k$th element being equal to one. Due to this flexibility, special test procedures like the Spearman test, the Wilcoxon-Mann-Whitney test or the Kruskal-Wallis test and permutation tests based on ANOVA statistics or correlation coefficients are covered by this framework. Splits obtained from (\ref{split}) maximize the absolute value of the standardized difference between two means of the values of the influence functions. For prediction, one is usually interested in an estimate of the expectation of the response $\E(\Y | \X = \x)$ in each cell, an estimate can be obtained by \begin{eqnarray*} \hat{\E}(\Y | \X = \x) = \left(\sum_{i=1}^n w_i(\x)\right)^{-1} \sum_{i=1}^n w_i(\x) \Y_i. \end{eqnarray*} \subsection{Censored regression} The influence function $h$ may be chosen as Logrank or Savage scores taking censoring into account and one can proceed as for univariate continuous regression. This is essentially the approach first published by \cite{Segal:1988}. An alternative is the weighting scheme suggested by \cite{Molinaro+Dudiot+VanDerLaan:2003}. A weighted Kaplan-Meier curve for the case weights $\w(\x)$ can serve as prediction. \subsection{$J$-class classification} The nominal response variable at levels $1, \dots, J$ is handled by influence functions\linebreak $h(\Y_i, (\Y_1, \dots, \Y_n)) = e_J(\Y_i)$. Note that for a nominal covariate $X_j$ at levels $1, \dots, K$ with $g_{ji}(k) = e_K(k)$ the corresponding linear statistic $\T_j$ is a vectorized contingency table. The conditional class probabilities can be estimated via \begin{eqnarray*} \hat{\Prob}(\Y = y | \X = \x) = \left(\sum_{i=1}^n w_i(\x)\right)^{-1} \sum_{i=1}^n w_i(\x) I(\Y_i = y), \quad y = 1, \dots, J. \end{eqnarray*} \subsection{Ordinal regression} Ordinal response variables measured at $J$ levels, and ordinal covariates measured at $K$ levels, are associated with score vectors $\xi \in \R^J$ and $\gamma \in \R^K$, respectively. Those scores reflect the `distances' between the levels: If the variable is derived from an underlying continuous variable, the scores can be chosen as the midpoints of the intervals defining the levels. The linear statistic is now a linear combination of the linear statistic $\T_j$ of the form \begin{eqnarray*} \M \T_j(\LS, \w) & = & \vec \left( \sum_{i=1}^n w_i \gamma^\top g_j(X_{ji}) \left(\xi^\top h(\Y_i, (\Y_1, \dots, \Y_n)\right)^\top \right) \end{eqnarray*} with $g_j(x) = e_K(x)$ and $h(\Y_i, (\Y_1, \dots, \Y_n)) = e_J(\Y_i)$. If both response and covariate are ordinal, the matrix of coefficients is given by the Kronecker product of both score vectors $\M = \xi \otimes \gamma \in \R^{1, KJ}$. In case the response is ordinal only, the matrix of coefficients $\M$ is a block matrix \begin{eqnarray*} \M = \left( \begin{array}{ccc} \xi_1 & & 0 \\ & \ddots & \\ 0 & & \xi_1 \end{array} \right| %%\left. %% \begin{array}{ccc} %% \xi_2 & & 0 \\ %% & \ddots & \\ %% 0 & & \xi_2 %% \end{array} \right| %%\left. \begin{array}{c} \\ \hdots \\ \\ \end{array} %%\right. \left| \begin{array}{ccc} \xi_q & & 0 \\ & \ddots & \\ 0 & & \xi_q \end{array} \right) %%\in \R^{K, KJ} %%\end{eqnarray*} \text{ or } %%and if one covariate is ordered %%\begin{eqnarray*} %%\M = \left( %% \begin{array}{cccc} %% \gamma & 0 & & 0 \\ %% 0 & \gamma & & \vdots \\ %% 0 & 0 & \hdots & 0 \\ %% \vdots & \vdots & & 0 \\ %% 0 & 0 & & \gamma %% \end{array} %% \right) \M = \text{diag}(\gamma) %%\in \R^{J, KJ} \end{eqnarray*} when one covariate is ordered but the response is not. For both $\Y$ and $X_j$ being ordinal, the corresponding test is known as linear-by-linear association test \citep{Agresti:2002}. Scores can be supplied to \code{ctree} using the \code{scores} argument, see Section~\ref{illustrations} for an example. \subsection{Multivariate regression} For multivariate responses, the influence function is a combination of influence functions appropriate for any of the univariate response variables discussed in the previous paragraphs, e.g., indicators for multiple binary responses \citep{Zhang:1998,Noh+Song+Park:2004}, Logrank or Savage scores for multiple failure times %%\citep[for example tooth loss times, ][]{SuFan2004} and the original observations or a rank transformation for multivariate regression \citep{Death:2002}. \section{Illustrations and applications} \label{illustrations} In this section, we present regression problems which illustrate the potential fields of application of the methodology. Conditional inference trees based on $c_\text{quad}$-type test statistics using the identity influence function for numeric responses and asymptotic $\chi^2$ distribution are applied. For the stopping criterion a simple Bonferroni correction is used and we follow the usual convention by choosing the nominal level of the conditional independence tests as $\alpha = 0.05$. \subsection{Tree pipit abundance} <>= data("treepipit", package = "coin") tptree <- ctree(counts ~ ., data = treepipit) @ \begin{figure}[t!] \centering <>= plot(tptree, terminal_panel = node_barplot) @ \caption{Conditional regression tree for the tree pipit data.} \end{figure} <>= p <- info_node(node_party(tptree))$p.value n <- table(predict(tptree, type = "node")) @ The impact of certain environmental factors on the population density of the tree pipit \textit{Anthus trivialis} %%in Frankonian oak forests is investigated by \cite{Mueller+Hothorn:2004}. The occurrence of tree pipits was recorded several times at $n = 86$ stands which were established on a long environmental gradient. Among nine environmental factors, the covariate showing the largest association to the number of tree pipits is the canopy overstorey $(P = \Sexpr{round(p, 3)})$. Two groups of stands can be distinguished: Sunny stands with less than $40\%$ canopy overstorey $(n = \Sexpr{n[1]})$ show a significantly higher density of tree pipits compared to darker stands with more than $40\%$ canopy overstorey $(n = \Sexpr{n[2]})$. This result is important for management decisions in forestry enterprises: Cutting the overstorey with release of old oaks creates a perfect habitat for this indicator species of near natural forest environments. \subsection{Glaucoma and laser scanning images} <>= data("GlaucomaM", package = "TH.data") gtree <- ctree(Class ~ ., data = GlaucomaM) @ <>= sp <- split_node(node_party(gtree))$varID @ Laser scanning images taken from the eye background are expected to serve as the basis of an automated system for glaucoma diagnosis. Although prediction is more important in this application \citep{Mardin+Hothorn+Peters:2003}, a simple visualization of the regression relationship is useful for comparing the structures inherent in the learning sample with subject matter knowledge. For $98$ patients and $98$ controls, matched by age and gender, $62$ covariates describing the eye morphology are available. The data is part of the \pkg{TH.data} package, \url{http://CRAN.R-project.org}). The first split in Figure~\ref{glaucoma} separates eyes with a volume above reference less than $\Sexpr{sp} \text{ mm}^3$ in the inferior part of the optic nerve head (\code{vari}). Observations with larger volume are mostly controls, a finding which corresponds to subject matter knowledge: The volume above reference measures the thickness of the nerve layer, expected to decrease with a glaucomatous damage of the optic nerve. Further separation is achieved by the volume above surface global (\code{vasg}) and the volume above reference in the temporal part of the optic nerve head (\code{vart}). \setkeys{Gin}{width=.9\textwidth} \begin{figure}[p!] \centering <>= plot(gtree) @ \caption{Conditional inference tree for the glaucoma data. For each inner node, the Bonferroni-adjusted $P$-values are given, the fraction of glaucomatous eyes is displayed for each terminal node. \label{glaucoma}} <>= plot(gtree, inner_panel = node_barplot, edge_panel = function(...) invisible(), tnex = 1) @ \caption{Conditional inference tree for the glaucoma data with the fraction of glaucomatous eyes displayed for both inner and terminal nodes. \label{glaucoma-inner}} \end{figure} The plot in Figure~\ref{glaucoma} is generated by <>= plot(gtree) @ \setkeys{Gin}{width=\textwidth} and shows the distribution of the classes in the terminal nodes. This distribution can be shown for the inner nodes as well, namely by specifying the appropriate panel generating function (\code{node\_barplot} in our case), see Figure~\ref{glaucoma-inner}. <>= plot(gtree, inner_panel = node_barplot, edge_panel = function(...) invisible(), tnex = 1) @ %% TH: split statistics are not saved in partykit %As mentioned in Section~\ref{framework}, it might be interesting to have a %look at the split statistics the split point estimate was derived from. %Those statistics can be extracted from the \code{splitstatistic} element %of a split and one can easily produce scatterplots against the selected %covariate. For all three inner nodes of \code{gtree}, we produce such a %plot in Figure~\ref{glaucoma-split}. For the root node, the estimated split point %seems very natural, since the process of split statistics seems to have a %clear maximum indicating that the simple split point model is something %reasonable to assume here. This is less obvious for nodes $2$ and, %especially, $3$. % %\begin{figure}[t!] %\centering %<>= %cex <- 1.6 %inner <- nodes(gtree, c(1, 2, 5)) %layout(matrix(1:length(inner), ncol = length(inner))) %out <- sapply(inner, function(i) { % splitstat <- i$psplit$splitstatistic % x <- GlaucomaM[[i$psplit$variableName]][splitstat > 0] % plot(x, splitstat[splitstat > 0], main = paste("Node", i$nodeID), % xlab = i$psplit$variableName, ylab = "Statistic", ylim = c(0, 10), % cex.axis = cex, cex.lab = cex, cex.main = cex) % abline(v = i$psplit$splitpoint, lty = 3) %}) %@ %\caption{Split point estimation in each inner node. The process of % the standardized two-sample test statistics for each possible % split point in the selected input variable is show. % The estimated split point is given as vertical dotted line. % \label{glaucoma-split}} %\end{figure} The class predictions of the tree for the learning sample (and for new observations as well) can be computed using the \code{predict} function. A comparison with the true class memberships is done by <>= table(predict(gtree), GlaucomaM$Class) @ When we are interested in conditional class probabilities, the \code{predict(, type = "prob")} method must be used. A graphical representation is shown in Figure~\ref{glaucoma-probplot}. \setkeys{Gin}{width=.5\textwidth} \begin{figure}[t!] \centering <>= prob <- predict(gtree, type = "prob")[,1] + runif(nrow(GlaucomaM), min = -0.01, max = 0.01) splitvar <- character_split(split_node(node_party(gtree)), data = data_party(gtree))$name plot(GlaucomaM[[splitvar]], prob, pch = as.numeric(GlaucomaM$Class), ylab = "Conditional Class Prob.", xlab = splitvar) abline(v = split_node(node_party(gtree))$breaks, lty = 2) legend(0.15, 0.7, pch = 1:2, legend = levels(GlaucomaM$Class), bty = "n") @ \caption{Estimated conditional class probabilities (slightly jittered) for the Glaucoma data depending on the first split variable. The vertical line denotes the first split point. \label{glaucoma-probplot}} \end{figure} \subsection{Node positive breast cancer} Recursive partitioning for censored responses has attracted a lot of interest \citep[e.g.,][]{Segal:1988,LeBlanc+Crowley:1992}. Survival trees using $P$-value adjusted Logrank statistics are used by \cite{Schumacher+Hollaender+Schwarzer:2001a} for the evaluation of prognostic factors for the German Breast Cancer Study Group (GBSG2) data, a prospective controlled clinical trial on the treatment of node positive breast cancer patients. Here, we use Logrank scores as well. Complete data of seven prognostic factors of $686$ women are used for prognostic modeling, the dataset is available within the \pkg{TH.data} package. The number of positive lymph nodes (\code{pnodes}) and the progesterone receptor (\code{progrec}) have been identified as prognostic factors in the survival tree analysis by \cite{Schumacher+Hollaender+Schwarzer:2001a}. Here, the binary variable coding whether a hormonal therapy was applied or not (\code{horTh}) additionally is part of the model depicted in Figure~\ref{gbsg2}, which was fitted using the following code: <>= data("GBSG2", package = "TH.data") library("survival") (stree <- ctree(Surv(time, cens) ~ ., data = GBSG2)) @ \setkeys{Gin}{width=\textwidth} \begin{figure}[t!] \centering <>= plot(stree) @ \caption{Tree-structured survival model for the GBSG2 data and the distribution of survival times in the terminal nodes. The median survival time is displayed in each terminal node of the tree. \label{gbsg2}} \end{figure} The estimated median survival time for new patients is less informative compared to the whole Kaplan-Meier curve estimated from the patients in the learning sample for each terminal node. We can compute those `predictions' by means of the \code{treeresponse} method <>= pn <- predict(stree, newdata = GBSG2[1:2,], type = "node") n <- predict(stree, type = "node") survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[1])) survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[2])) @ \subsection{Mammography experience} <>= data("mammoexp", package = "TH.data") mtree <- ctree(ME ~ ., data = mammoexp) @ \setkeys{Gin}{width=.9\textwidth, keepaspectratio=TRUE} \begin{figure}[t!] \centering <>= plot(mtree) @ \caption{Ordinal regression for the mammography experience data with the fractions of (never, within a year, over one year) given in the nodes. No admissible split was found for node 5 because only $5$ of $91$ women reported a family history of breast cancer and the sample size restrictions would require more than $5$ observations in each daughter node. \label{mammoexp}} \end{figure} Ordinal response variables are common in investigations where the response is a subjective human interpretation. We use an example given by \cite{Hosmer+Lemeshow:2000}, p.~264, studying the relationship between the mammography experience (never, within a year, over one year) and opinions about mammography expressed in questionnaires answered by $n = 412$ women. The resulting partition based on scores $\xi = (1,2,3)$ is given in Figure~\ref{mammoexp}. Women who (strongly) agree with the question `You do not need a mammogram unless you develop symptoms' seldomly have experienced a mammography. The variable \code{benefit} is a score with low values indicating a strong agreement with the benefits of the examination. For those women in (strong) disagreement with the first question above, low values of \code{benefit} identify persons being more likely to have experienced such an examination at all. \subsection{Hunting spiders} Finally, we take a closer look at a challenging dataset on animal abundance first reported by \cite{VanDerAart+SmeenkEnserink:1975} and re-analyzed by \cite{Death:2002} using regression trees dealing with multivariate responses. The abundance of $12$ hunting spider species is regressed on six environmental variables (\code{water}, \code{sand}, \code{moss}, \code{reft}, \code{twigs} and \code{herbs}) for $n = 28$ observations. Because of the small sample size we allow for a split if at least $5$ observations are element of a node The prognostic factor \code{water} found by \cite{Death:2002} is confirmed by the model shown in Figures~\ref{spider1} and~\ref{spider2} which additionally identifies \code{reft}. The data are available in package \pkg{mvpart} \citep{mvpart}. <>= data("HuntingSpiders", package = "partykit") sptree <- ctree(arct.lute + pard.lugu + zora.spin + pard.nigr + pard.pull + aulo.albi + troc.terr + alop.cune + pard.mont + alop.acce + alop.fabr + arct.peri ~ herbs + reft + moss + sand + twigs + water, data = HuntingSpiders, teststat = "max", minsplit = 5, pargs = GenzBretz(abseps = .1, releps = .1)) @ \setkeys{Gin}{width=\textwidth, keepaspectratio=TRUE} \begin{figure}[t!] \centering <>= plot(sptree, terminal_panel = node_barplot) @ \caption{Regression tree for hunting spider abundance with bars for the mean of each response. \label{spider1}} \end{figure} \setkeys{Gin}{height=.93\textheight, keepaspectratio=TRUE} \begin{figure}[p!] \centering <>= plot(sptree) @ \caption{Regression tree for hunting spider abundance with boxplots for each response. \label{spider2}} \end{figure} \section{Backward compatibility and novel functionality} \label{sec:novel} \code{partykit::ctree} is a complete reimplementation of \code{party::ctree}. The latter reference implementation is based on a monolithic \proglang{C} core and an \proglang{S4}-based \proglang{R} interface. The novel implementation of conditional inference trees in \pkg{partykit} is much more modular and was almost entirely written in \proglang{R} (package \pkg{partykit} does not contain any foreign language code as of version 1.2-0). Permutation tests are computed in the dedicated \proglang{R} add-on package \pkg{libcoin}. Nevertheless, both implementations will almost every time produce the same tree. There are, naturally, exceptions where ensuring backward-compatibility requires specific choices of hyper parameters in \code{partykit::ctree_control}. We will demonstrate how one can compute the same trees in \pkg{partykit} and \pkg{party} in this section. In addition, some novel features introduced in \pkg{partykit} 1.2-0 are described. \subsection{Regression} <>= library("party") set.seed(290875) @ We use the \code{airquality} data from package \pkg{party} and fit a regression tree after removal of missing response values. There are missing values in one of the explanatory variables, so we ask for three surrogate splits to be set-up: <>= data("airquality", package = "datasets") airq <- subset(airquality, !is.na(Ozone)) (airct_party <- party::ctree(Ozone ~ ., data = airq, controls = party::ctree_control(maxsurrogate = 3))) mean((airq$Ozone - predict(airct_party))^2) @ For this specific example, the same call produces the same tree under both \pkg{party} and \pkg{partykit}. To ensure this also for other patterns of missingness, the \code{numsurrogate} flag needs to be set in order to restrict the evaluation of surrogate splits to numeric variables only (this is a restriction hard-coded in \pkg{party}): <>= (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, numsurrogate = TRUE))) mean((airq$Ozone - predict(airct_partykit))^2) table(predict(airct_party, type = "node"), predict(airct_partykit, type = "node")) max(abs(predict(airct_party) - predict(airct_partykit))) @ The results are identical as are the underlying test statistics: <>= airct_party@tree$criterion info_node(node_party(airct_partykit)) @ \code{partykit} has a nicer way or presenting the variable selection test statistics on the scale of the statistics and the $p$-values. In addition, the criterion to be maximised (here: $\log(1 - p-\text{value})$) is given. \subsection{Classification} For classification tasks with more than two classes, the default in \pkg{party} is a maximum-type test statistic on the multidimensional test statistic when computing splits. \pkg{partykit} employs a quadratic test statistic by default, because it was found to produce better splits empirically. One can switch-back to the old behaviour using the \code{splitstat} argument: <>= (irisct_party <- party::ctree(Species ~ .,data = iris)) (irisct_partykit <- partykit::ctree(Species ~ .,data = iris, control = partykit::ctree_control(splitstat = "maximum"))) table(predict(irisct_party, type = "node"), predict(irisct_partykit, type = "node")) @ The interface for computing conditional class probabilities changed from <>= tr_party <- treeresponse(irisct_party, newdata = iris) @ to <>= tr_partykit <- predict(irisct_partykit, type = "prob", newdata = iris) max(abs(do.call("rbind", tr_party) - tr_partykit)) @ leading to identical results. For ordinal regression, the conditional class probabilities can be computed in the very same way: <>= ### ordinal regression data("mammoexp", package = "TH.data") (mammoct_party <- party::ctree(ME ~ ., data = mammoexp)) ### estimated class probabilities tr_party <- treeresponse(mammoct_party, newdata = mammoexp) (mammoct_partykit <- partykit::ctree(ME ~ ., data = mammoexp)) ### estimated class probabilities tr_partykit <- predict(mammoct_partykit, newdata = mammoexp, type = "prob") max(abs(do.call("rbind", tr_party) - tr_partykit)) @ \subsection{Survival Analysis} Like in classification analysis, the \code{treeresponse} function from package \code{party} was replaced by the \code{predict} function with argument \code{type = "prob"} in \pkg{partykit}. The default survival trees are identical: <>= data("GBSG2", package = "TH.data") (GBSG2ct_party <- party::ctree(Surv(time, cens) ~ .,data = GBSG2)) (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ .,data = GBSG2)) @ as are the conditional Kaplan-Meier estimators <>= tr_party <- treeresponse(GBSG2ct_party, newdata = GBSG2) tr_partykit <- predict(GBSG2ct_partykit, newdata = GBSG2, type = "prob") all.equal(lapply(tr_party, function(x) unclass(x)[!(names(x) %in% "call")]), lapply(tr_partykit, function(x) unclass(x)[!(names(x) %in% "call")]), check.names = FALSE) @ \subsection{New Features} \pkg{partykit} comes with additional arguments in \code{ctree_control} allowing a more detailed control over the tree growing. \begin{description} \item[\code{alpha}]: The user can optionally change the default nominal level of $\alpha = 0.05$; \code{mincriterion} is updated to $1 - \alpha$ and \code{logmincriterion} is then $\log(1 - \alpha)$. The latter allows variable selection on the scale of $\log(1 - p\text{-value})$: <>= (airct_partykit_1 <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, alpha = 0.001, numsurrogate = FALSE))) depth(airct_partykit_1) mean((airq$Ozone - predict(airct_partykit_1))^2) @ Lower values of $\alpha$ lead to smaller trees. \item[\code{splittest}]: This enables the computation of $p$-values for maximally selected statistics for variable selection. The default test statistic is not particularly powerful against cutpoint-alternatives but much faster to compute. Currently, $p$-value approximations are not available, so one has to rely on resampling for $p$-value estimation <>= (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, splittest = TRUE, testtype = "MonteCarlo"))) @ \item[\code{saveinfo}]: Reduces the memory footprint by not storing test results as part of the tree. The core information about trees is then roughly half the size needed by \code{party}. \item[\code{nmax}]: Restricts the number of possible cutpoints to \code{nmax}, basically by treating all explanatory variables as ordered factors defined at quantiles of underlying numeric variables. This is mainly implemented in package \pkg{libcoin}. For the standard \code{ctree}, it is only appropriate to use in classification problems, where is can lead to substantial speed-ups: <>= (irisct_partykit_1 <- partykit::ctree(Species ~ .,data = iris, control = partykit::ctree_control(splitstat = "maximum", nmax = 25))) table(predict(irisct_partykit), predict(irisct_partykit_1)) @ \item[\code{multiway}]: Implements multiway splits in unordered factors, each level defines a corresponding daughter node: <>= GBSG2$tgrade <- factor(GBSG2$tgrade, ordered = FALSE) (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ tgrade, data = GBSG2, control = partykit::ctree_control(multiway = TRUE, alpha = .5))) @ \item[\code{majority = FALSE}]: enables random assignment of non-splitable observations to daughter nodes preserving the node distribution. With \code{majority = TRUE}, these observations go with the majority (the only available behaviour of in \code{party::ctree}). \end{description} Two arguments of \code{ctree} are also interesting. The novel \code{cluster} argument allows conditional inference trees to be fitted to (simple forms of) correlated observations. For each cluster, the variance of the test statistics used for variable selection and also splitting is computed separately, leading to stratified permutation tests (in the sense that only observations within clusters are permuted). For example, we can cluster the data in the \code{airquality} dataset by month to be used as cluster variable: <>= airq$month <- factor(airq$Month) (airct_partykit_3 <- partykit::ctree(Ozone ~ Solar.R + Wind + Temp, data = airq, cluster = month, control = partykit::ctree_control(maxsurrogate = 3))) info_node(node_party(airct_partykit_3)) mean((airq$Ozone - predict(airct_partykit_3))^2) @ This reduces the number of partitioning variables and makes multiplicity adjustment less costly. The \code{ytrafo} argument has be made more general. \pkg{party} is not able to update influence functions $h$ within nodes. With the novel formula-based interface, users can create influence functions which are newly evaluated in each node. The following example illustrates how one can compute a survival tree with updated logrank scores: <>= ### with weight-dependent log-rank scores ### log-rank trafo for observations in this node only (= weights > 0) h <- function(y, x, start = NULL, weights, offset, estfun = TRUE, object = FALSE, ...) { if (is.null(weights)) weights <- rep(1, NROW(y)) s <- logrank_trafo(y[weights > 0,,drop = FALSE]) r <- rep(0, length(weights)) r[weights > 0] <- s list(estfun = matrix(as.double(r), ncol = 1), converged = TRUE, unweighted = TRUE) } partykit::ctree(Surv(time, cens) ~ ., data = GBSG2, ytrafo = h) @ The results are usually not very sensitive to (simple) updated influence functions. However, when one uses score functions of more complex models as influence functions (similar to the \code{mob} family of trees), it is necessary to refit models in each node. For example, we are interested in a normal linear model for ozone concentration given temperature; both the intercept and the regression coefficient for temperature shall vary across nodes of a tree. Such a ``permutation-based'' MOB, here taking clusters into account, can be set-up using <>= ### normal varying intercept / varying coefficient model (aka "mob") h <- function(y, x, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ...) glm(y ~ 0 + x, family = gaussian(), start = start, weights = weights, ...) (airct_partykit_4 <- partykit::ctree(Ozone ~ Temp | Solar.R + Wind, data = airq, cluster = month, ytrafo = h, control = partykit::ctree_control(maxsurrogate = 3))) airq$node <- factor(predict(airct_partykit_4, type = "node")) summary(m <- glm(Ozone ~ node + node:Temp - 1, data = airq)) mean((predict(m) - airq$Ozone)^2) @ Both intercept and effect of temperature change considerably between nodes. The corresponding MOB can be fitted using <>= airq_lmtree <- partykit::lmtree(Ozone ~ Temp | Solar.R + Wind, data = airq, cluster = month) info_node(node_party(airq_lmtree)) mean((predict(airq_lmtree, newdata = airq) - airq$Ozone)^2) @ The $p$-values in the root node are similar but the two procedures find different splits. \code{mob} (and therefore \code{lmtree}) directly search for splits by optimising the objective function for all possible splits whereas \code{ctree} only works with the score functions. Argument \code{xtrafo} allowing the user to change the transformations $g_j$ of the covariates was removed from the user interface. <>= detach(package:party) @ \bibliography{party} \end{document} partykit/R/0000755000176200001440000000000014415225047012326 5ustar liggesuserspartykit/R/lmtree.R0000644000176200001440000001012014172230000013714 0ustar liggesusers## simple wrapper function to specify fitter and return class lmtree <- function(formula, data, subset, na.action, weights, offset, cluster, ...) { ## TODO: variance as model parameter ## use dots for setting up mob_control control <- mob_control(...) if(control$vcov != "opg") { warning('only vcov = "opg" supported in lmtree') control$vcov <- "opg" } if(!is.null(control$prune)) { if(is.character(control$prune)) { control$prune <- tolower(control$prune) control$prune <- match.arg(control$prune, c("aic", "bic", "none")) control$prune <- switch(control$prune, "aic" = { function(objfun, df, nobs) (nobs[1L] * log(objfun[1L]) + 2 * df[1L]) < (nobs[1L] * log(objfun[2L]) + 2 * df[2L]) }, "bic" = { function(objfun, df, nobs) (nobs[1L] * log(objfun[1L]) + log(nobs[2L]) * df[1L]) < (nobs[1L] * log(objfun[2L]) + log(nobs[2L]) * df[2L]) }, "none" = { NULL }) } if(!is.function(control$prune)) { warning("unknown specification of 'prune'") control$prune <- NULL } } ## keep call cl <- match.call(expand.dots = TRUE) ## extend formula if necessary f <- Formula::Formula(formula) if(length(f)[2L] == 1L) { attr(f, "rhs") <- c(list(1), attr(f, "rhs")) formula[[3L]] <- formula(f)[[3L]] } else { f <- NULL } ## call mob m <- match.call(expand.dots = FALSE) if(!is.null(f)) m$formula <- formula m$fit <- lmfit m$control <- control if("..." %in% names(m)) m[["..."]] <- NULL m[[1L]] <- as.call(quote(partykit::mob)) rval <- eval(m, parent.frame()) ## extend class and keep original call rval$info$call <- cl class(rval) <- c("lmtree", class(rval)) return(rval) } ## actual fitting function for mob() lmfit <- function(y, x, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ..., estfun = FALSE, object = FALSE) { ## add intercept-only regressor matrix (if missing) ## NOTE: does not have terms/formula if(is.null(x)) x <- matrix(1, nrow = NROW(y), ncol = 1L, dimnames = list(NULL, "(Intercept)")) ## call lm fitting function if(is.null(weights) || identical(as.numeric(weights), rep.int(1, length(weights)))) { z <- lm.fit(x, y, offset = offset, ...) weights <- 1 } else { z <- lm.wfit(x, y, w = weights, offset = offset, ...) } ## list structure rval <- list( coefficients = z$coefficients, objfun = sum(weights * z$residuals^2), estfun = NULL, object = NULL ) ## add estimating functions (if desired) if(estfun) { rval$estfun <- as.vector(z$residuals) * weights * x[, !is.na(z$coefficients), drop = FALSE] } ## add model (if desired) if(object) { class(z) <- c(if(is.matrix(z$fitted)) "mlm", "lm") z$offset <- if(is.null(offset)) 0 else offset z$contrasts <- attr(x, "contrasts") z$xlevels <- attr(x, "xlevels") cl <- as.call(expression(lm)) cl$formula <- attr(x, "formula") if(!is.null(offset)) cl$offset <- attr(x, "offset") z$call <- cl z$terms <- attr(x, "terms") rval$object <- z } return(rval) } ## methods print.lmtree <- function(x, title = "Linear model tree", objfun = "residual sum of squares", ...) { print.modelparty(x, title = title, objfun = objfun, ...) } predict.lmtree <- function(object, newdata = NULL, type = "response", ...) { ## FIXME: possible to get default? if(is.null(newdata) & !identical(type, "node")) stop("newdata has to be provided") predict.modelparty(object, newdata = newdata, type = type, ...) } plot.lmtree <- function(x, terminal_panel = node_bivplot, tp_args = list(), tnex = NULL, drop_terminal = NULL, ...) { nreg <- if(is.null(tp_args$which)) x$info$nreg else length(tp_args$which) if(nreg < 1L & missing(terminal_panel)) { plot.constparty(as.constparty(x), tp_args = tp_args, tnex = tnex, drop_terminal = drop_terminal, ...) } else { if(is.null(tnex)) tnex <- if(is.null(terminal_panel)) 1L else 2L * nreg if(is.null(drop_terminal)) drop_terminal <- !is.null(terminal_panel) plot.modelparty(x, terminal_panel = terminal_panel, tp_args = tp_args, tnex = tnex, drop_terminal = drop_terminal, ...) } } partykit/R/print.R0000644000176200001440000001245014172230000013570 0ustar liggesusersprint.partynode <- function(x, data = NULL, names = NULL, inner_panel = function(node) "", terminal_panel = function(node) " *", prefix = "", first = TRUE, digits = getOption("digits") - 2, ...) { ids <- nodeids(x) if(first) { if(is.null(names)) names <- as.character(ids) cat(paste(prefix, "[", names[which(ids == id_node(x))], "] root", sep = "")) if(is.terminal(x)) { char <- terminal_panel(x) if(length(char) > 1L) { cat(paste(char[1L], "\n", paste(prefix, " ", char[-1L], sep = "", collapse = "\n"), sep = ""), "\n") } else { cat(char, "\n") } } else { cat("\n") } } if (length(x) > 0) { ## add indentation nextprefix <- paste(prefix, "| ", sep = "") ## split labels slabs <- character_split(split_node(x), data = data, digits = digits, ...) slabs <- ifelse(substr(slabs$levels, 1, 1) %in% c("<", ">"), paste(slabs$name, slabs$levels), paste(slabs$name, "in", slabs$levels)) ## kid labels knodes <- kids_node(x) knam <- sapply(knodes, function(z) names[which(ids == id_node(z))]) klabs <- sapply(knodes, function(z) if(is.terminal(z)) { char <- terminal_panel(z) if(length(char) > 1L) { paste(char[1L], "\n", paste(nextprefix, " ", char[-1L], sep = "", collapse = "\n"), sep = "") } else { char } } else { paste(inner_panel(z), collapse = "\n") }) ## merge, cat, and call recursively labs <- paste("| ", prefix, "[", knam, "] ", slabs, klabs, "\n", sep = "") for (i in 1:length(x)) { cat(labs[i]) print.partynode(x[i], data = data, names = names[match(nodeids(x[i]), ids)], inner_panel = inner_panel, terminal_panel = terminal_panel, prefix = nextprefix, first = FALSE, digits = digits, ...) } } } print.party <- function(x, terminal_panel = function(node) formatinfo_node(node, default = "*", prefix = ": "), tp_args = list(), inner_panel = function(node) "", ip_args = list(), header_panel = function(party) "", footer_panel = function(party) "", digits = getOption("digits") - 2, ...) { ## header cat(paste(header_panel(x), collapse = "\n")) ## nodes if(inherits(terminal_panel, "grapcon_generator")) terminal_panel <- do.call("terminal_panel", c(list(x), as.list(tp_args))) if(inherits(inner_panel, "grapcon_generator")) inner_panel <- do.call("inner_panel", c(list(x), as.list(ip_args))) print(node_party(x), x$data, names = names(x), terminal_panel = terminal_panel, inner_panel = inner_panel, digits = digits, ...) ## footer cat(paste(footer_panel(x), collapse = "\n")) } print.constparty <- function(x, FUN = NULL, digits = getOption("digits") - 4, header = NULL, footer = TRUE, ...) { if(is.null(FUN)) return(print(as.simpleparty(x), digits = digits, header = header, footer = footer, ...)) digits <- max(c(0, digits)) ## FIXME: terms/call/? for "ctree" objects if(is.null(header)) header <- !is.null(terms(x)) header_panel <- if(header) function(party) { c("", "Model formula:", deparse(formula(terms(party))), "", "Fitted party:", "") } else function(party) "" footer_panel <- if(footer) function(party) { n <- width(party) n <- format(c(length(party) - n, n)) c("", paste("Number of inner nodes: ", n[1]), paste("Number of terminal nodes:", n[2]), "") } else function (party) "" y <- x$fitted[["(response)"]] w <- x$fitted[["(weights)"]] if(is.null(w)) { wdigits <- 0 wsym <- "n" } else { if(isTRUE(all.equal(w, round(w)))) { wdigits <- 0 wsym <- "n" } else { wdigits <- max(c(0, digits - 2)) wsym <- "w" } } yclass <- .response_class(y) if(yclass == "ordered") yclass <- "factor" if(!(yclass %in% c("Surv", "factor"))) yclass <- "numeric" if(is.null(FUN)) FUN <- switch(yclass, "numeric" = function(y, w, digits) { yhat <- .pred_numeric_response(y, w) yerr <- sum(w * (y - yhat)^2) digits2 <- max(c(0, digits - 2)) paste(format(round(yhat, digits = digits), nsmall = digits), " (", wsym, " = ", format(round(sum(w), digits = wdigits), nsmall = wdigits), ", err = ", format(round(yerr, digits = digits2), nsmall = digits2), ")", sep = "") }, "Surv" = function(y, w, digits) { paste(format(round(.pred_Surv_response(y, w), digits = digits), nsmall = digits), " (", wsym, " = ", format(round(sum(w), digits = wdigits), nsmall = wdigits), ")", sep = "") }, "factor" = function(y, w, digits) { tab <- round(.pred_factor(y, w) * sum(w)) mc <- round(100 * (1 - max(tab)/sum(w)), digits = max(c(0, digits - 2))) paste(names(tab)[which.max(tab)], " (", wsym, " = ", format(round(sum(w), digits = wdigits), nsmall = wdigits), ", err = ", mc, "%)", sep = "") } ) node_labs <- nodeapply(x, nodeids(x), function(node) { y1 <- node$fitted[["(response)"]] w <- node$fitted[["(weights)"]] if(is.null(w)) w <- rep.int(1L, NROW(y1)) FUN(y1, w, digits) }, by_node = FALSE) node_labs <- paste(":", format(do.call("c", node_labs))) terminal_panel <- function(node) node_labs[id_node(node)] print.party(x, terminal_panel = terminal_panel, header_panel = header_panel, footer_panel = footer_panel, ...) } partykit/R/utils.R0000644000176200001440000000674314172230000013604 0ustar liggesusers ### length(x) == 1 will lead to sample.int instead of sample; ### see example(sample) .resample <- function(x, ...) x[sample.int(length(x), ...)] .median_survival_time <- function(x) { minmin <- function(y, xx) { if (any(!is.na(y) & y==.5)) { if (any(!is.na(y) & y <.5)) .5*(min(xx[!is.na(y) & y==.5]) + min(xx[!is.na(y) & y<.5])) else .5*(min(xx[!is.na(y) & y==.5]) + max(xx[!is.na(y) & y==.5])) } else min(xx[!is.na(y) & y<=.5]) } med <- suppressWarnings(minmin(x$surv, x$time)) return(med) } get_paths <- function(obj, i) { id0 <- nodeids(obj) if (inherits(obj, "party")) obj <- node_party(obj) if (!inherits(obj, "partynode")) stop(sQuote("obj"), " is not an object of class partynode") i <- as.integer(i) if (!all(i %in% id0)) stop(sQuote("i"), " does not match node identifiers of ", sQuote("obj")) lapply(i, function(id) { if (id == 1L) return(1L) .get_path(obj, id) }) } ### get the recursive index ### obj is of class "partynode" .get_path <- function(obj, i) { idx <- c() recFun <- function(node, i) { if (id_node(node) == i) return(NULL) idx <<- c(idx, which(names(unclass(node)) == "kids")) kid <- sapply(kids_node(node), id_node) nextid <- max(which(kid <= i)) idx <<- c(idx, nextid) return(recFun(node[[nextid]], i)) } out <- recFun(obj, i) return(idx) } ### shall we export this functionality? "nodeids<-" <- function(obj, value) UseMethod("nodeids<-") "nodeids<-.party" <- function(obj, value) { id0 <- nodeids(obj) id1 <- as.integer(value) stopifnot(identical(id1, 1:length(id0))) idxs <- lapply(id0, .get_path, obj = node_party(obj)) x <- unclass(obj) ni <- which(names(x) == "node") nm <- x$names for (i in 1:length(idxs)) x[[c(ni, idxs[[i]])]]$id <- id1[i] class(x) <- class(obj) if (!is.null(nm)) names(x) <- nm[id0] return(x) } "nodeids<-.constparty" <- "nodeids<-.modelparty" <- function(obj, value) { id0 <- nodeids(obj) cls <- class(obj) class(obj) <- "party" nodeids(obj) <- value id1 <- nodeids(obj) obj$fitted[["(fitted)"]] <- id1[match(fitted(obj)[["(fitted)"]], id0)] class(obj) <- cls obj } ### ## determine all possible splits for a factor, both nominal and ordinal .mob_grow_getlevels <- function(z) { nl <- nlevels(z) if(inherits(z, "ordered")) { indx <- diag(nl) indx[lower.tri(indx)] <- 1 indx <- indx[-nl, , drop = FALSE] rownames(indx) <- levels(z)[-nl] } else { mi <- 2^(nl - 1L) - 1L indx <- matrix(0, nrow = mi, ncol = nl) for (i in 1L:mi) { ii <- i for (l in 1L:nl) { indx[i, l] <- ii %% 2L ii <- ii %/% 2L } } rownames(indx) <- apply(indx, 1L, function(x) paste(levels(z)[x > 0], collapse = "+")) } colnames(indx) <- as.character(levels(z)) storage.mode(indx) <- "logical" indx } .rfweights <- function(fdata, fnewdata, rw, scale) w <- .Call(R_rfweights, fdata, fnewdata, rw, scale) ### determine class of response .response_class <- function(x) { if (is.factor(x)) { if (is.ordered(x)) return("ordered") return("factor") } if (inherits(x, "Surv")) return("Surv") if (inherits(x, "survfit")) return("survfit") if (inherits(x, "AsIs")) return("numeric") if (is.integer(x)) return("numeric") if (is.numeric(x)) return("numeric") return("unknown") } partykit/R/zzz.R0000644000176200001440000000161614172230000013273 0ustar liggesusersregister_s3_method <- function(pkg, generic, class, fun = NULL) { stopifnot(is.character(pkg), length(pkg) == 1L) stopifnot(is.character(generic), length(generic) == 1L) stopifnot(is.character(class), length(class) == 1L) if (is.null(fun)) { fun <- get(paste0(generic, ".", class), envir = parent.frame()) } else { stopifnot(is.function(fun)) } if (pkg %in% loadedNamespaces()) { registerS3method(generic, class, fun, envir = asNamespace(pkg)) } # Always register hook in case package is later unloaded & reloaded setHook( packageEvent(pkg, "onLoad"), function(...) { registerS3method(generic, class, fun, envir = asNamespace(pkg)) } ) } .onLoad <- function(libname, pkgname) { if(getRversion() < "3.6.0") { register_s3_method("strucchange", "sctest", "constparty") register_s3_method("strucchange", "sctest", "modelparty") } invisible() } partykit/R/cforest.R0000644000176200001440000002650014172230000014102 0ustar liggesusers ### constructor for forest objects constparties <- function(nodes, data, weights, fitted = NULL, terms = NULL, info = NULL) { stopifnot(all(sapply(nodes, function(x) inherits(x, "partynode")))) stopifnot(inherits(data, "data.frame")) stopifnot(inherits(weights, "list")) if(!is.null(fitted)) { stopifnot(inherits(fitted, "data.frame")) stopifnot(nrow(data) == 0L | nrow(data) == nrow(fitted)) if (nrow(data) == 0L) stopifnot("(response)" %in% names(fitted)) } else { stopifnot(nrow(data) > 0L) stopifnot(!is.null(terms)) fitted <- data.frame("(response)" = model.response(model.frame(terms, data = data, na.action = na.pass)), check.names = FALSE) } ret <- list(nodes = nodes, data = data, weights = weights, fitted = fitted) class(ret) <- c("constparties", "parties") if(!is.null(terms)) { stopifnot(inherits(terms, "terms")) ret$terms <- terms } if (!is.null(info)) ret$info <- info ret } .perturb <- function(replace = FALSE, fraction = .632) { ret <- function(prob) { if (replace) { rw <- rmultinom(1, size = length(prob), prob = prob) } else { rw <- integer(length(prob)) i <- sample(1:length(prob), ceiling(fraction * length(prob)), prob = prob) rw[i] <- 1L } as.integer(rw) } ret } cforest <- function ( formula, data, weights, subset, offset, cluster, strata, na.action = na.pass, control = ctree_control( teststat = "quad", testtype = "Univ", mincriterion = 0, saveinfo = FALSE, ...), ytrafo = NULL, scores = NULL, ntree = 500L, perturb = list(replace = FALSE, fraction = 0.632), mtry = ceiling(sqrt(nvar)), applyfun = NULL, cores = NULL, trace = FALSE, ... ) { ### get the call and the calling environment for .urp_tree call <- match.call(expand.dots = TRUE) oweights <- NULL if (!missing(weights)) oweights <- weights m <- match(c("formula", "data", "subset", "na.action", "offset", "cluster", "scores", "ytrafo", "control", "converged"), names(call), 0L) ctreecall <- call[c(1L, m)] ctreecall$doFit <- FALSE if (!is.null(oweights)) ctreecall$weights <- 1:NROW(oweights) ctreecall$control <- control ### put ... into ctree_control() ctreecall[[1L]] <- quote(partykit::ctree) tree <- eval(ctreecall, parent.frame()) if (is.null(control$update)) control$update <- is.function(ytrafo) d <- tree$d updatefun <- tree$update nvar <- sum(d$variables$z > 0) control$mtry <- mtry control$applyfun <- lapply strata <- d[["(strata)"]] if (!is.null(strata)) { if (!is.factor(strata)) stop("strata is not a single factor") } probw <- NULL iweights <- model.weights(model.frame(d)) if (!is.null(oweights)) { if (is.matrix(oweights)) { weights <- oweights[iweights,,drop = FALSE] } else { weights <- oweights[iweights] } } else { weights <- NULL } rm(oweights) rm(iweights) N <- nrow(model.frame(d)) rw <- NULL if (!is.null(weights)) { if (is.matrix(weights)) { if (ncol(weights) == ntree && nrow(weights) == N) { rw <- unclass(as.data.frame(weights)) rw <- lapply(rw, function(w) rep(1:length(w), w)) weights <- integer(0) } else { stop(sQuote("weights"), "argument incorrect") } } else { probw <- weights / sum(weights) } } else { weights <- integer(0) } idx <- .start_subset(d) frctn <- pmin(1, sum(perturb$fraction)) if (is.null(rw)) { ### for honesty testing purposes only if (frctn == 1) { rw <- lapply(1:ntree, function(b) idx) } else { if (is.null(strata)) { size <- N if (!perturb$replace) size <- floor(size * frctn) rw <- replicate(ntree, sample(idx, size = size, replace = perturb$replace, prob = probw[idx]), simplify = FALSE) } else { frac <- if (!perturb$replace) frctn else 1 rw <- replicate(ntree, function() do.call("c", tapply(idx, strata[idx], function(i) sample(i, size = length(i) * frac, replace = perturb$replace, prob = probw[i])))) } } } ### honesty: fraction = c(p1, p2) with p1 + p2 <= 1 ### p1 is the fraction of samples used for tree induction ### p2 is the fraction used for honest predictions (nearest neighbor ### weights) ### works for subsampling only if (!perturb$replace && length(perturb$fraction) == 2L) { frctn <- perturb$fraction[2L] if (is.null(strata)) { size <- N if (!perturb$replace) size <- floor(size * frctn) hn <- lapply(1:ntree, function(b) sample(rw[[b]], size = size, replace = perturb$replace, prob = probw[rw[[b]]])) } else { frac <- if (!perturb$replace) frctn else 1 hn <- lapply(1:ntree, function(b) do.call("c", tapply(rw[[b]], strata[rw[[b]]], function(i) sample(i, size = length(i) * frac, replace = perturb$replace, prob = probw[i])))) } rw <- lapply(1:ntree, function(b) rw[[b]][!(rw[[b]] %in% hn[[b]])]) tmp <- hn hn <- rw rw <- tmp } else { hn <- NULL } ## apply infrastructure for determining split points ## use RNGkind("L'Ecuyer-CMRG") to make this reproducible if (is.null(applyfun)) { applyfun <- if(is.null(cores)) { lapply } else { function(X, FUN, ...) parallel::mclapply(X, FUN, ..., mc.set.seed = TRUE, mc.cores = cores) } } trafo <- updatefun(sort(rw[[1]]), integer(0), control, doFit = FALSE) if (trace) pb <- txtProgressBar(style = 3) forest <- applyfun(1:ntree, function(b) { if (trace) setTxtProgressBar(pb, b/ntree) ret <- updatefun(sort(rw[[b]]), integer(0), control) ### honesty: prune-off empty nodes if (!is.null(hn)) { nid <- nodeids(ret$nodes, terminal = TRUE) nd <- unique(fitted_node(ret$nodes, data = d$data, obs = hn[[b]])) prn <- nid[!nid %in% nd] if (length(prn) > 0) ret <- list(nodes = nodeprune(ret$nodes, ids = prn), trafo = ret$trafo) } # trafo <<- ret$trafo ret$nodes }) if (trace) close(pb) fitted <- data.frame(idx = 1:N) mf <- model.frame(d) fitted[[2]] <- mf[, d$variables$y, drop = TRUE] names(fitted)[2] <- "(response)" if (length(weights) > 0) fitted[["(weights)"]] <- weights ### turn subsets in weights (maybe we can avoid this?) rw <- lapply(rw, function(x) as.integer(tabulate(x, nbins = length(idx)))) control$applyfun <- applyfun ret <- constparties(nodes = forest, data = mf, weights = rw, fitted = fitted, terms = d$terms$all, info = list(call = match.call(), control = control)) if (!is.null(hn)) ret$honest_weights <- lapply(hn, function(x) as.integer(tabulate(x, nbins = length(idx)))) ret$trafo <- trafo ret$predictf <- d$terms$z class(ret) <- c("cforest", class(ret)) return(ret) } predict.cforest <- function(object, newdata = NULL, type = c("response", "prob", "weights", "node"), OOB = FALSE, FUN = NULL, simplify = TRUE, scale = TRUE, ...) { responses <- object$fitted[["(response)"]] forest <- object$nodes nd <- object$data vmatch <- 1:ncol(nd) NOnewdata <- TRUE if (!is.null(newdata)) { factors <- which(sapply(nd, is.factor)) xlev <- lapply(factors, function(x) levels(nd[[x]])) names(xlev) <- names(nd)[factors] xlev <- xlev[attr(object$predictf, "term.labels")] nd <- model.frame(object$predictf, ### all variables W/O response data = newdata, na.action = na.pass, xlev = xlev) OOB <- FALSE vmatch <- match(names(object$data), names(nd)) NOnewdata <- FALSE } nam <- rownames(nd) type <- match.arg(type) ### return terminal node ids for data or newdata if (type == "node") return(lapply(forest, fitted_node, data = nd, vmatch = vmatch, ...)) ### extract weights: use honest weights when available if (is.null(object$honest_weights)) { rw <- object$weights } else { rw <- object$honest_weights OOB <- FALSE } w <- 0L applyfun <- lapply if (!is.null(object$info)) applyfun <- object$info$control$applyfun fdata <- lapply(forest, fitted_node, data = object$data, ...) if (NOnewdata && OOB) { fnewdata <- list() } else { fnewdata <- lapply(forest, fitted_node, data = nd, vmatch = vmatch, ...) } w <- .rfweights(fdata, fnewdata, rw, scale) # for (b in 1:length(forest)) { # ids <- nodeids(forest[[b]], terminal = TRUE) # fnewdata <- fitted_node(forest[[b]], nd, vmatch = vmatch, ...) # fdata <- fitted_node(forest[[b]], object$data, ...) # tw <- rw[[b]] # pw <- sapply(ids, function(i) tw * (fdata == i)) # ret <- pw[, match(fnewdata, ids), drop = FALSE] # ### obs which are in-bag for this tree don't contribute # if (OOB) ret[,tw > 0] <- 0 # w <- w + ret # } # # #w <- Reduce("+", bw) # if (!is.matrix(w)) w <- matrix(w, ncol = 1) if (type == "weights") { ret <- w colnames(ret) <- nam rownames(ret) <- rownames(responses) return(ret) } pfun <- function(response) { if (is.null(FUN)) { rtype <- class(response)[1] if (rtype == "ordered") rtype <- "factor" if (rtype == "integer") rtype <- "numeric" FUN <- switch(rtype, "Surv" = if (type == "response") .pred_Surv_response else .pred_Surv, "factor" = if (type == "response") .pred_factor_response else .pred_factor, "numeric" = if (type == "response") .pred_numeric_response else .pred_ecdf) } ret <- vector(mode = "list", length = ncol(w)) for (j in 1:ncol(w)) ret[[j]] <- FUN(response, w[,j]) ret <- as.array(ret) dim(ret) <- NULL names(ret) <- nam if (simplify) ret <- .simplify_pred(ret, names(ret), names(ret)) ret } if (!is.data.frame(responses)) { ret <- pfun(responses) } else { ret <- lapply(responses, pfun) if (all(sapply(ret, is.atomic))) ret <- as.data.frame(ret) names(ret) <- colnames(responses) } ret } model.frame.cforest <- function(formula, ...) { class(formula) <- "party" model.frame(formula, ...) } partykit/R/split.R0000644000176200001440000001712014172230000013566 0ustar liggesusers partysplit <- function(varid, breaks = NULL, index = NULL, right = TRUE, prob = NULL, info = NULL) { ### informal class for splits split <- vector(mode = "list", length = 6) names(split) <- c("varid", "breaks", "index", "right", "prob", "info") ### split is an id referring to a variable if (!is.integer(varid)) stop(sQuote("varid"), " ", "is not integer") split$varid <- varid if (is.null(breaks) && is.null(index)) stop("either", " ", sQuote("breaks"), " ", "or", " ", sQuote("index"), " ", "must be given") ### vec if (!is.null(breaks)) { if (is.numeric(breaks) && (length(breaks) >= 1)) { ### FIXME: I think we need to make sure breaks are double in C split$breaks <- as.double(breaks) } else { stop(sQuote("break"), " ", "should be a numeric vector containing at least one element") } } if (!is.null(index)) { if (is.integer(index)) { if (!(length(index) >= 2)) stop(sQuote("index"), " ", "has less than two elements") if (!(min(index, na.rm = TRUE) == 1)) stop("minimum of", " ", sQuote("index"), " ", "is not equal to 1") if (!all.equal(diff(sort(unique(index))), rep(1, max(index, na.rm = TRUE) - 1))) stop(sQuote("index"), " ", "is not a contiguous sequence") split$index <- index } else { stop(sQuote("index"), " ", "is not a class", " ", sQuote("integer")) } if (!is.null(breaks)) { if (length(breaks) != (length(index) - 1)) stop("length of", " ", sQuote("breaks"), " ", "does not match length of", " ", sQuote("index")) } } if (is.logical(right) & !is.na(right)) split$right <- right else stop(sQuote("right"), " ", "is not a logical") if (!is.null(prob)) { if (!is.double(prob) || (any(prob < 0) | any(prob > 1) | !isTRUE(all.equal(sum(prob), 1)))) stop(sQuote("prob"), " ", "is not a vector of probabilities") if (!is.null(index)) { if (!(max(index, na.rm = TRUE) == length(prob))) stop("incorrect", " ", sQuote("index")) } if (!is.null(breaks) && is.null(index)) { if (!(length(breaks) == (length(prob) - 1))) stop("incorrect", " ", sQuote("breaks")) } split$prob <- prob } if (!is.null(info)) split$info <- info class(split) <- "partysplit" return(split) } varid_split <- function(split) { if (!(inherits(split, "partysplit"))) stop(sQuote("split"), " ", "is not an object of class", " ", sQuote("partysplit")) split$varid } breaks_split <- function(split) { if (!(inherits(split, "partysplit"))) stop(sQuote("split"), " ", "is not an object of class", " ", sQuote("partysplit")) split$breaks } index_split <- function(split) { if (!(inherits(split, "partysplit"))) stop(sQuote("split"), " ", "is not an object of class", " ", sQuote("partysplit")) split$index } right_split <- function(split) { if (!(inherits(split, "partysplit"))) stop(sQuote("split"), " ", "is not an object of class", " ", sQuote("partysplit")) split$right } prob_split <- function(split) { if (!(inherits(split, "partysplit"))) stop(sQuote("split"), " ", "is not an object of class", " ", sQuote("partysplit")) prob <- split$prob if (!is.null(prob)) return(prob) ### either breaks or index must be there if (is.null(index <- index_split(split))) { if (is.null(breaks <- breaks_split(split))) stop("neither", " ", sQuote("prob"), " ", "nor", " ", sQuote("index"), " ", "or", sQuote("breaks"), " ", "given for", " ", sQuote("split")) nkids <- length(breaks) + 1 } else { nkids <- max(index, na.rm = TRUE) } prob <- rep(1, nkids) / nkids return(prob) } info_split <- function(split) { if (!(inherits(split, "partysplit"))) stop(sQuote("split"), " ", "is not an object of class", " ", sQuote("partysplit")) split$info } kidids_split <- function(split, data, vmatch = 1:length(data), obs = NULL) { id <- varid_split(split) class(data) <- "list" ### speed up x <- data[[vmatch[id]]] if (!is.null(obs)) x <- x[obs] if (is.null(breaks_split(split))) { if (storage.mode(x) != "integer") stop("variable", " ", vmatch[id], " ", "is not integer") } else { ### labels = FALSE returns integers and is faster ### use findInterval instead of cut? # x <- cut.default(as.numeric(x), labels = FALSE, # breaks = unique(c(-Inf, breaks_split(split), Inf)), ### breaks_split(split) = Inf possible (MIA) # right = right_split(split)) x <- .bincode(as.numeric(x), # labels = FALSE, breaks = unique(c(-Inf, breaks_split(split), Inf)), ### breaks_split(split) = Inf possible (MIA) right = right_split(split)) ### } index <- index_split(split) ### empty factor levels correspond to NA and return NA here ### and thus the corresponding observations will be treated ### as missing values (surrogate or random splits): if (!is.null(index)) x <- index[x] return(x) } character_split <- function(split, data = NULL, digits = getOption("digits") - 2) { varid <- varid_split(split) if (!is.null(data)) { ## names and labels lev <- lapply(data, levels)[[varid]] mlab <- names(data)[varid] ## determine split type type <- sapply(data, function(x) class(x)[1])[varid_split(split)] type[!(type %in% c("factor", "ordered"))] <- "numeric" } else { ## (bad) default names and labels lev <- NULL mlab <- paste("V", varid, sep = "") type <- "numeric" } ## process defaults for breaks and index breaks <- breaks_split(split) index <- index_split(split) right <- right_split(split) if (is.null(breaks)) breaks <- 1:(length(index) - 1) if (is.null(index)) index <- 1:(length(breaks) + 1) ## check whether ordered are really ordered if (type == "ordered") { if (length(breaks) > 1) type <- "factor" } ### format ordered multiway splits? switch(type, "factor" = { nindex <- index[cut(seq_along(lev), c(-Inf, breaks, Inf), right = right)] dlab <- as.vector(tapply(lev, nindex, paste, collapse = ", ")) }, "ordered" = { if (length(breaks) == 1) { if (right) dlab <- paste(c("<=", ">"), lev[breaks], sep = " ") else dlab <- paste(c("<", ">="), lev[breaks], sep = " ") } else { stop("") ### see above } dlab <- dlab[index] }, "numeric" = { breaks <- round(breaks, digits) if (length(breaks) == 1) { if (right) dlab <- paste(c("<=", ">"), breaks, sep = " ") else dlab <- paste(c("<", ">="), breaks, sep = " ") } else { dlab <- levels(cut(0, breaks = c(-Inf, breaks, Inf), right = right)) } dlab <- as.vector(tapply(dlab, index, paste, collapse = " | ")) } ) return(list(name = mlab, levels = dlab)) } partykit/R/simpleparty.R0000644000176200001440000001524114172230000015006 0ustar liggesusers.make_formatinfo_simpleparty <- function(x, digits = getOption("digits") - 4, sep = "") { ## digit processing digits <- max(c(0, digits)) digits2 <- max(c(0, digits - 2)) ## type of predictions y <- node_party(x)$info$prediction yclass <- .response_class(y) if(yclass == "ordered") yclass <- "factor" if(!(yclass %in% c("survfit", "factor"))) yclass <- "numeric" ## type of weights n <- node_party(x)$info$n if(is.null(names(n))) { wdigits <- 0 wsym <- "n" } else { if(names(n) == "w") { wdigits <- max(c(0, digits - 2)) wsym <- "w" } else { wdigits <- 0 wsym <- "n" } } ## compute terminal node labels FUN <- function(info) { yhat <- info$prediction if (yclass == "survfit") { yhat <- .median_survival_time(yhat) yclass <- "numeric" } if(yclass == "numeric") yhat <- format(round(yhat, digits = digits), nsmall = digits) w <- info$n yerr <- if(is.null(info$error)) "" else paste(", err = ", format(round(info$error, digits = digits2), nsmall = digits2), names(info$error), sep = "") rval <- paste(yhat, sep, " (", wsym, " = ", format(round(w, digits = wdigits), nsmall = wdigits), yerr, ")", sep = "") unlist(strsplit(rval, "\n")) } return(FUN) } plot.simpleparty <- function(x, digits = getOption("digits") - 4, tp_args = NULL, ...) { if(is.null(tp_args)) tp_args <- list(FUN = .make_formatinfo_simpleparty(x, digits = digits, sep = "\n")) plot.party(x, tp_args = tp_args, ...) } print.simpleparty <- function(x, digits = getOption("digits") - 4, header = NULL, footer = TRUE, ...) { ## header panel if(is.null(header)) header <- !is.null(terms(x)) header_panel <- if(header) function(party) { c("", "Model formula:", deparse(formula(terms(party))), "", "Fitted party:", "") } else function(party) "" ## footer panel footer_panel <- if(footer) function(party) { n <- width(party) n <- format(c(length(party) - n, n)) c("", paste("Number of inner nodes: ", n[1]), paste("Number of terminal nodes:", n[2]), "") } else function (party) "" ## terminal panel terminal_panel <- function(node) formatinfo_node(node, FUN = .make_formatinfo_simpleparty(x, digits = digits), default = "*", prefix = ": ") print.party(x, terminal_panel = terminal_panel, header_panel = header_panel, footer_panel = footer_panel, ...) } predict_party.simpleparty <- function(party, id, newdata = NULL, type = c("response", "prob", "node"), ...) { ## get observation names: either node names or ## observation names from newdata nam <- if(is.null(newdata)) names(party)[id] else rownames(newdata) if(length(nam) != length(id)) nam <- NULL ## match type type <- match.arg(type) ## special case: fitted ids if(type == "node") return(structure(id, .Names = nam)) ## predictions if(type == "response") { FUN <- function(x) x$info$prediction } else { if(is.null(node_party(party)$info$distribution)) stop("probabilities not available") scale <- any(node_party(party)$info$distribution > 1) FUN <- function(x) if(scale) prop.table(x$info$distribution) else x$info$distribution } predict_party.default(party, id, nam, FUN = FUN, ...) } as.simpleparty <- function(obj, ...) UseMethod("as.simpleparty") as.simpleparty.simpleparty <- function(obj, ...) obj as.simpleparty.party <- function(obj, ...) { if (is.simpleparty(obj)) { class(obj) <- unique(c("simpleparty", class(obj))) return(obj) } if (is.constparty(obj)) return(as.simpleparty(as.constparty(obj))) stop("cannot coerce objects of class ", sQuote(class(obj)), " to class ", sQuote("simpleparty")) } as.simpleparty.XMLNode <- function(obj, ...) as.party(obj) as.simpleparty.constparty <- function(obj, ...) { ## extract and delete fitted fit <- obj$fitted obj$fitted <- NULL ## response info rtype <- .response_class(fit[["(response)"]]) if (rtype == "ordered") rtype <- "factor" if (rtype == "integer") rtype <- "numeric" ## extract fitted info FUN <- function(node, fitted) { fitted <- subset(fitted, fitted[["(fitted)"]] %in% nodeids(node, terminal = TRUE)) if (nrow(fitted) == 0) return(list(prediction = NA, n = 0, error = NA, distribution = NULL)) y <- fitted[["(response)"]] w <- fitted[["(weights)"]] if(is.null(w)) { w <- rep(1, nrow(fitted)) wnam <- "n" } else { wnam <- if(isTRUE(all.equal(w, round(w)))) "n" else "w" } ## extract p.value (if any) pval <- function(node) { p <- info_node(node) if(is.list(p)) p$p.value else NULL } switch(rtype, "numeric" = { yhat <- .pred_numeric_response(y, w) list(prediction = yhat, n = structure(sum(w), .Names = wnam), error = sum(w * (y - yhat)^2), distribution = NULL, p.value = pval(node)) }, "factor" = { yhat <- .pred_factor_response(y, w) ytab <- round(.pred_factor(y, w) * sum(w)) list(prediction = yhat, n = structure(sum(w), .Names = wnam), error = structure(sum(100 * prop.table(ytab)[names(ytab) != yhat]), .Names = "%"), distribution = ytab, p.value = pval(node)) }, "Surv" = { list(prediction = .pred_Surv(y, w), n = structure(sum(w), .Names = wnam), error = NULL, distribution = NULL, p.value = pval(node)) ## FIXME: change distribution format? }) } ## convenience function for computing kid ids fit2id <- function(fit, idlist) { fit <- factor(fit) nlevels <- levels(fit) for(i in 1:length(idlist)) nlevels[match(idlist[[i]], levels(fit))] <- i levels(fit) <- nlevels ret <- factor(as.numeric(as.character(fit)), labels = 1:length(idlist), levels = 1:length(idlist)) ret } ## cycle through node new_node <- function(onode, fitted) { if(is.terminal(onode)) return(partynode(id = onode$id, split = NULL, kids = NULL, surrogates = NULL, info = FUN(onode, fitted))) kids <- kids_node(onode) kids_tid <- lapply(kids, nodeids, terminal = TRUE) kids_fitted <- base::split.data.frame(fitted, fit2id(fitted[["(fitted)"]], kids_tid), drop = FALSE) partynode(id = onode$id, split = onode$split, kids = lapply(1:length(kids), function(i) new_node(kids[[i]], kids_fitted[[i]])), surrogates = onode$surrogates, info = FUN(onode, fitted)) } obj$node <- new_node(node_party(obj), fit) class(obj) <- c("simpleparty", "party") return(obj) } is.simpleparty <- function(party) { chkinfo <- function(node) all(c("prediction", "n", "error", "distribution") %in% names(info_node(node))) all(nodeapply(party, ids = nodeids(party), FUN = chkinfo, by_node = TRUE)) } partykit/R/node.R0000644000176200001440000002147314172230000013366 0ustar liggesusers partynode <- function(id, split = NULL, kids = NULL, surrogates = NULL, info = NULL) { if (!is.integer(id) || length(id) != 1) { id <- as.integer(id0 <- id) if (any(is.na(id)) || !isTRUE(all.equal(id0, id)) || length(id) != 1) stop(sQuote("id"), " ", "must be a single integer") } if (is.null(split) != is.null(kids)) { stop(sQuote("split"), " ", "and", " ", sQuote("kids"), " ", "must either both be specified or unspecified") } if (!is.null(kids)) { if (!(is.list(kids) && all(sapply(kids, inherits, "partynode"))) || length(kids) < 2) stop(sQuote("kids"), " ", "must be an integer vector or a list of", " ", sQuote("partynode"), " ", "objects") } if (!is.null(surrogates)) { if (!is.list(surrogates) || any(!sapply(surrogates, inherits, "partysplit"))) stop(sQuote("split"), " ", "is not a list of", " ", sQuote("partysplit"), " ", "objects") } node <- list(id = id, split = split, kids = kids, surrogates = surrogates, info = info) class(node) <- "partynode" return(node) } is.partynode <- function(x) { if (!inherits(x, "partynode")) return(FALSE) rval <- diff(nodeids(x, terminal = FALSE)) isTRUE(all.equal(unique(rval), 1)) } as.partynode <- function(x, ...) UseMethod("as.partynode") as.partynode.partynode <- function(x, from = NULL, recursive = TRUE, ...) { if(is.null(from)) from <- id_node(x) from <- as.integer(from) if (!recursive) { if(is.partynode(x) & id_node(x) == from) return(x) } id <- from - 1L new_node <- function(x) { id <<- id + 1L if(is.terminal(x)) return(partynode(id, info = info_node(x))) partynode(id, split = split_node(x), kids = lapply(kids_node(x), new_node), surrogates = surrogates_node(x), info = info_node(x)) } return(new_node(x)) } as.partynode.list <- function(x, ...) { if (!all(sapply(x, inherits, what = "list"))) stop("'x' has to be a list of lists") if (!all(sapply(x, function(x) "id" %in% names(x)))) stop("each list in 'x' has to define a node 'id'") ok <- sapply(x, function(x) all(names(x) %in% c("id", "split", "kids", "surrogates", "info"))) if (any(!ok)) sapply(which(!ok), function(i) warning(paste("list element", i, "defines additional elements:", paste(names(x[[i]])[!(names(x[[i]]) %in% c("id", "split", "kids", "surrogates", "info"))], collapse = ", ")))) ids <- as.integer(sapply(x, function(node) node$id)) if(any(duplicated(ids))) stop("nodeids must be unique integers") x <- x[order(ids)] ids <- ids[order(ids)] new_recnode <- function(i) { x_i <- x[[which(ids == i)]] if (is.null(x_i$kids)) partynode(id = x_i$id, info = x_i$info) else partynode(id = x_i$id, split = x_i$split, kids = lapply(x_i$kids, new_recnode), surrogates = x_i$surrogates, info = x_i$info) } ret <- new_recnode(ids[1L]) ### duplicates recursion but makes sure ### that the ids are in pre-order notation with ### from defined in as.partynode.partynode ### as.partynode(ret, ...) } as.list.partynode <- function(x, ...) { ids <- nodeids(x) obj <- vector(mode = "list", length = length(ids)) thisnode <- NULL nodelist <- function(node) { if (is.terminal(node)) obj[[which(ids == id_node(node))]] <<- list(id = id_node(node), info = info_node(node)) else { thisnode <<- list(id = id_node(node), split = split_node(node), kids = sapply(kids_node(node), function(k) id_node(k))) if (!is.null(surrogates_node(node))) thisnode$surrogates <- surrogates_node(node) if (!is.null(info_node(node))) thisnode$info <- info_node(node) obj[[which(ids == id_node(node))]] <<- thisnode lapply(kids_node(node), nodelist) } } nodelist(x) return(obj) } id_node <- function(node) { if (!(inherits(node, "partynode"))) stop(sQuote("node"), " ", "is not an object of class", " ", sQuote("node")) node$id } kids_node <- function(node) { if (!(inherits(node, "partynode"))) stop(sQuote("node"), " ", "is not an object of class", " ", sQuote("node")) node$kids } info_node <- function(node) { if (!(inherits(node, "partynode"))) stop(sQuote("node"), " ", "is not an object of class", " ", sQuote("node")) node$info } formatinfo_node <- function(node, FUN = NULL, default = "", prefix = NULL, ...) { info <- info_node(node) ## FIXME: better dispatch to workhorse FUN probably needed in the future, e.g.: ## (1) formatinfo() generic with formatinfo.default() as below, ## (2) supply default FUN from party$info$formatinfo() or similar. if(is.null(FUN)) FUN <- function(x, ...) { if(is.null(x)) x <- "" if(!is.object(x) & is.atomic(x)) x <- as.character(x) if(!is.character(x)) x <- capture.output(print(x), ...) x } info <- if(is.null(info)) default else FUN(info, ...) if(!is.null(prefix)) { info <- if(length(info) > 1L) c(prefix, info) else paste(prefix, info, sep = "") } info } ### FIXME: permutation and surrogate splits: is only the primary ### variable permuted? kidids_node <- function(node, data, vmatch = 1:ncol(data), obs = NULL, perm = NULL) { primary <- split_node(node) surrogates <- surrogates_node(node) ### perform primary split x <- kidids_split(primary, data, vmatch, obs) ### surrogate / random splits if needed if (any(is.na(x))) { ### surrogate splits if (length(surrogates) >= 1) { for (surr in surrogates) { nax <- is.na(x) if (!any(nax)) break; x[nax] <- kidids_split(surr, data, vmatch, obs = obs)[nax] } } nax <- is.na(x) ### random splits if (any(nax)) { prob <- prob_split(primary) x[nax] <- sample(1:length(prob), sum(nax), prob = prob, replace = TRUE) } } ### permute variable `perm' _after_ dealing with surrogates etc. if (!is.null(perm)) { if (is.integer(perm)) { if (varid_split(primary) %in% perm) x <- .resample(x) } else { if (is.null(obs)) obs <- 1:nrow(data) strata <- perm[[varid_split(primary)]] if (!is.null(strata)) { strata <- strata[obs, drop = TRUE] for (s in levels(strata)) x[strata == s] <- .resample(x[strata == s]) } } } return(x) } fitted_node <- function(node, data, vmatch = 1:ncol(data), obs = 1:nrow(data), perm = NULL) { ### should be equivalent to: # return(.Call("R_fitted_node", node, data, vmatch, as.integer(obs), # as.integer(perm))) if (is.logical(obs)) obs <- which(obs) if (is.terminal(node)) return(rep(id_node(node), length(obs))) retid <- nextid <- kidids_node(node, data, vmatch, obs, perm) for (i in unique(nextid)) { indx <- nextid == i retid[indx] <- fitted_node(kids_node(node)[[i]], data, vmatch, obs[indx], perm) } return(retid) } length.partynode <- function(x) length(kids_node(x)) "[.partynode" <- "[[.partynode" <- function(x, i, ...) { if (!(length(i) == 1 && is.numeric(i))) stop(sQuote("x"), " ", "is incorrect node") kids_node(x)[[i]] } split_node <- function(node) { if (!(inherits(node, "partynode"))) stop(sQuote("node"), " ", "is not an object of class", " ", sQuote("node")) node$split } surrogates_node <- function(node) { if (!(inherits(node, "partynode"))) stop(sQuote("node"), " ", "is not an object of class", " ", sQuote("node")) node$surrogates } is.terminal <- function(x, ...) UseMethod("is.terminal") is.terminal.partynode <- function(x, ...) { kids <- is.null(kids_node(x)) split <- is.null(split_node(x)) if (kids != split) stop("x", " ", "is incorrect node") kids } ## ## depth generic now taken from package 'grid' ## depth <- function(x, ...) ## UseMethod("depth") depth.partynode <- function(x, root = FALSE, ...) { if (is.terminal(x)) return(as.integer(root)) max(sapply(kids_node(x), depth, root = root)) + 1L } width <- function(x, ...) UseMethod("width") width.partynode <- function(x, ...) { if (is.terminal(x)) return(1) sum(sapply(kids_node(x), width.partynode)) } partykit/R/varimp.R0000644000176200001440000002130714172230000013733 0ustar liggesusers logLik.constparty <- function(object, newdata, weights, perm = NULL, ...) { y <- object$fitted[["(response)"]] if (missing(newdata)) { fitted <- if (is.null(perm)) { object$fitted[["(fitted)"]] } else { ### no need to watch vmatch because newdata is always mf if (!is.null(perm)) { vnames <- names(object$data) if (is.character(perm)) { stopifnot(all(perm %in% vnames)) perm <- match(perm, vnames) } else { ### perm is a named list of factors coding strata ### (for varimp(..., conditional = TRUE) stopifnot(all(names(perm) %in% vnames)) stopifnot(all(sapply(perm, is.factor))) tmp <- vector(mode = "list", length = length(vnames)) tmp[match(names(perm), vnames)] <- perm perm <- tmp } } fitted_node(node_party(object), data = object$data, perm = perm) } pr <- predict_party(object, id = fitted, newdata = object$data, type = ifelse(inherits(y, "factor"), "prob", "response"), ...) } else { pr <- predict(object, newdata = newdata, type = ifelse(inherits(y, "factor"), "prob", "response"), ...) } ll <- switch(.response_class(y), "integer" = { -(y - pr)^2 }, "numeric" = { -(y - pr)^2 }, "factor" = { log(pmax(pr[cbind(1:length(y), unclass(y))], sqrt(.Machine$double.eps))) }, "ordered" = { log(pmax(pr[cbind(1:length(y), unclass(y))], sqrt(.Machine$double.eps))) }, "Surv" = stop("not yet implemented"), stop("not yet implemented") ) if (missing(weights)) weights <- data_party(object)[["(weights)"]] if (is.null(weights)) return(sum(ll) / length(y)) return(sum(weights * ll) / sum(weights)) } miscls <- function(object, newdata, weights, perm = NULL, ...) { y <- object$fitted[["(response)"]] stopifnot(is.factor(y)) if (missing(newdata)) { fitted <- if (is.null(perm)) { object$fitted[["(fitted)"]] } else { ### no need to watch vmatch because newdata is always mf if (!is.null(perm)) { vnames <- names(object$data) if (is.character(perm)) { stopifnot(all(perm %in% vnames)) perm <- match(perm, vnames) } else { ### perm is a named list of factors coding strata ### (for varimp(..., conditional = TRUE) stopifnot(all(names(perm) %in% vnames)) stopifnot(all(sapply(perm, is.factor))) tmp <- vector(mode = "list", length = length(vnames)) tmp[match(names(perm), vnames)] <- perm perm <- tmp } } fitted_node(node_party(object), data = object$data, perm = perm) } pr <- predict_party(object, id = fitted, newdata = object$data, type = "response", ...) } else { pr <- predict(object, newdata = newdata, type = "response", ...) } ll <- unclass(y) != unclass(pr) if (missing(weights)) weights <- data_party(object)[["(weights)"]] if (is.null(weights)) return(sum(ll) / length(y)) return(sum(weights * ll) / sum(weights)) } varimp <- function(object, nperm = 1L, ...) UseMethod("varimp") varimp.constparty <- function(object, nperm = 1L, risk = c("loglik", "misclassification"), conditions = NULL, mincriterion = 0, ...) { if (!is.function(risk)) { risk <- match.arg(risk) ### risk is _NEGATIVE_ log-likelihood risk <- switch(risk, "loglik" = function(...) -logLik(...), "misclassification" = miscls) } if (mincriterion > 0) stop("mincriterion not yet implemented") ### use nodeprune psplitids <- unique(do.call("c", nodeapply(node_party(object), ids = nodeids(node_party(object)), FUN = function(x) split_node(x)$varid))) vnames <- names(object$data) psplitvars <- vnames[psplitids] ret <- numeric(length(psplitvars)) names(ret) <- psplitvars for (vn in psplitvars) { cvn <- conditions[[vn]] if (is.null(cvn)) { perm <- vn } else { blocks <- .get_psplits(object, cvn) if (length(blocks) == 0) blocks <- factor(rep(1, nrow(object$data))) perm <- vector(mode = "list", length = 1) names(perm) <- vn perm[[vn]] <- blocks } for (p in 1:nperm) ret[vn] <- ret[vn] + risk(object, perm = perm, ...) } ret <- ret / nperm - risk(object, ...) ret } gettree <- function(object, tree = 1L, ...) UseMethod("gettree") gettree.cforest <- function(object, tree = 1L, ...) { ft <- object$fitted ft[["(weights)"]] <- object$weights[[tree]] ret <- party(object$nodes[[tree]], data = object$data, fitted = ft) ret$terms <- object$terms class(ret) <- c("constparty", class(ret)) ret } .create_cond_list <- function(object, threshold) { d <- object$data response <- names(d)[attr(object$terms, "response")] xnames <- all.vars(object$terms) xnames <- xnames[xnames != response] ret <- lapply(xnames, function(x) { tmp <- ctree(as.formula(paste(x, "~", paste(xnames[xnames != x], collapse = "+"))), data = d, control = ctree_control(teststat = "quad", testtype = "Univariate", stump = TRUE)) pval <- info_node(node_party(tmp))$criterion["p.value",] pval[is.na(pval)] <- 1 ### make the meaning of threshold equal to partykit ret <- names(pval)[(1 - pval) > threshold] if (length(ret) == 0) return(NULL) return(ret) }) names(ret) <- xnames return(ret) } .get_psplits <- function(object, xnames) { d <- object$data ret <- lapply(xnames, function(xn) { id <- which(colnames(d) == xn) psplits <- nodeapply(node_party(object), ids = nodeids(node_party(object)), FUN = function(x) { if (is.null(x)) return(NULL) if (is.terminal(x)) return(NULL) if (split_node(x)$varid == id) return(split_node(x)) return(NULL) }) psplits <- psplits[!sapply(psplits, is.null)] if (length(psplits) > 0) return(do.call("interaction", lapply(lapply(psplits, kidids_split, data = d), factor, exclude = NULL))[, drop = TRUE]) return(NULL) }) ret <- ret[!sapply(ret, is.null)] if (length(ret) > 0) { if (length(ret) == 1) return(factor(ret[[1]], exclude = NULL)) ### get rid of empty levels quickly; do.call("interaction", ret) ### explodes for (i in 2:length(ret)) ret[[1]] <- factor(interaction(ret[[1]], ret[[i]])[, drop = TRUE], exclude = NULL) return(ret[[1]]) } return(NULL) } varimp.cforest <- function(object, nperm = 1L, OOB = TRUE, risk = c("loglik", "misclassification"), conditional = FALSE, threshold = .2, applyfun = NULL, cores = NULL, ...) { ret <- matrix(NA, nrow = length(object$nodes), ncol = ncol(object$data)) colnames(ret) <- names(object$data) if (conditional) { conditions <- .create_cond_list(object, threshold) } else { conditions <- NULL } ## apply infrastructure if (is.null(applyfun)) { applyfun <- if(is.null(cores)) { lapply } else { function(X, FUN, ...) parallel::mclapply(X, FUN, ..., mc.set.seed = TRUE, mc.cores = cores) } } vi <- applyfun(1:length(object$nodes), function(b) { tree <- gettree(object, b) if (OOB) { oobw <- as.integer(object$weights[[b]] == 0) vi <- varimp(tree, nperm = nperm, risk = risk, conditions = conditions, weights = oobw, ...) } else { vi <- varimp(tree, nperm = nperm, risk = risk, conditions = conditions, ...) } return(vi) }) for (b in 1:length(object$nodes)) ret[b, match(names(vi[[b]]), colnames(ret))] <- vi[[b]] ret <- colMeans(ret, na.rm = TRUE) ret[!sapply(ret, is.na)] } partykit/R/mob-plot.R0000644000176200001440000002155114172230000014167 0ustar liggesusersnode_bivplot <- function(mobobj, which = NULL, id = TRUE, pop = TRUE, pointcol = "black", pointcex = 0.5, boxcol = "black", boxwidth = 0.5, boxfill = "lightgray", bg = "white", fitmean = TRUE, linecol = "red", cdplot = FALSE, fivenum = TRUE, breaks = NULL, ylines = NULL, xlab = FALSE, ylab = FALSE, margins = rep(1.5, 4), mainlab = NULL, ...) { ## obtain dependent variable mf <- model.frame(mobobj) y <- Formula::model.part(mobobj$info$Formula, mf, lhs = 1L, rhs = 0L) if(isTRUE(ylab)) ylab <- names(y) if(identical(ylab, FALSE)) ylab <- "" if(is.null(ylines)) ylines <- ifelse(identical(ylab, ""), 0, 2) y <- y[[1L]] ## obtain explanatory variables X <- Formula::model.part(mobobj$info$Formula, mf, lhs = 0L, rhs = 1L) ## fitted node ids fitted <- mobobj$fitted[["(fitted)"]] ## if no explanatory variables: behave like plot.constparty if(inherits(X, "try-error")) { rval <- switch(.response_class(y), "Surv" = node_surv(mobobj, id = id, mainlab = mainlab, ...), "factor" = node_barplot(mobobj, id = id, mainlab = mainlab, ...), "ordered" = node_barplot(mobobj, id = id, mainlab = mainlab, ...), node_boxplot(mobobj, ...)) return(rval) } ## reverse levels for spine/CD plot if(is.factor(y)) y <- factor(y, levels = rev(levels(y))) ## number of panels needed if(is.null(which)) which <- 1L:NCOL(X) X <- X[,which,drop=FALSE] k <- NCOL(X) xlab <- if(!identical(xlab, FALSE)) { if(isTRUE(xlab)) colnames(X) else rep(xlab, length.out = k) } else rep("", k) ## set up appropriate panel functions if(is.factor(y)) { ## CD plots and spine plots ## re-use implementation from vcd package if(!requireNamespace("vcd")) stop(sprintf("Package %s is required for spine/CD plots", sQuote("vcd"))) if(cdplot) { num_fun <- function(x, y, yfit, i, name, ...) { vcd::cd_plot(x, y, xlab = xlab[i], ylab = ylab, name = name, newpage = FALSE, margins = margins, pop = FALSE, ...) if(fitmean) { #FIXME# downViewport(name = name) grid.lines(x, yfit, default.units = "native", gp = gpar(col = linecol)) if(pop) popViewport() else upViewport() } else { #FIXME# if(pop) popViewport() else upViewport() } } } else { xscale <- if(is.null(breaks)) { if(fivenum) lapply(X, function(z) {if(is.factor(z)) 1 else fivenum(z) }) else lapply(X, function(z) {if(is.factor(z)) 1 else hist(z, plot = FALSE)$breaks }) } else { if(is.list(breaks)) breaks else list(breaks) } num_fun <- function(x, y, yfit, i, name, ...) { vcd::spine(x, y, xlab = xlab[i], ylab = ylab, name = name, newpage = FALSE, margins = margins, pop = FALSE, breaks = xscale[[i]], ...) if(fitmean) { #FIXME# downViewport(name = name) xaux <- cut(x, breaks = xscale[[i]], include.lowest = TRUE) yfit <- unlist(tapply(yfit, xaux, mean)) xaux <- prop.table(table(xaux)) xaux <- cumsum(xaux) - xaux/2 grid.lines(xaux, yfit, default.units = "native", gp = gpar(col = linecol)) grid.points(xaux, yfit, default.units = "native", gp = gpar(col = linecol, cex = pointcex), pch = 19) if(pop) popViewport() else upViewport() } else { #FIXME# if(pop) popViewport() else upViewport() } } } cat_fun <- function(x, y, yfit, i, name, ...) { vcd::spine(x, y, xlab = xlab[i], ylab = ylab, name = name, newpage = FALSE, margins = margins, pop = FALSE, ...) if(fitmean) { #FIXME# downViewport(name = name) yfit <- unlist(tapply(yfit, x, mean)) xaux <- prop.table(table(x)) xaux <- cumsum(xaux + 0.02) - xaux/2 - 0.02 grid.lines(xaux, yfit, default.units = "native", gp = gpar(col = linecol)) grid.points(xaux, yfit, default.units = "native", gp = gpar(col = linecol, cex = pointcex), pch = 19) if(pop) popViewport() else upViewport() } else { #FIXME# if(pop) popViewport() else upViewport() } } } else { xscale <- sapply(X, function(z) {if(is.factor(z)) c(1, length(levels(z))) else range(z) }) yscale <- range(y) + c(-0.1, 0.1) * diff(range(y)) ## scatter plots and box plots num_fun <- function(x, y, yfit, i, name, ...) { xscale[,i] <- xscale[,i] + c(-0.1, 0.1) * diff(xscale[,i]) pushViewport(plotViewport(margins = margins, name = name, yscale = yscale, xscale = xscale[,i])) grid.points(x, y, gp = gpar(col = pointcol, cex = pointcex)) if(fitmean) { grid.lines(x, yfit, default.units = "native", gp = gpar(col = linecol)) } grid.xaxis(at = c(ceiling(xscale[1L,i]*10), floor(xscale[2L,i]*10))/10) grid.yaxis(at = c(ceiling(yscale[1L]), floor(yscale[2L]))) grid.rect(gp = gpar(fill = "transparent")) if(ylab != "") grid.text(ylab, y = unit(0.5, "npc"), x = unit(-2.5, "lines"), rot = 90) if(xlab[i] != "") grid.text(xlab[i], x = unit(0.5, "npc"), y = unit(-2, "lines")) if(pop) popViewport() else upViewport() } cat_fun <- function(x, y, yfit, i, name, ...) { xlev <- levels(x) pushViewport(plotViewport(margins = margins, name = name, yscale = yscale, xscale = c(0.3, xscale[2L,i]+0.7))) for(j in seq_along(xlev)) { by <- boxplot(y[x == xlev[j]], plot = FALSE) xl <- j - boxwidth/4 xr <- j + boxwidth/4 ## box & whiskers grid.lines(unit(c(xl, xr), "native"), unit(by$stats[1L], "native"), gp = gpar(col = boxcol)) grid.lines(unit(j, "native"), unit(by$stats[1L:2L], "native"), gp = gpar(col = boxcol, lty = 2)) grid.rect(unit(j, "native"), unit(by$stats[2L], "native"), width = unit(boxwidth, "native"), height = unit(diff(by$stats[2:3]), "native"), just = c("center", "bottom"), gp = gpar(col = boxcol, fill = boxfill)) grid.rect(unit(j, "native"), unit(by$stats[3L], "native"), width = unit(boxwidth, "native"), height = unit(diff(by$stats[3L:4L]), "native"), just = c("center", "bottom"), gp = gpar(col = boxcol, fill = boxfill)) grid.lines(unit(j, "native"), unit(by$stats[4L:5L], "native"), gp = gpar(col = boxcol, lty = 2)) grid.lines(unit(c(xl, xr), "native"), unit(by$stats[5L], "native"), gp = gpar(col = boxcol)) ## outlier n <- length(by$out) if (n > 0L) { grid.points(unit(rep.int(j, n), "native"), unit(by$out, "native"), size = unit(0.5, "char"), gp = gpar(col = boxcol)) } } if(fitmean) { yfit <- unlist(tapply(yfit, x, mean)) grid.lines(seq_along(xlev), yfit, default.units = "native", gp = gpar(col = linecol)) grid.points(seq_along(xlev), yfit, default.units = "native", gp = gpar(col = linecol, cex = pointcex), pch = 19) } grid.rect(gp = gpar(fill = "transparent")) grid.xaxis(at = 1L:length(xlev), label = xlev) grid.yaxis(at = c(ceiling(yscale[1L]), floor(yscale[2L]))) if(ylab != "") grid.text(ylab, y = unit(0.5, "npc"), x = unit(-3, "lines"), rot = 90) if(xlab[i] != "") grid.text(xlab[i], x = unit(0.5, "npc"), y = unit(-2, "lines")) if(pop) popViewport() else upViewport() } } rval <- function(node) { ## node index nid <- id_node(node) ix <- fitted %in% nodeids(mobobj, from = nid, terminal = TRUE) ## dependent variable y <- y[ix] ## set up top viewport top_vp <- viewport(layout = grid.layout(nrow = k, ncol = 2, widths = unit(c(ylines, 1), c("lines", "null")), heights = unit(k, "null")), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_mob", nid, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = bg, col = 0)) ## main title top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) if (is.null(mainlab)) { mainlab <- if(id) { function(id, nobs) sprintf("Node %s (n = %s)", id, nobs) } else { function(id, nobs) sprintf("n = %s", nobs) } } if (is.function(mainlab)) { mainlab <- mainlab(nid, info_node(node)$nobs) } grid.text(mainlab, y = unit(1, "npc") - unit(0.75, "lines")) popViewport() for(i in 1L:k) { ## get x and y xi <- X[ix, i] o <- order(xi) yi <- y[o] xi <- xi[o] yfit <- if(is.null(node$info$object)) { fitted(refit.modelparty(mobobj, node = nid))[o] } else { fitted(node$info$object)[o] } ## select panel plot_vpi <- viewport(layout.pos.col = 2L, layout.pos.row = i) pushViewport(plot_vpi) ## call panel function if(is.factor(xi)) cat_fun(xi, yi, yfit, i, paste("node_mob", nid, "-", i, sep = ""), ...) else num_fun(xi, yi, yfit, i, paste("node_mob", nid, "-", i, sep = ""), ...) if(pop) popViewport() else upViewport() } if(pop) popViewport() else upViewport() } return(rval) } class(node_bivplot) <- "grapcon_generator" partykit/R/mob-pvalue.R0000644000176200001440000013030414172230000014502 0ustar liggesusersmob_beta_suplm <- structure( c(-0.0648467, -0.15305667, -0.23071675, -0.29247661, -0.35706588, -0.40514715, -0.45248386, -0.50458517, -0.55009159, -0.60241623, -0.64308746, -0.68833676, -0.73136161, -0.78078198, -0.82894221, -0.88430133, -0.9499265, -0.98828874, -1.04892713, -1.11527783, -1.14992644, -1.24010871, -1.38522113, -1.48296473, -1.78738608, -0.03933112, -0.14650989, -0.28765583, -0.35528752, -0.49538961, -0.58780544, -0.66900489, -0.77825803, -0.87260977, -0.96782445, -1.07358977, -1.12531079, -1.16041007, -1.2975797, -1.36743697, -1.43012785, -1.53311747, -1.65273586, -1.79350728, -1.9117747, -2.02659329, -2.18499383, -2.3765858, -2.51267262, -3.05559851, -0.1250856, -0.27323021, -0.43148524, -0.48172245, -0.6898932, -0.7928579, -0.85066146, -1.06133796, -1.11977435, -1.20203015, -1.28736105, -1.45874969, -1.60889159, -1.64346161, -1.68334797, -1.81974576, -2.02648892, -2.04820499, -2.3230492, -2.59516448, -2.79776102, -3.03865047, -3.31299004, -3.65667229, -4.09174097, -0.40798205, -0.58214849, -0.67464799, -0.85920669, -0.99797889, -1.10019761, -1.24048639, -1.44519417, -1.43104108, -1.52887344, -1.66695722, -1.79016819, -1.91159633, -1.93474222, -1.94039709, -2.14388035, -2.34856811, -2.52186324, -2.81381108, -3.02543477, -3.3338615, -3.70012182, -4.08017759, -4.47426188, -5.32601074, -0.11619422, -0.46546717, -0.74391826, -1.02744491, -1.26392205, -1.42145334, -1.65407989, -1.81536469, -2.02334533, -2.09938834, -2.20567987, -2.44943836, -2.63257362, -2.81161264, -2.98179286, -3.13342287, -3.30649507, -3.4646422, -3.54117909, -3.53272742, -3.80907119, -4.20676069, -4.84259892, -5.47685207, -6.39138173, -0.0687869, -0.33471313, -0.58645046, -0.84305517, -1.17255237, -1.46491217, -1.55238215, -1.79236992, -1.78127768, -2.21251422, -2.47288843, -2.61217463, -2.93562547, -3.34428329, -3.48448133, -3.64732289, -3.79479594, -4.04745714, -4.13484904, -4.27469148, -4.61491387, -4.91271109, -5.37456783, -6.01333062, -7.08021496, -0.53689878, -0.58562073, -0.95896123, -1.31359234, -1.55985878, -1.74442449, -2.0175967, -2.20599731, -2.25783227, -2.53419037, -2.83535247, -2.94857734, -3.23125462, -3.35534682, -3.46151576, -3.87863069, -4.23908351, -4.4191379, -4.82113958, -4.95712189, -5.33535348, -5.94327236, -6.2144914, -6.95870114, -8.48837563, -0.06587378, -0.58124366, -0.53482076, -0.70899479, -1.07383099, -1.05381577, -1.27585106, -1.68931537, -2.18809932, -2.50101866, -2.85948167, -3.35512723, -3.65167655, -4.01035186, -4.24709439, -4.50345226, -4.9099655, -5.36063931, -5.73370206, -6.09245707, -6.46768896, -6.84622409, -7.23578885, -7.80794405, -9.19862689, -0.8377844, -1.18727357, -1.67892814, -2.13655356, -2.40733753, -2.37013442, -2.49480314, -2.82625963, -3.17119868, -3.5636537, -3.88321378, -4.0313254, -4.38155427, -4.50039414, -4.87091786, -5.1383982, -5.39812039, -5.43335672, -6.18441355, -6.60044603, -7.11669991, -7.46755944, -8.07312922, -8.86841479, -10.22371148, -0.12732608, -0.77782321, -1.24808905, -1.76904345, -2.09486459, -2.30685545, -2.70509677, -2.92069286, -3.1997618, -3.6337934, -4.01274834, -4.50166071, -4.97277337, -5.21536918, -5.65195302, -6.06457328, -6.0595936, -6.46819929, -6.87347962, -7.25454462, -7.76257167, -8.18205476, -8.84260296, -9.55384281, -11.00985153, -0.28687631, -1.01453484, -1.7401651, -2.14079218, -2.50789978, -2.62260858, -2.8870498, -3.25691388, -3.77111395, -4.02040298, -4.21877289, -4.20809405, -4.62395981, -5.28744427, -5.60464823, -6.19483467, -6.56252902, -6.7891765, -6.97852808, -7.81007221, -8.50886767, -9.01689388, -9.55606731, -10.47717098, -11.89998388, -0.20697609, -1.25560706, -1.38547294, -1.87046797, -2.32172961, -2.77530991, -3.42319608, -3.9141916, -3.98123284, -4.27776907, -4.10943673, -4.62176712, -5.31805601, -5.801638, -6.31362677, -6.83561824, -7.27842657, -7.79706943, -8.24233569, -8.7511904, -9.26781892, -9.85615645, -10.35040195, -11.37537184, -12.87922864, -0.96032292, -1.78562028, -1.97966067, -2.42158333, -2.48856717, -3.28051437, -3.78503843, -4.14403801, -4.43321221, -4.69094902, -5.06109662, -5.7273341, -5.795782, -6.50909126, -6.60160327, -6.91561016, -7.54515073, -7.93078073, -8.41010623, -8.86495369, -9.52126643, -10.30207235, -11.06975833, -12.15664045, -13.88493811, -0.5305789, -0.80812173, -1.59572361, -2.19031473, -2.39824582, -2.75800734, -3.49182845, -4.05510978, -4.45062227, -4.75937805, -5.16988136, -5.77217189, -5.9007907, -6.28750433, -6.66785584, -7.29857891, -7.96433421, -8.54188927, -8.94534315, -9.35262892, -9.73355542, -10.52623971, -11.51719761, -12.35480897, -14.61237001, -0.6739616, -1.03059879, -1.04906844, -1.25236282, -1.64262441, -1.54300336, -2.4826069, -3.10322952, -3.81410781, -4.42629192, -5.3093647, -5.73487329, -6.59234495, -6.77170123, -7.5786476, -8.08212767, -8.54406816, -9.05194333, -9.3590013, -9.73494274, -10.57869777, -11.42062974, -12.44191891, -13.69538964, -15.485313, -0.0913465, -1.04378984, -1.96856694, -2.55693634, -3.48268362, -3.98503866, -4.68248535, -4.79433839, -5.22778799, -5.61157139, -5.77881057, -6.24269823, -7.00486744, -7.5911674, -8.17764741, -8.21284923, -8.56768956, -9.1302657, -9.38913624, -10.30386897, -11.01233954, -11.70690938, -12.26629045, -13.95205351, -16.33802631, -1.19451064, -0.61304263, -1.78139109, -1.74865854, -2.95068847, -3.9464868, -4.11204387, -5.01078513, -5.30560447, -5.99452544, -6.35254017, -6.84941244, -7.22864758, -8.40745421, -8.73700419, -9.42296398, -9.91701341, -10.45110576, -10.81712311, -11.30777705, -11.96527304, -12.76105449, -13.73171703, -15.05430428, -17.20018832, -0.57901589, -0.61566409, -1.94156883, -2.62055985, -2.7790414, -3.57177154, -4.42213185, -5.10532787, -5.46108672, -6.46824055, -6.35209946, -7.1942972, -7.76122523, -8.09612319, -8.86934521, -9.24340158, -9.82676851, -10.6299845, -11.27685859, -12.03859451, -12.73477308, -13.40440195, -14.15023958, -15.6500136, -18.0989596, -1.32304249, -2.79621128, -3.56766199, -4.05795479, -4.89711879, -5.92841321, -6.39059643, -7.0876829, -7.53083, -8.01208734, -8.70797744, -9.44730653, -9.83731797, -10.010367, -10.64602144, -11.18554702, -11.63296397, -12.1370488, -12.5235392, -13.0082886, -13.5821605, -14.17176731, -14.94024433, -16.01544412, -18.18744736, -0.93767346, -1.39743879, -2.78023901, -3.13333051, -3.6981945, -4.63133758, -5.05468994, -5.93983376, -6.51943117, -7.34041405, -7.87705422, -8.34525685, -8.8688471, -9.5207757, -10.19551877, -10.86984218, -11.59017802, -12.13536344, -12.88553549, -13.70987004, -14.26661135, -15.21057964, -16.08902791, -17.11358176, -18.99297261, -1.91882482, -2.50977144, -1.64637756, -2.92698693, -4.07208251, -5.13694912, -5.4194589, -5.70365743, -6.25263884, -6.36733605, -7.06329052, -7.98139299, -8.76118074, -9.60618958, -10.49489334, -11.2774052, -11.93420729, -12.57665664, -13.32753376, -14.07700093, -14.91429075, -15.75739961, -16.8692775, -18.19943522, -20.3546376, -1.0168543, -2.60495567, -2.86000663, -2.68675011, -1.94661764, -3.48454706, -3.992952, -4.97105555, -4.5575301, -5.45965609, -6.56098097, -8.3868022, -8.62176424, -10.1431575, -11.04032773, -11.45645206, -12.11371089, -12.76806289, -13.177768, -13.99800348, -14.80089189, -15.89462589, -17.22077668, -18.72943574, -21.25689814, 0.94096473, -1.22725053, -1.75872846, -3.9575768, -4.94110206, -5.7742865, -6.08848061, -6.58259851, -5.48128544, -6.79236566, -7.53943946, -8.34133308, -8.1735607, -9.41939055, -10.44472371, -10.87498349, -12.41061954, -13.05498712, -13.07771005, -13.99905583, -15.10380703, -16.40762679, -18.05996121, -19.76683028, -22.31185721, 1.08326391, 0.76051631, 2.07027863, -2.1057565, -3.78479942, -5.13505669, -6.06385571, -6.79994277, -8.01575875, -9.0065242, -9.39541502, -10.37808952, -11.16653768, -11.82597991, -12.53712013, -13.31498065, -13.92159257, -14.51359909, -15.40003703, -16.13707217, -16.63866207, -17.60771953, -18.6663428, -19.83568951, -22.51568418, -2.11162974, -3.35339899, -3.72841764, -4.91865235, -5.10718347, -5.34523901, -6.49950328, -6.56823372, -7.53743525, -8.23573648, -8.27526709, -9.42134551, -10.64615787, -11.30236859, -12.11073251, -12.6848716, -12.9766545, -14.16209122, -15.60464973, -16.44342921, -17.13809253, -17.81256047, -19.05804694, -20.65856043, -23.41820502, -0.05998747, -0.58564982, -1.39278332, -3.37780497, -5.80306991, -6.30431193, -6.6490522, -7.72028924, -9.77306301, -9.46699714, -10.44746836, -11.53549458, -11.5145561, -12.21245714, -13.33619262, -13.93937444, -14.13636162, -15.13548602, -15.12544755, -16.01073023, -17.45954163, -18.52209521, -19.96891259, -21.77962654, -24.37165652, 0.14408865, -1.68824341, -2.80529427, -3.84471906, -5.27514707, -6.30987093, -6.75814771, -6.67078231, -7.90742503, -9.48244344, -9.80080117, -10.70348941, -11.94969029, -12.95847838, -13.52794048, -14.23377404, -15.1851375, -15.8924598, -16.23689422, -17.15303179, -18.17974307, -19.3172696, -20.83059788, -22.53758651, -25.1817373, 0.79939887, 0.03205666, -0.89955233, -1.4857033, -0.82383039, 0.5324532, 0.08803781, -2.32772158, -3.26635598, -4.51747286, -6.03001976, -8.83424437, -10.45716586, -12.24748808, -13.51362312, -14.47395149, -15.43533936, -15.82692606, -16.48073364, -17.34560575, -18.4974839, -20.28612607, -21.45173389, -23.0525819, -25.86459932, -0.97451814, -3.31523561, -3.44181996, -4.06057325, -5.50043111, -5.90874636, -7.37484097, -8.0686921, -9.19980094, -9.97292626, -11.3341333, -11.13943081, -11.51670322, -12.8736633, -13.55604421, -14.91348471, -15.87673684, -16.80606996, -17.25885348, -17.9129516, -19.27876378, -20.33252371, -21.67046167, -23.45241774, -26.34713744, -0.45185348, -1.34552529, -4.10601015, -4.06956204, -4.37163956, -4.96136749, -6.09612958, -6.79175933, -7.92402706, -8.25906871, -9.38202152, -10.4807904, -11.51038877, -12.33853757, -13.30312119, -14.60679957, -15.90242413, -17.06116511, -18.47835054, -19.48334693, -20.3503361, -21.68959354, -22.91384536, -24.54026411, -27.29732409, -3.09939971, -3.32474971, -3.46755751, -3.41597684, -5.52680707, -6.65007406, -6.9115191, -8.55718448, -9.46056864, -10.0463213, -11.40239801, -12.74841191, -13.83627077, -13.7513071, -14.62859882, -15.42622988, -16.4459132, -17.15730455, -18.08342986, -19.34110938, -20.84497913, -22.05578685, -23.14341564, -25.17992235, -27.92675759, 0.9228326, -1.52070251, -4.79973408, -6.35231225, -7.66478177, -7.45406139, -7.96374777, -7.52809014, -9.48652501, -10.49223067, -10.93823367, -13.34914328, -14.40618037, -15.55996409, -16.73233927, -17.54459512, -18.37462368, -19.11400543, -19.85087871, -20.80840349, -21.58905123, -22.53427553, -23.6610257, -25.55743038, -28.6593938, -0.67127137, -2.35176782, -2.56288229, -5.0251296, -6.11785288, -7.97165633, -8.82467279, -8.56206391, -9.42732063, -11.28328634, -12.13419009, -11.99889194, -12.58860695, -14.51453528, -16.01651486, -17.04491345, -18.106229, -19.28255657, -20.38447451, -21.2043418, -22.28587689, -23.41422487, -24.64959031, -26.10948832, -28.82959083, 1.39267822, 2.73909431, -0.30852069, -0.49191557, -1.06900899, -4.80174038, -7.74429261, -8.57210051, -10.15214971, -11.15102586, -13.64298575, -14.48247672, -15.35212309, -16.11005408, -16.94107167, -17.64203321, -17.96105135, -18.79888981, -19.76444493, -21.25567826, -22.65736046, -23.78512985, -24.86149506, -26.88880413, -30.13194652, -3.4018918, -4.52188036, -5.97907586, -5.9471244, -6.29309233, -6.71089295, -8.38691622, -10.43531078, -11.30985554, -12.80509172, -12.96840994, -14.91752468, -15.7804277, -16.2310254, -16.57411667, -17.80722296, -18.56432089, -20.09211544, -21.15486984, -22.02891632, -23.25526587, -24.65449898, -25.87767407, -27.53979094, -30.01082046, -2.18411218, -3.42768338, -2.88898683, -5.03434617, -7.14143228, -6.44365876, -7.33644084, -7.81222962, -8.62497252, -9.09990075, -10.5800447, -14.26595287, -15.34887785, -16.54588899, -17.21897182, -17.95794773, -19.51533257, -21.06924324, -22.11906531, -23.30316044, -24.1346444, -25.2320325, -26.80940751, -28.70564311, -32.02058598, 4.96237545, -0.88879878, -2.35069382, -4.46357858, -5.13472407, -6.3847125, -7.85452304, -10.21404555, -11.36819028, -12.54093227, -13.80958526, -15.33641873, -16.15654992, -17.31366457, -18.27791676, -18.79767265, -19.18523508, -19.99538342, -21.37968612, -22.18429164, -23.38539326, -25.29878169, -26.80995112, -28.92403945, -31.7785054, 1.33123401, -1.02249003, -2.6059089, -5.03386748, -4.84022598, -5.71008884, -4.23324978, -5.43305024, -9.38670501, -12.35863658, -14.76322339, -15.92483383, -16.79956316, -18.35682673, -19.29588663, -20.45545504, -21.45765423, -22.56577441, -23.31772778, -24.27986692, -25.38170576, -26.59632792, -28.01733427, -29.564567, -32.7086858, 5.15430037, 3.20382719, 2.265794, 1.70478095, -0.81045339, -1.0908993, -7.75566411, -8.63732929, -7.28411605, -9.1182173, -10.74836959, -12.43301415, -12.68311992, -14.60913215, -15.59191441, -14.73154944, -16.53048259, -19.4591197, -20.612641, -22.83687863, -23.63057252, -24.48836498, -26.50792922, -30.20153782, -33.61395119, -3.35130854, -3.36891886, -4.26561375, -6.54543163, -8.81898894, -10.19461991, -10.90426574, -11.95264669, -12.34848756, -13.59064154, -14.57419256, -14.96507795, -14.17737602, -17.57479064, -18.43607852, -20.28106993, -21.12463625, -21.6498765, -23.45913736, -25.28117062, -26.44477551, -27.54322022, -29.23967429, -31.24787883, -34.24072356, 0.99671156, 0.96757645, 0.95825013, 0.95715782, 0.95237505, 0.96055795, 0.95810999, 0.96149538, 0.96684273, 0.96518399, 0.97354902, 0.97829106, 0.9820687, 0.99475319, 1.00023473, 1.00162529, 1.00384268, 1.01604712, 1.02570939, 1.03526033, 1.06643436, 1.06929468, 1.06808543, 1.1283969, 1.17220925, 0.99525784, 0.9938654, 0.98139359, 0.9942739, 0.96923268, 0.97339124, 0.97444133, 0.96678414, 0.97626434, 0.97636983, 0.97407744, 0.99897105, 1.01629918, 1.015268, 1.03004743, 1.05139461, 1.05280599, 1.05932633, 1.04936541, 1.0588459, 1.07200268, 1.08674781, 1.11342895, 1.15305027, 1.17629253, 0.98151496, 0.98324873, 0.98336371, 1.00450689, 0.99692978, 1.00417536, 1.01852003, 1.00719185, 1.03046019, 1.03885443, 1.04597379, 1.03549948, 1.03374376, 1.06767681, 1.09676432, 1.10216977, 1.0962988, 1.13491785, 1.12030935, 1.09122076, 1.09109337, 1.09037434, 1.10476754, 1.13355758, 1.21034051, 0.90528031, 0.91505724, 0.9364688, 0.93433918, 0.9411933, 0.95132377, 0.96334287, 0.96603109, 1.00890357, 1.02148881, 1.02616925, 1.03765517, 1.04392701, 1.071198, 1.10122554, 1.09891616, 1.10457466, 1.10727065, 1.10513873, 1.12012324, 1.12405358, 1.12268437, 1.14201041, 1.17607899, 1.21390643, 1.02457601, 1.01129094, 1.00172704, 0.9890919, 0.98620432, 0.9972466, 0.99253425, 1.0044353, 1.00046922, 1.01518764, 1.02275886, 1.02127435, 1.01887636, 1.02006744, 1.0305527, 1.0446574, 1.05369295, 1.06781143, 1.10989892, 1.15870693, 1.17183781, 1.17153767, 1.14601974, 1.15819167, 1.17642784, 1.03775792, 1.03320405, 1.03391895, 1.03864019, 1.02620388, 1.01747206, 1.02887917, 1.02880434, 1.06533575, 1.04598986, 1.04669836, 1.05733536, 1.04956126, 1.03025578, 1.04393869, 1.05837582, 1.07938759, 1.08339951, 1.11380916, 1.13359417, 1.14810477, 1.18479646, 1.1930588, 1.22140239, 1.25536339, 0.95219603, 0.98400121, 0.97640322, 0.97126847, 0.97651275, 0.99363695, 0.99545856, 1.00681619, 1.03037828, 1.02237747, 1.01736263, 1.03701081, 1.04527054, 1.07043687, 1.08475765, 1.07699402, 1.07739268, 1.10217153, 1.10489462, 1.14759912, 1.15489501, 1.14993703, 1.2117616, 1.21291275, 1.16895303, 1.00259864, 0.98811229, 1.02737978, 1.03875734, 1.03945526, 1.0784185, 1.10005486, 1.09777938, 1.08874332, 1.08718514, 1.08365161, 1.06078274, 1.06322641, 1.06373417, 1.07465019, 1.09341658, 1.08551877, 1.07646817, 1.07605364, 1.07280436, 1.0801085, 1.09621271, 1.12575792, 1.15036691, 1.17118238, 0.93113614, 0.93903334, 0.93065103, 0.92934556, 0.94488795, 0.97862192, 0.99988795, 0.99845236, 0.99862288, 0.99017086, 0.9946165, 1.01955132, 1.01232498, 1.03871207, 1.03085863, 1.03917618, 1.05170079, 1.10431373, 1.06499129, 1.07700965, 1.0808924, 1.09541073, 1.1095527, 1.11196659, 1.13939491, 1.01972827, 0.9982764, 0.9999548, 0.98955787, 0.99858018, 1.01743721, 1.02589592, 1.04951504, 1.06492822, 1.05272485, 1.05200434, 1.03350523, 1.01177319, 1.03214392, 1.01761463, 1.01623184, 1.06276209, 1.060171, 1.06428574, 1.07640874, 1.07583608, 1.09754669, 1.10727034, 1.13929623, 1.1430948, 0.98957614, 0.96835936, 0.95855704, 0.97100936, 0.968586, 0.99972676, 1.00826291, 1.0112365, 1.00174976, 1.01270387, 1.02263415, 1.06043526, 1.0533287, 1.0334176, 1.04034926, 1.01589606, 1.01908267, 1.03551668, 1.06079144, 1.01892107, 0.9994589, 1.01879789, 1.06131659, 1.06036243, 1.11053955, 0.993185, 0.95738412, 0.98877323, 0.99752949, 1.00261042, 1.00830993, 0.99496327, 0.99569457, 1.0326676, 1.03969503, 1.08139639, 1.06960628, 1.05319163, 1.04781506, 1.03917077, 1.03283667, 1.0342274, 1.023434, 1.02377082, 1.01203272, 1.03507954, 1.04416615, 1.09166954, 1.0585826, 1.06208248, 0.96782155, 0.94350733, 0.96963899, 0.9754331, 1.00870226, 0.98402078, 0.99298565, 1.00465319, 1.01579244, 1.02854159, 1.03493729, 1.01128328, 1.04440256, 1.01770567, 1.05548531, 1.06849333, 1.06249592, 1.0699571, 1.08030302, 1.10123141, 1.09017381, 1.07135898, 1.07145152, 1.07848089, 1.09269398, 0.98368009, 1.01109688, 1.00005397, 0.99792404, 1.03020888, 1.03961272, 1.01938528, 1.01959643, 1.03128162, 1.04463912, 1.04163329, 1.02954537, 1.05276183, 1.06353614, 1.07798238, 1.06357005, 1.05648117, 1.04729101, 1.07352566, 1.08488023, 1.11384048, 1.10944281, 1.11004154, 1.15898291, 1.15307761, 0.9675877, 0.98646992, 1.01868047, 1.04215207, 1.05467658, 1.09638126, 1.08329937, 1.081832, 1.08601992, 1.08458304, 1.06292778, 1.06520085, 1.04157247, 1.06366213, 1.03613103, 1.04059581, 1.04916238, 1.05477016, 1.08401132, 1.10730545, 1.09893801, 1.09102591, 1.07604096, 1.06057172, 1.03827923, 1.00135334, 0.98376663, 0.97066665, 0.97587169, 0.96434741, 0.97076823, 0.96454779, 0.99366441, 1.01098551, 1.01795115, 1.04350812, 1.05369725, 1.04041905, 1.04728599, 1.03465732, 1.06781106, 1.08294771, 1.08679108, 1.12271764, 1.10369615, 1.12282902, 1.14842385, 1.19537226, 1.17989802, 1.14691263, 0.96213021, 1.02910449, 1.00688152, 1.0464476, 1.01743683, 1.00624209, 1.03555902, 1.01746947, 1.04014327, 1.02756756, 1.0444662, 1.04282184, 1.05195602, 1.00952605, 1.0360307, 1.0298249, 1.04509046, 1.04570811, 1.07909554, 1.0980248, 1.10697097, 1.11400431, 1.14524902, 1.14911289, 1.1544346, 0.98622919, 1.02219984, 1.00123632, 1.00211368, 1.03422849, 1.02910203, 1.02211869, 1.01642223, 1.03819744, 1.01047248, 1.05135326, 1.03651021, 1.03574401, 1.05605009, 1.03830396, 1.06235959, 1.06441205, 1.05028481, 1.06503994, 1.0618399, 1.07685809, 1.10629121, 1.1442555, 1.15140506, 1.17029897, 0.95832919, 0.933535, 0.93210709, 0.94709624, 0.93567098, 0.91165966, 0.91773957, 0.91252457, 0.9218757, 0.92170289, 0.90225855, 0.88036159, 0.88884871, 0.92151941, 0.90818127, 0.89770414, 0.90139634, 0.90008482, 0.91853667, 0.92199325, 0.92194461, 0.94080557, 0.96868608, 1.0159258, 1.04257134, 0.97989282, 1.00526196, 0.97254899, 0.9992625, 1.00898788, 0.99712304, 1.01308178, 0.99844861, 1.00599883, 0.98818312, 0.99043401, 0.99739582, 0.9968266, 1.00334801, 0.99669217, 0.99308869, 0.97738919, 0.97206863, 0.98125679, 0.95151093, 0.99125929, 0.96736269, 0.98651967, 1.00653595, 1.02028684, 0.94842852, 0.96036523, 1.03641684, 1.02109845, 1.01005923, 0.99259316, 1.01412676, 1.03833275, 1.04479951, 1.07123783, 1.07312362, 1.07450508, 1.0701454, 1.05749547, 1.04481273, 1.03815847, 1.03827458, 1.03475703, 1.04014114, 1.04739527, 1.05478624, 1.06251211, 1.05837778, 1.05806746, 1.02487475, 0.96688912, 0.93597836, 0.9601954, 1.0102506, 1.07707279, 1.04456257, 1.06079869, 1.06472509, 1.12659794, 1.12532202, 1.11340021, 1.06099678, 1.0947578, 1.05136043, 1.04140032, 1.0705856, 1.07310397, 1.0706844, 1.08979475, 1.10274996, 1.10858659, 1.10743573, 1.10225224, 1.09611546, 1.13102626, 1.07372683, 1.02744152, 1.05225294, 1.00304141, 0.99181473, 0.9966397, 1.02262192, 1.03086116, 1.11650316, 1.09244046, 1.10004847, 1.10349604, 1.14793429, 1.12552664, 1.11384156, 1.13660786, 1.07982337, 1.09274429, 1.15828445, 1.15348295, 1.1621882, 1.14845028, 1.12716807, 1.0931102, 1.08834724, 1.05535733, 1.08055869, 1.15420882, 1.05432766, 1.02970587, 1.01490791, 1.01432448, 1.01889057, 1.00144128, 0.9884367, 1.00254099, 0.9849643, 0.97871428, 0.97385725, 0.97153821, 0.96309439, 0.96883525, 0.97639956, 0.96160022, 0.94646595, 0.98793255, 0.96687106, 1.00976894, 1.07633872, 1.09637139, 0.93794913, 0.93395086, 0.96199485, 0.94112157, 0.97222478, 0.99615092, 0.98202759, 1.0164916, 1.02132776, 1.02538744, 1.06566549, 1.04595452, 1.02650382, 1.03758, 1.03321785, 1.0502919, 1.0846636, 1.04603251, 0.99794254, 0.99847821, 1.03848496, 1.08470064, 1.0641286, 1.08638148, 1.06165219, 1.02982801, 1.04961528, 1.06454206, 1.04012063, 0.98378317, 1.00124407, 1.01380307, 1.02020813, 0.95922771, 1.01904485, 1.00004575, 0.98170567, 1.01813519, 1.01828881, 0.99253144, 1.00632148, 1.0372487, 1.02542669, 1.09007722, 1.10591548, 1.07588936, 1.09174638, 1.09508217, 1.06854561, 1.05183879, 1.01068622, 0.98929663, 0.98710321, 0.98918892, 0.97141833, 0.97040265, 0.99510374, 1.03907408, 1.02529341, 0.98724672, 1.01516838, 1.01679016, 0.99541567, 0.98964061, 1.00202774, 1.01739432, 1.00810225, 1.00825698, 1.05540668, 1.07131004, 1.07062455, 1.06937314, 1.05641563, 1.05115003, 1.04145774, 1.05529572, 1.05739119, 1.06602683, 1.09069306, 1.14737169, 1.21407944, 1.2335615, 1.20863128, 1.21820913, 1.21063524, 1.18925759, 1.12225802, 1.09052552, 1.05516616, 1.02900233, 1.02306775, 1.01004287, 1.04043642, 1.05566763, 1.07072731, 1.07548152, 1.01471198, 1.04802042, 1.04579565, 1.00620908, 1.00251973, 0.96215578, 0.99687847, 1.00256689, 0.99230352, 1.01123305, 0.99460204, 1.00890208, 0.99060666, 1.00048743, 0.98179803, 1.03315987, 1.05219197, 1.04309359, 1.053441, 1.0193217, 1.01992618, 0.99185982, 1.0367618, 1.04274235, 1.01724776, 1.06093825, 1.04904433, 1.02967967, 1.05793273, 1.01930905, 1.03045829, 0.97016447, 0.99953822, 1.02498848, 1.04738273, 1.04529594, 1.0536344, 1.05651914, 1.07606786, 1.07325257, 1.06712586, 1.07061948, 1.08004765, 1.08076894, 1.06716915, 1.04707974, 1.02912412, 1.00851672, 1.01907055, 1.02885912, 1.00697161, 1.0390513, 1.04178393, 1.03127677, 0.94450854, 0.98336716, 1.01384784, 1.04100008, 1.0094129, 1.0147673, 1.0386017, 1.01869204, 1.03020995, 1.04674799, 1.03515373, 1.02136329, 1.01042408, 1.06808974, 1.06540949, 1.07090333, 1.06245678, 1.06704407, 1.07219353, 1.05514805, 1.01634816, 1.02356982, 1.07932881, 1.06481382, 1.03279542, 1.03819509, 1.01562128, 0.95981872, 0.94668742, 0.93519189, 0.98490061, 1.00178787, 1.0541654, 1.02695236, 1.03229473, 1.04524242, 0.98612341, 0.97546849, 0.9546071, 0.92318283, 0.91990624, 0.90977204, 0.90749857, 0.9168134, 0.9042071, 0.90653965, 0.94378133, 1.0293784, 0.99195482, 1.04026978, 0.99575825, 0.99428102, 1.02614781, 0.99281512, 0.99467136, 0.96826751, 0.98460369, 1.03538692, 1.04021534, 1.01030721, 1.01871061, 1.06627775, 1.07757568, 1.0441522, 1.0133829, 1.00778531, 0.99955707, 0.98157477, 0.96440457, 0.97925864, 0.97032645, 0.96065258, 0.95483837, 0.94969826, 0.97151376, 1.06370058, 1.12756675, 1.09131542, 1.11653083, 1.13066921, 1.06728655, 1.01914747, 1.02604818, 1.01737407, 1.01099325, 0.95574297, 0.95189612, 0.94566483, 0.95928391, 0.96591946, 0.97511416, 1.01770827, 1.04307385, 1.04704203, 0.99817277, 0.9816989, 0.99354694, 1.05134906, 1.0670398, 1.03332063, 0.92713346, 0.93703071, 0.93890567, 0.97727174, 1.00636112, 1.03283419, 1.02082077, 0.9808383, 0.9945486, 0.97458461, 1.01144058, 0.97258099, 0.97385944, 1.00675003, 1.02867372, 1.00387999, 1.01357688, 0.97796504, 0.977507, 0.9827151, 0.99321682, 0.94535835, 0.97442736, 0.95282744, 0.91685692, 0.97764025, 0.98643182, 1.033447, 1.01504602, 0.98884827, 1.05228443, 1.06273693, 1.09281793, 1.11031113, 1.13092416, 1.12097086, 1.02527598, 1.02626485, 1.02936518, 1.04844837, 1.06766552, 1.03629324, 1.00404695, 0.99724967, 0.99065045, 1.01810829, 1.04075799, 1.0198155, 1.04320299, 1.04570116, 1.13500821, 1.04122648, 1.03883689, 1.02482957, 1.05482149, 1.05946609, 1.05512345, 1.01870031, 1.01898786, 1.01635998, 1.00364988, 0.99259816, 0.98898087, 0.97321427, 0.96357086, 1.00241461, 1.04936796, 1.06233004, 1.0307873, 1.06323292, 1.05755696, 1.02954167, 1.05544122, 1.02417637, 0.95805763, 1.04574971, 1.03081935, 1.02960286, 1.00662318, 1.05826122, 1.07393922, 1.14228276, 1.1417163, 1.07417889, 1.01975609, 0.97448773, 0.97857736, 0.98478833, 0.96142387, 0.95928468, 0.93437183, 0.9244452, 0.88706333, 0.9266293, 0.91481091, 0.93972718, 0.92517634, 0.96703695, 0.9161296, 0.9385061, 1.11132411, 1.11505569, 1.12976198, 1.15960051, 1.1456843, 1.17497088, 1.05526701, 1.06811547, 1.13474373, 1.1230698, 1.11574095, 1.09709216, 1.12345786, 1.10825333, 1.10990426, 1.18937861, 1.16832551, 1.10764914, 1.11904904, 1.07512997, 1.11501763, 1.17656691, 1.18124701, 1.09323998, 1.0020602, 0.9405836, 0.97357345, 0.9846081, 0.95855119, 0.92581528, 0.921272, 0.93679164, 0.93808197, 0.96444992, 0.96161791, 0.96936248, 1.01149428, 1.07379663, 0.99973403, 1.01689985, 0.98492061, 1.00251086, 1.05087814, 1.00568101, 0.96363276, 0.98893741, 1.00339074, 0.97820963, 0.98529795, 0.97134889, 1.2573241, 1.43651315, 1.56531261, 1.68851898, 1.77889686, 1.89761322, 1.98370422, 2.07086519, 2.17244338, 2.23509053, 2.33722161, 2.42776524, 2.50833918, 2.6209551, 2.70286643, 2.77835798, 2.84325795, 2.96752918, 3.08442682, 3.19770394, 3.44739573, 3.54993605, 3.61667211, 4.07202473, 4.4726701, 2.44239332, 2.78837829, 2.93724618, 3.18187129, 3.19484388, 3.32763253, 3.44170617, 3.48652761, 3.61709836, 3.6779502, 3.71945379, 3.95114475, 4.14932643, 4.17103882, 4.3223804, 4.53836755, 4.61175851, 4.69340428, 4.68380985, 4.8073354, 4.97772701, 5.14231666, 5.40268693, 5.88573096, 6.11067794, 3.43036267, 3.83943122, 4.07662685, 4.44796533, 4.49665381, 4.69772537, 4.95584784, 4.90812703, 5.20741484, 5.3693925, 5.52416853, 5.4888527, 5.50958245, 5.89426861, 6.23634969, 6.34122715, 6.29077373, 6.75208304, 6.59886028, 6.32294425, 6.35576003, 6.37212114, 6.5282289, 6.84167661, 7.79013953, 3.93318971, 4.41094611, 4.85980413, 5.01958587, 5.22477986, 5.46557096, 5.6723934, 5.73132847, 6.29613628, 6.51227891, 6.63448592, 6.82686641, 6.95318158, 7.36997641, 7.82328663, 7.83079173, 7.89044965, 7.95561422, 7.90116455, 8.08624226, 8.08884313, 8.00223819, 8.18314656, 8.60611855, 8.90496643, 5.80252297, 6.12710758, 6.30619245, 6.35729244, 6.4591257, 6.71491425, 6.740473, 6.95402735, 6.98677984, 7.27464455, 7.47265174, 7.46129265, 7.46907351, 7.52690766, 7.67224919, 7.90265755, 8.05397638, 8.27206632, 8.90945304, 9.72776829, 9.91294592, 9.84654688, 9.30420469, 9.30236461, 9.41930982, 7.09045346, 7.62520471, 7.96566986, 8.22807265, 8.19864669, 8.192869, 8.53383279, 8.59456107, 9.2685801, 8.91322396, 8.92953537, 9.17320934, 9.00301305, 8.63825734, 8.87565157, 9.13002628, 9.47650111, 9.51466537, 10.08288929, 10.47680321, 10.64305003, 11.1806159, 11.24873153, 11.55114952, 11.84388128, 7.1028369, 8.16310859, 8.31297248, 8.39458871, 8.6116192, 8.97007085, 9.05632019, 9.31295267, 9.83449349, 9.74010484, 9.65255439, 10.0582618, 10.13194554, 10.59763704, 10.91888223, 10.68834341, 10.59992445, 11.01503763, 10.94912199, 11.72034341, 11.78096338, 11.48022849, 12.57656495, 12.41746897, 11.0568314, 9.00416324, 9.29588314, 10.38413127, 10.86726887, 10.98596388, 11.87560902, 12.3098159, 12.24252384, 12.00013658, 11.97891812, 11.88283066, 11.38799144, 11.38822596, 11.32180872, 11.50213594, 11.80959613, 11.57319597, 11.25922919, 11.18469963, 11.07807286, 11.14611701, 11.40693419, 11.92603449, 12.32590546, 12.18766263, 8.5883869, 9.24954183, 9.29685978, 9.33656379, 9.70552238, 10.57272004, 11.11202863, 11.11899557, 11.12620845, 10.91577546, 10.95270011, 11.46852117, 11.27876602, 11.86056231, 11.63335876, 11.78048327, 11.99793995, 13.09302596, 12.01561699, 12.12034223, 12.02669094, 12.30726854, 12.39994474, 12.21815495, 12.28861527, 11.23288885, 11.39255875, 11.66130981, 11.58597271, 11.87831304, 12.36966797, 12.51217351, 13.04128558, 13.38535841, 13.0950741, 13.0322117, 12.57591029, 12.03313903, 12.43310006, 12.01632623, 11.88077482, 12.97932137, 12.81597962, 12.80920657, 12.97479282, 12.81308974, 13.20385908, 13.19094338, 13.69566019, 13.27442097, 11.83783861, 11.90975793, 11.79102043, 12.15587054, 12.2538371, 13.05242107, 13.33554168, 13.40020219, 13.1144629, 13.37818178, 13.67803712, 14.67639243, 14.43892816, 13.74971322, 13.84817867, 13.11638006, 13.1067846, 13.48939975, 14.12219368, 12.80828328, 12.06993783, 12.34966736, 13.1328694, 12.77710316, 13.39248273, 13.02526679, 12.6143028, 13.70117093, 13.97922155, 14.15156668, 14.27368705, 13.84539441, 13.77323571, 14.75121929, 14.92183058, 16.20106765, 15.83163865, 15.14323043, 14.88197405, 14.50509125, 14.18372982, 14.07860787, 13.63889444, 13.53052355, 13.11206506, 13.44530299, 13.45292064, 14.47635207, 13.31219885, 12.83248868, 12.96494958, 12.91224967, 13.91086002, 14.20571032, 15.25854613, 14.52667154, 14.63233359, 14.90420398, 15.22639182, 15.56571593, 15.68524541, 14.90697688, 15.81532942, 14.89617531, 15.88779531, 16.18754384, 15.76113514, 15.86478742, 15.98357275, 16.3712948, 15.84531873, 15.05116768, 14.77495506, 14.4865294, 14.09406033, 14.62946881, 16.00894877, 15.88694739, 15.9368477, 16.90193781, 17.24362728, 16.59438834, 16.46717786, 16.72458913, 17.05600286, 16.95591334, 16.46927443, 17.16009456, 17.3761859, 17.64938382, 17.05375164, 16.58128765, 16.11546709, 16.69846699, 16.94832682, 17.67968688, 17.23924469, 16.80463243, 17.87674562, 16.55755233, 15.25728555, 16.45491413, 17.87873686, 18.83215491, 19.31397857, 20.79452208, 20.1242591, 19.95277639, 19.81833633, 19.5873885, 18.63729564, 18.66118103, 17.61777071, 18.31681133, 17.20167832, 17.15999253, 17.25797283, 17.22576198, 18.02889558, 18.63943558, 18.01695357, 17.44317122, 16.55885361, 15.52893606, 14.10625561, 17.44844463, 17.48342087, 17.18307302, 17.39099592, 16.83961037, 17.00297254, 16.65995197, 17.63287496, 18.04404405, 18.19984089, 19.01734887, 19.19847986, 18.47770031, 18.4445317, 17.88295181, 19.0430438, 19.44003984, 19.32503948, 20.40520153, 19.39385495, 19.6306348, 20.12473257, 21.43391832, 20.06497381, 17.84014338, 16.67034331, 19.84900333, 19.19472094, 20.80901562, 19.63995018, 18.96154153, 19.97354223, 19.14389422, 19.86179186, 19.27339377, 19.73926209, 19.60762015, 19.8183546, 17.93825819, 18.62634828, 18.16414262, 18.43859768, 18.25837821, 19.20599318, 19.644922, 19.68717938, 19.57373518, 20.089278, 19.6215689, 18.79900119, 18.77173073, 20.85053838, 20.04023678, 20.13829144, 21.37945116, 21.06068346, 20.57597229, 20.2400462, 20.90280333, 19.60643024, 21.18669406, 20.37872334, 20.15817732, 20.75737492, 19.85238989, 20.52349087, 20.37023029, 19.53064308, 19.7225017, 19.27746128, 19.45448463, 20.15939105, 21.17276423, 20.6386709, 19.96762244, 18.48023306, 17.84287279, 17.94912876, 18.54127463, 18.06100574, 16.9966338, 17.17688227, 16.79805798, 17.0357087, 16.92467236, 16.08050151, 15.10697972, 15.27001414, 16.36094134, 15.66802961, 15.17074312, 15.16459209, 14.94170023, 15.46218201, 15.45235636, 15.24901053, 15.66519855, 16.27646089, 17.37790692, 17.17560191, 20.31537415, 21.8728502, 20.71574061, 21.81622923, 22.17948485, 21.55110669, 22.10566166, 21.32350727, 21.4437838, 20.55047206, 20.49316663, 20.64475672, 20.46923537, 20.41596695, 19.90054772, 19.50959355, 18.67196064, 18.31406331, 18.25001052, 16.87702723, 17.99806101, 16.73489655, 17.0176133, 17.31938288, 16.98233441, 19.69796548, 20.79858948, 24.52136264, 23.70330544, 22.99022226, 22.07384199, 22.93456068, 23.84581621, 24.00468583, 25.09882342, 24.91325266, 24.4965961, 23.99932504, 23.20433673, 22.31128884, 21.72831161, 21.47099142, 21.09789423, 20.94560832, 20.85908102, 20.7263403, 20.63366713, 19.95358696, 19.32667266, 17.11170102, 21.98022025, 21.11569491, 22.45634101, 24.78566589, 28.08627208, 26.32270605, 26.87255509, 26.57416348, 29.37877651, 28.93237653, 27.95718271, 24.99109955, 26.22161836, 23.77527362, 22.94742809, 23.90537726, 23.73157476, 23.38510717, 24.05711488, 24.14490565, 24.029918, 23.42573753, 22.54046335, 21.56661458, 21.5551957, 27.6196046, 25.92215252, 27.17649901, 24.50457048, 23.92842835, 23.87169872, 24.91962948, 25.20980936, 29.48574396, 27.91271614, 27.88603637, 27.67781945, 29.72018995, 28.20998253, 27.22012433, 28.01731654, 24.98332759, 25.19280476, 27.94298491, 27.34964066, 27.09040491, 25.86970847, 24.09159783, 21.90394123, 20.36172534, 28.30769774, 30.3539556, 34.90167248, 28.84155289, 27.21974833, 26.1134807, 25.77710031, 25.75182208, 24.53316419, 23.5834862, 24.1201497, 23.00476986, 22.39967565, 21.99126271, 21.57474142, 20.9046617, 20.89528342, 20.94992826, 19.95839186, 19.07445895, 20.53590146, 19.26301167, 20.40514584, 22.56413126, 21.91256097, 23.1874666, 23.36705501, 24.83937269, 23.85012631, 25.33396746, 26.4977394, 25.48747225, 27.08610064, 26.83965099, 26.75434581, 28.54918733, 27.20979632, 25.73918928, 25.93585014, 25.3703246, 25.85223952, 27.24720391, 25.04274427, 22.25921046, 21.88312221, 23.18507078, 24.85988352, 23.44248595, 23.5273219, 20.98144312, 28.61811868, 30.38532975, 31.22928765, 29.47389384, 26.04907108, 26.78760532, 27.46293864, 27.18313342, 23.59814373, 26.43272948, 25.25913836, 23.98255449, 25.70945692, 25.46270057, 23.80580119, 24.16639428, 25.56131431, 24.51652034, 27.47962222, 27.72250043, 25.62288587, 25.77408883, 25.13280835, 23.03450007, 20.98754102, 29.4132895, 28.64307647, 28.60200288, 28.5553145, 27.31581548, 26.90660641, 27.92165873, 30.11445362, 28.96859473, 26.51269125, 27.68474829, 27.33180829, 25.71194011, 24.9425481, 25.25357115, 25.58876661, 24.69139239, 24.39537925, 26.40052685, 26.61769943, 26.07177997, 25.45104495, 24.04909301, 22.91751863, 21.06003005, 32.44262828, 33.53896381, 34.12554601, 35.37929165, 38.84664089, 43.34230761, 44.36915131, 41.77712842, 41.88401734, 40.93437115, 39.19255188, 34.41082052, 32.03370191, 29.37133975, 27.5035569, 26.76722426, 25.71096559, 26.95265845, 27.40397458, 27.65472138, 27.22321787, 23.42269307, 24.32037996, 23.41133954, 20.07803846, 30.17147365, 28.27740352, 30.48576952, 31.01252468, 30.03585883, 31.00502132, 29.5914922, 30.02967848, 28.77440772, 28.8741381, 27.27530692, 29.98111389, 30.81037166, 29.57903806, 29.74943841, 27.46045464, 26.96048751, 25.28187726, 27.19758151, 27.27002912, 25.31003597, 26.73307797, 25.51049744, 23.64576459, 23.30933223, 32.24298561, 33.55893116, 29.93683335, 31.94397783, 33.39057344, 34.38432014, 33.86332566, 34.10720497, 33.70380373, 34.67231546, 33.98238317, 33.1674725, 32.75282944, 32.82218166, 32.34345098, 30.97875574, 29.29035507, 27.79346636, 25.96976442, 25.90274685, 25.98118906, 24.22686892, 25.12327539, 24.45407358, 22.45845735, 28.18134982, 31.00119845, 33.16681411, 35.20436783, 32.79414011, 32.62129883, 33.9688576, 32.1815323, 32.35862413, 32.97207244, 31.67172039, 30.27777146, 29.19032293, 32.22681722, 31.70409664, 31.64229513, 30.73299914, 30.67325888, 30.494215, 28.98065367, 26.22758107, 25.91832218, 28.10877448, 26.25824622, 23.2424173, 36.33563342, 35.00865489, 30.96474837, 29.87536642, 28.92933845, 31.79056039, 32.62128335, 35.81015699, 33.36834684, 33.13463429, 33.75914644, 29.37050071, 28.29855728, 26.6970793, 24.55288366, 24.01960086, 23.14149189, 22.6915029, 22.81736136, 21.71806053, 21.53250374, 22.87046348, 26.48362131, 23.58169052, 24.15683659, 34.35222758, 34.49659693, 36.7621526, 34.047806, 33.86945457, 31.69911484, 32.21002835, 35.22055765, 35.17987817, 32.5679444, 32.61863328, 35.3602398, 35.75917151, 32.86082315, 30.41571859, 29.60724743, 28.62030614, 27.0429925, 25.62314147, 25.99263787, 24.99138617, 23.93896797, 23.05197415, 22.11034185, 21.72303575, 39.90446451, 45.68828229, 42.67755711, 44.62849429, 45.58526881, 40.08783397, 35.86004532, 35.96295502, 34.64116979, 33.8928035, 29.48121395, 28.96091018, 28.25161906, 28.58397967, 28.48883403, 28.6779086, 30.82973139, 31.66576275, 31.40922243, 28.04338494, 26.36161115, 26.39511257, 28.91348082, 28.5724726, 24.94855681, 31.05989534, 32.0987241, 31.96003363, 34.53299133, 36.25124788, 37.75210182, 36.28591385, 33.13256438, 33.50225784, 31.65142746, 33.6994541, 30.50220157, 30.16328051, 31.77616051, 32.92383975, 31.00427739, 31.19720032, 28.3937874, 27.79854046, 27.67808123, 27.51721336, 24.25229057, 25.1864937, 23.2051115, 20.03361673, 35.24512733, 36.26056059, 40.03169209, 38.19765183, 35.87719583, 40.15835641, 40.47798496, 42.06777372, 42.75113028, 43.82742713, 42.48676913, 34.87158717, 34.32553895, 33.81086542, 34.54260171, 35.27984344, 32.67133541, 29.96124787, 29.08920579, 28.07370235, 29.19048928, 29.87748229, 27.88621124, 28.11622613, 26.3369738, 49.55454, 42.12503438, 41.96813093, 40.36943102, 41.97208403, 41.78295272, 40.87328962, 37.53836098, 37.0580762, 36.3181685, 35.00099651, 33.49444177, 32.97912, 31.54195411, 30.54263397, 32.4639633, 34.96423991, 35.30122987, 32.81051601, 34.2480093, 33.31852137, 30.54026938, 31.16023116, 28.22207761, 22.96722251, 43.56838471, 42.69352553, 42.46199624, 40.13577025, 43.60195097, 44.31867174, 49.78316782, 49.31508406, 42.83811659, 37.80317367, 33.73800017, 33.3105174, 33.22630913, 31.0087731, 30.40865036, 28.43881209, 27.36609083, 24.70344261, 26.52354799, 25.40327003, 26.17521882, 24.73857869, 26.30494308, 22.70128478, 22.09463252, 51.04502521, 51.51111157, 52.75284351, 54.81194369, 52.72699034, 54.75851856, 43.23767907, 43.70178295, 49.02252976, 47.24876375, 45.87483121, 43.85072076, 45.48505425, 43.38004215, 42.99786887, 48.64036596, 46.29534543, 40.66886396, 40.73416978, 36.69682239, 38.72599395, 42.01843505, 41.09368797, 33.38471226, 26.05468053, 36.52606302, 39.86827031, 40.82288701, 38.41130665, 35.46730729, 34.64407264, 35.37145682, 35.02176249, 36.58297963, 35.76037366, 35.72233032, 38.09322964, 42.6585412, 35.92893612, 36.47374756, 33.43948378, 34.04884608, 36.6796924, 32.92837796, 29.29840746, 30.12086854, 30.44677077, 28.0043309, 27.28218372, 24.79985495), .Dim = c(1000, 3), .Dimnames = list( c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", "270", "271", "272", "273", "274", "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285", "286", "287", "288", "289", "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362", "363", "364", "365", "366", "367", "368", "369", "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", "384", "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417", "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461", "462", "463", "464", "465", "466", "467", "468", "469", "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494", "495", "496", "497", "498", "499", "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", "510", "511", "512", "513", "514", "515", "516", "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527", "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571", "572", "573", "574", "575", "576", "577", "578", "579", "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604", "605", "606", "607", "608", "609", "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", "620", "621", "622", "623", "624", "625", "626", "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703", "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", "736", "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", "750", "751", "752", "753", "754", "755", "756", "757", "758", "759", "760", "761", "762", "763", "764", "765", "766", "767", "768", "769", "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", "780", "781", "782", "783", "784", "785", "786", "787", "788", "789", "790", "791", "792", "793", "794", "795", "796", "797", "798", "799", "800", "801", "802", "803", "804", "805", "806", "807", "808", "809", "810", "811", "812", "813", "814", "815", "816", "817", "818", "819", "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", "830", "831", "832", "833", "834", "835", "836", "837", "838", "839", "840", "841", "842", "843", "844", "845", "846", "847", "848", "849", "850", "851", "852", "853", "854", "855", "856", "857", "858", "859", "860", "861", "862", "863", "864", "865", "866", "867", "868", "869", "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", "890", "891", "892", "893", "894", "895", "896", "897", "898", "899", "900", "901", "902", "903", "904", "905", "906", "907", "908", "909", "910", "911", "912", "913", "914", "915", "916", "917", "918", "919", "920", "921", "922", "923", "924", "925", "926", "927", "928", "929", "930", "931", "932", "933", "934", "935", "936", "937", "938", "939", "940", "941", "942", "943", "944", "945", "946", "947", "948", "949", "950", "951", "952", "953", "954", "955", "956", "957", "958", "959", "960", "961", "962", "963", "964", "965", "966", "967", "968", "969", "970", "971", "972", "973", "974", "975", "976", "977", "978", "979", "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", "990", "991", "992", "993", "994", "995", "996", "997", "998", "999", "1000"), c("V1", "V2", "V3"))) partykit/R/extree.R0000644000176200001440000011076414230544657013764 0ustar liggesusers .select <- function(model, trafo, data, subset, weights, whichvar, ctrl, FUN) { ret <- list(criteria = matrix(NA, nrow = 2L, ncol = ncol(model.frame(data)))) rownames(ret$criteria) <- c("statistic", "p.value") colnames(ret$criteria) <- names(model.frame(data)) if (length(whichvar) == 0) return(ret) ### allow joint MC in the absense of missings; fix seeds ### write ctree_test / ... with whichvar and loop over variables there ### for (j in whichvar) { tst <- FUN(model = model, trafo = trafo, data = data, subset = subset, weights = weights, j = j, SPLITONLY = FALSE, ctrl = ctrl) ret$criteria["statistic",j] <- tst$statistic ret$criteria["p.value",j] <- tst$p.value } ret } .split <- function(model, trafo, data, subset, weights, whichvar, ctrl, FUN) { if (length(whichvar) == 0) return(NULL) for (j in whichvar) { x <- model.frame(data)[[j]] if (ctrl$multiway && is.factor(x) && !is.ordered(x) && (ctrl$maxsurrogate == 0) && nlevels(x[subset, drop = TRUE]) > 1) { index <- 1L:nlevels(x) xt <- libcoin::ctabs(ix = unclass(x), weights = weights, subset = subset)[-1] index[xt == 0] <- NA ### maybe multiway is not so smart here as ### nodes with nobs < minbucket could result index[xt > 0 & xt < ctrl$minbucket] <- nlevels(x) + 1L if (length(unique(index)) == 1) { ret <- NULL } else { index <- unclass(factor(index)) ret <- partysplit(as.integer(j), index = as.integer(index)) } } else { ret <- FUN(model = model, trafo = trafo, data = data, subset = subset, weights = weights, j = j, SPLITONLY = TRUE, ctrl = ctrl) } ### check if trafo can be successfully applied to all daugther nodes ### (converged = TRUE) if (ctrl$lookahead & !is.null(ret)) { sp <- kidids_split(ret, model.frame(data), obs = subset) conv <- sapply(unique(na.omit(sp)), function(i) isTRUE(trafo(subset[sp == i & !is.na(sp)], weights = weights)$converged)) if (!all(conv)) ret <- NULL } if (!is.null(ret)) break() } return(ret) } .objfun_select <- function(...) function(model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .objfun_test) } .objfun_split <- function(...) function(model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .objfun_test) } ### which.max(x) gives first max in case of ties ### order(x) puts length(x) last. This lead to confusion ### regarding the selected p-value and split variable .which.max <- function(x) { x[!is.finite(x)] <- -Inf order(x)[length(x)] } ### unbiased recursive partitioning: set up new node .extree_node <- function ( id = 1L, ### id of this node data, ### full data, readonly trafo, selectfun, ### variable selection splitfun, ### split selection svselectfun, ### same for surrogate splits svsplitfun, ### same for surrogate splits partyvars, ### partytioning variables ### a subset of 1:ncol(model.frame(data)) weights = integer(0L), ### optional case weights subset, ### subset of 1:nrow(data) ### for identifying obs for this node ctrl, ### extree_control() info = NULL, cenv = NULL ### environment for depth and maxid ) { ### depth keeps track of the depth of the tree ### which has to be < than maxdepth ### maxit is the largest id in the left subtree if (is.null(cenv)) { cenv <- new.env() assign("depth", 0L, envir = cenv) assign("splitvars", rep(0L, length(partyvars)), envir = cenv) } depth <- get("depth", envir = cenv) assign("maxid", id, envir = cenv) if (depth >= ctrl$maxdepth) return(partynode(as.integer(id))) ### check for stumps if (id > 1L && ctrl$stump) return(partynode(as.integer(id))) ### sw is basically the number of observations ### which has to be > minsplit in order to consider ### the node for splitting if (length(weights) > 0L) { if (ctrl$caseweights) { sw <- sum(weights[subset]) } else { sw <- sum(weights[subset] > 0L) } } else { sw <- length(subset) } if (sw < ctrl$minsplit) return(partynode(as.integer(id))) ### split variables used so far splitvars <- get("splitvars", envir = cenv) if (sum(splitvars) < ctrl$maxvar) { ### all variables subject to splitting svars <- which(partyvars > 0) } else { ### only those already used for splitting in other nodes are ### eligible svars <- which(partyvars > 0 & splitvars > 0) } if (ctrl$mtry < Inf) { mtry <- min(length(svars), ctrl$mtry) svars <- .resample(svars, mtry, prob = partyvars[svars]) } thismodel <- trafo(subset = subset, weights = weights, info = info, estfun = TRUE, object = TRUE) if (is.null(thismodel)) return(partynode(as.integer(id))) ### update sample size constraints on possible splits ### need to do this here because selectfun might consider splits mb <- ctrl$minbucket mp <- ctrl$minprob swp <- ceiling(sw * mp) if (mb < swp) mb <- as.integer(swp) thisctrl <- ctrl thisctrl$minbucket <- mb ### compute test statistics and p-values ### for _unbiased_ variable selection sf <- selectfun(model = thismodel, trafo = trafo, data = data, subset = subset, weights = weights, whichvar = svars, ctrl = thisctrl) if (inherits(sf, "partysplit")) { thissplit <- sf info <- nodeinfo <- thismodel[!(names(thismodel) %in% c("estfun"))] info$nobs <- sw if (!ctrl$saveinfo) info <- NULL } else { if (ctrl$bonferroni) ### make sure to correct for _non-constant_ variables only sf$criteria["p.value",] <- sf$criteria["p.value",] * sum(!is.na(sf$criteria["p.value",])) ### selectfun might return other things later to be used for info p <- sf$criteria crit <- p[ctrl$criterion,,drop = TRUE] if (all(is.na(crit))) return(partynode(as.integer(id))) crit[is.na(crit)] <- -Inf ### crit is maximised, but there might be ties ties <- which(abs(crit - max(crit, na.rm = TRUE)) < sqrt(.Machine$double.xmin)) if (length(ties) > 1) { ### add a small value (< 1/1000) to crit derived from rank of ### teststat crit[ties] <- crit[ties] + rank(p["statistic", ties]) / (sum(ties) * 1000) } ### switch from log(1 - pval) to pval for info slots ### switch from log(statistic) to statistic ### criterion stays on log scale to replicate variable selection p <- rbind(p, criterion = crit) p["statistic",] <- exp(p["statistic",]) p["p.value",] <- -expm1(p["p.value",]) pmin <- p["p.value", .which.max(crit)] names(pmin) <- colnames(model.frame(data))[.which.max(crit)] ### report on tests actually performed only p <- p[,!is.na(p["statistic",]) & is.finite(p["statistic",]), drop = FALSE] info <- nodeinfo <- c(list(criterion = p, p.value = pmin), sf[!(names(sf) %in% c("criteria", "converged"))], thismodel[!(names(thismodel) %in% c("estfun"))]) info$nobs <- sw if (!ctrl$saveinfo) info <- NULL ### nothing "significant" if (all(crit <= ctrl$logmincriterion)) return(partynode(as.integer(id), info = info)) ### at most ctrl$splittry variables with meaningful criterion st <- pmin(sum(is.finite(crit)), ctrl$splittry) jsel <- rev(order(crit))[1:st] jsel <- jsel[crit[jsel] > ctrl$logmincriterion] if (!is.null(sf$splits)) { ### selectfun may return of a list of partysplit objects; use these for ### splitting; selectfun is responsible for making sure lookahead is implemented thissplit <- sf$splits[[jsel[1]]] } else { ### try to find an admissible split in data[, jsel] thissplit <- splitfun(model = thismodel, trafo = trafo, data = data, subset = subset, weights = weights, whichvar = jsel, ctrl = thisctrl) } } ### failed split search: if (is.null(thissplit)) return(partynode(as.integer(id), info = info)) ### successful split search: set-up node ret <- partynode(as.integer(id)) ret$split <- thissplit ret$info <- info splitvars[thissplit$varid] <- 1L assign("splitvars", splitvars, cenv) ### determine observations for splitting (only non-missings) snotNA <- subset[!subset %in% data[[varid_split(thissplit), type = "missings"]]] if (length(snotNA) == 0) return(partynode(as.integer(id), info = info)) ### and split observations kidids <- kidids_node(ret, model.frame(data), obs = snotNA) ### compute probability of going left / right prob <- tabulate(kidids) / length(kidids) # names(dimnames(prob)) <- NULL if (ctrl$majority) ### go with majority prob <- as.double((1L:length(prob)) %in% .which.max(prob)) if (is.null(ret$split$prob)) ret$split$prob <- prob ### compute surrogate splits if (ctrl$maxsurrogate > 0L) { pv <- partyvars pv[varid_split(thissplit)] <- 0 pv <- which(pv > 0) if (ctrl$numsurrogate) pv <- pv[sapply(model.frame(data)[, pv], function(x) is.numeric(x) || is.ordered(x))] ret$surrogates <- .extree_surrogates(kidids, data = data, weights = weights, subset = snotNA, whichvar = pv, selectfun = svselectfun, splitfun = svsplitfun, ctrl = ctrl) } kidids <- kidids_node(ret, model.frame(data), obs = subset) ### proceed recursively kids <- vector(mode = "list", length = max(kidids)) nextid <- id + 1L for (k in 1L:max(kidids)) { nextsubset <- subset[kidids == k] assign("depth", depth + 1L, envir = cenv) kids[[k]] <- .extree_node(id = nextid, data = data, trafo = trafo, selectfun = selectfun, splitfun = splitfun, svselectfun = svselectfun, svsplitfun = svsplitfun, partyvars = partyvars, weights = weights, subset = nextsubset, ctrl = ctrl, info = nodeinfo, cenv = cenv) ### was: nextid <- max(nodeids(kids[[k]])) + 1L nextid <- get("maxid", envir = cenv) + 1L } ret$kids <- kids return(ret) } ### unbiased recursive partitioning: surrogate splits .extree_surrogates <- function ( split, ### integer vector with primary kidids data, ### full data, readonly weights, subset, ### subset of 1:nrow(data) with ### non-missings in primary split whichvar, ### partytioning variables selectfun, ### variable selection and split ### function splitfun, ctrl ### ctree_control() ) { if (length(whichvar) == 0) return(NULL) ms <- max(split) if (ms != 2) return(NULL) ### ie no multiway splits! dm <- matrix(0, nrow = nrow(model.frame(data)), ncol = ms) dm[cbind(subset, split)] <- 1 thismodel <- list(estfun = dm) sf <- selectfun(model = thismodel, trafo = NULL, data = data, subset = subset, weights = weights, whichvar = whichvar, ctrl = ctrl) p <- sf$criteria ### partykit always used p-values, so expect some differences crit <- p[ctrl$criterion,,drop = TRUE] ### crit is maximised, but there might be ties ties <- which(abs(crit - max(crit, na.rm = TRUE)) < .Machine$double.eps) if (length(ties) > 1) { ### add a small value (< 1/1000) to crit derived from order of ### teststat crit[ties] <- crit[ties] + order(p["statistic", ties]) / (sum(ties) * 1000) } ret <- vector(mode = "list", length = min(c(length(whichvar), ctrl$maxsurrogate))) for (i in 1L:length(ret)) { jsel <- .which.max(crit) thisctrl <- ctrl thisctrl$minbucket <- 0L sp <- splitfun(model = thismodel, trafo = NULL, data = data, subset = subset, weights = weights, whichvar = jsel, ctrl = ctrl) if (is.null(sp)) next ret[[i]] <- sp tmp <- kidids_split(ret[[i]], model.frame(data), obs = subset) ### this needs fixing for multiway "split" tab <- table(tmp, split) if (tab[1, 1] < tab[1, 2]) { indx <- ret[[i]]$index ret[[i]]$index[indx == 1] <- 2L ret[[i]]$index[indx == 2] <- 1L } ### crit[.which.max(crit)] <- -Inf } ret <- ret[!sapply(ret, is.null)] if (length(ret) == 0L) ret <- NULL return(ret) } extree_fit <- function(data, trafo, converged, selectfun = ctrl$selectfun, splitfun = ctrl$splitfun, svselectfun = ctrl$svselectfun, svsplitfun = ctrl$svsplitfun, partyvars, subset, weights, ctrl, doFit = TRUE) { ret <- list() ### use data$vars$z as default for partyvars ### try to avoid doFit nf <- names(formals(trafo)) if (all(c("subset", "weights", "info", "estfun", "object") %in% nf)) { mytrafo <- trafo } else { stopifnot(all(c("y", "x", "offset", "weights", "start") %in% nf)) stopifnot(!is.null(yx <- data$yx)) mytrafo <- function(subset, weights, info, estfun = FALSE, object = FALSE, ...) { iy <- data[["yx", type = "index"]] if (is.null(iy)) { NAyx <- data[["yx", type = "missing"]] y <- yx$y x <- yx$x offset <- attr(yx$x, "offset") ### other ways of handling NAs necessary? subset <- subset[!(subset %in% NAyx)] if (NCOL(y) > 1) { y <- y[subset,,drop = FALSE] } else { y <- y[subset] } if (!is.null(x)) { ax <- attributes(x) ax$dim <- NULL ax$dimnames <- NULL x <- x[subset,,drop = FALSE] for (a in names(ax)) attr(x, a) <- ax[[a]] ### terms, formula, ... for predict } w <- weights[subset] offset <- offset[subset] cluster <- data[["(cluster)"]][subset] if (all(c("estfun", "object") %in% nf)) { m <- trafo(y = y, x = x, offset = offset, weights = w, start = info$coef, cluster = cluster, estfun = estfun, object = object, ...) } else { obj <- trafo(y = y, x = x, offset = offset, weights = w, start = info$coef, cluster = cluster, ...) m <- list(coefficients = coef(obj), objfun = -as.numeric(logLik(obj)), estfun = NULL, object = NULL) if (estfun) m$estfun <- sandwich::estfun(obj) if (object) m$object <- obj } if (!is.null(ef <- m$estfun)) { ### ctree expects unweighted scores if (!isTRUE(m$unweighted) && is.null(selectfun) && ctrl$testflavour == "ctree") m$estfun <- m$estfun / w Y <- matrix(0, nrow = nrow(model.frame(data)), ncol = ncol(ef)) Y[subset,] <- m$estfun m$estfun <- Y } } else { w <- libcoin::ctabs(ix = iy, subset = subset, weights = weights)[-1] offset <- attr(yx$x, "offset") cluster <- model.frame(data, yxonly = TRUE)[["(cluster)"]] if (all(c("estfun", "object") %in% nf)) { m <- trafo(y = yx$y, x = yx$x, offset = offset, weights = w, start = info$coef, cluster = cluster, estfun = estfun, object = object, ...) } else { obj <- trafo(y = yx$y, x = yx$x, offset = offset, weights = w, start = info$coef, cluster = cluster, ...) m <- list(coefficients = coef(obj), objfun = -as.numeric(logLik(obj)), estfun = NULL, object = NULL) if (estfun) m$estfun <- sandwich::estfun(obj) if (object) m$object <- obj if (!is.null(obj$unweighted)) m$unweighted <- obj$unweighted m$converged <- obj$converged ### may or may not exist } ### unweight scores in ctree or weight scores in ### mfluc (means: for each variable again) ### ctree expects unweighted scores if (!is.null(m$estfun)) { if (!isTRUE(m$unweighted) && is.null(selectfun) && ctrl$testflavour == "ctree") m$estfun <- m$estfun / w } if (!is.null(ef <- m$estfun)) m$estfun <- rbind(0, ef) } return(m) } } if (!ctrl$update) { rootestfun <- mytrafo(subset = subset, weights = weights) updatetrafo <- function(subset, weights, info, ...) return(rootestfun) } else { updatetrafo <- function(subset, weights, info, ...) { ret <- mytrafo(subset = subset, weights = weights, info = info, ...) if (is.null(ret$converged)) ret$converged <- TRUE conv <- TRUE if (is.function(converged)) conv <- converged(subset, weights) ret$converged <- ret$converged && conv if (!ret$converged) return(NULL) ret } } nm <- c("model", "trafo", "data", "subset", "weights", "whichvar", "ctrl") stopifnot(all(nm == names(formals(selectfun)))) stopifnot(all(nm == names(formals(splitfun)))) stopifnot(all(nm == names(formals(svselectfun)))) stopifnot(all(nm == names(formals(svsplitfun)))) if (!doFit) return(mytrafo) list(nodes = .extree_node(id = 1, data = data, trafo = updatetrafo, selectfun = selectfun, splitfun = splitfun, svselectfun = svselectfun, svsplitfun = svsplitfun, partyvars = partyvars, weights = weights, subset = subset, ctrl = ctrl), trafo = mytrafo) } ## extensible tree (model) function extree_data <- function(formula, data, subset, na.action = na.pass, weights, offset, cluster, strata, scores = NULL, yx = c("none", "matrix"), ytype = c("vector", "data.frame", "matrix"), nmax = c("yx" = Inf, "z" = Inf), ...) { ## call cl <- match.call() yx <- match.arg(yx, choices = c("none", "matrix")) ytype <- match.arg(ytype, choices = c("vector", "data.frame", "matrix")) ## 'formula' may either be a (multi-part) formula or a list noformula <- !inherits(formula, "formula") if(noformula) { ## formula needs to be a 'list' (if it is not a 'formula') if(!inherits(formula, "list")) stop("unsupported specification of 'formula'") ## specified formula elements and overall call elements fonam <- names(formula) clnam <- names(cl)[-1L] vanam <- c("y", "x", "z", "weights", "offset", "cluster", "strata") ## y and z (and optionally x) need to be in formula if(!all(c("y", "z") %in% fonam)) stop("'formula' needs to specify at least a response 'y' and partitioning variables 'z'") if(!("x" %in% fonam)) formula$x <- NULL ## furthermore weights/offset/cluster/strata may be in formula or call vars <- formula[vanam] names(vars) <- vanam if("weights" %in% clnam) { clvar <- try(weights, silent = TRUE) vars[["weights"]] <- c(vars[["weights"]], if(!inherits(clvar, "try-error")) clvar else deparse(cl$weights)) } if("offset" %in% clnam) { clvar <- try(offset, silent = TRUE) vars[["offset"]] <- c(vars[["offset"]], if(!inherits(clvar, "try-error")) clvar else deparse(cl$offset)) } if("cluster" %in% clnam) { clvar <- try(cluster, silent = TRUE) vars[["cluster"]] <- c(vars[["cluster"]], if(!inherits(clvar, "try-error")) clvar else deparse(cl$cluster)) } if("strata" %in% clnam) { clvar <- try(strata, silent = TRUE) vars[["strata"]] <- c(vars[["strata"]], if(!inherits(clvar, "try-error")) clvar else deparse(cl$strata)) } ## sanity checking for(v in vanam) { if(!is.null(vars[[v]]) && !(is.numeric(vars[[v]]) | is.character(vars[[v]]) | is.logical(vars[[v]]))) { warning(sprintf("unknown specification of '%s', must be character, numeric, or logical", v)) vars[v] <- list(NULL) } } if(!missing(subset)) warning("'subset' argument ignored in list specification of 'formula'") if(!missing(na.action)) warning("'na.action' argument ignored in list specification of 'formula'") ## no terms (by default) mt <- NULL } else { ## set up model.frame() call mf <- match.call(expand.dots = FALSE) mf$na.action <- na.action ### evaluate na.action if(missing(data)) data <- environment(formula) m <- match(c("formula", "data", "subset", "na.action", "weights", "offset", "cluster", "strata"), names(mf), 0L) mf <- mf[c(1L, m)] mf$drop.unused.levels <- TRUE mf$dot <- "sequential" ## formula processing oformula <- as.formula(formula) formula <- Formula::as.Formula(formula) mf$formula <- formula npart <- length(formula) if(any(npart < 1L)) stop("'formula' must specify at least one left-hand and one right-hand side") npart <- npart[2L] ## evaluate model.frame mf[[1L]] <- quote(stats::model.frame) mf <- eval(mf, parent.frame()) ## extract terms in various combinations mt <- list( "all" = terms(formula, data = data, dot = "sequential"), "y" = terms(formula, data = data, rhs = 0L, dot = "sequential"), "z" = terms(formula, data = data, lhs = 0L, rhs = npart, dot = "sequential") ) if(npart > 1L) { mt$yx <-terms(formula, data = data, rhs = 1L, dot = "sequential") for(i in 1L:(npart-1L)) { mt[[paste("x", if(i == 1L) "" else i, sep = "")]] <- terms( formula, data = data, lhs = 0L, rhs = i, dot = "sequential") } } ## extract variable lists vars <- list( y = .get_term_labels(mt$y), x = unique(unlist(lapply(grep("^x", names(mt)), function(i) .get_term_labels(mt[[i]])))), z = .get_term_labels(mt$z), weights = if("(weights)" %in% names(mf)) "(weights)" else NULL, offset = if("(offset)" %in% names(mf)) "(offset)" else NULL, cluster = if("(cluster)" %in% names(mf)) "(cluster)" else NULL, strata = if("(strata)" %in% names(mf)) "(strata)" else NULL ) ymult <- length(vars$y) >= 1L if(!ymult) vars$y <- names(mf)[1L] ## FIXME: store information which variable(s) went into (weights), (offset), (cluster) ## (strata) ## idea: check (x and) z vs. deparse(cl$weights), deparse(cl$offset), deparse(cl$cluster) ## check wether offset was inside the formula if(!is.null(off <- attr(mt$x, "offset"))) { if(is.null(vars$offset)) mf[["(offset)"]] <- rep.int(0, nrow(mf)) for(i in off) mf[["(offset)"]] <- mf[["(offset)"]] + mf[[i]] vars$offset <- "(offset)" } } ## canonicalize y/x/z term labels vanam <- if(noformula) names(data) else names(mf) ## z to numeric if(is.null(vars$z)) stop("at least one 'z' variable must be specified") if(is.integer(vars$z)) vars$z <- vanam[vars$z] if(is.character(vars$z)) vars$z <- vanam %in% vars$z if(is.logical(vars$z)) vars$z <- as.numeric(vars$z) if(is.null(names(vars$z))) names(vars$z) <- vanam vars$z <- vars$z[vanam] if(any(is.na(vars$z))) vars$z[is.na(vars$z)] <- 0 vars$z <- as.numeric(vars$z) ## all others to integer for(v in c("y", "x", "weights", "offset", "cluster", "strata")) { if(!is.null(vars[[v]])) { if(is.character(vars[[v]])) vars[[v]] <- match(vars[[v]], vanam) if(is.logical(vars[[v]])) vars[[v]] <- which(vars[[v]]) if(any(is.na(vars[[v]]))) { vars[[v]] <- vars[[v]][!is.na(vars[[v]])] warning(sprintf("only found the '%s' variables: %s", v, paste(vanam[vars[[v]]], collapse = ", "))) } } vars[[v]] <- unique(as.integer(vars[[v]])) } if(is.null(vars$y)) stop("at least one 'y' variable must be specified") ## FIXME: subsequently fitting, testing, splitting ## - fit: either pre-processed _and_ subsetted data --or-- full data object plus subset vector ## - test: additionally needs fit output --and-- fit function ## - split: additionally needs test output ## - tbd: control of all details ret <- list( data = if(noformula) data else mf, variables = vars, terms = mt ) mf <- ret$data yxvars <- c(vars$y, vars$x, vars$offset, vars$cluster) zerozvars <- which(vars$z == 0) ret$scores <- vector(mode = "list", length = length(ret$variables$z)) names(ret$scores) <- names(mf) if (!is.null(scores)) ret$scores[names(scores)] <- scores if (length(nmax) == 1) nmax <- c("yx" = nmax, "z" = nmax) ### make meanlevels an argument and make sure intersplit is TRUE ret$zindex <- inum::inum(mf, ignore = names(mf)[zerozvars], total = FALSE, nmax = nmax["z"], meanlevels = FALSE) if (is.finite(nmax["yx"])) { ret$yxindex <- inum::inum(mf[, yxvars, drop = FALSE], total = TRUE, as.interval = names(mf)[vars$y], complete.cases.only = TRUE, nmax = nmax["yx"], meanlevels = FALSE) yxmf <- attr(ret$yxindex, "levels") yxmf[["(weights)"]] <- NULL attr(ret$yxindex, "levels") <- yxmf } else { ret$yxindex <- NULL yxmf <- mf } ret$missings <- lapply(ret$data, function(x) which(is.na(x))) ret$yxmissings <- sort(unique(do.call("c", ret$missings[yxvars]))) ## FIXME: separate object with options for: discretization, condensation, some NA handling ## below is just "proof-of-concept" implementation using plain model.matrix() which could ## be included as one option... if (yx == "matrix") { ## fake formula/terms if necessary formula <- Formula::as.Formula(sprintf("%s ~ %s | %s", paste(vanam[vars$y], collapse = " + "), if(length(vars$x) > 0L) paste(vanam[vars$x], collapse = " + ") else "0", paste(vanam[vars$z > 0], collapse = " + ") )) mt <- list( "all" = terms(formula), "y" = terms(formula, data = data, rhs = 0L), "z" = terms(formula, data = data, lhs = 0L, rhs = 2L), "yx" = terms(formula, data = data, rhs = 1L), "x" = terms(formula, data = data, lhs = 0L, rhs = 1L) ) ymult <- length(vars$y) > 1L npart <- 2L if (ytype == "vector" && !ymult) { yx <- list("y" = yxmf[, vanam[vars$y], drop = TRUE]) } else if (ytype == "data.frame") { yx <- list("y" = yxmf[vanam[vars$y]]) } else { ### ytype = "matrix" Ytmp <- model.matrix(~ 0 + ., Formula::model.part(formula, yxmf, lhs = TRUE)) ### are there cases where Ytmp already has missings? if (is.finite(nmax["yx"])) { Ymat <- Ytmp } else { if (length(ret$yxmissings) == 0) { Ymat <- Ytmp } else { Ymat <- matrix(0, nrow = NROW(yxmf), ncol = NCOL(Ytmp)) Ymat[-ret$yxmissings,] <- Ytmp } } yx <- list("y" = Ymat) } for(i in (1L:npart)[-npart]) { ni <- paste("x", if(i == 1L) "" else i, sep = "") ti <- if(!ymult & npart == 2L) mt$yx else mt[[ni]] Xtmp <- model.matrix(ti, yxmf) if (is.finite(nmax["yx"])) { Xmat <- Xtmp } else { if (length(ret$yxmissings) == 0) { Xmat <- Xtmp } else { Xmat <- matrix(0, nrow = NROW(yxmf), ncol = NCOL(Xtmp)) Xmat[-ret$yxmissings,] <- Xtmp } } yx[[ni]] <- Xmat if(ncol(yx[[ni]]) < 1L) { yx[[ni]] <- NULL } else { attr(yx[[ni]], "formula") <- formula(formula, rhs = i) attr(yx[[ni]], "terms") <- ti attr(yx[[ni]], "offset") <- yxmf[["(offset)"]] } } ret$yx <- yx } class(ret) <- "extree_data" ret } model.frame.extree_data <- function(formula, yxonly = FALSE, ...) { if (!yxonly) return(formula$data) if (!is.null(formula$yxindex)) return(attr(formula$yxindex, "levels")) vars <- formula$variables return(formula$data[, c(vars$y, vars$x, vars$offset, vars$cluster),drop = FALSE]) } ## for handling of non-standard variable names within extree_data() by mimicking ## handling of such variables in model.frame() etc. in "stats" prompted by ## https://stackoverflow.com/questions/64660889/ctree-ignores-variables-with-non-syntactic-names .deparse_variables <- function(x) paste(deparse(x, width.cutoff = 500L, backtick = !is.symbol(x) && is.language(x)), collapse = " ") .get_term_labels <- function(terms, delete_response = FALSE) { ## ## with just standard variable names one could use: ## attr(terms, "term.labels") ## delete response from terms (if needed) if(delete_response) terms <- delete.response(terms) ## with non-standard variable names -> deparse to handle `...` correctly vapply(attr(terms, "variables"), .deparse_variables, " ")[-1L] } ### document how to extract slots fast "[[.extree_data" <- function(x, i, type = c("original", "index", "scores", "missings")) { type <- match.arg(type, choices = c("original", "index", "scores", "missings")) switch(type, "original" = { if (i == "yx") return(model.frame(x, yxonly = TRUE)) mf <- model.frame(x) ### [[.data.frame needs lots of memory class(mf) <- "list" return(mf[[i]]) }, "index" = { if (i == "yx" || i %in% c(x$variables$y, x$variables$x)) return(x$yxindex) ### may be NULL return(x$zindex[[i]]) }, "scores" = { f <- x[[i]] if (is.ordered(f)) { sc <- x$scores[[i]] if (is.null(sc)) sc <- 1:nlevels(f) return(sc) } return(NULL) }, "missings" = { if (i == "yx" || i %in% c(x$variables$y, x$variables$x)) return(x$yxmissings) x$missings[[i]] } ) } ### control arguments needed in this file extree_control <- function ( criterion, logmincriterion, minsplit = 20L, minbucket = 7L, minprob = 0.01, nmax = Inf, maxvar = Inf, stump = FALSE, lookahead = FALSE, ### try trafo() for daugther nodes before implementing the split maxsurrogate = 0L, numsurrogate = FALSE, mtry = Inf, maxdepth = Inf, multiway = FALSE, splittry = 2L, majority = FALSE, caseweights = TRUE, applyfun = NULL, cores = NULL, saveinfo = TRUE, bonferroni = FALSE, update = NULL, selectfun, splitfun, svselectfun, svsplitfun ) { ## apply infrastructure for determining split points if (is.null(applyfun)) { applyfun <- if(is.null(cores)) { lapply } else { function(X, FUN, ...) parallel::mclapply(X, FUN, ..., mc.cores = cores) } } ### well, it is implemented but not correctly so if (multiway & maxsurrogate > 0L) stop("surrogate splits currently not implemented for multiway splits") list(criterion = criterion, logmincriterion = logmincriterion, minsplit = minsplit, minbucket = minbucket, minprob = minprob, maxvar = max(c(1, maxvar)), stump = stump, nmax = nmax, lookahead = lookahead, mtry = mtry, maxdepth = maxdepth, multiway = multiway, splittry = splittry, maxsurrogate = maxsurrogate, numsurrogate = numsurrogate, majority = majority, caseweights = caseweights, applyfun = applyfun, saveinfo = saveinfo, bonferroni = bonferroni, update = update, selectfun = selectfun, splitfun = splitfun, svselectfun = svselectfun, svsplitfun = svsplitfun) } .objfun_test <- function(model, trafo, data, subset, weights, j, SPLITONLY, ctrl) { x <- data[[j]] NAs <- data[[j, type = "missing"]] if (all(subset %in% NAs)) { if (SPLITONLY) return(NULL) return(list(statistic = NA, p.value = NA)) } ix <- data[[j, type = "index"]] ux <- attr(ix, "levels") ixtab <- libcoin::ctabs(ix = ix, weights = weights, subset = subset)[-1] ORDERED <- is.ordered(x) || is.numeric(x) linfo <- rinfo <- model minlogLik <- nosplitll <- trafo(subset = subset, weights = weights, info = model, estfun = FALSE)$objfun sp <- NULL if (ORDERED) { ll <- ctrl$applyfun(which(ixtab > 0), function(u) { sleft <- subset[LEFT <- (ix[subset] <= u)] sright <- subset[!LEFT] if (length(weights) > 0 && ctrl$caseweights) { if (sum(weights[sleft]) < ctrl$minbucket || sum(weights[sright]) < ctrl$minbucket) return(Inf); } else { if (length(sleft) < ctrl$minbucket || length(sright) < ctrl$minbucket) return(Inf); } if (ctrl$restart) { linfo <- NULL rinfo <- NULL } linfo <- trafo(subset = sleft, weights = weights, info = linfo, estfun = FALSE) rinfo <- trafo(subset = sright, weights = weights, info = rinfo, estfun = FALSE) ll <- linfo$objfun + rinfo$objfun return(ll) }) minlogLik <- min(unlist(ll)) if(minlogLik < nosplitll) sp <- which(ixtab > 0)[which.min(unlist(ll))] } else { xsubs <- factor(x[subset]) ## stop if only one level left if(nlevels(xsubs) < 2) { if (SPLITONLY) { return(NULL) } else { return(list(statistic = NA, p.value = NA)) } } splits <- .mob_grow_getlevels(xsubs) ll <- ctrl$applyfun(1:nrow(splits), function(u) { sleft <- subset[LEFT <- xsubs %in% levels(xsubs)[splits[u,]]] sright <- subset[!LEFT] if (length(weights) > 0 && ctrl$caseweights) { if (sum(weights[sleft]) < ctrl$minbucket || sum(weights[sright]) < ctrl$minbucket) return(Inf); } else { if (length(sleft) < ctrl$minbucket || length(sright) < ctrl$minbucket) return(Inf); } if (ctrl$restart) { linfo <- NULL rinfo <- NULL } linfo <- trafo(subset = sleft, weights = weights, info = linfo, estfun = FALSE) rinfo <- trafo(subset = sright, weights = weights, info = rinfo, estfun = FALSE) ll <- linfo$objfun + rinfo$objfun return(ll) }) minlogLik <- min(unlist(ll)) if(minlogLik < nosplitll) { sp <- splits[which.min(unlist(ll)),] + 1L levs <- levels(x) if(length(sp) != length(levs)) { sp <- sp[levs] names(sp) <- levs } } } if (!SPLITONLY){ ## split only if logLik improves due to splitting minlogLik <- ifelse(minlogLik == nosplitll, NA, minlogLik) return(list(statistic = -minlogLik, p.value = NA)) ### .extree_node maximises } if (is.null(sp) || all(is.na(sp))) return(NULL) if (ORDERED) { ### interpolate split-points, see https://arxiv.org/abs/1611.04561 if (!is.factor(x) & ctrl$intersplit & sp < length(ux)) { sp <- (ux[sp] + ux[sp + 1]) / 2 } else { sp <- ux[sp] ### x <= sp vs. x > sp } if (is.factor(sp)) sp <- as.integer(sp) ret <- partysplit(as.integer(j), breaks = sp, index = 1L:2L) } else { ret <- partysplit(as.integer(j), index = as.integer(sp)) } return(ret) } .start_subset <- function(data) { ret <- 1:NROW(model.frame(data)) if (length(data$yxmissings) > 0) ret <- ret[!(ret %in% data$yxmissings)] ret } partykit/R/pmmlTreeModel.R0000644000176200001440000002623114172230000015204 0ustar liggesuserspmmlTreeModel <- function(file, ...) { stopifnot(requireNamespace("XML")) as.party(XML::xmlRoot(XML::xmlTreeParse(file))) } as.party.XMLNode <- function(obj, ...) { stopifnot(requireNamespace("XML")) ## check whether XML specifies a TreeModel stopifnot(c("DataDictionary", "TreeModel") %in% names(obj)) if(any(warnx <- c("MiningBuildTask", "TransformationDictionary", "Extension") %in% names(obj))) warning(sprintf("%s not yet implemented", paste(names(obj)[warnx], collapse = ", "))) ## process header information if("Header" %in% names(obj)) { hdr <- obj[["Header"]] h_info <- c(Header = paste(as.character(XML::xmlAttrs(hdr)), collapse = ", ")) if(length(hdr) > 0L) { h_info <- c(h_info, XML::xmlSApply(hdr, function(x) paste(c(as.character(XML::xmlAttrs(x)), XML::xmlValue(x)), collapse = ", ") ) ) } } else { h_info <- NULL } ## parse data dictionary extract_empty_model_frame <- function(x) { ## extract DataDictionary dd <- x[["DataDictionary"]] ## currently we can only look at DataField if(!all(names(dd) == "DataField")) warning("data specifications other than DataField are not yet implemented") ## check columns nc <- as.numeric(XML::xmlAttrs(dd)["numberOfFields"]) if(!is.na(nc)) stopifnot(nc == length(dd)) ## set up data frame (only numeric variables) mf <- as.data.frame(rep(list(1), nc))[0,] names(mf) <- XML::xmlSApply(dd, function(x) XML::xmlAttrs(x)["name"]) ## modify class if necessary for(i in 1:nc) { optype <- XML::xmlAttrs(dd[[i]])["optype"] switch(optype, "categorical" = { mf[[i]] <- factor(integer(0), levels = XML::xmlSApply(dd[[i]], function(x) gsub("&", "&", XML::xmlAttrs(x)["value"], fixed = TRUE))) }, "ordinal" = { mf[[i]] <- factor(integer(0), ordered = TRUE, levels = XML::xmlSApply(dd[[i]], function(x) gsub("&", "&", XML::xmlAttrs(x)["value"], fixed = TRUE))) }, "continuous" = { dataType <- XML::xmlAttrs(dd[[i]])["dataType"] if(dataType == "integer") mf[[i]] <- integer(0) } ) } return(mf) } mf <- extract_empty_model_frame(obj) mf_names <- names(mf) mf_levels <- lapply(mf, levels) ## parse MiningSchema extract_terms <- function(x) { ## extract MiningSchema ms <- x[["TreeModel"]] stopifnot("MiningSchema" %in% names(ms)) ms <- ms[["MiningSchema"]] ## currently we can only look at MiningField if(!all(names(ms) == "MiningField")) warning("MiningField not yet implemented") ## extract variable info vars <- t(XML::xmlSApply(ms, XML::xmlAttrs)) if(sum(vars[,2] == "predicted") > 1) stop("multivariate responses not yet implemented") if(!all(vars[,2] %in% c("predicted", "active", "supplementary"))) warning("not yet implemented") ## set up formula ff <- as.formula(paste(vars[vars[,2] == "predicted",1], "~", paste(vars[vars[,2] != "predicted",1], collapse = " + "))) return(terms(ff)) } trms <- extract_terms(obj) ## parse TreeModel tm <- obj[["TreeModel"]] tm_info <- c(XML::xmlAttrs(tm), h_info) ## check response stopifnot(tm_info["functionName"] %in% c("classification", "regression")) mf_response <- mf[[deparse(attr(trms, "variables")[[2L]])]] if(tm_info["functionName"] == "classification") stopifnot(inherits(mf_response, "factor")) if(tm_info["functionName"] == "regression") stopifnot(is.numeric(mf_response)) ## convenience functions for parsing nodes is_terminal <- function(xnode) !("Node" %in% names(xnode)) is_root <- function(xnode) "True" %in% names(xnode) n_kids <- function(xnode) sum("Node" == names(xnode)) n_obs <- function(xnode) as.numeric(XML::xmlAttrs(xnode)["recordCount"]) has_surrogates <- function(x) { ns <- sum(c("SimplePredicate", "SimpleSetPredicate", "CompoundPredicate") %in% names(x)) if(ns != 1) stop("invalid PMML") if("CompoundPredicate" %in% names(x)) { if(identical(as.vector(XML::xmlAttrs(x[["CompoundPredicate"]])["booleanOperator"]), "surrogate")) return(TRUE) else return(FALSE) } else { return(FALSE) } } has_single_splits <- function(x) { wi <- which(names(x) %in% c("SimplePredicate", "SimpleSetPredicate", "CompoundPredicate")) sapply(wi, function(i) { if(names(x)[i] %in% c("SimplePredicate", "SimpleSetPredicate")) return(TRUE) if(identical(as.vector(XML::xmlAttrs(x[[i]])["booleanOperator"]), "or")) return(TRUE) stop("CompoundPredicate not yet implemented") }) } n_splits <- function(xnode) { wi <- which("Node" == names(xnode)) rval <- unique(sapply(wi, function(i) { xnodei <- if(has_surrogates(xnode[[i]])) xnode[[i]][["CompoundPredicate"]] else xnode[[i]] rval <- has_single_splits(xnodei) if(!all(rval)) stop("invalid PMML") sum(rval) })) if(length(rval) > 1) stop("invalid PMML") return(rval) } kid_ids <- function(xnode) { wi <- which("Node" == names(xnode)) rval <- sapply(wi, function(j) { as.vector(XML::xmlAttrs(xnode[[j]])["id"]) }) } get_pred <- function(xnode) { pred <- as.vector(XML::xmlAttrs(xnode)["score"]) if(is.na(pred)) return(NULL) if(is.numeric(mf_response)) as.numeric(pred) else factor(pred, levels = levels(mf_response)) } get_dist <- function(xnode) { wi <- which("ScoreDistribution" == names(xnode)) if(length(wi) < 1) return(NULL) rval <- sapply(wi, function(i) as.numeric(XML::xmlAttrs(xnode[[i]])["recordCount"])) names(rval) <- sapply(wi, function(i) XML::xmlAttrs(xnode[[i]])["value"]) if(inherits(mf_response, "factor")) rval <- rval[levels(mf_response)] return(rval) } get_error <- function(xnode) { if(tm_info["functionName"] != "classification") return(NULL) tab <- get_dist(xnode) if(is.null(tab)) return(NULL) c("%" = sum(100 * prop.table(tab)[names(tab) != get_pred(xnode)])) } get_extension <- function(xnode) { if(!("Extension" %in% names(xnode))) return(NULL) if(length(xnode[["Extension"]]) > 1) warning("currently only one Extension allowed") rval <- XML::xmlApply(xnode[["Extension"]][[1]], XML::xmlAttrs) names(rval) <- NULL rval <- unlist(rval) to_numeric <- function(x) { y <- suppressWarnings(as.numeric(x)) if(!is.null(y) && !is.na(y)) y else x } sapply(rval, to_numeric) } node_info <- function(xnode) list(prediction = get_pred(xnode), n = n_obs(xnode), error = get_error(xnode), distribution = get_dist(xnode), extension = get_extension(xnode)) get_split_prob <- function(xnode) { rval <- rep(0, n_kids(xnode)) wi <- XML::xmlAttrs(xnode)["defaultChild"] if(is.na(wi)) rval <- NULL else rval[which(kid_ids(xnode) == wi)] <- 1 return(rval) } get_split <- function(xnode, i, surrogates) { wi <- which("Node" == names(xnode)) rval <- sapply(wi, function(j) { nj <- if(surrogates) xnode[[j]][["CompoundPredicate"]] else xnode[[j]] if(any(c("SimplePredicate", "SimpleSetPredicate") %in% names(nj))) { wii <- which(names(nj) %in% c("SimplePredicate", "SimpleSetPredicate"))[i] c("predicateType" = as.vector(names(nj)[wii]), XML::xmlAttrs(nj[[wii]])) } else { wii <- which(names(nj) == "CompoundPredicate")[i] nj <- nj[[wii]] if(!identical(as.vector(XML::xmlAttrs(nj)["booleanOperator"]), "or")) stop("not yet implemented") if(any(names(nj) %in% c("SimpleSetPredicate", "CompoundPredicate"))) stop("not yet implemented") rvali <- sapply(which(names(nj) == "SimplePredicate"), function(j) c("predicateType" = as.vector(names(nj)[j]), XML::xmlAttrs(nj[[j]]))) if(is.null(dim(rvali))) rvali <- matrix(rvali, ncol = 1) stopifnot(length(unique(rvali["predicateType",])) == 1) stopifnot(length(unique(rvali["field",])) == 1) stopifnot(all(rvali["operator",] == "equal")) c("predicateType" = "simpleSetPredicate", "field" = rvali["field", 1], "booleanOperator" = "isIn") } }) stopifnot(length(unique(rval["predicateType",])) == 1) stopifnot(length(unique(rval["field",])) == 1) if(rval["predicateType", 1] == "SimplePredicate") { stopifnot(length(unique(rval["value",])) == 1) if(ncol(rval) != 2) stop("not yet implemented") if(!(identical(as.vector(sort(rval["operator",])), c("greaterThan", "lessOrEqual")) | identical(as.vector(sort(rval["operator",])), c("greaterOrEqual", "lessThan"))) ) stop("not yet implemented") partysplit( varid = which(rval["field", 1] == mf_names), breaks = as.numeric(rval["value", 1]), index = if(substr(rval["operator", 1], 1, 1) != "l") 2:1 else NULL, right = "lessOrEqual" %in% rval["operator",], prob = if(i == 1) get_split_prob(xnode) else NULL ) } else { varid <- which(rval["field", 1] == mf_names) lev <- mf_levels[[varid]] stopifnot(length(lev) > 1) idx <- rep(NA, length(lev)) lab <- lapply(wi, function(j) { nj <- if(surrogates) xnode[[j]][["CompoundPredicate"]] else xnode[[j]] if(any(names(nj) %in% c("SimplePredicate", "SimpleSetPredicate"))) { wii <- which(names(nj) %in% c("SimplePredicate", "SimpleSetPredicate"))[i] ar <- nj[[wii]][["Array"]] stopifnot(XML::xmlAttrs(ar)["type"] == "string") rv <- XML::xmlValue(ar) rv <- gsub(""", "\"", rv, fixed = TRUE) rv <- if(substr(rv, 1, 1) == "\"" & substr(rv, nchar(rv), nchar(rv)) == "\"") { strsplit(substr(rv, 2, nchar(rv) - 1), "\" \"")[[1]] } else { strsplit(rv, " ")[[1]] } stopifnot(length(rv) == as.numeric(XML::xmlAttrs(ar)["n"])) return(rv) } else { wii <- which(names(nj) == "CompoundPredicate")[i] as.vector(XML::xmlSApply(nj[[wii]], function(z) XML::xmlAttrs(z)["value"])) } }) for(j in 1:ncol(rval)) { if(rval["booleanOperator",j] == "isIn") idx[which(lev %in% lab[[j]])] <- j else idx[which(!(lev %in% lab[[j]]))] <- j } stopifnot(all(na.omit(idx) > 0)) if(min(idx, na.rm = TRUE) != 1) stop(sprintf("variable levels (%s) and split labels (%s)", paste(lev, collapse = ", "), paste(sapply(lab, paste, collapse = ", "), collapse = " | "))) partysplit( varid = varid, breaks = NULL, index = as.integer(idx), prob = if(i == 1) get_split_prob(xnode) else NULL ) } } ## function for setting up nodes ## (using global index ii) pmml_node <- function(xnode) { ii <<- ii + 1 if(is_terminal(xnode)) return(partynode(as.integer(ii), info = node_info(xnode) )) wi <- which("Node" == names(xnode)) ns <- n_splits(xnode) nd <- partynode(as.integer(ii), split = get_split(xnode, 1, has_surrogates(xnode[[wi[1]]])), kids = lapply(wi, function(j) pmml_node(xnode[[j]])), surrogates = if(ns < 2) NULL else lapply(2:ns, function(j) get_split(xnode, j, TRUE)), info = node_info(xnode) ) nd } ## set up node ii <- 0 if(is_root(tm[["Node"]])) nd <- pmml_node(tm[["Node"]]) else stop("root node not declared, invalid PMML?") ## set up party ## FIXME: extend info slot? pt <- party(node = nd, data = mf, fitted = NULL, terms = trms, names = NULL, info = tm_info) class(pt) <- c("simpleparty", class(pt)) return(pt) } partykit/R/modelparty.R0000644000176200001440000012160514172230000014617 0ustar liggesusersmob <- function(formula, data, subset, na.action, weights, offset, cluster, fit, control = mob_control(), ...) { ## check fitting function fitargs <- names(formals(fit)) if(!all(c("y", "x", "start", "weights", "offset") %in% fitargs)) { stop("no suitable fitting function specified") } ## augment fitting function (if necessary) if(!all(c("estfun", "object") %in% fitargs)) { afit <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ..., estfun = FALSE, object = FALSE) { obj <- if("cluster" %in% fitargs) { fit(y = y, x = x, start = start, weights = weights, offset = offset, cluster = cluster, ...) } else { fit(y = y, x = x, start = start, weights = weights, offset = offset, ...) } list( coefficients = coef(obj), objfun = -as.numeric(logLik(obj)), estfun = if(estfun) sandwich::estfun(obj) else NULL, object = if(object) obj else NULL ) } } else { if("cluster" %in% fitargs) { afit <- fit } else { afit <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ..., estfun = FALSE, object = FALSE) { fit(y = y, x = x, start = start, weights = weights, offset = offset, ..., estfun = estfun, object = object) } } } ## call cl <- match.call() if(missing(data)) data <- environment(formula) mf <- match.call(expand.dots = FALSE) m <- match(c("formula", "data", "subset", "na.action", "weights", "offset", "cluster"), names(mf), 0L) mf <- mf[c(1L, m)] mf$drop.unused.levels <- TRUE ## formula FIXME: y ~ . or y ~ x | . oformula <- as.formula(formula) formula <- Formula::as.Formula(formula) if(length(formula)[2L] < 2L) { formula <- Formula::Formula(formula(Formula::as.Formula(formula(formula), ~ 0), rhs = 2L:1L)) xreg <- FALSE } else { if(length(formula)[2L] > 2L) { formula <- Formula::Formula(formula(formula, rhs = 1L:2L)) warning("Formula must not have more than two RHS parts") } xreg <- TRUE } mf$formula <- formula ## evaluate model.frame mf[[1L]] <- quote(stats::model.frame) mf <- eval(mf, parent.frame()) ## extract terms, response, regressor matrix (if any), partitioning variables mt <- terms(formula, data = data) mtY <- terms(formula, data = data, rhs = if(xreg) 1L else 0L) mtZ <- delete.response(terms(formula, data = data, rhs = 2L)) Y <- switch(control$ytype, "vector" = Formula::model.part(formula, mf, lhs = 1L)[[1L]], "matrix" = model.matrix(~ 0 + ., Formula::model.part(formula, mf, lhs = 1L)), "data.frame" = Formula::model.part(formula, mf, lhs = 1L) ) X <- if(!xreg) NULL else switch(control$xtype, "matrix" = model.matrix(mtY, mf), "data.frame" = Formula::model.part(formula, mf, rhs = 1L) ) if(!is.null(X) && ncol(X) < 1L) { X <- NULL xreg <- FALSE } if(xreg) { attr(X, "formula") <- formula(formula, rhs = 1L) attr(X, "terms") <- mtY attr(X, "offset") <- cl$offset attr(X, "xlevels") <- .getXlevels(mtY, mf) } Z <- Formula::model.part(formula, mf, rhs = 2L) n <- nrow(Z) nyx <- length(mf) - length(Z) - as.numeric("(weights)" %in% names(mf)) - as.numeric("(offset)" %in% names(mf)) - as.numeric("(cluster)" %in% names(mf)) varindex <- match(names(Z), names(mf)) ## weights and offset weights <- model.weights(mf) if(is.null(weights)) weights <- 1L if(length(weights) == 1L) weights <- rep.int(weights, n) weights <- as.vector(weights) offset <- if(xreg) model.offset(mf) else NULL cluster <- mf[["(cluster)"]] ## process pruning options (done here because of "n") if(!is.null(control$prune)) { if(is.character(control$prune)) { control$prune <- tolower(control$prune) control$prune <- match.arg(control$prune, c("aic", "bic", "none")) control$prune <- switch(control$prune, "aic" = { function(objfun, df, nobs) (2 * objfun[1L] + 2 * df[1L]) < (2 * objfun[2L] + 2 * df[2L]) }, "bic" = { function(objfun, df, nobs) (2 * objfun[1L] + log(n) * df[1L]) < (2 * objfun[2L] + log(n) * df[2L]) }, "none" = { NULL }) } if(!is.function(control$prune)) { warning("Unknown specification of 'prune'") control$prune <- NULL } } ## grow the actual tree nodes <- mob_partynode(Y = Y, X = X, Z = Z, weights = weights, offset = offset, cluster = cluster, fit = afit, control = control, varindex = varindex, ...) ## compute terminal node number for each observation fitted <- fitted_node(nodes, data = mf) fitted <- data.frame( "(fitted)" = fitted, ## "(response)" = Y, ## probably not really needed check.names = FALSE, row.names = rownames(mf)) if(!identical(weights, rep.int(1L, n))) fitted[["(weights)"]] <- weights if(!is.null(offset)) fitted[["(offset)"]] <- offset if(!is.null(cluster)) fitted[["(cluster)"]] <- cluster ## return party object rval <- party(nodes, data = if(control$model) mf else mf[0,], fitted = fitted, terms = mt, info = list( call = cl, formula = oformula, Formula = formula, terms = list(response = mtY, partitioning = mtZ), fit = afit, control = control, dots = list(...), nreg = max(0L, as.integer(xreg) * (nyx - NCOL(Y)))) ) class(rval) <- c("modelparty", class(rval)) return(rval) } ## set up partynode object mob_partynode <- function(Y, X, Z, weights = NULL, offset = NULL, cluster = NULL, fit, control = mob_control(), varindex = 1L:NCOL(Z), ...) { ## are there regressors? if(missing(X)) X <- NULL xreg <- !is.null(X) n <- nrow(Z) if(is.null(weights)) weights <- 1L if(length(weights) < n) weights <- rep(weights, length.out = n) ## control parameters (used repeatedly) minsize <- control$minsize if(!is.null(minsize) && !is.integer(minsize)) minsize <- as.integer(minsize) verbose <- control$verbose rnam <- c("estfun", "object") terminal <- lapply(rnam, function(x) x %in% control$terminal) inner <- lapply(rnam, function(x) x %in% control$inner) names(terminal) <- names(inner) <- rnam ## convenience functions w2n <- function(w) if(control$caseweights) sum(w) else sum(w > 0) suby <- function(y, index) { if(control$ytype == "vector") y[index] else y[index, , drop = FALSE] } subx <- if(xreg) { function(x, index) { sx <- x[index, , drop = FALSE] attr(sx, "contrasts") <- attr(x, "contrasts") attr(sx, "xlevels") <- attr(x, "xlevels") attr(sx, "formula") <- attr(x, "formula") attr(sx, "terms") <- attr(x, "terms") attr(sx, "offset") <- attr(x, "offset") sx } } else { function(x, index) NULL } subz <- function(z, index) z[index, , drop = FALSE] ## from strucchange root.matrix <- function(X) { if((ncol(X) == 1L)&&(nrow(X) == 1L)) return(sqrt(X)) else { X.eigen <- eigen(X, symmetric = TRUE) if(any(X.eigen$values < 0)) stop("Matrix is not positive semidefinite") sqomega <- sqrt(diag(X.eigen$values)) V <- X.eigen$vectors return(V %*% sqomega %*% t(V)) } } ## core mob_grow_* functions ## variable selection: given model scores, conduct ## all M-fluctuation tests for orderins in z mob_grow_fluctests <- function(estfun, z, weights, obj = NULL, cluster = NULL) { ## set up return values m <- NCOL(z) pval <- rep.int(NA_real_, m) stat <- rep.int(0, m) ifac <- rep.int(FALSE, m) ## variables to test mtest <- if(m <= control$mtry) 1L:m else sort(sample(1L:m, control$mtry)) ## estimating functions (dropping zero weight observations) process <- as.matrix(estfun) ww0 <- (weights > 0) process <- process[ww0, , drop = FALSE] z <- z[ww0, , drop = FALSE] k <- NCOL(process) n <- NROW(process) nobs <- if(control$caseweights && any(weights != 1L)) sum(weights) else n ## scale process process <- process/sqrt(nobs) vcov <- control$vcov if(is.null(obj)) vcov <- "opg" if(vcov != "opg") { bread <- vcov(obj) * nobs } if(vcov != "info") { ## correct scaling of estfun for variance estimate: ## - caseweights=FALSE: weights are integral part of the estfun -> squared in estimate ## - caseweights=TRUE: weights are just a factor in variance estimate -> require division by sqrt(weights) meat <- if(is.null(cluster)) { crossprod(if(control$caseweights) process/sqrt(weights) else process) } else { ## nclus <- length(unique(cluster)) ## nclus / (nclus - 1L) * crossprod(as.matrix(apply(if(control$caseweights) process/sqrt(weights) else process, 2L, tapply, as.numeric(cluster), sum))) } } J12 <- root.matrix(switch(vcov, "opg" = chol2inv(chol(meat)), "info" = bread, "sandwich" = bread %*% meat %*% bread )) process <- t(J12 %*% t(process)) ## NOTE: loses column names ## select parameters to test if(!is.null(control$parm)) { if(is.character(control$parm)) colnames(process) <- colnames(estfun) process <- process[, control$parm, drop = FALSE] } k <- NCOL(process) ## get critical values for supLM statistic from <- if(control$trim > 1) control$trim else ceiling(nobs * control$trim) from <- max(from, minsize) to <- nobs - from lambda <- ((nobs - from) * to)/(from * (nobs - to)) beta <- mob_beta_suplm logp.supLM <- function(x, k, lambda) { if(k > 40L) { ## use Estrella (2003) asymptotic approximation logp_estrella2003 <- function(x, k, lambda) -lgamma(k/2) + k/2 * log(x/2) - x/2 + log(abs(log(lambda) * (1 - k/x) + 2/x)) ## FIXME: Estrella only works well for large enough x ## hence require x > 1.5 * k for Estrella approximation and ## use an ad hoc interpolation for larger p-values p <- ifelse(x <= 1.5 * k, (x/(1.5 * k))^sqrt(k) * logp_estrella2003(1.5 * k, k, lambda), logp_estrella2003(x, k, lambda)) } else { ## use Hansen (1997) approximation nb <- ncol(beta) - 1L tau <- if(lambda < 1) lambda else 1/(1 + sqrt(lambda)) beta <- beta[(((k - 1) * 25 + 1):(k * 25)),] dummy <- beta[,(1L:nb)] %*% x^(0:(nb-1)) dummy <- dummy * (dummy > 0) pp <- pchisq(dummy, beta[,(nb+1)], lower.tail = FALSE, log.p = TRUE) if(tau == 0.5) { p <- pchisq(x, k, lower.tail = FALSE, log.p = TRUE) } else if(tau <= 0.01) { p <- pp[25L] } else if(tau >= 0.49) { p <- log((exp(log(0.5 - tau) + pp[1L]) + exp(log(tau - 0.49) + pchisq(x, k, lower.tail = FALSE, log.p = TRUE))) * 100) ## if p becomes so small that 'correct' weighted averaging does not work, resort to 'naive' averaging if(!is.finite(p)) p <- mean(c(pp[1L], pchisq(x, k, lower.tail = FALSE, log.p = TRUE))) } else { taua <- (0.51 - tau) * 50 tau1 <- floor(taua) p <- log(exp(log(tau1 + 1 - taua) + pp[tau1]) + exp(log(taua-tau1) + pp[tau1 + 1L])) ## if p becomes so small that 'correct' weighted averaging does not work, resort to 'naive' averaging if(!is.finite(p)) p <- mean(pp[tau1 + 0L:1L]) } } return(as.vector(p)) } ## compute statistic and p-value for each ordering for(i in mtest) { zi <- z[,i] if(length(unique(zi)) < 2L) next if(is.factor(zi)) { oi <- order(zi) proci <- process[oi, , drop = FALSE] ifac[i] <- TRUE iord <- is.ordered(zi) & (control$ordinal != "chisq") ## order partitioning variable zi <- zi[oi] # re-apply factor() added to drop unused levels zi <- factor(zi, levels = unique(zi)) # compute segment weights segweights <- if(control$caseweights) tapply(weights[oi], zi, sum) else table(zi) segweights <- as.vector(segweights)/nobs # compute statistic only if at least two levels are left if(length(segweights) < 2L) { stat[i] <- 0 pval[i] <- NA_real_ } else if(iord) { proci <- apply(proci, 2L, cumsum) tt0 <- head(cumsum(table(zi)), -1L) tt <- head(cumsum(segweights), -1L) if(control$ordinal == "max") { stat[i] <- max(abs(proci[tt0, ] / sqrt(tt * (1-tt)))) pval[i] <- log(as.numeric(1 - mvtnorm::pmvnorm( lower = -stat[i], upper = stat[i], mean = rep(0, length(tt)), sigma = outer(tt, tt, function(x, y) sqrt(pmin(x, y) * (1 - pmax(x, y)) / ((pmax(x, y) * (1 - pmin(x, y)))))) )^k)) } else { proci <- rowSums(proci^2) stat[i] <- max(proci[tt0] / (tt * (1-tt))) pval[i] <- log(strucchange::ordL2BB(segweights, nproc = k, nrep = control$nrep)$computePval(stat[i], nproc = k)) } } else { stat[i] <- sum(sapply(1L:k, function(j) (tapply(proci[,j], zi, sum)^2)/segweights)) pval[i] <- pchisq(stat[i], k*(length(levels(zi))-1), log.p = TRUE, lower.tail = FALSE) } } else { oi <- if(control$breakties) { mm <- sort(unique(zi)) mm <- ifelse(length(mm) > 1L, min(diff(mm))/10, 1) order(zi + runif(length(zi), min = -mm, max = +mm)) } else { order(zi) } proci <- process[oi, , drop = FALSE] proci <- apply(proci, 2L, cumsum) tt0 <- if(control$caseweights && any(weights != 1L)) cumsum(weights[oi]) else 1:n from_to <- tt0 >= from & tt0 <= to stat[i] <- if(sum(from_to) > 0L) { xx <- rowSums(proci^2) xx <- xx[from_to] tt <- tt0[from_to]/nobs max(xx/(tt * (1 - tt))) } else { 0 } pval[i] <- if(sum(from_to) > 0L) logp.supLM(stat[i], k, lambda) else NA } } ## select variable with minimal p-value best <- which.min(pval) if(length(best) < 1L) best <- NA rval <- list(pval = exp(pval), stat = stat, best = best) names(rval$pval) <- names(z) names(rval$stat) <- names(z) if(!all(is.na(rval$best))) names(rval$best) <- names(z)[rval$best] return(rval) } ### split in variable zselect, either ordered (numeric or ordinal) or nominal mob_grow_findsplit <- function(y, x, zselect, weights, offset, cluster, ...) { ## process minsize (to minimal number of observations) if(minsize > 0.5 & minsize < 1) minsize <- 1 - minsize if(minsize < 0.5) minsize <- ceiling(w2n(weights) * minsize) if(is.numeric(zselect)) { ## for numerical variables uz <- sort(unique(zselect)) if (length(uz) == 0L) stop("Cannot find admissible split point in partitioning variable") ## if starting values are not reused then the applyfun() is used for determining the split if(control$restart) { get_dev <- function(i) { zs <- zselect <= uz[i] if(w2n(weights[zs]) < minsize || w2n(weights[!zs]) < minsize) { return(Inf) } else { fit_left <- fit(y = suby(y, zs), x = subx(x, zs), start = NULL, weights = weights[zs], offset = offset[zs], cluster = cluster[zs], ...) fit_right <- fit(y = suby(y, !zs), x = subx(x, !zs), start = NULL, weights = weights[!zs], offset = offset[!zs], cluster = cluster[!zs], ...) return(fit_left$objfun + fit_right$objfun) } } dev <- unlist(control$applyfun(1L:length(uz), get_dev)) } else { ## alternatively use for() loop to go through all splits sequentially ## and reuse previous parameters as starting values dev <- vector(mode = "numeric", length = length(uz)) start_left <- NULL start_right <- NULL for(i in 1L:length(uz)) { zs <- zselect <= uz[i] if(control$restart || !identical(names(start_left), names(start_right)) || !identical(length(start_left), length(start_right))) { start_left <- NULL start_right <- NULL } if(w2n(weights[zs]) < minsize || w2n(weights[!zs]) < minsize) { dev[i] <- Inf } else { fit_left <- fit(y = suby(y, zs), x = subx(x, zs), start = start_left, weights = weights[zs], offset = offset[zs], cluster = cluster[zs], ...) fit_right <- fit(y = suby(y, !zs), x = subx(x, !zs), start = start_right, weights = weights[!zs], offset = offset[!zs], cluster = cluster[!zs], ...) start_left <- fit_left$coefficients start_right <- fit_right$coefficients dev[i] <- fit_left$objfun + fit_right$objfun } } } ## maybe none of the possible splits is admissible if(all(!is.finite(dev))) { split <- list( breaks = NULL, index = NULL ) } else { split <- list( breaks = if(control$numsplit == "center") { as.double(mean(uz[which.min(dev) + 0L:1L])) } else { as.double(uz[which.min(dev)]) }, index = NULL ) } } else { if(!is.ordered(zselect) & control$catsplit == "multiway") { return(list(breaks = NULL, index = seq_along(levels(zselect)))) } ## for categorical variables olevels <- levels(zselect) ## full set of original levels zselect <- factor(zselect) ## omit levels that do not occur in the data al <- mob_grow_getlevels(zselect) get_dev <- function(i) { w <- al[i,] zs <- zselect %in% levels(zselect)[w] if(w2n(weights[zs]) < minsize || w2n(weights[!zs]) < minsize) { return(Inf) } else { if(nrow(al) == 1L) 1 else { fit_left <- fit(y = suby(y, zs), x = subx(x, zs), start = NULL, weights = weights[zs], offset = offset[zs], cluster = cluster[zs], ...) fit_right <- fit(y = suby(y, !zs), x = subx(x, !zs), start = NULL, weights = weights[!zs], offset = offset[!zs], cluster = cluster[zs], ...) fit_left$objfun + fit_right$objfun } } } dev <- unlist(control$applyfun(1L:nrow(al), get_dev)) if(all(!is.finite(dev))) { split <- list( breaks = NULL, index = NULL ) } else { if(is.ordered(zselect)) { ## map back to set of full original levels split <- list( breaks = match(levels(zselect)[which.min(dev)], olevels), index = NULL ) } else { ## map back to set of full original levels ix <- structure(rep.int(NA_integer_, length(olevels)), .Names = olevels) ix[colnames(al)] <- !al[which.min(dev),] ix <- as.integer(ix) + 1L split <- list( breaks = NULL, index = ix ) } } } return(split) } ## grow tree by combining fluctuation tests for variable selection ## and split selection recursively mob_grow <- function(id = 1L, y, x, z, weights, offset, cluster, ...) { if(verbose) { if(id == 1L) cat("\n") cat(sprintf("-- Node %i %s\n", id, paste(rep("-", 32 - floor(log10(id)) + 1L), collapse = ""))) cat(sprintf("Number of observations: %s\n", w2n(weights))) ## cat(sprintf("Depth: %i\n", depth)) } ## fit model mod <- fit(y, x, weights = weights, offset = offset, cluster = cluster, ..., estfun = TRUE, object = terminal$object | control$vcov == "info") mod$test <- NULL mod$nobs <- w2n(weights) mod$p.value <- NULL ## set default for minsize if not specified if(is.null(minsize)) minsize <<- as.integer(ceiling(10L * length(mod$coefficients)/NCOL(y))) ## if too few observations or maximum depth: no split = return terminal node TERMINAL <- FALSE if(w2n(weights) < 2 * minsize) { if(verbose) cat(sprintf("Too few observations, stop splitting (minsize = %s)\n\n", minsize)) TERMINAL <- TRUE } if(depth >= control$maxdepth) { if(verbose) cat(sprintf("Maximum depth reached, stop splitting (maxdepth = %s)\n\n", control$maxdepth)) TERMINAL <- TRUE } if(TERMINAL) { return(partynode(id = id, info = mod)) } ## conduct all parameter instability tests test <- if(is.null(mod$estfun)) NULL else try(mob_grow_fluctests(mod$estfun, z, weights, mod$object, cluster)) if(!is.null(test) && !inherits(test, "try-error")) { if(control$bonferroni) { pval1 <- pmin(1, sum(!is.na(test$pval)) * test$pval) pval2 <- 1 - (1 - test$pval)^sum(!is.na(test$pval)) test$pval <- ifelse(!is.na(test$pval) & (test$pval > 0.001), pval2, pval1) } best <- test$best TERMINAL <- is.na(best) || test$pval[best] > control$alpha mod$p.value <- as.numeric(test$pval[best]) if (verbose) { cat("\nParameter instability tests:\n") print(rbind(statistic = test$stat, p.value = test$pval)) cat(sprintf("\nBest splitting variable: %s", names(test$stat)[best])) cat(sprintf("\nPerform split? %s", ifelse(TERMINAL, "no\n\n", "yes\n"))) } } else { if(verbose && inherits(test, "try-error")) cat("Parameter instability tests failed\n\n") TERMINAL <- TRUE test <- list(stat = NA, pval = NA) } ## update model information mod$test <- rbind("statistic" = test$stat, "p.value" = test$pval) if(TERMINAL) { return(partynode(id = id, info = mod)) } else { zselect <- z[[best]] sp <- mob_grow_findsplit(y, x, zselect, weights, offset, cluster, ...) ## split successful? if(is.null(sp$breaks) & is.null(sp$index)) { if(verbose) cat(sprintf("No admissable split found in %s\n\n", sQuote(names(test$stat)[best]))) return(partynode(id = id, info = mod)) } else { sp <- partysplit(as.integer(best), breaks = sp$breaks, index = sp$index) if(verbose) cat(sprintf("Selected split: %s\n\n", paste(character_split(sp, data = z)$levels, collapse = " | "))) } } ## actually split the data kidids <- kidids_split(sp, data = z) ## set-up all daugther nodes depth <<- depth + 1L kids <- vector(mode = "list", length = max(kidids)) for(kidid in 1L:max(kidids)) { ## select obs for current next node nxt <- kidids == kidid ## get next node id if(kidid > 1L) { myid <- max(nodeids(kids[[kidid - 1L]])) } else { myid <- id } ## start recursion on this daugther node kids[[kidid]] <- mob_grow(id = myid + 1L, suby(y, nxt), subx(x, nxt), subz(z, nxt), weights[nxt], offset[nxt], cluster[nxt], ...) } depth <<- depth - 1L ## shift split varid from z to mf sp$varid <- as.integer(varindex[sp$varid]) ## return nodes return(partynode(id = id, split = sp, kids = kids, info = mod)) } mob_prune <- function(node) { ## turn node to list nd <- as.list(node) ## if no pruning selected if(is.null(control$prune)) return(nd) ## node information (IDs, kids, ...) id <- seq_along(nd) kids <- lapply(nd, "[[", "kids") tmnl <- sapply(kids, is.null) ## check nodes that only have terminal kids check <- sapply(id, function(i) !tmnl[i] && all(tmnl[kids[[i]]])) while(any(check)) { ## pruning node information pnode <- which(check) objfun <- sapply(nd, function(x) x$info$objfun) pok <- sapply(pnode, function(i) control$prune( objfun = c(objfun[i], sum(objfun[kids[[i]]])), df = c(length(nd[[1]]$info$coefficients), length(kids[[i]]) * length(nd[[1]]$info$coefficients) + as.integer(control$dfsplit)), nobs = c(nd[[i]]$info$nobs, n) )) ## do any nodes need pruning? pnode <- pnode[pok] if(length(pnode) < 1L) break ## prune nodes and relabel IDs pkids <- sort(unlist(sapply(pnode, function(i) nd[[i]]$kids))) for(i in id) { nd[[i]]$kids <- if(nd[[i]]$id %in% pnode || is.null(kids[[i]])) { NULL } else { nd[[i]]$kids - sapply(kids[[i]], function(x) sum(pkids < x)) } } nd[pkids] <- NULL id <- seq_along(nd) for(i in id) nd[[i]]$id <- i ## node information kids <- lapply(nd, "[[", "kids") tmnl <- sapply(kids, is.null) check <- sapply(id, function(i) !tmnl[i] && all(tmnl[kids[[i]]])) } ## return pruned list return(nd) } ## grow tree depth <- 1L nodes <- mob_grow(id = 1L, Y, X, Z, weights, offset, cluster, ...) ## prune tree if(verbose && !is.null(control$prune)) cat("-- Post-pruning ---------------------------\n") nodes <- mob_prune(nodes) for(i in seq_along(nodes)) { if(is.null(nodes[[i]]$kids)) { nodes[[i]]$split <- NULL if(!terminal$estfun) nodes[[i]]$info$estfun <- NULL if(!terminal$object) nodes[[i]]$info$object <- NULL } else { if(!inner$estfun) nodes[[i]]$info$estfun <- NULL if(!inner$object) nodes[[i]]$info$object <- NULL } } ## return as partynode as.partynode(nodes) } ## determine all possible splits for a factor, both nominal and ordinal mob_grow_getlevels <- function(z) { nl <- nlevels(z) if(inherits(z, "ordered")) { indx <- diag(nl) indx[lower.tri(indx)] <- 1 indx <- indx[-nl, , drop = FALSE] rownames(indx) <- levels(z)[-nl] } else { mi <- 2^(nl - 1L) - 1L indx <- matrix(0, nrow = mi, ncol = nl) for (i in 1L:mi) { ii <- i for (l in 1L:nl) { indx[i, l] <- ii %% 2L ii <- ii %/% 2L } } rownames(indx) <- apply(indx, 1L, function(x) paste(levels(z)[x > 0], collapse = "+")) } colnames(indx) <- as.character(levels(z)) storage.mode(indx) <- "logical" indx } ## control splitting parameters mob_control <- function(alpha = 0.05, bonferroni = TRUE, minsize = NULL, maxdepth = Inf, mtry = Inf, trim = 0.1, breakties = FALSE, parm = NULL, dfsplit = TRUE, prune = NULL, restart = TRUE, verbose = FALSE, caseweights = TRUE, ytype = "vector", xtype = "matrix", terminal = "object", inner = terminal, model = TRUE, numsplit = "left", catsplit = "binary", vcov = "opg", ordinal = "chisq", nrep = 10000, minsplit = minsize, minbucket = minsize, applyfun = NULL, cores = NULL) { ## transform defaults if(missing(minsize) & !missing(minsplit)) minsize <- minsplit if(missing(minsize) & !missing(minbucket)) minsize <- minbucket ## no mtry if infinite or non-positive if(is.finite(mtry)) { mtry <- if(mtry < 1L) Inf else as.integer(mtry) } ## data types for formula processing ytype <- match.arg(ytype, c("vector", "data.frame", "matrix")) xtype <- match.arg(xtype, c("data.frame", "matrix")) ## what to store in inner/terminal nodes if(!is.null(terminal)) terminal <- as.vector(sapply(terminal, match.arg, c("estfun", "object"))) if(!is.null(inner)) inner <- as.vector(sapply(inner, match.arg, c("estfun", "object"))) ## how to split and how to select splitting variables numsplit <- match.arg(tolower(numsplit), c("left", "center", "centre")) if(numsplit == "centre") numsplit <- "center" catsplit <- match.arg(tolower(catsplit), c("binary", "multiway")) vcov <- match.arg(tolower(vcov), c("opg", "info", "sandwich")) ordinal <- match.arg(tolower(ordinal), c("l2", "max", "chisq")) ## apply infrastructure for determining split points if(is.null(applyfun)) { applyfun <- if(is.null(cores)) { lapply } else { function(X, FUN, ...) parallel::mclapply(X, FUN, ..., mc.cores = cores) } } ## return list with all options rval <- list(alpha = alpha, bonferroni = bonferroni, minsize = minsize, maxdepth = maxdepth, mtry = mtry, trim = ifelse(is.null(trim), minsize, trim), breakties = breakties, parm = parm, dfsplit = dfsplit, prune = prune, restart = restart, verbose = verbose, caseweights = caseweights, ytype = ytype, xtype = xtype, terminal = terminal, inner = inner, model = model, numsplit = numsplit, catsplit = catsplit, vcov = vcov, ordinal = ordinal, nrep = nrep, applyfun = applyfun) return(rval) } ## methods concerning call/formula/terms/etc. ## (default methods work for terms and update) formula.modelparty <- function(x, extended = FALSE, ...) if(extended) x$info$Formula else x$info$formula getCall.modelparty <- function(x, ...) x$info$call model.frame.modelparty <- function(formula, ...) { mf <- formula$data if(nrow(mf) > 0L) return(mf) dots <- list(...) nargs <- dots[match(c("data", "na.action", "subset"), names(dots), 0L)] mf <- formula$info$call mf <- mf[c(1L, match(c("formula", "data", "subset", "na.action"), names(mf), 0L))] mf$drop.unused.levels <- TRUE mf[[1L]] <- quote(stats::model.frame) mf[names(nargs)] <- nargs if(is.null(env <- environment(formula$info$terms))) env <- parent.frame() mf$formula <- Formula::Formula(as.formula(mf$formula)) eval(mf, env) } weights.modelparty <- function(object, ...) { fit <- object$fitted ww <- if(!is.null(w <- fit[["(weights)"]])) w else rep.int(1L, NROW(fit)) structure(ww, .Names = rownames(fit)) } ## methods concerning model/parameters/loglik/etc. coef.modelparty <- function(object, node = NULL, drop = TRUE, ...) { if(is.null(node)) node <- nodeids(object, terminal = TRUE) cf <- do.call("rbind", nodeapply(object, ids = node, FUN = function(n) info_node(n)$coefficients)) if(drop) drop(cf) else cf } refit.modelparty <- function(object, node = NULL, drop = TRUE, ...) { ## by default use all ids if(is.null(node)) node <- nodeids(object) ## estimated coefficients cf <- nodeapply(object, ids = node, FUN = function(n) info_node(n)$coefficients) ## model.frame mf <- model.frame(object) weights <- weights(object) offset <- model.offset(mf) cluster <- mf[["(cluster)"]] ## fitted ids fitted <- object$fitted[["(fitted)"]] ## response variables Y <- switch(object$info$control$ytype, "vector" = Formula::model.part(object$info$Formula, mf, lhs = 1L)[[1L]], "matrix" = model.matrix(~ 0 + ., Formula::model.part(object$info$Formula, mf, lhs = 1L)), "data.frame" = Formula::model.part(object$info$Formula, mf, lhs = 1L) ) hasx <- object$info$nreg >= 1L | attr(object$info$terms$response, "intercept") > 0L X <- if(!hasx) NULL else switch(object$info$control$xtype, "matrix" = model.matrix(object$info$terms$response, mf), "data.frame" = Formula::model.part(object$info$Formula, mf, rhs = 1L) ) if(!is.null(X)) { attr(X, "formula") <- formula(object$info$Formula, rhs = 1L) attr(X, "terms") <- object$info$terms$response attr(X, "offset") <- object$info$call$offset } suby <- function(y, index) { if(object$info$control$ytype == "vector") y[index] else y[index, , drop = FALSE] } subx <- if(hasx) { function(x, index) { sx <- x[index, , drop = FALSE] attr(sx, "contrasts") <- attr(x, "contrasts") attr(sx, "xlevels") <- attr(x, "xlevels") attr(sx, "formula") <- attr(x, "formula") attr(sx, "terms") <- attr(x, "terms") attr(sx, "offset") <- attr(x, "offset") sx } } else { function(x, index) NULL } ## fitting function afit <- object$info$fit ## refit rval <- lapply(seq_along(node), function(i) { ix <- fitted %in% nodeids(object, from = node[i], terminal = TRUE) args <- list(y = suby(Y, ix), x = subx(X, ix), start = cf[[i]], weights = weights[ix], offset = offset[ix], cluster = cluster[ix], object = TRUE) args <- c(args, object$info$dots) do.call("afit", args)$object }) names(rval) <- node ## drop? if(drop & length(rval) == 1L) rval <- rval[[1L]] ## return return(rval) } apply_to_models <- function(object, node = NULL, FUN = NULL, drop = FALSE, ...) { if(is.null(node)) node <- nodeids(object, terminal = FALSE) if(is.null(FUN)) FUN <- function(object, ...) object rval <- if("object" %in% object$info$control$terminal) { nodeapply(object, node, function(n) FUN(info_node(n)$object)) } else { lapply(refit.modelparty(object, node, drop = FALSE), FUN) } names(rval) <- node if(drop & length(node) == 1L) rval <- rval[[1L]] return(rval) } logLik.modelparty <- function(object, dfsplit = NULL, ...) { if(is.null(dfsplit)) dfsplit <- object$info$control$dfsplit dfsplit <- as.integer(dfsplit) ids <- nodeids(object, terminal = TRUE) ll <- apply_to_models(object, node = ids, FUN = logLik) dfsplit <- dfsplit * (length(object) - length(ll)) structure( sum(as.numeric(ll)), df = sum(sapply(ll, function(x) attr(x, "df"))) + dfsplit, nobs = nobs(object), class = "logLik" ) } nobs.modelparty <- function(object, ...) { sum(unlist(nodeapply(object, nodeids(object, terminal = TRUE), function(n) info_node(n)$nobs ))) } deviance.modelparty <- function(object, ...) { ids <- nodeids(object, terminal = TRUE) dev <- apply_to_models(object, node = ids, FUN = deviance) sum(unlist(dev)) } summary.modelparty <- function(object, node = NULL, ...) { ids <- if(is.null(node)) nodeids(object, terminal = TRUE) else node rval <- apply_to_models(object, node = ids, FUN = summary) if(length(ids) == 1L) rval[[1L]] else rval } sctest.modelparty <- function(object, node = NULL, ...) { ids <- if(is.null(node)) nodeids(object, terminal = FALSE) else node rval <- nodeapply(object, ids, function(n) info_node(n)$test) names(rval) <- ids if(length(ids) == 1L) rval[[1L]] else rval } print.modelparty <- function(x, node = NULL, FUN = NULL, digits = getOption("digits") - 4L, header = TRUE, footer = TRUE, title = NULL, objfun = "", ...) { digits <- max(c(0, digits)) if(objfun != "") objfun <- paste(" (", objfun, ")", sep = "") if(is.null(title)) title <- sprintf("Model-based recursive partitioning (%s)", deparse(x$info$call$fit)) if(is.null(node)) { header_panel <- if(header) function(party) { c(title, "", "Model formula:", deparse(party$info$formula), "", "Fitted party:", "") } else function(party) "" footer_panel <- if(footer) function(party) { n <- width(party) n <- format(c(length(party) - n, n)) info <- nodeapply(x, ids = nodeids(x, terminal = TRUE), FUN = function(n) c(length(info_node(n)$coefficients), info_node(n)$objfun)) k <- mean(sapply(info, "[", 1L)) of <- format(sum(sapply(info, "[", 2L)), digits = getOption("digits")) c("", paste("Number of inner nodes: ", n[1L]), paste("Number of terminal nodes:", n[2L]), paste("Number of parameters per node:", format(k, digits = getOption("digits"))), paste("Objective function", objfun, ": ", of, sep = ""), "") } else function (party) "" if(is.null(FUN)) { FUN <- function(x) c(sprintf(": n = %s", x$nobs), capture.output(print(x$coefficients))) } terminal_panel <- function(node) formatinfo_node(node, default = "*", prefix = NULL, FUN = FUN) print.party(x, terminal_panel = terminal_panel, header_panel = header_panel, footer_panel = footer_panel, ...) } else { node <- as.integer(node) info <- nodeapply(x, ids = node, FUN = function(n) info_node(n)[c("coefficients", "objfun", "test")]) for(i in seq_along(node)) { if(i == 1L) { cat(paste(title, "\n", collapse = "")) } else { cat("\n") } cat(sprintf("-- Node %i --\n", node[i])) cat("\nEstimated parameters:\n") print(info[[i]]$coefficients) cat(sprintf("\nObjective function:\n%s\n", format(info[[i]]$objfun))) cat("\nParameter instability tests:\n") print(info[[i]]$test) } } invisible(x) } predict.modelparty <- function(object, newdata = NULL, type = "node", ...) { ## predicted node ids node <- predict.party(object, newdata = newdata) if(identical(type, "node")) return(node) ## obtain fitted model objects ids <- sort(unique(as.integer(node))) mod <- apply_to_models(object, node = ids) ## obtain predictions pred <- if(is.character(type)) { function(object, newdata = NULL, ...) predict(object, newdata = newdata, type = type, ...) } else { type } if("newdata" %in% names(formals(pred))) { ix <- lapply(seq_along(ids), function(i) which(node == ids[i])) preds <- lapply(seq_along(ids), function(i) pred(mod[[i]], newdata = newdata[ix[[i]], , drop = FALSE], ...)) nc <- NCOL(preds[[1L]]) rval <- if(nc > 1L) { matrix(0, nrow = length(node), ncol = nc, dimnames = list(names(node), colnames(preds[[1L]]))) } else { rep(preds[[1L]], length.out = length(node)) } for(i in seq_along(ids)) { if(nc > 1L) { rval[ix[[i]], ] <- preds[[i]] rownames(rval) <- names(node) } else { rval[ix[[i]]] <- preds[[i]] names(rval) <- names(node) } } } else { rval <- lapply(mod, pred, ...) if(NCOL(rval[[1L]]) > 1L) { rval <- do.call("rbind", rval) rownames(rval) <- ids rval <- rval[as.character(node), , drop = FALSE] rownames(rval) <- names(node) rval <- drop(rval) } else { ## provide a c() method for factors locally c.factor <- function(...) { args <- list(...) lev <- levels(args[[1L]]) args[[1L]] <- unclass(args[[1L]]) rval <- do.call("c", args) factor(rval, levels = 1L:length(lev), labels = lev) } rval <- do.call("c", rval) names(rval) <- ids rval <- rval[as.character(node)] names(rval) <- names(node) } } return(rval) } fitted.modelparty <- function(object, ...) { ## fitted nodes node <- predict.party(object, type = "node") ## obtain fitted model objects ids <- nodeids(object, terminal = TRUE) fit <- apply_to_models(object, node = ids, FUN = fitted) nc <- NCOL(fit[[1L]]) rval <- if(nc > 1L) { matrix(0, nrow = length(ids), ncol = nc, dimnames = list(names(node), colnames(fit[[1L]]))) } else { rep(fit[[1L]], length.out = length(node)) } for(i in seq_along(ids)) { if(nc > 1L) { rval[node == ids[i], ] <- fit[[i]] rownames(rval) <- names(node) } else { rval[node == ids[i]] <- fit[[i]] names(rval) <- names(node) } } return(rval) } residuals.modelparty <- function(object, ...) { ## fitted nodes node <- predict.party(object, type = "node") ## obtain fitted model objects ids <- nodeids(object, terminal = TRUE) res <- apply_to_models(object, node = ids, FUN = residuals) nc <- NCOL(res[[1L]]) rval <- if(nc > 1L) { matrix(0, nrow = length(ids), ncol = nc, dimnames = list(names(node), colnames(res[[1L]]))) } else { rep(res[[1L]], length.out = length(node)) } for(i in seq_along(ids)) { if(nc > 1L) { rval[node == ids[i], ] <- res[[i]] rownames(rval) <- names(node) } else { rval[node == ids[i]] <- res[[i]] names(rval) <- names(node) } } return(rval) } plot.modelparty <- function(x, terminal_panel = NULL, FUN = NULL, tp_args = NULL, ...) { if(is.null(terminal_panel)) { if(is.null(FUN)) { FUN <- function(x) { cf <- x$coefficients cf <- matrix(cf, ncol = 1, dimnames = list(names(cf), "")) c(sprintf("n = %s", x$nobs), "Estimated parameters:", strwrap(capture.output(print(cf, digits = 4L))[-1L])) } } terminal_panel <- do.call("node_terminal", c(list(obj = x, FUN = FUN), tp_args)) tp_args <- NULL } plot.party(x, terminal_panel = terminal_panel, tp_args = tp_args, ...) } ### AIC-based pruning prune.lmtree <- function(tree, type = "AIC", ...) { ## special handling for AIC and BIC ptype <- pmatch(tolower(type), c("aic", "bic"), nomatch = 0L) if(ptype == 1L) { type <- function(objfun, df, nobs) (nobs[1L] * log(objfun[1L]) + 2 * df[1L]) < (nobs[1L] * log(objfun[2L]) + 2 * df[2L]) } else if(ptype == 2L) { type <- function(objfun, df, nobs) (nobs[1L] * log(objfun[1L]) + log(nobs[2L]) * df[1L]) < (nobs[1L] * log(objfun[2L]) + log(nobs[2L]) * df[2L]) } NextMethod() } prune.modelparty <- function(tree, type = "AIC", ...) { ## prepare pruning function if(is.character(type)) { type <- tolower(type) type <- match.arg(type, c("aic", "bic", "none")) type <- switch(type, "aic" = { function(objfun, df, nobs) (2 * objfun[1L] + 2 * df[1L]) < (2 * objfun[2L] + 2 * df[2L]) }, "bic" = { function(objfun, df, nobs) (2 * objfun[1L] + log(n) * df[1L]) < (2 * objfun[2L] + log(n) * df[2L]) }, "none" = { NULL } ) } if(!is.function(type)) { warning("Unknown specification of 'type'") return(tree) } ## degrees of freedom dfsplit <- tree$info$control$dfsplit ## turn node to list node <- tree$node nd <- as.list(node) ## node information (IDs, kids, ...) id <- seq_along(nd) kids <- lapply(nd, "[[", "kids") tmnl <- sapply(kids, is.null) ## check nodes that only have terminal kids check <- sapply(id, function(i) !tmnl[i] && all(tmnl[kids[[i]]])) while(any(check)) { ## pruning node information pnode <- which(check) objfun <- sapply(nd, function(x) x$info$objfun) n <- nrow(tree$fitted) pok <- sapply(pnode, function(i) type( objfun = c(objfun[i], sum(objfun[kids[[i]]])), df = c(length(nd[[1]]$info$coefficients), length(kids[[i]]) * length(nd[[1]]$info$coefficients) + as.integer(dfsplit)), nobs = c(nd[[i]]$info$nobs, n) )) ## do any nodes need pruning? pnode <- pnode[pok] if(length(pnode) < 1L) break ## prune tree <- nodeprune.party(tree, ids = pnode) node <- tree$node nd <- as.list(node) ## node information kids <- lapply(nd, "[[", "kids") tmnl <- sapply(kids, is.null) id <- seq_along(nd) check <- sapply(id, function(i) !tmnl[i] && all(tmnl[kids[[i]]])) } ## return pruned tree return(tree) } .mfluc_test <- function(...) stop("not yet implemented") partykit/R/glmtree.R0000644000176200001440000001252514172230000014076 0ustar liggesusers## simple wrapper function to specify fitter and return class glmtree <- function(formula, data, subset, na.action, weights, offset, cluster, family = gaussian, epsilon = 1e-8, maxit = 25, method = "glm.fit", ...) { ## use dots for setting up mob_control control <- mob_control(...) ## keep call cl <- match.call(expand.dots = TRUE) ## extend formula if necessary f <- Formula::Formula(formula) if(length(f)[2L] == 1L) { attr(f, "rhs") <- c(list(1), attr(f, "rhs")) formula[[3L]] <- formula(f)[[3L]] } else { f <- NULL } ## process family if(inherits(family, "family")) { fam <- TRUE } else { fam <- FALSE if(is.character(family)) family <- get(family) if(is.function(family)) family <- family() } ## distinguish whether glm should be fixed for case weights or not glmfit0 <- function(y, x, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ..., estfun = FALSE, object = FALSE, caseweights = TRUE) { glmfit(y = y, x = x, start = start, weights = weights, offset = offset, cluster = cluster, ..., estfun = estfun, object = object, caseweights = control$caseweights) } ## call mob m <- match.call(expand.dots = FALSE) if(!is.null(f)) m$formula <- formula m$fit <- glmfit0 m$control <- control m$epsilon <- epsilon m$maxit <- maxit m$method <- method if("..." %in% names(m)) m[["..."]] <- NULL if(!fam) m$family <- family m[[1L]] <- as.call(quote(partykit::mob)) rval <- eval(m, parent.frame()) ## extend class and keep original call rval$info$call <- cl rval$info$family <- family$family class(rval) <- c("glmtree", class(rval)) return(rval) } ## actual fitting function for mob() glmfit <- function(y, x, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ..., estfun = FALSE, object = FALSE, caseweights = TRUE) { ## catch control arguments args <- list(...) ctrl <- list() for(n in c("epsilon", "maxit")) { if(n %in% names(args)) { ctrl[[n]] <- args[[n]] args[[n]] <- NULL } } args$control <- do.call("glm.control", ctrl) ## add intercept-only regressor matrix (if missing) ## NOTE: does not have terms/formula if(is.null(x)) x <- matrix(1, nrow = NROW(y), ncol = 1L, dimnames = list(NULL, "(Intercept)")) ## call glm fitting function (defaulting to glm.fit) glm.method <- if("method" %in% names(args)) args[["method"]] else "glm.fit" args[["method"]] <- NULL args <- c(list(x = x, y = y, start = start, weights = weights, offset = offset), args) z <- do.call(glm.method, args) ## degrees of freedom df <- z$rank if(z$family$family %in% c("gaussian", "Gamma", "inverse.gaussian")) df <- df + 1 if(substr(z$family$family, 1L, 5L) != "quasi") objfun <- z$aic/2 - df else objfun <- z$deviance ## list structure rval <- list( coefficients = z$coefficients, objfun = objfun, estfun = NULL, object = NULL ) ## add estimating functions (if desired) if(estfun) { wres <- as.vector(z$residuals) * z$weights dispersion <- if(substr(z$family$family, 1L, 17L) %in% c("poisson", "binomial", "Negative Binomial")) { 1 } else { ## for case weights: fix dispersion estimate if(!is.null(weights) && caseweights) { sum(wres^2/weights, na.rm = TRUE)/sum(z$weights, na.rm = TRUE) } else { sum(wres^2, na.rm = TRUE)/sum(z$weights, na.rm = TRUE) } } rval$estfun <- wres * x[, !is.na(z$coefficients), drop = FALSE]/dispersion } ## add model (if desired) if(object) { class(z) <- c("glm", "lm") z$offset <- if(is.null(offset)) 0 else offset z$contrasts <- attr(x, "contrasts") z$xlevels <- attr(x, "xlevels") cl <- as.call(expression(glm)) cl$formula <- attr(x, "formula") if(!is.null(offset)) cl$offset <- attr(x, "offset") z$call <- cl z$terms <- attr(x, "terms") ## for case weights: change degrees of freedom if(!is.null(weights) && caseweights) { z$df.null <- z$df.null - sum(weights > 0) + sum(weights) z$df.residual <- z$df.residual - sum(weights > 0) + sum(weights) } rval$object <- z } return(rval) } ## methods print.glmtree <- function(x, title = NULL, objfun = NULL, ...) { if(is.null(title)) title <- sprintf("Generalized linear model tree (family: %s)", x$info$family) if(is.null(objfun)) objfun <- if(substr(x$info$family, 1L, 5L) != "quasi") "negative log-likelihood" else "deviance" print.modelparty(x, title = title, objfun = objfun, ...) } predict.glmtree <- function(object, newdata = NULL, type = "response", ...) { ## FIXME: possible to get default? if(is.null(newdata) & !identical(type, "node")) stop("newdata has to be provided") predict.modelparty(object, newdata = newdata, type = type, ...) } plot.glmtree <- function(x, terminal_panel = node_bivplot, tp_args = list(), tnex = NULL, drop_terminal = NULL, ...) { nreg <- if(is.null(tp_args$which)) x$info$nreg else length(tp_args$which) if(nreg < 1L & missing(terminal_panel)) { plot.constparty(as.constparty(x), tp_args = tp_args, tnex = tnex, drop_terminal = drop_terminal, ...) } else { if(is.null(tnex)) tnex <- if(is.null(terminal_panel)) 1L else 2L * nreg if(is.null(drop_terminal)) drop_terminal <- !is.null(terminal_panel) plot.modelparty(x, terminal_panel = terminal_panel, tp_args = tp_args, tnex = tnex, drop_terminal = drop_terminal, ...) } } partykit/R/plot.R0000644000176200001440000010120214301732274013422 0ustar liggesusers.nobs_party <- function(party, id = 1L) { dat <- data_party(party, id = id) if("(weights)" %in% names(dat)) sum(dat[["(weights)"]]) else NROW(dat) } node_inner <- function(obj, id = TRUE, pval = TRUE, abbreviate = FALSE, fill = "white", gp = gpar()) { meta <- obj$data nam <- names(obj) extract_label <- function(node) { if(is.terminal(node)) return(rep.int("", 2L)) varlab <- character_split(split_node(node), meta)$name if(abbreviate > 0L) varlab <- abbreviate(varlab, as.integer(abbreviate)) ## FIXME: make more flexible rather than special-casing p-value if(pval) { nullna <- function(x) is.null(x) || is.na(x) pval <- suppressWarnings(try(!nullna(info_node(node)$p.value), silent = TRUE)) pval <- if(inherits(pval, "try-error")) FALSE else pval } if(pval) { pvalue <- node$info$p.value plab <- ifelse(pvalue < 10^(-3L), paste("p <", 10^(-3L)), paste("p =", round(pvalue, digits = 3L))) } else { plab <- "" } return(c(varlab, plab)) } maxstr <- function(node) { lab <- extract_label(node) klab <- if(is.terminal(node)) "" else unlist(lapply(kids_node(node), maxstr)) lab <- c(lab, klab) lab <- unlist(lapply(lab, function(x) strsplit(x, "\n"))) lab <- lab[which.max(nchar(lab))] if(length(lab) < 1L) lab <- "" return(lab) } nstr <- maxstr(node_party(obj)) if(nchar(nstr) < 6) nstr <- "aAAAAa" ### panel function for the inner nodes rval <- function(node) { pushViewport(viewport(gp = gp, name = paste("node_inner", id_node(node), "_gpar", sep = ""))) node_vp <- viewport( x = unit(0.5, "npc"), y = unit(0.5, "npc"), width = unit(1, "strwidth", nstr) * 1.3, height = unit(3, "lines"), name = paste("node_inner", id_node(node), sep = ""), gp = gp ) pushViewport(node_vp) xell <- c(seq(0, 0.2, by = 0.01), seq(0.2, 0.8, by = 0.05), seq(0.8, 1, by = 0.01)) yell <- sqrt(xell * (1-xell)) lab <- extract_label(node) fill <- rep(fill, length.out = 2L) grid.polygon(x = unit(c(xell, rev(xell)), "npc"), y = unit(c(yell, -yell)+0.5, "npc"), gp = gpar(fill = fill[1])) ## FIXME: something more general instead of pval ? grid.text(lab[1L], y = unit(1.5 + 0.5 * (lab[2L] != ""), "lines")) if(lab[2L] != "") grid.text(lab[2L], y = unit(1, "lines")) if(id) { nodeIDvp <- viewport(x = unit(0.5, "npc"), y = unit(1, "npc"), width = max(unit(1, "lines"), unit(1.3, "strwidth", nam[id_node(node)])), height = max(unit(1, "lines"), unit(1.3, "strheight", nam[id_node(node)]))) pushViewport(nodeIDvp) grid.rect(gp = gpar(fill = fill[2])) grid.text(nam[id_node(node)]) popViewport() } upViewport(2) } return(rval) } class(node_inner) <- "grapcon_generator" node_terminal <- function(obj, digits = 3, abbreviate = FALSE, fill = c("lightgray", "white"), id = TRUE, just = c("center", "top"), top = 0.85, align = c("center", "left", "right"), gp = NULL, FUN = NULL, height = NULL, width = NULL) { nam <- names(obj) extract_label <- function(node) formatinfo_node(node, FUN = FUN, default = c("terminal", "node")) maxstr <- function(node) { lab <- extract_label(node) klab <- if(is.terminal(node)) "" else unlist(lapply(kids_node(node), maxstr)) lab <- c(lab, klab) lab <- try(unlist(lapply(lab, function(x) strsplit(x, "\n"))), silent = TRUE) if(inherits(lab, "try-error")) { paste(rep("a", 9L), collapse = "") ## FIXME: completely ad-hoc: possibly throw warning? } else { return(lab[which.max(nchar(lab))]) } } nstr <- if(is.null(width)) maxstr(node_party(obj)) else paste(rep("a", width), collapse = "") just <- match.arg(just[1L], c("center", "centre", "top")) if(just == "centre") just <- "center" align <- match.arg(align[1L], c("center", "centre", "left", "right")) if(align == "centre") align <- "center" ### panel function for simple n, Y terminal node labeling rval <- function(node) { fill <- rep(fill, length.out = 2) lab <- extract_label(node) ## if gp is set, then an additional viewport may be ## required to appropriately evaluate strwidth unit if(!is.null(gp)) { outer_vp <- viewport(gp = gp) pushViewport(outer_vp) } if(is.null(height)) height <- length(lab) + 1L node_vp <- viewport(x = unit(0.5, "npc"), y = unit(if(just == "top") top else 0.5, "npc"), just = c("center", just), width = unit(1, "strwidth", nstr) * 1.1, height = unit(height, "lines"), name = paste("node_terminal", id_node(node), sep = ""), gp = if(is.null(gp)) gpar() else gp ) pushViewport(node_vp) grid.rect(gp = gpar(fill = fill[1])) for(i in seq_along(lab)) grid.text( x = switch(align, "center" = unit(0.5, "npc"), "left" = unit(1, "strwidth", "a"), "right" = unit(1, "npc") - unit(1, "strwidth", "a")), y = unit(length(lab) - i + 1, "lines"), lab[i], just = align) if(id) { nodeIDvp <- viewport(x = unit(0.5, "npc"), y = unit(1, "npc"), width = max(unit(1, "lines"), unit(1.3, "strwidth", nam[id_node(node)])), height = max(unit(1, "lines"), unit(1.3, "strheight", nam[id_node(node)]))) pushViewport(nodeIDvp) grid.rect(gp = gpar(fill = fill[2], lty = "solid")) grid.text(nam[id_node(node)]) popViewport() } if(is.null(gp)) upViewport() else upViewport(2) } return(rval) } class(node_terminal) <- "grapcon_generator" edge_simple <- function(obj, digits = 3, abbreviate = FALSE, justmin = Inf, just = c("alternate", "increasing", "decreasing", "equal"), fill = "white") { meta <- obj$data justfun <- function(i, split) { myjust <- if(mean(nchar(split)) > justmin) { match.arg(just, c("alternate", "increasing", "decreasing", "equal")) } else { "equal" } k <- length(split) rval <- switch(myjust, "equal" = rep.int(0, k), "alternate" = rep(c(0.5, -0.5), length.out = k), "increasing" = seq(from = -k/2, to = k/2, by = 1), "decreasing" = seq(from = k/2, to = -k/2, by = -1) ) unit(0.5, "npc") + unit(rval[i], "lines") } ### panel function for simple edge labelling function(node, i) { split <- character_split(split_node(node), meta, digits = digits)$levels y <- justfun(i, split) split <- split[i] # try() because the following won't work for split = "< 10 Euro", for example. if(any(grep(">", split) > 0) | any(grep("<", split) > 0)) { tr <- suppressWarnings(try(parse(text = paste("phantom(0)", split)), silent = TRUE)) if(!inherits(tr, "try-error")) split <- tr } grid.rect(y = y, gp = gpar(fill = fill, col = 0), width = unit(1, "strwidth", split)) grid.text(split, y = y, just = "center") } } class(edge_simple) <- "grapcon_generator" .plot_node <- function(node, xlim, ylim, nx, ny, terminal_panel, inner_panel, edge_panel, tnex = 2, drop_terminal = TRUE, debug = FALSE) { ### the workhorse for plotting trees ### set up viewport for terminal node if (is.terminal(node)) { x <- xlim[1] + diff(xlim)/2 y <- ylim[1] + 0.5 tn_vp <- viewport(x = unit(x, "native"), y = unit(y, "native") - unit(0.5, "lines"), width = unit(1, "native"), height = unit(tnex, "native") - unit(1, "lines"), just = c("center", "top"), name = paste("Node", id_node(node), sep = "")) pushViewport(tn_vp) if (debug) grid.rect(gp = gpar(lty = "dotted", col = 4)) terminal_panel(node) upViewport() return(NULL) } ## convenience function for computing relative position of splitting node pos_frac <- function(node) { if(is.terminal(node)) 0.5 else { width_kids <- sapply(kids_node(node), width) nk <- length(width_kids) rval <- if(nk %% 2 == 0) sum(width_kids[1:(nk/2)]) else mean(cumsum(width_kids)[nk/2 + c(-0.5, 0.5)]) rval/sum(width_kids) } } ## extract information split <- split_node(node) kids <- kids_node(node) width_kids <- sapply(kids, width) nk <- length(width_kids) ### position of inner node x0 <- xlim[1] + pos_frac(node) * diff(xlim) y0 <- max(ylim) ### relative positions of kids xfrac <- sapply(kids, pos_frac) x1lim <- xlim[1] + cumsum(c(0, width_kids))/sum(width_kids) * diff(xlim) x1 <- x1lim[1:nk] + xfrac * diff(x1lim) if (!drop_terminal) { y1 <- rep(y0 - 1, nk) } else { y1 <- ifelse(sapply(kids, is.terminal), tnex - 0.5, y0 - 1) } ### draw edges for(i in 1:nk) grid.lines(x = unit(c(x0, x1[i]), "native"), y = unit(c(y0, y1[i]), "native")) ### create viewport for inner node in_vp <- viewport(x = unit(x0, "native"), y = unit(y0, "native"), width = unit(1, "native"), height = unit(1, "native") - unit(1, "lines"), name = paste("Node", id_node(node), sep = "")) pushViewport(in_vp) if(debug) grid.rect(gp = gpar(lty = "dotted")) inner_panel(node) upViewport() ### position of labels y1max <- max(y1, na.rm = TRUE) ypos <- y0 - (y0 - y1max) * 0.5 xpos <- x0 - (x0 - x1) * 0.5 * (y0 - y1max)/(y0 - y1) ### setup labels for(i in 1:nk) { sp_vp <- viewport(x = unit(xpos[i], "native"), y = unit(ypos, "native"), width = unit(diff(x1lim)[i], "native"), height = unit(1, "lines"), name = paste("edge", id_node(node), "-", i, sep = "")) pushViewport(sp_vp) if(debug) grid.rect(gp = gpar(lty = "dotted", col = 2)) edge_panel(node, i) upViewport() } ## call workhorse for kids for(i in 1:nk) .plot_node(kids[[i]], c(x1lim[i], x1lim[i+1]), c(y1[i], 1), nx, ny, terminal_panel, inner_panel, edge_panel, tnex = tnex, drop_terminal = drop_terminal, debug = debug) } plot.party <- function(x, main = NULL, terminal_panel = node_terminal, tp_args = list(), inner_panel = node_inner, ip_args = list(), edge_panel = edge_simple, ep_args = list(), drop_terminal = FALSE, tnex = 1, newpage = TRUE, pop = TRUE, gp = gpar(), margins = NULL, ...) { ### extract tree node <- node_party(x) ### total number of terminal nodes nx <- width(node) ### maximal depth of the tree ny <- depth(node, root = TRUE) ## setup newpage if (newpage) grid.newpage() ## setup root viewport margins <- if(is.null(margins)) { c(1, 1, if(is.null(main)) 0 else 3, 1) } else { rep_len(margins, 4L) } root_vp <- viewport(layout = grid.layout(3, 3, heights = unit(c(margins[3L], 1, margins[1L]), c("lines", "null", "lines")), widths = unit(c(margins[2L], 1, margins[4L]), c("lines", "null", "lines"))), name = "root", gp = gp) pushViewport(root_vp) ## viewport for main title (if any) if (!is.null(main)) { main_vp <- viewport(layout.pos.col = 2, layout.pos.row = 1, name = "main") pushViewport(main_vp) grid.text(y = unit(1, "lines"), main, just = "center") upViewport() } ## setup viewport for tree tree_vp <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = c(0, nx), yscale = c(0, ny + (tnex - 1)), name = "tree") pushViewport(tree_vp) ### setup panel functions (if necessary) if(inherits(terminal_panel, "grapcon_generator")) terminal_panel <- do.call("terminal_panel", c(list(x), as.list(tp_args))) if(inherits(inner_panel, "grapcon_generator")) inner_panel <- do.call("inner_panel", c(list(x), as.list(ip_args))) if(inherits(edge_panel, "grapcon_generator")) edge_panel <- do.call("edge_panel", c(list(x), as.list(ep_args))) if((nx <= 1 & ny <= 1)) { if(is.null(margins)) margins <- rep.int(1.5, 4) pushViewport(plotViewport(margins = margins, name = paste("Node", id_node(node), sep = ""))) terminal_panel(node) } else { ## call the workhorse .plot_node(node, xlim = c(0, nx), ylim = c(0, ny - 0.5 + (tnex - 1)), nx = nx, ny = ny, terminal_panel = terminal_panel, inner_panel = inner_panel, edge_panel = edge_panel, tnex = tnex, drop_terminal = drop_terminal, debug = FALSE) } upViewport() if (pop) popViewport() else upViewport() } plot.constparty <- function(x, main = NULL, terminal_panel = NULL, tp_args = list(), inner_panel = node_inner, ip_args = list(), edge_panel = edge_simple, ep_args = list(), type = c("extended", "simple"), drop_terminal = NULL, tnex = NULL, newpage = TRUE, pop = TRUE, gp = gpar(), ...) { ### compute default settings type <- match.arg(type) if (type == "simple") { x <- as.simpleparty(x) if (is.null(terminal_panel)) terminal_panel <- node_terminal if (is.null(tnex)) tnex <- 1 if (is.null(drop_terminal)) drop_terminal <- FALSE if (is.null(tp_args) || length(tp_args) < 1L) { tp_args <- list(FUN = .make_formatinfo_simpleparty(x, digits = getOption("digits") - 4L, sep = "\n")) } else { if(is.null(tp_args$FUN)) { tp_args$FUN <- .make_formatinfo_simpleparty(x, digits = getOption("digits") - 4L, sep = "\n") } } } else { if (is.null(terminal_panel)) { cl <- class(x$fitted[["(response)"]]) if("factor" %in% cl) { terminal_panel <- node_barplot } else if("Surv" %in% cl) { terminal_panel <- node_surv } else if ("data.frame" %in% cl) { terminal_panel <- node_mvar if (is.null(tnex)) tnex <- 2 * NCOL(x$fitted[["(response)"]]) } else { terminal_panel <- node_boxplot } } if (is.null(tnex)) tnex <- 2 if (is.null(drop_terminal)) drop_terminal <- TRUE } plot.party(x, main = main, terminal_panel = terminal_panel, tp_args = tp_args, inner_panel = inner_panel, ip_args = ip_args, edge_panel = edge_panel, ep_args = ep_args, drop_terminal = drop_terminal, tnex = tnex, newpage = newpage, pop = pop, gp = gp, ...) } node_barplot <- function(obj, col = "black", fill = NULL, bg = "white", beside = NULL, ymax = NULL, ylines = NULL, widths = 1, gap = NULL, reverse = NULL, rot = 0, just = c("center", "top"), id = TRUE, mainlab = NULL, text = c("none", "horizontal", "vertical"), gp = gpar()) { ## extract response y <- obj$fitted[["(response)"]] stopifnot(is.factor(y) || isTRUE(all.equal(round(y), y)) || is.data.frame(y)) ## FIXME: This could be avoided by ## predict_party(obj, nodeids(obj, terminal = TRUE), type = "prob") ## but only for terminal nodes ^^^^ probs_and_n <- function(x) { y1 <- x$fitted[["(response)"]] if(!is.factor(y1)) { if(is.data.frame(y1)) { y1 <- t(as.matrix(y1)) } else { y1 <- factor(y1, levels = min(y, na.rm = TRUE):max(y, na.rm = TRUE)) } } w <- x$fitted[["(weights)"]] if(is.null(w)) w <- rep.int(1L, length(y1)) sumw <- if(is.factor(y1)) tapply(w, y1, sum) else drop(y1 %*% w) sumw[is.na(sumw)] <- 0 prob <- c(sumw/sum(w), sum(w)) names(prob) <- c(if(is.factor(y1)) levels(y1) else rownames(y1), "nobs") prob } probs <- do.call("rbind", nodeapply(obj, nodeids(obj), probs_and_n, by_node = FALSE)) nobs <- probs[, "nobs"] probs <- probs[, -ncol(probs), drop = FALSE] if(is.factor(y)) { ylevels <- levels(y) if(is.null(beside)) beside <- if(length(ylevels) < 3L) FALSE else TRUE if(is.null(ymax)) ymax <- if(beside) 1.1 else 1 if(is.null(gap)) gap <- if(beside) 0.1 else 0 } else { if(is.null(beside)) beside <- TRUE if(is.null(ymax)) ymax <- if(beside) max(probs) * 1.1 else max(probs) ylevels <- colnames(probs) if(length(ylevels) < 2) ylevels <- "" if(is.null(gap)) gap <- if(beside) 0.1 else 0 } if(is.null(reverse)) reverse <- !beside if(is.null(fill)) fill <- gray.colors(length(ylevels)) if(is.null(ylines)) ylines <- if(beside) c(3, 2) else c(1.5, 2.5) ## text labels? if(isTRUE(text)) text <- "horizontal" if(!is.character(text)) text <- "none" text <- match.arg(text, c("none", "horizontal", "vertical")) ### panel function for barplots in nodes rval <- function(node) { ## id nid <- id_node(node) ## parameter setup pred <- probs[nid,] if(reverse) { pred <- rev(pred) ylevels <- rev(ylevels) } np <- length(pred) nc <- if(beside) np else 1 fill <- rep(fill, length.out = np) widths <- rep(widths, length.out = nc) col <- rep(col, length.out = nc) ylines <- rep(ylines, length.out = 2) gap <- gap * sum(widths) yscale <- c(0, ymax) xscale <- c(0, sum(widths) + (nc+1)*gap) top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines[1], 1, ylines[2]), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste0("node_barplot", nid), gp = gp) pushViewport(top_vp) grid.rect(gp = gpar(fill = bg, col = 0)) ## main title top <- viewport(layout.pos.col=2, layout.pos.row=1) pushViewport(top) if (is.null(mainlab)) { mainlab <- if(id) { function(id, nobs) sprintf("Node %s (n = %s)", id, nobs) } else { function(id, nobs) sprintf("n = %s", nobs) } } if (is.function(mainlab)) { mainlab <- mainlab(names(obj)[nid], nobs[nid]) } grid.text(mainlab) popViewport() plot <- viewport(layout.pos.col=2, layout.pos.row=2, xscale=xscale, yscale=yscale, name = paste0("node_barplot", node$nodeID, "plot"), clip = FALSE) pushViewport(plot) if(beside) { xcenter <- cumsum(widths+gap) - widths/2 if(length(xcenter) > 1) grid.xaxis(at = xcenter, label = FALSE) grid.text(ylevels, x = xcenter, y = unit(-1, "lines"), just = just, rot = rot, default.units = "native", check.overlap = TRUE) grid.yaxis() grid.rect(gp = gpar(fill = "transparent")) grid.clip() for (i in 1:np) { grid.rect(x = xcenter[i], y = 0, height = pred[i], width = widths[i], just = c("center", "bottom"), default.units = "native", gp = gpar(col = col[i], fill = fill[i])) if(text != "none") { grid.text(x = xcenter[i], y = pred[i] + 0.025, label = paste(format(round(100 * pred[i], 1), nsmall = 1), "%", sep = ""), just = if(text == "horizontal") c("center", "bottom") else c("left", "center"), rot = if(text == "horizontal") 0 else 90, default.units = "native") } } } else { ycenter <- cumsum(pred) - pred if(np > 1) { grid.text(ylevels[1], x = unit(-1, "lines"), y = 0, just = c("left", "center"), rot = 90, default.units = "native", check.overlap = TRUE) grid.text(ylevels[np], x = unit(-1, "lines"), y = ymax, just = c("right", "center"), rot = 90, default.units = "native", check.overlap = TRUE) } if(np > 2) { grid.text(ylevels[-c(1,np)], x = unit(-1, "lines"), y = ycenter[-c(1,np)], just = "center", rot = 90, default.units = "native", check.overlap = TRUE) } grid.yaxis(main = FALSE) grid.clip() grid.rect(gp = gpar(fill = "transparent")) for (i in 1:np) { grid.rect(x = xscale[2]/2, y = ycenter[i], height = min(pred[i], ymax - ycenter[i]), width = widths[1], just = c("center", "bottom"), default.units = "native", gp = gpar(col = col[i], fill = fill[i])) } } grid.rect(gp = gpar(fill = "transparent")) upViewport(2) } return(rval) } class(node_barplot) <- "grapcon_generator" node_boxplot <- function(obj, col = "black", fill = "lightgray", bg = "white", width = 0.5, yscale = NULL, ylines = 3, cex = 0.5, id = TRUE, mainlab = NULL, gp = gpar()) { y <- obj$fitted[["(response)"]] stopifnot(is.numeric(y)) if (is.null(yscale)) yscale <- range(y) + c(-0.1, 0.1) * diff(range(y)) ### panel function for boxplots in nodes rval <- function(node) { ## extract data nid <- id_node(node) dat <- data_party(obj, nid) yn <- dat[["(response)"]] wn <- dat[["(weights)"]] if(is.null(wn)) wn <- rep(1, length(yn)) ## parameter setup x <- boxplot(rep.int(yn, wn), plot = FALSE) top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_boxplot", nid, sep = ""), gp = gp) pushViewport(top_vp) grid.rect(gp = gpar(fill = bg, col = 0)) ## main title top <- viewport(layout.pos.col=2, layout.pos.row=1) pushViewport(top) if (is.null(mainlab)) { mainlab <- if(id) { function(id, nobs) sprintf("Node %s (n = %s)", id, nobs) } else { function(id, nobs) sprintf("n = %s", nobs) } } if (is.function(mainlab)) { mainlab <- mainlab(names(obj)[nid], sum(wn)) } grid.text(mainlab) popViewport() plot <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = c(0, 1), yscale = yscale, name = paste0("node_boxplot", nid, "plot"), clip = FALSE) pushViewport(plot) grid.yaxis() grid.rect(gp = gpar(fill = "transparent")) grid.clip() xl <- 0.5 - width/4 xr <- 0.5 + width/4 ## box & whiskers grid.lines(unit(c(xl, xr), "npc"), unit(x$stats[1], "native"), gp = gpar(col = col)) grid.lines(unit(0.5, "npc"), unit(x$stats[1:2], "native"), gp = gpar(col = col, lty = 2)) grid.rect(unit(0.5, "npc"), unit(x$stats[2], "native"), width = unit(width, "npc"), height = unit(diff(x$stats[c(2, 4)]), "native"), just = c("center", "bottom"), gp = gpar(col = col, fill = fill)) grid.lines(unit(c(0.5 - width/2, 0.5+width/2), "npc"), unit(x$stats[3], "native"), gp = gpar(col = col, lwd = 2)) grid.lines(unit(0.5, "npc"), unit(x$stats[4:5], "native"), gp = gpar(col = col, lty = 2)) grid.lines(unit(c(xl, xr), "npc"), unit(x$stats[5], "native"), gp = gpar(col = col)) ## outlier n <- length(x$out) if (n > 0) { index <- 1:n ## which(x$out > yscale[1] & x$out < yscale[2]) if (length(index) > 0) grid.points(unit(rep.int(0.5, length(index)), "npc"), unit(x$out[index], "native"), size = unit(cex, "char"), gp = gpar(col = col)) } upViewport(2) } return(rval) } class(node_boxplot) <- "grapcon_generator" node_surv <- function(obj, col = "black", bg = "white", yscale = c(0, 1), ylines = 2, id = TRUE, mainlab = NULL, gp = gpar(), ...) { ## extract response y <- obj$fitted[["(response)"]] stopifnot(inherits(y, "Surv")) ## helper functions mysurvfit <- function(y, weights, ...) survfit(y ~ 1, weights = weights) ### structure( ### survival:::survfitKM(x = gl(1, NROW(y)), y = y, casewt = weights, ...), ### class = "survfit") dostep <- function(x, y) { ### create a step function based on x, y coordinates ### modified from `survival:print.survfit' if (is.na(x[1] + y[1])) { x <- x[-1] y <- y[-1] } n <- length(x) if (n > 2) { # replace verbose horizonal sequences like # (1, .2), (1.4, .2), (1.8, .2), (2.3, .2), (2.9, .2), (3, .1) # with (1, .2), (3, .1). They are slow, and can smear the looks # of the line type. dupy <- c(TRUE, diff(y[-n]) !=0, TRUE) n2 <- sum(dupy) #create a step function xrep <- rep(x[dupy], c(1, rep(2, n2-1))) yrep <- rep(y[dupy], c(rep(2, n2-1), 1)) RET <- list(x = xrep, y = yrep) } else { if (n == 1) { RET <- list(x = x, y = y) } else { RET <- list(x = x[c(1,2,2)], y = y[c(1,1,2)]) } } return(RET) } ### panel function for Kaplan-Meier curves in nodes rval <- function(node) { ## extract data nid <- id_node(node) dat <- data_party(obj, nid) yn <- dat[["(response)"]] wn <- dat[["(weights)"]] if(is.null(wn)) wn <- rep(1, NROW(yn)) ## get Kaplan-Meier curver in node km <- mysurvfit(yn, weights = wn, ...) a <- dostep(km$time, km$surv) ## set up plot yscale <- yscale xscale <- c(0, max(y[,1], na.rm = TRUE)) top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_surv", nid, sep = ""), gp = gp) pushViewport(top_vp) grid.rect(gp = gpar(fill = bg, col = 0)) ## main title top <- viewport(layout.pos.col=2, layout.pos.row=1) pushViewport(top) if (is.null(mainlab)) { mainlab <- if(id) { function(id, nobs) sprintf("Node %s (n = %s)", id, nobs) } else { function(id, nobs) sprintf("n = %s", nobs) } } if (is.function(mainlab)) { mainlab <- mainlab(nid, sum(wn)) } grid.text(mainlab) popViewport() plot <- viewport(layout.pos.col=2, layout.pos.row=2, xscale=xscale, yscale = yscale, name = paste0("node_surv", nid, "plot"), clip = FALSE) pushViewport(plot) grid.xaxis() grid.yaxis() grid.rect(gp = gpar(fill = "transparent")) grid.clip() grid.lines(unit(a$x, "native"), unit(a$y, "native"), gp = gpar(col = col)) upViewport(2) } return(rval) } class(node_surv) <- "grapcon_generator" node_ecdf <- function(obj, col = "black", bg = "white", ylines = 2, id = TRUE, mainlab = NULL, gp = gpar(), ...) { ## extract response y <- obj$fitted[["(response)"]] stopifnot(inherits(y, "numeric") || inherits(y, "integer")) dostep <- function(f) { x <- knots(f) y <- f(x) ### create a step function based on x, y coordinates ### modified from `survival:print.survfit' if (is.na(x[1] + y[1])) { x <- x[-1] y <- y[-1] } n <- length(x) if (n > 2) { # replace verbose horizonal sequences like # (1, .2), (1.4, .2), (1.8, .2), (2.3, .2), (2.9, .2), (3, .1) # with (1, .2), (3, .1). They are slow, and can smear the looks # of the line type. dupy <- c(TRUE, diff(y[-n]) !=0, TRUE) n2 <- sum(dupy) #create a step function xrep <- rep(x[dupy], c(1, rep(2, n2-1))) yrep <- rep(y[dupy], c(rep(2, n2-1), 1)) RET <- list(x = xrep, y = yrep) } else { if (n == 1) { RET <- list(x = x, y = y) } else { RET <- list(x = x[c(1,2,2)], y = y[c(1,1,2)]) } } return(RET) } ### panel function for ecdf in nodes rval <- function(node) { ## extract data nid <- id_node(node) dat <- data_party(obj, nid) yn <- dat[["(response)"]] wn <- dat[["(weights)"]] if(is.null(wn)) wn <- rep(1, NROW(yn)) ## get ecdf in node f <- .pred_ecdf(yn, wn) a <- dostep(f) ## set up plot yscale <- c(0, 1) xscale <- range(y, na.rm = TRUE) a$x <- c(xscale[1], a$x[1], a$x, xscale[2]) a$x <- a$x - min(a$x) a$x <- a$x / max(a$x) a$y <- c(0, 0, a$y, 1) top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_ecdf", nid, sep = ""), gp = gp) pushViewport(top_vp) grid.rect(gp = gpar(fill = bg, col = 0)) ## main title top <- viewport(layout.pos.col=2, layout.pos.row=1) pushViewport(top) if (is.null(mainlab)) { mainlab <- if(id) { function(id, nobs) sprintf("Node %s (n = %s)", id, nobs) } else { function(id, nobs) sprintf("n = %s", nobs) } } if (is.function(mainlab)) { mainlab <- mainlab(nid, sum(wn)) } grid.text(mainlab) popViewport() plot <- viewport(layout.pos.col=2, layout.pos.row=2, xscale=xscale, yscale=yscale, name = paste0("node_surv", nid, "plot"), clip = FALSE) pushViewport(plot) grid.xaxis() grid.yaxis() grid.rect(gp = gpar(fill = "transparent")) grid.clip() grid.lines(a$x, a$y, gp = gpar(col = col)) upViewport(2) } return(rval) } class(node_ecdf) <- "grapcon_generator" node_mvar <- function(obj, which = NULL, id = TRUE, pop = TRUE, ylines = NULL, mainlab = NULL, varlab = TRUE, bg = "white", ...) { ## obtain dependent variables y <- obj$fitted[["(response)"]] ## fitted node ids fitted <- obj$fitted[["(fitted)"]] ## number of panels needed if(is.null(which)) which <- 1L:NCOL(y) k <- length(which) rval <- function(node) { tid <- id_node(node) nobs <- .nobs_party(obj, id = tid) ## set up top viewport top_vp <- viewport(layout = grid.layout(nrow = k, ncol = 2, widths = unit(c(ylines, 1), c("lines", "null")), heights = unit(k, "null")), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_mvar", tid, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = bg, col = 0)) ## main title if (is.null(mainlab)) { mainlab <- if(id) { function(id, nobs) sprintf("Node %s (n = %s)", id, nobs) } else { function(id, nobs) sprintf("n = %s", nobs) } } if (is.function(mainlab)) { mainlab <- mainlab(tid, nobs) } for(i in 1L:k) { tmp <- obj tmp$fitted[["(response)"]] <- y[,which[i]] if(varlab) { nm <- names(y)[which[i]] if(i == 1L) nm <- paste(mainlab, nm, sep = ": ") } else { nm <- if(i == 1L) mainlab else "" } pfun <- switch(sapply(y, class)[which[i]], "Surv" = node_surv(tmp, id = id, mainlab = nm, ...), "factor" = node_barplot(tmp, id = id, mainlab = nm, ...), "ordered" = node_barplot(tmp, id = id, mainlab = nm, ...), node_boxplot(tmp, id = id, mainlab = nm, ...)) ## select panel plot_vpi <- viewport(layout.pos.col = 2L, layout.pos.row = i) pushViewport(plot_vpi) ## call panel function pfun(node) if(pop) popViewport() else upViewport() } if(pop) popViewport() else upViewport() } return(rval) } class(node_mvar) <- "grapcon_generator" partykit/R/prune.R0000644000176200001440000000245014172230000013564 0ustar liggesusers nodeprune.party <- function(x, ids, ...) { ### map names to nodeids if (!is.numeric(ids)) ids <- match(ids, names(x)) stopifnot(ids %in% nodeids(x)) ### compute indices path to each node ### to be pruned off idxs <- lapply(ids, .get_path, obj = node_party(x)) ### [[.party is NOT [[.list cls <- class(x) x <- unclass(x) ni <- which(names(x) == "node") for (i in 1:length(idxs)) { idx <- c(ni, idxs[[i]]) ### check if we already pruned-off this node tmp <- try(x[[idx]], silent = TRUE) if (inherits(tmp, "try-error")) next() ### node ids of off-pruned daugther nodes idrm <- nodeids(x[[idx]])[-1] ### prune node by introducing a "new" terminal node x[[idx]] <- partynode(id = id_node(x[[idx]]), info = info_node(x[[idx]])) ### constparty only: make sure the node ids in ### fitted are corrected if (length(idrm) > 0) { if(!is.null(x$fitted) && "(fitted)" %in% names(x$fitted)) { j <- x$fitted[["(fitted)"]] %in% idrm x$fitted[["(fitted)"]][j] <- ids[i] } } } ### reindex to 1:max(nodeid) class(x) <- cls oldids <- nodeids(x) newids <- 1:length(nodeids(x)) nodeids(x) <- newids ### this takes also care of $fitted! return(x) } partykit/R/party.R0000644000176200001440000005370614415214357013625 0ustar liggesusers## FIXME: data in party ## - currently assumed to be a data.frame ## - potentially empty ## - the following are all assumed to work: ## dim(data), names(data) ## sapply(data, class), lapply(data, levels) ## - potentially these need to be modified if data/terms ## should be able to deal with data bases party <- function(node, data, fitted = NULL, terms = NULL, names = NULL, info = NULL) { stopifnot(inherits(node, "partynode")) stopifnot(inherits(data, "data.frame")) ### make sure all split variables are there ids <- nodeids(node)[!nodeids(node) %in% nodeids(node, terminal = TRUE)] varids <- unique(unlist(nodeapply(node, ids = ids, FUN = function(x) varid_split(split_node(x))))) stopifnot(varids %in% 1:ncol(data)) if(!is.null(fitted)) { stopifnot(inherits(fitted, "data.frame")) stopifnot(nrow(data) == 0L | nrow(data) == nrow(fitted)) # try to provide default variable "(fitted)" if(nrow(data) > 0L) { if(!("(fitted)" %in% names(fitted))) fitted[["(fitted)"]] <- fitted_node(node, data = data) } else { stopifnot("(fitted)" == names(fitted)[1L]) } nt <- nodeids(node, terminal = TRUE) stopifnot(all(fitted[["(fitted)"]] %in% nt)) node <- as.partynode(node, from = 1L) nt2 <- nodeids(node, terminal = TRUE) fitted[["(fitted)"]] <- nt2[match(fitted[["(fitted)"]], nt)] } else { node <- as.partynode(node, from = 1L) # default "(fitted)" if(nrow(data) > 0L & missing(fitted)) fitted <- data.frame("(fitted)" = fitted_node(node, data = data), check.names = FALSE) } party <- list(node = node, data = data, fitted = fitted, terms = NULL, names = NULL, info = info) class(party) <- "party" if(!is.null(terms)) { stopifnot(inherits(terms, "terms")) party$terms <- terms } if (!is.null(names)) { n <- length(nodeids(party, terminal = FALSE)) if (length(names) != n) stop("invalid", " ", sQuote("names"), " ", "argument") party$names <- names } party } length.party <- function(x) length(nodeids(x)) names.party <- function(x) .names_party(x) "names<-.party" <- function(x, value) { n <- length(nodeids(x, terminal = FALSE)) if (!is.null(value) && length(value) != n) stop("invalid", " ", sQuote("names"), " ", "argument") x$names <- value x } .names_party <- function(party) { names <- party$names if (is.null(names)) names <- as.character(nodeids(party, terminal = FALSE)) names } node_party <- function(party) { stopifnot(inherits(party, "party")) party$node } is.constparty <- function(party) { stopifnot(inherits(party, "party")) if (!is.null(party$fitted)) return(all(c("(fitted)", "(response)") %in% names(party$fitted))) return(FALSE) } as.constparty <- function(obj, ...) { if(!inherits(obj, "party")) obj <- as.party(obj) if (!is.constparty(obj)) { if(is.null(obj$fitted)) obj$fitted <- data.frame("(fitted)" = predict(obj, type = "node"), check.names = FALSE) if(!("(fitted)" %in% names(obj$fitted))) obj$fitted["(fitted)"] <- predict(obj, type = "node") if(!("(response)" %in% names(obj$fitted))) obj$fitted["(response)"] <- model.response(model.frame(obj)) if(!("(weights)" %in% names(obj$fitted))) { w <- model.weights(model.frame(obj)) if(is.null(w) && any(w != 1L)) obj$fitted["(weights)"] <- w } } if (is.constparty(obj)) { ret <- obj class(ret) <- c("constparty", class(obj)) return(ret) } stop("cannot coerce object of class", " ", sQuote(class(obj)), " ", "to", " ", sQuote("constparty")) } "[.party" <- "[[.party" <- function(x, i, ...) { if (is.character(i) && !is.null(names(x))) i <- which(names(x) %in% i) stopifnot(length(i) == 1 & is.numeric(i)) stopifnot(i <= length(x) & i >= 1) i <- as.integer(i) dat <- data_party(x, i) if (!is.null(x$fitted)) { findx <- which("(fitted)" == names(dat))[1] fit <- dat[,findx:ncol(dat), drop = FALSE] dat <- dat[,-(findx:ncol(dat)), drop = FALSE] if (ncol(dat) == 0) dat <- x$data } else { fit <- NULL dat <- x$data } nam <- names(x)[nodeids(x, from = i, terminal = FALSE)] recFun <- function(node) { if (id_node(node) == i) return(node) kid <- sapply(kids_node(node), id_node) return(recFun(node[[max(which(kid <= i))]])) } node <- recFun(node_party(x)) ret <- party(node = node, data = dat, fitted = fit, terms = x$terms, names = nam, info = x$info) class(ret) <- class(x) ret } nodeids <- function(obj, ...) UseMethod("nodeids") nodeids.partynode <- function(obj, from = NULL, terminal = FALSE, ...) { if(is.null(from)) from <- id_node(obj) id <- function(node, record = TRUE, terminal = FALSE) { if(!record) return(NULL) if(!terminal) return(id_node(node)) else if(is.terminal(node)) return(id_node(node)) else return(NULL) } rid <- function(node, record = TRUE, terminal = FALSE) { myid <- id(node, record = record, terminal = terminal) if(is.terminal(node)) return(myid) kids <- kids_node(node) kids_record <- if(record) rep(TRUE, length(kids)) else sapply(kids, id_node) == from return(c(myid, unlist(lapply(1:length(kids), function(i) rid(kids[[i]], record = kids_record[i], terminal = terminal))) )) } return(rid(obj, from == id_node(obj), terminal)) } nodeids.party <- function(obj, from = NULL, terminal = FALSE, ...) nodeids(node_party(obj), from = from, terminal = terminal, ...) nodeapply <- function(obj, ids = 1, FUN = NULL, ...) UseMethod("nodeapply") nodeapply.party <- function(obj, ids = 1, FUN = NULL, by_node = TRUE, ...) { stopifnot(isTRUE(all.equal(ids, round(ids)))) ids <- as.integer(ids) if(is.null(FUN)) FUN <- function(x, ...) x if (length(ids) == 0) return(NULL) if (by_node) { rval <- nodeapply(node_party(obj), ids = ids, FUN = FUN, ...) } else { rval <- lapply(ids, function(i) FUN(obj[[i]], ...)) } names(rval) <- names(obj)[ids] return(rval) } nodeapply.partynode <- function(obj, ids = 1, FUN = NULL, ...) { stopifnot(isTRUE(all.equal(ids, round(ids)))) ids <- as.integer(ids) if(is.null(FUN)) FUN <- function(x, ...) x if (length(ids) == 0) return(NULL) rval <- vector(mode = "list", length = length(ids)) rval_id <- rep(0, length(ids)) i <- 1 recFUN <- function(node, ...) { if(id_node(node) %in% ids) { rval_id[i] <<- id_node(node) rval[[i]] <<- FUN(node, ...) i <<- i + 1 } kids <- kids_node(node) if(length(kids) > 0) { for(j in 1:length(kids)) recFUN(kids[[j]]) } invisible(TRUE) } foo <- recFUN(obj) rval <- rval[match(ids, rval_id)] return(rval) } predict.party <- function(object, newdata = NULL, perm = NULL, ...) { ### compute fitted node ids first fitted <- if(is.null(newdata) && is.null(perm)) { object$fitted[["(fitted)"]] } else { if (is.null(newdata)) newdata <- model.frame(object) terminal <- nodeids(object, terminal = TRUE) if(max(terminal) == 1L) { rep.int(1L, NROW(newdata)) } else { inner <- 1L:max(terminal) inner <- inner[-terminal] primary_vars <- nodeapply(object, ids = inner, by_node = TRUE, FUN = function(node) { varid_split(split_node(node)) }) surrogate_vars <- nodeapply(object, ids = inner, by_node = TRUE, FUN = function(node) { surr <- surrogates_node(node) if(is.null(surr)) return(NULL) else return(sapply(surr, varid_split)) }) vnames <- names(object$data) ### the splits of nodes with a primary split in perm ### will be permuted if (!is.null(perm)) { if (is.character(perm)) { stopifnot(all(perm %in% vnames)) perm <- match(perm, vnames) } else { ### perm is a named list of factors coding strata ### (for varimp(..., conditional = TRUE) stopifnot(all(names(perm) %in% vnames)) stopifnot(all(sapply(perm, is.factor))) tmp <- vector(mode = "list", length = length(vnames)) tmp[match(names(perm), vnames)] <- perm perm <- tmp } } ## ## FIXME: the is.na() call takes loooong on large data sets ## unames <- if(any(sapply(newdata, is.na))) ## vnames[unique(unlist(c(primary_vars, surrogate_vars)))] ## else ## vnames[unique(unlist(primary_vars))] unames <- vnames[unique(unlist(c(primary_vars, surrogate_vars)))] vclass <- structure(lapply(object$data, class), .Names = vnames) ndnames <- names(newdata) ndclass <- structure(lapply(newdata, class), .Names = ndnames) checkclass <- all(sapply(unames, function(x) isTRUE(all.equal(vclass[[x]], ndclass[[x]])))) factors <- sapply(unames, function(x) inherits(object$data[[x]], "factor")) checkfactors <- all(sapply(unames[factors], function(x) isTRUE(all.equal(levels(object$data[[x]]), levels(newdata[[x]]))))) ## FIXME: inform about wrong classes / factor levels? if(all(unames %in% ndnames) && checkclass && checkfactors) { vmatch <- match(vnames, ndnames) fitted_node(node_party(object), data = newdata, vmatch = vmatch, perm = perm) } else { if (!is.null(object$terms)) { ### this won't work for multivariate responses ### xlev <- lapply(unames[factors], function(x) levels(object$data[[x]])) names(xlev) <- unames[factors] mf <- model.frame(delete.response(object$terms), newdata, xlev = xlev) fitted_node(node_party(object), data = mf, vmatch = match(vnames, names(mf)), perm = perm) } else stop("") ## FIXME: write error message } } } ### compute predictions predict_party(object, fitted, newdata, ...) } predict_party <- function(party, id, newdata = NULL, ...) UseMethod("predict_party") ### do nothing expect returning the fitted ids predict_party.default <- function(party, id, newdata = NULL, FUN = NULL, ...) { if (length(list(...)) > 1) warning("argument(s)", " ", sQuote(names(list(...))), " ", "have been ignored") ## get observation names: either node names or ## observation names from newdata nam <- if(is.null(newdata)) { if(is.null(rnam <- rownames(data_party(party)))) names(party)[id] else rnam } else { rownames(newdata) } if(length(nam) != length(id)) nam <- NULL if (!is.null(FUN)) return(.simplify_pred(nodeapply(party, nodeids(party, terminal = TRUE), FUN, by_node = TRUE), id, nam)) ## special case: fitted ids return(structure(id, .Names = nam)) } predict_party.constparty <- function(party, id, newdata = NULL, type = c("response", "prob", "quantile", "density", "node"), at = if (type == "quantile") c(0.1, 0.5, 0.9), FUN = NULL, simplify = TRUE, ...) { ## extract fitted information response <- party$fitted[["(response)"]] weights <- party$fitted[["(weights)"]] fitted <- party$fitted[["(fitted)"]] if (is.null(weights)) weights <- rep(1, NROW(response)) ## get observation names: either node names or ## observation names from newdata nam <- if(is.null(newdata)) names(party)[id] else rownames(newdata) if(length(nam) != length(id)) nam <- NULL ## match type type <- match.arg(type) ## special case: fitted ids if(type == "node") return(structure(id, .Names = nam)) ### multivariate response if (is.data.frame(response)) { ret <- lapply(response, function(r) { ret <- .predict_party_constparty(node_party(party), fitted = fitted, response = r, weights, id = id, type = type, at = at, FUN = FUN, ...) if (simplify) .simplify_pred(ret, id, nam) else ret }) if (all(sapply(ret, is.atomic))) ret <- as.data.frame(ret) names(ret) <- colnames(response) return(ret) } ### univariate response ret <- .predict_party_constparty(node_party(party), fitted = fitted, response = response, weights = weights, id = id, type = type, at = at, FUN = FUN, ...) if (simplify) .simplify_pred(ret, id, nam) else ret[as.character(id)] } ### functions for node prediction based on fitted / response .pred_Surv <- function(y, w) { if (length(y) == 0) return(NA) survfit(y ~ 1, weights = w, subset = w > 0) } .pred_Surv_response <- function(y, w) { if (length(y) == 0) return(NA) .median_survival_time(.pred_Surv(y, w)) } .pred_factor <- function(y, w) { lev <- levels(y) sumw <- tapply(w, y, sum) sumw[is.na(sumw)] <- 0 prob <- sumw / sum(w) names(prob) <- lev return(prob) } .pred_factor_response <- function(y, w) { prob <- .pred_factor(y, w) return(factor(which.max(prob), levels = 1:nlevels(y), labels = levels(y), ordered = is.ordered(y))) return(prob) } .pred_numeric_response <- function(y, w) weighted.mean(y, w, na.rm = TRUE) .pred_ecdf <- function(y, w) { if (length(y) == 0) return(NA) iw <- as.integer(round(w)) if (max(abs(w - iw)) < sqrt(.Machine$double.eps)) { y <- rep(y, w) return(ecdf(y)) } else { stop("cannot compute empirical distribution function with non-integer weights") } } .pred_quantile <- function(y, w) { y <- rep(y, w) function(p, ...) quantile(y, probs = p, ...) } .pred_density <- function(y, w) { ### we only have integer-valued weights and density complains ### about weights since R 4.3.0 (because bandwidth selection doesn't ### work with weights) yw <- rep(y, w) d <- density(yw) approxfun(d[1:2], rule = 2) } ### workhorse: compute predictions based on fitted / response data .predict_party_constparty <- function(node, fitted, response, weights, id = id, type = c("response", "prob", "quantile", "density"), at = if (type == "quantile") c(0.1, 0.5, 0.9), FUN = NULL, ...) { type <- match.arg(type) if (is.null(FUN)) { rtype <- class(response)[1] if (rtype == "ordered") rtype <- "factor" if (rtype == "integer") rtype <- "numeric" if (rtype == "AsIs") rtype <- "numeric" if (type %in% c("quantile", "density") && rtype != "numeric") stop("quantile and density estimation currently only implemented for numeric responses") FUN <- switch(rtype, "Surv" = if (type == "response") .pred_Surv_response else .pred_Surv, "factor" = if (type == "response") .pred_factor_response else .pred_factor, "numeric" = switch(type, "response" = .pred_numeric_response, "prob" = .pred_ecdf, "quantile" = .pred_quantile, "density" = .pred_density) ) } ## empirical distribution in each leaf if (all(id %in% fitted)) { tab <- tapply(1:NROW(response), fitted, function(i) FUN(response[i], weights[i]), simplify = FALSE) } else { ### id may also refer to inner nodes tab <- as.array(lapply(sort(unique(id)), function(i) { index <- fitted %in% nodeids(node, i, terminal = TRUE) ret <- FUN(response[index], weights[index]) ### no information about i in fitted if (all(!index)) ret[1] <- NA return(ret) })) names(tab) <- as.character(sort(unique(id))) } if (inherits(tab[[1]], "function") && !is.null(at)) tab <- lapply(tab, function(f) f(at)) tn <- names(tab) dim(tab) <- NULL names(tab) <- tn tab } ### simplify structure of predictions .simplify_pred <- function(tab, id, nam) { if (all(sapply(tab, length) == 1) & all(sapply(tab, is.atomic))) { ret <- do.call("c", tab) names(ret) <- names(tab) ### R 4.1.x allows to call c() on factors, this is needed for ### backward-compatibility ret <- if (is.factor(tab[[1]]) & !is.factor(ret)) factor(ret[as.character(id)], levels = 1:length(levels(tab[[1]])), labels = levels(tab[[1]]), ordered = is.ordered(tab[[1]])) else ret[as.character(id)] names(ret) <- nam } else if (length(unique(sapply(tab, length))) == 1 & all(sapply(tab, is.numeric))) { ret <- matrix(unlist(tab), nrow = length(tab), byrow = TRUE) colnames(ret) <- names(tab[[1]]) rownames(ret) <- names(tab) ret <- ret[as.character(id),, drop = FALSE] rownames(ret) <- nam } else { ret <- tab[as.character(id)] names(ret) <- nam } ret } data_party <- function(party, id = 1L) UseMethod("data_party") data_party.default <- function(party, id = 1L) { extract <- function(id) { if(is.null(party$fitted)) if(nrow(party$data) == 0) return(NULL) else stop("cannot subset data without fitted ids") ### which terminal nodes follow node number id? nt <- nodeids(party, id, terminal = TRUE) wi <- party$fitted[["(fitted)"]] %in% nt ret <- if (nrow(party$data) == 0) subset(party$fitted, wi) else subset(cbind(party$data, party$fitted), wi) ret } if (length(id) > 1) return(lapply(id, extract)) else return(extract(id)) } width.party <- function(x, ...) { width(node_party(x), ...) } depth.party <- function(x, root = FALSE, ...) { depth(node_party(x), root = root, ...) } getCall.party <- function(x, ...) { x$info$call } getCall.constparties <- function(x, ...) { x$info$call } formula.party <- function(x, ...) { x <- terms(x) NextMethod() } model.frame.party <- function(formula, ...) { mf <- formula$data if(nrow(mf) > 0L) return(mf) dots <- list(...) nargs <- dots[match(c("data", "na.action", "subset"), names(dots), 0L)] mf <- getCall(formula) mf <- mf[c(1L, match(c("formula", "data", "subset", "na.action"), names(mf), 0L))] mf$drop.unused.levels <- TRUE mf[[1L]] <- quote(stats::model.frame) mf[names(nargs)] <- nargs if(is.null(env <- environment(terms(formula)))) env <- parent.frame() eval(mf, env) } nodeprune <- function(x, ids, ...) UseMethod("nodeprune") nodeprune.partynode <- function(x, ids, ...) { stopifnot(ids %in% nodeids(x)) ### compute indices path to each node ### to be pruned off idxs <- lapply(ids, .get_path, obj = x) ### [[.partynode is NOT [[.list cls <- class(x) x <- unclass(x) for (i in 1:length(idxs)) { ## path to be pruned idx <- idxs[[i]] if(!is.null(idx)) { ### check if we already pruned-off this node tmp <- try(x[[idx]], silent = TRUE) if(inherits(tmp, "try-error")) next() ### prune node by introducing a "new" terminal node x[[idx]] <- partynode(id = id_node(tmp), info = info_node(tmp)) } else { ## if idx path is NULL prune everything x[2L:4L] <- NULL } } class(x) <- cls return(as.partynode(x, from = 1L)) } nodeprune.default <- function(x, ids, ...) stop("No", sQuote("nodeprune"), "method for class", class(x), "implemented") .list.rules.party <- function(x, i = NULL, ...) { if (is.null(i)) i <- nodeids(x, terminal = TRUE) if (length(i) > 1) { ret <- sapply(i, .list.rules.party, x = x) names(ret) <- if (is.character(i)) i else names(x)[i] return(ret) } if (is.character(i) && !is.null(names(x))) i <- which(names(x) %in% i) stopifnot(length(i) == 1 & is.numeric(i)) stopifnot(i <= length(x) & i >= 1) i <- as.integer(i) dat <- data_party(x, i) if (!is.null(x$fitted)) { findx <- which("(fitted)" == names(dat))[1] fit <- dat[,findx:ncol(dat), drop = FALSE] dat <- dat[,-(findx:ncol(dat)), drop = FALSE] if (ncol(dat) == 0) dat <- x$data } else { fit <- NULL dat <- x$data } rule <- c() recFun <- function(node) { if (id_node(node) == i) return(NULL) kid <- sapply(kids_node(node), id_node) whichkid <- max(which(kid <= i)) split <- split_node(node) ivar <- varid_split(split) svar <- names(dat)[ivar] index <- index_split(split) if (is.factor(dat[, svar])) { if (is.null(index)) index <- ((1:nlevels(dat[, svar])) > breaks_split(split)) + 1 slevels <- levels(dat[, svar])[index == whichkid] srule <- paste(svar, " %in% c(\"", paste(slevels, collapse = "\", \"", sep = ""), "\")", sep = "") } else { if (is.null(index)) index <- 1:length(kid) breaks <- cbind(c(-Inf, breaks_split(split)), c(breaks_split(split), Inf)) sbreak <- breaks[index == whichkid,] right <- right_split(split) srule <- c() if (is.finite(sbreak[1])) srule <- c(srule, paste(svar, ifelse(right, ">", ">="), sbreak[1])) if (is.finite(sbreak[2])) srule <- c(srule, paste(svar, ifelse(right, "<=", "<"), sbreak[2])) srule <- paste(srule, collapse = " & ") } rule <<- c(rule, srule) return(recFun(node[[whichkid]])) } node <- recFun(node_party(x)) paste(rule, collapse = " & ") } partykit/R/as.party.R0000644000176200001440000001702714172230000014202 0ustar liggesusersas.party <- function(obj, ...) UseMethod("as.party") as.party.rpart <- function(obj, data = TRUE, ...) { ff <- obj$frame n <- nrow(ff) ### it is no longer allowed to overwrite rpart::model.frame.rpart ### make sure to use our own implementation ### which works without `model = TRUE' in the rpart call mf <- model_frame_rpart(obj) ## check if any of the variables in the model frame is a "character" ## and convert to "factor" if necessary for(i in which(sapply(mf, function(x) class(x)[1L]) == "character")) mf[[i]] <- factor(mf[[i]]) rpart_fitted <- function() { ret <- as.data.frame(matrix(nrow = NROW(mf), ncol = 0)) ret[["(fitted)"]] <- obj$where ret[["(response)"]] <- model.response(mf) ret[["(weights)"]] <- model.weights(mf) ret } fitted <- rpart_fitted() # special case of no splits if (n == 1) { node <- partynode(1L) } else { is.leaf <- (ff$var == "") vnames <- ff$var[!is.leaf] #the variable names for the primary splits index <- cumsum(c(1, ff$ncompete + ff$nsurrogate + 1*(!is.leaf))) splitindex <- list() splitindex$primary <- numeric(n) splitindex$primary[!is.leaf] <- index[c(!is.leaf, FALSE)] splitindex$surrogate <- lapply(1L:n, function(i) { prim <- splitindex$primary[i] if (prim < 1 || ff[i, "nsurrogate"] == 0) return(NULL) else return(prim + ff[i, "ncompete"] + 1L:ff[i, "nsurrogate"]) }) rpart_kids <- function(i) { if (is.leaf[i]) return(NULL) else return(c(i + 1L, which((cumsum(!is.leaf[-(1L:i)]) + 1L) == cumsum(is.leaf[-(1L:i)]))[1L] + 1L + i)) } rpart_onesplit <- function(j) { if (j < 1) return(NULL) idj <- which(rownames(obj$split)[j] == names(mf)) ### numeric if (abs(obj$split[j, "ncat"]) == 1) { ret <- partysplit(varid = idj, breaks = as.double(obj$split[j, "index"]), right = FALSE, index = if(obj$split[j, "ncat"] > 0) 2L:1L) } else { index <- obj$csplit[obj$split[j, "index"],] mfj <- mf[, rownames(obj$split)[j]] ### csplit has columns 1L:max(nlevels) for all factors ### index <- index[1L:obj$split[j, "ncat"]] ??? safer ??? index <- index[1L:nlevels(mfj)] index[index == 2L] <- NA ### level not present in split index[index == 3L] <- 2L ### 1..left, 3..right if(inherits(mfj, "ordered")) { ret <- partysplit(varid = idj, breaks = which(diff(index) != 0L) + 1L, right = FALSE, index = unique(index)) } else { ret <- partysplit(varid = idj, index = as.integer(index)) } } ret } rpart_split <- function(i) rpart_onesplit(splitindex$primary[i]) rpart_surrogates <- function(i) lapply(splitindex$surrogate[[i]], rpart_onesplit) rpart_node <- function(i) { if (is.null(rpart_kids(i))) return(partynode(as.integer(i))) nd <- partynode(as.integer(i), split = rpart_split(i), kids = lapply(rpart_kids(i), rpart_node), surrogates = rpart_surrogates(i)) ### determine majority for (non-random) splitting left <- nodeids(kids_node(nd)[[1L]], terminal = TRUE) right <- nodeids(kids_node(nd)[[2L]], terminal = TRUE) nd$split$prob <- c(0, 0) nl <- sum(fitted[["(fitted)"]] %in% left) nr <- sum(fitted[["(fitted)"]] %in% right) nd$split$prob <- if (nl > nr) c(1, 0) else c(0, 1) nd$split$prob <- as.double(nd$split$prob) return(nd) } node <- rpart_node(1) } rval <- party(node = node, data = if(data) mf else mf[0L,], fitted = fitted, terms = obj$terms, info = list(method = "rpart")) class(rval) <- c("constparty", class(rval)) return(rval) } model_frame_rpart <- function(formula, ...) { ## if model.frame is stored, simply extract if(!is.null(formula$model)) return(formula$model) ## otherwise reevaluate model.frame using original call mf <- formula$call mf <- mf[c(1L, match(c("formula", "data", "subset", "na.action", "weights"), names(mf), 0L))] if (is.null(mf$na.action)) mf$na.action <- rpart::na.rpart # mf$drop.unused.levels <- TRUE mf[[1L]] <- quote(stats::model.frame) ## use terms instead of formula in call mf$formula <- formula$terms ## evaluate in the right environment and return env <- if(!is.null(environment(formula$terms))) environment(formula$terms) else parent.frame() mf <- eval(mf, env) return(mf) } as.party.Weka_tree <- function(obj, data = TRUE, ...) { ## needs RWeka and rJava stopifnot(requireNamespace("RWeka")) ## J48 tree? (can be transformed to "constparty") j48 <- inherits(obj, "J48") ## construct metadata mf <- model.frame(obj) mf_class <- sapply(mf, function(x) class(x)[1L]) mf_levels <- lapply(mf, levels) x <- rJava::.jcall(obj$classifier, "S", "graph") if(j48) { info <- NULL } else { info <- RWeka::parse_Weka_digraph(x, plainleaf = FALSE)$nodes[, 2L] info <- strsplit(info, " (", fixed = TRUE) info <- lapply(info, function(x) if(length(x) == 1L) x else c(x[1L], paste("(", x[-1L], sep = ""))) } x <- RWeka::parse_Weka_digraph(x, plainleaf = TRUE) nodes <- x$nodes edges <- x$edges is.leaf <- x$nodes[, "splitvar"] == "" weka_tree_kids <- function(i) { if (is.leaf[i]) return(NULL) else return(which(nodes[,"name"] %in% edges[nodes[i,"name"] == edges[,"from"], "to"])) } weka_tree_split <- function(i) { if(is.leaf[i]) return(NULL) var_id <- which(nodes[i, "splitvar"] == names(mf)) edges <- edges[nodes[i,"name"] == edges[,"from"], "label"] split <- Map(c, sub("^([[:punct:]]+).*$", "\\1", edges), sub("^([[:punct:]]+) *", "", edges)) ## ## for J48 the following suffices ## split <- strsplit(edges[nodes[i,"name"] == edges[,"from"], "label"], " ") if(mf_class[var_id] %in% c("ordered", "factor")) { stopifnot(all(sapply(split, head, 1) == "=")) stopifnot(all(sapply(split, tail, 1) %in% mf_levels[[var_id]])) split <- partysplit(varid = as.integer(var_id), index = match(mf_levels[[var_id]], sapply(split, tail, 1))) } else { breaks <- unique(as.numeric(sapply(split, tail, 1))) breaks <- if(mf_class[var_id] == "integer") as.integer(breaks) else as.double(breaks) ## FIXME: check stopifnot(length(breaks) == 1 && !is.na(breaks)) stopifnot(all(sapply(split, head, 1) %in% c("<=", ">"))) split <- partysplit(varid = as.integer(var_id), breaks = breaks, right = TRUE, index = if(split[[1L]][1L] == ">") 2L:1L) } return(split) } weka_tree_node <- function(i) { if(is.null(weka_tree_kids(i))) return(partynode(as.integer(i), info = info[[i]])) partynode(as.integer(i), split = weka_tree_split(i), kids = lapply(weka_tree_kids(i), weka_tree_node)) } node <- weka_tree_node(1) if(j48) { pty <- party( node = node, data = if(data) mf else mf[0L,], fitted = data.frame("(fitted)" = fitted_node(node, mf), "(response)" = model.response(mf), check.names = FALSE), terms = obj$terms, info = list(method = "J4.8")) class(pty) <- c("constparty", class(pty)) } else { pty <- party( node = node, data = mf[0L,], fitted = data.frame("(fitted)" = fitted_node(node, mf), check.names = FALSE), terms = obj$terms, info = list(method = class(obj)[1L])) } return(pty) } partykit/R/ctree.R0000644000176200001440000005061014230544657013563 0ustar liggesusers .ctree_select <- function(...) function(model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .select(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } .ctree_split <- function(...) function(model, trafo, data, subset, weights, whichvar, ctrl) { args <- list(...) ctrl[names(args)] <- args .split(model, trafo, data, subset, weights, whichvar, ctrl, FUN = .ctree_test) } .ctree_test <- function(model, trafo, data, subset, weights, j, SPLITONLY = FALSE, ctrl) { ix <- data$zindex[[j]] ### data[[j, type = "index"]] iy <- data$yxindex ### data[["yx", type = "index"]] Y <- model$estfun if (!is.null(iy)) { stopifnot(NROW(levels(iy)) == (NROW(Y) - 1)) return(.ctree_test_2d(data = data, j = j, Y = Y, iy = iy, subset = subset, weights = weights, SPLITONLY = SPLITONLY, ctrl = ctrl)) } stopifnot(NROW(Y) == length(ix)) NAyx <- data$yxmissings ### data[["yx", type = "missings"]] NAz <- data$missings[[j]] ### data[[j, type = "missings"]] if (ctrl$MIA && (ctrl$splittest || SPLITONLY)) { subsetNArm <- subset[!(subset %in% NAyx)] } else { subsetNArm <- subset[!(subset %in% c(NAyx, NAz))] } ### report by Kevin Ummel: _all_ obs being missing lead to ### subset being ignored completely if (length(subsetNArm) == 0) return(list(statistic = NA, p.value = NA)) return(.ctree_test_1d(data = data, j = j, Y = Y, subset = subsetNArm, weights = weights, SPLITONLY = SPLITONLY, ctrl = ctrl)) } .partysplit <- function(varid, breaks = NULL, index = NULL, right = TRUE, prob = NULL, info = NULL) { ret <- list(varid = varid, breaks = breaks, index = index, right = right, prob = prob, info = info) class(ret) <- "partysplit" ret } .ctree_test_1d <- function(data, j, Y, subset, weights, SPLITONLY = FALSE, ctrl) { x <- data[[j]] MIA <- FALSE if (ctrl$MIA) { NAs <- data$missings[[j]] ### data[[j, type = "missings"]] MIA <- (length(NAs) > 0) } ### X for (ordered) factors is always dummy matrix if (is.factor(x) || is.ordered(x)) X <- data$zindex[[j]] ### data[[j, type = "index"]] scores <- data[[j, type = "scores"]] ORDERED <- is.ordered(x) || is.numeric(x) ux <- Xleft <- Xright <- NULL if (ctrl$splittest || SPLITONLY) { MAXSELECT <- TRUE if (is.numeric(x)) { X <- data$zindex[[j]] ###data[[j, type = "index"]] ux <- levels(X) } if (MIA) { Xlev <- attr(X, "levels") Xleft <- X + 1L Xleft[NAs] <- 1L Xright <- X Xright[NAs] <- as.integer(length(Xlev) + 1L) attr(Xleft, "levels") <- c(NA, Xlev) attr(Xright, "levels") <- c(Xlev, NA) } } else { MAXSELECT <- FALSE if (is.numeric(x)) { if (storage.mode(x) == "double") { X <- x } else { X <- as.double(x) ### copy when necessary } } MIA <- FALSE } cluster <- data[["(cluster)"]] .ctree_test_internal(x = x, X = X, ix = NULL, Xleft = Xleft, Xright = Xright, ixleft = NULL, ixright = NULL, ux = ux, scores = scores, j = j, Y = Y, iy = NULL, subset = subset, weights = weights, cluster = cluster, MIA = MIA, SPLITONLY = SPLITONLY, MAXSELECT = MAXSELECT, ORDERED = ORDERED, ctrl = ctrl) } .ctree_test_2d <- function(data, Y, iy, j, subset, weights, SPLITONLY = FALSE, ctrl) { x <- data[[j]] ix <- data$zindex[[j]] ### data[[j, type = "index"]] ux <- attr(ix, "levels") MIA <- FALSE if (ctrl$MIA) MIA <- any(ix[subset] == 0) ### X for (ordered) factors is always dummy matrix if (is.factor(x) || is.ordered(x)) X <- integer(0) scores <- data[[j, type = "scores"]] ORDERED <- is.ordered(x) || is.numeric(x) if (ctrl$splittest || SPLITONLY) { MAXSELECT <- TRUE X <- integer(0) if (MIA) { Xlev <- attr(ix, "levels") ixleft <- ix + 1L ixright <- ix ixright[ixright == 0L] <- as.integer(length(Xlev) + 1L) attr(ixleft, "levels") <- c(NA, Xlev) attr(ixright, "levels") <- c(Xlev, NA) Xleft <- Xright <- X } } else { MAXSELECT <- FALSE MIA <- FALSE if (is.numeric(x)) X <- matrix(c(0, as.double(attr(ix, "levels"))), ncol = 1) } cluster <- data[["(cluster)"]] .ctree_test_internal(x = x, X = X, ix = ix, Xleft = Xleft, Xright = Xright, ixleft = ixleft, ixright = ixright, ux = ux, scores = scores, j = j, Y = Y, iy = iy, subset = subset, weights = weights, cluster = cluster, MIA = MIA, SPLITONLY = SPLITONLY, MAXSELECT = MAXSELECT, ORDERED = ORDERED, ctrl = ctrl) } .ctree_test_internal <- function(x, X, ix, Xleft, Xright, ixleft, ixright, ux, scores, j, Y , iy, subset, weights, cluster, MIA, SPLITONLY, MAXSELECT, ORDERED, ctrl) { if (SPLITONLY) { nresample <- 0L varonly <- TRUE pvalue <- FALSE teststat <- ctrl$splitstat } else { nresample <- ifelse("MonteCarlo" %in% ctrl$testtype, ctrl$nresample, 0L) pvalue <- !("Teststatistic" %in% ctrl$testtype) if (ctrl$splittest) { if (ctrl$teststat != ctrl$splitstat) warning("Using different test statistics for testing and splitting") teststat <- ctrl$splitstat if (nresample == 0 && pvalue) stop("MonteCarlo approximation mandatory for splittest = TRUE") } else { teststat <- ctrl$teststat } varonly <- "MonteCarlo" %in% ctrl$testtype && teststat == "maxtype" } ### see libcoin if (MAXSELECT) { if (!is.null(cluster)) varonly <- FALSE } else { if (is.ordered(x) && !ctrl$splittest) varonly <- FALSE } ### if (MIA) use tst as fallback ### compute linear statistic + expecation and covariance lev <- LinStatExpCov(X = X, Y = Y, ix = ix, iy = iy, subset = subset, weights = weights, block = cluster, nresample = nresample, varonly = varonly, checkNAs = FALSE) ### in some cases, estfun() might return NAs which we don't check if (any(is.na(lev$LinearStatistic))) { if (!is.null(iy)) { Ytmp <- Y[iy[subset] + 1L,] } else { Ytmp <- Y[subset,] } cc <- complete.cases(Ytmp) if (!all(cc)) { ### only NAs left if (SPLITONLY) return(NULL) return(list(statistic = NA, p.value = NA)) } lev <- LinStatExpCov(X = X, Y = Y, ix = ix, iy = iy, subset = subset, weights = weights, block = cluster, nresample = nresample, varonly = varonly, checkNAs = TRUE) } if (!MAXSELECT) { if (is.ordered(x) && !ctrl$splittest) lev <- libcoin::lmult(matrix(scores, nrow = 1), lev) } ### check if either X or Y were unique vr <- lev$Variance vr[is.na(vr)] <- 0 if (all(vr < ctrl$tol)) { if (SPLITONLY) return(NULL) return(list(statistic = NA, p.value = NA)) } ### compute test statistic and log(1 - p-value) tst <- doTest(lev, teststat = teststat, pvalue = pvalue, lower = TRUE, log = TRUE, ordered = ORDERED, maxselect = MAXSELECT, minbucket = ctrl$minbucket, pargs = ctrl$pargs) if (MIA) { ### compute linear statistic + expecation and covariance lev <- LinStatExpCov(X = Xleft, Y = Y, ix = ixleft, iy = iy, subset = subset, weights = weights, block = cluster, nresample = nresample, varonly = varonly, checkNAs = FALSE) ### compute test statistic and log(1 - p-value) tstleft <- doTest(lev, teststat = teststat, pvalue = pvalue, lower = TRUE, log = TRUE, ordered = ORDERED, minbucket = ctrl$minbucket, pargs = ctrl$pargs) ### compute linear statistic + expecation and covariance lev <- LinStatExpCov(X = Xright, Y = Y, ix = ixright, iy = iy, subset = subset, weights = weights, block = cluster, nresample = nresample, varonly = varonly, checkNAs = FALSE) ### compute test statistic and log(1 - p-value) tstright <- doTest(lev, teststat = teststat, pvalue = pvalue, lower = TRUE, log = TRUE, ordered = ORDERED, minbucket = ctrl$minbucket, pargs = ctrl$pargs) } if (!SPLITONLY) { if (MIA) { tst <- tstleft if (tst$TestStatistic < tstright$TestStatistic) tst <- tstright } return(list(statistic = log(pmax(tst$TestStatistic, .Machine$double.eps)), p.value = tst$p.value)) } ret <- NULL if (MIA && !any(is.na(tst$index))) { if (ORDERED) { if (tstleft$TestStatistic >= tstright$TestStatistic) { if (all(tst$index == 1)) { ### case C ret <- .partysplit(as.integer(j), breaks = Inf, index = 1L:2L, prob = as.double(0:1)) } else { sp <- tstleft$index - 1L ### case A if (!is.ordered(x)) { ### interpolate split-points, see https://arxiv.org/abs/1611.04561 if (ctrl$intersplit & sp < length(ux)) { sp <- (ux[sp] + ux[sp + 1]) / 2 ### use weighted mean here? } else { sp <- ux[sp] ### X <= sp vs. X > sp } } ret <- .partysplit(as.integer(j), breaks = sp, index = 1L:2L, prob = as.double(rev(0:1))) } } else { ### case C was handled above (tstleft = tstright in this case) sp <- tstright$index ### case B if (!is.ordered(x)) { ### interpolate split-points, see https://arxiv.org/abs/1611.04561 if (ctrl$intersplit & sp < length(ux)) { sp <- (ux[sp] + ux[sp + 1]) / 2 } else { sp <- ux[sp] ### X <= sp vs. X > sp } } ret <- .partysplit(as.integer(j), breaks = sp, index = 1L:2L, prob = as.double(0:1)) } } else { sp <- tstleft$index[-1L] ### tstleft = tstright for unordered factors if (length(unique(sp)) == 1L) { ### case C ret <- .partysplit(as.integer(j), index = as.integer(tst$index) + 1L) } else { ### always case A ret <- .partysplit(as.integer(j), index = as.integer(sp) + 1L, prob = as.double(rev(0:1))) } } } else { sp <- tst$index if (all(is.na(sp))) return(NULL) if (ORDERED) { if (!is.ordered(x)) ### interpolate split-points, see https://arxiv.org/abs/1611.04561 if (ctrl$intersplit & sp < length(ux)) { sp <- (ux[sp] + ux[sp + 1]) / 2 } else { sp <- ux[sp] ### X <= sp vs. X > sp } ret <- .partysplit(as.integer(j), breaks = sp, index = 1L:2L) } else { ret <- .partysplit(as.integer(j), index = as.integer(sp) + 1L) } } return(ret) } ctree_control <- function ( teststat = c("quadratic", "maximum"), splitstat = c("quadratic", "maximum"), ### much better for q > 1, max was default splittest = FALSE, testtype = c("Bonferroni", "MonteCarlo", "Univariate", "Teststatistic"), pargs = GenzBretz(), nmax = c("yx" = Inf, "z" = Inf), alpha = 0.05, mincriterion = 1 - alpha, logmincriterion = log(mincriterion), minsplit = 20L, minbucket = 7L, minprob = 0.01, stump = FALSE, maxvar = Inf, lookahead = FALSE, ### try trafo() for daugther nodes before implementing the split MIA = FALSE, ### DOI: 10.1016/j.patrec.2008.01.010 nresample = 9999L, tol = sqrt(.Machine$double.eps), maxsurrogate = 0L, numsurrogate = FALSE, mtry = Inf, maxdepth = Inf, multiway = FALSE, splittry = 2L, intersplit = FALSE, majority = FALSE, caseweights = TRUE, applyfun = NULL, cores = NULL, saveinfo = TRUE, update = NULL, splitflavour = c("ctree", "exhaustive") ) { testtype <- match.arg(testtype, several.ok = TRUE) if (length(testtype) == 4) testtype <- testtype[1] ttesttype <- testtype if (length(testtype) > 1) { stopifnot(all(testtype %in% c("Bonferroni", "MonteCarlo"))) ttesttype <- "MonteCarlo" } if (MIA && maxsurrogate > 0) warning("Mixing MIA splits with surrogate splits does not make sense") if (MIA && majority) warning("Mixing MIA splits with majority does not make sense") splitstat <- match.arg(splitstat) teststat <- match.arg(teststat) if (!caseweights) stop("only caseweights currently implemented in ctree") splitflavour <- match.arg(splitflavour) c(extree_control(criterion = ifelse("Teststatistic" %in% testtype, "statistic", "p.value"), logmincriterion = logmincriterion, minsplit = minsplit, minbucket = minbucket, minprob = minprob, nmax = nmax, maxvar = maxvar, stump = stump, lookahead = lookahead, mtry = mtry, maxdepth = maxdepth, multiway = multiway, splittry = splittry, maxsurrogate = maxsurrogate, numsurrogate = numsurrogate, majority = majority, caseweights = caseweights, applyfun = applyfun, saveinfo = saveinfo, ### always selectfun = .ctree_select(), splitfun = if (splitflavour == "ctree") .ctree_split() else .objfun_test(), svselectfun = .ctree_select(), svsplitfun =.ctree_split(minbucket = 0), bonferroni = "Bonferroni" %in% testtype, update = update), list(teststat = teststat, splitstat = splitstat, splittest = splittest, pargs = pargs, testtype = ttesttype, nresample = nresample, tol = tol, intersplit = intersplit, MIA = MIA)) } ctree <- function(formula, data, subset, weights, na.action = na.pass, offset, cluster, control = ctree_control(...), ytrafo = NULL, converged = NULL, scores = NULL, doFit = TRUE, ...) { ## set up model.frame() call mf <- match.call(expand.dots = FALSE) m <- match(c("formula", "data", "subset", "na.action", "weights", "offset", "cluster", "scores"), names(mf), 0L) mf <- mf[c(1L, m)] mf$yx <- "none" if (is.function(ytrafo)) { if (all(c("y", "x") %in% names(formals(ytrafo)))) mf$yx <- "matrix" } mf$nmax <- control$nmax ## evaluate model.frame mf[[1L]] <- quote(partykit::extree_data) d <- eval(mf, parent.frame()) subset <- .start_subset(d) weights <- model.weights(model.frame(d)) if (is.function(ytrafo)) { if (is.null(control$update)) control$update <- TRUE nf <- names(formals(ytrafo)) if (all(c("data", "weights", "control") %in% nf)) ytrafo <- ytrafo(data = d, weights = weights, control = control) nf <- names(formals(ytrafo)) stopifnot(all(c("subset", "weights", "info", "estfun", "object") %in% nf) || all(c("y", "x", "weights", "offset", "start") %in% nf)) } else { if (is.null(control$update)) control$update <- FALSE stopifnot(length(d$variables$x) == 0) mfyx <- model.frame(d, yxonly = TRUE) mfyx[["(weights)"]] <- mfyx[["(offset)"]] <- NULL yvars <- names(mfyx) for (yvar in yvars) { sc <- d[[yvar, "scores"]] if (!is.null(sc)) attr(mfyx[[yvar]], "scores") <- sc } Y <- .y2infl(mfyx, response = d$variables$y, ytrafo = ytrafo) if (!is.null(iy <- d[["yx", type = "index"]])) { Y <- rbind(0, Y) } ytrafo <- function(subset, weights, info, estfun, object, ...) list(estfun = Y, unweighted = TRUE) ### unweighted = TRUE prevents estfun / w in extree_fit } if (is.function(converged)) { stopifnot(all(c("data", "weights", "control") %in% names(formals(converged)))) converged <- converged(d, weights, control = control) } else { converged <- TRUE } update <- function(subset, weights, control, doFit = TRUE) extree_fit(data = d, trafo = ytrafo, converged = converged, partyvars = d$variables$z, subset = subset, weights = weights, ctrl = control, doFit = doFit) if (!doFit) return(list(d = d, update = update)) tree <- update(subset = subset, weights = weights, control = control) trafo <- tree$trafo tree <- tree$nodes mf <- model.frame(d) if (is.null(weights)) weights <- rep(1, nrow(mf)) fitted <- data.frame("(fitted)" = fitted_node(tree, mf), "(weights)" = weights, check.names = FALSE) fitted[[3]] <- mf[, d$variables$y, drop = TRUE] names(fitted)[3] <- "(response)" ret <- party(tree, data = mf, fitted = fitted, info = list(call = match.call(), control = control)) ret$update <- update ret$trafo <- trafo class(ret) <- c("constparty", class(ret)) ### doesn't work for Surv objects # ret$terms <- terms(formula, data = mf) ret$terms <- d$terms$all ### need to adjust print and plot methods ### for multivariate responses ### if (length(response) > 1) class(ret) <- "party" return(ret) } .logrank_trafo <- function(...) return(coin::logrank_trafo(...)) ### convert response y to influence function h(y) .y2infl <- function(data, response, ytrafo = NULL) { if (length(response) == 1) { if (!is.null(ytrafo[[response]])) { yfun <- ytrafo[[response]] rtype <- "user-defined" } else { rtype <- .response_class(data[[response]]) } response <- data[[response]] infl <- switch(rtype, "user-defined" = yfun(response), "factor" = { X <- model.matrix(~ response - 1) if (nlevels(response) > 2) return(X) return(X[,-1, drop = FALSE]) }, "ordered" = { sc <- attr(response, "scores") if (is.null(sc)) sc <- 1L:nlevels(response) sc <- as.numeric(sc) return(matrix(sc[as.integer(response)], ncol = 1)) }, "numeric" = response, "Surv" = .logrank_trafo(response), stop("unknown response class") ) } else { ### multivariate response infl <- lapply(response, .y2infl, data = data) tmp <- do.call("cbind", infl) attr(tmp, "assign") <- rep(1L:length(infl), sapply(infl, NCOL)) infl <- tmp } if (!is.matrix(infl)) infl <- matrix(infl, ncol = 1) storage.mode(infl) <- "double" return(infl) } sctest.constparty <- function(object, node = NULL, ...) { if(is.null(node)) { ids <- nodeids(object, terminal = FALSE) ### all nodes } else { ids <- node } rval <- nodeapply(object, ids, function(n) { crit <- info_node(n)$criterion if (is.null(crit)) return(NULL) ret <- crit[c("statistic", "p.value"),,drop = FALSE] ret }) names(rval) <- ids if(length(ids) == 1L) return(rval[[1L]]) return(rval) } partykit/MD50000644000176200001440000002050714416215302012433 0ustar liggesusersc3ebd55ea57991bbd34be3b78d231b28 *DESCRIPTION dbb653bb1b54f81b13e2715252581cbf *NAMESPACE dca7b2a658a4a7e788b807e8126c0062 *R/as.party.R c83d333faa723d2dc3aeb6b54eef7aac *R/cforest.R 0c5fc0284b63902ccf049fda0c1f4f6d *R/ctree.R 25514cb2f7ef2245354a58736d2f3f4d *R/extree.R e09deeecb4ea0bb89f5c50e57e988246 *R/glmtree.R acc00e722783ecc249a989d38cc32f07 *R/lmtree.R fdcdcf277b20053030c67f4b1f1b81f1 *R/mob-plot.R 3f0cd2fec6a3949d66984e510bd8a714 *R/mob-pvalue.R a45c6d5627dc69723d1e0f0cd434576d *R/modelparty.R 5436a41d79d26887924734b7370e61b6 *R/node.R 3db9b98e63a333ecca51d3a91462a764 *R/party.R 2df0900fcdbbdbe513477761dbe417cb *R/plot.R 053f20e5f4b287f6c3c771953993f817 *R/pmmlTreeModel.R 238c6759ddefee9668c3d5a64091d694 *R/print.R 76481105b6825a322fa3079cd4fad5df *R/prune.R e2768629fae5ce80c1753bfece8770c2 *R/simpleparty.R 8ea171dac47d40724e40dac4d47e4837 *R/split.R d7247611d1d9f749912867e8f6d4c151 *R/utils.R 9c46336441e4f4907c25cd2129b96244 *R/varimp.R 4376d9c236937c0f13ba909b235790f5 *R/zzz.R 7f2094c7b4d5faa522b624cffc621f8b *build/partial.rdb c5398dd8b01c2bb9d5fd0f533c5924d1 *build/vignette.rds e6811a27b27d6fd7150506491a07f8e2 *cleanup b410bf42e75f4c300b7a574bfd4dcd55 *data/HuntingSpiders.rda 192b6ae6c6a51225bbd34f5280594f5c *data/WeatherPlay.rda 0bf664829f0398ca3b38000eb93e5e10 *demo/00Index a10fbafb2e117a2df08603dc03569f82 *demo/memory-speed.R b094cb0509a048dc80d9fb84f036d358 *inst/CITATION 168382e7decba0ee8472098b50de3fcf *inst/NEWS.Rd b847249ab71ee834cfa87e649308f59d *inst/ULGcourse-2020/Data/Axams_pred.rda d623d2cc7274d7341c86b2fa0af3af8a *inst/ULGcourse-2020/Data/Axams_testdata.rda f67b3afd0d6efa130e59e49bf76cee22 *inst/ULGcourse-2020/Data/GENS_00_innsbruck-flughafen.txt e5bac6a452c0e6f20213815caebd5bcd *inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200410.dat 2d08cd782e8ea15cffe8c23c71846a9a *inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200411.dat 250ad191a24a5b23597fe28f7cc37d47 *inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200412.dat ac40ec3c42f05d034c509a31ddb11ea6 *inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200413.dat 21f17cac76c05d9e9974972f4216c5a1 *inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200414.dat 1eb55f9f8d1898c74c0ef0441639e572 *inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200415.dat 04039e1bce8c623068861c6b441084ce *inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200416.dat eedd6523f6d0f7a529f7f55769808d9f *inst/ULGcourse-2020/Data/STAGEobs_tawes_11121_defense.rda 9a9d0206d33996a089793d0bbf9d9146 *inst/ULGcourse-2020/Data/crps_24to4_all.rda 5c44b47585fa1c07fd270b2d524747e9 *inst/ULGcourse-2020/Makefile 893b248e4313aea082a5afb45fb65ae1 *inst/ULGcourse-2020/airport_20200412.jpg 57a95ad84387f6184dde62de97b46f37 *inst/ULGcourse-2020/airport_20200413.jpg da6632449d39e20e0995f2c8307908de *inst/ULGcourse-2020/circtree_ibk.pdf ae5a965733912cd2fbafb14714387973 *inst/ULGcourse-2020/code_tree.R 07b619cae57b028b5b074055b95b5277 *inst/ULGcourse-2020/density_1.pdf f0b5fa73b9ac06a9d75dade1012543e5 *inst/ULGcourse-2020/density_1_hist.pdf 920991864620065d18f735f5dd0df8f4 *inst/ULGcourse-2020/density_2.pdf be8a62e4c43a6781df2aeff6e693ef3d *inst/ULGcourse-2020/density_2_hist.pdf 81159642fee90f81db6c3445a69eb39d *inst/ULGcourse-2020/density_all.pdf 359be7b2fa3d8e5e7e78be024f3560ca *inst/ULGcourse-2020/density_all_hist.pdf 797ebffd5a515234a3d980cab48394ee *inst/ULGcourse-2020/exercises/data/CPS1985.rds 7d11268b9e6f7ca07d3ecee50023fee7 *inst/ULGcourse-2020/exercises/data/german.rds e2bc7bed5e6c0f65f4c24450689ec20e *inst/ULGcourse-2020/exercises/data/titanic.rds c0d119799e516f8024b8c2240e151000 *inst/ULGcourse-2020/exercises/exercise_forest_german_credit.Rmd 0987c34216c3931235e61459e3e33f28 *inst/ULGcourse-2020/exercises/exercise_forest_wage.Rmd ebe8194e8e61ff7d26a281a1a7d16c70 *inst/ULGcourse-2020/exercises/exercise_german_credit.Rmd 7d7e9953561bf8a756fd303326eb7e23 *inst/ULGcourse-2020/exercises/exercise_titanic.Rmd 1e05eed3bca3e4ebc800811eaffbccc6 *inst/ULGcourse-2020/forest.jpg 6e065ace8e3b8f1ce9620bb6db9c4c12 *inst/ULGcourse-2020/slides_forest.Rnw 42e4fcdf80c1540ed882f2c4a839b447 *inst/ULGcourse-2020/slides_tree.Rnw f2ca7db8c507840478c7004ebdd53f69 *inst/doc/constparty.R aa446969fd4208132475bfde86b9c40b *inst/doc/constparty.R.R 4b9b60c4a153db5aff4de375332282fc *inst/doc/constparty.Rnw f3608bd709bf010f592872bb05500480 *inst/doc/constparty.pdf cce3ded51d9ee9b75ff3b8dbcac6e45c *inst/doc/ctree.R 8b8a6cb7a963d2d1b6b338d6bdbe3662 *inst/doc/ctree.Rnw 06392cd6bc1f42238522297de12a52a4 *inst/doc/ctree.pdf 6e73710f40ce9f193f1251e8c8127a0e *inst/doc/mob.R 2aa00ddac6a0c0669215861489afb47c *inst/doc/mob.Rnw 889d3f8bae47660b48184a3eff364bfc *inst/doc/mob.pdf 28f92802e645a7f199668aaba137ff80 *inst/doc/partykit.R a3b1aeaa489b1646ef97a745f3d7f121 *inst/doc/partykit.Rnw 3cbc9fe94faa0759f680c6b55b7e2e21 *inst/doc/partykit.pdf 1b961019a4c8e43e4d046ae20d4a2cf5 *inst/pmml/airq.pmml 8a72f1494239b092e6821e6534ed6627 *inst/pmml/bbbc.pmml ecc0e4f670cfbfda89e14f9df7a76df3 *inst/pmml/iris.pmml 3cda8eba999d2fcbda7bd2fa7c08511b *inst/pmml/ttnc.pmml 7eadce18c13d50e927eee62fa4d0826a *inst/pmml/ttnc2.pmml 16dde1216f012a8a516fa55ca30aad6f *man/HuntingSpiders.Rd 8dffc3d0b772b517ce3e5b05b6359b91 *man/WeatherPlay.Rd 9061ddc2e141367d04e8a49c83ccdce7 *man/cforest.Rd 913a297793d2423b77f959a700561ede *man/ctree.Rd e8c7e5fc5f9c4aeb1575fece43022454 *man/ctree_control.Rd 96965067106369acaebaeef4efb71414 *man/extree_data.Rd 6dfbdfc0a2b2d6d9055637ce7c94d5d3 *man/extree_fit.Rd c2afbe9e7ef82fd690d18b9f2478fb2a *man/glmtree.Rd d7f4f8f3fb1470a37a88b3ad8beb75de *man/lmtree.Rd 00116e69ba0acfaf0322c16221a29cb2 *man/mob.Rd 2ba683e96aa9e27e9fee41099ec46cb4 *man/mob_control.Rd 742603a0b0b4c13400af6755ba42516d *man/model.frame.rpart.Rd 8916d3b39ce7391822c626e5f316d163 *man/nodeapply.Rd fde1b215547848add8adbcfa3d417d72 *man/nodeids.Rd 26a5c8b15bb5ff452bb1645cff5b2c56 *man/panelfunctions.Rd 24de60da10de292cea0739f0fcdc0b92 *man/party-coercion.Rd ec2dcd1082de56328e92036c098377d0 *man/party-methods.Rd f801d519e4a6ee6b7f038f36b06b97d1 *man/party-plot.Rd 745288e5b2e53bba0c948ee8ee795089 *man/party-predict.Rd d329054e50a030f8c0a0584615e0b23c *man/party.Rd e4d4025e957e10d1c8a45e8fd444a7a3 *man/partynode-methods.Rd 10639f07e30b8ff06856a4bfab22a63d *man/partynode.Rd 404f06377e9cead790fb9128203da5e8 *man/partysplit.Rd 031e4e7cada9d87cd4197899a6b8f023 *man/prune.modelparty.Rd eec28a4fa9e134a2801eb6f369fb232f *man/varimp.Rd 972ddff277f32ad003c721d2062c7d5b *src/partykit-init.c fd714ab2ff6772bca8ef031c055525f8 *src/partykit-win.def c6bfb525d83363577b5c96ce8ed114f7 *src/rfweights.c b78cdbea9965051c934da58e257f1ce2 *src/rfweights.h 2f6423e2d27d37c3520b09718ad007dd *tests/Rplots.pdf 5590526a517d233e5001c81ad4db5002 *tests/bugfixes.R 798111fd23d9d6854c28f30ca55c400d *tests/bugfixes.Rout.save 6d509223e375177c4394469f0f265915 *tests/constparty.R e7660e943cea3c2c6a53c48ce9e39e30 *tests/constparty.Rout.save f3b5655e58241522bff835acf3585361 *tests/regtest-MIA.R 2c0fd3b3bf5a579d3c493a6b07c1b077 *tests/regtest-MIA.Rout.save a87608f0180d7ddbee707e97278bea86 *tests/regtest-cforest.R 8c6a848b11099d8eb26d1a77c3508450 *tests/regtest-cforest.Rout.save d358e27525373a082b707ecd12993fbf *tests/regtest-ctree.R fed8bca2a0b65561e10f8fb3f9f65791 *tests/regtest-ctree.Rout.save 8c428631f54101f49a7855a3e62c0be5 *tests/regtest-glmtree.R 88c7e07edad60a37b23dc5fb825d3adf *tests/regtest-glmtree.Rout.save 68dc869bd4347d3dd58214a08ba88e6a *tests/regtest-honesty.R 22a2ad91f9661ffe2fb649c048ddd75c *tests/regtest-lmtree.R da0329585d44c113b176c019aba3cead *tests/regtest-nmax.R 23758595667da50139304789cd478dbc *tests/regtest-nmax.Rout.save b7282c3b5e5b409bda765a6574ad067c *tests/regtest-node.R 7cbae6da6e23dfa3cd63efe0579849e1 *tests/regtest-node.Rout.save 734be9552d73690d36bcd9996afec506 *tests/regtest-party-random.R 78bd213d1c28bda5e96a73e6b816e178 *tests/regtest-party.R 40c5cc268563a028d4484b1b3b5a3c62 *tests/regtest-party.Rout.save 2595ea3adf5fe85a005bae526a6eb335 *tests/regtest-split.R ba90fd5e552ec80cbce743457016a6f3 *tests/regtest-split.Rout.save 42f5cbe7c29a9f57d0fb195e4d68da19 *tests/regtest-weights.R 6b6b4f8ced56d88ecb5052b92e6be60c *tests/regtest-weights.Rout.save 4b9b60c4a153db5aff4de375332282fc *vignettes/constparty.Rnw 8b8a6cb7a963d2d1b6b338d6bdbe3662 *vignettes/ctree.Rnw 4c6a8da36879bf731746411098c59cc2 *vignettes/ctree.Rout.save 2aa00ddac6a0c0669215861489afb47c *vignettes/mob.Rnw 5c9623bc793ae30eafcb90e72cf940a9 *vignettes/party.bib a3b1aeaa489b1646ef97a745f3d7f121 *vignettes/partykit.Rnw 091d6cc8ce2ed0cc6cb41d99b0631df3 *vignettes/partykit.Rout.save partykit/inst/0000755000176200001440000000000014415225047013102 5ustar liggesuserspartykit/inst/doc/0000755000176200001440000000000014415225041013641 5ustar liggesuserspartykit/inst/doc/constparty.R0000644000176200001440000002655314415225002016202 0ustar liggesusers### R code from vignette source 'constparty.Rnw' ################################################### ### code chunk number 1: setup ################################################### suppressWarnings(RNGversion("3.5.2")) options(width = 70) library("partykit") set.seed(290875) ################################################### ### code chunk number 2: Titanic ################################################### data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" ################################################### ### code chunk number 3: rpart ################################################### library("rpart") (rp <- rpart(Survived ~ ., data = ttnc, model = TRUE)) ################################################### ### code chunk number 4: rpart-party ################################################### (party_rp <- as.party(rp)) ################################################### ### code chunk number 5: rpart-plot-orig ################################################### plot(rp) text(rp) ################################################### ### code chunk number 6: rpart-plot ################################################### plot(party_rp) ################################################### ### code chunk number 7: rpart-pred ################################################### all.equal(predict(rp), predict(party_rp, type = "prob"), check.attributes = FALSE) ################################################### ### code chunk number 8: rpart-fitted ################################################### str(fitted(party_rp)) ################################################### ### code chunk number 9: rpart-prob ################################################### prop.table(do.call("table", fitted(party_rp)), 1) ################################################### ### code chunk number 10: J48 ################################################### if (require("RWeka")) { j48 <- J48(Survived ~ ., data = ttnc) } else { j48 <- rpart(Survived ~ ., data = ttnc) } print(j48) ################################################### ### code chunk number 11: J48-party ################################################### (party_j48 <- as.party(j48)) ################################################### ### code chunk number 12: J48-plot ################################################### plot(party_j48) ################################################### ### code chunk number 13: J48-pred ################################################### all.equal(predict(j48, type = "prob"), predict(party_j48, type = "prob"), check.attributes = FALSE) ################################################### ### code chunk number 14: PMML-Titantic ################################################### ttnc_pmml <- file.path(system.file("pmml", package = "partykit"), "ttnc.pmml") (ttnc_quest <- pmmlTreeModel(ttnc_pmml)) ################################################### ### code chunk number 15: PMML-Titanic-plot1 ################################################### plot(ttnc_quest) ################################################### ### code chunk number 16: ttnc2-reorder ################################################### ttnc2 <- ttnc[, names(ttnc_quest$data)] for(n in names(ttnc2)) { if(is.factor(ttnc2[[n]])) ttnc2[[n]] <- factor( ttnc2[[n]], levels = levels(ttnc_quest$data[[n]])) } ################################################### ### code chunk number 17: PMML-Titanic-augmentation ################################################### ttnc_quest2 <- party(ttnc_quest$node, data = ttnc2, fitted = data.frame( "(fitted)" = predict(ttnc_quest, ttnc2, type = "node"), "(response)" = ttnc2$Survived, check.names = FALSE), terms = terms(Survived ~ ., data = ttnc2) ) ttnc_quest2 <- as.constparty(ttnc_quest2) ################################################### ### code chunk number 18: PMML-Titanic-plot2 ################################################### plot(ttnc_quest2) ################################################### ### code chunk number 19: PMML-write ################################################### library("pmml") tfile <- tempfile() write(toString(pmml(rp)), file = tfile) ################################################### ### code chunk number 20: PMML-read ################################################### (party_pmml <- pmmlTreeModel(tfile)) all.equal(predict(party_rp, newdata = ttnc, type = "prob"), predict(party_pmml, newdata = ttnc, type = "prob"), check.attributes = FALSE) ################################################### ### code chunk number 21: mytree-1 ################################################### findsplit <- function(response, data, weights, alpha = 0.01) { ## extract response values from data y <- factor(rep(data[[response]], weights)) ## perform chi-squared test of y vs. x mychisqtest <- function(x) { x <- factor(x) if(length(levels(x)) < 2) return(NA) ct <- suppressWarnings(chisq.test(table(y, x), correct = FALSE)) pchisq(ct$statistic, ct$parameter, log = TRUE, lower.tail = FALSE) } xselect <- which(names(data) != response) logp <- sapply(xselect, function(i) mychisqtest(rep(data[[i]], weights))) names(logp) <- names(data)[xselect] ## Bonferroni-adjusted p-value small enough? if(all(is.na(logp))) return(NULL) minp <- exp(min(logp, na.rm = TRUE)) minp <- 1 - (1 - minp)^sum(!is.na(logp)) if(minp > alpha) return(NULL) ## for selected variable, search for split minimizing p-value xselect <- xselect[which.min(logp)] x <- rep(data[[xselect]], weights) ## set up all possible splits in two kid nodes lev <- levels(x[drop = TRUE]) if(length(lev) == 2) { splitpoint <- lev[1] } else { comb <- do.call("c", lapply(1:(length(lev) - 2), function(x) combn(lev, x, simplify = FALSE))) xlogp <- sapply(comb, function(q) mychisqtest(x %in% q)) splitpoint <- comb[[which.min(xlogp)]] } ## split into two groups (setting groups that do not occur to NA) splitindex <- !(levels(data[[xselect]]) %in% splitpoint) splitindex[!(levels(data[[xselect]]) %in% lev)] <- NA_integer_ splitindex <- splitindex - min(splitindex, na.rm = TRUE) + 1L ## return split as partysplit object return(partysplit(varid = as.integer(xselect), index = splitindex, info = list(p.value = 1 - (1 - exp(logp))^sum(!is.na(logp))))) } ################################################### ### code chunk number 22: mytree-2 ################################################### growtree <- function(id = 1L, response, data, weights, minbucket = 30) { ## for less than 30 observations stop here if (sum(weights) < minbucket) return(partynode(id = id)) ## find best split sp <- findsplit(response, data, weights) ## no split found, stop here if (is.null(sp)) return(partynode(id = id)) ## actually split the data kidids <- kidids_split(sp, data = data) ## set up all daugther nodes kids <- vector(mode = "list", length = max(kidids, na.rm = TRUE)) for (kidid in 1:length(kids)) { ## select observations for current node w <- weights w[kidids != kidid] <- 0 ## get next node id if (kidid > 1) { myid <- max(nodeids(kids[[kidid - 1]])) } else { myid <- id } ## start recursion on this daugther node kids[[kidid]] <- growtree(id = as.integer(myid + 1), response, data, w) } ## return nodes return(partynode(id = as.integer(id), split = sp, kids = kids, info = list(p.value = min(info_split(sp)$p.value, na.rm = TRUE)))) } ################################################### ### code chunk number 23: mytree-3 ################################################### mytree <- function(formula, data, weights = NULL) { ## name of the response variable response <- all.vars(formula)[1] ## data without missing values, response comes last data <- data[complete.cases(data), c(all.vars(formula)[-1], response)] ## data is factors only stopifnot(all(sapply(data, is.factor))) if (is.null(weights)) weights <- rep(1L, nrow(data)) ## weights are case weights, i.e., integers stopifnot(length(weights) == nrow(data) & max(abs(weights - floor(weights))) < .Machine$double.eps) ## grow tree nodes <- growtree(id = 1L, response, data, weights) ## compute terminal node number for each observation fitted <- fitted_node(nodes, data = data) ## return rich constparty object ret <- party(nodes, data = data, fitted = data.frame("(fitted)" = fitted, "(response)" = data[[response]], "(weights)" = weights, check.names = FALSE), terms = terms(formula)) as.constparty(ret) } ################################################### ### code chunk number 24: mytree-4 ################################################### (myttnc <- mytree(Survived ~ Class + Age + Gender, data = ttnc)) ################################################### ### code chunk number 25: mytree-5 ################################################### plot(myttnc) ################################################### ### code chunk number 26: mytree-pval ################################################### nid <- nodeids(myttnc) iid <- nid[!(nid %in% nodeids(myttnc, terminal = TRUE))] (pval <- unlist(nodeapply(myttnc, ids = iid, FUN = function(n) info_node(n)$p.value))) ################################################### ### code chunk number 27: mytree-nodeprune ################################################### myttnc2 <- nodeprune(myttnc, ids = iid[pval > 1e-5]) ################################################### ### code chunk number 28: mytree-nodeprune-plot ################################################### plot(myttnc2) ################################################### ### code chunk number 29: mytree-glm ################################################### logLik(glm(Survived ~ Class + Age + Gender, data = ttnc, family = binomial())) ################################################### ### code chunk number 30: mytree-bs ################################################### bs <- rmultinom(25, nrow(ttnc), rep(1, nrow(ttnc)) / nrow(ttnc)) ################################################### ### code chunk number 31: mytree-ll ################################################### bloglik <- function(prob, weights) sum(weights * dbinom(ttnc$Survived == "Yes", size = 1, prob[,"Yes"], log = TRUE)) ################################################### ### code chunk number 32: mytree-bsll ################################################### f <- function(w) { tr <- mytree(Survived ~ Class + Age + Gender, data = ttnc, weights = w) bloglik(predict(tr, newdata = ttnc, type = "prob"), as.numeric(w == 0)) } apply(bs, 2, f) ################################################### ### code chunk number 33: mytree-node ################################################### nttnc <- expand.grid(Class = levels(ttnc$Class), Gender = levels(ttnc$Gender), Age = levels(ttnc$Age)) nttnc ################################################### ### code chunk number 34: mytree-prob ################################################### predict(myttnc, newdata = nttnc, type = "node") predict(myttnc, newdata = nttnc, type = "response") predict(myttnc, newdata = nttnc, type = "prob") ################################################### ### code chunk number 35: mytree-FUN ################################################### predict(myttnc, newdata = nttnc, FUN = function(y, w) rank(table(rep(y, w)))) partykit/inst/doc/constparty.R.R0000644000176200001440000000006014172230001016356 0ustar liggesusers### R code from vignette source 'constparty.R' partykit/inst/doc/partykit.R0000644000176200001440000002153414415225041015640 0ustar liggesusers### R code from vignette source 'partykit.Rnw' ################################################### ### code chunk number 1: setup ################################################### suppressWarnings(RNGversion("3.5.2")) options(width = 70) library("partykit") set.seed(290875) ################################################### ### code chunk number 2: weather-data ################################################### data("WeatherPlay", package = "partykit") WeatherPlay ################################################### ### code chunk number 3: weather-plot0 ################################################### py <- party( partynode(1L, split = partysplit(1L, index = 1:3), kids = list( partynode(2L, split = partysplit(3L, breaks = 75), kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = partysplit(4L, index = 1:2), kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))), WeatherPlay) plot(py) ################################################### ### code chunk number 4: weather-splits ################################################### sp_o <- partysplit(1L, index = 1:3) sp_h <- partysplit(3L, breaks = 75) sp_w <- partysplit(4L, index = 1:2) ################################################### ### code chunk number 5: weather-nodes ################################################### pn <- partynode(1L, split = sp_o, kids = list( partynode(2L, split = sp_h, kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = sp_w, kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))) ################################################### ### code chunk number 6: weather-nodes-print ################################################### pn ################################################### ### code chunk number 7: weather-party ################################################### py <- party(pn, WeatherPlay) print(py) ################################################### ### code chunk number 8: weather-plot (eval = FALSE) ################################################### ## plot(py) ################################################### ### code chunk number 9: weather-predict ################################################### predict(py, head(WeatherPlay)) ################################################### ### code chunk number 10: weather-methods-dim ################################################### length(py) width(py) depth(py) ################################################### ### code chunk number 11: weather-methods-subset ################################################### py[6] ################################################### ### code chunk number 12: weather-methods-names ################################################### py2 <- py names(py2) names(py2) <- LETTERS[1:8] py2 ################################################### ### code chunk number 13: weather-methods-nodeids ################################################### nodeids(py) nodeids(py, terminal = TRUE) ################################################### ### code chunk number 14: weather-methods-nodeapply ################################################### nodeapply(py, ids = c(1, 7), FUN = function(n) n$info) nodeapply(py, ids = nodeids(py, terminal = TRUE), FUN = function(n) paste("Play decision:", n$info)) ################################################### ### code chunk number 15: weather-methods-predict ################################################### predict(py, FUN = function(n) paste("Play decision:", n$info)) ################################################### ### code chunk number 16: weather-methods-print ################################################### print(py, terminal_panel = function(n) c(", then the play decision is:", toupper(n$info))) ################################################### ### code chunk number 17: weather-methods-plot (eval = FALSE) ################################################### ## plot(py, tp_args = list(FUN = function(i) ## c("Play decision:", toupper(i)))) ################################################### ### code chunk number 18: weather-methods-plot1 ################################################### plot(py[6]) ################################################### ### code chunk number 19: weather-methods-plot2 ################################################### plot(py, tp_args = list(FUN = function(i) c("Play decision:", toupper(i)))) ################################################### ### code chunk number 20: weather-prune ################################################### nodeprune(py, 2) nodeprune(py, c(2, 6)) ################################################### ### code chunk number 21: partysplit-1 ################################################### sp_h <- partysplit(3L, breaks = 75) class(sp_h) ################################################### ### code chunk number 22: partysplit-2 ################################################### unclass(sp_h) ################################################### ### code chunk number 23: partysplit-3 ################################################### character_split(sp_h, data = WeatherPlay) ################################################### ### code chunk number 24: partysplit-4 ################################################### kidids_split(sp_h, data = WeatherPlay) ################################################### ### code chunk number 25: partysplit-5 ################################################### as.numeric(!(WeatherPlay$humidity <= 75)) + 1 ################################################### ### code chunk number 26: partysplit-6 ################################################### sp_o2 <- partysplit(1L, index = c(1L, 1L, 2L)) character_split(sp_o2, data = WeatherPlay) table(kidids_split(sp_o2, data = WeatherPlay), WeatherPlay$outlook) ################################################### ### code chunk number 27: partysplit-6 ################################################### unclass(sp_o2) ################################################### ### code chunk number 28: partysplit-7 ################################################### sp_o <- partysplit(1L, index = 1L:3L) character_split(sp_o, data = WeatherPlay) ################################################### ### code chunk number 29: partysplit-8 ################################################### sp_t <- partysplit(2L, breaks = c(69.5, 78.8), index = c(1L, 2L, 1L)) character_split(sp_t, data = WeatherPlay) table(kidids_split(sp_t, data = WeatherPlay), cut(WeatherPlay$temperature, breaks = c(-Inf, 69.5, 78.8, Inf))) ################################################### ### code chunk number 30: partynode-1 ################################################### n1 <- partynode(id = 1L) is.terminal(n1) print(n1) ################################################### ### code chunk number 31: partynode-2 ################################################### n1 <- partynode(id = 1L, split = sp_o, kids = lapply(2L:4L, partynode)) print(n1, data = WeatherPlay) ################################################### ### code chunk number 32: partynode-3 ################################################### fitted_node(n1, data = WeatherPlay) ################################################### ### code chunk number 33: partynode-4 ################################################### kidids_node(n1, data = WeatherPlay) ################################################### ### code chunk number 34: party-1a ################################################### t1 <- party(n1, data = WeatherPlay) t1 ################################################### ### code chunk number 35: party-1b ################################################### party(n1, data = WeatherPlay[0, ]) ################################################### ### code chunk number 36: party-2 ################################################### t2 <- party(n1, data = WeatherPlay, fitted = data.frame( "(fitted)" = fitted_node(n1, data = WeatherPlay), "(response)" = WeatherPlay$play, check.names = FALSE), terms = terms(play ~ ., data = WeatherPlay), ) ################################################### ### code chunk number 37: party-3 ################################################### t2 <- as.constparty(t2) t2 ################################################### ### code chunk number 38: constparty-plot ################################################### plot(t2, tnex = 1.5) ################################################### ### code chunk number 39: party-4 ################################################### nd <- data.frame(outlook = factor(c("overcast", "sunny"), levels = levels(WeatherPlay$outlook))) predict(t2, newdata = nd, type = "response") predict(t2, newdata = nd, type = "prob") predict(t2, newdata = nd, type = "node") partykit/inst/doc/partykit.Rnw0000644000176200001440000010150114172230001016166 0ustar liggesusers\documentclass[nojss]{jss} %\VignetteIndexEntry{partykit: A Toolkit for Recursive Partytioning} %\VignetteDepends{partykit} %\VignetteKeywords{recursive partitioning, regression trees, classification trees, decision trees} %\VignettePackage{partykit} %% packages \usepackage{amstext} \usepackage{amsfonts} \usepackage{amsmath} \usepackage{thumbpdf} \usepackage{rotating} %% need no \usepackage{Sweave} %% additional commands \newcommand{\squote}[1]{`{#1}'} \newcommand{\dquote}[1]{``{#1}''} \newcommand{\fct}[1]{\texttt{#1()}} \newcommand{\class}[1]{\squote{\texttt{#1}}} %% for internal use \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} \newcommand{\readme}[1]{\emph{\marginpar{README} (#1)}} \hyphenation{Qua-dra-tic} \title{\pkg{partykit}: A Toolkit for Recursive Partytioning} \Plaintitle{partykit: A Toolkit for Recursive Partytioning} \author{Achim Zeileis\\Universit\"at Innsbruck \And Torsten Hothorn\\Universit\"at Z\"urich} \Plainauthor{Achim Zeileis, Torsten Hothorn} \Abstract{ The \pkg{partykit} package provides a flexible toolkit with infrastructure for learning, representing, summarizing, and visualizing a wide range of tree-structured regression and classification models. The functionality encompasses: (a)~Basic infrastructure for \emph{representing} trees (inferred by any algorithm) so that unified \code{print}/\code{plot}/\code{predict} methods are available. (b)~Dedicated methods for trees with \emph{constant fits} in the leaves (or terminal nodes) along with suitable coercion functions to create such tree models (e.g., by \pkg{rpart}, \pkg{RWeka}, PMML). (c)~A reimplementation of \emph{conditional inference trees} (\code{ctree}, originally provided in the \pkg{party} package). (d)~An extended reimplementation of \emph{model-based recursive partitioning} (\code{mob}, also originally in \pkg{party}) along with dedicated methods for trees with parametric models in the leaves. This vignette gives a brief overview of the package and discusses in detail the generic infrastructure for representing trees (a). Items~(b)--(d) are discussed in the remaining vignettes in the package. } \Keywords{recursive partitioning, regression trees, classification trees, decision trees} \Address{ Achim Zeileis \\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org} \\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} \\ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/} } \begin{document} \SweaveOpts{eps=FALSE, keep.source=TRUE, eval = TRUE} <>= suppressWarnings(RNGversion("3.5.2")) options(width = 70) library("partykit") set.seed(290875) @ \section{Overview} \label{sec:overview} In the more than fifty years since \cite{Morgan+Sonquist:1963} published their seminal paper on ``automatic interaction detection'', a wide range of methods has been suggested that is usually termed ``recursive partitioning'' or ``decision trees'' or ``tree(-structured) models'' etc. Particularly influential were the algorithms CART \citep[classification and regression trees,][]{Breiman+Friedman+Olshen:1984}, C4.5 \citep{Quinlan:1993}, QUEST/GUIDE \citep{Loh+Shih:1997,Loh:2002}, and CTree \citep{Hothorn+Hornik+Zeileis:2006} among many others \citep[see][for a recent overview]{Loh:2014}. Reflecting the heterogeneity of conceptual algorithms, a wide range of computational implementations in various software systems emerged: Typically the original authors of an algorithm also provide accompanying software but many software systems, e.g., including \pkg{Weka} \citep{Witten+Frank:2005} or \proglang{R} \citep{R}, also provide collections of various types of trees. Within \proglang{R} the list of prominent packages includes \pkg{rpart} \citep[implementing the CART algorithm]{rpart}, \pkg{mvpart} \citep[for multivariate CART]{mvpart}, \pkg{RWeka} \citep[containing interfaces to J4.8, M5', LMT from \pkg{Weka}]{RWeka}, and \pkg{party} \citep[implementing CTree and MOB]{party} among many others. See the CRAN task view ``Machine Learning'' \citep{ctv} for an overview. All of these algorithms and software implementations have to deal with very similar challenges. However, due to the fragmentation of the communities in which the corresponding research is published -- ranging from statistics over machine learning to various applied fields -- many discussions of the algorithms do not reuse established theoretical results and terminology. Similarly, there is no common ``language'' for the software implementations and different solutions are provided by different packages (even within \proglang{R}) with relatively little reuse of code. The \pkg{partykit} tries to address the latter point and improve the computational situation by providing a common unified infrastructure for recursive partytioning in the \proglang{R} system for statistical computing. In particular, \pkg{partykit} provides tools for representing fitted trees along with printing, plotting, and computing predictions. The design principles are: \begin{itemize} \item One `agnostic' base class (\class{party}) which can encompass an extremely wide range of different types of trees. \item Subclasses for important types of trees, e.g., trees with constant fits (\class{constparty}) or with parametric models (\class{modelparty}) in each terminal node (or leaf). \item Nodes are recursive objects, i.e., a node can contain child nodes. \item Keep the (learning) data out of the recursive node and split structure. \item Basic printing, plotting, and predicting for raw node structure. \item Customization via suitable panel or panel-generating functions. \item Coercion from existing object classes in \proglang{R} (\code{rpart}, \code{J48}, etc.) to the new class. \item Usage of simple/fast \proglang{S}3 classes and methods. \end{itemize} In addition to all of this generic infrastructure, two specific tree algorithms are implemented in \pkg{partykit} as well: \fct{ctree} for conditional inference trees \citep{Hothorn+Hornik+Zeileis:2006} and \fct{mob} for model-based recursive partitioning \citep{Zeileis+Hothorn+Hornik:2008}. This vignette (\code{"partykit"}) introduces the basic \class{party} class and associated infrastructure while three further vignettes discuss the tools built on top of it: \code{"constparty"} covers the eponymous class for constant-fit trees along with suitable coercion functions, and \code{"ctree"} and \code{"mob"} discuss the new \fct{ctree} and \fct{mob} implementations, respectively. Each of the vignettes can be viewed within \proglang{R} via \code{vignette(}\emph{``name''}\code{, package = "partykit")}. Normal users reading this vignette will typically be interested only in the motivating example in Section~\ref{sec:intro} while the remaining sections are intended for programmers who want to build infrastructure on top of \pkg{partykit}. \section{Motivating example} \label{sec:intro} \subsection{Data} To illustrate how \pkg{partykit} can be used to represent trees, we employ a simple artificial data set taken from \cite{Witten+Frank:2005}. It concerns the conditions suitable for playing some unspecified game: % <>= data("WeatherPlay", package = "partykit") WeatherPlay @ % To represent the \code{play} decision based on the corresponding weather condition variables one could use the tree displayed in Figure~\ref{fig:weather-plot}. For now, it is ignored how this tree was inferred and it is simply assumed to be given. \setkeys{Gin}{width=0.8\textwidth} \begin{figure}[t!] \centering <>= py <- party( partynode(1L, split = partysplit(1L, index = 1:3), kids = list( partynode(2L, split = partysplit(3L, breaks = 75), kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = partysplit(4L, index = 1:2), kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))), WeatherPlay) plot(py) @ \caption{\label{fig:weather-plot} Decision tree for \code{play} decision based on weather conditions in \code{WeatherPlay} data.} \end{figure} \setkeys{Gin}{width=\textwidth} To represent this tree (or recursive partition) in \pkg{partykit}, two basic building blocks are used: splits of class \class{partysplit} and nodes of class \class{partynode}. The resulting recursive partition can then be associated with a data set in an object of class \class{party}. \subsection{Splits} First, we employ the \fct{partysplit} function to create the three splits in the ``play tree'' from Figure~\ref{fig:weather-plot}. The function takes the following arguments \begin{Code} partysplit(varid, breaks = NULL, index = NULL, ..., info = NULL) \end{Code} where \code{varid} is an integer id (column number) of the variable used for splitting, e.g., \code{1L} for \code{outlook}, \code{3L} for \code{humidity}, \code{4L} for \code{windy} etc. Then, \code{breaks} and \code{index} determine which observations are sent to which of the branches, e.g., \code{breaks = 75} for the humidity split. Apart from further arguments not shown above (and just comprised under `\code{...}'), some arbitrary information can be associated with a \class{partysplit} object by passing it to the \code{info} argument. The three splits from Figure~\ref{fig:weather-plot} can then be created via % <>= sp_o <- partysplit(1L, index = 1:3) sp_h <- partysplit(3L, breaks = 75) sp_w <- partysplit(4L, index = 1:2) @ % For the numeric \code{humidity} variable the \code{breaks} are set while for the factor variables \code{outlook} and \code{windy} the information is supplied which of the levels should be associated with which of the branches of the tree. \subsection{Nodes} Second, we use these splits in the creation of the whole decision tree. In \pkg{partykit} a tree is represented by a \class{partynode} object which is recursive in that it may have ``kids'' that are again \class{partynode} objects. These can be created with the function \begin{Code} partynode(id, split = NULL, kids = NULL, ..., info = NULL) \end{Code} where \code{id} is an integer identifier of the node number, \code{split} is a \class{partysplit} object, and \code{kids} is a list of \class{partynode} objects. Again, there are further arguments not shown (\code{...}) and arbitrary information can be supplied in \code{info}. The whole tree from Figure~\ref{fig:weather-plot} can then be created via % <>= pn <- partynode(1L, split = sp_o, kids = list( partynode(2L, split = sp_h, kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = sp_w, kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))) @ % where the previously created \class{partysplit} objects are used as splits and the nodes are simply numbered (depth first) from~1 to~8. For the terminal nodes of the tree there are no \code{kids} and the corresponding \code{play} decision is stored in the \code{info} argument. Printing the \class{partynode} object reflects the recursive structure stored. % <>= pn @ % However, the displayed information is still rather raw as it has not yet been associated with the \code{WeatherPlay} data set. \subsection{Trees (or recursive partitions)} Therefore, in a third step the recursive tree structure stored in \code{pn} is coupled with the corresponding data in a \class{party} object. % <>= py <- party(pn, WeatherPlay) print(py) @ % Now, Figure~\ref{fig:weather-plot} can easily be created by % <>= plot(py) @ % In addition to \fct{print} and \fct{plot}, the \fct{predict} method can now be applied, yielding the predicted terminal node IDs. % <>= predict(py, head(WeatherPlay)) @ % In addition to the \class{partynode} and the \class{data.frame}, the function \fct{party} takes several further arguments \begin{Code} party(node, data, fitted = NULL, terms = NULL, ..., info = NULL) \end{Code} i.e., \code{fitted} values, a \code{terms} object, arbitrary additional \code{info}, and again some further arguments comprised in \code{...}. \subsection{Methods and other utilities} The main idea about the \class{party} class is that tedious tasks such as \fct{print}, \fct{plot}, \fct{predict} do not have to be reimplemented for every new kind of decision tree but can simply be reused. However, in addition to these three basic tasks (as already illustrated above) developers of tree model software also need further basic utiltities for working with trees: e.g., functions for querying or subsetting the tree and for customizing printed/plotted output. Below, various utilities provided by the \pkg{partykit} package are introduced. For querying the dimensions of the tree, three basic functions are available: \fct{length} gives the number of kid nodes of the root node, \fct{depth} the depth of the tree and \fct{width} the number of terminal nodes. % <>= length(py) width(py) depth(py) @ % As decision trees can grow to be rather large, it is often useful to inspect only subtrees. These can be easily extracted using the standard \code{[} or \code{[[} operators: % <>= py[6] @ % The resulting object is again a full valid \class{party} tree and can hence be printed (as above) or plotted (via \code{plot(py[6])}, see the left panel of Figure~\ref{fig:plot-customization}). Instead of using the integer node IDs for subsetting, node labels can also be used. By default thise are just (character versions of) the node IDs but other names can be easily assigned: % <>= py2 <- py names(py2) names(py2) <- LETTERS[1:8] py2 @ % The function \fct{nodeids} queries the integer node IDs belonging to a \class{party} tree. By default all IDs are returned but optionally only the terminal IDs (of the leaves) can be extracted. % <>= nodeids(py) nodeids(py, terminal = TRUE) @ % Often functions need to be applied to certain nodes of a tree, e.g., for extracting information. This is accomodated by a new generic function \fct{nodeapply} that follows the style of other \proglang{R} functions from the \code{apply} family and has methods for \class{party} and \class{partynode} objects. Furthermore, it needs a set of node IDs (often computed via \fct{nodeids}) and a function \code{FUN} that is applied to each of the requested \class{partynode} objects, typically for extracting/formatting the \code{info} of the node. % <>= nodeapply(py, ids = c(1, 7), FUN = function(n) n$info) nodeapply(py, ids = nodeids(py, terminal = TRUE), FUN = function(n) paste("Play decision:", n$info)) @ % Similar to the functions applied in a \fct{nodeapply}, the \fct{print}, \fct{predict}, and \fct{plot} methods can be customized through panel function that format certain parts of the tree (such as header, footer, node, etc.). Hence, the same kind of panel function employed above can also be used for predictions: <>= predict(py, FUN = function(n) paste("Play decision:", n$info)) @ As a variation of this approach, an extended formatting with multiple lines can be easily accomodated by supplying a character vector in every node: % <>= print(py, terminal_panel = function(n) c(", then the play decision is:", toupper(n$info))) @ % The same type of approach can also be used in the default \fct{plot} method (with the main difference that the panel function operates on the \code{info} directly rather than on the \class{partynode}). % <>= plot(py, tp_args = list(FUN = function(i) c("Play decision:", toupper(i)))) @ % See the right panel of Figure~\ref{fig:plot-customization} for the resulting graphic. Many more elaborate panel functions are provided in \pkg{partykit}, especially for not only showing text in the visualizations but also statistical graphics. Some of these are briefly illustrated in this and the other package vignettes. Programmers that want to write their own panel functions are advised to inspect the corresponding \proglang{R} source code to see how flexible (but sometimes also complicated) these panel functions are. \setkeys{Gin}{width=0.48\textwidth} \begin{figure}[t!] \centering <>= plot(py[6]) @ <>= <> @ \caption{\label{fig:plot-customization} Visualization of subtree (left) and tree with custom text in terminal nodes (right).} \end{figure} \setkeys{Gin}{width=\textwidth} Finally, an important utility function is \fct{nodeprune} which allows to prune \class{party} trees. It takes a vector of node IDs and prunes all of their kids, i.e., making all the indicated node IDs terminal nodes. <>= nodeprune(py, 2) nodeprune(py, c(2, 6)) @ Note that for the pruned versions of this particular \class{party} tree, the new terminal nodes are displayed with a \code{*} rather than the play decision. This is because we did not store any play decisions in the \code{info} of the inner nodes of \code{py}. We could have of course done so initially, or could do so now, or we might want to do so automatically. For the latter, we would have to know how predictions should be obtained from the data and this is briefly discussed at the end of this vignette and in more detail in \code{vignette("constparty", package = "partykit")}. \section{Technical details} \subsection{Design principles} To facilitate reading of the subsequent sections, two design principles employed in the creation of \pkg{partykit} are briefly explained. % \begin{enumerate} \item Many helper utilities are encapsulated in functions that follow a simple naming convention. To extract/compute some information \emph{foo} from splits, nodes, or trees, \pkg{partykit} provides \emph{foo}\code{_split}, \emph{foo}\code{_node}, \emph{foo}\code{_party} functions (that are applicable to \class{partysplit}, \class{partynode}, and \class{party} objects, repectively). An example for the information \emph{foo} might be \code{kidids} or \code{info}. Hence, in the printing example above using \code{info_node(n)} rather than \code{n$info} for a node \code{n} would have been the preferred syntax; at least when programming new functionality on top of \pkg{partykit}. \item As already illustrated above, printing and plotting relies on \emph{panel functions} that visualize and/or format certain aspects of the resulting display, e.g., that of inner nodes, terminal nodes, headers, footers, etc. Furthermore, arguments like \code{terminal_panel} can also take \emph{panel-generating functions}, i.e., functions that produce a panel function when applied to the \class{party} object. \end{enumerate} \subsection{Splits} \label{sec:splits} \subsubsection{Overview} A split is basically a function that maps data -- or more specifically a partitioning variable -- to daugther nodes. Objects of class \class{partysplit} are designed to represent such functions and are set up by the \fct{partysplit} constructor. For example, a binary split in the numeric partitioning variable \code{humidity} (the 3rd variable in \code{WeatherPlay}) at the breakpoint \code{75} can be created (as above) by % <>= sp_h <- partysplit(3L, breaks = 75) class(sp_h) @ % The internal structure of class \class{partysplit} contains information about the partitioning variable, the splitpoints (or cutpoints or breakpoints), the handling of splitpoints, the treatment of observations with missing values and the kid nodes to send observations to: % <>= unclass(sp_h) @ % Here, the splitting rule is \code{humidity} $\le 75$: % <>= character_split(sp_h, data = WeatherPlay) @ % This representation of splits is completely abstract and, most importantly, independent of any data. Now, data comes into play when we actually want to perform splits: % <>= kidids_split(sp_h, data = WeatherPlay) @ % For each observation in \code{WeatherPlay} the split is performed and the number of the kid node to send this observation to is returned. Of course, this is a very complicated way of saying % <>= as.numeric(!(WeatherPlay$humidity <= 75)) + 1 @ \subsubsection{Mathematical notation} To explain the splitting strategy more formally, we employ some mathematical notation. \pkg{partykit} considers a split to represent a function $f$ mapping an element $x = (x_1, \dots, x_p)$ of a $p$-dimensional sample space $\mathcal{X}$ into a set of $k$ daugther nodes $\mathcal{D} = \{d_1, \dots, d_k\}$. This mapping is defined as a composition $f = h \circ g$ of two functions $g: \mathcal{X} \rightarrow \mathcal{I}$ and $h: \mathcal{I} \rightarrow \mathcal{D}$ with index set $\mathcal{I} = \{1, \dots, l\}, l \ge k$. Let $\mu = (-\infty, \mu_1, \dots, \mu_{l - 1}, \infty)$ denote the split points ($(\mu_1, \dots, \mu_{l - 1})$ = \code{breaks}). We are interested to split according to the information contained in the $i$-th element of $x$ ($i$ = \code{varid}). For numeric $x_i$, the split points are also numeric. If $x_i$ is a factor at levels $1, \dots, K$, the default split points are $\mu = (-\infty, 1, \dots, K - 1, \infty)$. The function $g$ essentially determines, which of the intervals (defined by $\mu$) the value $x_i$ is contained in ($I$ denotes the indicator function here): \begin{eqnarray*} x \mapsto g(x) = \sum_{j = 1}^l j I_{\mathcal{A}(j)}(x_i) \end{eqnarray*} where $\mathcal{A}(j) = (\mu_{j - 1}, \mu_j]$ for \code{right = TRUE} except $\mathcal{A}(l) = (\mu_{l - 1}, \infty)$. If \code{right = FALSE}, then $\mathcal{A}(j) = [\mu_{j - 1}, \mu_j)$ except $\mathcal{A}(1) = (-\infty, \mu_1)$. Note that for a categorical variable $x_i$ and default split points, $g$ is simply the identity. Now, $h$ maps from the index set $\mathcal{I}$ into the set of daugther nodes: \begin{eqnarray*} f(x) = h(g(x)) = d_{\sigma_{g(x)}} \end{eqnarray*} where $\sigma = (\sigma_1, \dots, \sigma_l) \in \{1, \dots, k\}^l$ (\code{index}). By default, $\sigma = (1, \dots, l)$ and $k = l$. If $x_i$ is missing, then $f(x)$ is randomly drawn with $\mathbb{P}(f(x) = d_j) = \pi_j, j = 1, \dots, k$ for a discrete probability distribution $\pi = (\pi_1, \dots, \pi_k)$ over the $k$ daugther nodes (\code{prob}). In the simplest case of a binary split in a numeric variable $x_i$, there is only one split point $\mu_1$ and, with $\sigma = (1, 2)$, observations with $x_i \le \mu_1$ are sent to daugther node $d_1$ and observations with $x_i > \mu_1$ to $d_2$. However, this representation of splits is general enough to deal with more complicated set-ups like surrogate splits, where typically the index needs modification, for example $\sigma = (2, 1)$, categorical splits, i.e., there is one data structure for both ordered and unordered splits, multiway splits, and functional splits. The latter can be implemented by defining a new artificial splitting variable $x_{p + 1}$ by means of a potentially very complex function of $x$ later used for splitting. \subsubsection{Further examples} Consider a split in a categorical variable at three levels where the first two levels go to the left daugther node and the third one to the right daugther node: % <>= sp_o2 <- partysplit(1L, index = c(1L, 1L, 2L)) character_split(sp_o2, data = WeatherPlay) table(kidids_split(sp_o2, data = WeatherPlay), WeatherPlay$outlook) @ % The internal structure of this object contains the \code{index} slot that maps levels to kid nodes. % <>= unclass(sp_o2) @ % This mapping is also useful with splits in ordered variables or when representing multiway splits: % <>= sp_o <- partysplit(1L, index = 1L:3L) character_split(sp_o, data = WeatherPlay) @ % For a split in a numeric variable, the mapping to daugther nodes can also be changed by modifying \code{index}: % <>= sp_t <- partysplit(2L, breaks = c(69.5, 78.8), index = c(1L, 2L, 1L)) character_split(sp_t, data = WeatherPlay) table(kidids_split(sp_t, data = WeatherPlay), cut(WeatherPlay$temperature, breaks = c(-Inf, 69.5, 78.8, Inf))) @ \subsubsection{Further comments} The additional argument \code{prop} can be used to specify a discrete probability distribution over the daugther nodes that is used to map observations with missing values to daugther nodes. Furthermore, the \code{info} argument and slot can take arbitrary objects to be stored with the split (for example split statistics). Currently, no specific structure of the \code{info} is used. Programmers that employ this functionality in their own functions/packages should access the elements of a \class{partysplit} object by the corresponding accessor function (and not just the \code{$} operator as the internal structure might be changed/extended in future release). \subsection{Nodes} \label{sec:nodes} \subsubsection{Overview} Inner and terminal nodes are represented by objects of class \class{partynode}. Each node has a unique identifier \code{id}. A node consisting only of such an identifier (and possibly additional information in \code{info}) is a terminal node: % <>= n1 <- partynode(id = 1L) is.terminal(n1) print(n1) @ % Inner nodes have to have a primary split \code{split} and at least two daugther nodes. The daugther nodes are objects of class \class{partynode} itself and thus represent the recursive nature of this data structure. The daugther nodes are pooled in a list \code{kids}. In addition, a list of \class{partysplit} objects offering surrogate splits can be supplied in argument \code{surrogates}. These are used in case the variable needed for the primary split has missing values in a particular data set. The IDs in a \class{partynode} should be numbered ``depth first'' (sometimes also called ``infix'' or ``pre-order traversal''). This simply means that the root node has identifier 1; the first kid node has identifier 2, whose kid (if present) has identifier 3 and so on. If other IDs are desired, then one can simply set \fct{names} (see above) for the tree; however, internally the depth-first numbering needs to be used. Note that the \fct{partynode} constructor also allows to create \class{partynode} objects with other ID schemes as this is necessary for growing the tree. If one wants to assure the a given \class{partynode} object has the correct IDs, one can simply apply \fct{as.partynode} once more to assure the right order of IDs. Finally, let us emphasize that \class{partynode} objects are not directly connected to the actual data (only indirectly through the associated \class{partysplit} objects). \subsubsection{Examples} Based on the binary split \code{sp_h} defined in the previous section, we set up an inner node with two terminal daugther nodes and print this stump (the data is needed because neither split nor nodes contain information about variable names or levels): % <>= n1 <- partynode(id = 1L, split = sp_o, kids = lapply(2L:4L, partynode)) print(n1, data = WeatherPlay) @ % Now that we have defined this simple tree, we want to assign observations to terminal nodes: % <>= fitted_node(n1, data = WeatherPlay) @ % Here, the \code{id}s of the terminal node each observations falls into are returned. Alternatively, we could compute the position of these daugther nodes in the list \code{kids}: % <>= kidids_node(n1, data = WeatherPlay) @ % Furthermore, the \code{info} argument and slot takes arbitrary objects to be stored with the node (predictions, for example, but we will handle this issue later). The slots can be extracted by means of the corresponding accessor functions. \subsubsection{Methods} A number of methods is defined for \class{partynode} objects: \fct{is.partynode} checks if the argument is a valid \class{partynode} object. \fct{is.terminal} is \code{TRUE} for terminal nodes and \code{FALSE} for inner nodes. The subset method \code{[} returns the \class{partynode} object corresponding to the \code{i}-th kid. The \fct{as.partynode} and \fct{as.list} methods can be used to convert flat list structures into recursive \class{partynode} objects and vice versa. As pointed out above, \fct{as.partynode} applied to \class{partynode} objects also renumbers the recursive nodes starting with root node identifier \code{from}. Furthermore, many of the methods defined for the class \class{party} illustrated above also work for plain \class{partynode} objects. For example, \fct{length} gives the number of kid nodes of the root node, \fct{depth} the depth of the tree and \fct{width} the number of terminal nodes. \subsection{Trees} \label{sec:trees} Although tree structures can be represented by \class{partynode} objects, a tree is more than a number of nodes and splits. More information about (parts of the) corresponding data is necessary for high-level computations on trees. \subsubsection{Trees and data} First, the raw node/split structure needs to be associated with a corresponding data set. % <>= t1 <- party(n1, data = WeatherPlay) t1 @ % Note that the \code{data} may have zero rows (i.e., only contain variable names/classes but not the actual data) and all methods that do not require the presence of any learning data still work fine: % <>= party(n1, data = WeatherPlay[0, ]) @ \subsubsection{Response variables and regression relationships} Second, for decision trees (or regression and classification trees) more information is required: namely, the response variable and its fitted values. Hence, a \class{data.frame} can be supplied in \code{fitted} that has at least one variable \code{(fitted)} containing the terminal node numbers of data used for fitting the tree. For representing the dependence of the response on the partitioning variables, a \code{terms} object can be provided that is leveraged for appropriately preprocessing new data in predictions. Finally, any additional (currently unstructured) information can be stored in \code{info} again. % <>= t2 <- party(n1, data = WeatherPlay, fitted = data.frame( "(fitted)" = fitted_node(n1, data = WeatherPlay), "(response)" = WeatherPlay$play, check.names = FALSE), terms = terms(play ~ ., data = WeatherPlay), ) @ % The information that is now contained in the tree \code{t2} is sufficient for all operations that should typically be performed on constant-fit trees. For this type of trees there is also a dedicated class \class{constparty} that provides some further convenience methods, especially for plotting and predicting. If a suitable \class{party} object like \code{t2} is already available, it just needs to be coerced: % <>= t2 <- as.constparty(t2) t2 @ % \setkeys{Gin}{width=0.6\textwidth} \begin{figure}[t!] \centering <>= plot(t2, tnex = 1.5) @ \caption{\label{fig:constparty-plot} Constant-fit tree for \code{play} decision based on weather conditions in \code{WeatherPlay} data.} \end{figure} \setkeys{Gin}{width=\textwidth} % As pointed out above, \class{constparty} objects have enhanced \fct{plot} and \fct{predict} methods. For example, \code{plot(t2)} now produces stacked bar plots in the leaves (see Figure~\ref{fig:constparty-plot}) as \code{t2} is a classification tree For regression and survival trees, boxplots and Kaplan-Meier curves are employed automatically, respectively. As there is information about the response variable, the \fct{predict} method can now produce more than just the predicted node IDs. The default is to predict the \code{"response"}, i.e., a factor for a classification tree. In this case, class probabilities (\code{"prob"}) are also available in addition to the majority votings. % <>= nd <- data.frame(outlook = factor(c("overcast", "sunny"), levels = levels(WeatherPlay$outlook))) predict(t2, newdata = nd, type = "response") predict(t2, newdata = nd, type = "prob") predict(t2, newdata = nd, type = "node") @ More details on how \class{constparty} objects and their methods work can be found in the corresponding \code{vignette("constparty", package = "partykit")}. \section{Summary} This vignette (\code{"partykit"}) introduces the package \pkg{partykit} that provides a toolkit for computing with recursive partytions, especially decision/regression/classification trees. In this vignette, the basic \class{party} class and associated infrastructure are discussed: splits, nodes, and trees with functions for printing, plotting, and predicting. Further vignettes in the package discuss in more detail the tools built on top of it. \bibliography{party} \end{document} partykit/inst/doc/constparty.pdf0000644000176200001440000042454314415225042016557 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 4359 /Filter /FlateDecode /N 76 /First 637 >> stream x\ks8~mBrkn'${%DO{%>dvwG@wt7@˄'*.Inyb!Nl"ID'"2I/ը,d"C4>Ncj<5>M ! /o@mJQ_TXV :UIoT܎ĥ꒩5m`1ۙFec-c ;a90vѻ+>xX,K6{跃NLqFdvF'AeX[lYNkuȗI-Sf#4~2ν<^jPa Q?_תƧ6Ftd$K.-&PŒ"g=\&lf  \F("F^u׊`QcIͦJ#>&{/L>;`OS=g숽d' |:1+ US(;clɦ؜g%df'1[%Xu(KV}+}#;g{? }/żi<ɴ#"'=:..kBhovi}?,PNDG|\ɲCEr6.֐4]brs5F8-OpD\ԩd^ͫrio7%. $,Wm,Zu/W\[I RĹ@`1ǣ}u47B$l7[N`t,@4~zGMhׯS>f{]@͆[㎋q음`+{_&j2$[Z~fET,اE1\Vu0.2S( *-gep9Z6!XV[r4_ی]浱RPz7egPS7:%ݯǿ0׹ۦ=$8Wm?tfWsLANVbCV"{a+xr>( 46xU z}_s"TrޚW MP/5mp/OVt=4~i0kũ Gfmm7M65>-ho3Oc;F͎>mT,JrJhЊI@D(+$e疒7-ѰsͪO:38L686dG]]H}nSrgy_uײ}=-fխQ_ُbN;UuK9phlV#Q]7>ߐoe(j oĺM͈1׏C.Fvo~J375d<5U3:vdȩUnsi[+q؇pН~qB[Wn[v0J]>?# ,'3yAR %mzoO&ldK*P'{ pml btu1U!&/Q~MN6~>bZ.!)qu lOfwKMvbn$9rC=Xl72kv I;8~vpg-DsvTS* UC@<"2$P̍Xl]$Sf)lA%W} @'unSa;R]2/9Bm0IIYS I0hrCRrwɑrddjTH%c-TŚ5OUnvʒ$NiyÒy)P&1(Q.m-J.ө;ڥ&9Z"$Lm&La4"[1u$qD:]nܩkIõ;Kd]Iܺ׍{uBuhEo췺^a|Z1SBMVI3Ms]H7F( Їo\9mQ4"UKQ;0R;?L\CPZ ΁딶;8]kC-[:x۟ӿj2*9ӍQ}|IsiDŕPWMG̚*"–u LSb;ȸXyjFtʺjO)&ٮѢ '*Zw5f\p%šަ/-N($0vBd_w0ثu)oT~5N2[wg7ћERLo(L1e|1 hͫ7?y{tzBo Glڃ6;lzg5}}~cmg|Hжr*VnWV^L/ 6:SY;,|^ɎY oPiœ᳓ 7_5͏fQq)P 9QΉp<@= J9O#buC4PU{/z'V1OxtJ.ؗ/_Y:_ˋ?ʯ%(jZpj<`.H^L>'JMkRcԧg.]usj1ej;0?+ś[Hn*4s/J.ӰKQ~PE(؇ ]F`>$@uKB%W Y* sj аpl ]LVR>vu:Phl܆<@Q,ψex|  q &gPT<ي ʕZRW[Zhfp/o_U|qY1+y'Hx "5|9zd8=ӗaB)FTr")nxwy=HJ@:(d鎧-lӤ}+02xʬ[r?K;6pZn@Ŗ\3Npwb39G.I锾 n|#vb&u#Q )"opcL)endstream endobj 78 0 obj << /Subtype /XML /Type /Metadata /Length 1559 >> stream GPL Ghostscript 9.55.0 recursive partitioning, regression trees, classification trees, decision trees 2023-04-11T11:36:33+02:00 2023-04-11T11:36:33+02:00 LaTeX with hyperref Constant Partying: Growing and Handling Trees with Constant FitsTorsten Hothorn, Achim Zeileis endstream endobj 79 0 obj << /Type /ObjStm /Length 2673 /Filter /FlateDecode /N 76 /First 665 >> stream xZ[s6}_vv ~d2k'IڕͥEmneѕlۇ{>hRrdY#A|`ɔ,(aA3q1kTZd1)gRB`8Bd& ފJ)bJ;kt *2b1y,EȴL5(H(^ ͌@i e1{fK!4 5R0+4G2+Z-i5MIf\eI*8HQRTIXJ2gzV9- 9OC(\𘅲 4h祣=*Hzd`&K[Z1} m0p'5 Zi,ҜTf %BEQ8 4Ў( f<=1"K6ICHJSn F7б1>I&i%ux'OXU@yد,XG,{#fa!QrͮSe`Ω1ݘuGEƜn~s욻y9{r aWg_U晭TޡqSv){4MmÄ< ը A j4*0]?e*[POQ`-}DzM3Q(|hcC3rr_c$O@W9uu@$Jv0:aNE5k~ΒNd.9i}kq#J4#۹_~8-4ֆZQL:{Y[mg1bLYlZ7ٮ1 c =J|vD-?/۟ըϤ88*,{1elQ*R v13#ɵ0ɼ9эehOmȧU,/ٺY ]qZ]Pe_pWs?e8MfπV,^I Ql|c^_8l}&Yz_ q)<+glgYU<Ϫ'HZv</ZJb;j!=%4q1ͱpFTz|oTOxZLg&8[,sR jN߉uyah &VӍoWneVsh%X|0rP ˡ7G͖L ̷Bb} LXy8ѿ>k5&% {\LJzAd[LX? &'p5ݩn0UGd@\br`6rG}{db;`ܣR\@n` H=S0 0)H@D9r2P(<*PK{P}apd*@&_KV7 -5@9V6)ZKqHHK @~]V9iΫ0C>%ІO$mj"%%4n#Y`faє冂4x_`q@BzSIaШFFv.!ۛeɐ +: k aޛx⹇)ܿlʶT]K@!θ2z:څh\ձ;T*Nd[XBX7RnmBIΡjkZGg?XfXKPFpvftR_usm6z]c=vov Rv->A0;T ^Yx"-ߖ nnX](\xLZ0P4=,ЂZj1A3IP I.dj/Qmu[\ |/zEvwa_-Dz͉b{F)rJR={q/ʿɟ"MU RU1Tuh-^bF?+UH;Yi}J/b\-U trؘ*,=@CJ: Ns+-wX *4J#z+DTX֑Ivqm"ѥV#>1aMLLr=}u?|.٭x]xj=0z=?whPk4uF[)6>ѺAaɵ0}mlȶ@DuIAc}{ \-a}mr֬#{.|蓪(guwbZ?)aXV|ռV^ϿOoCpC_P RNJ1-u ~ȲE>`O >.jٝ=s1<: /'%ÉElE@. KO9k[y>)gOW=l ]m[\i)dgg9> stream x[Isudu(GFTFLSLj>T$U?C2ȇ-, ~oϛ g3AO7gQRxWwmj)JixU{m2Zn{UsUݩ*YV2hoQEsw Cn0,?-^ïC|aQ\lPoDqm2{3!RX{C߆nhȍiD  (sKS6ʗ2>l*SW,]=mR \Ք֠υ* KVR|+M'5#J⧿gsN$|+)ɶIWAJF1F?þ⪄K YJ+gk8sgoœ.L.gc#podd78sVV㙑ru8{;vKoudKxnES|U[8\[*k@&5XPPuws_ȯBr0=a.|Ωys,؅6cm-gv[ߜm5_=}hXAx(.Q"[:>מSru]5:w"xQ($iR,sq5gFG{)C@B_Q`֣9OeQGoLF.Z>y}eYeq+ 09q*r .L0J`F499wuZچyRoO(g\P7> GwGԏ25f\M 3Q[I*2  i޷XP{PO9F J^Ij#=$Қ'Ee2}eڜKS֠`dB CQJb'¡R$/ 3Wh:_?(TUQ*! U*10\?0b;C_DZH/a؝ BAOAQXcbēւm7|E_,b3o6SracZcԹN?l] ޵pc >'6P3sƿ]<3Nm41-&-h8  Uc?|.fSø&m gs!)&sVmb)m:͒0fc d_ecJ@F* &J\|Lrh;F/g \*> E2bVh3- ?,mǓ(NG fsz4ryJF6JA<Vܞn͊(;uT67|y̩LQpGػX9OˌPDC A \nM4;j ݷU)B] P1RX=Ԁ&IJkܪ#$mj"o4lF Ev͹é(#Ѿ$DvЏ5,H=PPuRO֩͊-VlXྺ9ؤhnT PG}ކ ڛ$/IcNJ>"]Pz?Kc,M;̀%*74){jKfd%7zԼ(ڊrЙ%yn,vsAPA[[zvj9}#SӦ*|B!4^_w g{sS)`RU'i>4*\Pz ћ -)w2ꖹxi> ya[Jݟ8(ϡ %Wy#Q1jA=˔g!.΀[HbFӳŒF:t#B?6f* \Lj(c $+}<B8Z n3 X~lԎzZ EJCrPCQb{/<4Qb{c an-Ą҇5R'4" WyaGj0 ;+񈌩Ji_#:Jn*͒wI8SzN $|FKu`r\KԄ w7X[1tAFS4y9m_,|񄐋&jPgVh\qo3f*Ѕwxq' ]Չ\ R#iZAciu)SJ+{&{E -C|H j{OQ#[2^D% VVpnw]sRe_Y҅jfNf =[zy77~QVP )(VfKzƫIK,G¥>3t$P +B !kw9钷#jL=6цw.A$ZÜiL.RؠܙBBykO:."td 8P & @Y3w]I6Ѭy<xIuVl25g4ynt푄'-WNQ HtS}C[)Ess6AuC]ߍ] x /li'(M&EuR_p{ѐ*jCu\su) "Ӣ11f7.D8L\x<Yexn͚t`_zCx[:d!z9뼸̝ґj]QTTŇ|l8ѕo3\|P5K7%촧d:]Og҅vo90:f > D5p|kb&zFEvkU/5E6+}Wfpc5v^ka k$"}W}FYF惞UbE~ AS-_&!]}񁡘xu+ hMڪL7EM/_i'/ oR;350{dQ B*í_s!jZLz j?uI_ 5MόT/ ]<7ne Jδt uĐZo,znM_ RaQ*A%(ka/%t1ݖ *ZbC@|Hlpwy t< pvn2OCВW*QOnx:QVO|n{M+|nū,=^BcGxZOOp%Dj+ $7,L5YH6&S@NR_ӧo .zrx(-ͤ$B5$/=i6 uPSJ]IlqM5GK'=Ka]˭5K skڕ1]|'Oe-SjʑbNg &lxNΤ)! o+@ז+SOݦNdە616_|hV4.jsi2.ֶPԶ~"L3MB\gVR;jlb/nCWtW P8 >5H_ppn?mʏߓN=RW%ٺ# 59Q}@ڥcAek=jgljendstream endobj 157 0 obj << /Filter /FlateDecode /Length 5034 >> stream x\oHv딹A0L3/8nfv7-C[\wmV9ob+e/bի~>8ΫRW_pVߞ}8Syp닳I[lV_=GԹWkָY7Υck]*eowmam)[VJ/Mk]?n4,VxYZ7[kmGzBiW܇QQU[5.7e[w%LYUx`\l8+_B1w㟃 Og4|n6\Hƕ`q&ֶeq/GJG+pl[#{/L->|Lֈר}1v{q LduXߪfWWs_dG{x>w2ru2lu0?'_wnoN}8SM5.~rOQ~{+nd3=ۦ.v#bZj]׺A-Qt/.u>~]5U_DVi7_7lnrjP?FyEix\`7(N[V֊K{cqZ:1JnQ+Q?kdKRmT1SO^XR/P4Qk=o(͢69-)5mAO=pg=troddW5Y*\UK1]u{17Ժ Į@i?+pd'ui%lJdGTvA<Єa L/dA(nk]L CgzԅD]7ù凝DѸ-WtCgk fzD&<ħsl2aQ~(__*Azt gjM!4Ҟv|K"c`k |*.R/[ݖ"V\=0&l^Ӎ|֒9D[^KGN:H L (Lpۍ,gw8Ƣvn/=>$\>/p[ T@PBO8$>Mk Z^m8Aߦ֮,Ð``ȑ&sme0*.h?q#uaK)egTQeS"]7.F֔L|bJmGդS^nVtZu75a`  s~/" ~>^zsiRk܏(oA.m~VyEx]~\EF~KXeRK+ wݽ=.]1MoE>Vǁo\;ƽp,U&w|ֆ:ݑfE>sptI]𺜔 uxd&:<Co񾿹 > Cg)ءyj=aM}[R0m&A}75!BqB.@ak8{q N=a_f G;J23TcLH}+@HR,7<q=M9bMj.5BUq4urkm-Bnjς:%Oլy R)C8.=jiw1UM$,`yHÔ?rE"+4` vWEc'@Yn qNp%,Y"H ,3 uijRkRC׉xKTk} ѕ #3yJh킋ˑS%`S\!o|/>P[*Bu >& Q=|"xրAa9f:8 W9/hTYQCT1ºlCqi(Xx:?2@,ٔ !S:g熥$K{ԵORCbT7&{ ~?V 8%HF.q)LQSw{68FaNx*U.<Ƭa D}./Cz0|LZک絽H.=C̏cjmcb'5K if8v Uʖ(3Bdcg H t? 4#>y^n9%]$co ,9[VdK9[P(Ņ,OB ܦ8Q*k<)Ňoc!SeAw.{~Zl G޸QSo%H%pDA_Ͳf@ rEqs=hI\5 `-:Ǥ |@N ~hui~BUjB-> "B[]4JLi5֒e b@B8EɠPKVxB m@ۇ3xkPQW>Fpk^M(zmm?PRsrMhbOɕml,#B;|$h-*׃]M55<;/ո'R+ K >P]`ZT:R?bS|sbMUbSe"bch]^;o##3dN"00"49m-b )D3Β$F $EMXuR`e@G80sPRn΃((ZxkBb/ҥS[*bi55܏I'qi"ct {u ݡ'o%A*.#V՟NUorx֥F[A۷__>iQC4?3϶9E⸙^2a!y枂F-&|c2)żpH%7y8XjA`wZB[b~xB58*_jB@^R؞zn 3nOS7/R&Z /S(o\M K4RFΖLޅQS9DVPÚbS! EzUw[&AcQ80+ ӟo(pm+kX Q+>? `0{?qCSJӇ80<+GDK2 ]ޭY{,rxI\l |j!acҥq4QUe\^Wq:[شEmK18}Ltv湒DTsGP58\OqNp$uVZ@N*Xʼ*-'-Gӹx@.N:=mCkL7>ҐҫL|D> ESGvKYaj)z:GN{##=_z)th0}>wݞFdz96"uwfp(~!A'ʶBULba_1FXqY ^|PD~w#M0*/`C3->wWqFW6|_$~w,tIgMoÝ~/RKc!|H!Y,/q)+}ۛbtǾZQ-aScx-q9jԬ}Bs4Wuc7iSH$IӰ)-N51wt֮βrG;|vc}S"&;;'ʼn=,ĹND {dSS15HdjF25+Q"[94vVO)]4[Q0/5Pp fZֲ~N >3T2 _ez!8ULҝ_3z_o N_yqKڠY◘3x'_Y˲Df!HCGf/$Ncs;Z,ԡV} NuAo;(J!nʢ*0įyHϱ["IQbr q?!=~x:wyX2 u:.OB?EuM.USvJtjN}naf4\ld]0dUM}M*H՘Zus6nGlt`s@0K2i xb$wȧ],آJzYf[]a|KJ$ABݛ~?wx:^n1op#҄-#隌+Є#WL嚚RMy8LfzW'I)؜pgendstream endobj 158 0 obj << /Filter /FlateDecode /Length 1980 >> stream xX[~SaQΝ3FS1F# h%.mJ\5=s#g$]'ay9sov Vx}z"_mV/'ƚ7W+)z]L7K+0fu0Y ,Jc3FAT&tޱ`{9ӌ&RҌht6/7 5mz;d䑡WP5$Rk^1N_"TZksՌc7):"SN%n Փ v B}-et3x[%p,Xͬ{QD.RI%J+:`J98Kr0hYOnm)4*DY7YG٣EQR~_UqW&YCA  q2t_M'6\BN+ґ̯͊8?s1]Ea7~sMM6_-4]͂Ϙ?U}]|)稭vb]|]<[=\D,k//Cȧ['͑4U|w"B䀵9n,lcx+PZd;FkMNr\D&ypa`i ^M}()q`5 /-&O@TBWqx7Ի3" )>Tiqo*EfUf49/m5,9fTbjha8/Qq%cY6yj %яdy!,eAShOA6"UU`PB"?$=ꤻ t—x?GsT@7)xwhbW]lasqF45O80bJ5/c])g(rOo L@5! `*YpQr,kxD1-"B^Dje R="[*dz6NJHj+'ycye##d)Fxr C,8c.QBeBÎio5x(Sp(JmMׄM8` ]@5t cK'v6`S~ 9W1Cikx A§6gE7'8?Z !5/2arG{>$f7b1;\BEV7WX+^8 嚁 ΀8uz4m@?sl(_Ř]lxX93Z17gُY k( 8OqUP,8K:Og>:d',&vZOD ,鯢X_^$*Hvu RƷ쓇 /'MVKd@sGfϪ˜}n[KKHI,[#꜒B)5U)Xox@40y?#"`|)l$>m3s]%l2T?YzQKngS_4}rZ=1haf$4cfw҃9?Q5Wa.3Kv5=?B'_ oiJ ^s)|Vl]T;:2']=bN,4ǝnr_%yOG aL=uixvB?а8g4MX g _jsg22K.^sQ"%nvdvpInaOSt׎jCCiBs)ʇ ,L_G5;P~}0UlirѳE6Ĭ`~ƗzrK.__endstream endobj 159 0 obj << /Filter /FlateDecode /Length 3574 >> stream xZmo^㣹\IljIФ*V2$1;Iʒ.]'A ܝg^oOӄڝW'oO8==v_77IѶu(7!ϿW'x:9:gg?Yƕ/e ]a>K}VcnP CS- 'G Cfin)*x\G6sʰ2̄NtFJu"9.OE*i"n9+N. N0Ree?T&xs7Rsn`UIKY-2l*qɏ'i*u N*e nóOooo*ꫧR?o7S7=7nE8(b u(cUQUr|6')_.@|[onDXMWSKh% ,w- kr(7y.,D6s^[OVt-NxP޳7-Y(<ƽ’{9c.FW!S4d){n@W[\#HYjKkm Wg"QPC4QUh& Jj@+޲mK2VFPwVKd(uɦ \uh9T,Ew mF2rnxHg۞B۫.#56r<jr&˅j)@=YUODL˳;¤婏fq2 ~E֎۴ ކRBEA/p9qt*1ΫzfUMm !<D슈\}Sbe`hR ڼW9'Y(@ (y&-JK88ɭ_1qt#9rGe-6QWMGvBCR Y*l)il袬)8E ݇ǡ*N-F/JAAEp0ӢXYD .v#0ǭ0n/FHj^DnH-)w΄1^RrNyah^|/Mh)[5?؀cKRq5 cf^6>3qL/'DF*Y}0d.we3#<Ð=!ͨG%_$q|T%M1IXFbX9 EMfQY4/BquEu@9BM"{lmǮv]I[BJ\|%2:pC:J/Ɏ.+=bދ0`QK2BQq TXai&";1hL LNLa&Aİbl#5\zȕZ$*{YDĕFL(F]{#rdWf{Ù$"1 =cD`~OrDj܋@y^8 6/۠J<R'fF-}·T baߡ(ii jJք$G#8K%2@ $O!?H͝(d |aѐLJhpBC!:)/; fDո%&ɫ;Q hot"Hq,K7) /N\Ƹ[ǐ__>B\N#m̠&wCt~9Ƣ% 49n9W_7FۋNE.Dڭ9FMldkn @-E.F-щ88Z? `\Q{nI]OE}Ko*UB c {i4hB>@ʸan :{mP;*YEeOZ_&Z#IŠ(?\KdTOnzƦ6m U37Ky%T- _B.StU]X#䮉2cvpg4~g?]usrpuy_a |;OȒ΂ GpgjºYp] k5FOGH}`t{/xWlo%wGjfYP"U9\WcYwHrټ):ߵiAؕ}47z4 mGўwyFh`/v pU{lv,8<`Fx;+?Mendstream endobj 160 0 obj << /Filter /FlateDecode /Length 4211 >> stream x[ou䜝Cc.ag4; @I=&5yUYUdkF; aH>W?ٟ5}]n_]/J5.ޝ)lŹeVF ؟]Vk+:a4uV~=p7aX0ι횛aZW7sdhc3lfնvk߁.SVSrYlZ~Ki9:=}ۥ,8Fl5heRHL䪫0g$fZlh]cbفRr^} `Q0!m(̠_L,f.8ʸ h )[8z.> 3#@ylXaMHڌ ]5&,5Ը.J h``FKSWd *A1 qX?a83"UÄD 2Y4P3 )nb)djh,n@VK2׾MtW_ӊ^S0mw9jdDgiP'MW)"b8M w78Oȅ;A)@A4?z΅2<1 _@ L{̨S\tKΘȻ6ש U6ddTSԏgy=O6 ȍDun~1k#8O޻ V:"7:FcbPϩarBSp>yTC ' ^q)(R2~dH': }d)n+\7x? r3rbb> ˾x=1z .젴<>y q@0ALcz*_&N[Tc^@TpY ..>JCV?[D\S*U /oa fLVh[ '*bl|z7 ,T֢!~]* 5e]~8vק4F9.dmȰshi%^.*8E:_N㲚\vWDt,jE6h ,Gh!=- a\v6MiLWq-6OH3C7ik!z Ӆ.=!s1)^If yq²?CE wұuɡ8k{Y\\"Pfs"h^X*F}I]΃ iXIS%4IXX6o.@n<) !p(9ȝ~XG<`Q">[`,!̓ 8uf$$keK,>OhΘhwmդ( Ghm4ۣe_C֚| {+0/zUiaqHhP,`ؔXA%F֖[ >QSF=^!a{Npèy\-u0YcFnohPh9:Crk$(ApY?O`q;)ŷɴ _od.j3}Y%![kVX2)ZC5B(I%l4x訫$;ttt4-(6݌0y+МaTVôCLcH3<egrgMS,Ա aGΐ6 ܇21.N݅:U,4ɞ,+Mz8qOZMSlr脬Ix 9AyXvXzN R-ېO׏8OwC.?}99q=!9fJ #r^![Ȕ]u8UelHT*:}i;vc`|SW^4<@#GZSy]&,gq\“ ˜F&[C@ 7,pb5=F) _{CStf ^cZp+5%ftmph18SR1P\?~aJ;pS isRWq<D-J׻Wd.; GJ~Z˼=~2Xc \dzH/tS3P<5 )kFCrz0*&p<e3AKú1]zP^UO%Xˇx}/lvw,569)EDDHoYLFHxZfZVy ;|ȯ\rC/ucwo4|$BH@y z$2YCP3-30>;CSV|*q ^/2fB!FV̱lkPOfY\Ѻ<]Pa͎І7hTG T^L=FλUWyb5SeG'mW8-*7ƣf2$U}7258sXlo&F1;'hmǧ6yGA/z cU.B'g[K$~e.D4S!DPRJ,e;MƳ`"p]Bj7 7x aKHVe!f36qѯ<ܥr[!@uUUr3>Fǻyі(pgu 'E?*=v\G| Բ`Ɖ%$$ϻncVڢ}d-U҆W!uq{,=u5/@~;։WoOwXnB>j];X  dMD-b9xx3'5]gd+ ka-A>_GVetendstream endobj 161 0 obj << /Filter /FlateDecode /Length 2350 >> stream xY͏H !S6ݍ VB@x%qctd& <}&7ZÓWovOwAo0j[z7;+,JjvXl+ةJ)`anM۝蛴쫸{Bزư=~{!YZٿf;Xsȿſw߀+BKѡ׸tV)J]:cp;-]YUӶjGRh˕,bƅ:D*;%" #2!M6JVVx/2kU/&Y$S*ǍL"`>c9RU)|]_/Kʁ2 if2uǶ`J(tY.9]Z\̷s{v_ˌֺa;v9-5=aBJ&Kr]ʰXC;_傗;5^w/1'm"{sJ >ֱt>lj1^dϞ9Ou . Vh= 01] {TgYC{l~L*.Ni.5N )Ko!kX:'@I *r`yBE Mye'ɮ t8e!;0zZ8*B-k±*ClnqQA0R6d֬Ӳ1 8ڧ1ׅȶ|K4fhW*^.]ӹ=5|\+dݮ,suP2P␠m(ߧTe|,A{3 0N[fٝhRPIK~Z\_g:)gC)&<| ٸ(#4Ӗ&NFMG@ TW;:i _*-NWJӴT #zuO/=N!à,J|gCxΝSiop[rL[,ـv߶)q%X|SoOFUV{sÔ) Cf6{>! ~kxc+"ꍵ#{.n7a(f+$`du>}yN3iqlE"rTSZ3,3AB&Z^ ǩ/*]HIoc|TrEg @%kqqY$T@9C8fjO8ϫ֖+k6L?`X%"k($%2Fimi'pIc<$e&DT (1U,U,$U*qAم*̗Œ7C-}\)ҤZ0&wЮ\.n_:0g|01s\7/W~KBt$a3h`:[tEk<0?Q6 ^`h86CvR]^>]~`6avWVKXel;Tendstream endobj 162 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4480 >> stream xX T׶ ebuF9Oh4HDqJpFDIA&f " FDP!Qc^bKh^z`bB9gϾ(k+FP ^4,:i`?HY!=c% S kt{V o?9opT(Vn96_l*r9Ks.^'aƽ6{s΋ (vK7- 4y?xa3/ƕY¼x3ehf9,ÌeV1ٌ;&3x0sI3Y,dc<{g2Ɓ2L3X1qc$uVJ2WQPG<ܥ\20h{iP젏f;78bp!bo"NъqK RvG6Li)$Sv0Hb w2T8 Vfsv':8a}2QnPכ g2qCLӐj-*nݺZ<"[Q \ G>_r=03P@+5-y)Ye`?V/[t,G"?bo LjEQXJ4@Ұa%G+%0"EcDFElUv'b45sGb"$dIdѬ `>N C][Wkk|(tVBV0sw$č_|<&@FGKJVf81>i:C0BkUtz$wWgO_s[.p8g8RGlU Ý%G?8Et 9fߓ>p;m^cT'1>jU&vC",uIT8<'QI]ݚ T\LWIfs+XϋƝ*J5G\ 8@S X~%agB6|-۪,-M㴻K@Wt)X4mxsŠ1zDŚSyfZ֨n kp@լdIӵ8ZE~A)=: oDmY^pq!s܆rT 7 qy2!R[;RMCؕV⟳2pYNfCsRs8'BԪE%]aBmEAVaH)5C~`рahOSEp*Δ)#JOtKpFd#Lzev2 Q><:.8Ka^~G#h J?>(~Zqg!LDpEPPCKЬ?؊Z.h:+!| *W6}FN6QA.7^v E^V.#T}_G'eMEz 4t!}:.[c~t=J9+pC2WI@h2#h"H.ٍQ`kl!uO6J]hI[ ^0ҞnG|UFSF^IbLYU~Bc~i r'*7*dpw R'%QQ]#iB\ol Lubꌨ0yfpewe'eD@ڮxW`|V\zW@}Y{ʍNm!Z)ɏ?j+ +'w#Ҭw@o\- P8|e0JM$),ʄ03=MlҦckkʛRm+, -fֳd2('"''ZU`IPAiAoZ}L^FH\& ."|d1AOjOliYiYl >G7*ۙX K#}V'\oY~Vg/ ~簒wv<:ZQMM@Ԕ>KPdt2dE@TTB)} oi9  #n2kUdlBlcѳ--~ghZ6jm:!!ǜY[M%<$8"*puݛo_i/`dٛwvR:FEsF)%@4!%f tQwl&:cYSdLU79~9ˉ:XwpNC.Ꮛ4t_ H IERz9P%N@Zjز+ ViĽ;qYPI2Yy;!'Sk2墫PH66%ȑٻ@W)X^|0d-Yƃd)DOF7Ԟ:^f9[3ZկWmt&Ch՝>S -kY'b1U`-y8H; u{Fz\e(yeiŸU)W[,_N'{q,=T76d)o,?T!Ŗ~C+;e~$bESJKҴll}m"Qn yE2{K9Ô#HLQ؃m4`zFqv6EٽBJ 3!kž_foo0L;Q 0cϊ58zV`_ws #1R9[o4FF =s/3<'5P-&6Jҿ|;u^Eo_jIMxs`!LpXi&*OyŅ{ڷbY#N}qGhc|@v9=z8.jo{af xL~x@+<|;9#͌ 矋ޫ#xͲ FiY3(.S&}G DOi,˟!/u8}ނs2{y7_4-u|667[} !+]6'm8}e,\Y2O~j)T@L3]1q$aw:Tn X^ȥϿ=yOGgvՆJ;Y )Jc#-DSQ^W[ ܍XCbRdu~7-XqBuU&}PtXD pފV[6=q\_xǷ;~'s o-^cag{l/Pq+"_ ?4,\wJ)ESG6L֘ Hxu!QCt4z* ϡCTF-zPd :ӣRv$&;NPSDg:{-/'p qGe]clXgv9pwf~il_$:bۤlߞGP@CF{ vhkjDwdBWxqWgOtzo~PٱĆչBk6xZŴ˔)ۖv5ZBY >:1%WSfCC.87wuK]ole#R Au8Fz5xt,V0Q?nYJ5xQER&Onm1 C 5%'9 ,o$7TC3d8RWv((!-Q?ܾoS4ŜnN.H=%/0g E{nQ0 _L3{+t|'Ӹ?dSצ@]qqFu%jPUo)woBQkY^@ToxJj|zӮu?Հoa&]V Cs[ /yc /ZbXollj]#qMu~~}}-GXZik}3h8ym4TȮCOo_eQ6ͅ]+'E_ ,oU6ZH@2H77_~sتgO?KW%z$?q5ި$<>5n>?Ǒ(.xضu$*2H^ngMHҎ(n ޾p[-I^nAZA@zYXi-jkۚ}h9?7˜m;a&f\endstream endobj 163 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 8209 >> stream xzwx ڥ de:SBI 6\pr%k$*[.6ƦZHB1Pr9 ! 7>{X$Z8? 2hg &G[DZo?<{6%㗏^N.ngnnm|{v+}@Q*[us 0/p~Ђ!B- w^,uyԶnv+=VyowZw&OiC`>mk4q !5JfPèUpʞA9P#(ʑzZCRcuj,K6PFj>@-lEDj15ZBMRSerj*F,()ՏQpʒSV@ QS]n="K^?՛#FQfT$RT.%a"ff/̝oIH.БL/Ƶ붮V}eo{\^/^_j1}ַ/pZz_Jq[<'XY[e (3ܠY>g; UP sg9x!CC [9jxG(G=ӑGCz&spQs. .j.OKɈhШcku;s^d4uzAdi@rө*P[:@C`p?%ádn.c p94Z.WKi _۟Bhw2ȁy99 -+}諙IޢE-܀̄ -RZFKk~vG{Ǽqy"NTj/nEWq}.Gݵ-:+b+lWWk OIIRb )2bH΄T+51n>%)(I*G0'prL@VBbCz yf]TC!5# Ar4'5h .4Ip]@vƑ.Q#gw's[J*R<%>)r `wgۺTHn #EHCÖ(ptWtT,fpgbQƓ(*ټӇdSJ.D+iٳxO0wļ7~#_➸h,}1+S$eeCn`kYpNV:xl/}NN ܘ׎Bw[Ze Lˆp*VR /FAiVe,G{glpF1d* ;^׾BRoF^׈7.Hݨ@4rD68צQ\8NtS:Ȳ!#V x-ZO"`Vu1t}Z& } h)CET!.]o^vx +z۠hS@#E5V\TxRڇ/F>2$ t^O0!)e*<_YtZtW??E2ŴnMlL蠔A߱#5^?? ;qDn^'ϠRY$+"$Ix9[Fy<êPlj$|7hyͪ ')A VQiP42{s\ܺȐ=l𬷇p hZ8cCxU~%JyVfMB> &;kd(gBi .? aq'#si_Q%HMYтh/n5O^#@W#:TbƘ &q5!8!slUg>x0 h%u&LAB`Ljv5>e +Rs-<8Xâ.*Ʀ^8{ EѶ)9 4zUzV @ƿlؔ[CuCq A--_P(knV"nB&= hXȫS }W@LNAP`r(,qHH)~pŮpaK4Ԇθ\mΙ9,SWtuIѳ` Dc{&@\,Q'5n."BPEm`Fzݨ=w:OיS=܋`5yx`b!)Rt$t%%^e$胟~NB!yqk0J&Q{>xSK?4(Kil KvYܯwQ$WD쌝d< _UnE^^` @Ѝi&A8Jвp  C}dgVӶn"qh( vrD;]5JK{F{?V}!/.phwG'v:鏄+z} xjlIti`|*(8{~I R(PGodF%wC8ZdIqD-݇G& Ι>t@hiSǯ7A3QG3a{zֆ&n\ zCl`هĮmae׆N4@a_=7ם&$ƿljJ1# Bil@$8SP*R*G,WOEHUacy@JF\d;j/1TpV[qCP/Z5F %9vΒB\ X:T ~6@aJvl*7#b NEɹ䍩%'N\M7b "Q'ܐ.YA@+F^|˫#(MdPFu<|xt*HRHc&ѣa[L_ioiTeuqien:EUݑZ`6QN,=h-leO.^>P +Z|h`oc2n[6=|MO'{#ZCHX;BX~"dy7 xCiD!!I2>.GSq.-e Yg廍A^TͶL,ryT-KW:B>@{  ;0WF#ۖZdF MV-)c ӭ TH)MlaqtCvϰLR6o\2% JzNW kC IyX_g*I%$2R ;S^f7vS Kf:mfUCSKc] y`Jdb%n r rt9OeVpt1؃ Qp~bgIF$?n1D#'NM;ݐ=HGi<&m0VaŒN9l, F~+gQr##N[EںxmJrc12SRIU6@ɟ01(nɃV_7IQ̥f( qbә3,ϪxLW(Hvё@z.>PwYvuQQpѨ|! ,,-٬Əp0~FPzd IŽJ*jTP&~K]3%ڤHvN}3 F |-4tl&ȮUPH?]bHZ!35i[{um$Y{ )4AL|?җ]pdG_S!b>$5)B23e#m%i =M3 s5ʸ=NB4D]EWIQjpW_E, rG>5(h5:-D0m%":-YMUc۞ȳt `!D u9pK''SXa6ugHa  P ;a{/I(#+wv"ܦi&A&n}!nuCd !Ó Qw-Ac$/E(4to9}AfEb[k f1t_" "H*`ԑĄWV="gQ^ _[xo;,~_4F=sŰd$VYTH$AN`rd@ya9r 4KؗRZGdEq·\Y)Vrv6`G[n0EH/<7.. \V^n[Wͮ^+9A;5ZʋJ4%k#=tJs͢ O-GzJrl} pHv#}Ž_g~6! -V5*x1-=>R~6RvkJA;wVߐu>fq94ZtҧвKb^VSKq?N`Ie_=y&mIgu*Pths{%5.M AN<ĜQUI;~TYiGְNj.iىymoj3t G e]o=E]GdJ|p;0@=r_/4+@r#KkzK”!CSY//\kb6HB_pzlA&q-N!?$}.Bc*!;L JaHl!$DĕUA_"<^ YuwLxwXʵtSμxY_&g?M,տ\#mb!<&uo+uyW/Kn nvH(u.kF[C$qkB(_uL^nuiXKǴ쭶ۏ a.u:DǵeD%jT)*-Lx*Ϯ9!D@*kЎi<(}ZZ> j>lF Hɿ%(9[8'?<'9v2 L|҆O (-R7U;R)>Z_ %-Pi R\x2MMI'}γPَB^ig r=XfJ0[o>%&纣MmrC!>Air4-UUF: 9wn$ 5ʍ;(wBep+^ v0'eNio#p*}해53-WFrr鎱[`4E<c3O_f`\,`0, ~n.Pb~jΛ4(tCK'ЇuW2m8G`/2}sLmt`ZZʔJw%D~IKRHR@W&uO{nːӟM\!r%f3"MgYoݼ*Q;ݟYSF&l[tjVH6mhY*a3\l {(ڵh #e\etK1ZWUTT԰_uFV4Rx: (Yx-b;Sӳ~P\$=BTt{"UuxՍN9+8MVVTRY_yD[H%{~ v19>IR$Dڝ̋CC~ he éYgG EBV9m SNd.=R%EьWelIyyΏW7ێa% H侁&3b]%BIl.7ʿVT*I׈Yj.,bԓ7'RV[y绐ECn܋-^}u V- :!AH%;R(Q ūhG((^-L2e6u(;x_iZudiRuk:>^sNr,$ Dm`?~i7J3x.[޲z+Y`bf--$f|Js$\oY&\hUҨ'@iOn7r:^F~nI7JnWVڣ+n. {05!-=GO?y\endstream endobj 164 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 6436 >> stream xyXTʙ#`x=C4v%FAcT5 * ozc#v, F&&7i$:f0r|3>e~׻޵Q:ZH$^(}}Pw\aH%C; G ^"mdsy+ צBd>G#e>^!f˖.]d \ev(4<=vi8c6_hvLil&G;vt\`GFEYp%h&xsȖP0pC"Goc-}c7-fZꜵX.ܷh%nQ,jI^ަޢ#5rSnj!L-P^jr6R>jeCm^PrʎzJQ+){j;52P,5r8j:eDS&6eJ͠t)  O :j5P[P:T,%Eiк^NgNoѩO3eOzb=k4qD瓎L:y))S~f8kfL332͝NO_0¨Xdf?&;Lnޚ!i:̦#_çy,1XI<%e5IG+-R9TZb('g@=ġ:c9 A))) ( hFUtu#jG^ta%0[+4jɏtU3j൰m@wxeP8) S҈=#s2ͻA ÞSkDDUhK7dv՛7Dm/x\Gϵ[2dxeA0l{l `oEZ F=!bՠ !tj~rU2 و箃 ]Dn5 I 8*P&4lOd8CBGix1) X!&L5u|<,-[0m 8s{K++ϾuG7^ -|̑5Qd_\  u&'TQ.*]}ih 0 _SY JF5\W0O A|t/|.DeG#J@"DM ɩ|Fʈ݃M ՂXE`Fpd,Ĩ5ysmP!Tb'b@7Jl/di=1kxZ u%C 垊kP7 7V1<"+P>*69"x%훔+Gc*P"Ə"bP J0G5c#p^M9xOܑRMdG<`4ABZ2,Qۈ]*D \mI=[#93b- T?5#(+ֆ4׾|VpUxbk+[FU~TL⮶+pO՘5$Ռ\ 3鿌Lr+g\ #T+7ʡ0W痷80ws)zi>+*;c$1y&OPBVysS/X]߱䡌ON+ Bj$ H^TSy]h%^yurV+x \&'87bVOF$QqͿOްx޻p;1U<m?aпrVձ5FB#D!)ˈFu޾aQ|CBb֡KMH X#z PӼ@tzч^zjpa pUT7?]A2Aޤ>7aW ;FMCrf{F o&ȗj'T6f0Qڀ#u".]= 9{}uCOыz{[{xv_VqlRu;T5L rqM^5$ԸRT&)D҅W!4X`7/7U2mxvh J59\{0䱘 5>z/I5Ǟ덼^HŇ'|Z8I;E> A`nHN drU+g3YtsTUJQʩ̭u'0h´B%A) y9I<zpnh-QaVVmvyV*B?/oMx^amn3Pqg-gJ:Q]\ ;ɰeQ^(ic}srX!.6p1b?Bi< V'QL-mxբ zx>W٦0A 0/&ɺQ DV UHI'Ce?'P>6S\AG@J%<A/ָR!f$hvb;)} f؋<kĚـ}b=S"M2ԚĺsH6nDa~2AHfa2b2WT&a-"e<{hTd}/΀qI^鶏$UAAmD\k JNOSb#[!f;_o%i:](7"l-w˱s$ǾA*T* f/#A%h C~ w2] Hg<1h v5J L $ٖpn9f'4ʐ1Ñm$:!O6O AY7SnlaHG^r~Rir)*C充9LPBc8D}J%0rW5׋f堪=Lh\3d-zNLZT&*HJ E%XF-N^°?Q~4}Hj;2a(١cx8?K >=s1a>/Yl]<'CycYB=Z/J /ݲSSDqˈa5nz+;ths]ЫX焖Ԏ6N%5* ?Խԕ0嚕[~,Q]57L\#um9̻̬άʬiZpR_YğPD$%Hi%FQ#?A(.;&Px6*`ZCBBy6q7yvZ_I͟(Bfq_4&Crqͷոhp߷j'9;kՑ= A=N!4^js4D7$w׎k]]>?5)pZ?PBޚU+=[ZKS :G̣,򶭓I)Hn߄*y6,3*}\w 01!PkͶ+=X 6mת,O)N;:ڥ/xx 22b dTqJI h-}6@?} `_r1))|4(ZNZƤز:tICcCQ$]]Y_6WbRMbkÎZPU[VG A~iIOkUǂɅ>F8j2P8[CǕ-due4G]ul;B!zL'p~X=vK=ă$;r}$FB:s d7X۽qǛҭKI HB*bX| t`'.65:O0|w _dG ~z rv:ʗ+_?zTB\T[B;x"v cgȫ)FT \O/oR_&\UN+ ?S*#Qb|Ph}kZy惏"ȑowUUI=j #HUTV8}`wͪ3} hC \]˰;-M>[Sx 89ػYlK>gI9~uY ~ꍯ^ٶ}8?s"A"rƢV݌brZQʫΪb'Ԏ=Jh|3ٜ[`mb=ׂ~ .]=')k/B++27//U1AD{ .ڏ9]wp˻j ' t)h?y`?LՆ!lD$Q%!9WSA7)-!#%DTF4Trsnqv*04 w޽;zv^s>B-Bz:$xאQr隖ҚnhGwDB`u{q'B.BXW:ΗQtyŠ.U$F):qW%'.L 1.g__~؈iQjpC,#K O)IKUDN> stream xuUmPT~ݽe]sw$1P5iQ5ʗ_gwa! lq5cokښD0N41'ڗ+鴝4?{9y ! bڤsai0oc̢`Y)F! R5QBf:fba8nA EzA*󮲢V-?gW3K,yLS>1.)N\"3Y9zs~u}Zj|J~Mb,6$$I}mK`H_߉31o^ẰNJQ"^h'哥%[fZ~[pfm-0{nSgbt[8tA&"Y۔e=5!v%>J/'*:UJ.iFdM"ȇNီvKh!vr Y[ےx8ڼ%*Ylo:'!KoTm8٫bVϯ\K=)(K~ E a5d-&glR5IY0Tٌ,8:m }_I,|Or9挘00 Cp{`Dܮc=J8EQ j˺ z*uf?9qcG}PQVW!m+)2߭dm;wel7L.b ̰SZ>a;'ƢǡؕHP=n$@<}JX>soa YT?)"Fq1 Cc$-`w an5uUFsz Cq{p[H;>?M ϲ"Yd,&5T^k]g0/޶feڭ`k''j{MMCGeSK),B8-ԍecJQ _ay>Z>78Yoҭ` f bXra'}Gveј/r]B|Xgs =έ,*"=UDO* ͨoQ!_;;`e].ylp載Qt_%+%t|z釢ϐ==}\=8_YΟXTP G0fHj:fk[0`+#Nyӄ):mt58=ábPs!t:!xendstream endobj 166 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 529 >> stream xcd`ab`dd N+64 JM/I, f!Cß <<,}G1<=9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5300030230QLu}zÌ~|ǭ 4^߭پ |}EJ7oۿ+}g:g&4*Ȕ'r h_Qo}ZyRwVߍؾZcwo.*g|Waq6dvC~vo1h(}&gw☽YSά]21Evc?;+gܬ!kB8uK7H9Q~kcʦv,/_0;3 p%s!kOuK~x;<_s/Mn9.xnͳz< 4endstream endobj 167 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5422 >> stream xY xSe>!4A#2TDMTQ"P`6Mtf;ɗfito7]hKRʢuQPq=O[Q/w}O&}S<o֖;R$+/}>+*%)B<)3T"`fL=9oޒYr'ҤyI YA+/_t)xPt^eAbi⤠(Ile[mK&-JE%F;4xghЦ!.^c3Amn ܔ97ٖqw&Jy1uG֬tA'Bb%vċD0XO,!K}FbL}+33ٙ|w5{  a݆#J,Ѯ{#NJ:f0x>w.w|sB { n#[k*؇OG *1dLV(3m@Z\PTDkM f@m4;Nnm@n2R ,P]pZ4\mCWV>FޥnwΩ#tС zJ-.ddokOpp{/hR[$$@nVA,F PoU#p' Z^X[VeQjZgq\`j-o|ty Hb!hI8E'Zlfaє7Qٛ|y_mc5w''s  | +ɮ=} _Gy%b; r%=zcoTbB FGh@ULmYƎʽ 91)Q( P,Vj=z1 ]u ?׈V\AS?z<:]'ɚJ&ŽAK&0 yﵡ^?CLHPePn-hhN0NQ3FQ1Ƣ5c2gZ1ʊ@>_f:ZsBeFd w]&lsOhбS%K^g<lneWߣB4kɆ+ENJWKTY{E?Nj-5P4XI;,԰kmBCE}`KKKh[SSFV@ ]*X؍ =7-{AK_C h[9Z --xnK3 N:@k1ˉp˸<(,Y>Nyj*菱gv)JTZ?cUNܳP@?!FJ Q]((Kv,*` 6pz}E{;b~N ?T{Oxo1[KCe[L~& ""7U#Qܠ. ,Mdx@HgR5dODnvi4N'Y$ \}ZʉζzwSSvOzoaB>{3]J$+#+KaX5TC:+.+nۭ:q)K&7/HΠ'5Q3loro)UR-NN` ,_Yk]& 'Zhz9Gʞ !Qg61#wgcS+J̅/?nMZlAU`Jӊשk#hç|_<ĈGg_roAߡRSs>1qI4R NNI3`ZR{1zO)[V˵ ${RSf{ Sj?(=gP_[mh ooF^om5Dm&IgdJ1Vn>w;[f(uG}9]nLo] 3m3OhGc]X {.p77{Fvp#`/:'讏VdgI r&9 IG{=7i.A60;=mp0D藲]ce8eAV󊭌N]IEƤw MP,XK*h}kM\`Yi>~o:wK݃;{d !KWKWF{G'+"Fd"ʏ5E #Fis-s9Buʶ'~IPoNs8$ ƨ7h'\I e7q ښ^AF0!Ț&Dv}LcPJ&++^-}˸au#쏮^ݝr)1Ũ ֏MSn-I(h7@-sdd&tׇب71IhyPgp䙐KfWU66vQ?N=M{;/~ݩY\(6fn /|K'[m￟:u9D0FH-757:\Ռ/":4[tJ;7]VJѩ/qbف*5{uT8E]i&HziE`"wb!j308A BAHcu%Pm s n [R6ƏkfY }g̎I贠c(MF~,* D}qưrP#=͍.Ә[+{V TeJȠR!HW4\;4[v(mL| qT$@ 嘹8L3LJB/޷f&'#ʊo|UFDR7j!%'< 沺crJ5C1so^ۻRyMZ|”jMVVs|][J 5FG?<-8j:LqIbuS ROP %,0 ` tu9hK.o -ZCzQy B4i=8},ٔibRz*[O!q J<({~h*ȑOrw 3Fަ[+N^j;P ]3YbfҋrtJuV j誜Av "nD]2mW#.~9:_O -lMILPe'Uشf ::<7\ TjYYm2W"lS63kQgO⡭6q.:bx̹mƯY#Դ*ʳ´u/ZqFq%^xL=-"S׆xzO7t KhܞYs,5;@fds /h9zaP +ϵ^B2$*wCf],qDn^n,9aZ=JÖxi7w5q^.K'&W7uz:ڨ4jqJVenKCOx|g|qv~ů.Wdf95OqjAqG31pï(ɱR.w;dpX>)4`Oksg9_2&]btPT,u}6Z]_/=ԍ 9Ż|/ VJq°`* Z̿C5v j0 زWEnpLs[tvE̘3Yl:cFOf.7Yju3~G yVendstream endobj 168 0 obj << /Filter /FlateDecode /Length 4031 >> stream xZwܶrAGl"~~IlVJ4+ƻ¥}grm7\ ?}̀?,_r}P.~?0w>|rqp|.)|~ն>X0Q.~Z-/i{3+R+'mf&v(`饬$~&`}ucdzRYR.4eŖ8F+|/p|ݡdQ]>HͺlMwƱfBl6[(oI67]M:px&f횛`=(6s(Wm?:6]I8, VQAG鴝L00nV骲r }*vڴGБKv6k>&ϓ;L_e5ਕ+ׄ纻 ;Uf&i&[o^rDeU%/^\%N*v#XJ)o *__m7`F7tT X!<N }VFULdah {uiVq}i7fhOɆc#sNf7҆=A(@{Ƞ]a+(Ru5X<5re8i%5Lפ;†_v;69>eJB -E G'iTj'bksq@)a xH&5Ma}jxܳE |7hrzNzv^\U02N2xmtc<#&mW)ͶvIake徼˙8p20|]&T# zNŔF}xV*,1>< 4#dYe'oR/*C:$̝$ s7)yȃV53]#o\"Dt~:4cnJck#+qV~DF҂R ёj- *=_Wj*uKχC*(DT!^H+VZ?rüPb}3Fu|'9j5oaT:gG(ί\kF6 <}~\;KO7iXnGgN˲==vx8Y4 ,ҊԹ!rə|7NQ iA{>^.g ;z0^̬IG\z2p3!HBq ۙJas?Ye,{4ijrH ޖs9h(' ǞL2XpbޕCNO@|ӛ+ Ï^![t#vwڃ 8;+x{Wƀάbƥ_=2 ƀJH+:o/~8( MtM% #C ^g@`~_P:WZ/[c;94KIs{8{ \>7 r/kjY<^B<,HmҌar}V.ei`rt. i0pxzi>Ez@$kP|:uH X;ӘRb` ^LŔp3m* =@.5XU<1] @G T>^r<` HY u~gC1DqI`%T܄kɾMY&aK,DepchD0ExĀ`e>KUz7]Bq~Hg |=ƭ"0h0dO> lX,w!vJ%^I!(H5Bu{J+?1`.>1cLbyfI0[k0)U*#!Fʢj9t7]YѲ$#v,Sg EIA܉) w9z]$LN 95mY^ V{|DD粖{D'Wa %<+zELbтzo,]S >hoWz_\ DoMVu3Ϛ^Po}I.6Mui_Vj!H i_[=.zё3ra70~*)MkDB[~RA"rv z(Tj,LQoKGb }ܢŐ~l] ]Zd,# WG ũKD9]ⲧC\-Z#̇腥!% > stream xW tT~d3ϱ4"j " (d0d$f$e7K&u&LH$A6HbAR)Jcmx_z;$j3睙D"Qa،˗&&+9W 2pJ7D|sQ\3o*IMN ||K,=ue;2 `j`PfF`\bJ<)03)0X+4@@,FNȈN1xt7,}9ÎA8 Dݧ({b[ķ'QXk@j]! ]EpX0F`DZ0Sn4~ 06JഠmRy_;+SqL*G2i b^&)h6T-CH/I ̇Jd\I,ΡKW-!ه6,nz8KG1LElJ4Ћg?8-GHlJo}=tTʙJ;@/ho2xj()j]ZGȐ0uJ]f#JSMUbf5d~כ* *]K"f#A{J4οUk3-}u\"lTѷLeR9oTNmZ];ܨN6KЌIlUUVI)ZOX265r&:jn7A{# %3ꤽtϧskSSV9egvC5#VXөQHHh u6N!_vHy" E\b49k&h2 Z$L| դpc]/džh LuNc1H{n&!K&q|y3#;Jr?ws߈4lҶ*@QBʓ`{@N 682LPd>ư޶oX/W/Ly!}0|̔1P:N䖟7ps^J$#j"8K1{=p Fzu)H I$B}uYR#1(8^t`z:d鯻ws %mQ5EP+tH\4*UFjϢP!Xq2)}E;=g{-Kțoa'Dvrm(2UN]BE!T7؈ZշOH F4A:UDaUJ4%z_EV,^I[@BmF6FP@Up\ }T[c6W{fh%"I&uWa\:2agRIqB n.[ϰ DG~IIn:E#&vl+QǓڸp'C_jFv0ln!!Ke.ړ9k?W߷W+NoLV.V{0%fTgeƓF"ƿV3tj::P69;9[Rnbxv^%zTI|[Km(]|gpiq㮆dFO;WM66EL.p?rI.L3 $?~օtf-f ɞoB*{Gϱ/$ 9MVK1W5Ef;](#.BoބA'i0DޱCh-!Vlm 5҅࿄&%1ap<M&]o7:Q"d)[Z`; w9G5~mbr1}> stream xemLSw-P{WNjQX1Le) Tz†k*{8^tTBP"($j6 hEe&~1'9y~ss! {rLr[AalU b!~&?;f@%"WcRo1]:*-q`35Rb =le;tqRVQo]$ bb晷Sn^ G>!s&"52 R)h0T|<,Xj:[@hV r!P^ 60چu^]h#]T~`opH7Nzt>pӝ~ a%m8C~Yة4ۆme'k TGOw(K?g9(> stream xyxT aG@H HRH%L2YɔL&N(R *CUT^u3b?.Lg=gֻ5t6fڵ11{^5ccphb87Ə?SjpCό{6Ƀ_:5B"S_9w 4,kYsf .ڛl="b#xzڙ^b1^{Dxńxm FovjۀE^_,f۫cǭ_:yO5֦_͑Q/̖I;&.4yK/O}i;kF̠)jHQIj#MSSMTj3 R˨mԫ j;5A-VP+U/5ZMͥ^QkZjM<( (15BI(wj(I(zzzO=JyQèj25zEPSkHvۅ!zׇYGR!ѡvhxoFl}ǪFǩǣGq<1w[ķ;o,p$$Oy2zMxjSOtǗUL3'80sRG'o{̻/Sf֑|mIvkACyC8PgS5DgGB4HA{*99$FQeӵQuP ̿2s9Bؿ946O dFJQ5P&):V1h4 }(rڀ.7=~qMl#_$67Ǒ >zs HV) h1y.G^/XPt( E3^ׄJ>;| d;65׺$; {"ŕhP>nS$~2 ]%`Ve3}|R~^7 ÙղYvt;I$MeȭHdധ6s)߶?[_ |P댍8kF肨H0Iavo';-%::{aMEs70uZ4>; mv0V*xXbTPgjԺ,ЧE7 X ?WG׻h t-y;"#qȡvD\8W:>jؑ?a'Qf( #4Y5OɰjL^Tho۞c 7@T"Y1]F=']zK|zǎV\}xM8L679Qc|0{YVn4U ]&81n5æ$oO#;j'G!+7Y@j⯋v-hyYJD; 2Ё9Q=嘸XNId%3Vp`?z!YqM%eo7 f=KhevT^6oEj :ݸs , ESjьM`!͔QH"@TSH#{`(4AgS ɘYvO1þր@5IIG8|8La$]b_f yM (RЂde!Y/CB.] phn ֡hX _t@]tDž?0Z(> b~A #s XZ-oꇙݻqM۱]U e7J͂1I0Bh͝OzHYсk&tK0#dMy|r*ARN_ڊ|߹Egۍ8݇߁r^3S>6$*BufLQ##(^P9膯Cny+jwǬ)ЎxR*NΪr`NS):q1%C~d'jkd@)>@M%4 ws ;zԜgox]cQnMgGsTyieP`)V!usMQv:q+@}(j!_9a2d,FKk{r;r9Eم$G?ȌrIcX K'gS<0xb]BVҞT1m ;m3 7!4ĊL"Y~pRc=щA$A +א.5727&B `X$OF;K]_hG%䔓]@~+`= "kq ^RWSp *VD  D&N t>WB (rN?XG|,MwM9馄`ڤW@![L"K&{b{#uفmT+u0h?dMEX*%:yJ&\ӥ *1rh?d|AKhT tɏ- cqy]2ߎu gu \$؍(bAF'ݜgtַ42P^~YmW-x5q޿ ሿrS_؅$_V=30j%=1yUn<Ӣ֙}ZwR1lA.7P&(4Zkst{ 4Op*(u)Q[1d)Q1LI£L=&je' tݍ+^p>N5 h4-4NJ^va_eY0|r 7e|Yf͂XQ@yMN"4rTZGdkgIYۡjK NJ}-={(>!ul!-H:lT-oL톀 |yD.|zwAx~J4=Q f, T+=瑋E_X:g^f9tPȈ3E* Q&Sư^:}N[IoDMY 5UjBmN, (6Áμ3 l:yv*0'0S`囹oˊ[+J9M 湢 7P/G2hݟ/P=)cXt+{bs0TQ2$ bz\plrjUcJeFF{/,6`3 WMPǔ'e%M)Vk"Zi%h 03(Vmߴa0:yf6?Վ2::}fB?1' ď jNanĦԪĬmLYb4@]Uo8,:±:Hl0hlOKeܾvkgީs'ّDU!!Ń*-=*=6wD6_x~|L<`bSX=V)))puzsz kd櫻 S FO8BoA=H"gaHhȑ0,mZ5Sri'kHWc&ChwJrs("圤п{X6`|wC'Mn8zwnC;h:ve>lEҘA[􈨽2>f3ygLۧ~x:Zzivpf:H-y7 qKMm>UR"6?ٰ6=lbRR_&<و-sίΩKdCsܱ*q} P?絤2u4@#1Цr,PORPՋNZh99gx>% 4Dz* a5J_Xaʽ o` N ($iU8ѰZ4yy&)gS.w 67e+{-hg5t\+06Zs;,Pi1MY#5m &T' m#$MV6`:t"N >pV}`iG#=9g_񥽜.IU:#`fEaRC^W-& ˩ï,f &YLlR1 VWN!;Gw\i1 .\( S^ԐS/TV?.i4K6Go&l8J]ד9mu#V3!>v5ŜƠ0HwlyVPmAOc2Ȝ86B6 h{}%)(E֪4br1$ D(5 /d4 r|y?(;Ϥ$T'K%si1]l%d;ڊry % w^Oij}uvqáJhA4' o_X^yٓyz[hF%Eʍn2%I}n,_ CGřW-#qh^;}'pNP0b+ M +a;.}5gӍO/mtG*pARTJj,;Ȼ*ЋWU48m[ _ -:Ajiw-ӭD $eǸItA&LNJ!{3`GJhkg>r$Xx$hFc܎غHm:.CS3Ÿ?|hא "̸~5SnݪP3t麄¤zV ,ホå#!+N'sX+K30^ 2.\9e1XMզdѐ,._FBXb9!, 'dyzzݣl=cʭ;}P4w9=PфHwM]!4HXm.N\x;kl2|_j?'[ 2E񐙢~[i2uZZR(-'Xle|^Jb3 `K_x:/dUA 17 ke9VTH0J+ifhs߲U]_@`Q|Por53ې/"߂b\bN+ R%xt)t"ON`Pc#T^Y`v ;C]g>Ov ݒYuIq vTm>z\rmtj? ZΐڕJil8\Ҷ<|ǮXO[c"(1] !u\]PpK4k#Vbmt|L5|s]A*Yxז!zIZnK(oT;pU7 I" }ZNU7>BdS?$)&mXSfߧ BM2B\F(0)$ed%RU65a__žj!ҌRcMySl %?}*Yeٲ,M 'r5Bg/Vc4GI[mRYw7Y}E68 ;{o'L6^,u,B Jmt>K$ZzP~@Rl}?KW5d!K}иfj JMxtx<PKJDvG -Y"ݽ=3WnZq$(m:6r9kI3DiRh~ 1b~}a ;h0C~#VNOb9u h?*>QIkKӊ:%h-{/^LNވNqUDȔ{6˔ҥU@؊_Wpl2TϿ^7aO)fģ0bK\aѕ]m;kx?endstream endobj 172 0 obj << /Filter /FlateDecode /Length 2582 >> stream xZ[~SFbN[$QpW.%I3(j?X# C\,/fqAܷ~f_o Yn-#dI,86K%TaXn YiV`:6m[q0\ktXpU?csp'6ig zDJtm?F z\&ZjT]T &?GL?yނ Րg~]~_n%Z'iA65Jj"WhċK# zS@I 0q' EVvM?[Itj* £0d3u` m=M2Ko4ɪH绳q# M-à9<1&f&ϛ M95Qb8VrUv;yYeK6s0ayf2Cfhjo[uv,,lpp>+Dfy>1>Y!ާ`8dgažLeU]67]&WC+ B0q8UhjrPۜw;7LoW8!nn9W>l&SxUT.v)wu+tӔieBfPnx#_g"FNa'J7pyz", @O,1:[-F> stream x\ێ\q}'ŀB H8  !EgH1x/䐀=ξTUOك\ë?^&={s lT{~yb9x~sq nZ7'_\|{KKWw+f;{/zݟ5r|˫Vw ǡ5:(s-Aj>bMqp(Sח|<\^QؒqBba 2v7Zj^M^aP˫b{wώw?sakh* oD[vۋ@|F2l`Ö%ˁ`fIC9S>V$͝g8%jP1ΔCw`>q>&d0,Gܼ}qss ~ߜ/+<9@\W)!۴9}\-Oras٦w~Y\@wwaʀVH`K:6gmVO`h3Q9U0bL7ͧO/mfsOفZ%, cQizWId̐%@n;D ; "4 ֕!n0j@J@$t 6)I4K-c yN ]@rCWs :r`-Jm@&HH4¤$u]I 'Y;06A I4yT&3Nfʉ Fu}y G$&P澋!!"WW@@i j7ĦTw+L8F&Ҁ>9IpPC)#@LᠬRbˈ;I&&"gC& ؊Ly;8hU/\a5e"heUf!RfgD2 rPmޠח&G+A",抈+j10{{Z{&(Y{/"SQ)Y)NM;EA5(1mf+IUC 3EjE%DMƖ?+2SnBi^аƙc5"Z Bk3Pmx3c߈˾3.Ȼ43/LLp3 kr@gZZ k}E/%RIvm'_]|rmQS7ìEUvR_ 0`oQLz;ħoSއqA$pf m0Bhaq~ V;ۆ.-bS!4B8̹o!qxsc%DC}}Ȑ40V,ExgDHr2ûr3D-XPXNA*>yiAQ"hz 9os٦^Ao$bsB@#@YwI%rSæd0U`_Ao@@\@(yIBMJ->+2$M >1/RV>d<:&yP^zS&& 6X&۞Ġ&^'M,n1sX;_Cv$&~N"@2$ƚ\h4H;!jkLdp GcHbn)E@mTcǁ؉Fw0dƌ5ь+k-3tN㜘fFe-gD̠48rFfXIbj&lZ)k|ńYfn\)+A-"UtWF$o|YԶ7%;dђ5$;XmV)-(!Z)!(%ONzDK,}4M&ZX0LJ҅1GQ\Gp[Wυ?(,OTGწ3IKh*GlNݧ"BXz*HQT%z1PtDA6MPk돰Nj*^:ja6^bl%:DGC cͳD#@p~U@ #oB:7Lw/2dPYM N]bq]%"fFO 9|͛sz`|G=u$^^̵b8dN["0-1ՐEY;qcbhݖod[4bNxD~K 1(EvQ#2<$d}g$pMBrU,3i"FuG{MhJ܎Jg5Όk_zf ZKajm뜤Ge g\fuybFGg_^~!cf1fVY gufg[pgEN~o'9i<ژEKɁ3CdP s2l lVziM.5&P#ɟw 6&z' x`Ƽ)/Z|ּ䏻y_'}j?uOH=S{{ wy4+Y .z'ђIT$Z;DKz'RuNSINQJO0w*93f:) c3/nA>'k'ݝeT\![bd:CGSq,&MıDaW4ob<??̫٧A~YGuYz혐}Pg/?jo- yƛ_Iʙ-곣fL8+zPG;|?7/g1ao9Y~.lnx|__Z$vXa_ܯߍB?x~|a?/n~bpfxyovS,*{v0PɣCe&/iştn)-_?Ofj)#tΟS_]8N;_M/^endstream endobj 174 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3133 >> stream xVyXWl%.`5at"8.Dj8C4>3E(<A`@ {Th@ֶ#*OL4Tm߼ې|Ϳus=#LQ"48#ggFavZ^X( VbU }DXdF!31239k5tpd$Ϧ"Jvћ:88ggf*\y(R~Qgdgd3#'7O* V(PlLQEQ>8E)iaY9Je=P\zZ/eMEPj1Emޣb(;*Dm|)?ʟr(* S!TNYPTQs(KI)5O-hj%SLjDLz%U^N5dVl%N3Q$t<}n3A2*/ӗL/~rzi36ȟqyưefW.zr\J/z;\ ǻi0aЄʅGYjr_ P1Z#Be iq^(Njb_54*U۹[c`-!Ǝ#o<ώvq\fL>>\7Ăjx(DHGՌ1֘Xo/ ^.-Eksb#e lY.֨y/g uޭRFe{!/qB bnk.Q]_?<5f+d=*:`?.ĂD a9W-=c8Go뀒PYlgquY0F?)|@K~>INgvE"㼡׽ܰ9/kпΠ7.wpUsTfkZrqՐ_DNxOśUHBO` v*6ƞ F'H,.E^V=p`%qrX /AA^UuU=\}eUr# }g۲c>|[v*VSl XrL`V?8 X5mD,THhbQ~  kdrGU#> 'WCO rˌ5`;|Gz ofv>}^|',.t۞9I(u6ٟb/A_ϏVg-(@I~avNqjӟUrL ބ΃HȜxG)`kMG A X%/2]ſ !6xz{E2C/Yb싽t nS&_I0.10wzTצxtkZ5R@WbYf, &!k!(4U/ 謦$+7,ž8`aŎ:9;1K^׺[ʹ(Ow'`w(Gg v`6t0013mBrk.Fh|b;xJ FIvH9+ÍOI\suPI^ԐGulmVl i翹~TY,qp9 6<x3"M" z5DPyrٹ|mh 2̘Cxk9ؓW*i^iz\dkH wJ2kdiC X|3ت@8+M'Hc$GFB:pl7LUhD˼Wͷ%&zh &7`X.8w?.6!=+꣸LK,[a6_ȡL@{a_NpqOc9)QeU<'=jXqY w^/6RϔW{7礗 m40; 􉠟`~<ӂ>k!;݆3}<Χ!NhQIi&\oN E[0Ě$Qeۯ>'AL{P8Vqi{J)H/8D/ujL!/˝(槽olCj2, ˞c. f jyC7Ҿ`Ie䇛"\#֯Y(+SI1 6R9]EOa3x@TPkY arB\w*bÖ}-z$~^w!!*Ok[,o%'PVߪs?Vm{JhmC#mRn=U ViOPw\@X}z[c+|\s0hgЇJ,v"\^HN뼝z_i4q%G$%lLkik yt 'Iحss{{۞V6eKlZ“:R&c 2X%`qh! @I-/aW^b2O8E~D {M~KCqvC&HLM> stream x]O  H,KdhU8!2ˣ|w|l/w{ZM};" ո8ODGUaUMԊщ6=(d\JfԲBQXY{rNK+و#T=K=jBq fBZ_endstream endobj 176 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 825 >> stream xmoLw=QݖGE$j шUanHK0bK)=xzW *EuK7/o>2EQkTU>>l[J.h vky`6ٴncܳ{ʣ#{; ;Wб4L$p ⣩)6qx ނ?eIams0M 1>==sad~6zYSFVvV,#xK=k 7v{nwƛf2YUDxU{;!%6{N@#T?q?(N&A(`(<8bH')bRo@מ8r ̎]ˍ(p.W7v H %bBJH## q")Ւ/IwM}{a8s{OeK< HҀĈ f&AN8 'AF> stream xcd`ab`dd M̳ JM/I, f!CGO]nn? }G1<=9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5300020310} &ayFW_^h[Gysd}Ek}wu7o7fںfLɓG~[oA9<6FQZf.X5kpzW-bo߼~ Oo,!qC/4|g]{w˅|yŅ?:&F;\1ՙrCgon]YZںۻۚSjbCfLoQP){'{ew}'Mq߃bTINN ͏M RrC@C_פn ڐ721wvya_|+[y-ý&L|gy߬e}'N0tendstream endobj 178 0 obj << /Filter /FlateDecode /Length 2812 >> stream xZ[o~S!r  kQvPp-Fco9s!g(ʖ!8sΙseigt?(\}:׉r=a~L/ -t餐EfGDOZ)㵊e 1_fgCLwI;q.2rj䆓rN09%w+К\=΄A$~/hne eQ4гXYk2j|l.T+M_[ Rw:pd xg[fn j_θ̴RNt$ਆ2M,Pl2}49y 2R.",":G*n0/9XpSJ)XYRc9.=8Ez @sp$x zgkP-1 ,h\ւ`Ȟ`'ܨ,/(Y%f/UKvy& Mp"O{ &XcE7l"řBeFy~ptJ1X~8ɬe^ s6J;xMHlkH2w +:@T;輵> Ge`efr Q+>G]%1!F/֐;Fjl<$AØOuRRT"q2u~q`t' J0@hq2LS\us9KwxR 7F(@'G+s6myBx7J}v]̋Kw"=0 B5 XBPQ53>34y_jY Ҭ6Hl„4$G@N,J2- =p[dB-*S,krzL[pȓSP1WH$I̾GU m:`؃&TdeKHF-q %'g '>rD1w؍ЏBys.eg M%3gigPiy{;+K*l;Y~PirӸ% zVA%P4(<+TbXg$ /NwՓW{oZ"Up;̬obMi5ot&B 5\ԅwӶX% mh_ĚW])أRטD_a#R>D:eu3R !]-,Ab`pull%$r=K%>'k12}vޱ\=j1) GO^ -u2KHv0i* "M* &`;Yϱ Q{xr?Ei;Fn;={XrH r~Lx@ ^xQ0O*X4sWSTdnU>dª獫Me~xVs<)+B@N^0{`L1ggddw6C)х*A+(a#o~{9Y< x`l$M҄k'%XG2y1%Aa ƅ䏕lU/,tV Z@-{ 4y_M漣dWH/HfX!$EV}5[cl(&uU54 @|z84d}aD.$Ŕ̄K>‪|QFwg^ۮ:Jd+! I2+`* ?}_ ϩW+rSm|/T G?}QZfe4wM\gy[{:/ qY,AO>XMK}?dj[ő%a]2u;>gz#/L\-;[D$bj<1!ķcf$y]>e 6{&n-*쬿gaiFf͘|ECJ >TJ9LPHE&X]כ1 {q"qT1؋)@>Zr6eW6d-}Mpl4P~X I7KoFK;4GfJδKxr72-w=%j}ZQxutI㈋Nn7mUX .ňf\~v\Yj[ƽӇAMWaz'SMz5 w~*NjL):zБ>܆$sn5JDI˅_Ώc2O5@G{s;A0n*Ǫ5|polhLMu<7PUGAu"NߍHPf|*̏彷;;0a2M /}+MJ@t8oWendstream endobj 179 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1992 >> stream xUyPTW_SG)u4&1 d7EmEQʾ 66heJۀ,2Fd,fL$Syεy85U?(+ J&M \/"{_^X],XnrkKSX=p-e)m_MZ`"OO^ԪTk"2RbUu^ R0Vػ[[  Vm<5(jҊԈ(aG(jLPZES@)(Gʙr\)[IʊJ2e7,-X~fYh%2Y7Ҷt5㈧l[F'R LAܙ!{{QÐʷ/sa?$Ⴧ+g]jz ѻ ,ZeYy(f)͆z)tY)H&4vm5l)@,q7>97X4;G.w73|&|PьvLGP 6{׀5$L/Nw|~ckv\ ZSpөMJRtWAh) +E`y/_[65_&emō#=o`='2JJJJ7Ն#uDiendstream endobj 180 0 obj << /Filter /FlateDecode /Length 161 >> stream x]O10 ] ]Z2D! }I$[.%Mů F0Sau@vz&ե=4R> stream xcd`ab`dd74 JM/I, f!CL<<,o$={ #cxz~s~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+k꡻ /,/I-KI+)6d```Tg`b`bdd ˾*p?nv.WVUUY!> stream xX]o6}5VO6+C[aHADl',ð߾KRIE@c^OOXMzig2won7c6n4N8HGHj؃YSOCTWG孇&1jw_x!_l@Pm>G34諷 #E!8^P`/ L:obccW>U(eC@덗P]A#sT܇ K@.hS $E#MYmI8I2Rc ̒*H+Xb:'-Ǟ#I ?Μdج8E4jvwe^ZV2;宬=.c㽴qoGQ<-W#,~3a|08YL1=DҾ"`?Aq9=\]MjQdApsܷn #?XQq 6&I,G8)>X1.DF99f9>ˡAJz(/Q:"F飫bn~Bk(k@[yΫUJWml ve$MXTD7Pgź.g9Ta5N!!ЕWRVźf o»iuEMt.sj{ +^{~1 i.zP3Fb+n |[KYwg`=$0}|Oگѵխ1}^l}jef!;;7*x!t/iGF)0N>;ȌNq'*9ִ}41o&2Wi ͣ'Zy/ʘ875uuaR7>A)~R00h!}S!`f8ڥ 9^,̉`m,TX HNRMWڣCs BuwFA i 9+E˷н Ǭ?Fcc?Ee6\r1\$]xЮpSwj m#onFxsffkۊ .rBg=1&b 2槽XVq~Sl_SʛzE+'ё:nvԮu@(:{q/.㬮gp8o?jJa>Le:]endstream endobj 183 0 obj << /Filter /FlateDecode /Length 5716 >> stream x\[dGr~'c5x~1ؠ550d̠I#Eb/2#2TH Btẗv2/ooA=o#gP?>mqs.nSkwb `-{íݻ[?0_nCݜ/-Gߏ?obͷҎp?ϿQBG =oӁ9?ie>#B;5q}C79ocj܎͗Co9mG qPjz JB5T§Ӥx ORIP@HyR=e<-Jq[B!At4t.gXTzgN 8ÒEÈ2L2+ =cc.Ydl~_s?V5I %ǁcK91RMftϲ 5xmJA#?kpac kF 3RK-5ųpOQ ͨ C:GQ'T(BV)P*R,T/-:WG.v^lg1/bUL5)kts&('H(h)3j>27f RT_x8=([9ջ(YH=y$Pn.X~Vյ˓RɤV\5V됾PVprU Aj x.H-_dcW.-mc儧)ҵ?6BL<BLi&0SJ4Jc>`Hdx@z¿@8K6(>? C!)znLbn"=x!+B(e P< >]JP>r$"aP27(y&P}Pt_N995(LeP@G% O@JuWPdv@ivnf Dɑ'J)s^N \y!

|G@,.+Wgp-dI,WΨ;K<@rIDḜGh65 p(HkGO9qXk{OJL^{t`qw/ϯMZ)Z΍v6Nڅ-k3ݫۀ&>}WrٺŘH (iv6JTjzqȇJa J(T{wP`i OF O(Q{-'|nೕ9Q԰L+2)7(eVDtR堌Zg ;J(nj>yf)77Rg(p,ɏt(ȜH.͵َ-D?y/yݍ~/UTZ,?ClW)n*o7\jUa%]LT@t+ږ>+RfP!j?f딬6*,Uk9ًj~i͏bm~͸QH*-To!$$hFIAIdFRAgCr5 ! ҟ5r5C;FV6)_ 9;<!΍I oD B##IV3$ʛU{TZB5d@N-~ k#TrO’"n>1@H}L:SݯN{43Wo^_ \ح^Zz7^fB6s^8iW/kF/_?7gf3zy[plJIau#a._}}Q!2Acyl;z0|K"J1?Z p&*\eb nV P W$ѥݕP,W% .:99IH]'wH!˼ 2WXgb:YH@B&}q}@,YPgGvuK,6o2OsYsFu8%WKv vP"B Q.gu' w#bX*עPutn ,0 p JͮbK(<愆J䰐͗ܦ,"&/](Se %/Z׿NB}9Wb@n;:HOK DoD.Plvk.\r1P))U)܅egJ03TpfT(tf;J~n"&MY(҄4(IYpR0k mB&,A)҄?(] e6&ً"+ xni@?KviXֈVv-wxNLOo̞QX,3Byw2(RP1)(ʚY3 E:J>4 nW%nƼ{>̴@P ҇~jhɳ3sgv9׌\W4TquBV/ER=UROHͭ"uZjq\ޫMJ@Vj(۠H5l(Zy!?g!k?Ȟɹ_ ck)Mm-', U?-JW_.^lGcؗ 6A,b&%n#D:F,1}R&ǷG`dX?͙ܲrC X\|HW Ψ#kgkqV9%o(kxZ֠ƬeWgk1-D6:A0Ma5a ܄* g  x%o&n2&mlѵ8Y 0~[my8E޸OEPO&5}M9 ([5Lk~4r$k>^s/ i8 ݑy/Lڅ^|~H֦ f/>rHֆw-'7ڕO]p s7] }#=MڻBr- <|W*Sua:J(P%ursBuee:c4n4ƍ6}2eH)+־ycOOեMWG+wT~CZwڵ  QyL %&2 0Nftw6b| ?kY!wap.f$nZ-~%8%P-g2ExRc4,ɏo+P r)%Y%.|&!aZ<]-b@E1\''T+AZȲfۂ[M|\z 0F?f(>2wxh+پ?Ũr)}۽5LB0|L/Lw<ղ@o"}Wz|kQ>oZn'_b5KHm~~}:O8knEcD;9Nap|i/_|=d=t $=vYgo\s8o7='֝v|w{gCnTKMؗ7+endstream endobj 184 0 obj << /Filter /FlateDecode /Length 7644 >> stream x\n$q}]y,+A !iF0읅A 9yܕ׆>'3#3 ,'*/'n'eg6 d|8ÉMϻߜoBdWb6oޟ[ڸK٤vŅ͛/oN- ۻӳeP|3,.۟=~u:r,e_WSvqg+uM6ɲ1o|8ϱVl P7'rmїyo6gggy:= 6`]vˇǷu95GbAKڕ]̛ͿnnO.-֟!~zbq.mbBܜVqæE>ڲKeuYTÕ`0 $$qjhIp5TYGIKp*)9Lc]pKಮI܎3 sms&].M-%;, l[%u $7d@#wYh$K+-A~b IYN:$LlJN5!.mxd(!3I'v:^6>'Ye"eBQmzy{qy: 5{GHo7Ü)lY|(jB 9Y͌+QSя4Ԍ +?abCsX@dZwߨ¸Xce_HR]E;%'JثPgJ &Ǯ*W**qA_`! &^ 8B߮.#CMǐ蛤(Sٚ΀F8 ׁKRM.!Cr*k=ޔ+`<LK Q%0n3mТ&!T \qJ+p ]D w!:jl|LfB`߷q\F:YЩU\a]!8.PV3A2X} q.zڨg-bԫȭ+@+zW$9ix xAtS˞hKe-E=PGGtN'x| e `N$2gPR 0: tE L.iAZR-~5''ՠSC^Tkّ +H} mySu \0]Cv ^0mln|*n[ KV۟5F|㮆#F`6jbBhΖ{Sw!] ="AvQ=j3SbyĄ9č9Ė?s澎IZʑ`8'sjXj7Di#ӎ=xOSK|p0!#ybªg<5&|%gMK^n ozȏÛF7ʽ\e!bqc"~t}𰮥\jmEJ՛*a>qvg C'Fa&_ztIUaaiUxa1BԔZ5hײ56bF^$p 6 \-sUvl`<3![&qy`cMyǟl!K!F˪ Fp*͉JYeK+^Z;i}U)g\Qe4"*:gwek`(بjA&՛L^Gdؖ=5@j [$ڠiR gͶk_j(1%r}]BP*!@KծװS_@b+_aa6 kBA%}܋,ԃZanEwN`k|B 3XZ/l O cx#*q+Do!kc65k $Hyu `jX=VA&qDL]sW$RjS;VViV[jZĶ% 5 5;{Bjm0lIu~2u: 4 ք B5)C`k56_+2Z $J<[j=& %lJMȌƬƵoXVV[04JW$JCr1+P-tH̻. K `,H ^BŽi@.4f{$\/95Wځ$%8ق_\ЎhXd=Y*WCM\bRsO$-MHDꓠ95,uXaaŘ#{K@`3s@kH9Й:g&0LR3vVs?z :/"`G|S]ĉM&f"׮)O*;YpT[ J.vx;x`HIr;Yo(^Xw# aB( #z޼]j& [%ȃYtLr)k1Ĩuv<֦jkڜ i1|X$9 n+- K W(N$`=N3$RF;L2 J)jK4}f♺QQIK9pvsv 7v1!m q(lpCzfz@ X(Xj$`q ;@ۨt8Рs=pQ>y5=&qzܘsIlˑ3W,1j꘤ź Sw0~%vHԝ<({Z"d SL&$Ll4+YkB\2t~U$Ao9txȳ+r'7|%sbJi\ |9XE̸L-?ư;c)4βr`"BB&_i:^nV|-jU4WYRτy:|Oe vҜkIC KHxy בs~u :dV@CrKѬ0MP;2P֨mʓ @kD*S͎T]-YZ$ʠx)#IdGGV:pdBR(vF#'U(qgJLռ2 _OR 5WgBkQIIH9nBM }5 ܦ`S).mS趩rY fow qhЌjpr vՃ<&!pA'pAgTpA׌0c5X YRcSG%- 匈(AsxɹK일AK쾄y0R8%hb#\2F#'ɉdq18o9OFe!^&VXK&5U`v`6ޗ`\=>뉳3 oB"gꘓmWWkWO뀊疏]j/>y-; T+rQ&EC .Pl3_e{ lx{*beeUҥfSW%t(% Hk+]ҏtJê 1ȆN r!,[; Ƚ=Dldr!qmِD6/:BI(d;Zo YCPH|[J!ZURS!/N8OskmC{j..<)һgrU$wJ鰃a_]cL8Еs:>^A6JQ똤0?(L0Z|:3@]ᰅᑯ2h`>gmt-3mslY] qj9nPQpiLLAt0f<FfzTb_{2gIc0tzlgI"/i}%خG%R{-Pba $:u$IwGV+X#ڸ9cBj̺`lklkc֏HZ!R+7 ]ʄ"׫kzdH3I4+qj阤ŻS7%N;H=)q|\b \W&z4a, lB]I_F>5̸YөJ̞cYuFF0yOzSt1gjgSkY=[_6:a!]k#eak^TC7/$cL{wo3-=J7Wބ)#8 ͛0oKxAx:n}X <0Ty4v \*E:Hiޛs!qOI{N$\$W"pqu~~0V)5@R]$'#G-Sg |U,tC){nw}xxc#(UN4;%FMXT 7j5qZq$XHZ fzh3(S|pX"-ųEcz\K!#"םD14¢F&#UI w6?@G2 S2ӭ05Ւ Q[>{vC.Ş|iXBǗpR)J դ|l UT꼐uM{!yX!Ǘ}u*>joDണaYQ/YI-_N4qRnQ՜.qGӎcH߁kzpPAFf Vs_$- H\9,uA"DiM'*$#LH֘yeP2Ĩdc`=Mw<8]Frt+ɧ$N˟\A|۰a[>B^_s+}YixNҚm ?^#QZ`?|#gwp"e@_ c,*(Ly^r5p8 fKsGOŨ6>qKo{1 ǭ/XVCU/*>°OU!U%̄^Oj3SR;P7З Bb j`'q n̢|)2>\k$Y?T%?O^JS9#R)R?PHl:GKf>'[NK=;oK\}Z}fPgK_*Rosyix? v e wMq\=]\(~y|\}zSWz}(Rgh%n=׿z]ӓ =?>ܲEJS\}<=_8x\<_q_#=6g<]mZ~Ul%CgV9S׸llQٮ3OGՊޜWc J"ɛbQ\ 7k`7{~EASqR4L=),pPj?^J}LSor{ W\3"W6nsQK/V+LY侎j6b9/"ԥ{>]1? zD^HqCa j.\L8;єPMh^Ōߵ0،m6mW1XVzknEt{?6O\Y?ck\bXP?Գ{K]W7G}}&oW]_U0jyRs-`g{_=m:ltdytR*ro̪>_.SUaƇpѣ 8T5nJr^e> W7/?"|{,(Cu߫% Xժ0GFENuƺ^ODz\O'mZk;?=߃wwO;Mf@;Q)rV(L@񊋬P \n9gk/ %sFĮ]ia/p<Y;iVIU| ߦv(QHR9\z@vq{ck <#?5-VfsNDr~lkP_wm_+x/ݞ\>j/OTRjwoqu;Wٷhn?cıܿ?=3|1UPG\/ԃ%S=ꉹ1"c\qqӁ8W@teJՠAnԋn5k-:|iwfV#-^ͨɣf # v1dSo}2 Iau7*>J(KIf_=*-ז݃:Q7"834.l&s@0/a{%E\>5_.vt}endstream endobj 185 0 obj << /Filter /FlateDecode /Length 7947 >> stream x]mo$qOXLtn#` l2, 㝨G\Y穮!O:@ _ꩪfٙB_ܞ-g93i_~o=(xuƗM6Ү=ۚK0cڅX蒋go?{s-e|sn3>gݟ?scDW~n1GYk6OΟyw|W06li\.l_ӠLi{/v%/Sv˒pa{uX1om!! xXAgY/~M-ZϺHa?#S8C[ ⃍ Cn6ؼ9=Co_/aY x0ܞd fss0u1\f|V2YBbw%J;(UJ6L9&]..0`M63% X䝧q,^M4Lr;ë)0wL dS4Udbw0ʔ36 +Ɛ @)G"b23S*6iY>47(~g|lo!;>x(ˇһcNüzh&0Ē{#D2.TRxv;6"iIG.}xs0'P.U7hwlv+ ZKO,g0+d`l>:'_B~3j&d^`lKFlNְ56i@-lJ)"%4o^^mksUd0"P/XCJq۫g/ HJd8CʺocXpǍώtG0%G# #z08Jї.z/dUl6 /,mHsYꋗ ")2ѯq5܉%U8PAPEXm{ͬ(>}!dL*ʼn}83I^ B` 'W 4SmMZzt`AF Z&܎(ks XJ{7jTK!JRk&KyCLQBMƑoRi<ВaJ>s5x{TE[P 8tHLD^ykVb]O3"ZG5Z0 ,=J[ Z,,Y]y8M"&4 < S#o(-5H (s*TXl ljr<JIJ]MW"@:R(aWBAYt/_ab x@᪢(A)40T!) cn { $@s.0@ |((\*Z*])40[a! R   䒼kMM+fI 5gp]4mfUn%K)}͒v-+"xkW.*ze/Ly@SVhAL3Cڒ"W ]Kp^j5!˛St2ѝ'*E|NW|(@(I|(R([|1bXO$戁J\6,K\@@J#v@yO<Aa@P2X=#H#-^N;J8}E&:&;:ԋk>^NfdN"KקLت?C>ƌ8̛ ;j3zB;%zAVԓp* \ÄsēL'1>C|8T}iS9ɧqO'yԓOT~ ;uKD fSmm~c('l8RPJG޽3!UЩA}AY9ZC9ZC9ZC9ZCkZp.2?qVfTZ XI76>ɵn>Q8|qq(^+(e`kT"zPR@)sSyjfEf+(yn@ lV8:j J>H7[As87[Asӽ3S7V(Hfhjœl^sjzds4[}tvnySG0lksSku\tjf+(qnzbj J>A`S;7[As47[A)s'~jf+(qjfOPlVPZ]:=1y ZHv %٥DE%’.T:]"t醉bzLt'=5ѯ7'v";%IPlRzbOۖa.FIT(]RtR;*,9aSu'3527[/v9PDCYOv_>0vzC0~%ܣ0 $vHTIPI<ͧ<s~Kn+nkfrP~Zu:j="oozoPJ-5|FOJV!OA*v7!Ǒ=P3@qs0@sv-4>(~>(eY*kN} P%} Pb>(a>(e} K7O]5 7u8dK^>-} b;>N%q9̧y_>[2ܒrKvsg>(i,sQy9*5O} G䨰<\-,>%} PrTX@ SQaY@Hs2 S? 2@sg>xmYeR 1HJ"M)ŋĥ\/ZhN]i H@DZ bI҆kVX3j!-m5JCH#@&Q9X0$xo!4d q, q>}FSk>@r4ٺOwG{4FNJ`d4!{#hw6Z-HiJޙ='>A 뫹CRz@0Azu =tJ~J\NYz99뛹ك99)뛹Ԟ(zkGҪ7KwUՅh&LcT8FrRuʡKՍc+.U7QT=/qZ.'תC'UNשV|)-Hjo >ܞ9 @ɾZzEr+pjB2oPtCH곀)& >#zb^VJÐar}7 Sn%hǫIÄڸYYj1pI Ø3L|OO2ǡ{1r-E,&BUZN$oȔ0(uS{G(9cuzJȰ6r0<;=usXJv"NUU蹗p)pY3PA]X12JñZMQb~C8t7uZ 0V `hEHJY*O(ToVaRIRkú@ae)2aǞ07^:(J9 d$*P#D8t>B8U _DSFN`={DmV LPzf6ze`ŕm%.҄P{¡)&Q>)%i:Y vBEj[JYmo.f 8Em-GmTy/JH¹Gi}5*޹1 ?͘O wiK>h,5 !"uߡ:p #!CKŠXDRNb% "z H\I<I|k dXc7yu^E]|5w1W+?4#U}i z>ƴÇ\8*RT~ndnv =r3em5$t*gU  Z$~ $ G{EJc jr6/ @M&DŽZ+ Qj2KJ2K21˪4Bd0I.K S2 =ETOO8Пgѕ:Ni %˼8f uZeAOaydjVau@=#G6 +>~9 J&ĥ.Ղ5 U{Nĉ!%hkN ncP`Vu]Pe"Yo_(ÈMx: ,V 5Ɩ4 ʐ#S["ZV#&/4"ݨ"m54cTANlv%VA)\92ee.θEɓ\\Jy/e(rZ/03EI&EzLVxu6s(MPym\Җ\Niq.LG=5.w,:JO2s)Aa 95Lsj`d5w?56BinD_wCݵ5t;T]PgwCՋUh0 Ga\= qgiMÐ{CD3=PXX:'VyO=uz$gsCb/oF3zolg5/Г; *a^CM}:(-a[z"rm^Y^3Ĕ([(ǏmɅA~] p5SդG]=5`RjRjRjRj=-]8NZ?|yr*\rRφu;~2զ}C |Q鿄{/}~F&eZhkcrh5ʡ8*ڼq*Jٙ# ԞN혏n H2zB绲do;B7~OB1_|O+ԏ / 1@s(p1@s(p1@s(p1@s(pMKEmM^ O-RknaNa@&X2ķ]Q7GQk-íy9YCY-k$1a!OX8m̡8m̡8m̡8m̡6/q5ٿ@擉'A4ЎFU } eow߀&Ϸ]Z>?Kzz7@/>S\4~;-ƻ+uz?7Ÿ楢_/?77z#A;4VF˕,Uc}VF&_v̗2IΛ0ΟQ I v`Skas9~BRyxVIR,<̆u2n'l/XP@eo %k_*틻7.{-fo 'vۻ?7a/&7mB-ˀTs*Aa_8p{72t@ʾ/ɀ]%gj5",]<'iθ6\ ~Ze#s-뇶n/o<~:`ƍ5"Ra$^J?5o}kOd 8_ެMGkSz_#%vmSӻ.77ח(2ד5/;K-RWon -E$7 ЯɶfE^Wzɯ^ vu֗`a嗳oQ/^_LQDc+~/B0y qlutKl䦽粸8[ϜwZT*G\r_?\" O^EJs}8c]M_qdJ^Z=FJjbgB i(fcSuњZ߱nd lPK,bq-"趡rwBJ̄g0&/.($0zyӯF_MsPi}]w}vPXdIWJXJY4f V# ]}IFfQ\a|rռ>bVzGQ؋Jgٟjgs񛳋FusooL]T#kR>nk򲿺ym#\_>_yF}=x6F]Hqh@˰:uC ϶m\<ie?0AloW +Q_K64%&{ׇcƓ^#~j'|ǚXTOYjTH_}squ+H}>L="M6W8|}!dϾ_^I {[AmNi++WQIȒE*mq|ٯH|nWB~n/g&ce|D!f }5ԩAiAXow|3>(CWclfqGuTY.+G$cendstream endobj 186 0 obj << /Filter /FlateDecode /Length 1651 >> stream xXY6~SAft[$EMrLJdIKko%Q9z ?X"s|spF7c˴ǖvdף]ۿt;~9}`ŌV=ԟgc}S"ydeaX{E0Cc⺞i^t#$LȈ,eY?ae}v|oܩmEd-:@4% ^_u׌zE_rM F$ 0Ik}&6"~aаm0»553wh(H'oA̘8 䇉~滪bVdŚ$d:1|oCl\!IKh[nRS~q׫؈Z]5}/rƳ;WUXd\diߓU’-uJ$/ZK>{" Sf$[h:`^O%y,e,I.uU$QM\@r4ltY$JFŎo]]q6+N8cnD-mGO˴/Lcܬ7$h]nGGpNnQ3Kj}:9J3 [nZcӄ%38bP@ 6N}7yfXwWSe`z>NNFcW6W<T8Q[b_~)%Ca[M Cy8̗DQu3)(2Zl-NK-6tuT_Y!t=7FU0usaL 8}cp~>lnS6t@lLQ:.4^<(;'U{PW5&5@j=oN^bӬxwsqNڤ>%cW D2j]R/I,tI&Af,KD_i$; V9+0 ӣKᣒ j cɩ3c1ԕ`{Oה?S!0Ms-z hͽax @G-FBA]T\_Ǫ'z!f pןz4X:'b 3Y%*VoR#jl^7t?PlUT|nǵ,Gk~9/fR%1ra~$LRy*Yٓӈ"2k9Gui "{ >keĈ/Z#eí\HwukrVGl0y6]M "(p\TB1DbKxO F 24YZ kR?O (iK'ݑ^␯ !BHiì6_R,Xѥs i#T3:?0ȳR=D;qeESrPW u]6!3j6_ҏEF_\Kw! 29\( ZԔלDZuDކlG)=4ҽ;A7~@Bnw\XXk|^F?Zendstream endobj 187 0 obj << /Filter /FlateDecode /Length 1465 >> stream xXnF}WI.[R @Q(/VTK;F,o3+Ӗ?\}ϜesKqf3]?qj߇3b{ͺ-qӳyfqf+#rMr}VBrci^XTuپml1{g8iA2vD4?EvD,/WalV@(GCqbcj;ckSTfy|fJl~2z!{XdgTë;R$FkN`) Y0|HY6EOz_=p_6uSZrb(Wã !aJK_MfI~XhMTDmCB ݷbHPةER8q^p5) "xHj Q%T){@hH=]]Uc,P^b4λVH =*z\^@.Pou#x}ݰdM]RbT% "NXc#vU7XTj3Ni o <0pV_1x{,jq8)TY)UֶfcK,ٌmu: AboH>rp![ZIj$ƞ#< Oِ14}]ɚSP1 f^J (HV1牱n.WOgDʗp7Xt(Nˇ[ T9NKS  k|06oӢa:Ҡ7~N߱@.|x&R@0he@Xba,;qjZ:E0@mO)?=]H!\V:q`wqGTRh{!kZ3Bv DcxJT 7nB#ުԠИgɤxf/RqibIMIy+rҥ Rνɨ=#sh283B4MˡiB)$u`&3x L]Sfj@'j.4?C_G _ %VG2J*2 59"mZM1܏iP 8ܵCOy].U#){\hqDػ:rI,Rq;AS_֠Tp Q^nLaiokDuy-U4tOU%cB6廲kT'؍pST}v=qo}ؾV槄פ%!8M#;iM=K)e.Mr>A;IIR~]W% 1S2 I䮨gV jKjqrpnt%k]x Iendstream endobj 188 0 obj << /Filter /FlateDecode /Length 3226 >> stream xZKo}l5 I: ,l$ wf$q=$HSUMvÎ~T㫯yW3NO.~OIfs/o~^BrwƸZ\~ZǃMicq슽=ykU kYU(RnRe9PZɪ[=n,R)Y]s\hGɂ̬ϣR2].J!5k6%)yiJ ^nY@v/QktT:+AŲ/Q\fZYq~oْ4d/>Aawm@fWmfM0\yĸn+A,?5 ^%[W]5Av|q+>roSBO{ah]Ԫ),:!> -3\[E .=V[?W즩vϮgax"QĐͦ5lT'Hƫ0ݻU6]Fxzfn)1ٙ~\/.f B:B'vsckŻTU jR χfEX.:(CV&`vo Qt+t:sC*֋[&@.M& mhvo}#@^rOf%ЀsYI7Aa)sPi؇HD@ ꝟ `&輟Ow0F[|x j}ְzf---co%ΰ`7L|c<*}(" !@+9+(A? :jE 1骩b (uS%9{OI@tjwَžtL^:sgܩL1' T1:LM{ÔSn|X0$fћqx/Q"HG;OMCAXSc0Bu#ԚCx)&Z9jps8`T)I5Gti'g0!rz1hv^v!B4bΕl&G]zANY.|D0BLGȘ-b! 4hI!!%`O0nY\U80`c`mP%םDU'J9iUbhUM(V0'P3 qLN̂brW6vݹ1̕8Ŋӝɝ bBգ&& s`P.dǃ|7qp"^M <-Cߐ~jDp(V~q1]7+F?t=pJk^?TfגZyex;+ƑU`aI׿ݵ7E#;:bxi+b/;8-֧aEr0;&6/z1|1{eˉ:Z6_o+Zl/gOC'z3$bt߼Zt{HS> stream x]Yo]q3b01oz_ '1ed\LR3Qz>eĺuzӷNN*߯O?B=mGNWރ*gN#Ԙs*Fwg'ϗgg~<;W;}v)-7gg_Onn_6j7/L)+[&W,Ҳ?ݳc+ɭw>ӆ>ٹb؅pzu.!%lvV2wAbXpv.%R*wց\ Gܠ䝋yFP݅:ϻL#JfwP#`n7\)iih Dw&":lJ4\I.w&ʓݎêΓ13͓B]S QxNG(=a8S2$J#;,+e`HBr,G{# $aB #?3mvVK3 јk! #KQivIKh) 9;!aWe=n(0Ut6@еu,8Œ-s$7}wF3yn @VV1hy-0,p vG()1XAd\m 3r*D琄 q4YwIyS ;w6vjS^u mUKKP.t6#QhfH#m)=* UP ҬTJ H) fʘJ羉W ک[jp70FNcXIw>cAPѱd/dᱻdKee=_f]f}gvqmc sb;֡!QasN>ɓ ӓVECh4 (-?yyyG9  ~h<)9, n {wyz`;]T3υ(4PLUkMc,+Ѡ|~m+DTpđsb],ϗ/si)% 6`2T_9ҫϱ<.E"J0 G I.L J!2IR<7(FP RH_( RgW)"JlL0%$^O%Qx)H0uW\iXr"7PJ'/[((͕wyqNOi*xئ"%-|S=dNUGJ4!墉P"6Q ZqDH,2-fetNc!0qbWMd,(6"#K[ڢ@SI рr MV(7Q( H4ӕ P0 2]hȩ ԐW7ŽtU Ց|2+z-DlHz%&=9@L2uF.0 -7 /Fɘ,),EL+ XGSqSM}5XqR ]RٚBJp|W5ʀbF9i-m;$#K'p䳪#3<3*!# M6DWċϛSC4t2/}ohR} C{L/{UV{^V{gV%{mvlh8Xaq@a0.6so   )u#v`#qKe߉ZP%}I߰7"~§doThe[""$TWc湐MCJpaѠ2ʱRr!SIQdZұ4]*aOi_,~m@8 _,~;ǑC4e'2Қ_a^i>4>1 7AYq Gi$z,[qJ,WBTIZŖ$+*CJ%[9f(4\4z^\ @%mJP2;6AI%{+ZAp%XL}.U^bwV :UV - -ClAj2+ق0ԇa]} j܀} Ad+Q(Mr^ Y6)62h@ e]z f啸l@Kq̊%.JӥDT(lRـ 6-˔ʒS:FXծ,(ـJw~%b+MJ{9c^ {4+*D/x\uIʍeŵ˓?9׈#Yw\k~ë́Z6%}ܸ>%4-Wl\oP:@gq@P1;OŽ·7I}!ˎ%]*.=37=<G6lZM8Ⰹԍ9G:XFAnچu,>@]d? VTOo@jD碃3b}jZ:LtzaIy5  @4܀XgȲ l|萉NSl72. N"pVz5֕'GFl0E,1%TK赽2,P%@! av:r§^DvP\s(NTp(%)%\|ݝQ\ J6 `.T#O JhGO,k%BAA^ܗ-9 OXBGʶ0\9lciVA[;s^UMD# "n 9 z:AKccZ :` m2(-GE_t!:QmQST׸G1't`ˍƀ: YDtqEokE}?#p R5^rHETq Bp uM\(#Z1u¶a$rn[N kQ{ r6 F(4DG:+Gs b:,ݷet3}!^u({ޡ"g]w'?̡a2=X e^:<[\C0z`arR\|d:9y:t\SC%FqXiZ,|-D}2N*6RV47ss[}JSzjgiJ{zWE>[S 2uS;^ RRї.nޮ^U[wѹrߺquu}!:qkc+q]Ϯ~|Di>ѼnRۣ-_f@ai!ͥё}G&yN& ' 6!1؆($ cpH 6!18/sAޟ]ǟ<Ҕ@+ƌb=dPo;2RgzՎ8dJ:m#,%S; as;7#,(P܎P܎@v(nnGv$~jGbv(~nGvuXԎ͇-JLs;R2#ǹas;R#l \MKԎ@nvLK%ԎSO͇MJ(ԎP܎tjGbv(anGv (Nv(~nGv5#@S;ҹJbԎP܎܎͇M@z9Q"mi(<\$uVF~IЦ&D K’iX Vؠ>Wf#[3ם0'ecpHaΈcBY8+ecpH͋G?.eG$R<6\ mՓ{|pȔRj?8J: z 'c"l%[DeSow?Ro!@r+$-zgHe/\Ҧ B\zH=QnU(zKvMH\sy [2 ~߇+P^|EI^*G_*糩8*n_iBu ^*Me([-/CqS;yEz LHE/,b ő Ey## 2GFe(P7:yw8* :dZ8ڱ8*vLjGP@F_ W 'lRS_ @݁77@F. HwMH> ;Y{-X}|_V7h-lM|[э/`;?ض^ J/8;Hk#d˗tLu(;1Hwu]^?\+[>KDن߰9J'Տ. N?OYT|NW9ORsQRsrpy9D4-}pW 9^ғωi$ hB=;U*+mFI? тg7&5BՆp9u'L([xe8emXYP8gCq0*Dټq(?6%G$|׬Fzχ!vt~,}ɈK7]ܺV\hwNߋT>/g%'SίdJZ.G192k?C˻J˃q`4Bya=/t?>_^iފR9z]ع7mF\r0N֒m$m7_m-D})&x؝m|nɥȂXkʜ}KJf%̲i%]^ Fdn?m2ߋEZn6giqKOpywCV2Pp#oF": ww)#2eooS.Cۻ+Wzf0i___bl _[ǖC藫wm,lY:I:У;Y\> o +D~կҵ_.,vԹ~pf򪤧%*ZW k%I{T]L1of~Lb]ӊHpJ"NU; Ɖ7Q|/3m^^)?͓kOawمߺP>i>%Q z;{06f2gk6~ r GgbޤW"Z_HAf$R3=+8WnfFsy5g3NcǍg G6RfS׷w  EڬPqnEtT gI}by~A%̮Jzdwܹ~z ]6Ûw[ǝ=Ut!W8a]g!OrCr!t_%苙lxʺO.h&e>4MO8NoR;E>9U3DDz\st)UV6ܱ_WNḾ ,T'ej$  .&ߕ`{# Hk=}uJ?p y_C+Ƀ zuLYι9lIt#^CJ nxIuH`,N7nAR5>9? BjLvMM͡CoW#Z&p,;j"{nO Oaasآ?YϦ]b՗~ΗYAzYۦcmkV 5JzAgMnave=) ]f$dI}^ΰnLh+׏wuId/jVjU CqqnpOUyՑ8ot%;zO)}FIĔ~@Z2[ɞ/݅ -^@\}wX×[ˏ oV+Esqw^_kqYrodf'Ӽ 8 ݥY5?J3{a1<}d/#b_ysmԂh Ŝwòб_׶At[s㫳I=Q꒲k'gw7SL^F> stream xcd`ab`ddM,M) JM/I,If!Cg=<<<,.={3#cxns~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+kaw(#/c`bdd?U@W.*sdaLf.^$8uB7-dɵ[9\Ğ{y_={&LY3gɽ=< mendstream endobj 191 0 obj << /Filter /FlateDecode /Length 4972 >> stream x\[Y~C 4Y+s?ᕖ BҫrC] b6a~q.q"q{$LwtD|ťjj_ܜMWg8SYzq-$cZ<+UT˜[ߜ ʯe礲9:{6|sw٨S۵=cIYh.ǵiRÇ]y%덵vL]~Bi7Z&) hQ 0\J͘~{8Mq8_Ga]oH%0A\de ~׶dfwd[DUz9<<J^bmJbT[2](~gC(_'9|oH\B82Hb6)uQ 5BdJɒ!my ?:stH!yb44}Y\B%NKR>i`b7="ZO11T4(CI$9]+]̣Q\U>y+:"5 tP>Rk_)=9Ru, lBrل z~V>o^̈́GAZY<3Еp$9*tHlO$њ U!$Uk|`4C''D@I=zjM'3"H!A~;8091P9M5,s&csaYC3+g_ 2bN!W~-#T~*?*<@ jK9m )PvVvЫHH|/9Sa|9ܬ4? @֝D;ceygz2{7Zqr^fKhD~P+GT PD{:5bISfb+nWOabM! =d訒pkZ)Eԯ&wXI\"nX'IS-&iBJfZK*i*I"BBJVOג7We ?Uo`EkJ%Bm%x_) 5AM"1">:ð>u&5F3mX6XJA0D?r Z0yp_s "]p|g <'Y ~iij$ӈUׂۇymvf~e_0٥v{FF0N-AN?SNQ ʜ8 8rpǙ$9?zbã)Q!;JtˬGR|gx-N4b |D#WEy>L1։^PbB[[' [͇)p|0}r#7oFQ>yyKw3a|v_SIdEFͺ4.DZܥXuiԻ4.Dvz. IҿI˯X&&!e\"Mk{0ڳ6R gSZ*N(j<`O㑊2Ý4.fK3-RQZ%ZRR(e%ZRJ*?V=.L?=,u:KaD#O c >pzQ+Wo{t~٥w?|V"_/Z'S˭ᅔSٵx|=򸻻o;=k=y;qqՎڇg/Q>`pn/B?_mފK͌l@å=^:2Btd*m;xb G`=Xx9q\6Ɔ>Gʏ^pt}1u+h-o=lQo5\Po7o8wRꐌפ뺔:3$@[#th']o@{e+:$sWFqο;;ٳ`TE'鬜Fƭ b ]Iw/+%`‡63,~BٓVn_VW)fƣdA%;gBSayvȪ}WZҁS'$ԢyGWlFʇd~bz2ނN}dT@#COӹ@l^J3!uXBfU4awuhqxڟywyhnfPۍ$yS/(pϒM1?`O" vRp4_;Fqg}S769F-YJɕI~2~+X喺sxrTtFyT=i%kgָC]@D>N@0CZAq}&:NH ;ZՉ>G lRs).;NszY[lF Wx&=A%5糃, IiA{(RIz%_ uٺ3F.t=È3̅=5FYk|2'%,A CUF$,}R;`v\3.}F5>SA冦"B}NG7www/aݻEȾ*!NjvlG1=-xK.{;0VcW'}tjɩѺCN@޵51Wl|xwVb.(!j΁8Pvۚ~ןQ~)~ *|{rb62lcf^bOd!mX,6ZQb[8w_ o.%Dnڟ@(Sv.2/*Z!-O*c9k"ʤ0BOuo4^^0JFd^wW !)liY ?S_EU'҃-=ɫ}/xFrb?u =Pendstream endobj 192 0 obj << /Filter /FlateDecode /Length 1098 >> stream xVK6WAT\EHХ{p-ի–Iv}HI{}Аo8/Q(=hn4>|oTgG_##e) aeΡ)Bb8K3ݦ2kEQ'4oRMѦbbFOՀ)vwqK6 G8hg$vZ`?bnYP++P2NJ(,ZXu#\M99fMؐMյ6f4q)M(OCbNxKub6I6uXmGHF7MѾܷkd|ѫW#iV8\-l9͑ܠg^1zWZt(u{a> vQA+%DXʱ'T588!6Xv=6{H]@kw`M8@Mr>6|ƛ0+fކ(oCy.eX!}zRvp_K!Lk%?糅, » S*.ӛPUiVqrDLetlܸ%0Z*x&ӓ5rf~Aә]@F&4p&W`#@qq` O`9 VL'o6\5}rW$8z,N ""b3],381-M ȦTm =W_Ǣ|12ќpx*> stream xkLeǟrKlędOc,l\)2:`@q+ޮ\'8na87߸%(>5F3B tS|[Ly<'?%GJ$Iة,stXU~0.&b퉔xvK=ɚhw[rP@_6A&2$BcuyiY-J\\|Lx7rI\lRSQL%\jlZ,nrn 89.xeR2t/>S յce!I6ё$LH:Q␨%-`釲R ܖ EG"T,I@6.ch8y5q|){Pl0a6(5eQݯ>˓v=xTYDТ?_ACj)&f]th\3 N Edvnn/H\HL|3PPsِs4Q}^=CWD|Y~>y_b\"gUk|=Rx2 vұ{,.`EiMՃKr=ӪkՕ@[C8F$=4b=e:J5gL!lU~ _.{QIf0-4Rc-=z;Xycj]>^40 30c8^,#jȡ{ƨ+SY[s7@qaRP]u:C{QbDWϣ QO!yGt%v5ן1N D<3=&!*^F|#`wSj AvN8֣!wqdxTc+)zWQ8]\!'rWz䙡?3@O}ބ:Iݑ#ld`sp1j>9f(w^[OJ`_=6e!endstream endobj 194 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 346 >> stream xcd`ab`dd N+64O,,M f!CgO/nnC }_1<=9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C53000103012_*ÂO|qwaW[ߙV޽4w~+wsne׋!۹Y}} 5.v*T];G҅?|_8{! 'r\,!!<<܇zl^}?20lendstream endobj 195 0 obj << /Filter /FlateDecode /Length 872 >> stream xVKs0G0> Q5i#V`_ʖ9fxM~·` ϪNHz|HhGUd~&%`C MdBSĤ̱2--*21!\"L4Bkf30UqlwҴ~sJ zA1JʿN ZFZLS4/ &TXPq F⽷a)HɼLθZʖ6`>qIs((NB0p!w!43Kayt:g&Z|9І PZoҷ =Lnw{-&k۬k;)26]s6}t8Cq/ećk4x# }hpC|#v}|4k_.! :]j@9bƍOl:G;nˋl9:Ho9vLCƶ8tֈ mKzm.8-Ȫ\GmݓPV`ˉ@"y,{h)Lઐ)t-)'gd<<ݶEp^BB&44Bb(oNv?)ǎntK[j9_.is=o/F3K8Ha˽?mrD-{'rihF' rQ>LǒrJ~Mp$LDSc؎\ۍ&?Oc(d84=$~.E$Mv0ε8FFFW_2&dF! 7pE\$܆$?мjik|1ݿ a|?(P9Hb5؋\Vt/wCJ;z|.Qendstream endobj 196 0 obj << /Type /XRef /Length 191 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 197 /ID [<57550e2b1c1199f4d9784a8b4dd9c5ba>] >> stream xcb&F~0 $8Ja?`V -/3Gt @q*"_@$s{A$W "r@d=X%db RH2*,A\ ND?A$d09 l2X`zy`nl`1|Wm`7L`2nld F endstream endobj startxref 141201 %%EOF partykit/inst/doc/ctree.pdf0000644000176200001440000066235614415225044015463 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 5316 /Filter /FlateDecode /N 85 /First 721 >> stream x\[w۶O{zBĽNĩ\l'qZmJT )vv7  fdB(Di" 1!"+I4a"&EB,a'Q,k$TOL8K"e)"dA.2C$P%R(i$ #*OrP9ђ*=p$h I41\Ph-Sb23b t$S@“r2eQLdCt@SPz/O<r`LǮ [ fDqnABcaYRApr X@RBmj昴pf)jafjV #Ĕ%Ԭ9PjTC=8UD (f !5k QǹI`l@Z%p̌ja|a\@w4lL*60]PдY f? 20ScMpkI9 #؆qh H 5Ð'eE:MPrLbϳ0;^‰'_n2?%yU.KEvqA "8lx.a(Ra}n$9k2!:υ H7U<ԉLCxmRkz"_"# ȥ&?߇r^W b.ab9]ct^Wיit>1suɺZ#>jr0oW׬=; ϖs2sT]6WѦԿOh1k,$1~%y~X2)(9YM ,kw_7\1sA=7C~ t:70(=6Ψ12n/ap_ wCYKMZ/If?TSt&={o< WoRoxURj|Q&4BC]%FZ؇>1^t1/9TH,hi>YB32B(X#;RJvhDAmP{99 (~ zPε@Cr)3R Ogb׏#D}͐W:ӲTѮAa$C\ԒUs70ҏK90vG-^y';H}zJ>=*:خ0I/oxˣu:gɣ'ٔ?'i>D0w*]"t-:- 1sWSڅkg%rTuӏs'0Do\Plč]ВF(ĩt00Yq R# 7T6 {hEaw]pPc#^qjvA_^0{is,~/(~4~?i|Ob8/⋋/u)_w͑-,D`xI Xz,eg\Kl#߾|O无aH q0.\9)[4}yj>:.3񆌘;דё4d\#V-/Awfxу@9P&AϡdlIQ7$%0Ω{T^# 0{ϡ,5:XT' hl8QJLGg' R9*tqXkHq:6zƦ}d[?ztЛmC}_6JyV*NA42(%Y:u girڬf:Jժ mk+k((O|wV_=t~КrR8C.x3MGG}zVGpi.^ðVd΅sxOB8=%\<]H5]M(#ǘX p4C"k- Eb+2Yhko;KS+Q=IQ$RjsqV't^YU֣sjOhy:p+tC[l)J;bh!me'vman'a}}9hx;0V q|2`kƖ[l->}Y,Դ]eN|]L:IZWKꁚ%}?`o7H~W$y{}y C! lCAՀ n+]_O}XT^cLɍڤ"`N!#n4EbFm  /P?5Y@mg+3lwϻF_b(-|[ȔZYyoև@wsp Bx`8.|Rpq[vU.UJk&K{. IP$(:8T?C7H>RXk_.p-f/TQ9 okDbl"gq:r*U`ku|mxS@-PmމJ<: m]{@9wX!Sxyhb2oU ˅҆ [LWwpUh츟h62_g}~ޗNmsЀ=݈ϲof_b6Ȃӈu>[gnѮoË .^.0>_eŨișZLR0kʉ8x퇃KOL/\;/劔.mCN~;khhS6FlvI9qj.aol1[ugыmfxz(x/3uu؜i! H@-8N+^f=-z}VNBߙKӝˍ;v*٦io*?;=jԶd?5*zұZ}u|6hƁjKDp' &GY0@ ?E~8af (hJc"][F| X9x^h"_l%cyX5 j m@]v5XMoQpʂ \\]m  "-j{$l4fVMVϗg,p'P2tv 7H4_/Gz^}ʐų%QVvo2n4VӋV# ߤ)Uǯ>ynՐHɕDu]2>eW{m,EX_dl8b3 w Уwg~m7dN@']įh7ZEcoDQ$#EObq(>dSFY~!S/bzjSع0c͢;"](.p^,WJI= ^}_ic!ڞcёPݰjh!]՝iE6h?hn/f "qI[Y#-}j  JH2o@œ$WSD1)jѡЌpK#-&"&H$!X$qLpZp-"zXYFߦ D ʁy?s(xy|U[޼ X-9p,qyc8p1plg2(SMތ]?԰uvĴnvy{B3pWgܶv }<xǖ#=osmNl`TvcCa \c* }/:}dFZYuߵ4L[!p4epM""-%(# IP7~&VLMd~޷Àn/ȀBF.wEQDMR%;$1+5BEP+&!eP!P*0ʂM2܂on[oz_ ʨ!]Lkb𮡞i.,*Vl\[FN6SfKC?mIܡ:oI'弸'$~wH܏qxUtf/D%F&_Inf2,lqYDpDvjH_\ ߎH, ;o#|O#t3h={ ~'qn9I`p y =#_Xxͣ~l?Ѩ%論sbx3O֫la<*Z}M+O~|/4rV'W;1hF؂Mlۍ9lPUٯTJ1UqLT*Ύ`eC%)|SV?@!f[}tzCqcv6PJ@#7DZY T3DZ!L0VӇ4.HSA"`{$OSMGׯ(W"51[?+q 7S oQ0.ZO:QzRwV2ZXȧL̽T_s˰" y^o!6X]4,>sL9Q@q&ZL;UX·_nendstream endobj 87 0 obj << /Subtype /XML /Type /Metadata /Length 1532 >> stream GPL Ghostscript 9.55.0 conditional inference, non-parametric models, recursive partitioning 2023-04-11T11:36:34+02:00 2023-04-11T11:36:34+02:00 LaTeX with hyperref ctree: Conditional Inference TreesTorsten Hothorn, Kurt Hornik, Achim Zeileis endstream endobj 88 0 obj << /Type /ObjStm /Length 3015 /Filter /FlateDecode /N 85 /First 772 >> stream x[r7}߯cR)ڸmR%b;.Y'ZIܥI;_1%֖J+0ݍ (eEZ#.&!DxFhEX Y<@"'a"90 δSm549'/'$l64A8U~sgA+ 0+\h}CVQVAP (($A9d7OZ4>1"1DP!`zA("DH2x/3"ڈAADbt$b$~ًX. wH+NH"QB+Tou[1c0X5X%yV6ۣG0A; bH{yő5*[ɚYŚOggͬ~Th´O9wԩ_"$O$\97)(B8& !3!2(wN"c\|;㜏SN,02|X/(1w]z59IJpMLF~= &){U8Cci@g%'KLɳ PH 'Aυ 1E:=#kAP$ y:nem\hZP&##s5@:ldW f.wSA\сupgZ6lOX 2'iUUm7VQ8gF#U6^.zIT'z~UCFx:QgQj~չ:k9,K]K5Rc5nsVMd4iTMJ]1E{6+\5L\͛wDGjxڨZ\kNޫ 9uŰ s0W˿!}c$Sc\L/Ufɇo9uf+j̊ce I>$[m-B[Ж~5Q*k25CWo]/9갽KnWtN~D6|l[檑nmK;yMOrU\\.KT9:sk_ft5)]2_@Dx}+$8CXZ%iZu֌|"p0VF^%{[@HJRtpra#TZi#7&˞Z@%eŵ"JzwB<~!ɷ./tv:azހJȔ*H) ~6+-FS6aءZ߲!:$S{堪`n@-C4 Tp`_WFr_"{zXPaQF}'y@g= jlj\ Y]fG-AXo@pȇA{)@c @s4g؏H0,:?ɁPEvN9x3s0m M!Ie!QI%$;n]hzV3.G_w@kc{{ntp"σ>]ߕz28z!f@r::̪fh9"B$I?EX;Yxcn@!Th$۔\j: APA@VG&cϦpG⢓n_2n+{OG 6ibގ&/Se,ھ-Ký_endstream endobj 174 0 obj << /Type /ObjStm /Length 2938 /Filter /FlateDecode /N 83 /First 761 >> stream x[[s~c2aqdCx ޑMs`LCCpgX"a%>DxzF$7D* p./tCC5D a(…2Б{ODswDL h>Xb P;{b>c H9P2BpI0)[\ 1jXb] X @q/48qB8Bo IVPąׅ!Σ83V8(Px#^x HRJRoT;d N j$ I`JP 8IP@caJ3)(0h'cYomz7?1؄c@JU=pa ~`I10$#HDҒ!ڎ4ws,QJу:뒃<AF|K+x=+5%\ɰ7C"b8,xۨ .Ժ8,XyXʤu)($I[kK-,K .] >ˮ,g T^d!{azjuimjڒ#]_ΖrEr]FJwٌ9l]fl<@|P)|a$ON QlŬ0E$Of:ps@/%D%ȍ v+E%U=^c=ŴS¡MX5DG=O|WѠ[ +)z&9䄾)%l3Sҕi k?}i%JPYDʇFM &6[:s]h뱞-򔸴 e;$(W'/+3UԚ.$>_yY1Ӫw5aߞHkm+( V.2q1HMY %~}/wp26򝞚"kK!ث%ҋ~f5U4P Vd#[Am LT穯߰ʢ&3l2IhM;aDi$'a6czGZKk1)1)q?WoHL#>eΈ=&6jR:riF\acÏT8 SL])f4fGיRQ )ў=R3e@ LE!<Br[Pn@eG!e|dfi18!(XH~(8Q',$^V3So/oF{zsm{[CE9ԋmZSߢXpP_,~4>X+h K'jwg߼}7ߎg/)g'|3uG7fulG3%C { \;궺|+/^,k{!5kn}u;ެ~G'wߡaͅ7-L΂!T;"^j?xBǫ(S J*{7zO#Nty8Zhj!ߖj0w\뺞g~K"_{(ܱ~tTEendstream endobj 258 0 obj << /Filter /FlateDecode /Length 4443 >> stream x[ےq}oXG 6WmE[ޕ-oj\8==0?* "nzTwU)vK_./}K]v矴 WJaE"vt4~wy(v7Aڔ"˛}}3UY`Qm{{}Ot|(.A!Q"hDe?D!P^ARU.f(m^UJʢO_|wߟ}62T :LjJk|9*2N_4r Eq/}Y i 2hQཿ ^8ms Z粒ֶ% - m?hC\#vrPU)]f[s]\~}|i/;`:f+H`q6p|v(߄zhA]oNѹro.:X%XU2|+9cncμ*暌7@?^]xK)ߝ.ş6ר](6^BiY I@YoiA[*k@/n!F(jJ)]qҎjbE[a6m` >)(UVKHKA =՜1G6>ݓ'DfԢ8Kl+\| Ϙ>umm6$oY6mr!(my'=HEZ p X4+0Zn"|T1S(~ZPJ3zSP.Vr-%rqv2dNR ).B/#b,RКyl@KCUܗFǍق~,tf,> Fe=PNg%ln-%+ $f;X9/Kt|cz|=L|F"iN>qnMt $\R2L%_i@]&.?/`nitƣFl=A.O֠XCpEMulW⏄r!xm>WvVQŇ8$xX  63̴w,iS 'Dž[Dgw >ީ3,I}3_{`le:1ö6~es0Gb5"x)ut z,EK~4u@M=@f4n `!04+yG!<W{P4o⿭) a]%Yu/cz)!N`%9ޠW̾pI)֏e ̧jI;gmTL2gifɫ7 (M=NYۂMe&/ !C:IR/a4<)^`W\`o*n"RU^2H '_D` crUOuU~Ð58I=A2XЯX̭uTGjM>6kk9__IJ̷󼮔"| WB' F #)>G)z BMJ0ih&i2k5IIG8YI9LD.2m0TQYr0Uog8 s ͐:RX=X96e˶4gV.6m!Xϕ4wWN R1C[5P1ǗtȌ@12ˑA#s!Th>:A)RA5ZO3YZ;+ ֫MtKGZRNҢΚ_G/!Pz1P PB5_=b9iqgl&9^-&ܺٵۜ: =; wRFO@J:Sӓ䯢X#OݰFR4JsdU|svW ulWo#ѰHz}moi鑦rtߧy3M`G/1\kPzFҐD)/AM L7LĪcIG]ZW 8*{cI<)~hוc OzCܿrwVI k%X%x '-ikDf{M-qRX"a-N"ͺflEV!^ ӹ듰+#s%/7Hf zpdJ"fXM@FуPO%)q/y`Ë!Jcq_EdEKT10y~87O cZUz-gfTT$YXS{|BjךPjImg8t"SiC BǺ}{qY"lMXY!}-}ga%ڍWZM0:&;r)@fB:e_㙋 ɽ&|1s\by~f23@ H(4?U~YIQ)7>dq|g5<]:":GZJ0Y*)=.:=zKT*?wZA'ųB7D\L7[Iԣj:[>piG) [6]Fhп|).3)bhaxqW P6cֆSsџg)҉Bo~ *<M3 eî91G%"K7'T̠k7O?`d/r Cendstream endobj 259 0 obj << /Filter /FlateDecode /Length 5887 >> stream x\͓u/Ƿfjvk^ǩ8SeF{4҈(Ԫ>=xh49#/)!}~=zWWN]w{o0q}*N^\;۟`slpUtx: 0{W7Z~TFh'CwI Jdw AmMޮnR d8[91 }68{ㅷ;)^uMw 3TqNFhիo齵qwFXۇ :ho}#o G o$#|_s{ qj/C࿼.x_:R>m ;":{g<m~ts'>UiϸO4iV<)u bac將Ƿi^ny0ZO+:|+⎩6ZJPd(vX#E.h} "WӪӐmv.UP6~Bt#ɮB=[1jR Ft|oJNvh)h -hDBТ;uqCŶtY.wBٜP.X3Z(*yVvd\Y0Lv/JN?1 SæԺ$(QE 9qz>Z`QQ2 n"XO{Ae"/Æ _KAޗVuIE֣ߎ/V mH W6ZvFtѝ^PhDKNپE~M\ av9U%@smmI̢dI2~k~@,#Krv `!f _NNO.ȁ0"MD9&PB'ϠSНo,0i=ڻ |t202y<]<ׯh-= .@w}c}8n[&-ÏlE*1ij&]@Jpy{"~U2Jryșjq܄.LyȐ{aEb%1Jze( }Tig+p< &iEAΈɦV*N)hPat $VM-ioڔ{4N4a9[يiaͷ;ahWY(x* !=3"3qOqF *(}@#ևO!8!|3=Z/@n,![aLmY9@%xNCdzP DTܽyh7X2I4J %b0D!MuFB<%jb%aOg~& 3Cv#7_VjEY]՗g{o <*񀖃b* _JB~d:=֐UWwTZyqL^&qMJ ")'B>ɡ(&DGZ凒AOcfUc(@' i>JRf.hUiba)SpLzkĽсXr_3͡Ceeh0"3yQ0ɛc>>`EdPf1 >MC>1=ZڶDhi Tp&Ј $0㞟E`ƣU,XQYE 1Vѡ^ɖUq=e3=h>eR1NF,|?eE1e3fWDS3#C#?CX~f,nq&VtMLR{9Dޮ[ԋ"V$Q`+RrUC{$3Xt$`y@0\ʕ+cÀN{#)bfm3;`39sزyPpH6o8TM2(a\*JyX(hC44 Be+pmKZXeI ӐKGq$ g813<~msخzɕV :dh@ԲS rT%_.B }: K2Ɉ#y>zW ܟHSTgo@6bM[kPpLNLȾI QLgL +f1v# 2JWq "nI6x5@Vm,ŵAh|<ſÏkVOkDZcZ,'b #E^[wZՃfB[GA$}:%͙S$hT$ruJ)ZRDbķس5T8k#ihb 81hG}լ ](< b< { єq+îTᨅЅ^L[kܪw_3|v'yѭg{ 1af! ?uGJ2k(@-i]Tyz|]}?~3 kVH0$ 8)9ˁ/V-dVħtđbɤ ;c 4\g%YXMC*; ֱf8 Qu,#XG=kBC|PH[|DnrB(d~ۗ8Y=o(,vYY{QשZ⽔SαdBlÆpb7jv>o}UA5Ĕ Q'cف!c;2իn CNRz"ILmJ'3уO|E]n]X h[{?j47tc6}GzP* ^jSk0"jޢmFx L$pT;* ΘC'jܨ_I.D0stgѨZ/R]c{Ҁ7AY~s<)b1͹oYI.!ߏ;"}9Lڵtd\Zjve0X7w|&lB+ TO}Ü8lFu88F˪EUUK:nbx)6.OK3RUS-" N^`@IY<c#>GpM1w$F-޺ovl_'0z`l&q֔erS\x9١25*\5ޙowfPVO: Pcb"XczJ_a^Qgn>+am Eڒ#ǟ lO=JrJ7֝DvV1!!Ek<6Ou67뻦vI+a*T Q5h]ӵEw~>#{'A],?td?qq[ toBŒx?S❉ N14%qF&rI䜳i->"Y ]SeQt㧒#8]%i.բ9bi /*.{C/7% %Z6cI*gGŴ~ -I`Y>j}Z* ;GϔڎG9ё^̞ej!Io]*-Hq3؊vn"M֪ 4n& ] 1no9q$l8D?V'!ej %>~pʏcݚC<1ҀMcz*, !g+V@p?}xK}N; 9M?ve1n&^ߘ]m!rr'8YBi_.ޕԯvie^4lJc1?r\! o b3yo2YQ߸06VH5j՟hp9f Re?k lL(y}AjYSMOtnh=όiݴBccck{m@46:'Oۮ$` YO .-ɚe>+4w3-`8s<WG0lj;g1)z!CU:CdȎ,B0_ !# d[S.v7&v2uo\cG=%b(,ofR4I K _[RJKW endstream endobj 260 0 obj << /Filter /FlateDecode /Length 6629 >> stream x][#7vO[ JN6`ov'^ HsHK{AQWx9<~1l1հEv2nplq̉^H0Nꦻ^Zp<-WC?(夵r%f9/a຿ ~!ku8 /8tP|y>KBvK0׽B?Zf6?W,_ pW+ im+z5D\I` }zvze5Ja%?r9tDw(޼a5Ћ .m_DZ ?ѭs CK lbziX}F(&zUxѲ!T PNuM&xtR;g|k;3Pc N.V7Gۻ'z H75୕ab0/lne4əLbb \1zGdM/m\knrZ bp!w=Mb%V _7T ܮXh}X6nLKTHuƠfNy}9a-6"y/k[0 9'a4l7\>| z*ob\9J*/ p@/N@/wQAM dM)\n6q=l]\ooPEzUzw^ڹ,5cu𜩹 EOٌ\!-# ZW[u\1Mlް󓫹"Oa TǼ߿.װ?XHfNJv }NԢ ܨ QQqYQ iyGl-ȞC]Q%SMA֍ [WH ^ͺ*DZda60Enstq)hP g&pC>7xUH~fsg,(p~ݍ-(n6 PڧB_vS7#T`1n E&J]>pp[E Ju/Yt Zi26ZUoc&ʎȖsc21sz _l=̜`qov(gZh+#v<+]XhF\Rjf]WV=nmFְf4֨`^,'y]15!y N]*'vB;>*UADzŬ<[=J^*5@/C<=7>N 2Ԑ oϖ+`!?ӊElleQy0^Nʩ(ZV$K<2<c "C] tiZKd#i?Vza Ll5ŋO3I7m\Jd(͐.mTl*{68!̭1!@ gZB:ƫ>,'!(j21),V̆Ac6>PZd/D@;"q~Ägun$p8PH MQn P2Bh|n)9OA4ݜ]3Js it -nItm ^ߢP%I?2iRE>f+v1{dxPY qdZzu06@58&[0)I \? _gHR6r$_S'KF 7*ds]h$˒)ưLDp|9Oa VŌF>Wu*U ,kF Wd=*()F/I<@lb ލLGDP.pC&ZHF*It o(ৠ5f*'-|mU(PIL@WSxހ[n/z4 @Sڳ^lO z,ܩq=h¬0bB~v,IT|}рCBMo$<J9SAoMӆ A \kɔAZy9іR&@d/gIS*H1 >j3{G=A2ܲ.Tch1TNejLUh tNr/ЈsiYh ~"NLܰYTSL20RE-iTPP%VI6Qqi uXndFvéP]ęa%*d)RY%7qQ3:8n H!%qȨwXشYooբxҦLNNV1e >֋@eTi) uG#( VL,~Rf܌Ĉx9fy^qd+GH0D,VlBlLBGRe/͢ ą nUPК=C1 ϯ GD~2-ml>]܂ChjJFPڈE c#\\/D0ggBo[:6yۚ bH`*Z rQXї)g$,r5@Mf- p%zg?Y-6^hJ7$="(luķVg`ZYu}qĪ| DrX/¡~^H p`\7ǂ1+Pj1X0ԯ) q?ob| 0:p'>NIєiT5S X9SCVubp6Pi&0T{Jy<T dƫ}-Z*ZVx=orI-(=I"8ZIW&Ҏ$C6s þdim+Pe`IML@:k1Jy2lG(aWOj%fl+[^5mnQC :qx]ɟ'{0f22S ?ESc0\ %yN%=&"K[ 9T_<_3t~j,na 9rkyUcz~zC=RQq*ċl~hBoob1[Of㭩υEotkl3;ҡZvq !i#ܴhjoGbuV$8xa?G>h'ЬьDZC%bq0saPؗ4Due|>TY_T11. m|3^3wt tޜOP3EG`O4!5<~S+Go zfc!O Q*c\)3~4A%1)!1LֲI>*vm˴_zr4:Yۇ1q)K1=$ *e:*9KkNNL&|y4"#M+az㬭*?GIJְ6E .-\TiH&)Җdf` ]X;S'ªb<&P? T^vJ;u9 .abMLzȁx#YശoqKͬ `lr'$Z1=Oo݈X@4z޳(dGvI펝?!4F8y ?&!jAXşx؆wB% @+*FS(9= O* j="<2sFJm7cukM5D9XL#'k;c@q;6\c溵RMQsg4GmKcm! bsUÚ -axΆI xN;x0U N?IX&L#6zvFC ܟȣSD82_?0w΅1m&#*zhxL1/1n9U6&;di#$#<+u7evQ`.s!ޮˡqR\"15.+lu5Vӡ4mD+VWexQ\0'=oC]~`tnJsSX .璉MI& t.j5dXHր'59xB23e7l5xƺ׉2Qq-tu׺:W@Tzt*?<4GOxO *KJ5UU˔_4So fm#z8bXēe1I\db09Ru%B; M"ҁ'hs&sJy{RbC+ *kưWJB/YwIWʟnR^t:V׀$(2-LI}5G;x_NF}앵 +Pr .5:%_V.c%jK?+xa3YQ/*rtgq0j3 Ac3ݧ.Vf-!å@e,,U Y  0Ψ U ggUL}Fqe|h%Wr].*fl5J<ˢj§ωF#sFt4^X=c3Y.!xlz@*f9o{sڃ 7Hj>7+5xWkˍ>qRd! '%Hje^xK *M7,஺eL:K.?8ATI_ϫv H =W+8~1endstream endobj 261 0 obj << /Filter /FlateDecode /Length 3648 >> stream xZo#BP @Ҥ &uPيXݹ}gܥw(]r8oO ÿrg?qz.?[M^RնR/g/-c46k^9-WR j/i9ͳ8ˇlT7 (loIRCN撞$M>xFw5]_~ؿp(/<[)+[g }Ѽ+*'``yfe\6[i^/TԷ˕3ƛ/I{ж\t}wOuAr(~u]92Jg0adlbqo_4wB@ed!dh00i%hB+ټ  I9)8G'iəOKsqz ,=qܝ:yj wZwF% $5nenF@:ZFq9 #[;8% a DsmEs9 3~`^>;\m>XFL1JƐ€*|Ly`y$ E$an(/67]#+%e2Mi#,v#xæAg @c,/Xڡ4u`Ɉ 灗\YhՆѸ`bEa!CAH pD7gp!y3ΰuvJ.ư֨o'SR@c+HUb])/IŰ{>gYj!,DuruFכȢsP<9S0| WC8j6|$L1IWɬ^me:Z"VKR7: ~};V0IRb`]ps1>!"5ÀrK"@Yza}2\E:NiӽOÍ"~_wc n9cN ),]$ĥR[` |G;(nW TEmJQ}xlY=ЂYr۾EQwIp4)] 85G}kYaW$).0Bq62PJ;ͿBAq1H4PY@1J׀«Zq߾r-rbHBq$haE(~kcOhiU©{'A⨁#f@x0[?6wF\xj@f=7uDH e 4e.}롊(Ű"n>Xn= c6vsFlv/ XJS_P5QjQ`KnaXѳgĢҘg|comFeRFUmH9fR)[RoXĺ"]d&50kL$yHI&6| *mgC51JB׍iP"n6=-Ze:/GuPO@hԟz9}^̵Wq:dPH;sQl LZʇZ-?4_6Ԃz i%Pg|یBPOQ^ߐY]0:Taislک&;8 @.;MHVu hA(+uڍ8x'ud‡lMNQj1`hࠠ!C9zpy64ScAiE1=6-+Y' S/[YDv'71EDrǩդ!|+<nz=)""}<mסExMj2ezGu*Y}UQ'1j05D;.VذN>47!FDnӇط !I]v"d*H'`Pm_-!:h ՄRP/$NQf'4e Bø\w{.[(YkS ? '(qU:P= m/'.qV KMS#V`8  t4pYW|RqV'Z[Wmu`t<¸ .Nw~<)3 ,KF i!^N`?g~Ҕ"@vTR#%Nh{2 f= ČIǣҊ{J0@zT\\L+vTEǔ}mi) Xh]Pyijn#5:~Rc  $ccL'| x/Z)z 0>GMmxdY1Qcq&w5hZx):0Ӎ}79n u4A1I]%MPxu̟z'"( \xArxAdz[ %8#NK!V׻]85yп)q ,SY"m؏8@meb ]V tjP阇/[rDPRtř@@V MnmIT28Rī0Rfe3RQvɎ nf5lf^ßWG~\V{CӸ~a +Nb' !Uq3OB*@7 j,`bU% e˵fTo"aEsK_!a ]lP4r!Z u+<@*Z(By8BܿBN9cE b'qQ[dw #eTvTTDDď'3ӝxx"bT:IZ%[ WxL7p.cu~Avrh{eg3ٽS F.]7QrzUJ99Ÿa^m%I1(2ɰWolOWg;79<KU҈|w]}gVD+]P3%* Ѷ`)ttyy:r9: DUB=XHrVbn V Wrx}\8vdC%,{e(^vzM[gL{7 *<0&(qD5cA~y7gPendstream endobj 262 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5454 >> stream xXXT׶>#b80xfM$FcŎe@X`,wQD`$%&v˽7jL1ћĘup}w{>83{?2ƪ#/ AKD'rqȚ`+[/}qA?F.- 92,Vͫ..ƌ?h|"53j{  xl>Vnh ,]Y9{fK=%_d`.qm Kc#IJǯ`MKNmEjLB5Tu(7pvBhNjLimhRyb=F3=K$[ӭ,-af; ע́[\=c{(dj=cW-[n:+udn]8T>M U>#-2} |Y޾ ݕ䫤wq'"7O::k rwj2?S0H,yKT'noV n>zVzgŗ̲Z\UDq?dĞ8qҗ?@lpDI{9 eG-p7%󊞉``0";bJ=+RvĀ(ĒWrx=ol<(׏pQq ۻ2fA.p`Pc[ۄ3=ϭxIK?#itE,PYB*O Õ(GS[{2tZmٱ 3X~Cm. *)zZΉvSz+H4^a qMf. Dz8  =nVpPNq?. qk bnef ZppJ3j7;Oۗa9JGFM%3N.|V]4u3x+x<]|!c E}gm5DvA/m"J9q*[z+{7J&nUmY~9'`Oa>~Dr>&rzK% eB3j(`3:ڄ 8iPY#Vb\7+qF K+pT')eۘ3Tk.+rq$p|9@@9 s8w<}vIHʔ@W /ؕ`]BR>>19/`2 췭6Q]hNH0v ‡B^ctUMXv;dpƓP .:RȷN"QР3Cg@/_J n@ JCYAoX #ݯo8-\񑶿".Z֤>x&<\.Tld ւv?̻{S=m{9;/8$h!\.!Gxm,x*lv ZyyhT#,-T[ŇO,l ؟. 8RLnaKLV~z~j 9g<ȑ?^`,!Z/ujъ_p^N[I^߱|a_ܶ)o("> b%>D+ ot zdxHl41cQSGYd%qRz>-8[UtŨIOMxE06C,-cϳ8.k) !ӔoM]WwnbycYD g,pc=Y65nOTZljBv8$&EE鮭9@`IgY?#2- s(2>bRMӱ R3{(J@:]Af\%4UH9"6)KcaPa{9Il'yEVT6YPܕ&),yLXG.E\{-{ ?(*J3LMcOI|GA=&7ckH)y޲] I{bIv0deG 1T39j20l fwCnb }I)9-`eL@vI WRl\fT"9yYIg-J()XI5G K]b:G j Iu{2LGhrdUT.SJ6zOW\&3.ms٪隭|M mX'fpoSF:Q'wq()JX V;FO7;a? b2eAzYNsF.nPCN1:Q߾y8:w)}rl :CYC" :99jqvT6Cu6,yq8"Ah5z3(?&>w.n( ;Q –tjDj<8*ko9n[$ׇ;G#OQIbå%u,9hìnhW)磳(q#p #d N?j3nKC@0B?ykXT*j}x]O'mʳT}^{hQ; np CN.!loB侄A | 3R9d4 bbw[_E%dMzf =`W{g$1b8DYYEގِ‰Kޞޱ=r#%\m_N^uKqͯU ^ `:HLfD7йRw|i(X?n VWVŌt/)(p(Dz(\Kp]rED%Dy(PBq.wYh?R!`[5+X+~J7r6,xȌvN׹ WťFm7GĕAPX' $h].tXk(݃q {^l#Em ~|.]>ߺcO_I8V8)X8)uunmѩ@|%[,- 6*0^REPiρ:a曊i\ވs__ųZ t*ZՈkϵ>|jP*XmУ'cbҕGQ:yThSnvNUITl1DlNres+ 0kQ?n*eqKj7@_b s ʊ7qQ3 ^1Tu>QqIzB ܉Xm6Bح_OKϒ23 _@'C{t, ?y騑ӚfٮfS/~B1Xt"kP}AG<+eԿ'V$H~`QF/#_X[,c!_Tyi7:U|MgT7j]׷.zNNas hX:_Z/ʶM V额..iL\n ; \zk][8my\GQkY\f~m:Zd=p\4a[?vё9NAQ ]iF QQ ^YfU^[_z94(Mh<ږV 3.U`K}q2۵gta]\ow )VzA؃F¾%㪾|ݜy7V޹`3+=p NZk6F I܎t+W Z ΄K=ॶdB R#ӽCB=Z}qʧe1ö́[5a|S/xSꉟN^c~gGb>6GzTTGށJ DͨWx}PRsnɲOM 9uE-hON%s T}Ԩ o^v23Im[a߶g7w,xmh<%ܮRE<{MaiC6DR: 㢜Ϩp稝AY!R8&Q8GMhG]""lTaæ s&YZ8yjўC-~`$]ű%ZnId#zCƜzba ? WN`+zؿ4 tI9)f+ӍT셳rMq>i>;k9A>:ѹGۛؠ`c$Զ'NMIMM1dfܴmN;ǔjJ0 > stream xzw\T2 j`7X&E]QT){0ì:0D؍XbK0%샛wow?]ߵ܌+WL<+5:"qݱ#z ɡm,UPM??%6x/ f3ui'߳mܢmLY5`I&٬$w، qv Yc{%vkޝu@Qmm^q%aK×E,t]2}UvkzpY)SM1f1ǾپewMLRpʎMPP#ԇ(ʞM9PcuXʑzZO6P㩍jZHM6SIc=j15ZBMRSe4j95ZA͠VRSjjeK ,)15PHʊR`j5)AzRʟCPQ}@eNES/fsʄ#%͟[Z-]{A=׳ך^賡}70k@djyK|i`ʠ~ZcuN#ml;D8d吳CU30v>{LLl3ay _4\7F0jըG:OƘ1èoG&#-R:MA\uXHS Ҳb!T84zNG5GCHo 1T4 @ :'jZ( tWa0x ʑp2G7-xF(["+㊕d7@w1ȁ`k+)_ `K*7Z|[WS6p$+B-ZI~ɥy,{. S^3E>a^ )zmoXi,TpY{pĴ9R,AilH|}> cU  ԯ>e)eh%6J,m47!NA|a&J!G#O)JT֐cݨ#H@;H@Chdwљ Yt |;+,\v||<4ʽdUW#6ԏ*!K{gb!G!AuEE_/w%6iY 2Tbmr*E 9_#AǼ}qX`ɯQ'Hʖ8;;9lp:Cɪ5U/ڥւzнŽKsW tkqT\Tl\) CH{޵-/FG) Q| \#T-2H#GY`MP6 7vL4 >yvLDq\Ȋ"Q&6xnt GvGxtLB`AW!Ct dɕJHHf7z6m<:aSj4 !F֕"xMs8+?W$H<)6^ŏH>)e)eޯnC$:Έms'H"5xGykW(gP(-xHݱ!OJ܇RAӨ\"JƲxY"Nʽ#gY+ \'p ( Y"")rPCuLTGu23LرK=yoA, ,dv40Ml~&W-ڷ&gs߹W3vEW\^/F;N{Lu!f8<x<1W[exZ  ̂Fvmk:K j-RG&@0XS_jȯgIs| ѦC hJm{5ƛ27-2~@ >(S$~ "4 Ř%*PSrVfp;l%:@ ߕS=5!oia[ )~ZVLd~6%hj$ij*ebRQ;X]X.U|Ljwb>wQ@L/9\ ߗȈFNgۼdi>~?$4]vhw8]CxVqUt6[eylIchKp<>?dAԨ=4ut\/76}F^dɋ|uD-އ&[, q׆(>,JCx5ooTً./--Omئ4ɫSeFǪwlgF,q*c k\ 8_ xL"LXi[SmwLǹ7Fhq,A"ǾnOfA&&&]LŅ4bZ+2r!;q ýp5L0Zs++ KqhmXl9RUmlj-:Ļ4u0zm,[lS;,<>UjtI1̴r #. ;M"`&UШ=V;Hje횴 o5JJ??\RP4u z4[^KX3H͈UfRhQJ~*Y=l#w]%Pw{)uˢtu3IKBQXۦ/GH3.)xU6RPONeWh vكqHnjwIFMrLC>*E~".Ӵ ? Fxk2 swX|]XNKs6Z#_Ȩ.!m]:-5a4VK镹i$󪛡0 HCք \7RIUjLC1SUubU,ZͫxLS[v`5#<=LxӱQ\>rʦբo/okx(@;I?w:I"X㹯#yCz~}$qM)YF|u󐺣TyM*њuZϠ |`!F!;Ig3f)BFwNI !׉UAz/eȌ8wICZeAwETOa5_, e\իZJ 4\OKX$t`wA$C4cqp!ա{[UT4Fhitʋ!~5Zͮ%P~?Ay4~'5QDEP.RW4jb:%tFF&t>$hYBV;BkW8r7ÒIi4{HM+0\&Ջ:xH{oHɖ!k Newv<.Y&:?vxGǓ~q9^'؍Ix2ZhrbGJp)~g{P!G?-˟=}Aeoٳabz-|o:Ȉ{ "H)b„GW=Ѳ9<=GϭĿws ɓwX-޿( Ih.z#gi?ji0l3?ńJ hWe_Yi9͍$otVb,opuՅxGzC,~gx_1.ܙOסn6Xˮ] @7=_Uʀʕͱ!MDYS˕rH`b s˲*YSR IN tf:<dKڽC1a2dKhӻ;qpO~{VÌnϯZ\gEryo$ID5ptw;#L'h 'mrccfN[4H()Cd/ 5lsq *Ҥ˱u@1 *@6Cmi W<78WD4]La=^Ka9z0c^,S+4XT|TB^r`"s%EHu%_D x˔-2NHOcOsD75BcnXYRV#20$2xZ۵7g؈O.}v $h-34JWm?I'D,LVE^w:!skJZ8sڰY' )%\IٕRY>̢M g8]{RuIݤMիn{hX]z K^ɺؔP0@#$4Cr# 4cEjEPTGFGo$W.}ϊv 7D_!@덂&nGa-Q?(4+D3x(jMP”7u~9áp7*fikE"m3|ּ].l' ,FKjmj&qf_<֦s*_s:W@\0WʅƷ@^sҩ :*FŚ,qԩ%H 7r۟_*uh<|܇drMч[$*au{tnZ-nx=XK״쭱 MGꈎIݱEz X`U4^!VQhN4^̟?}R*fdPs:It[6sos#oP0ͅ(ubl2Z o|0!$> U2Aj\OiOuMH-.u* K:m N{'|OCK%@!h l.C>huBܽr[LǾ@/BsTxE%*:-M @Zaz}/yJMOϚ{U9k,fwH(sA%p;~] v mԹ!O:o#IbW2n-fV{| NGp.eW9hecs`0K9KOQ5˸3thU+/Жf: SX_f} {ϷyӍ7~6Zo%&"?9qgJ2"' ^*zMF칓}{S1:;9 *ӓg~eOMs֭및Tw Gxjjd%MzDb&]64OwVQqUНi=n>X;v# i=>%!mmU:Y5$2,(a4/y]2䬷1ը=LSPy@o!&T`#N`=q?-13cTaʦՖu8mp¤N[zQU"zXbEfOEOk#HˣO#$V $gŢ P7A~_H{P@`*2isRb(wؖ"Y=c!9Vѐ\ey'`ؖ]No u x|NPb1yl+3C'$&q_J=ORǍ{ 9z;:(8$07T~Vç6N雲p*YBwȻ5ɢLHr+~`> |h%$q ԟp-lM VcUmzv;8Ui9|x4#f2)$!lF[`S6V9EQ! g*#[ a38Dܨ'\YDh!`e"ns.geބMEO`N@.{SS'+ 쿀 {i:)~AъHuϏ9hh]#2hc>uj%4bp̰_,~;7۷yv)wC sӶk/mXVtJ$7̞3bQQaiMU^4#4Űǿ!Ov,1u\X70W߽Ϸd}i?bG vv]1(ػVٮ暹q*;yӶ p~gg54WiB@՜>N9xbo\hl0fhD|O>t[u̽`UR7N[Uشٓ.yx%eWWuؤ'm)&z_Upx3R)▵1%xEkM`ZQS`v#6KBb>9\`2uY?Œ׷!nQui"0 Rhٓ4ċpl"]s$>CfHzyǁ=.㬖<'hPs%\*2/:$<"XjdAhY#i`$ꍣl$EO#^0Nҥ/'{(${ǽx/~;7O7he )|2)Vs:MqdYĝO콰)1uKSB,S_VYY6IF,`C9 7T`V WyChI,gRh-*csW;oU(jP2-Do$ŇEzFPJPkZkB72ña-OKF>%+ޞ5PM`Y`>L#r'~?&s\W9R  QkiD}2~U._՞!Czґ{ge*lԿ ߌUi#C>tcUP'UEmBRD$H`0w OFF3ď֑ŽorjxrMT["Nw͆5of"AXc!iI ~m٪o[X2"c+؞9{5Zdi{ZuLN޻Eendstream endobj 264 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2226 >> stream xU{PW{0MI@Ԁhc5d B s)08́FAg M&1Fd-&Y7Ik۰[}s$JPL 3°[ha*qW~L4k䫄ǟ?^W%\5Oms Ն] . XvUv~G!+-)QOӮ z3Hސ%_&j ;ڨЈHmXĆsEyܓݱp%K_\,ImUjj A)xj:E͠)J-JPMEI>WIyD9撤U LaYl][CC!s'/g)\x*eKv4/ ťHcƣwo[YiaH?CM-,wQgFC<6%n+LP ̱a` qOgXijzz4"~d1-eBj; 3#l67hƜ"%l&k#a+ CX N kӸI7 R]1(טJ(,XLLd!EsI>g=dk^PxnG0 7sovini a+(kY ,)JhHsjS ˠHS ln['DcC{w/lB5 V|^,5^G+)4@f-:d#}2&S\q(sJQgvLX5rs}~AJ8n vqsdxd^$o1'/+;%7QuVVW`BMDv--5EVK<(ѐA** }އ%95-^]Wtv~0-wkew#&Lë>G!ph@2[SMBN7!=.?AȜqS13B4xO@TUfVZjjY@l*kh^ٙƌe5 $ Mb_3 Ylbgm|}FmT@_ S14z}*7r7]pu &1wDJLE*y\w8Io&$yf{ね0~y`N܈9*oә6Ўn@q֓}ـ~ i=C``UĽq] FUzSR>@‡-n=-*`$nu|Azfdprj-/,N}*VP]g= SNmqendstream endobj 265 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2422 >> stream xV{PSg!{QKĽZBvktQEJ@^!L 9 zbk[tN]wWm\c{jt盹|ߝ{I(GJ"L]Z1AD1-0oZ93!~+;;~7 \3s1J*Dg6diRs/,* o+C2ty4e6Y\7ӔsuZe:5!3EKQQSFET.]&EQ^Zݦl}β͹ IjMjښ̍NEPHj E=O7 j= BeߩPj! VRHi%a{S 1NN#eb&19,L_)౅:u(bMC>H%k92:yIEd9ÌF'_5֣KX랲*cZ%S*dN3\'ӈlEȢ˨gT]VPw)1  h3!be<ΰ >cXH4zzc\m 7BIvF(+~y v /#uݼYQ~DOLl~f%p>ч ϷU/&w qb|SUj;Ǜǥ8 9Ҝ>MS5D5Wv.ϭ*vv)/(36-Ȟ~_V6E`C%c + rL|`P :VASzWN0~~ARtg#<2b*z;Ug9GWb6# }Du)NUKݣxl%fbΔ5L7x:I T3AH6=?qOE[`H\bdx?avJy{xGH{6@l#Y(:(u[9n rKeݹl^"T 3<]5eClRɨwLbK$w>eHN34ΚpnjhnniwMf $_O+eCY%]/L*Þ*C `&}s=xUn8ܟ\Gu]`N,UhhxLdž-G:\X5wX *H( C7ksz V\uRRъr{Hb6qh;LGQS?=>zmW)-H]OAƞ,mXှIݔǕ‡ioje[L!83J6Cb4%P -5-pMiUq'/;Ƿq,|D:$IDN)Ra:wmrӶrnGA2gXal嶗ކ!, ^@dpб{O_%*w e``U?l+$$s^#soa[D}Α49)8vo4SbMak>]f}vEVsnz? bmPVXQӯ\$8ͲW5L^ bu[^88MNelJ3W|o'[p+ۊX5=)JC@ "]E"1MͱIoU|kD_ۓzsI(C[ .]zc0~:vL JU &X;|/o7*wUePd.ݾ#kʐ8sc?x8;aoq&\fQ=zݐ}9Ru= t=19vIҭcLxEƎ'W~8P'%X4#|}9dbOB<K&.rI/G'0N\$TQpB\?¨{4(-׾RO|+ ]ƜeVw:Fu0VDl&NjB=]Ehv;2`h.Fԧ8p[E!U{7 n4{.z_'hO?FM\u]OSS0@2RxQ>jOMX,#QǸF? gN&9ѹ8sueUuemmVrfWjW#^endstream endobj 266 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5962 >> stream xY XS=1*M%jVjZkkuY8U0 $$; H3a&PVZmuꤽﶷO]}srk# x<&ąĿ:mʲؘ0ϋQgoBTrfi(eb5@銋jljh;'O;7_"Tc! Sq0j|zD]*?RFZ.šUQXj)P{L\irA_PTymi!0ZBTu^3l|INs~%ҮhX݇w#r9GqRN]uɀV#={1jy? F7h}OǢYzP 2N'lKb5܇PӂX0ZFL_B^h$zރ1E.K|֌\¯.8nℳn?oS'oܶHCtn>иȃA}3.x>+͐OΖ*PR+_\S D\('Rlnm?S@|} 4L z@_ꫮaK3Оڍ|/,z5Y -ਘx*lS*p(VeʳaM+9 fR_BB-5Gp9xh&SRavrF ܶFޏX\?NZqH"7$~'%x7ߑUCIErbr ^?L5dR=#ө%e>:V#S&+/FӁDqE( '\v% Ean <ݥ7v?.\O ŠTzv9Y/l^(d%C-=7OoFzPKL]w\um{!=\j GE/fT {.z iJAdm` eqSofFL, 䛂n=.@DMܢDAtv/*gUCz9!@IP(5Y47g篓T^o)%m?պ[z1F[|V>%<ܾ}qԦT)8^I]:N$"C,Z!Hj\E=D?I~y&  qch㞽FCw~ȂB s C~1}n d%fjZNӟWܼ&S| Seȣ2IqC3X3vF¤:υu|IhCئ@#ϡWpwnYhA9 7ZsXLRaά.-{78?ի@LH]c:,\HKIܶdԟыmhX~6߫9V)761 ی@*吮C1m8TU2V@:]K_oD'ьOHiVG cѸt6;Qvl@|U[;`Õ+rt`le(-a5%=,mAsh&.de)'9' Ku87k aC,4)DvzJt'>[KUSu1@&A]Q߳/vc(+TJ-m\$I r[n_\"('mwO&POY]u_ngv$$H<hscc5UaZUVxlpau@?9PaK+>%9%EnQUTuQAV.Aqhɦu)S1;+şBouToYw;{{@mTnb [8j^PP ZhYid#o=Btݠ3`DmtGZr,~`6Rovώuzqv7Z9߽w0@q@n-W;-ӶSxU".ZNJХaX(bg:~7]1cєɔB8GI<ao{/FS(u1.G-V(>q{{8ꮎʃ{hִ_"["*ū\VC.4l/]u[ʚЩj`>qS36{S7W.϶do>h%RU~"ަRҢ1ҒH!ˆϭDQ3E<1YR9:lmZς**"p: B}7cok7nz3Y{w } X &S݂& UɜZKsH¢mV X.XCCع;4q u Wo֙&)u HD 0rFԤZBKh0z{G}Xʫ- H@[P\Ѱ _z?,{tBll#QQMXGlD>JTfVޥC!85 _ .ĉy24'sHo[қ f0_UpP6Ef]:(!+ ۔^s/kM_%Qξ"6^hRڕ.GI͟2] ΓGQ{uPK'Nmq&5>ڥUuζ+#N- =soU+?oੵ|MͶ=pzAwwLP&v؞jVmtn־zt0sRsRF k8y+.Xl4M]= U`t|Oc-}=m 1c#֚!W*=+|8T]c &c`驓oD q}S^["rv;alГxB*m\Dym?nuZ݂Fxz {8nDi0rov*M~rOUbZ"Rkݳkxhlm ÍB0.^Ơ("55kfDqw-9mݧhHW򽄆Gy._Fy`4塌ą|\%Bg-Z:9{6FEqyRL,*'T&R $FEq*HgMm_Z(r2esMh~tPuHd; L-)h~jY6 o-݇}3mH^h`zFҳ&GEocd\@u{;KVx Nvp=RxbPzl幁 n7v%Wk/,^ޤNKm VKhVbuv'eZ3n)) f`\^tͱNו4#5!݃5=litt\,uu>&Gpz:TQU^(}h~`PTѴq qą>DG\# kbw;+Ekuy .Ni!k5Vkic*Dލehܮ w yp+lxyG(1~\Zf@j$. 7Fq'7TUȋRA^E%`RB}%: qۓ2k];O*iE+M)Iov5$'8/#ЈkhsiZ4{ t访\tXg+3mҴ8I©g.9niaX$4WUWeZ2e*Q: NV} !$\[Ϸ'O^NW~ ttv%:⢳SN:2 ȵ<{Cc}r$І<\b`> 禽/7C$Z^QCmYRL]Ǎ>r~gSq B ƃ]ݫ,q\>*$spnl"1kۺ3Ŝ{;*IN`I /#!iMDS^h#+>!VָV~4)+#oN=`?cX"|~}UMW^l!qb由+ʃT}vC4މƣqut zB~%ߢz tAecR'`cHRS%<.a3Qzn?| f^Eajky eZ/(}g,$6]laNv08'N ~}0tӈ.7VdV} Eendstream endobj 267 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 7501 >> stream xYXWמ̎%6#f{( {]Rw+%O5&|I3Rq;3{﹧{ (=J de;olkg`/ũ8?^O7 Zh6n$lE vk|]݂Lϝ`ldK@Ow'&sl&}}L;9y:4nd[mޟgE0ikZu6[H6v*f-.[]Yxzn77b^|邨deOYrڪﯞ{欽8~@Q-RjZFMQ˩)55Qtj;>AQ;)3jZCͦ쩵j72Ryj>eA-,FjZLYQ%)5CP{)@K9R,52(cJKMGqC!Pj5ZA ޡVQ#jjeGGQQ/(yOAj z&zzߧBa91:T0T>xX=1xu ##%#Z:b45A@t]]%-3gLRYFFGWg;8q5EcszKnW})N?6 7@O0 p{I3'O::铭&LΞ|ZFH WEOhdQAbntFBZ0D(T|PsTIQJHIHEQw-*~KQc~ևt$}W FZ(+a'OS}ХU|[6"wX=4QΌ բB)80t!]I#E o9w %<'֬Ku`L_sPtQ$D P _I'WœUkU0U 55ho[H\Epq~0-$ԐP3Y ?ט>f1*Tx(H沲'/.X!Tx *H9GN@z#f:u+ݞ E׮^UdsatwC!n c>,e\C(Ohx0RyB',6%XcJT/tKVNs,XXf`c3H\# )"b9 $9A3o5"s¶/M;s~ k"< йuB=%rm~RSϞV}* X 1TR!A2 (,^ދaCpE퐲w=aSB;3d{~ŴHgZ*U Es~[}|΍alCBC͌Xg]FP8CXW]_^{pI b*ˋzP ~Rx]]>O` =`bKcP Ԗxxo}1J~R.Y3f+<3GG,OM[`T9V8PAK]?%Tyxc(K,MG:\ИSh:\/ԓrY- %T ^2Q x؀3X~,(#?֏0U"N ό#($ƸGrn'qoð+HVJ[H3[*O%!Pv=]|2?YBuS'6я}0 Ct< /?@jm~ /70Sz^T}Y&)? k=dB𩼆qWi$Ps%oJ• S8#uUnG%[iP ` Ec`(0N,Q` X1BF0"kJA9bꚰNt/<Ё7(/]  [w["bS$2.!*t)bzR*8­LZꊒ{^_ >CIo6-UBJ;aNmӣ 3d|T 2ǟVOmSbCS4mgH&g\)QQHC%Vb*7qGDµIWfrTa-uJ&3D 6$P,Jãx]C='스Ǹ^sCVjd-w_ݾyF@脐N" YWNM|rtKd2^?NՄ?u_ 6$kqc~1Y#H2t?]ȏ?؛daɡ2.x8_> 2%1ʎ*yOʔc1uxD~#jeDU`yyxGB՟!m-w6[wiQ[wC7ƌXIWLSx]AerV+vDsD  T&I .ܴTQX|P{2p=]_eFNέ sZ4+K K(렌m^bwTt\^*/zv|HUf6pǼ7a>8 Foxz,oMBczf(99{UꃢS#S ,>$$(8܇}j)a NN2ȧ.87-=RA'Znւ0`My荱߇0ڞ9Y_П߇aѭ[CE1TCvZ?AH_&vv;,//՚QczMO>xsFߴv,}AԱ,J0Lk( 4J˕D"c?/yȷy"oi`0#1Eyj @ŸKҋO^&aP~0ܒRah!I1'ʀ紈k}@E,:) ,ztʮawt7Ą/K"ɥ{0@ ϔ=(BxJdɒ'ߕQ$Vdsy&$a-:\|謢Z`48ٽOA`Ƣ;{Y4v.1>B<|nsiz߅ i\Sŭsޑn~bOH|5,riQm43⌌,ҳ0աAF/Q- [Y }#>s $FK"}QQQ5\"% C:T_\UR^PJ{#Yvt)[h+lwΗD( ſE$aݘ}ٗ8/;8!8$;ց~ tJt@ >#={vX.|W^>~☌D@X*)/ip4Xvg=_p"YX<ءpթը~?_\`^?7T]] N(CqGb^/砄Ʀx;CX"֒.`6)z3U {Ilt眥L+>;Ձ0?W,>3NtguƭxFsKkmhƉZ̬Nu^<٣+ą(knaY/T)~+6k 8# 6{v E>1iHRO1TQ%ߟndi;_HpnuU%sBI).Z9}&(WEHqzFF&*a$ޞkIgdDg4s+ۭ,'w:a愮 x=ͻ9˥ѿHMS AG,}1pPؒtNZ36>1E1DUT=rm"8g!։2E^ :d<Ik%WWù%jS#)aDomGV:wat={+U=,gc >ON8 Ļݷĭ,&(%PeL.%h%>>:عyGmvlid$PJ8 .)6%ɌC#ʪJ9{>=75e_rm.m[ϝkv|6ZԛEKZwdY]~~/ݾeQYTvL>F@^ QqUh~D\lsZwqf(xJ~Q>s;@$H#dbXExi3`177d3%5 Te+Jh$/v:;A(6<rn1foUTf[.xe;^ӛ"Z<†x^#18u7_n|GK jiR)]o;ElĔiID0IvĬ`֠#, -Q{]W}[v|8M:'$_Ix0֪ۉxݯ`Ljsia.a:tnhRfqV{"bPAO@_Jvco_l1$> stream xZKsF=9J["yc\ǎV$e`` PR}=p'A`==_>roGjdzBRxBGi3h:"Ic3QH0:"m3f&nƊLq]_D9'zg!WYQV47\'M?:QBI~]f7d:.8Z%{]P%^P2h"L&d!Y̯+gMϏBO$) ^tð|]i_ۑR Jw) }=doj^/%4j$e|rwVd=*eWGq9sF&_^/bh[{6V0[˽k}`tCJN=*7`kr9KK1M?0lD \jɌTd۳M'iRRo}'H&dqnZ7 ),$iU, &f3E7.&LA%Z x+ :W{lz㦀}u}r\+1S5Hu&Ф`jƸu ζ I6Ond Ah"g0h) RӹKQPUz5EYҎ\d\.cZÌJ} B'cP&[]~.f6Fhpjȵm ƽ;p#eA{Y&Yang8rh}z( n%܏_krsxPK_'Iwcq\ZNh2 i%{ܧ^Jڶzac n[asJYʎu0Q|f{b<+m AѰmx]~kdlPؕ -N:پ*̻]g9n!'&r*8$˨P~6zw 'иۃzA * m|#Ju7LJFbd6֕3UxeK rö!w7)8"ߢ\R\RLAm7ZLtϡHpgLzv9KRZy]əHʋ^!bhU",.+A@x yְMAҧ6ѾTQL߀[Eafݛ!!8ٍ e>I,\n+BP5pfeR <.B(F>m( XuS僑(* kcԶj.]a +$\%X~<0:*Ye2ǀC2O8]y%g~'bF)$b ":I7ժDQN’o H|o4W _v] 89C&{4%g<C-lRz*g31(K67NQ!wCL,Vh\? ` 5Ka|ƫ2hc/~? ʫ(;Gyr p2\V0]ŭQ;u\-/K+8!="pvaFiEA( DЎ Pȵ$ TpK@vcy;}?!8Í+{CWބ/Yw^x8bYmPVW&v6'RiTv9NS"USll[.m,wƣ:><SP k j@.:Bczk"b$ecQ2TJÂ%Ab yK✀)M3)pA&Ea4{ *љrIAMl ,U@N%ع!n `H ̵A t8 o 9^Hv*uNz"xHze |30cU0,FUGn/JF.!Ž!=* hjvL\=~m2o3ҫw2H1{tfa@ѹ!M޸ d[ˍ9`vyPOzt/ Hyc,es]ҷPvG+7湁!'DEX'HzLRF8>l;&I빿y{5˫H5RtCbbh U½{]Ƃ}ìoڻ{1ÉBБoTendstream endobj 269 0 obj << /Filter /FlateDecode /Length 3652 >> stream xZKs6=趵S塉'VȎ$Wa<#**^g `p$eKqH<n%grjNoÿӝ'7+?]>wW*tbeQʰ[iYZ;e-L԰M_~Ɋ= c&?H `KyɰT쌞$wl6^q`AB˭?k_ [pzä3UO.1#;nM*bݵ8.J.1ɫ@^6iuN 6qbP0g,t-K~h0PRuWdǯóUObˁs>c]6`c^f/ΣD;N7rwMB1!0FT*ol(676Q_^US. xFsFdi%l3@5ee, `_`&4;if8Ha&z6Yml!.&\:Ьa0noz*%9k/vy2/{nj&kM ȴIUH-yl&F@|O<ZK߹V{ ju,xHt6gG4kt.5#v#j# ]d*sJѻw/ǕGa4H*52ġvNQ/nRߺU&H M MK928-JȆrUv7bYd7b?7M8uj΢|k4:K ~D{ENs\f1p_ˀi~`ǎ/ֹ!2f)}hj c -hj ؤD nh&i]D@N|-ؠ2<<Z3$iS^6%6 }.dI؄W!´0S {p$~2ۤ4"xq!zX=,3Bxn@Np~H~+ fL*>89y&e;c`IP ѬS~iҕz2e_Fr68_]|[9sEeC^S/T IH"θr{ܨ;[Jځ|]3OS!P 23c|2ua<&{xPmp"}G6Jp<0 DU5eYu '~ MCArȌS'h!h_+ X۵] zKk `7HGllRgZSk2j\3dLjO.X(EiI дIwNqB|`I]1nԙUUblW*D hY" h>9l\_{ eiqdpJjj@oԂRȲäKj[i4̛lóu'A].:"1ʥ<GX/mzqJApEDVHz|PPT=t}UL^-2$~!ٮhV#QQ+1vJZhe ޺eJeJm ȺIރ1=eF^l`53O!c G[!ɭ2-td3Mg//  )a䔮k05,MmO65 taE5 8X顇Xk4rtU8ȃ3b [G'nlS!(d$40{pUj]Kv#/ȯ9uL'bTq&5KŽ~wKH8| TNvևKl"n#mwU4DłV8_匭ymb{˃.TiF`@rg#ClΗjRbۣPV@goB{$Ԁ ,_I,y~/Me c:ac2-jPZdeֲܲ^Aq̿Ҟ B8a5&'. j7V(`a~( ̠kR6X ϐWfMUЬ7]VjMj)ur4B*JvoU=|L(4c08"?6]ce~6'Ӈ)]}M7zƂrM&/6KkE4Sn+:eP`BE袋@5yVu}VZ>x0kwB?vs9n4.9p=9e|%bG;1O+l0[<=|-}bÕ+Zgg &~ 8^s z8CpN*_<yi3AJ@mG&䜯Yf~YySI5ͯ뱃*.d3@Hǭ˓DSl>#㢢J;HGd`Ms@y!.תJʊ!;Jx!ſbTHcKf׾DžM;o Ke<ePꂃNC+6/K՗ֹ&t%CV>1B ~cҫU]DzSGM=iƪ-U8D!9}i3:ŨL見?#1_Svۯ֚UZQbc@wk8닶Җkzt. o xz{θ*y7Ϟ>]^tКYq۬8==]lBendstream endobj 270 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 7442 >> stream xy|Tն a"HCNHW&݀RZzoLf&32-M.Cr-A zn|d$>f}{o8PP#WzxDFD köO+18рG+D0<ĽNe8^dTRLp`P봩SOL~qݑx;C#bC]Gr]1c2:12uW/-Yu=׽> EQ,X^TK'X#y*Akׅx v괴3f1sǎ`|ޜu(j4CyRc5Zj<@yQʛH-6QQʇZBE-R˨;5ZA͠>fR+YMPNV|)?JL8jH $WWQ j05J=O-QR)7j%qpv;x}`Ud17!|8tÞ6cXí/,|zĂG./1qHf$8; qҸK^xH.Wv~9Qi\͍5ј5c*.k8n8whܷE㧍Fmjj_KphEBy]X_ɗTxH`IHTK8Pie m:ʀ.Z05Z ʡYiL $:E^ œ2's2( " /+:M|qC6d(߇e9l OdXkPSN`A10ho|NwMm{.׌ئ_9.9 yqk1=I-Zd+jNAրT\>y"\-7#0XJA4auP L=q(a: @"]tَ;X xC(Wy 2KARzf|3}T(L\F,q(#b*,Nqs[`%e'WN[\VՑCXD\0^ިC{70:wTv.:PeA8C.@Rj@Ѹr#`1` ~)tH@ <.-lc,- (`5ƺ۪F|WN7|ϯ$ cرT VGM{P`X%b"p~tѾ}\ яUedSo]Dn)ʱ#g/Tr >Z:{Y>"Ϊ!*y="𶙾,b+ `IhUMkm!A~yyV晬GXQ7D0?DlT ayJs;Z[Ld} #_ٲ}n?77d{4.;$#DJhbjJM v Bh]'/*q՞<m4/l!}{wzϮ5\Yױ=}ɂR-|!. 3rFœΖ័&[+`,4U~xQ0;HtUn0rmA4# N yP]aIm#i?snA-NVdAmH)65~H[6\X:4M b8tFYC J489d;ࡀ$7 ps-ɘY aoDkL-.=NHBjzYC$6 RM3#B cnۇ"4o8YO$vBД4ř[lHƗ>nsOE졷SgB%fj=jpɟfoy)o~K>ȰC\r.i)IBnMy~A}Hwu/t]σ>+ \*ڐk~Y"#GNK Ȧ5PQz>.PH?S]AdLW+WW ֢㢣B*<}v*h# u>S} 9L6]3ˡ:\[5{ce"Ct;(LJn\5 `+Rjr:ٕ"B0xsRdXRH:Ӝ- VvDGHl'=kⲤۓ])v޼w:8copjEHDymvfZ!l,fQhh) 0ӐV9]z3#Gxh'6y@ a/4GB|vɒAv|͂DۭN8iF+˳5 YpiCG|<=R$zGY: FRn!_l7>V+U==A#%]4ݬ(ﴱB@A~3'ZV!'? cq6a/Eo &"a ::,$lM):|r<QpgCs,r _"K!HV[AJwZ%E#E:6F`uV QBIg` _\6mڊƸҘY,"(-(6U' {ݳKzw+&~SC=cwPdB2rD :B'琞&4dUp@pl4E!㜮X"OShUh&m7a$KpCk.Ti=&Eَu %ҟ^Y YHoxQ=q$FٖfekyOM3{)ʦ< =\]r | z|/p(4)" ܏ieqYhHCs&HpDmAŸz%8gb2>mRtF|Hi@>Q>C|4 yZ !,O!{?a}ºp4Ҫc*8Wp⣚m7:)^-27^6XK[hEsfw ÕY[f(6ph$4 6&o0f@DhX?qn\ EePWjj۶҂4[G&.y?G7!$kJ8݂V ?o.KjAo ڏ4韠eb>ANI'N%g[SL@řL=ۛWh[{ffN`MZmm3"[G bccRu$Et|V:<'l5*lAs#(E縕/(vv;~e@A79;LwՈ]H#L:KX5H s>1U r}<.c/3[;ϤEFசn5,'/}i}y >MVDLgX&ې]cBT &9+"ݟa?qЅ'*t]Q:XDOx'.o7ޓ-swC.6yk(~HO~ũg7]I7>[a4f4='腌DJ~o['=7qV4̞qPajL{CjY%.5Dls$fԃSR$<+R{E"_"\ݼe;Qfަ 5^~rީDϠ{䵧qTA }XEjzt=|7Y? A/ӧ]hqf=j6#5g$bö]BC"fC$IB{Rhׯ6[%2=]r~I $Wi\Ⳍ{O/tLN5ARB3NAh3M>~҂<@H;mҪou6OC U9oI =ۤ\̻ruv&;q..yDhUs}B[z!kM+9)Jz1R!gsj|K/9bD?zW_hUV?2UP%}0|ɲbc}]&Q`}8w/+0 u|ʜYzyˌBmQfNG'[N [S˗xq&gԚ4Нg@ĊSslvfc}NW#smi0ArO2DWdzE TDᙜrg~޸U[tYx)PZ{e\ޜ{Xr36)[r$t JL|岐``:\ ԮJu?ټ{oyƚUWNVtl%=62͘Tuh֠လ}'֗JSS3U)i$yŒ`ԐxM60W9dbȇE TNrPn'I¿Bu.<%s*@%&X%'}ߜ<]$Br-B3LI”ȣd]Q("H Z8FQOPZ,h&2lV\`AoEk9w+Z-~:WpV&S^~[3pW͛"/.$=DW(mB };yqtH0yqT6HmE Vs f;+f@02`h]h?݆+O0PDhdAyn:S=sގmgp/*h&cn4{W>$],,9fk4H~83>![T#î hזu8-wuI#;tφ^DƈФ~u^G0:̘N䪽䄲/m|YN\ig@cS,KN4&AZ\?.G.F̣4SI4rRqg9 O{g}bJ|43ڊԶe.ONw]<so竏&*2R3c)]&0!$_h)_ B^ Ђcml^C!{JS> stream xVyTSW~!TD5C^qjNXuDhPEM4dKK aqHྠV[:mZǩi{:k\87Ȼ~>5ćD+VIIQ+cT3gO(cҼ^EXbsc^GmcP(=Dsf%%nM8cƬ +ߒ%_4]<&v{JIU|a)$|Ke<%A^_&\l*( V,Lۑ Sl\|֤y(jZM=OBSLPikj) SJ* FRb!T)EyO\$ǐCqR:ah*3ð7Q{m2E1z$Y*/׷!q<r+-SUJ=Fgd|> !p:'C*p٨B54>=S$J~Sh& A5q(|m'+Qվ@r2*+?Hn3vGi!8<\!1 w(ZdWXdO0j H(CۤN><C(`革hӉXf]K,R6'GE6@4:w:Zy^YqsigN#].!2yDHrOJsy>j w.AӨ4:6^$f Lɸ{wuBK\  PX"Xl9=*$cQ 9;V? 2-  t$Ht=^ͤk"TF l =XP#6xC4#cC'a+$D|N#GJ1fTto/Ѥ)Ы )r]TۚD&5uYxm:I0=#8TXobWT-Um@>P8Ӡdv|KJ!`@.`? ) mNٯiP]sn,.^*0s 3.SY!䃩Ę21TRVB~v::b…\rҺ+؃Vd?^rq`ԇFK+.Hh( 8!>Dp'C&wIF 7fQ_w U]az^S/J$?v^Vu:}1⁋8/gN+3쇳 v# 1푡3fI]CzNz?22@Iy)m$lTxiK-naX<ѢOd}KS_͝wN5t^Ν)#$xEn{R4@U7``8zp0N=pKuK?gS}<(u6(;föNUǶ΍{߀`6T\] ଵ[eNAw\.aqqY27/)i]f*8u.5Ɯt;wdn)jRT`$lmx-4FS6r?̲^B(~8ո.6/]&KziQiNAaQ ~΢k~]42|X,+*/- (42Y DD=:P/XAXF~\F(Rk#hv{,TeS#64_ޓİޯZڹ ;8|0Ggg: 13R=AoP| ޿iu|W^r"V+I?9 p[2v!BR1TͰ](^}0PCx6eφRccjh=AV-z/+:cgB!lM9U=vog'3?;t:Ww0'Ņ]Mn{PK西]=a===#J%u([Z5~'*O^)AzJ&D m9ms8K;O=$ߐoH3<1p=J*WTb&1o8~SʾITIYHz!WH0eWF@Z]]<.uő\v=>S̷Akic we! R iT ZP,䰰 ^F :7 !),:FrkB!4ق\NC֐ΰ&]}1opĻ8plj]^mmeDKZ~2r@ؖg{6Rh07;vh@u,j#l̇H0K0ٵD҅fc?٧B: OȇGͷǷ8,iD|#4KG.9`@^_#!IG J,VO,^q;͟/9i9iJo]q ~Rkcf TCҫjw45Yd%xaRPK6UWVHO5 v=]m,љL`(-P _p%,A* !}l1[, ׽y|GR4endstream endobj 272 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1153 >> stream xULgk ЦNOpnιbz (J[bݨ\RdLS ]\kDMe4YHs޺\^o|p$D8xg~iȳ*9Zh88cx C"f\25ץ3}T]ڳagM~7N+['8z)Q! e .0:ʡWC ]p\Hr?H-'K8˛1c-=620=sT)5z>N3HХ[rsUK(ݺGO æܸ5[fc1B,ty pWfKkX=FxE)bjЧ:7FuCveLu5uA+imC-m %1C&t=ͦ`Wߴ gz;>FM4Rj|T@ѯF8+[~:Sbendstream endobj 273 0 obj << /Filter /FlateDecode /Length 375 >> stream x]N0D|E 4 @8((̄K/]G{{XK}x\i^ƭ|\꡼KqΗ_ҙ?:=ZjPrxicԧfo|}.[B:MS2+qCMiW;ƒoj!QoSlQB8fbIR-{c"$Ę$`$N xCM' qgԽ8S,p$N;N6TLUcպ$|C4p=I@044 M&& M&& M&& SLYrw=Gl9bsE '\.umeh3y\y)˻WvPCN?endstream endobj 274 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4986 >> stream xXgxTe>CHBWem늫귋˵~$p}^?2?f9s~ã&Nx<}7lHd$R/Z%-8'0ӣx'96'Fԉ'L }2@;)۞[.pY(#SEO,X@>DEX69%;_Z-NK^pR(zN~^޴ibj˦m1s|?6%SS\$M.Q5ټω WY+]W*KIKfe.ei(jEmfS[Xj.5zS;9jZMRQ멍 O4<3³R!xR o]S".OL}-JutҲIL2sf꼩eLh7|}ř_Uwחw?y{OuOUCRhZ=߫psHc=@XNq=A$NaR:i6z.~ZVb)rA3^W3%De) AEn礕**Xa? fԳx, @DN~BrJ -пF.D.Y|8pzF*+62uCh_3rq:Iyo.*Y2 1}@{Y%R݌˹ BY@]u;wD:F}!wzֆ|OV-1)@IT*5~%਩ =fjh{8Hf aܮ ({?PY4w ,M&^<7@B'\x/< 3jsڠ'|W, T&(^1.k3%:}Pǒ}$A4@0؂rpeyޯ뾹 W\S|-4L7AkZr08N#P5IǯehzMFdG'~?OgQk!G}7s'3J0ά2sfp,Pm=Zp\'?ƶГW"Br˿;3RՉ= cDRd"&?j4 4xQBJ5vL =i[p}Cf֟זЈF3ѣ,E'fFfPJz)3&& !K#oۤ;ZG?&yc(*nךL>@3(_UǢP*  R'O@ȟ=:,]ԗaAؗD?v=xEXjɻ;-ALh89ʔ2Dju69d2`=̆7 4*Mk ¬B7}\8lQV*cvvīb;+pi/ϡ<%k~/_|Z__het:am]^v)rtZꋋ@L{KI?’39׉zHAVCiz>:,vA} lq(c=[#5ʟ!#'߄9>u)}Vϕ֟CWlm` BBQ^Bt ]]jŠ_/ A-@L)Sb1 .D: t |,pXh+jR=j?pOΩP>VgEs[4OCG FuVMF [k:,.hi􀱙mTΨ5j7EVm1yʏ[MDh*6 __EBn$^s=btU,*+,:*Őxq\f&Yn; :N9;mv-=V+2Tpڝ8V+e #m4%q9@/5]#hp>՟0?VRmgZ?]m.Tk$"d.xG"Be|[,R*ԌQ1ȤjCŞ׀0^yp͹6oQ;~ʨHW dR6aI?~>@OM[#߮HHvVﶖ T>C,$Y`SIvL?wPdQF^ 6x05";CFY>@c#sX}LF4AE{ƬG(i{xsT5 ZNdPeB-UԵ1G%{i_ :O]j翽*o7צp|{CHTz_&>Jc&MG]BͷLQ P@_>  ޸n棈P<LU00̖(|'ƿs6ʙ#GlZ4aB9O]+(Ζ~f^ygiOı:TX"ˑIQq|Xɭ/ }1T7LV<3g\Q}4d(Te?A!4Nӯ =>1gW:z=2$+4F11)M UG-ZIoLPRwWWv'Ehq`ug!miWHD`x[U{ȁ?ɯ JeMfD>kc7qϲi2aXKQ-1Xx7,(wd%Ev&-;GЪ˨rDEkxZA[{ 21*l1'P~T$T`lo^ B|7Ӗz._}/Y0w;MĆmfhLL Cఛsԁ͗*O( I*Btgկyk:Sw>"0H+ɕ[[[Zd ^ҧ{wr .\b>{@!yzᯚUa7N,tnd I<Rhfm5D<']]MG803d1&rTPm4"4V2ԔCKUn rXZ0p*1);ZLA)ғ0FglگY!Ɔtz 텰֕I;v U~|M.iUIjݝ.3tV0x d%cEO?B@[EMyyEEyyMEMM')%C+k?jzZY^ mCʳV%7zc&ى7g􉋖pGQvgm̞6+c2 ͷ8$Wk06>.6 ]5}^~1,AE%|~%ȝFVJ]в 6$ZB[3gBrepL - F$3b@j0^j֕fnb$Z}m4)x_xChPU.*,/xXo#5xVYiZeؕ4Kzx{eXV tO$u-4yWNe#UΡs8NA2Kms;}?t"G0}4w:-i9F/9NSf{Mn@m(ɰt1;ǞaA+-y4}uzd5W x)%٭r]8ւ#o#+)6[EEp\I+<`h ߣ R)Myiz+EgS@v<>@w=|!d .Oyiha 9Ȣ Q>aV|vJScIJH{ ;Hl]krr?#IN0DY)5v4͘ˇJF%u875 vCټǒJ "IJ7k ْdN^rnXޮ.N0U)HM>R W 0oeȀ| ו6?Rd3*mh,7')ɥdt6ƨ5(3^>7tyS铠a@zLzznk *.I s5:#s=b"<^G0'nݚ4uL4[V:`2Ol!c LFQ RZendstream endobj 275 0 obj << /Filter /FlateDecode /Length 260 >> stream x]n0 WڒtUendstream endobj 276 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1982 >> stream x}}Pgw ULIk7isE-j*Zڊb b"!"flC"d֦RӫVՙ^k?g[7gyfy%4$ EEc}F{yAnIЎi?!Yi"ޑ)$AV3?OӈLܢ6B}GV`6.X(7W+5䅊nw\+'ߨ1uZ^Uv5;o)%%׋,T2{0iFXQT ]BƝTiT&Uc]XU*Z&J)L+Ս*N7~ߠ4(J [lP;wդeJ| y%VZxN $nCzI3ur;O+Ls5=I}'z_3SH'ɳ_4Q*Ivsv:k܋Vgʙ3N^CQzuŮV;Aƭ0WP,/nE/fTuk:yܧ@K8~gRLt1 :p&1G` p;up.2[ !UJg B]IQJ__إ3oomAEߵ:z;.:\=>(4ӌ; 69Nth.2v.+\C]r\yW"ߡYIڈQ1ܠ-exV 0&+Øz!]N`XilGʱDVz=/0i-Zct2^f];,V)o*F`]Dž? '{nAoܤ@}ڬmatFp:uaKK*%uUJ|n?i :i>redjhR.aK=H3`3ԝy@EhJRzH^F z h62Lм?1|:û<pd{;ևveejpB-z(X;}} άWACar-4FcX顑5;8 \@D/! KoCH"҈-digYB{UX"NO;HVcC6&6#mШbኰ4/X<7I `GM`0@Lz`lHkX$b g,hdX|,ǺVkF.e3v{loRvMV5`RN-[S>ǹ}=({:ƍ5hY??O^q(""<u๸8CE(E4 \Xϝu ނ[ K)ǂ$%Wzc~ZDxG289X/)ȯ]?1){~v챱6ڤ-y(>JG҅tңIt&Baj"a:xg|cFOS+Ϗ WQ -~,b8=/$j -y1 D;fh/rg}t9 =zǭq$0!?F8%?> stream xV TWP(+lNugI$1#QL$DYUffm_w" tC(@D₉zBIt$$%d Ms9uN_u޻ s3B X%':-\24 qfLJ,JVsFP 00bWʒ)1ۤ.\`wnVHoSbW=bt,Q92&<>J*En+]wh76:! DYJNť.||Ax _$+N)Pn-zAAb6:hmBcFKƖ½ZIk@U"Iԯ%Ʀ@(I)]Iy̡rR?S ^vϭ ٸs1\13&4߬9 jRA֎푛[L]Z$N.N$CђbJ/ɴ9mͫAmF-I՘ĘPC6Ig3 ZMmLyAq&#LZm5Uڃ}?k[ɄJҐO͞b;Y  ASn5Z1 %Vr n]!-PX7c\ZM+QOBDzrn 8g*ԏwa/Q4̫̳m:%KNn w\ mk!n)yrVubE+Щ~th&{uG)U,UZH{"fd!E<[=wEKL~1hL@^YBe/yb?VbH%9hDO5)w5 >B.Һ O/g>kVvS}0. {Is-N$lUh5*ר4TC=sPt{|8j1"^eZԜ:iCfCd3-Y[[NmD_f9T;͠1E :ЌהKUʒPCZQK˃lϔwز{Scp.J`yFD%]s$IjXVS尷ܜaܚ Pz% sD~{wpO4]1Z]Cndl >ka45Q6əf1*C37-ߜe۳HKliK ~8ii ^`$*"&/tܹVwSU [^MJJ>H6+4~oD."~:2v<۩QR0k<4 mOumŪ%]E滠?}Hr:j >æv_Ny9SVUVJ*/(۩cblOxUc&bxD䂖9yMw72Ur4JЋ9bM6 I01io#A= ݸ 7@JT9L|%zKDž3]F=7#w4ͪ*,/b v8zf6B> stream x]mLSgǟ f{W{#nsYK ~cnt8!qV&)R r,lx-}Z] &Fhf3nds&ae$';/IA=ePh6eDxZ v (%YMO=k j|둶+jW{++vxW{S#gny]XY]f#ojf [8S~N0|zBx+/ D*D'H{2a K!{(MeG%^ n|U z..$dQoi|CY]g/_ޑO1yջQ5TATA#9W{7+GG3Ѝ@ԣ.Y UdyneG|[<j#tS}a?{TʻVqutDxW>WOXN8o.6[,BnJuxG8 !Aa#ǃd,{!ɖxE(r8v|Nzа"?/endstream endobj 279 0 obj << /Filter /FlateDecode /Length 233 >> stream x]n1D{|#DQkt>)RJϞ폇cW}%j\Rrmħ~its{lapm,%-s˙ oƔMO*0[RT 8 8;ajjN&A&#"ѨFI5W|Tjkk\VSץʖBxendstream endobj 280 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2138 >> stream xUip^YF,@Z!U!I!4GiBm O`[%˲u!ZݕuZ-a `a IPΖr6i3&~2넮f`Iooy}x22 iuUɪji̗xS?=WO΂4>~~{]T|x9eu U O_}+jqq͕-Ғ}&*TeeJq[/Պ*bYxgnoIv7Jvm߱l"aߨoشek}5kbb, $l{ۂmŶalGKŢä !_---\muw{^246fok9#ɢP u<ߐ&'lQ5V"E~7pyή;B1G(xxı t)wJY*3p1ّ!q/oG2ohPkkj M`x OQ7PO L?x[!7X6#ɦNgٌ% A8}my(7'!~P 8ҩׄ`Ur]El,z pTt@m)RkHa?D:I~IDkT\kX@#9_o9\A9tB5B*d\"OGfzTo\2{^$W%2vɦ86?AkQP@ i=G7k8:`%m.+!/.KoZ9{;(aKy85rj{dv$“ރx8o72Ӭfֹ ut+ ܢgv#51Bʞ:Bd;?x|i;K'kj)!WLdn4m6z(^9k[6G(e Θ_r#b(/*sVB_zs?@$%W;y!=M$3GGCǰy\̋C%4([\Ugx<=X 7+5l&b˷K٪> stream x]; D{N U¢q$XEn]S1bg~n<{E`:`]0YNJkSҳIxLw9CtUZ4^*M<1I/BD@ HIԉjHD[BV" i'9ن=p[AHլߚ)Q {i6endstream endobj 282 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1722 >> stream xT{lSv컐#a6PAK`%ZBSpZ48qNB{H'&*)j6Dc[B" * ƹ!9(?t{|=߹O>>¥īWWRROHI(MOx%*ws'cKҭIetpfV~R5VC/M?q~_C12٘VglcGx:v\J\rRЎxɳ 9] ꟿM]V W,KdAVK]җn:G.Iq !h]׏nN)MQ&v@ 4Igf~$7^zK-tڝ<6UF.-Da>Z` vZJU8 ~A!(B}^=ۙ GJj-@AN /tSZscE'Cr^G~Nuum l47GW&tkwGy+]ש>C [jwǺ~-HoHh#y׬7w:Z ; '6=s .L1s@#9VԫCJ|8 ~?L+7rP3^?zq f!yVE79u {L)mOuj(:_9Fq*0Zzv a?>D$Zq0nby|)tM3C*4.p ۃoNBȿ t <\܅̌lBK~M {cJsPV 4l93@Ɉ5/Y: gU kڋc|5:}6TJ8- Y!(tS:&ըkA0gac u( /-n N~6YÎJt5bo8A0ڠYoȗ#N1*߷6fx0q4/bYjΈ2)Ϊ _Քij>oEik@B1f+H Oy:3|B=,ր些]L z+<)xTRm"mP9GAl 5 #ɸNFFv'00צ9P)R9OgZkCTȠ7)Х";ه5u]1NI_RC( AVdwld c *Siw i?ȹ@;~H&=q!$endstream endobj 283 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 420 >> stream xcd`ab`ddM,M)6 JM/I,If!C<<,~ }/=[1<9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5 U4$(8;(2Luo:cwCu';!]'uϗ\X1^諾3X̨mn[ɝ=-ݒuef_Z].Y:~Ƥޞ徫> stream x] w7R.@(|{Xcx>MܢWHX#~ uqJZd@d|U.@]OkEkXT 鿧LY9"#Mt:䢉ꊝ*ڻ%/V[RMYS孃GJBo`6endstream endobj 285 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 649 >> stream xmOQ@PFFq:6BdG Ƙ ܙiCqv 4i(C}C۱ت q w,;o4s8I.-!86>gx~o Lؐ 4-z= h+2ap,^N/=xYO_Mz&L8Qfv[ yisz1q{4禟SNcgpLwy]1D]]]^Y*& 4CA&(l ĵ<UQ܉nl>,"w_moA~CR_fW_p#(TrRUo: "d]ecNO#s{--es)9ʦN3]%R3$,@endstream endobj 286 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1804 >> stream xU Pw$]íۤNBcވ]Ui!1qb|W4 ʣ"-ŞNGsRk;pw7 scvwvf1ɕ7Ud:k2\郧 D/*AP7&25az]vfVt]pk{4U/ Fr4y9R:]$r4U%WeH5xiBܶ8طv7g <銌̬lU.bqXb`۰,"h,ܰr쟼HPP(vKv~S",7!~gHzS|&i|g Kq w{` Y1h5r*aNJ]pP K1%@lFԝ%?}0V" C~y8R"SP5]QįL- L& >vFVe$qPREq%c=bE"$#J2m (溈,&8uMs E3ܕ/N1X!dg83qqTlD?Ϳ: Azޙ[MfvKLn*gQ{'،Uj'+w૬7+F*K@Kl IZ+bou1*iy8aaƏYT$w%nY X]wM$Y/䎓/7:}ܸd}~!RS[HD}!y]O̎}<5zڱ=?5"=t0aHsH|p׈%G0k|*9LvSCln-ư`endstream endobj 287 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1054 >> stream xukhU߷ZbۨLFEhUimzْ4m\skK4iTlZVE/E2A& Ɣp7Tp?P4MOWV䯇2茸 ٮl(@Cp1n n|xtP_OVvR.*˪ʡNyYB۫T+Sj #j/t2ZS?RO+kPjC#.Y]yB7WvCE kO64Saz?(g.gˀßsxrp's [lM`IqR6Y%v㐔l1b9gW7}aۃ_P^k9vpoH yy^1ayIWaHdaGA&$ 8 Nf?ٵic#d׬.’]s!{vohVm3m7ԭϟދ}"+h|6 [ EM?_L`?M[q%'ϕOt!os&|u_?e^)!]XrK3 x))`Y[bvb1au̓giSuaE pZ0o}d:vW/-f `NQWR(Z,z a R$endstream endobj 288 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 392 >> stream xcd`ab`ddM,,IL6 JM/I,hf!Cw:=<<<,*={3#cxNs~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+kau c7##K5|Ob5^3N t>E9e+,]d\3St87o3{gN[qC+'uvup5}Y '䖦r;<+p:ml6pqpvp5gj~ L7x2endstream endobj 289 0 obj << /Filter /FlateDecode /Length 162 >> stream x]O1 yiNQtЪj&bA }$3H6^XW0l5'V:V7 h.ܖUӸz0HuB1=CR L:/ə!D?%biZw> }-tS+endstream endobj 290 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 311 >> stream xcd`ab`dd74 JM/I, f!C?XyyX|_(=F{$0F ʢ#c]] iTध_^竧_TSHJHISOSIP v Vp Cw^XWRl} ߏ?˾K3<[{ukvwwuwvUu4TwWwmYp?MbF̦g,%0-ýq0"ϺzL=f*/RwBendstream endobj 291 0 obj << /Filter /FlateDecode /Length 6585 >> stream x]ݏ$GRGBayx^̵lɖ@g8qAܱF3;׋뉈̬ٝC=UY^\ _ˇgݳ zzgI _=+TtrAg/W0hj=1A{߽Yv[Mov7rb']?+ZB Oߏ yK}W6~H@f腷?'X5HgY]~Z\齵Ew|a];uڪ.U'3 8~/bt\E`p)ensӜF.;Թn0EKد7F^ z sU:n3M{ [vFdC $`ѷ;i K>!Q#g6׋aG8%{Hiz-\6Z5nF +AH-CnsMU &Hi 4j:x_lt[d,F^K>l%65kZ۟4`m9;77 ^6Ih~\=pDVޟOC"yOs=%"2c{1Б*NG|+=;}< VZ+xS ?kx!{Lsг-5D(eHte[^QgLE~ ݠ84p#=L_C@cOmKr'CG {Oȵ&% y ps_ 6!)"J8 *]&~{^b$ #Z򳔞-Ɓم_G{#yI|6Q$MҀ^1=2Q룲[% Ĺ%xg q SIؑC -%Tt:J?JS߮M@&q0ޤVSITciI9q"g؏+,G`׵pĚhsm5%(!=bPG5ˣ/T—oZ@ڠVԠA57f-T+HG֍L5B$ QgAs4qlK0! ]Zu~@lH gڸ>ԋAHdފ}Mk z:ɸO`@H=*O"FOܲ H?}`[ٙfAv{pZӨv-PQp"y&wZe8H [z-wl=- {R.՝-€ .PJn?Q>S+K~b^aGsSclMF{NZbKS#[h:0la k)jDRN%2 =8@i УBFyxiHsSp" G|/EE8.Z!]f8541Zs42a? "Լ |OZ'[_7 3傺n_'GI/,,L8L@ ^J* AR /`T?.Z;4EV + ʉ7gj|-4ԫ5\l:ք"ԕjTv\! .Kl8pSĻgfp9%o# ?ҁJE?.:S;/66^$(O:QQ+p4-̉νyS?t٤ za|c (6 4ZI!y1mHC})[ ~.D( IЙ aJq&Q2BQ׺; `P?o:keL6њ[D,iwMYExnybٷU$Mk_uyZ9, %N!v95^Kǜ5߶^ Kp`"هc U\2o0 vh^$ L,.'U[MM(acS }66ڭk]<󂇍||3ԓ&T1gat#Onb#[¬U3E ،!-1*WĴՙT8db[*2zQd%>Y:gu~A&3`q-{9I̥܉M=cYDc3F3Uq#B*U3T9ˑ*c9\t&ybѲe۴sd7џP&n IpZR"Gj xrǟbMnr[ [W%"N1t- ՀG $09%~4*QJWo @U%h@Db=JAM7r1ܔ{A`!2% PVmFA߁蛧Q7(b跞KZ kk#dnف`o{s$ ͸O{$.rJnGoҫU}NxȷO늎\7|S8⇔e'mM 9!!h5$eojF5UNZ6NP2BL6̇{[AWJZOK.Ej^1*ҝ ŒKK[N5>ZZF\.z~t@T*.9#'m$PdªtCW=>Z!||>U=RT_1-@ފX]߮ v]mJ1Ԃ b 2 ,]Â] =2.Ll6slWa)5Lm)SO:40P1,R'S`*`n=>]V0ĞSǸx/uSqkkIs+rqĥ8YM32w/W'2aGAQsS5Ɔ7i_{)I]lڻLyD\Z>o.Lq۫ő\]mx*H*:“hWhEs==Pz VKZao#sn\]fkյV"YĤ-n/d&ֈ"cz;qҁ!I6v˦5ΆnaMZhқYG ;~BEЦ[ cD鞪 Ч~\U)ΦVe|j|u-x&|^q/{0a( j܇6yfC-T2/ bU,,cRLEQu*X6hmc_xn{kL+ކI` N*Y cߴѿg1] ,ݟrrhPXj1nErQ쥟(gH* E+R~9`eo3o47[F KuiKz{X4?Kb>w m)Oky~N h 0QyGa˭a_;)Fԯ6jendstream endobj 292 0 obj << /Filter /FlateDecode /Length 4299 >> stream x[K$>|(etMw ]F tFczRjUhf|o߈ I2Y=lL& /X?lm:/ܝp&~Y1xҺα3 X1ʴNYXc/oΚx{tZa͛NJvh:: [#4 |!Ԫ۝o_ :׼+:eն9f\/nü9Zq?ck6P8~h펓bE|?ŬHSeֱR;g`x˘Vx#Zt`_aiSpxY?;Qh0\;&_CwnZCVL|1(@1Uo8OGKfưhfae|Z*DMہf!nhsChd>ƔYb֫-Z'n>)Ysِٟ|TPFpv8 LV:w\n[ 4 %&o~Uπ٥t ` @,ġm^F^4ݢދ \k8q w0Хi.w' B ~{`⭃I5Q,%9!=ζw*qAJLs} pb!Z"aҚ"NUvca3,/TI*tY~HoD8ě]2pn k9;arQ`v %`5Nco?fKeѴ̋RzP?`"qi >$gn-)2HӇ9 ͋%3d:eɝ u?!#I2|P2=a1d3H2djѐs+\$G2>0S 4H~#+zI#hk+kf S4SK@NMO2C+5a5rc).;CX|ON WLe*թɈ!aQYpkV<ܤh9{QچO2۠D@+ OBYSPk2 1q o;4H>9;a?Nh0%ӡ}\ ߹"sR~{pHQM"up OAE_J.e SBz(_Np.U+ St UŘ{ur`GV ⒀2t W ˥'gO{]ߞ` 8`\@z \3bWyg!]%r2.@O$y2RQ0]+Y Q2@-Jj;Ŀ]QgX0 'vƌT? ,gDBy4YRaLB΋.Em8qQwʒ'sN?"D٤t;R23w\ 'J*3[cQNpA9U!3܆/ p|NVЀFEW$wV?$]з ZKeB9URCsCl*˕?KB0`DA=B9$q +|T]efрʭ 3C7EYpzhje*͘uz< 8W} :]T9bz&nLy}=Ġ)y闘D{5`9os)x4%X"nA0YXaiKna=cA59rD>Bg /-|LcSڨ/Quֆs%nqCہIe- ʀR B[d^nh6h*V1$i)y8͹ CʦOʤfd݋t+xY&q ʅ2JC p}ucTE9Sեo:@"h )V\֗yf V=q i9뼶>eUi:)e4|&@X9[EnO U WYe6R!<\C)S WÁ)4_.*ΝX@4 $Plt& Ct^ԑe[~zv=S#$zpinN5bCOf:4BՉL4Zg| "[HQ,0y? _E 1!3Asm¶B/Z&!پ)Ph$TV$)ՆRl(^O & ?mC?yWrj{dOc 2UI~%]KV׮9$>l9{0:U()xUf/5-A4[}O} " vXx_Fu簻Om"y˻WWm/>k>Edx0y/("8k:\z ۪׈tA⤈A5HW8,c@~ |X?ND7fUn߁/=y(B{QbZ-A}EV狲} +3u}y U?$M<$]ޔ\~:Z]"L#`{VѤ_ʩ2.4`}> stream x\ݓqV7WZ?0%N!ե"_;I>l Zx.%reICrU҃%ݘ ϯNN=__9ӳ'~նR]t~ًfsq|pƆaORgLv߮gg ߽+2&-g[fs)ex=t1ǝqݦ?rp2ݝ͜Uvgߏ6\ӹԽ3<t=I/RVe[|)V"Rvid4ozm<2 [hV9 l02-do{avuϺ@\>{Ll8iȳL`Nu4w%T-K4/bևM9H"ݣ.n?Y" }ИRY 2O{W :]w*Ҥ;wP) =^А/RU 5Yop0/ޭ&2_MK\)U{̴C$(S%K`+m}aU _nO ,), .^j^JSVٽ} \Xu) lf߂(̾͝ RǻJ%* !CY֊zPm KeIdB@ qp' E2o{mǗk{~A~MYΎsvOс5tk2nvzlhw?fƝpb-6W6k{3ʌ8wz_v?.WŦaѠ  -?Y_sݜ*eys=yPDW*$I4[^Wp$="ؒzǁ>÷jf&']k~PݛenfIarYP=GU-ƥA0EzӌĝB(ay`ۛyq<?}yc֛RWq;DJӡŠ([2K[Ly QA<,uisRzbxq!/^FCL_a &TpoN~"o}m9!>5U+(xF!9Y)ﺫŇ*gZA2p4׫ *W\'p/`B?ȌumGF?’(pA 9pty4H AHXj?)`6"=IBb@0Ϛ0r?@ya ѱ!Y" *ZMFak;!ȻJ(\E^^In( &drȴ7Q%#f&еepqƜ iXׅUhbQ(%ڛ@ɁsZ I$K UHC -(Dpʦi0s4 ;6#yKRzo!v)͒3N'{!!AW,fIw7.%siȟ['*ߴC\܇*&锽Mx.< %8X[S`s8@\R|D 5%u|^y(U]uBh0w i6-ŖHw=)眱ļ = =YL F)|J˫s}) P7C]oZiJ1Wv O^L|f9. d`a A_3qYrO7*paN[Q:tMn6i.'R.ϯ([YXC0#oI0->JRܑ:B̐}1+[ "*͍C*t BCfѮA?Cp<;B@wAij69D-_ Yx<"]ǿH" C*e a4tЊdƯH.H1WV[bfyR"ri o h/vuxΛnMtyx})7Ⱥ(pǩ-@&b*zyLq0u[m.Cb͘@X2v "Y\ P|m"d.OdYL? [ kΔ.($Q !t NǤ删(j aud@͏x)C=EKōd (Rmᡃ<>劽m54a>c?1]:xzl\ҫ%0 OG˫Ք{D/𑘪~Lp8 pAI|U>'S׺, {}A{>InK<RH^Gk0U l*Ͳy!Ц*k$\}+V|4Hy0Jq6 H1ua:oX TeԷZ hWuT}]n6BMϜje \Tn0}*Ըk+XCPnq?j:W |䷄ ðBN\۪hp/EUHBsj2G3 Bg#ѺlCD g)߭ȑAAHr? 4Aka <¸+US.4]SKdj %X7Zu#:D8|PN$ }!M N{;ŒJ0 w%!c$5eјVWJVtQf;kܥab &dO-^h[kvw#3*T?6 92;R;C2܈A/Ñ\8-,d.b0NX;òoC0Qim;;lvT.M'Qԡ?ΝE09n"vˀU[ne.f,|=kHāJѦ,Yk, IE\"}tǶJh)BڝexnF!Ea轩cYbL0uJu Q%) d`f lci ".+g3aqƄixoZW UVrvҦW!uRza"zc ;i"z;nSٽU ߅[~[n@_`>ym&CoXr?ĩ~cfCШڏ|~cEG,WG~PYg@8MfYw{8xt.@RaVkGMςć }= שּa7 Pf#|?a^Uo/V]*abyM*DDBa9FyHFJbqs>wt́ ƦC먣B؝Aᬞs7eh5'pVyx`']ˤ8nE+Mr  Vu3]Պ?!zM ULC0It&Nv%[mȜ_9AlqhȃUuk pbWU\'4v#NbMCt&Y "m1w=,kjKG{xL4#ePV'UgJOf>ALҶhb%J˟@`6‚f:< w[N t_# Nv7w `-@qUԨg,dZ>6KH5{5B;OY'4$՞| CQq1.\9NRL7[g^}\HeC/ՀhUW[=pc6Cw[ζ8ȥAf6t7vh@D0H?h2|ϑ h+ x}⿫To1 !?ݣw_MB]cdџMu{[tȈ9H7?TlCh]1vv").~ex3X[pMKLuWjNdUJI8ahޔ0̲ 0l`~xQ9F=ٓz!y00C(-֓iqk9[`^L]M wPsIAi|$r(&{m[ .Ck߰SU6 Z+y bEl#'nu^vרy7&BXÛ-Fi5|/<Y,M/FUy= nM #Tm v &@j&J7 ԙ6Mj&L jL(\8JIZ'( .ON3S֡yw݅c· ېU\j('t #_مsr'Cn?-&*b(Ml_$Z~L;k6;gFW' v KfvJu/>ƺ]YRg#QJ39U)."B(Y6FH5yY3~@'RV]LwN pQ [j;QB AG\-n6d%{hgmf g*{wqzt^%dwH֯(;}`]="tL?o9ɓ {= 8w }k%Եџoa?yJp_~di vj#Ep:6~Tӡ_{A11By/gc ĸgXoU+ȡB~lnYK؁m@xzc_X4򼅣yW[9lD0[IALLzeᣥȘB \Lm][ r|9P8\.;AtFsD6Q]03-SkÊ]//q~HNh8c%?Vpw)EGNm]oo&;̝xH2|ko440`⺻AW5amYc$V't{R!3<$.%d endstream endobj 294 0 obj << /Filter /FlateDecode /Length 4708 >> stream x[Yq~;Աlu+:w=H=3db`!5/zpfVPY< <<*Ů¿|UW?^ vݜwr |S6U#vo*nvθQfw}zQ\kUVECUV4A) Cm~|/wI9Q5ų0i=$.# )ݻi-%T+]ГM6| ֢uѝaHϯd]Z\*_꠵)kk%#.UaFピpeCnFÆh/]; F!YHt tQū=F4SN;l~@릎38E˄XQcft}ẹ_խ(K5 .r/)H*U퇼(ڔ**EY)84{-AVQZJ/rLI<Η<x:=jjqJki Fz2nR/wMR``(FYEe"E~@]uqMSflrxB8ەldCGLю]P,Ȉ5˶$4ZURZ.1#^dn5jeܓj+N̸gŻQ|X;1mI/uErxH~:u CbM z2xyzMWaT4TXaڮ|Ɯ JL21CU:fu9dٹHgLIQd13!HmJѶF(n3Yeދ 1Vٹyqؑ[~ ?D`qIs@ 3µ|½/D")EK=IHą#N=KONAM_` n@.4tEd^N=7s;0 3+qh5T.;ۥ ݶɌw+û{~< Dž$6`[,S `x+$k$3uS*mO-޴ K 9ِK rPRi6Y(똍pZ9V.  54G&I΂_CQjw |C,8!texw=nE/W`ʔ`?8f'Wyz)@&suNQh aZMYf\Gŷj iP['(:|a7%@.D0a|zazA<x@G>*c 2 (*WFaTfBg2"y^D'QNe+{jzG#a_ k3ЀcLV.鳻DTL$xNQ)Jv+9 FX\]s>=i kGnJRNJzJR:qz*{jfh][+ōmʬ1 I"DQ%[Dpo(x]@n+WwpIU=;[#me ֶhoܷ7(+dZ|y_=U’>kJQAeq?!u&8ZScRJ&1Z|5EיՒ~Eh}qRTzȌ6:뗱Ԭ4da݅0)F1C96o *ª4,-6R?ʒ!K]A0di;yM3$)\v$ 1 A%D-Qm V S ,hJl]J EE8Tp!Qyg7SPf'k٬= @ZjS$ m"Q}38lHpeӘum#WAi_|F8紷!Jv\wf*FemkK)ny;o!@CU0M}d` jmH;vVxS|g(N}=wmncq CKnH@kUK{$ػq>W`C}]c JKcc$an4DAR8M2vz:O* |%UiĝGJI2/ܸLr#̠ҽDoLHh/bDɲg\L(J(0߂I>ѕҖ&:¦$GOV{SXf2Lj$V\]:li8?Jt!κ:5?NVP6M' 6^07QlLPk4+>=tGҚW[+'̒QC+/&L֖i#g̈́V.TjJf |iJx4f}ڌEM{T;XJBUȕᯭZP?Y wOΣɚnTJl lf^'S{p +r?t#pdgIM"҈QX SGS2E#)qT~?UдYy73DJɂnXpF'-c@K!w_/3k֗C1}+A\= dZ Z4:8b1ī'~RQ[R'Al֟nwC\=|6{[$Ez,W_(.z; k!Re)CjiYo_sUr¦ p]&p3_ N; UFB?WEp_\?#r@GLKa3?6I[SQ倛;PO2K Ʌ_8828**DSU1]L͠ݙn$qhK)$ˏ1 ?"ޣǡFwwY|犩L=ꢥLVkhԻE3 ` M1:m+@zb.k? -8MMbwm B^-[  _9QM,{SOm ܶa . JcڐiЎ4>?C26˘'Mwk ę EEbgDLT8QӲ> stream x}YoeG;F?ܲ/1=hAhPJ{Ȣ^GyĊ[lzj꟯`7o?@sz~{*oN!y'"8 xtyyAL۹߼9-~v 1^]zntr=lt{&t}?oB0B@s훖Xr(o>鈛s&ErB<}5CZPNF[/|z1^+fwo"A[<,s~+B޴E?|ON_py|_Xuԫw6ƍ_X=p/Ѕ{#BpS۟{i4mnۧˇ? ;$0> mPBԾ/ _}U|:ꫯ wYAbt{SPGN_{Ow_yo~}y/˄׆0I3uc^ۯ>8FXύݯ~pO6~y_÷>G-;5wz:X?s# ӯ>JE۷Wn{&p-ks׽D}?^^"%L3OJ{1Q1*N:O~[#^tCS8boꄑsd~ԙv\C=u&tu`d3c{;F%c\dg2 Tg!iC0Rnl{8%[v 5q7"k$nFVD(I)<0$N*;Ht" ܒ60(I"@%KGȮU)yFHBBVDKJA0 j6Z2!Rs)@C,S9 q cHSdYMND"u܆(H}1f#ǢkҜ#%F%w2<ğj'L6Ȕk-`X #%Α~ D}A.dqۄh ܲ FI.!a`uDȰ,ϴRg9,4Z0h&-Iӵa}N:w5,ͤAɺC6 |\u2ji4/V5&zAi{?GZ&Udm PJ`Y*O.kXʊ@9 igICxε фhRJu4%7TUQfޢ`~ӹX]]ՕL+Ju%+UsP4dMR' %( !2 T P\ͩOB'.r8V\@epuEgI? D!kҠ2P|a5a"t(30p\&I?Hv jM>-K lyc:v">p%B`3n} * Kɒ{ɠ.28BZVԋ uD"vߐ1' 9 |ݔ=(jȌR0D `@ &37%L0!Ҋ vWvmǾtwGM9~m4=xnגVvi Q0 'י ĉo&1X[HB&L h'3r2)NeW)ذƉK&FGIa&qXEG Pa]cYQ12<30(688:a6)tKPX dӐA)LJphǪ}:i(k|7-T1i|Ngo 5qؿ6>Wɍ}|@Gb$aTp.C03B) ,$"CkL,m|`Vc66XgȠ.3ʯM@(&L8!G40H;LLֻR+voFR.8Ku(,k R8JiKtDDݏ"ya a6m8MXy Ko@ rápziɢGx&ʾfdn=ZC$4VarrҢ `((\608q^3WvAn[b]ȈL^Sd [6lwvkT`azqԠ0P:ڨ~ V) ҵg"gYlM&,EpZA-ɾ0W`"hFa;^L-ŽR㐒50%W0k8:.W8R: p)Jv T=JqjItL(DG6]CuS@l>!ű1*H#Fa"(lַ\5nB $}DoF>^lbe` *\ yI (U&Q`i(6-p 'Y]fbwk8's +Gp%H0( PkP N": &䚰50a`) mym'`vQp'%)j5{!5NR:{,Y&"mZrU؆`щ8gh|wQaؒ99nYU| g:p`I1$&!,,x,䔵08Ä)O F\0pxZ s (\JphVykUj  $-]w Aq0u\Spl9hu(WYFR:d2m3z@R/"I ҄/`Cw`T!%5Ҥ8*S @etk+4-nyQZ۝C6rt`E], ~pH(,5Dp 9L-R vdpxdj`5Qv=JvVS@6ņ`Fؠ) A ϲFv yk݂"T';XCLŹ9d(,*q8@GGJeZY̵$ShN4V|aPGs'dZy'gtkUlJ`T!ŠAj98HbU(T'0ڊ˲Da8 8FaaȪ Ɓ9:2ywLphG`BpOB';4#h5[P;~#T-4 Yٮ.T#]h; gVu]mɇ Ct/gׄha_f2,ֶQ Y_H)!YQnCaϻBtk;fGnASW)< #۰lydy\O8ڱ58:ZB15y :eDݫPP8&28ZxU!Xe7xE'"758:<sk#kI+Ca $B(TJ簶mha 4Yayyk!`dݣT{`!=E֍q(MLסp 9t!욒rLn7\ ڒ)ԫE޲Zppu$Fv 盬 EQAP!ڊݽ~֫(pz@ȡ} '>S' rt劇q08@ cGp a.rXZx2| /'=Px@J̛26ޔOB (O-eiB0 M4d9Kh2pukX˩B&P"!|c j0+Ie5(,M P &_Xw"֩%S<[XN*xq=e·ԂC4#6d-{s x4#MԱDYF-Έ4w=3"MHS9^ۥfIv"#`NH;(0apg9_@֩g,g8Ԩg8#vf}pOpP Wb`6M?Nؤ  R `80a_6Fw_,VVNေ;<p@y00Xj\ &ŬgyQ+"ˑQ<ɸ s(LD6~x_`S?)&Y4 y36ykyYheppuH $y`piM 0)ásE91aoރ- ?Zh8E;1Nasa.8^d|R#尶mδ<+ðї*!q(C7Xꍪfu(Qj`mLyԡqIRam#gzIz0E;b k  Xb7"3hr50|J#D,HT p)ápKfiqw hzP,[ڃo>OhD\5@(LFcC˭I#??5 Ϫ)f_۸ʿ3VcFOø_DFz4fFc |m-)]2ƌWZӘ9 V`j8m)Ҩ7He"QP 9?#u(,Ө'¤4k;$r׫@D@݁T w ա*gExVt  "5E˯ -W7*BF+z<"5BNO8:bSFQ)¤4k;0!sAc(n¯T5A5]zM?DK}CbT9RPPPKNaRmMV L ^SY5 CAv6xӫUCe5EkZpa>ʿbWEÐDUXQaGGŽX?r #VNd?b~J9ˎ PjrZfVoxhE&vy@ț@g}/b`xIU $&v3^ivܓFc}Y`;vn++q:wIO;d6|Ýev_E^t*p(x-k ՝>08p$剴1TmT&ády4Osly]<4Li4^<ydJbGHp܎">r uNHڰw#nD#3nR6&(R/59.*%+%*(n0*\ Lh .GU0ڈ!Ʀqq̮aLE]kaLF#3(Ge{0(oO&^=0<G5S8<^om[šS7SF05%`UpRp1Q^[S+HaXNQ`!% +Wa~G%NQ)Vk;{b0,v_Fa~_»:|`2 6 F,/vl!ZFkF5{`p/v֠ea*_;Uܹo 8n? )Y[Ļaqc69FH6'\ pzNoYw et&9y(Ç-f_鮃r}P&z bAY1m8h'®gQ 1p‚>雦#b-#kGGĔ„TVeF6=gY_qp"sJH9c(FrNcpl4L4%5LT [9?G+6y9F QN:~zcOSww}{G*R03FDhhw 3S]Sf:gjDh@M'HRqW_W۶77[* '~(ۚ~ e|?vՠS5x]R̔af*2PAͧRf3 NJ&䮼><ǃg ;- @U"@{>}P2$;OYG7ú_ p1IA>S%]gЮroJ;GK}u_ T-y9/SZ*q=W"Ō*e4y;ł=H.?41/ 3!STpg ު7  V%Ps&|7 5_OaΦRJoxiOg}|#M%~Ü~ Fq\铝E1T2"E?;#\d'eQ{Ͽt~WC9S?ʬz[?-h!E%2}ti9>+z뭟ޝ Hg~T}3_>}?UȪMv*4ތ'Ū:fKş><}ӯymt}ç0nNR.K7@Q;x-:7{kxV7yZN IE]' _b/[Ok>WS>F#rIUAa痃BYt;]acXW>.Q~e 7f_3N$I|+> w_R<.2O"n+kR<2A5LQ\:yUfl(3Xtv3?gYqGũy!#,#:$OFNBΑSywuX8DQ=; +33i"~ٔv!KҤ29 xߏ% ͳa/=',ݲm Q-M|>DO9p˝8Y(ӫ=UÐX2i~_EIE~uԶjzRaM覃q:1^IJ YC>OgVl*EKʍw5gnO:F7 !^LJBś+Ԧ8_%"gT[&ڬ@*i௭fUӴJ-8𷬷nioogFT4Ew6ۧGw~Qʤ:9L7)I/銸se]2 A<$VoKsX% 7 فaBH,YE=͗篆'Xh Hk~?hqd3?}z>2D~HpC჉%fuQUo:LY4Czצ^qwMxEs ND \RQf<7UX$R\h~>g礉Az 6s#RmvB}K)=y8H)r{Ym aIǞי#i =Gb3wS^ғEZ:44U_Жw(a2+!dv^ʼng[>{K-6ֽm!)WZ :{nMoV-z S 鷪rUEo^e ] [2ӗOs~oBEt_(Z/ mBLeկE:yKZwIY/T-eWBM BrK~>-yy$SIpiӷ/oVmpe0m^Gt9ELݱ״amǤg3a\N_ 2җgv9ײ:sPH'NO<Ž%2Fno4B*,A7>r--ֳg}|6D o5DٚȲ{V[}AdtsІ}~<.$iJ8^Jf oޑQk-n?`endstream endobj 296 0 obj << /Filter /FlateDecode /Length 8622 >> stream x}[o]9r~A KsgΙ rA2F j[mkZ<{WErqU[$X\\d,rWwg,Wwxqg-!j=͙<^ˋtΝ_zGNfţ$zy}ӢZb8DB:>wgZVgxrGlΓ ߞv"aGb1!!bj銣UBSIƛct cPDžE N MHPto9dAq&Q&Q'壑S¼Sɦ#?]QpLH;) +1Ҥcp!c8MTsLxcIT3!J$*xT;ziˌАTR5qmcj#(078w_ ˅i0ڈ{K=4MJE*Ʊ[b_&zyhcTcrzKdaf+Ou!$ v"zN zKZbRrcVXfy C]d3/bEH>F;w kw$$SMO T;4ZgZRb>4!L}gLL gjeS.͆D6 j9%L/p# )͌BWFxVhnDȍ% ԧmSνD ,D,h =bUֆzGr"xL)6ibH陦 hY #X=925#(҄:N~Մ:n8ϯ"Op8C< \X!5L!$@).$$A $"9KJe @5-5!Yz9F^,CHfl嬳Tg=B; WtcrBr&e<=䉐*Ou#3O$$S=SܒFv#,6АE”IcF(1Zɡ̐!)3IM-d7YKC1^RU[bCz4r90+ #23ܻmL -HC@.꺐[u? !! 3IS K7]u,e g1䡦ƴTD PCg2w:VbhޱTC9 |,P-!3`aP vәtXr VmHðCbR.yҹǟ B8o%F[viސ+>WǕc/`IӪ\X׏KRC(u8ܢ!C!ĉӫ1eLLo),8/h9|yD`Iwv]x+q' dj~n5UD57Ԇ"5{SL6練I5fh,Ĵ)6n;DC!׃5D3SۃçeO5ꖸZ%<uq8U6 DC?/M(I6x܆M6mKiV?ܕg `"; +6zf^GGzL 30L Ÿ&elOIL&k>>jSmL߲Qg2Ґ,tH6$Bq煶05h2NRPdRqtNP2NގT $4-?1H0Ram5$xXv#-/Mz3K(;=H0:%ekE!Hhr0HlQ4 WVl qB qxO!T'ب7%0t|9o^C&jHzR*; i@i# `|b$3¹Y 3:^Ґ# 'U{&&NG pF2SCOxAE, $s [Ch!jYWI5Bu( d8Br9bBIQA*5Ķ]+!GQGB[cOrs#Bf=wB:bM> ?/!2`myU&ߟ2~ɃV䬂V[LyH*ңL1>l>H@ IJ_?*zX"2u7=FJCx 䳤"% ->SVG gj,#)= LBIZ +UOF+!`gֈ* *B&)6 Nъ!ҴDs&+VC_ UI&쁂?+;,i #k*oj</4$g`9)V8qn82SJ%mDa ĂL`d㪣L"9NenԁM,SL63iz i0g &sӷs ]Yx-ătvGҡ7bz)D#E≄25 mKaH#v醏z&Ztv@7-*TIl"yz1mVCRM %#rUxH:bV7bΣb+ w [A(̗. TĴFj~ iثh Œ5u")3fW|2ˬ"2φkr;KG\/tdcT^aD Զycq*'9a= V **< S[+*bV߫Z3醜T2~!.6‚X#z<EW^3Optڗ]˴\X:x읖yޣb1\B u ا-sR_@H@i(A xX<\ %\<+" j"O _Q. BTA\kt>Fik;y1dV}{$9ZjM|%*ڹ<`ŻԬCusy Ls( 3#Ĺ<&!^"4ǐVHj,CX<èHF0NBBBb{5HQk d2CpYX&qVʒ& 4w̤2:RYr|e q\CHy2GHeruѐT߁_zc'pI1Q30h1 :z MD caFXQ1xJ OFEgQ1XmTn veG`Q%!M=\شQIp aJp񉙹z"K6N:$H_ER?ɂ5!ψx [cG {?(H+bH/IjA!<"_(mS$( wڱnL *R ֝D\- r(Pݼ4lT F = (Bdb/kGyqpB@;5h('5,h( *A`Ra1E)`4k&[QdBL,CF k(&5$-bK4ķ3EC\i7g@4S=IUCL&H)HYQB[CƵ,)SH͒!K!7̆@CB2do̅!?剿`F(*3B)}w P㜊7k P|BZ![U,* )LmpׂL6iy"Vp7Ny"QQ@4yf{5D&Syfm&<̠D59'h Y1~BǁD\%H , )}̣HHU%NKE\"83Ek'e{md1O#*? 8$qͪT-h~kO "͂dɚS4mǂHaDPmݤ}VԲ%P\u]@(F"g&$\uK!VG{)5hkkK<`Pķ!,DZn#;2 g4vo(Sn *bzA@tķ]| 5j'hZʀCY>7T\܅ۺB /3G{ s(r|LA$K##0(N"?G|PC\4*b+<#R ?iKp F`VSk) TJ ^Z9 D UGH{H ^*ƃrZ` A6oNjC*zQPhbKl{RGZTiq|^^ @T%ZlU+kRe1U&Iiz8 '6ɣh\;H}34(UA: 15)*3R|xw!8 x[AR0Rk#. *)H@uR|sa@sO6+ ~ud܅!fےC%W=dpeix'V|Ad-!ܪ=ݛ56SڭAOos{_o/~76vtՇDÛ""z 7cKw.yVY 1.iB>{_QOw@#&+fF&`ė7KVxxZ߷}w#3~a7:˷BUN/,V~ņ\'w'VĻc'&!`Z=\Pc2#b>\- &ZִYӧ۫ 8*aoF'/@Z~s+ŗtxۇ:Kzxi@1ό-N7.EF2t2( G iddi9xqd_Iڮ<\{-bnt=}AKX}8\?\{umo^Mb;s|xQ_uo9џ73/ß_΋_ _:a#샊*ܑ*6!i 7%Vfn!gp? #'UHHX#iVnHpz~u=]Np";Wtj?=Sd8 ߩ`&{er:׻݌)m=ٲ_K?;DT)Ց`u&}2x7 +rm7z`kxZ+=&$ ?]ЅhG4 e`1^?\ݭ9IF9rW4C$b6d/?,Y[vs zrm"9וֹǵiyh3agyzd7z={ #[x+oW bI0O⧎s#h^FFi"+ȗ~rILp+xjc#*)Eϙ:zKVȏk<>\?k+G u-6],v79&ɮJJoD`ۭ^¸iDwb(/+]gdSq? | x"#!erj/9N]pM;/rn 1;nd&{,v_S gu\X;7Wdu/2ZwfK-m<$߯ېs_9mLuhZV:5a{ތ#噱ɐ N-|ͫTY)d[-~\='Yp3VNKH{.5  1`Q]]L݊If2 Zsچʏ}j-~ȸ~zx_Fr(/ lNz\{chW:dDkId, p%v5Ykwe}g'GL/EL qկ9~FxlKHaUe%$A3KNvT6|u, 9EGWKd>Ѷ[-\m=O -J\_fTWjMwEi˜C[-]U٦.Wߟ'zendstream endobj 297 0 obj << /Filter /FlateDecode /Length 6187 >> stream x\[#7v~/)%4 䲋M OtkzZmI3CLhsHVR5@`f"yn߹ϋK쮺WG韛os#mX\U:,qmPfq^zvp< ~RJ6ܟ^.'=B$х뫂p $&^4d/%6nnyYLwG#a^ɜ&OsA" |y|&Ãh 4>ƕ2 48HQ:G &uTDQYGf~ FbSFqgF[kapt)ʱtt!9۫WOx.7II Ўܭ5%3+DV2r!yHN+$(Ql?%X4pK,QNdd뒰4X+nveX!'z'x"t 1aths"X@YӬ13.fF|:3AMޗ6>2#"{2$[FK >ۄ` PN7B.5B(Ӄh m  p{F5(!"CvDyd$^7}( J*%"?6߬P7TQ(5T#W~/o=+R4[""5)&+xN#h**^RBTFDqWx|AF**WziCIFJHUrC4"puYk* c#1Y7svp8ipn,'* )_; _Ļ UP'\E^Zq1 Y :jϨ*Q?RmOf"Gs*dzRᒊ@Sd.wm ňl= q" PTR;+AR9b)1vqh}(  a  UT b$"Q8-XJ(yDq5A%Ә*FX x#аu4 ɹA`"6FP` (?DTZ#X2pCOYֲ$uZ XsXC-*ıtc?/ dgǁkf;ӚQN9;ҩ.uS*F}9(tSG;ҩ.mÑNKq˖FH:g899h #4@EUQDԅXّE U Q13!R.p&[`T/ a0(= jΖBU͢Y&+, (TŇl9&S榰KdIf |0me$S%[9Yb }qw5kb B?ue狚X)$LPkTXɪ\~y ]fYEE*bƒ}Kbiŝ,FʂqP8Sx Kf($x*Jj($3R}BILOg0TOfK⩊.&|eTONV׸iI,(SOդ$VRm SD=Kb>::"IDh0 j Ƅ\p*&|AG z t*φsqNѱ,GJB-:/UƹhĹfjj)?#'*MUtM8<@*gXJE g0F2;c~o~Zj%Px_6wDr5q_-W6pp[^:*+[zXNO@*u͑ߧl^iܛTse]C!^C/_~p.KG׺B!8w)П@ *di4O{9 ^W Vk7 obIg\8wE&|ȾA<>l*Y,l~@5vGiҒZ6u _"Kkwr*4M:-fh-zQi`w|-&VMZ죝*eW:t}Z R7vqOo7xrLNգR8 -ѯm o6?jMM{ d)gSg_hLcBzsdHX9%`lIVړ)wosJ{s<=$vcaϨ"ɱHwls9_>~No6wRT+Ul9x>vק"D* 1mnBΖBD_i𾉋~N RJUUaB,bzߎ]78\nI7躾1zA"*tb^J6˵(`QyS+f3蔦o"c6R3Z ӊҁ*Y~AYAΉJi,ȌrCN:c~E o=ʑFpCLG:>GeO"7!Hy4%UtOۼb(˽JXUu1jN*alP,|q8t4MΣ'R )lEg|PW `c)cH%:d8T)ĖͶ/Әm&*@>M76Kczs4_?d8ͧ\EBcJ0I u$_,*F0ŷ?Guyv}8~46}b~eVr,/V9>Wߝk~J x𷚡S}uZ祛:xМyз ooyAC=nqWW %7saa?7/sߟ}"ܬ\Lt/ևq=n OICMzÔ{܃X/"bbd[Ɵ<#;&ۜԕ_yn6f솠D?}zX~)??ɸrV<UxXo]KEl|7n W)o:vZ:MVb,n+gSc0\hAt7Yr,)vvrk¤}R bƶrbOۭLltb&%z.Sx nD+WUHe{*{ѫ!W\U5"GSYnĮbD^XeesUi8 AG tBtO<(uՍRy55:/-a hVP'ms}Sm%l<73ܺaaK%T1󜎱#Iv)u1Ǘ|RP,(ϓㄯ:Rw3cN\N5ϓWë}کiC?Df_s(ɞwo?Ujx H?&Jh&׷ H9;! {8ZX@ I)suIPt!^]]=er:.KPUh_ n &Y_bY=aQ¿v63EY)//q= *oԌ3ҡC_Мj(x/N(_7ai KU^&3oR}0S׆Ӂ 59J&B\^]'/hx<-|k}\/U-endstream endobj 298 0 obj << /Filter /FlateDecode /Length 4835 >> stream x[KqoaSm:HRrc;FggVb`0]/Jr%X;L&suٿ9(Wo-r[?GmWg  7\^MWfS"gSav3 ߝYX,tф0mRi}s~coM 20+~av<[\HһY* *VYH5=^OыB~:lvۻ wz.pٟ`KZlV گvշ3=[^gJ 5 0홴Q/gW7g3iAN'& R҄~9r6og) :oDqbvhfy@ҙuгku<:gb jV(ayMPTat$BUa(.%/= ?IMjҹLqdKP=B!9h/SF!]YD.։I<sDu2O3jIa7 %i5#$54v 2Y4 uVG8J9E \+F]sF]#` -`9 sC _rF| FsYr0ܡ 6/ UF#"ocd)Z1Œ%Z 7!i`J *qXW%_{+$Q> 03pr9Nn%EIL_'wGzQSX1xx<GBt 2'񀅲Jq$D)=Cz3i7I̱GG(%:<xQ\cÊE3]g,* 5*h}*tY*4q+8뚩@صWkjBn ݚ+7ݦZ%t龎{hF݋k޲ZZĴآey-˶\d⛳g9{+;; OEZCDM?t֨ZRrA@ կP{ !LJ %js!w/V%dkqc!ha%QjTAE6 Ŵs;Jͥ"YQҤ e;t.ۯ?WI )P3G~l' &s+ B'wV+"A TZ *%G\@N\ȹqi%g5p5 dsU)BaرQO KU!35 o3p5 BuYeƳ^LAlXDJ'zwuo>Ш vzXHȮaw5@4sM46"H9L*sb7:hFQ3B2B,*QL0P2pS3.3"Dhġ#$01@PH$5#yLR$H:g seIŠTyxJ1oRiut-%r^:09E調}F$Y2X%B݁5ϙ7/qHN 9gg979KZh= #MHiLlNp/lT` sP$)%ɑ  |bF13@U޸cr,%!17U.l9r"t{J $s/JmP׳TrcS JL}"ܭk Z^So3Ŧzߠ !SB (M~X[(&Ugy\ qH- a:S<5uI@GO$ :|%ݤe@p0hl ]&i4DA匂 ?#uec(gO[!фCU-JLG(H8΀H p9An%ʕqvHX/KeR: DI`㧠1NɕIӆمYS')KFMC|*XFn-{sEvϽI O8(S*\C7VPPJx($,o !źL!փ㡨,o WVdRRTKS1K\q%]NĮMY*vCU, ]qDojUSJwvݸ5piLK-Z:mRn EZⱒPdCw*/pTzpGIQ'=9Bsg%qg 0-YL'ٻ5`Yr$emz{4 CPhMWPa1!RErY P})r#nT"^/Cd +ӳƝF? !E%7A.g?(@3Qُoq̽;~4w.'|g?ZӺΧ(]m gD<we-GI"[aQk8>E*>1rJV-~`UGd#1홉&}Sz2 <H/) 5 W-0.962 ;6 (3( -iW0.z?rE1p5 Z،[K+ =UCOVBG#Ε ,x} 7LhLLhLLhLLh<,h=oFoGdOt0Pnͷ;BW{d.NvLY7o5f>PF^'p_~nHvߧJJ=zM5|88圢7H9PqGrI_ta @́ t۬,ڀRE'oz BT;8gR!Ghţb}58گG˜JP2bV,\@&}VDZO`>*VjJ(DLqN:8aky2EGa>cB98ܰGD~> (B. \kpH>qo3'hL8<q Dz>TH"İq0x$Sh`-`G\Yp4c1>DqY*,mws r t2 t )eģQMx ۰_ >>1fv(nFa,Fv<`+ȶؗDENpDZ!e ݿ[گ}W ľ`.2}bx̛Io:A8j x0|66ӽW >o*&駗/ӧeEf&I_4ANOWw n'TIf5(HIB3CoS%GTෛ1trPl߾~ڏDߡ_/>6-D.ʮÇ>n~oErs. {߮olu?~}uW ppweMrH:(y!;I__e@IBk)]3sJ`W BIGsc*R\4iPla}R>zbO"_,=qQ l߽?O4c?yJ8 IsHV$V }hL|endstream endobj 299 0 obj << /Filter /FlateDecode /Length 4951 >> stream x\ݏ#9?x؇ϼR:pi$@Kes7&;znN:CB.U׳f/ˋgoj86|qa3fF 5\_Tr~95&i+y|Et}<4sq3nk-ͮ󅔲nQjs3oF1ij5g ^WJjU- !D0^?- k\>+|z42mMy<˹(Mu4fZQJnI08ݽ ZЕҠ^vcͮ}܈j"Ga9BMcgM3Q; @Z۠:a[Ø,gbOtEhsYְ*Otb4fOdW%K־q).9OyJ܊B~jҗ> YN+mKߖwucӡyIv^_Fvt;;$̲m ]$WgR%5%a "VUr݁ȐDgݒ!EXPbJl_s&t;jɃP2y;odњT)ͬCU5GwmƬ,|Udvߒ^#X4栁ZM8nN,'C-wtθc He $h s//ta5۞K4LhaC+so]*ck*G܄c5cJhFxS5;h,<_sI\]JV DҢY0])Aq`I:Iɒ%qt~oH`"D+gap7MB,o}a)xL@IH/;0K Lbup7eMvwTh ^>Xq)Q5Mab< KB8T d12slVPD-$0_0XAI>!K%gل,?JAx^cNkOǬ@yޖÛz:嫲 BಉȟEn=gG`9"~Ro5jDya>‰âOuňk\iYA!u{`JK[I!:DGgN $?bt;Ѱxi4 I~RpgV@p p56[@t(PS'}p gn&y4>8 ^( 1̊S0l]QeTWׂ68qv:?Hئ Ι,ЀH~ vxo qx/R+}s}4iM]yT~4~Pt1(}@b{p>GN={MMZ%d|\AP f̢ aNb6 (1RI&?H5YD 6SM>j+*R|a>h%|+umT]wL:= "663?,nN`R|\LԤ hިn\p Uczu%1b/,3`:Ix6?^^mӶWb_EZumã.9p:;ͅveFPajd` k8Tϩ6~}Q+?n}Q`7(pӌB61IH+1<PUB7یFhҁ†۬F,*>JKp/w(`RF0k㏅Ɂ1"^)ƯA~rq0 p0C3ҙ1vIj|o4):B:-~oT ::6NgEK?mz~P]K.ltTC{\olsoŚnPF SSgosgNERw5,ߤe{F՞K#E{MCPA28J) 9MZ@#_-t}^_TiVcE!GVa+1uBtqs6ϡS]ޥ}AHTiQ+`(1ZRXnz֨\!>ι8׫ɥܔ i= V$JL`]pa+dmDh\d \ ӊ fʆM2#xSRIiF j;R| Hw"hjmUyE=2oW1gi6a! czThW4.i`QW!{4X s* vU UNHs/[SsGֿq a؆Ȇ "g'#sSLw|HtƁoB}@ ; |ݾ;| _1!Q{,JbxQ6Qp i !0}j6XQ;ayv]-fũ;̾5}Olf` Ba-ꌌ`_U7TeSl'3-38ҧ0!x֟r0Dc$q~w!'xm>W f~ ћPiGێYzX xx:H p }P 0k(65xrelV@/ 났#}8CnA8ml|4:MN)!V28(.6ĪeU%u >|FI^3 :܅V>-=l7zPl~ehPӇq0ǎLKqآ}< yA-e? 7AK1[_xCeir:C"p#yFl_Ҁt5%> }BKe;AQ`t$+P/ZΪh3_~eJf肅ķW >eiCf^sjXE]Cf`Xc6+m>1څUaCpRpdk/3=s̢ĻkL׃ q\\PPb3#Z;r1/Ⴓ̨b?a$L9 *r{,TB9FWkBF8|VVmY)~xN8Vpq[ %0D(XV39duVAqYO_3ZXb..n@A\^H˅.L+D;X`$1CI◯d^n+[~݆=No7ۨ(U"!s&.NHO^cޮ}nG LLjNJTb}'+$|cHTB.1!S\H ļ؆`G7㕮4O2LIQ0kwD]d <`S8:<09ˌp\~5~_fHaH*ͣ R((Y&}3DYQ4,@(徻K;@V?LM:iŚ| x/PS ЃՓY õ~~.C)&ΙxbV2s(mTtL(OZnm#GD9OqE[.K`'۶1?)QV6jrOQ UT&RKo 0(nQ@(ڥ~W?]endstream endobj 300 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 350 >> stream xcd`ab`dd M3 JM/I, f!CǮ=<<<,*=3#cxzs~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+k꡻ g```4``d`bdd?SCL~]/^wK/r:3DժM벺߫>d3.yz}ƺgK q+[ym-ýwRO<<z7O;jendstream endobj 301 0 obj << /Filter /FlateDecode /Length 2451 >> stream xYێ}7a^4c`;p@@$\rMrc03ќpIi%' ,YSS}.? Aпv&7f2Ivxq1|Gpz_ko=Kv1 aBpam4!|c'&}^Ȟٟ;݁hi^؁Aj=s%oewpq=c~~* c"K|aB*v^ëyk>Fí:`AyfYRz1C8B®#T3N{}ֳ'p8ђ Iލ{ M=tp\ t$$?8 IҒǬM~K$S\!I0HIH,V>A,!M0%*d B%9*6KIL+Q_[=`"\C^ ,!$]˖"@O(䝈}z3HI$ MmN$ŏ$\i-r2yY C?qhG(fh 3< 0c\S/r@{ N\e9͐XJ1(u#ZHJuH,mgL P~魒;Xd^Z)ZS.M҂;ե2$]kjI@b[l"A+-Hc *ͱD!Rg$-/޲bԭQze'3)+{Rde1EhԳ-̨Z} T]"Xk$mK'X٧նIZl/FMocI)\f2#ib!VS/lMr+i$jD42jamki\l E#F-[h]%O-ZwiI:PK֥Z2NuV#i]W묭[Cgog/f$< ( ?EY ~4,-Xuf an3I#-i` =f(P$ZhlN"j`=-EOcӦ["V{wz3u<(7E4m`D~QJ@_HLe ct",Z*j{}3 φ06 Ӧ%MҩJJ L z+UkY>tA8"…B8K5AGϩy#I%ݩISP*U2hpQ;u*E2Ju*ND1.ْDKD!Щ׊,DB &Z$X.F:CӔ6C u5t{V:š#ޜ9Id_@-HU -+lHjBN59эi=1kebM>⤚ȯ"Srq\4ǒEr#3gf3#?ZMtR*鵎w+~Om zj)w}]/XxyÈ1^;_]¬aDv(pq03,p J_1BoSg Bw7_ݭ md3=+GȺx&o;a_?WetA,n1V#scv!`4.xЧ{ eף8/}tyro)_NbV(.~w6N/z4ϣq.gJ}>*@D ( Zj^oYDk'0P]&8>}6~ OĠ\g<'n)Yom=|Q!Gh#@*i$f7FXB[m6 3!-vXfw,ުɬ:kJweطRB&!K~Bo*Rqy:3a:."wTiC=?6sD=hNWF6]c{ü5{=V~v(Qjrul~A}4rv%tږR3rLבԯH)sbendstream endobj 302 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3561 >> stream xWyTWlfU%"웲 tDDCwj0 ,BD&kk9}^Uz~n (1@ OɊLY~~a sDt= Ήi+ ᏉxX= \3w[jZNzRBb|ɚ?1qHJP"4E2/IfCIp2/(n55--=#sCƘ59q~kCR+m,4Yd|ER@-fPT0BRaJjJSnTNYQeM-l(Oj>E-)9({j"eHIGM$BQS)cj:%RxJNHt&ɂ1Vc< Wb;$Z# ]r&ya6Xݱc+}?nƸތ{'+?[K?N*8o0l !)JHp=+DXƇ?*D*:8=x&2kQ!ԚXh {z$["NS ƊX)wo{͒mQ"ڕU1]ao7l6TCO- t3q&TVxBmTtk?/]8X\MC6sTG()oLV~L}셍CwusD[ J_Rۙbw29`>wR½s@kvNZ6۰G98q:fh!n~[p]-u9)%[º]~'Q+ЛΥoMڤT&9L3oLo*ΤU a:x[ڴ藈na% &4,mQPr/Ɉ-]hqp/.86A]0@yvׅdq^ ?:`v[CњHgV1w~ yoހX1pp YG?NdF\W.Β~q__bX)6)qcbtɨ깦ʐR8[4 ao̰3=֘СʆwDl޹eW.b$hk 3l聽=K$l>k2_dkqI|yRט3_bvT}uB!Ge!/ͣd>"db[fҳ5&d`M%~[۴ *p5b=-{ڳs.~i[߬d{}?@+ ̮/g]@Mmv΃&` ;`":og1i rR6O%'C " cp8ex*hՀHKj+o*'hܨ-]Zq?rxn[o'$tbmp*N=L՜i7-{\> e~S0{OKGSɢv5ȫEh^_}Ie;x5]/8MI}7gB/4si,* 'S+7ܮ&nP^>_>v|> p8b+sox$ tu>"X،e0:x)#o &^ŚԭD$bVTcy7}]ǥL-DDf٢Qo݂j /V^>~ =davoA!ӌMݔ_nx݌򘲕{ȋ[VCZ;zOgJ"Ay`bO BFV">J4v[pſrAL!g=a .WWO!Coo`4%{g/o}t5Kґ{V?bwk h!@)Py1W˰yc_qVFI( axc~"D)jbwhEN$FK p YMt;\0 \n.ji^&wtTwlEi Bka-8pXPU4T\B A`S\ym{ll1 `y0aU]+|E]kaa뾿W0#& `{!{ϙ"ŀPPcEF h'd[~m7Ng3uFk/>RmfcFx>¶,aov`NY쟯S'ro@G`޳A†*lV"־F` Q't(TW=c^=}h]endstream endobj 303 0 obj << /Filter /FlateDecode /Length 1796 >> stream xYmo6_a@ &: 6`C1`}HqElڭ~(=K&k|w^HލQ5~3z7qv}WwkN3<OG>v|l-j\1}KfJ +W#6oŢc&\i-9{VLReUIvYUYi쪘"lYpRfILh6-&RʲܮW]GZlTqg.E'Wid0O,ڪЛp[DRq--lmO M-gQ&W윿lγzi"Sxw1E_<ђ}| ų4Ygp9{>{s:H^0& Eћh/>SPՀT5U j@UP5Mz 5׀^z 5nS]x:dx#)L-`jS Z0L-҂^zuׁ^z>Q)^{xPuT=Uz@Az?4xU ?yq q#?sVVU/sPB4 ,< 8phG 8Zн(^qI :&RrQ+] DW @tW%Z H@tMsܡ+/IW" UB|_*B+@t%Ɂ:uof!7,ˁ<.7zqb"+yK>gV=k:ǾD[8fEE۽nKxǑW6Ng(4`smS/~nLGLSA^#(.Y~(}4hM[ ciw~{G"dKx|~09&Eq7sQ]<9y2.Wk< `ejiZ!u2L ?0M:ER 6 GJescqJZ]U%4̄ 7&m7endstream endobj 304 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 376 >> stream xcd`ab`ddM,,IL64 JM/I,If!C=<<<,.={3#cxns~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+kaw(6##K5|dѸ;fMD5uWUtvWʅeml-vwsMwws{o?QݒѳwMXtŊٍ r+|_~«߹~dO^;uOsp:ml+qqpvp7si޵}=z20~9endstream endobj 305 0 obj << /Filter /FlateDecode /Length 4448 >> stream x[[~oȃ[9V/6@$9'8H`A{<Ռ&l;&[c{aT]$ulczf/_nus{5U׎z}sܼ rn^.MHc#V)3&6g ߽ Wu>=3 VJ{omqg\wjCnwq^$ m7L[nMυXoF;fxy]IGrw? ?w;}G/Sa/%*X+q\ M/ta{0-\+8kcaHkm[V?,p)fD/}Z2Tr3V J "^)R,iXh住!v []uKe#e5EFEXe[K{E; |--(0\UXyz%+)xX. K*ZTɊǗlWd9%k*}sN3afՓu!RvDD'Gʼc…nB_S"*?̞ss+D),AȒ)#D&3fIES5K,IїD w-eQ)d7=c"Q-qi kpŰ(WOxDlD`vH}U|\H|F|ۉxqY)TIFNIܟhCH]1X"-aLlDW4ZxWT8P*tHɆ+Sj.qU Rq)AcRs)Ǩ2OfJh9@/`M[e^^cmLlKxDj N 3W Յuкp.\`OwTqt̖T0[1_#fOtE>-4u m@72Rr '<}-P&rӒ ^RYY('8:Q/ꐔ\sXLFBP509GlN)3d~GVuݺ@J~C|ɽLE~:^?#u߉tQ(~a?T,~~=i`55ُ4yyS=(rř%#RtjXK[K[ }ۭ58Jv6^ߟܟvW\K,qpm,_gҼˢq$ feQX`~ 90;D߄* ;cHnNaĵkCHB$x_|8*'%I\Qh;ЙrzW=saŧ.<>t8`zDtYV8ZufTUzLwl4=bZtX(2$:m S%_w^ĥ%ak)5݇vg54bhB^w8-J5WrKLœ 0d\brNJCQ5y՚t*AӁ:A. bNoI){s`R|ʧ;˗qn+ w!|:o::+AiZHlvT;ʈ+ (ڪ*N{ {t7N#@~ "7 !cz`@rQOUsiCf57NtK]h}aC.0gEhcۆSM7C-*'̂*k %:Vg!|34)Tk9mK5øbPjlZ!?gboA#sM=E>8+=$ ,Kt Y$I(2Lo.oO[؀ {<^iW-onLV|!SXM-a-tEϗd,ܹVa gi~"GC$mϗIY:◭Mt=\&EAQo4-f7 18g%S ѽ479SB.RŰBz 1D-$!zi23/Wz|O "]l 7fxֲ -r -/z{<0j.}XG LiOg渖=X`t=:^գe"'a^4۽[dBO{j!cJtsyJܵN4Ǣt.5'Iǩ\ӫQQ}dNKf1~C|9|LsxŦfO2T CWuO}*]^Juj3ڔoީ2iN611xJ$|0k1̅<필ۖN&Tu!LB>Ζ-RġP͖tSld?mAC*:VOY~ :Sy!w &DciB]؏sy(ϊ7Xd:4@[rIȹ5U0tzcPMb;=K"3Oyą"!bgJ6S W7TgsʥCtՏ6&ÄPcDא1$~hY:ٙg0nmGM2e3ʩotJ:Ps`GnBN5M5r^ӍIǚEnjt9#K| d./Z2vb c"nR2+blfX@wc 9fR2Y%wi{䎬7tdFՠ#:2䪍/=A N|/MWIyi >!hNOxsT70 q)ܞY(knոKMZMY YIv U-,#ԍmS/ի|x_2-^Qʜ:4UiL>mb,y99y^X%ھ.c57"aѯ1tM|`$1J5NO"Ox9y`?Ti&ݫ]6xw=ܒ6x?_^DF1P>sa&kynd^cG􋔁#X|\ƾm^lB=I[t=j[A8MO%7q.9Eau3`WCȂVi¶<TCnXR #<&'Y#endstream endobj 306 0 obj << /Filter /FlateDecode /Length 5016 >> stream x\n$q}jC,"XeC6 @ϕP"+{>Ȩi` }*+32N2{W+|sS?tۏ7ww1C2g>:ٺ>쬔 ӻÕ٥4}>\Yk ??}l*OjY XJ]cWa)_Zߚ4OZ~=\E}V%g676syfm?C?AJY}FvF3;9?~a8(Ah[9Zi(&e|9bO0"PH3*g\8 ~ 9`X%K"s8R詐T_hHTP=T[%n6$aLd:(i^0*vh)'7Թe3Z4~Tb3IRrcmV*/cAhisM*?=!O8Ew/Oˍ\CYR_'"9+9մT*J'fSWݙh.E7M'c IqK#J:%$.1i;GiM I$-'DX c`[aox*$sT8?0-aje̦1ƪ6%ױvvd[}`{=8oxln8TiX¶'#`Ylט -QBuf;1ב-`MD 1krtp*Vt[+i25Q!SJsR҅20&xO9g2D CSVumXhl@ck^mȱ ¦kJ]&3^Z8b^LZ 9לM&⤘oOMnOn'>z$GaJ -R(" #{N l}iTJ! %묰|J|ZP%{ZD{Wȱ *p?2HR4N*uFC~LWPrxA\KEBžӦbouz6є)g IΤ"aX><%$q5ؒ ֙kuص^gA1rG"G#u:KS8ZY]Uy>~ % dMII5~ 9 JSa=C~^Jw.MK[ IhRw,څ1j(t RyK;LlRblWl8 RI0@dL*HXA1*KNUI'ΤjG܂~ 3)^צ;ĮBe}yCMg?φ6vr`bC^C$(oڲMP|iHtdwF։㇚Ro^CJh*d1TWҫpRZ؁W5?4HAJFߚKCX*ESo ȫ&;~arZS{`0L H5m% ݂evv0}ÁA+zJ#&X8#̃{+2vtf7w7@ZPj"ڟ0RZp14U% M2 QX@d@< H HI"``4Gd}LtOݙi-B߄a 97% p]MP=]C/H>öBVTtDPU kK+IU& dU N2i(AKF13%(&'9ɠrBR}{L\F G4/)H%@k ա?_wj^HBr]ljE ޫϢ5F薚I7|KMXeE/Oo ,5s=-IyϽ Kk+6wgq'(pU:Np_ydr[O xae~+?x/~_\~XN73û'G%gMq2z!6ƒi`fyWzޑ[L]OaX!ڥnZ Hȧ2ՅR|) !q[&J 1_wbߋbaI|Py;>watxʢ^ޖ+B VXp+8!?0/erX=>><;v~vfG[]ng$ݘ ^kt(=]ϤG6PZdFq@fȌ(y;JdFq@f ԥx/8y?# mڗ<o,_+i5iOݏhziOD^K2i(ASF1M%hʳ`v)4]H.i?{<gG孏kvQHHwD}ѻ{O[jr>\9 ޭ'ew>Fq~|ҹ>w/ӊzܽ|: wtPZΟ`9w{*w|!wyl;Ye2/==:G_v+?ҙ&Oc^i,=B?5nZmy}ف/MSOI :n>غ1 zۆǨO6n_|}Q~?Ijendstream endobj 307 0 obj << /Filter /FlateDecode /Length 2330 >> stream xY[o~oF@44(P{e# Io9s!g(EI̹_3yN36w3: ^r%2C|Dd>v .xXoK!HfSuG,3`RmD ,`bS}*lڶq0jHl[/J̫oZ/4 9@ZIsıeSR!0(%8Q>us&0r1 E76m' Y?F\gד.(.ruN wc*[*>]":!~aRn.0c&5m8C2 2t9dGDI`FcRW,k'Ԩ9@  V.rAbR> zfĬ6-!ٌpdM\S$9ےuI[__|u-3B^HԶGW~&\ƕ'~ӲeuT&5w)3j:7Vk#ZQIw Rƅ7~ޤf'ɛvXY`yVMEgJ/SclK=2>hIY/TX*3\ B2!5`޵$DB+0H ?LCY*ܾ?jx [ݔ0,)16N2ē(Rv>|/&X (JKJ!N!|~qKr(/V_@!ס ~Pַ-TX`= (d Ƕ !/Y9gK7-.Zf;ɿG1-gVpHźXo^{[{A}ؖW pBP : }El[_ZT}U{veew? KPrh1~|(nوC.\/tA5f{zt55{tB4 !kdʠ57Ze*ƠNDŽDDh􂭎ƾ@K:b (ϰgTuWc}Oc % 3V0Hq*cA5nY=s2Dz%"0cq |ʴ2aw[~30 -z jw܎r![xXN"Z!wxx,D=ě$ޑ'@3 F.fX"M"\Jd륣2AI{gHQZbP7_K Tswy&%Io.HbT6 ^=rҵw)tLFgnW_Y&OMs4L;%L`rų>q`EA+ԑJI{[3ƏZL\6;XiTN}Oz(. uem {G Ԅ 5 v2xRNK)ו.r&~*y2\$,vޏ!pЭ\5]8{r?5gt*~;Rpx<]jsS;HȎd?Uwh1Lh1뤲%|љj:2I /k ?D!͇c˨yT{ |rth4؈>>I2~&8cѤTxfR`/.ǎ=vU?G[SjTiru~̏AǦ_Wi+-Q]E6b&c9sBdh>A=^(/~ |C.5|7* @ϱgIh>0JqLB`B89jOZX۰tidiX q9 id¸1F1cdE&3r|?@:endstream endobj 308 0 obj << /Filter /FlateDecode /Length 2085 >> stream xWnFͳ!BɰN& 2@&;8aF5$Y|Vn=م,tթSE7E][`;6ŗr #.4^on ^*\z@b)LLqذ.Цo/2rAtˮ*cEAwaUCD5S }ąFnQJs%!6U|(Bmo[p^)jP[P$^˰9&dQ+!?e?{L \&iʈ4t5HhpHJ J?jZw12^"XQ_Pn>F_yL@e[E;&Gg(Kw$;(]_uכ4d9 ,o6ǨsH]*jn)O[ ? Ӝ3M\'\ <λLmkJYn<㢢1 9y#Je>PrwgÙ0~vvXQp)!a7@r6rH{G( u#Mi[GNXCaxmcl1}l3tq>UD9ǃ l5aOqݏ>qJcs,(1z#4Ή8!Kkޑ*tճtnIƨȡPʡ;/X~ET<Ƚ !HJ q~qdN(}5@ A7Ӑa՟nJGg4)x`JGL*pPpNWzZZܬ;v }ٽ} wfAZI^)6\j9 YO.=ÉĖ1sv$R\oQrh )ਇh\h5зSFV;,?1Mz7Pj*N)~v[,ܟmZ:\?,=Ok9 }@L>nb'C$P}x QDyNiLHƹ\ۖ$$NKa[EK*Z[Z7”`qS̭L>uo):NNBl7`gjrlN;=-zqJuJ{%iCpw*C\^w@/r9JG8R=gd<*<}eφ?@7\⎸tk(EoQWkGSѶo/Ӓj*`Nkj5Iw<=D@"'lwsA6 7dj1%{ ;@&ХM}qofeN]^5Xm }(/e_oqsh?A͹-Lxomlޙ$Pho:l*a"|@_ڛrͶ8J0ZuUbL 7iaKǻ  V]cu\ 8 ϋ_~n_Wm*,ĩyUmb(vaŰ5F0ѯ*q/("lq9YȠ MLz"wU߾ˑYj'Ըg\6J #-oBJGnTudYX0 @\J|Ƒ!(eb.! ϸo\#ij19+!F>" PʏuIt>\072p1_6͡o5'8k;n)Ag=8 Ànv+/Gܣ~>`"0ڨԈȬN%bjhcJ>+{\~8}EE2z9 KWMƥQxq1RQ#}7A.7f'>:e˼|5U՛f״9731"993œ#}*˧Eƀ>ԛr(~ikcn>Շr,#נs|֙rYs|^ kd.endstream endobj 309 0 obj << /Filter /FlateDecode /Length 1633 >> stream xWmo6߰FTsD퀵m52ŠJն\IImo߉ē+{0% 9}M/֓pz18avu- 5a|TTibj& 2H8˘J@!YNȢ.3Xk(vbI0R0I B*0 Yge$vO,4$]3!5&&/9RʂY󢙎4)oXe72g7T$ hPKO~Af,(|:(r*V\\_UirF ŊӐqr۫7ίyIa O{IbFwX~:[baLiYzԪ{wf )D#ΏP?'y]ger2{˜8geRo灅McBf$2ӄ}'Pn0F#?@4؛݇Ph:By}>Ĥ8ͦ"O17|6Ug:ߤnE&qwG`ݻwy^:mUZU,ҳ|-Ɛ#uyG{-edŢŏ;#f֩JU>mQmeA~j ]$=dYEZQyoGPހ>y(yО_-la( )4b*(Uy:{I~DgeG([,WHǾHbHyHu,?PZi)Gypvђ5IT$u&57 SVy"%2l,,Tźˬe1ds%]ź0dGs&QQgYE/Ɯ!և,lv f.ጰr !Lg-6gٳ$g*L6S.Js0eLkc+ƇYrg\!op eIM(ݛR^`y*2ь*#GFO0vbCoa*hJ[gǎΊul:h!1W';K6~XSU݆5%49KZ WKvֲ 5Nnves2Hc  _>l=qT45$3#t<^G;;%>'pGti2~$Ydc/ =F< CF{^R P/zj=Kyw\9nY_%$U \ mWƣU]Y ×&E\ diMQi}ݩ?}#R__G7^( 3`th+ΪE -Λ`-#L ,"@p9'i3ic H:MʱuA?*'FɧOg ]%Q0F*_i2~endstream endobj 310 0 obj << /Filter /FlateDecode /Length 1955 >> stream xXm۶gO(jO,A\8S;mS[1E$2.H$t"X,}vs96?fx~70#׹}lvoW?R$k2_Ά)dN4Ks%TvZ,KT7m/8BhZ, *_~Gߘ"X++5H5`0@AA4x?NقA)hcDPxg[ Se.ެ$?i"Aa!*AFF2K|DJinzPf׽v5~x^_֨+v#6yծfuo_1Er# ew { ns<|R]wdqHRAW։*}S5ƫ V K|A}Qt]zY= n'Ƒ,D(#o<*dž~ԍ1ĦfX{Q^bm{h%<}ay~y84niQ"2\X<7G=J<JxZ<ɳ21}E&ɧHimCZ)ɏݻַށEU! +Cic/;ucUVzCB|X ځ61&(kr "K<`[nT3STW6d㮨C*7vˤlY(|suָJPb:Lvp*ԃ +gА}oMwd_9%W>,}70 ݓ +L\a=H%=T5~7ڶzSQfˢҿ=`ʛj4'(:6hߌi>߼Oz5~~ų^?xCjQ[鹝!I$$,?B~ m8Ϻqc3J-)9`~dkSD( <]rb4twG? "k`#EwfZs}Ab&3 [R:r Qpc(.v0F@Y,+uߙjҏRΘ0_fj÷#4&e<&@qotiPI˔K*.@?D-]G%Mk%RÐO9XvuF5Ŀ$|n#K#d! eh>I$N>sJhV<2WwmpRM5B#^QfQ%5r\z B+e6C~_lzܴODRI$Uy=BjiIa1_+9N& hԝMS@?e=oɸ8ʠV=Wf1ХYIa {L.9ar "qOB0e>"ˆ=tqR竲bJ@u>+S0A&k@N`GϣF kePŠ@}-O(9۠LsCe2Z;vNm,-Nm݀Ic! HSdB~tI*%UC-HEB1N19[ď= 1\?Z!5I.1s(Z rFt.- fexeiz~` :ܲ$$)"e'_h[2u ȍ__㷺ꉡr牓c,jP1#!5Mzlkh8t Vfy6 ]7A&QN Qu &vXT Ǯut.&y5yg+``/ ÿdbyr'8v޾49^8wǢ7 8$-;kfSpb\OR.;Wendstream endobj 311 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 644 >> stream xcd`ab`dd)14uIf!CG=<<<,~|'=3#cxZs~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+k9 e```)*INe`fepapc`z2c5|?v_{-5zStaNp [') ;Tuf H[5OM.ly] IlsWߐS)MX8]U.]h*9׾]w?¿.^U\.Tѽs:sW 祖smaג䤮9g;]sobӸzϡ&tw{Ņ?&6I<ѻK~ՓfY ﷬oW*߅+4j4C,mj/m+j.VyZ% g|[7oU}rw5߭lOy{gi&| ~XLn15{r\,!<<ܻyyx.LOendstream endobj 312 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 657 >> stream xcd`ab`dd N+64 JM/I, f!Cß <<,-=3#cxzs~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+k; g```q 6a`Pa0f0ae`c5|344'?mWW(ݐѕ.i_ҫ׺-ؖ}֝^ٽcEʦ5K+gޕȝ35{bnn/_lnn'ݎyI~ܽ{]کkr.֫ ʾ_<}aߺ>tqެ)gV.m{;DZǟߝAn5!s%˛hj$Lܜ(5n{eS;ͯZ՝id8\۵%K sdFo_203%+endstream endobj 313 0 obj << /Filter /FlateDecode /Length 8836 >> stream x][q~_qQy6b1  myV+Gȣ䏦d]طӧ80|$dGv7揧3W?p;_ߤ$؏RŜ:S ]8p຾C0?޿r4{c.dw7PO,4Ty_\)ނB/gmgp0C޷{+0z] 8 ;pƼޜ^B~pqߜq*ƞ?|۷Nݯqc'c{8Sơ 8}]Nzrgޟ" X>bpCw]@9b`}1c)vP=J`{vd:oQ!%c7VI` `AI2Vç)p %X$fBIRif+{*}b-cYbвd,򾳹]l8$HBw?ԑm$ln9B@#wQE\#O,uM-CGP<؃YB>+0(`}~CدG9B)&:0U9V0Z9aaKjLBspoVl#ZLjխZq՞V7F³oL<]pX槐)o)~"COo6 [ݲcGQaLfU<$ j3HҠU(gyF#]DsT3Ew^pgY2GY՞Hܙ0У`zLV.g~hʮ’iO751 }O># /?|w u.?( 1?k5PՑEؠAyi_EsLFI UFQ2ƃ4cKk` N@|0"xl!lm=?\Q-2Wp9Z\!'MP}VZ Iի(esL3Jٜ?k$ }֨jsFa}̈ڂG)c ҂%Ў(]!3X3: ؉XO;5~à!crѨ.$iQ b*}fˍUҢBU$ PJc/bhXq胦80`}!4"JǑ9\u#kwTdtւdRkZ4#nW,x|5j鳔QLZrC8Ώ~5j >>k,'ҒZhqwbfz+^]Rc;׾]ҨJ^UҠI8 U%-*A᫙*iQEWR@_s>sڦ8-P\ Cqvj.RԞH6)NYɈk-H&V)nի(nsL3ۜc4ã) r~xo;wo'BI4`CETu*iQ7g*iPcLjd7hreuVbD= q T.}RhyEuRYZგ 7~'7W}~z|>}tatDRUԍ-hT!4=^P*iQcU% *]E]5J?FxH0ca0H";?m5?)9\<)w9^Kj$:_^3Ic.D\:1 MN/K3;s,%KB->@bjB-W) w -8N^\q,㆓˗ML=޽tlǷ{wd<`B&/5E̔vG6(Ӱa4(gzAI*#(l˔}r" D2˔ Cl& L.RԞH6)SY9k-H&΄[^Ŭc11#VJQBFQ^-+ZeD%MnM˩xa$_ 8qmA01܎P]{.ވT7><~|y2xYRXɋz*~P*Vߣ{0ɼeDal:211V%Ф`*S c܇lHHb`F[$wr.ЕJu9Ѥ$0\$}`,*aYp/ 9iÃdnxIE^8ZC -^`&s%yMQK7Sƨ| k܃T1{'}r,x llhs(`(DarfԒd̑2957`r}ғ#^`ˋpF/h@tzY Ep5@6]v1@&HV@Ȧ4@ (̀gUFEIC. ָo!k0ńm=̄kL$XLV} A M.QyezYrɘfW7-O ^[Ig8 ?v'ctjLfO^6ƶ;"*Q;Q C#;#2rؒKi+)&*qH7D. K$%CZT!B#Ҕ)&be "~$'@ -QhmI.1txd]wRvKY9҇r65ilR}#Xd׿n2r6"<ȖAܠ2DeX@Uy2eH-Q*[T :-2dv.˸ AIJD${rQ$Q9%ֈ0m){(>}[p2bXm6 N,dJbOJY!#Xdc;7_,Oӫ D*bÁQÁQ%L*($TW:'0 2p5IA~jO$[L[ E$}Λ<65+4O1ӛGyNs2}ȉZr_O,Pg}1-Lơُ`WΒ!mV?R1j-p!c5j )g>JY&ֻ0 iWǔ]a$QKPD*8 TAQAIт0J]Q05+2\f^sղ#Hd/qSE|iv~A#fETz0z0J00J])T4p& Lv"=K#} ;ԞH6b؁/a*K'DWea"Eb4MBgq>p( َAKeU]Kgaga#(N(#ZP&FL0S]5p&r FB*..N'ɖfa~Hrv&%WhÀbA|YraD=p R}%:]飔#Ҳ0>9b9IFV'a3OZna=RVbiX )n3a;/Kqî/Y5Hһ,u Fk)nRRJR܈Q*ō(ō$tu8 _GY 9n.][Ol^b^uUŠ`eniD->3U\*]KBR \.}(4GaqiTwia2/ccRYFR6 ܃+5jYcma2vdJ2ԡVm:ԲZE)>l7AZ&8:҈OPV%i5$*/nm:38 $8TV%AQV%AIV u<m_?)eT6=iOTdkg%'+IAwe~mi*YJ'F|%8|PQɉ[rC $r ^ZYR}2$fO}4/̈́ŞIX"}@D*$T$AQ&,AI&,FI#BDGLXLX)LXLTXRa]t^pf.)]jO$.\2U̿9o1q֬| (kٝbKɃ:k8kT,Aq""FI,тS) TJS]5p,b6Ku;mEn#KwTdTRk.ZㆭV1Ma{rmSP'5~i *67I2DiE~ RP J1Ha jPSP1#|TT{8mzG*=lr"Zsɴ*'lz'li w'4[!Ώ9w1c蛕eۊah:;KT :$@Q5r_@/eD3#"Ɍ}E3JEOGQ#1-J߻V#'?Y~?c-DO*I>OÜ.-a$̖+r#)f9,Qb ?!3cؗ\@qƖ?4Ch'71XHv8' P[41Cq/Y*u1ϫKc^v}](FmXmv/O'Y*ޥCEq`nSU\(.XP.G+.:ZzH욏}:1ħJ!379芽p] +k쑸R6#\BUUqRFRAq$TRFҩu8]ǕʴpM^qm^ބ(A1c_Ȇ$q^$Q{KV*LP((QdxJx b%1+(2J(NGQc~Eh{HXb $x(/ /y2دl#LF "}H'FDx9 E2 ?d [BA EF EAq$M EF ũu8H|)ʴí:p˟e'SIHp}0AH>qd}xFI, ITzxTfAA&( aD(&(xDMGQ#ޘ3:"dmT & ώΞ)Vƒ7 Gdqv;l~L);z$2q(1JipnC)/!Q$Q1,Kj:BBP#(aG0JE"p%8S]xQ׏au`͖wwx)$*L%׿0;(X$ǕՐd ojb7qt!sHz(` tJ:RAI@d@ t8/!K46b!xtD*CTNp+FllL{ H2<-dI<+G9Cq/YYNP]uFqT(LCP!ZP; ӘQ4~L x]tdۻ4ϨH<0sRDQ^_&_$IPC-tAQ$Q  `H0* 븊}yب`O$.}rdZkիHasL3R؜_YfnK4mOo_9'*џ?c?N*p~#IVzxЭS8uXќ a{sZϟk~S}d]!y-x9?5ϟԍ>sE8t}bendstream endobj 314 0 obj << /Filter /FlateDecode /Length 1653 >> stream xX[D~o)xk3KhyZ DA 6&ޭ!.Bv3Cƞ3|~ SlÄoo~5|FxSlt~=&S%Ta7Dq6J*p`eT#31ՅdR dhcm3\`A~- ]"ؠr匱7CUMԨI#xbf88ݶ(%mSe-we/E%bgC%$o- RJ%R4}wMSaPԽk uk7,6B4é- |^'iR!mV0JFK `"pHcT9N `a,- zԸ7V\ )/>M ,(0T+AP#=DzڊQP& ] Hv2=s$vP[ߏ Lc(GݍcPׁ }r@=WڹD?ƭC]W\2g!ظ0؃70xiw4t`} F&I]m$ zXѦn:6Զ,afA` hs>0n5\O(߇ѧ7^s$"9κ $c "+&\:,u%{LޫDo!;6czUCkYj0y^9n]@{j}6$FjO̒E,;dafaJ8.h6XjQb, GH|',$p2=MӺs}~R< 7AHA8;3s G|NcqtxO8 ٩3e'jsNII~QqOiansU50ƛnBmŦf1UͦޖkYz_ ϵZݣ7SZC? UUOY,cIO8tCῇokbRKhz>p|9N%endstream endobj 315 0 obj << /Filter /FlateDecode /Length 1000 >> stream xVmo4_b<~7 NB|!ўN\n7f{Ǝ8m+&yfc(.Agw̿/C uA^-THe* +(cRSd)夵+J!8ji/S߅7a9EstI/\~7im1 +$م'ܧLj-XmI{X7Տ_A_pKYPT^;KڻUÓ +Jeys<8@ ysV}vC 3.F<} aLlBpaļJ8>XnǤ}q%-y}wۇo )1BCit@ Nj97&ۉ3I(7jF1IJ/a8OtM'] "(2t>fVbKp͆\sa{SB`_4hwx7?<]< VtPy::|) l`\D I9{\-8.yFv:=.J .( HrF_N汔&DeFDhVG ;j%km(%Ñ&nQ%D5=ey Ұ0\Ni>iה &B~s6 f_jX!x_XVu8RsD {mw791I>)4Bcb9R+5Hkf=kOERbUTr-~ׇ v;AX4Nޠ%EXeXѢYr7S*c׋N9 P͌J&13vd,QJg<^zq$נp> stream xWs6~%5T?HNҙu'iN26qҿ@8'3{8 vW}Z>-QHV.jiӥY],@ 7K,h@CYʖI4@(n.| D9TO)K#xUwn*=1FN:!gUөT `bR|"x!dzDkwqip$CyġM!Uϰ?%F6qk0HZk!4O I&-BAfaYM]+ d ]җhȉ8+1E,nR\/(K\0&TrɈ^7,<ѐJX˽LWtw`$nP!B [p]Q΄ݿi1i Nğd5a#zDI0ۭ?&ev=Z$ozvv,yjyT6ґ?iAW{xz=)V G^ʑ'y$B[v~Yoװ,ְj6E]~$܉ 읾lbKA[`k1\$qQHE*T&/  >KQ\M䄻TڜA31iow]x~(")x\G&hs"PW.C8vs5~f^{R01(ǵĄauN`S W*#%õ)-vr|VhBg] Ӻi(ʳnH (obwN{ejEReu1F)dteٯn(}}LYX%e5h@+b_fJ|}A1X:?Qq~S]mumCD 2/qB0MiϠUs}?B~w6:U C*6MמM޼Mx^8{~2OɀMɛ޴y9U qw1ŃKSF//e ݲYR5is"vNÅDIuC}v=[ۼڙ*&15,бB!b;lB=nq`ᤣ$QޯsDwrda I?tcHfGUH56FD(s2]dV5Q馿A8#{͉:_c}qWZK{z۷odM'endstream endobj 317 0 obj << /Filter /FlateDecode /Length 1987 >> stream xYoW !êXC <ؗ-6[I5>;ER~0ŝ sw|~?{?[Y|1t|u7s[\2ӔW"b'K31aj3C)KOc22AtdrdeyNzȳ#>s͔BUW5*qQ],)/EPX We/ojAG[GP$Z[b2|Iyp-Œ|%3˴כ\ka{gW?V:ͫ+]7roXQ D<|DVN֓c6cpYw{Wս7I-5~(/bz_zV`e )7պBx)$N.`LF~Sa =1|DS}Xpa|J?E.зXΝ"Z;(PE(LpG69F]B bMǮT(dGb T\}V]Wb)Z=Dz"MRU6ڱ=Ю3a=0\AcD۬+lNr` S7=u.K-2ׂ: #n{vsxQx"FC0h"}mW(:$4&>)h*o7gDc7BAz]?{r ^ԫb0 &)bo;اiQ@ x?݆BAK(cOw}KHKZ`Z]t**: 8A56k[IviL>8DZ˨ݚZJR ,АBs<8Rbm7|2k!wr:Ih3\+닒cu &FvAAADBaRRQCu*0*4s38(Y6:psY@)pIFe=H+\ hŅ/+ zH;GlLM`3 iæx{E fw &sρI;B ->rX^ XGD[̾ Uw(Y$C,CQXm J7ߡx.]+ GP<7wM807jl/r8.:^ ePbD;#8sdr`jR\^iSj/杘nvOrJ5nQ͑] AªOZ0B_A╿@>7 }5$oj=K̥k(y5tDLmЈOF"ӗ $*CWu'y4CpSe; (on4E4˘;?CI#E@I)=CE=g(>IyJ$PAa% I ĠQƈ?Ӹ\b("ω"T"8C?N4 dT48BzĎ$$,cөOkL#ǓDNI23r@RdB#H13q. >?ghP j>s)98dF$/CePŇՓ6xkS`^% &j63"wDߏVžfiE"8xW7WIl4UInnڗ *~8P+jw2HIw5Ho[0w;vL}露X?Ch31n "R19`yTb : Ex)WsAU VG X0K ]wk&fUhTϻ)8iw􃩨"Q[}N'  0}k9y ed[ߗdd?& endstream endobj 318 0 obj << /Filter /FlateDecode /Length 1898 >> stream xXmo6FkȠ-m׭À%EJU\II`oߑ"%Rf0)x{]qzO/&'ؼڿzbDH ObE#4I(.֓cI1&(\1)f6@ߗ)y :tJ<60C=HRfEB>X %B?ǾHpb5A$-9mǖ0d`1:IX9YPT[mc$2G@X t6oPl6+hv ˺<%(ҿ9AeJe0d҂IL,أ(t XDiōctx8p9jƂ}ﻰ0<$7΄UpwUiA 2j%Z{Ցcy)ד7M:J>: 8!^vZO}hv|c tl3XK/V1#LCH6V\'"'f_;<&&_d[4ʩ;oc@IwjSyO2Tl,X) AI0ccœ̚5NB>6UP# UUkzhp7uVAZeտC;C4pw!ϵlT Ÿ'/{^]|W_ 0ZeU˺umS(6RIt辜u&&-zKl=uI (**[f*-%:ţi,8Uy+mrif3ݒQ`AQ)X׿bZ gwy/ڰx2JHb M(VM!r8@I G3grh=%o(~Ir('DYӣjLyRfMtVVQsey1rnj H0``8t1 2R %LC%|u@`\CCW\\"Cbeb,C )|G/;zIj.tiy%$* UVu:^=KAmX{9nm#ֽ<-M Wv>J6=sЧ񦜎7]Wo~{ b{x'A1S'=#^zyhOŸzcD8VGh/~Wnӿmonb+endstream endobj 319 0 obj << /Filter /FlateDecode /Length 2284 >> stream xYK7An ^ @*Ìa͘ITu7ncM쮮W/lI/ty`~um?l}:-li)PaA]m~bc2bi i.ȶkvHR2n - djR U;r럕֒0:RWk!D!J7C_,ڒ&{KlӍ]K٬@hҮn jkft8_*ACsTݗZqY8++|Te?~.pZ ;A QTdr N͜{A26yHe=Uٶ} b<7p##]`Bf2btܹ[q1Mx&[ڮR牙 ?UQ3CaC%ټ|Xg2 $a;h*85 }!.(y>C݌s$G |-sF/1QMnzNCF;AҧCH $QIY,>H@ QK/Ӓ|MT҅~|TX_)ʦruoVAje"Ȃb֖|qO> Li)1!jh9 3kg}7ŚBhΫ^D֊-pcҔ6H U*' vyb!$C(ZfԕQ(&w~1 Wvj]3.ƜսOascE9ri? r2LcIFKLDwsC|уer40 wME"C/>~rf M}9/61̷| 86:2nzy&WVC W+ONBꥇPۿ_l~s}%>SzAʯOЦBN2&Qw`OyZhڀ@턙8>H(5-AJ9/4f&wg`)CMdA}ӎ<RcY@-Y:;!qR *ۏ}@S]>)jں1La<4m\o)A$9$> i2SI|ɠqE{Up?8N<,ЮiƗaQ9`3J85gոcXay9.?9S d!. }`'|@U_63O`2jD.<񣘛=ϗ×ѷP ӿeⲒ>CL16p|أB'Od0LJ`fQ␨{r:iV{+Vc"G(,-H)~wDxA =Tr?~Y  33Fu!*tǣ<6C(7(D:Iʷ?}uc* B%CDӈl"0VꌵOPhCq\> stream xYop:K.B h:}A\IxLR>샻iBD3""{{8gϨz0?$d,b?,tA%x"YE쒬98\(NS9i+ };,ݗk_<$NJ{ ,$WK 349~f'?H ar~4"Y% ]xB %o%p$W?~d~g䳦ꗿ;JQ)㘌8-˗ȐF1eP͆lHQu?)0ʑun;+r;,ͩG"s66^8$9{W bG3OvսOp(QlQ<Aℊ@!ӄ劉Hy ۽8 xȽV"ȇemU\y!K"!v1oɧ2 mJkj}XȣD))vw/Z`q 6.P[ \PN~u9F^Dyxzqc+L}bܝ䷌R.M~_BS8Pf"(6F%b)AXU8hVS,:]r]QG6ZdܚslG((FH,13 GVC2ƢӮ-bInSH MpwT+4OXKX՝eN>$}sߗ xaqw39y j k \X@VW|0"p` ?X-)$8MNgj ru%}i#G*ȍ@bbUspqWV  ', ہ,,T\b\ƨ'_U V<X.7h]+܈tIJ \bJV+$9]b /? .j+&qgN&QӉB+p+W&U]֠caJ-2AY)BDu]`_[oj+9h!{ś01ph8 b뵰84%Ac/w`-PPEmcM1] ? ݨ.n)@A]ZD =X?{@`OY] ]yW6 [~\Ef[SgЍ R}9J'CYaU +M+_mlڐ/܁@+NWJb3+lqHNݐs+#E?`2~/^xLFsop8~-p¨k|y[`C9*(ȶlz8F,Ν wP̚ׯc]A͉MB z,hƀ^1(;mq&>wץ P60q諟YqҮt?kN;,ce~4:rz'dc\F2}`*\66] S劦8Jr8L| 8sܾ rQ!υa0)xW;"\8q|q:|Np|8aENBC6Ԕ'JO3{JϮ@Ŕ atpQ[|R- @$Q]~$ ewvzZ6m*_"?)t zPTԣVJS0''I\̨3y>c,4il!0] ૵<[Rn_>W c̭g38̚1s52U^Oli2U-A7N,N;1I;8ߒ_! /t}8 vB2Y7n ʄu>E)pl['0JUM>z'ԯVL!|N9$ fڡ=Fl5\TJ^-% 檋P焏ciTc`;+ljW]zR'[L7.=0Sl4 !-c Z$\_tX.sNZ[ihkS{+@@91Om,'WP x"MʐDk(X&}>+_endstream endobj 321 0 obj << /Filter /FlateDecode /Length 1912 >> stream xXM6TvEqUIyak++)j(IjrA@Ic]Rs^w~aa2ԟWh~=0#׹Wo_ _pd2O\ S&jX,Rz<`kLKi41]!GC]HMѺ)OTvcD)ʶAi*яYTzIH'%;PhHe0啘,^ODƘP:I@]G<@$و2γz-BdPҋn*EK?#h[Nq54bTAHZ5gq.UY\ezuyp&M1c*Qu udqPpew1Fbyʜ6Aԗl!qZ/]o'HcϠPDSc!R(1H;xf3`+̚}kfuٔyY.uـУ~hcK#N}6]tB khq|yj}/_:_7]kOO7Ac;Lg=S1ƆE!{OD_, }n蛬*G܄]/C΀Up~da&ly>I+hl-߿/|0<4_^GS+FI~. w>ہ6k+r^^g]fZi=Tq8Ǧ>Ũ1p#1A5sW>q:*PwwUx5/@oc:fS 7NBJ.w*!9hek۰zl{CanLg[\o8)Zg{jKI`yiGR}&rT [Xi;ĩ=v=c]~Vɡ h0(I|,{UN13ܗ/xaq\-$6P:,:eIp  ̼Hy_ :Nƺh? ';CHgrO+c CQءBo"˻YۦXywWph{ Wu?(>..BGz YzxՆÝ24qs9[;P(/^mgVo1dԏ2WG*%يdzLF W1t! ID 4J,rHxOPf1ܞ[8I /ڮYAG[c 8K46{%. ;+̳goYSPT H]e@  anHYG<9 F XP Y*#b)MVS^p<9WL> stream xVn6}/z*X*h l^vD@DeG]Ib!%TE€mr3gn|BLP߬Zv fʻH_^E v b8B<f\ybK J05m~P~U~hJ6+PQO)j{-` ``vx<OP8?Fzp}DXƨ( h,$bOރ/`Rjt]lb@PCP֬n$p%A$t\8$vy7 9x+AiO]M7tj<K~^$g7h-]vES[@MɤB늴v8ڤUQ~,Hԧco&UsQQͷ<ٗuz|i1FB,Mm/ DjWpn> stream xRmLSW>׊^ t$s1nl_(v ge(-o|Xh9Md2 Yc{1qۯ%&qNry'e a&XUC큌|k}mckUt*`1 xhQ~ׇZl܎ hN$ )o?j?T[]¿q0-Mt>N\W[l|nt>>VX3|Qid<^hs MƗӟ)?CB{@)b$&RB(VY_}~5nw"VQ`ysDHCX>9`XܳmWȮ m Wk4 >M!yendstream endobj 324 0 obj << /Filter /FlateDecode /Length 820 >> stream xUR@+XNODR*-!&̄@ң% vL(5Iw﹏sNbiLoϫgUDx˫i%lqzWhlhƖ8"Ea'HD(wMQ lxh' !0!=/@̢YZa *]9U2ck5z8 ./ 5ʠf ዢK$J}VɢM>ڌj)cKl _wi"P<˺\v1)RXQXdu[k7f u3v v+!PP G e!AQ&s ʤUA my?sl\' x$@ *2ڵ&T9Ո'ߴF @w &@7eh8ZM*Ո|^VћQq02ިM}v=33klcFg*+W;ݩ4z,;I7w;U!c%w6n-OgM}^͙}wQ`EqtxvaOY=prg>oA Y37*cͽ~+f=9hj aˆr5rn C:fn1+uzߥ է#5ӐCИV&uZ1R;и'<`5Le5e=M۞Rp6̿H MXDle~`ɘ$ %iƙ7ߚу;dn(+ IxPy(A}Iz1;5endstream endobj 325 0 obj << /Type /XRef /Length 292 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 326 /ID [<142c402c2d697c54d0c5b775bb530cf1>] >> stream xcb&F~0 $8J8? ^M #Ϡn~M#`f- RJDwHѕ R:\AH= LH\"YH R*d D2?1o``fJtR }} fORW0^rDJuZ6a_wp6شU``R`߂UFs``wŶz[!i6 X!'z8s-i|6 endstream endobj startxref 221879 %%EOF partykit/inst/doc/mob.R0000644000176200001440000005435114415225033014552 0ustar liggesusers### R code from vignette source 'mob.Rnw' ################################################### ### code chunk number 1: setup ################################################### suppressWarnings(RNGversion("3.5.2")) library("partykit") options(prompt = "R> ", continue = "+ ", digits = 4, useFancyQuotes = FALSE) ################################################### ### code chunk number 2: PimaIndiansDiabetes ################################################### data("PimaIndiansDiabetes", package = "mlbench") ################################################### ### code chunk number 3: PimIndiansDiabetes-formula ################################################### pid_formula <- diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age ################################################### ### code chunk number 4: logit ################################################### logit <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { glm(y ~ 0 + x, family = binomial, start = start, ...) } ################################################### ### code chunk number 5: PimaIndiansDiabetes-mob ################################################### pid_tree <- mob(pid_formula, data = PimaIndiansDiabetes, fit = logit) ################################################### ### code chunk number 6: PimaIndiansDiabetes-print ################################################### pid_tree ################################################### ### code chunk number 7: PimaIndiansDiabetes-glmtree ################################################### pid_tree2 <- glmtree(diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age, data = PimaIndiansDiabetes, family = binomial) ################################################### ### code chunk number 8: PimaIndiansDiabetes-plot ################################################### plot(pid_tree) ################################################### ### code chunk number 9: PimaIndiansDiabetes-plot2 ################################################### plot(pid_tree2, tp_args = list(ylines = 1, margins = c(1.5, 1.5, 1.5, 2.5))) ################################################### ### code chunk number 10: PimaIndiansDiabetes-sctest1 ################################################### library("strucchange") sctest(pid_tree, node = 1) ################################################### ### code chunk number 11: PimaIndiansDiabetes-sctest2 ################################################### sctest(pid_tree, node = 2) ################################################### ### code chunk number 12: PimaIndiansDiabetes-sctest3 ################################################### sctest(pid_tree, node = 3) ################################################### ### code chunk number 13: PimaIndiansDiabetes-prune (eval = FALSE) ################################################### ## pid_tree3 <- mob(pid_formula, data = PimaIndiansDiabetes, ## fit = logit, control = mob_control(verbose = TRUE, ## minsize = 50, maxdepth = 4, alpha = 0.9, prune = "BIC")) ################################################### ### code chunk number 14: PimaIndiansDiabetes-info ################################################### names(pid_tree$info) ################################################### ### code chunk number 15: PimaIndiansDiabetes-info ################################################### names(pid_tree$node$info) ################################################### ### code chunk number 16: PimaIndiansDiabetes-print3 ################################################### print(pid_tree, node = 3) ################################################### ### code chunk number 17: PimaIndiansDiabetes-coef ################################################### coef(pid_tree) coef(pid_tree, node = 1) ## IGNORE_RDIFF_BEGIN summary(pid_tree, node = 1) ## IGNORE_RDIFF_END ################################################### ### code chunk number 18: mob.Rnw:785-786 ################################################### exp(coef(pid_tree)[,2]) ################################################### ### code chunk number 19: mob.Rnw:789-790 ################################################### risk <- round(100 * (exp(coef(pid_tree)[,2])-1), digits = 1) ################################################### ### code chunk number 20: PimaIndiansDiabetes-logLik ################################################### logLik(pid_tree) AIC(pid_tree) BIC(pid_tree) ################################################### ### code chunk number 21: PimaIndiansDiabetes-deviance ################################################### mean(residuals(pid_tree)^2) deviance(pid_tree)/sum(weights(pid_tree)) deviance(pid_tree)/nobs(pid_tree) ################################################### ### code chunk number 22: PimaIndiansDiabetes-predict ################################################### pid <- head(PimaIndiansDiabetes) predict(pid_tree, newdata = pid, type = "node") ################################################### ### code chunk number 23: PimaIndiansDiabetes-width ################################################### width(pid_tree) depth(pid_tree) ################################################### ### code chunk number 24: PimaIndiansDiabetes-subset ################################################### pid_tree[3] ################################################### ### code chunk number 25: mob.Rnw:877-880 ################################################### predict(pid_tree2, newdata = pid, type = "node") predict(pid_tree2, newdata = pid, type = "response") predict(pid_tree2, newdata = pid, type = "link") ################################################### ### code chunk number 26: Journals-data ################################################### data("Journals", package = "AER") Journals <- transform(Journals, age = 2000 - foundingyear, chars = charpp * pages) ################################################### ### code chunk number 27: Journals-tree ################################################### j_tree <- lmtree(log(subs) ~ log(price/citations) | price + citations + age + chars + society, data = Journals, minsize = 10, verbose = TRUE) ################################################### ### code chunk number 28: Journals-plot ################################################### plot(j_tree) ################################################### ### code chunk number 29: Journals-print ################################################### j_tree ################################################### ### code chunk number 30: Journals-methods ################################################### coef(j_tree, node = 1:3) summary(j_tree, node = 1:3) sctest(j_tree, node = 1:3) ################################################### ### code chunk number 31: BostonHousing-data ################################################### data("BostonHousing", package = "mlbench") BostonHousing <- transform(BostonHousing, chas = factor(chas, levels = 0:1, labels = c("no", "yes")), rad = factor(rad, ordered = TRUE)) ################################################### ### code chunk number 32: BostonHousing-tree ################################################### bh_tree <- lmtree(medv ~ log(lstat) + I(rm^2) | zn + indus + chas + nox + age + dis + rad + tax + crim + b + ptratio, data = BostonHousing) bh_tree ################################################### ### code chunk number 33: BostonHousing-plot ################################################### plot(bh_tree) ################################################### ### code chunk number 34: BostonHousing-AIC ################################################### mean(residuals(bh_tree)^2) logLik(bh_tree) AIC(bh_tree) ################################################### ### code chunk number 35: TeachingRatings-data ################################################### data("TeachingRatings", package = "AER") tr <- subset(TeachingRatings, credits == "more") ################################################### ### code chunk number 36: TeachingRatings-lm ################################################### tr_null <- lm(eval ~ 1, data = tr, weights = students) tr_lm <- lm(eval ~ beauty + gender + minority + native + tenure + division, data = tr, weights = students) ################################################### ### code chunk number 37: TeachingRatings-tree ################################################### (tr_tree <- lmtree(eval ~ beauty | minority + age + gender + division + native + tenure, data = tr, weights = students, caseweights = FALSE)) ################################################### ### code chunk number 38: TeachingRatings-plot ################################################### plot(tr_tree) ################################################### ### code chunk number 39: TeachingRatings-coef ################################################### coef(tr_lm)[2] coef(tr_tree)[, 2] ################################################### ### code chunk number 40: TeachingRatings-rsquared ################################################### 1 - c(deviance(tr_lm), deviance(tr_tree))/deviance(tr_null) ################################################### ### code chunk number 41: Titanic-data ################################################### data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" ttnc <- transform(ttnc, Treatment = factor( Gender == "Female" | Age == "Child", levels = c(FALSE, TRUE), labels = c("Male&Adult", "Female|Child"))) ################################################### ### code chunk number 42: Titanic-tree ################################################### ttnc_tree <- glmtree(Survived ~ Treatment | Class + Gender + Age, data = ttnc, family = binomial, alpha = 0.01) ttnc_tree ################################################### ### code chunk number 43: Titanic-plot ################################################### plot(ttnc_tree, tp_args = list(ylines = 1, margins = c(1.5, 1.5, 1.5, 2.5))) ################################################### ### code chunk number 44: GBSG2 ################################################### data("GBSG2", package = "TH.data") GBSG2$time <- GBSG2$time/365 ################################################### ### code chunk number 45: wbreg ################################################### library("survival") wbreg <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { survreg(y ~ 0 + x, weights = weights, dist = "weibull", ...) } ################################################### ### code chunk number 46: logLik.survreg ################################################### logLik.survreg <- function(object, ...) structure(object$loglik[2], df = sum(object$df), class = "logLik") ################################################### ### code chunk number 47: gbsg2_tree ################################################### gbsg2_tree <- mob(Surv(time, cens) ~ horTh + pnodes | age + tsize + tgrade + progrec + estrec + menostat, data = GBSG2, fit = wbreg, control = mob_control(minsize = 80)) ################################################### ### code chunk number 48: GBSG2-plot ################################################### plot(gbsg2_tree) ################################################### ### code chunk number 49: GBSG2-scatter ################################################### gbsg2node <- function(mobobj, col = "black", linecol = "red", cex = 0.5, pch = NULL, jitter = FALSE, xscale = NULL, yscale = NULL, ylines = 1.5, id = TRUE, xlab = FALSE, ylab = FALSE) { ## obtain dependent variable mf <- model.frame(mobobj) y <- Formula::model.part(mobobj$info$Formula, mf, lhs = 1L, rhs = 0L) if(isTRUE(ylab)) ylab <- names(y)[1L] if(identical(ylab, FALSE)) ylab <- "" if(is.null(ylines)) ylines <- ifelse(identical(ylab, ""), 0, 2) y <- y[[1L]] ## plotting character and response if(is.null(pch)) pch <- y[,2] * 18 + 1 y <- y[,1] y <- as.numeric(y) pch <- rep(pch, length.out = length(y)) if(jitter) y <- jitter(y) ## obtain explanatory variables x <- Formula::model.part(mobobj$info$Formula, mf, lhs = 0L, rhs = 1L) xnam <- colnames(x) z <- seq(from = min(x[,2]), to = max(x[,2]), length = 51) z <- data.frame(a = rep(sort(x[,1])[c(1, NROW(x))], c(51, 51)), b = z) names(z) <- names(x) z$x <- model.matrix(~ ., data = z) ## fitted node ids fitted <- mobobj$fitted[["(fitted)"]] if(is.null(xscale)) xscale <- range(x[,2]) + c(-0.1, 0.1) * diff(range(x[,2])) if(is.null(yscale)) yscale <- range(y) + c(-0.1, 0.1) * diff(range(y)) ## panel function for scatter plots in nodes rval <- function(node) { ## node index nid <- id_node(node) ix <- fitted %in% nodeids(mobobj, from = nid, terminal = TRUE) ## dependent variable y <- y[ix] ## predictions yhat <- if(is.null(node$info$object)) { refit.modelparty(mobobj, node = nid) } else { node$info$object } yhat <- predict(yhat, newdata = z, type = "quantile", p = 0.5) pch <- pch[ix] ## viewport setup top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_scatterplot", nid, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = "white", col = 0)) ## main title top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) mainlab <- paste(ifelse(id, paste("Node", nid, "(n = "), ""), info_node(node)$nobs, ifelse(id, ")", ""), sep = "") grid.text(mainlab) popViewport() plot_vp <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = xscale, yscale = yscale, name = paste("node_scatterplot", nid, "plot", sep = "")) pushViewport(plot_vp) ## scatterplot grid.points(x[ix,2], y, gp = gpar(col = col, cex = cex), pch = pch) grid.lines(z[1:51,2], yhat[1:51], default.units = "native", gp = gpar(col = linecol)) grid.lines(z[52:102,2], yhat[52:102], default.units = "native", gp = gpar(col = linecol, lty = 2)) grid.xaxis(at = c(ceiling(xscale[1]*10), floor(xscale[2]*10))/10) grid.yaxis(at = c(ceiling(yscale[1]), floor(yscale[2]))) if(isTRUE(xlab)) xlab <- xnam[2] if(!identical(xlab, FALSE)) grid.text(xlab, x = unit(0.5, "npc"), y = unit(-2, "lines")) if(!identical(ylab, FALSE)) grid.text(ylab, y = unit(0.5, "npc"), x = unit(-2, "lines"), rot = 90) grid.rect(gp = gpar(fill = "transparent")) upViewport() upViewport() } return(rval) } class(gbsg2node) <- "grapcon_generator" plot(gbsg2_tree, terminal_panel = gbsg2node, tnex = 2, tp_args = list(xscale = c(0, 52), yscale = c(-0.5, 8.7))) ################################################### ### code chunk number 50: gbsg2_tree-methods ################################################### gbsg2_tree coef(gbsg2_tree) logLik(gbsg2_tree) ################################################### ### code chunk number 51: bt-packages ################################################### data("Topmodel2007", package = "psychotree") library("psychotools") ################################################### ### code chunk number 52: btfit1 ################################################### btfit1 <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ...) btmodel(y, ...) ################################################### ### code chunk number 53: bt1 ################################################### bt1 <- mob(preference ~ 1 | gender + age + q1 + q2 + q3, data = Topmodel2007, fit = btfit1) ################################################### ### code chunk number 54: btfit2 ################################################### btfit2 <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ..., estfun = FALSE, object = FALSE) { rval <- btmodel(y, ..., estfun = estfun, vcov = object) list( coefficients = rval$coefficients, objfun = -rval$loglik, estfun = if(estfun) rval$estfun else NULL, object = if(object) rval else NULL ) } ################################################### ### code chunk number 55: bt2 ################################################### bt2 <- mob(preference ~ 1 | gender + age + q1 + q2 + q3, data = Topmodel2007, fit = btfit2) ################################################### ### code chunk number 56: bt2-print ################################################### bt2 coef(bt2) ################################################### ### code chunk number 57: bt2-worthf (eval = FALSE) ################################################### ## worthf <- function(info) paste(info$object$labels, ## format(round(worth(info$object), digits = 3)), sep = ": ") ## plot(bt2, FUN = worthf) ################################################### ### code chunk number 58: bt2-plot ################################################### plot(bt2) ################################################### ### code chunk number 59: bt2-plot2 ################################################### worthf <- function(info) paste(info$object$labels, format(round(worth(info$object), digits = 3)), sep = ": ") plot(bt2, FUN = worthf) ################################################### ### code chunk number 60: bt2-nodeapply (eval = FALSE) ################################################### ## par(mfrow = c(2, 2)) ## nodeapply(bt2, ids = c(3, 5, 6, 7), FUN = function(n) ## plot(n$info$object, main = n$id, ylim = c(0, 0.4))) ################################################### ### code chunk number 61: bt2-nodeapply-plot ################################################### par(mfrow = c(2, 2)) nodeapply(bt2, ids = c(3, 5, 6, 7), FUN = function(n) plot(n$info$object, main = n$id, ylim = c(0, 0.4))) ################################################### ### code chunk number 62: bt2-plot3 (eval = FALSE) ################################################### ## plot(bt2, drop = TRUE, tnex = 2, ## terminal_panel = node_btplot(bt2, abbreviate = 1, yscale = c(0, 0.5))) ################################################### ### code chunk number 63: node_btplot ################################################### ## visualization function node_btplot <- function(mobobj, id = TRUE, worth = TRUE, names = TRUE, abbreviate = TRUE, index = TRUE, ref = TRUE, col = "black", linecol = "lightgray", cex = 0.5, pch = 19, xscale = NULL, yscale = NULL, ylines = 1.5) { ## node ids node <- nodeids(mobobj, terminal = FALSE) ## get all coefficients cf <- partykit:::apply_to_models(mobobj, node, FUN = function(z) if(worth) worth(z) else coef(z, all = FALSE, ref = TRUE)) cf <- do.call("rbind", cf) rownames(cf) <- node ## get one full model mod <- partykit:::apply_to_models(mobobj, node = 1L, FUN = NULL) if(!worth) { if(is.character(ref) | is.numeric(ref)) { reflab <- ref ref <- TRUE } else { reflab <- mod$ref } if(is.character(reflab)) reflab <- match(reflab, mod$labels) cf <- cf - cf[,reflab] } ## reference if(worth) { cf_ref <- 1/ncol(cf) } else { cf_ref <- 0 } ## labeling if(is.character(names)) { colnames(cf) <- names names <- TRUE } ## abbreviation if(is.logical(abbreviate)) { nlab <- max(nchar(colnames(cf))) abbreviate <- if(abbreviate) as.numeric(cut(nlab, c(-Inf, 1.5, 4.5, 7.5, Inf))) else nlab } colnames(cf) <- abbreviate(colnames(cf), abbreviate) if(index) { x <- 1:NCOL(cf) if(is.null(xscale)) xscale <- range(x) + c(-0.1, 0.1) * diff(range(x)) } else { x <- rep(0, length(cf)) if(is.null(xscale)) xscale <- c(-1, 1) } if(is.null(yscale)) yscale <- range(cf) + c(-0.1, 0.1) * diff(range(cf)) ## panel function for bt plots in nodes rval <- function(node) { ## node index id <- id_node(node) ## dependent variable setup cfi <- cf[id,] ## viewport setup top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_btplot", id, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = "white", col = 0)) ## main title top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) mainlab <- paste(ifelse(id, paste("Node", id, "(n = "), ""), info_node(node)$nobs, ifelse(id, ")", ""), sep = "") grid.text(mainlab) popViewport() ## actual plot plot_vpi <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = xscale, yscale = yscale, name = paste("node_btplot", id, "plot", sep = "")) pushViewport(plot_vpi) grid.lines(xscale, c(cf_ref, cf_ref), gp = gpar(col = linecol), default.units = "native") if(index) { grid.lines(x, cfi, gp = gpar(col = col, lty = 2), default.units = "native") grid.points(x, cfi, gp = gpar(col = col, cex = cex), pch = pch, default.units = "native") grid.xaxis(at = x, label = if(names) names(cfi) else x) } else { if(names) grid.text(names(cfi), x = x, y = cfi, default.units = "native") else grid.points(x, cfi, gp = gpar(col = col, cex = cex), pch = pch, default.units = "native") } grid.yaxis(at = c(ceiling(yscale[1] * 100)/100, floor(yscale[2] * 100)/100)) grid.rect(gp = gpar(fill = "transparent")) upViewport(2) } return(rval) } class(node_btplot) <- "grapcon_generator" plot(bt2, drop = TRUE, tnex = 2, terminal_panel = node_btplot(bt2, abbreviate = 1, yscale = c(0, 0.5))) ################################################### ### code chunk number 64: tm ################################################### tm <- data.frame(age = c(60, 25, 35), gender = c("male", "female", "female"), q1 = "no", q2 = c("no", "no", "yes"), q3 = "no") tm ################################################### ### code chunk number 65: tm-predict ################################################### tm predict(bt2, tm, type = "node") predict(bt2, tm, type = function(object) t(worth(object))) predict(bt2, tm, type = function(object) t(rank(-worth(object)))) partykit/inst/doc/constparty.Rnw0000644000176200001440000007155714172230001016546 0ustar liggesusers\documentclass[nojss]{jss} %\VignetteIndexEntry{Constant Partying: Growing and Handling Trees with Constant Fits} %\VignetteDepends{partykit, rpart, RWeka, pmml, datasets} %\VignetteKeywords{recursive partitioning, regression trees, classification trees, decision trees} %\VignettePackage{partykit} %% packages \usepackage{amstext} \usepackage{amsfonts} \usepackage{amsmath} \usepackage{thumbpdf} \usepackage{rotating} %% need no \usepackage{Sweave} %% additional commands \newcommand{\squote}[1]{`{#1}'} \newcommand{\dquote}[1]{``{#1}''} \newcommand{\fct}[1]{{\texttt{#1()}}} \newcommand{\class}[1]{\dquote{\texttt{#1}}} \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} %% further commands \renewcommand{\Prob}{\mathbb{P} } \renewcommand{\E}{\mathbb{E}} \newcommand{\V}{\mathbb{V}} \newcommand{\Var}{\mathbb{V}} \hyphenation{Qua-dra-tic} \title{Constant Partying: Growing and Handling Trees with Constant Fits} \author{Torsten Hothorn\\Universit\"at Z\"urich \And Achim Zeileis\\Universit\"at Innsbruck} \Plainauthor{Torsten Hothorn, Achim Zeileis} \Abstract{ This vignette describes infrastructure for regression and classification trees with simple constant fits in each of the terminal nodes. Thus, all observations that are predicted to be in the same terminal node also receive the same prediction, e.g., a mean for numeric responses or proportions for categorical responses. This class of trees is very common and includes all traditional tree variants (AID, CHAID, CART, C4.5, FACT, QUEST) and also more recent approaches like CTree. Trees inferred by any of these algorithms could in principle be represented by objects of class \class{constparty} in \pkg{partykit} that then provides unified methods for printing, plotting, and predicting. Here, we describe how one can create \class{constparty} objects by (a)~coercion from other \proglang{R} classes, (b)~parsing of XML descriptions of trees learned in other software systems, (c)~learning a tree using one's own algorithm. } \Keywords{recursive partitioning, regression trees, classification trees, decision trees} \Address{ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/}\\ Achim Zeileis\\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org}\\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} } \begin{document} \setkeys{Gin}{width=\textwidth} \SweaveOpts{engine=R, eps=FALSE, keep.source=TRUE, eval=TRUE} <>= suppressWarnings(RNGversion("3.5.2")) options(width = 70) library("partykit") set.seed(290875) @ \section{Classes and methods} \label{sec:classes} This vignette describes the handling of trees with constant fits in the terminal nodes. This class of regression models includes most classical tree algorithms like AID \citep{Morgan+Sonquist:1963}, CHAID \citep{Kass:1980}, CART \citep{Breiman+Friedman+Olshen:1984}, FACT \citep{Loh+Vanichsetakul1:988}, QUEST \citep{Loh+Shih:1997}, C4.5 \citep{Quinlan:1993}, CTree \citep{Hothorn+Hornik+Zeileis:2006} etc. In this class of tree models, one can compute simple predictions for new observations, such as the conditional mean in a regression setup, from the responses of those learning sample observations in the same terminal node. Therefore, such predictions can easily be computed if the following pieces of information are available: the observed responses in the learning sample, the terminal node IDs assigned to the observations in the learning sample, and potentially associated weights (if any). In \pkg{partykit} it is easy to create a \class{party} object that contains these pieces of information, yielding a \class{constparty} object. The technical details of the \class{party} class are discussed in detail in Section~3.4 of \code{vignette("partykit", package = "partykit")}. In addition to the elements required for any \class{party}, a \class{constparty} needs to have: variables \code{(fitted)} and \code{(response)} (and \code{(weights)} if applicable) in the \code{fitted} data frame along with the \code{terms} for the model. If such a \class{party} has been created, its properties can be checked and coerced to class \class{constparty} by the \fct{as.constparty} function. Note that with such a \class{constparty} object it is possible to compute all kinds of predictions from the subsample in a given terminal node. For example, instead the mean response the median (or any other quantile) could be employed. Similarly, for a categorical response the predicted probabilities (i.e., relative frequencies) can be computed or the corresponding mode or a ranking of the levels etc. In case the full response from the learning sample is not available but only the constant fit from each terminal node, then a \class{constparty} cannot be set up. Specifically, this is the case for trees saved in the XML format PMML \citep[Predictive Model Markup Language,][]{DMG:2014} that does not provide the full learning sample. To also support such constant-fit trees based on simpler information \pkg{partykit} provides the \class{simpleparty} class. Inspired by the PMML format, this requires that the \code{info} of every node in the tree provides list elements \code{prediction}, \code{n}, \code{error}, and \code{distribution}. For classification trees these should contain the following node-specific information: the predicted single predicted factor, the learning sample size, the misclassification error (in \%), and the absolute frequencies of all levels. For regression trees the contents should be: the predicted mean, the learning sample size, the error sum of squares, and \code{NULL}. The function \fct{as.simpleparty} can also coerce \class{constparty} trees to \class{simpleparty} trees by computing the above summary statistics from the full response associated with each node of the tree. The remainder of this vignette consists of the following parts: In Section~\ref{sec:coerce} we assume that the trees were fitted using some other software (either within or outside of \proglang{R}) and we describe how these models can be coerced to \class{party} objects using either the \class{constparty} or \class{simpleparty} class. Emphasize is given to displaying such trees in textual and graphical ways. Subsequently, in Section~\ref{sec:mytree}, we show a simple classification tree algorithm can be easily implemented using the \pkg{partykit} tools, yielding a \class{constparty} object. Section~\ref{sec:prediction} shows how to compute predictions in both scenarios before Section~\ref{sec:conclusion} finally gives a brief conclusion. \section{Coercing tree objects} \label{sec:coerce} For the illustrations, we use the Titanic data set from package \pkg{datasets}, consisting of four variables on each of the $2201$ Titanic passengers: gender (male, female), age (child, adult), and class (1st, 2nd, 3rd, or crew) set up as follows: <>= data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" @ The response variable describes whether or not the passenger survived the sinking of the ship. \subsection{Coercing rpart objects} We first fit a classification tree by means of the the \fct{rpart} function from package \pkg{rpart} \citep{rpart} to this data set (make sure to set \code{model = TRUE}; otherwise \code{model.frame.rpart} will return the \code{rpart} object and not the data): <>= library("rpart") (rp <- rpart(Survived ~ ., data = ttnc, model = TRUE)) @ The \class{rpart} object \code{rp} can be coerced to a \class{constparty} by \fct{as.party}. Internally, this transforms the tree structure of the \class{rpart} tree to a \class{partynode} and combines it with the associated learning sample as described in Section~\ref{sec:classes}. All of this is done automatically by <>= (party_rp <- as.party(rp)) @ Now, instead of the print method for \class{rpart} objects the print method for \code{constparty} objects creates a textual display of the tree structure. In a similar way, the corresponding \fct{plot} method produces a graphical representation of this tree, see Figure~\ref{party_plot}. \begin{figure}[p!] \centering <>= plot(rp) text(rp) @ <>= plot(party_rp) @ \caption{\class{rpart} tree of Titanic data plotted using \pkg{rpart} (top) and \pkg{partykit} (bottom) infrastructure. \label{party_plot}} \end{figure} By default, the \fct{predict} method for \class{rpart} objects computes conditional class probabilities. The same numbers are returned by the \fct{predict} method for \Sexpr{class(party_rp)[1L]} objects with \code{type = "prob"} argument (see Section~\ref{sec:prediction} for more details): <>= all.equal(predict(rp), predict(party_rp, type = "prob"), check.attributes = FALSE) @ Predictions are computed based on the \code{fitted} slot of a \class{constparty} object <>= str(fitted(party_rp)) @ which contains the terminal node numbers and the response for each of the training samples. So, the conditional class probabilities for each terminal node can be computed via <>= prop.table(do.call("table", fitted(party_rp)), 1) @ Optionally, weights can be stored in the \code{fitted} slot as well. \subsection{Coercing J48 objects} The \pkg{RWeka} package \citep{RWeka} provides an interface to the \pkg{Weka} machine learning library and we can use the \fct{J48} function to fit a J4.8 tree to the Titanic data <>= if (require("RWeka")) { j48 <- J48(Survived ~ ., data = ttnc) } else { j48 <- rpart(Survived ~ ., data = ttnc) } print(j48) @ This object can be coerced to a \class{party} object using <>= (party_j48 <- as.party(j48)) @ and, again, the print method from the \pkg{partykit} package creates a textual display. Note that, unlike the \class{rpart} trees, this tree includes multiway splits. The \fct{plot} method draws this tree, see Figure~\ref{J48_plot}. \begin{sidewaysfigure} \centering <>= plot(party_j48) @ \caption{\class{J48} tree of Titanic data plotted using \pkg{partykit} infrastructure. \label{J48_plot}} \end{sidewaysfigure} The conditional class probabilities computed by the \fct{predict} methods implemented in packages \pkg{RWeka} and \pkg{partykit} are equivalent: <>= all.equal(predict(j48, type = "prob"), predict(party_j48, type = "prob"), check.attributes = FALSE) @ In addition to \fct{J48} \pkg{RWeka} provides several other tree learners, e.g., \fct{M5P} implementing M5' and \fct{LMT} implementing logistic model trees, respectively. These can also be coerced using \fct{as.party}. However, as these are not constant-fit trees this yields plain \class{party} trees with some character information stored in the \code{info} slot. \subsection{Importing trees from PMML files} The previous two examples showed how trees learned by other \proglang{R} packages can be handled in a unified way using \pkg{partykit}. Additionally, \pkg{partykit} can also be used to import trees from any other software package that supports the PMML (Predictive Model Markup Language) format. As an example, we used \proglang{SPSS} to fit a QUEST tree to the Titanic data and exported this from \proglang{SPSS} in PMML format. This file is shipped along with the \pkg{partykit} package and we can read it as follows: <>= ttnc_pmml <- file.path(system.file("pmml", package = "partykit"), "ttnc.pmml") (ttnc_quest <- pmmlTreeModel(ttnc_pmml)) @ % \begin{figure}[t!] \centering <>= plot(ttnc_quest) @ \caption{QUEST tree for Titanic data, fitted using \proglang{SPSS} and exported via PMML. \label{PMML-Titanic-plot1}} \end{figure} % The object \code{ttnc_quest} is of class \class{simpleparty} and the corresponding graphical display is shown in Figure~\ref{PMML-Titanic-plot1}. As explained in Section~\ref{sec:classes}, the full learning data are not part of the PMML description and hence one can only obtain and display the summarized information provided by PMML. In this particular case, however, we have the learning data available in \proglang{R} because we had exported the data from \proglang{R} to begin with. Hence, for this tree we can augment the \class{simpleparty} with the full learning sample to create a \class{constparty}. As \proglang{SPSS} had reordered some factor levels we need to carry out this reordering as well" <>= ttnc2 <- ttnc[, names(ttnc_quest$data)] for(n in names(ttnc2)) { if(is.factor(ttnc2[[n]])) ttnc2[[n]] <- factor( ttnc2[[n]], levels = levels(ttnc_quest$data[[n]])) } @ % Using this data all information for a \class{constparty} can be easily computed: % <>= ttnc_quest2 <- party(ttnc_quest$node, data = ttnc2, fitted = data.frame( "(fitted)" = predict(ttnc_quest, ttnc2, type = "node"), "(response)" = ttnc2$Survived, check.names = FALSE), terms = terms(Survived ~ ., data = ttnc2) ) ttnc_quest2 <- as.constparty(ttnc_quest2) @ This object is plotted in Figure~\ref{PMML-Titanic-plot2}. \begin{figure}[t!] \centering <>= plot(ttnc_quest2) @ \caption{QUEST tree for Titanic data, fitted using \proglang{SPSS}, exported via PMML, and transformed into a \class{constparty} object. \label{PMML-Titanic-plot2}} \end{figure} Furthermore, we briefly point out that there is also the \proglang{R} package \pkg{pmml} \citep{pmml}, part of the \pkg{rattle} project \citep{rattle}, that allows to export PMML files for \pkg{rpart} trees from \proglang{R}. For example, for the \class{rpart} tree for the Titanic data: <>= library("pmml") tfile <- tempfile() write(toString(pmml(rp)), file = tfile) @ Then, we can simply read this file and inspect the resulting tree <>= (party_pmml <- pmmlTreeModel(tfile)) all.equal(predict(party_rp, newdata = ttnc, type = "prob"), predict(party_pmml, newdata = ttnc, type = "prob"), check.attributes = FALSE) @ Further example PMML files created with \pkg{rattle} are the Data Mining Group web page, e.g., \url{http://www.dmg.org/pmml_examples/rattle_pmml_examples/AuditTree.xml} or \url{http://www.dmg.org/pmml_examples/rattle_pmml_examples/IrisTree.xml}. \section{Growing a simple classification tree} \label{sec:mytree} Although the \pkg{partykit} package offers an extensive toolbox for handling trees along with implementations of various tree algorithms, it does not offer unified infrastructure for \emph{growing} trees. However, once you know how to estimate splits from data, it is fairly straightforward to implement trees. Consider a very simple CHAID-style algorithm (in fact so simple that we would advise \emph{not to use it} for any real application). We assume that both response and explanatory variables are factors, as for the Titanic data set. First we determine the best explanatory variable by means of a global $\chi^2$ test, i.e., splitting up the response into all levels of each explanatory variable. Then, for the selected explanatory variable we search for the binary best split by means of $\chi^2$ tests, i.e., we cycle through all potential split points and assess the quality of the split by comparing the distributions of the response in the so-defined two groups. In both cases, we select the split variable/point with lowest $p$-value from the $\chi^2$ test, however, only if the global test is significant at Bonferroni-corrected level $\alpha = 0.01$. This strategy can be implemented based on the data (response and explanatory variables) and some case weights as follows (\code{response} is just the name of the response and \code{data} is a data frame with all variables): <>= findsplit <- function(response, data, weights, alpha = 0.01) { ## extract response values from data y <- factor(rep(data[[response]], weights)) ## perform chi-squared test of y vs. x mychisqtest <- function(x) { x <- factor(x) if(length(levels(x)) < 2) return(NA) ct <- suppressWarnings(chisq.test(table(y, x), correct = FALSE)) pchisq(ct$statistic, ct$parameter, log = TRUE, lower.tail = FALSE) } xselect <- which(names(data) != response) logp <- sapply(xselect, function(i) mychisqtest(rep(data[[i]], weights))) names(logp) <- names(data)[xselect] ## Bonferroni-adjusted p-value small enough? if(all(is.na(logp))) return(NULL) minp <- exp(min(logp, na.rm = TRUE)) minp <- 1 - (1 - minp)^sum(!is.na(logp)) if(minp > alpha) return(NULL) ## for selected variable, search for split minimizing p-value xselect <- xselect[which.min(logp)] x <- rep(data[[xselect]], weights) ## set up all possible splits in two kid nodes lev <- levels(x[drop = TRUE]) if(length(lev) == 2) { splitpoint <- lev[1] } else { comb <- do.call("c", lapply(1:(length(lev) - 2), function(x) combn(lev, x, simplify = FALSE))) xlogp <- sapply(comb, function(q) mychisqtest(x %in% q)) splitpoint <- comb[[which.min(xlogp)]] } ## split into two groups (setting groups that do not occur to NA) splitindex <- !(levels(data[[xselect]]) %in% splitpoint) splitindex[!(levels(data[[xselect]]) %in% lev)] <- NA_integer_ splitindex <- splitindex - min(splitindex, na.rm = TRUE) + 1L ## return split as partysplit object return(partysplit(varid = as.integer(xselect), index = splitindex, info = list(p.value = 1 - (1 - exp(logp))^sum(!is.na(logp))))) } @ In order to actually grow a tree on data, we have to set up the recursion for growing a recursive \class{partynode} structure: <>= growtree <- function(id = 1L, response, data, weights, minbucket = 30) { ## for less than 30 observations stop here if (sum(weights) < minbucket) return(partynode(id = id)) ## find best split sp <- findsplit(response, data, weights) ## no split found, stop here if (is.null(sp)) return(partynode(id = id)) ## actually split the data kidids <- kidids_split(sp, data = data) ## set up all daugther nodes kids <- vector(mode = "list", length = max(kidids, na.rm = TRUE)) for (kidid in 1:length(kids)) { ## select observations for current node w <- weights w[kidids != kidid] <- 0 ## get next node id if (kidid > 1) { myid <- max(nodeids(kids[[kidid - 1]])) } else { myid <- id } ## start recursion on this daugther node kids[[kidid]] <- growtree(id = as.integer(myid + 1), response, data, w) } ## return nodes return(partynode(id = as.integer(id), split = sp, kids = kids, info = list(p.value = min(info_split(sp)$p.value, na.rm = TRUE)))) } @ A very rough sketch of a formula-based user-interface sets-up the data and calls \fct{growtree}: <>= mytree <- function(formula, data, weights = NULL) { ## name of the response variable response <- all.vars(formula)[1] ## data without missing values, response comes last data <- data[complete.cases(data), c(all.vars(formula)[-1], response)] ## data is factors only stopifnot(all(sapply(data, is.factor))) if (is.null(weights)) weights <- rep(1L, nrow(data)) ## weights are case weights, i.e., integers stopifnot(length(weights) == nrow(data) & max(abs(weights - floor(weights))) < .Machine$double.eps) ## grow tree nodes <- growtree(id = 1L, response, data, weights) ## compute terminal node number for each observation fitted <- fitted_node(nodes, data = data) ## return rich constparty object ret <- party(nodes, data = data, fitted = data.frame("(fitted)" = fitted, "(response)" = data[[response]], "(weights)" = weights, check.names = FALSE), terms = terms(formula)) as.constparty(ret) } @ The call to the constructor \fct{party} sets-up a \class{party} object with the tree structure contained in \code{nodes}, the training samples in \code{data} and the corresponding \code{terms} object. Class \class{constparty} inherits all slots from class \class{party} and has an additional \code{fitted} slot for storing the terminal node numbers for each sample in the training data, the response variable(s) and case weights. The \code{fitted} slot is a \class{data.frame} containing three variables: The fitted terminal node identifiers \code{"(fitted)"}, an integer vector of the same length as \code{data}; the response variables \code{"(response)"} as a vector (or \code{data.frame} for multivariate responses) with the same number of observations; and optionally a vector of weights \code{"(weights)"}. The additional \code{fitted} slot allows to compute arbitrary summary measures for each terminal node by simply subsetting the \code{"(response)"} and \code{"(weights)"} slots by \code{"(fitted)"} before computing (weighted) means, medians, empirical cumulative distribution functions, Kaplan-Meier estimates or whatever summary statistic might be appropriate for a certain response. The \fct{print}, \fct{plot}, and \fct{predict} methods for class \class{constparty} work this way with suitable defaults for the summary statistics depending on the class of the response(s). We now can fit this tree to the Titanic data; the \fct{print} method provides us with a first overview on the resulting model <>= (myttnc <- mytree(Survived ~ Class + Age + Gender, data = ttnc)) @ % \begin{figure}[t!] \centering <>= plot(myttnc) @ \caption{Classification tree fitted by the \fct{mytree} function to the \code{ttnc} data. \label{plottree}} \end{figure} % Of course, we can immediately use \code{plot(myttnc)} to obtain a graphical representation of this tree, the result is given in Figure~\ref{plottree}. The default behavior for trees with categorical responses is simply inherited from \class{constparty} and hence we readily obtain bar plots in all terminal nodes. As the tree is fairly large, we might be interested in pruning the tree to a more reasonable size. For this purpose the \pkg{partykit} package provides the \fct{nodeprune} function that can prune back to nodes with selected IDs. As \fct{nodeprune} (by design) does not provide a specific pruning criterion, we need to determine ourselves which nodes to prune. Here, one idea could be to impose significance at a higher level than the default $10^{-2}$ -- say $10^{-5}$ to obtain a strongly pruned tree. Hence we use \fct{nodeapply} to extract the minimal Bonferroni-corrected $p$-value from all inner nodes: % <>= nid <- nodeids(myttnc) iid <- nid[!(nid %in% nodeids(myttnc, terminal = TRUE))] (pval <- unlist(nodeapply(myttnc, ids = iid, FUN = function(n) info_node(n)$p.value))) @ Then, the pruning of the nodes with the larger $p$-values can be simply carried out by % <>= myttnc2 <- nodeprune(myttnc, ids = iid[pval > 1e-5]) @ % The corresponding visualization is shown in Figure~\ref{prunetree}. \setkeys{Gin}{width=0.85\textwidth} \begin{figure}[t!] \centering <>= plot(myttnc2) @ \caption{Pruned classification tree fitted by the \fct{mytree} function to the \code{ttnc} data. \label{prunetree}} \end{figure} \setkeys{Gin}{width=\textwidth} The accuracy of the tree built using the default options could be assessed by the bootstrap, for example. Here, we want to compare our tree for the Titanic survivor data with a simple logistic regression model. First, we fit this simple GLM and compute the (in-sample) log-likelihood: <>= logLik(glm(Survived ~ Class + Age + Gender, data = ttnc, family = binomial())) @ For our tree, we set-up $25$ bootstrap samples <>= bs <- rmultinom(25, nrow(ttnc), rep(1, nrow(ttnc)) / nrow(ttnc)) @ and implement the log-likelihood of a binomal model <>= bloglik <- function(prob, weights) sum(weights * dbinom(ttnc$Survived == "Yes", size = 1, prob[,"Yes"], log = TRUE)) @ What remains to be done is to iterate over all bootstrap samples, to refit the tree on the bootstrap sample and to evaluate the log-likelihood on the out-of-bootstrap samples based on the trees' predictions (details on how to compute predictions are given in the next section): <>= f <- function(w) { tr <- mytree(Survived ~ Class + Age + Gender, data = ttnc, weights = w) bloglik(predict(tr, newdata = ttnc, type = "prob"), as.numeric(w == 0)) } apply(bs, 2, f) @ We see that the in-sample log-likelihood of the linear logistic regression model is much smaller than the out-of-sample log-likelihood found for our tree and thus we can conclude that our tree-based approach fits data the better than the linear model. \section{Predictions} \label{sec:prediction} As argued in Section~\ref{sec:classes} arbitrary types of predictions can be computed from \class{constparty} objects because the full empirical distribution of the response in the learning sample nodes is available. All of these can be easily computed in the \fct{predict} method for \class{constparty} objects by supplying a suitable aggregation function. However, as certain types of predictions are much more commonly used, these are available even more easily by setting a \code{type} argument. \begin{table}[b!] \centering \begin{tabular}{llll} \hline Response class & \code{type = "node"} & \code{type = "response"} & \code{type = "prob"} \\ \hline \class{factor} & terminal node number & majority class & class probabilities \\ \class{numeric} & terminal node number & mean & ECDF \\ \class{Surv} & terminal node number & median survival time & Kaplan-Meier \\ \hline \end{tabular} \caption{Overview on type of predictions computed by the \fct{predict} method for \class{constparty} objects. For multivariate responses, combinations thereof are returned. \label{predict-type}} \end{table} The prediction \code{type} can either be \code{"node"}, \code{"response"}, or \code{"prob"} (see Table~\ref{predict-type}). The idea is that \code{"response"} always returns a prediction of the same class as the original response and \code{"prob"} returns some object that characterizes the entire empirical distribution. Hence, for different response classes, different types of predictions are produced, see Table~\ref{predict-type} for an overview. Additionally, for \class{numeric} responses \code{type = "quantile"} and \code{type = "density"} is available. By default, these return functions for computing predicted quantiles and probability densities, respectively, but optionally these functions can be directly evaluated \code{at} given values and then return a vector/matrix. Here, we illustrate all different predictions for all possible combinations of the explanatory factor levels. <>= nttnc <- expand.grid(Class = levels(ttnc$Class), Gender = levels(ttnc$Gender), Age = levels(ttnc$Age)) nttnc @ The corresponding predicted nodes, modes, and probability distributions are: <>= predict(myttnc, newdata = nttnc, type = "node") predict(myttnc, newdata = nttnc, type = "response") predict(myttnc, newdata = nttnc, type = "prob") @ Furthermore, the \fct{predict} method features a \code{FUN} argument that can be used to compute customized predictions. If we are, say, interested in the rank of the probabilities for the two classes, we can simply specify a function that implements this feature: <>= predict(myttnc, newdata = nttnc, FUN = function(y, w) rank(table(rep(y, w)))) @ The user-supplied function \code{FUN} takes two arguments, \code{y} is the response and \code{w} is a vector of weights (case weights in this situation). Of course, it would have been easier to do these computations directly on the conditional class probabilities (\code{type = "prob"}), but the approach taken here for illustration generalizes to situations where this is not possible, especially for numeric responses. \section{Conclusion} \label{sec:conclusion} The classes \class{constparty} and \class{simpleparty} introduced here can be used to represent trees with constant fits in the terminal nodes, including most of the traditional tree variants. For a number of implementations it is possible to convert the resulting trees to one of these classes, thus offering unified methods for handling constant-fit trees. User-extensible methods for printing and plotting these trees are available. Also, computing non-standard predictions, such as the median or empirical cumulative distribution functions, is easily possible within this framework. With the infrastructure provided in \pkg{partykit} it is rather straightforward to implement a new (or old) tree algorithm and therefore a prototype implementation of fancy ideas for improving trees is only a couple lines of \proglang{R} code away. \bibliography{party} \end{document} partykit/inst/doc/mob.pdf0000644000176200001440000136706514415225046015140 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 5077 /Filter /FlateDecode /N 89 /First 756 >> stream x\[wDz~?bv<}e導 H0p <ؚ KFC]FBꪯ{$ ^ºB!B)]BX. /s7B*(Nu_tGiUHQXz) k$uR8.1qSH[<:-} ȓ޹B"pDEp\ rQСAp|@bxTa cˆ9^c ݢ3!F‚0Mq`'Dи,%BZMA qI fTNвU$! ) >+0'5(4hY[4A EqQxĢeA8q<&` --Z:@"T80ZvLvhIHdXAJQEZ [IZ;'yd o5I'lDr&@8Q+M`I'rp&)BO?jz^+8)ӫfTt?QЩeU49/܉M^5ɴ:;\C *]&_/|5NT}׹|ik^(TU.^Tu3,tZt0kЯC4 ZH%b-:zE,%,)1E{[Mu1muیttd)6>NW ||q`85lPSrE݌f=Kҟ弾+-T/'.nF޴8؂t0gt &&tJћ|^m9e:UWScJ|zz^fۥt qʗss&?nr7&<2-MF/Ǔ8)c~8|#y<3\c&|$L:ྥdTclj|P&,SעL@kOjǘh@?OHCx6:?4Ğn;X.6)q2kOޫf\٫oJN*>'ԻtGq;}Bq% O!d$o#Uv䉒)" RD~LdA,H)2EU{n7./:SyD"O ޲4O/Iu¦ai"6ja=&ΉRz~Ya`{΋cRtF_ KWTX˨#o!Q(`aX nyT8 ~@3T$؂I-¬y~D e,ĆȤ\OUȔ@GhL}Vg'?Sv֧FRA4vχm:M;vȎ]vg?!{~a=aO3vž7;{^ ޠլSgh2ߋnX5fCv;3zvΆ հ޲`c6g㫋j:l&p.r&Mcht'X@tIS NG񉶐tqflV]i,=ȚوѰf8*|+v5{>?t}*wNAqG,#ZA9Ts=TAyNwQd!stw\f0p=%Sd罣rd4Xr^\XXQ׭hvYs+*neE3[}WS΄3N`;,҄Kť ׋&M4'hBD'eOju 4f%J\4t>peH~[p٬bU悆YӷW^0vX?|fqFYL\jӝ6U2B< I+$=y O" -빓CL>ED*qPrMQI9uxWo֏}yvYJ-z,Q;oFu9~h ]INbUO@58jF94j l-ݼGYiW o{ND $&ѫpDrJY~W@d$/xIV1e_l$ ` ŸU )*;ѝ ת48@u㟜ZO7/^~'Z)эpijKl&q7n~n{gѦNB8 ƠmWWߐtJs[DI#KU&Ф4O^xiܜ7Ar0XvBnC+=_5]ɋO=hQoBlP\! l$RVtJ "AEgp~l'Wvn(7$9w^ j\Udo lLD~B55hGGwAQ}z!/-$ZZl+8- o~M*pk2ms.# P@n۸F[F(,@'}hr#> 1np L-׬d8pkO&2-hm$%˓QjK0q_JI!ӒR\):OJr3i_|Ij2jzή: "`nm⺄ōpL 2u] ȒV;XLekt t́ɀD7%mD  JK[K /̘uI߀(gJڷ:'*V'+Еv%mPTRjZF]*Ȅ/"ma֔ t2^Z%!JMHAAL):$]H Ih猙V6X}AVs< EkD5IBcxCKqKJe~%m;4&JDi+K/׬ Ӻ`$Brh;+q߆( WBs<}Եy`̺ %mE"[Qt| mk&pv҂..}`4PKqy a5z_5u Ex=kxVkx6&8( o/ve-o7ߍKm7Nj-KKta{zqm=sBzy0Ѷ[ږ%# 8cMr{ DB9]RÈڋz|5%_NEJl?'߈#~]Hd4B&ㆹ9:'57g']|n|!sO w2~y~4~BeM\zSPR•ogՓ'r/])f]ݼ}^\hyX/;1|Y' w l@K~mfqb;~y~;y4W>K6双=9|R\N'P9ö£f<^|=Hr\/-'I1ҕҁ(F">*bAHv=fg }0#ʱf=׾؅jmihϒR4-í!';3A/bY hLAME-ƸO* ]m ޓA5j&l'}|_4/RrmB4w+Y+PZ•RTI=~xzN F(x7%9%NqxSNq-W[mhdkBMAYObgθg\ѿXπ-glӛ*gd@PO5;\̰.APrGh|"cD(KP;Q$Jx);IJ}̕ Ӏ~ Xao2~*[su8 qS7%Ju浀~sh@UgÇi*;6ep(~IdD?M3T@,V5ƕf}ghEg -:TE~o\/7pN=.K)=}7AXȘka{*h_Ԉq05J]\]M\]NsIjFFɆKRl-lp)8 ~G*@G%Z/\mw #եWbz-/H4h53\r{pCi%N8A %vF<r_)ZirF8@J5A_8 A.鍴0.n+ܗA<MUz?+V}%DH Aj }UU'>}[ea'ѿ[iTz/&YSˇu3YhZ.AP$- Afմ5aa"<&4GOB(x䶫Yur쬚VcZ#2 86øVڙF5eMUe4ܶ/2lz:_'yeMh[MB Xq1Dnn]L!endstream endobj 91 0 obj << /Subtype /XML /Type /Metadata /Length 1568 >> stream GPL Ghostscript 9.55.0 parametric models, object-orientation, recursive partitioning 2023-04-11T11:36:36+02:00 2023-04-11T11:36:36+02:00 LaTeX with hyperref Parties, Models, Mobsters: A New Implementation of Model-Based Recursive Partitioning in RAchim Zeileis, Torsten Hothorn endstream endobj 92 0 obj << /Type /ObjStm /Length 2887 /Filter /FlateDecode /N 89 /First 811 >> stream x[ko_1[Q5),ץud"R{) C]p=wc2[DvB'-V'։E ^$fMBCvV>I'I9a+/7A=n0.$Ll&Ik-zk'l ^eÀ:3Q8 sp7Y8g \ fbp#\JXE? O)hㅷ.q>= |M>sVC"Sōڠ1 a@X/B)yqC$pN9C,1ar9@>ΉD!i&6A$y%M1z0@ވlz+<̝Ot!!:͙={"Y_>PiUıw Cy yFHR $ ;roEJ Y$TQ d"ȥ![YBoIg`ɧ[ҧq‰%T|#|?ᚫk\߉|ghmSӶ:O_}>{ JN˔k|A4=Uz1#{}=zLT,÷_jvuU㱀^b$?ȳ._7oF~y~>^~B'f:_fUlrX>^\^O~YίiJ .n~^ġ;8?N/??.l4oqIJ",j|wc)?Vէf'QQ:lS\l?x+MN5/&ҰBGƟr<\>]Mkt>Y,@_0XLŲטXp"o/~vGOYڢqt>X) ,@K҆B%ƝXJ$p'f<泺ZwFUOTf6Y>dj.n*{hrkj-|VQtv$}=ܩt(Iksr2OX!j$o%ClHҁ̸蔠>&ᕕ \ un: PlRDa PJRx@IA*ı.gqK.Wq#2@&zIlrD`i`8z#Ja)Pxq@Ee6U<;isX%S -@̱u|&r#S42aS`B~NPL26fdJ'唒yA#3`!Y5C3i!] ӵW{dԲ! #&G]d;b0Mr3F9ns&ڷ^c{M۹0[nmcL_Dse\l_;5OMly/595CW{Ex5H,uƤbzPHpOU娠ymkyqޠ4Ud.71t|Xg7(0 ktWN`X*DѼ P{#s @=(c@y$A4K f*Yx1%wmtP;&yxLqn *: dF SnC[$HOɨ!YSc@8  y/1&} z,jG+50Uu?׳j1R-?^-egkoRtpMõCfw-ȥ3[~Ӻj~<QZoEjxeJ>Rlͼ/=gHfd{w- }endstream endobj 182 0 obj << /Type /ObjStm /Length 3732 /Filter /FlateDecode /N 89 /First 833 >> stream x[[s۶~? qt&N&i.>rݤAi'JrןoARr([nQ qw],eL0 ΢1#Jϼ@[,j=a)/Q+(Ԩha`$-SVx;ig0jLG1`& &$3:T360G2+,UZmAf-P"2KS()FtR1'p͜RЗ*4t+q$ht@%0Yɠ:h(lY*zPEY9D-5 ,GFM'c%lR] [B)h*KiYxG- L"J2SpQZA\g0 $xK5bd9 /e0.i<̡Z${%DH1"jCk‚yX̡aO+Hԑ҈@+9 :27Ƃ50I@i|J0S[BCZZ159,Q6c$6~`d2]o ۨdOЪ!tϊ3S/m O gx Oof|hCd!ͦ|C?/0?:.r\6@%H]*mUUz9#RVxٰ5/$ MEMZ2B dH[DVamh/~em%6vU} NVJ]*mU{z)Nv;S>x:WWC~sߧC_/ /_ $:3tEYf|'<7/>_\/?/3NEo,H~8^`sP.GPoU ^C~XsؘZ)t**/q1z<x.s{J8/_ɶX5oÓON^bd.Es!A''buc T+:ZPʥ)'&'RNk5a̹A$ KAv${75zRVO`]h_܌A5 ESrۦ}mյ˟4HۼlyOUS`yB.RKKM]d7tѼb6:+y3o藢R*:,&jBlhhtCXѭDDFz@6D5EyU"Jo޿}s..\N%Ԯ^qK6]۲oHR"ӓIqs|տSUM|ݴxX|11+.%dd{s M}}Y'm_-;ye! J4m%!] m/ 彡7̢ bR*65$ V&+NNYJ'Bx<(UgY󓙀> QWB):2ipm282 }Xcɫb򱆗ʶC\%7|F?Gjg7LY+Yi]FnTPW0mfibgQebf iI71Y6PYP)Qł>cL'ɄjaRJdĠ40LNI:Q)OZgN.*L(0\%%OA@e,H[(hX{LźjN4`U/qg3cZd2QڄE:\ 1s=1 #V8/h%Wu:pu:WuHtݟN(|]ǺXo ޿b-Pn_=^ziX=7{]r-S\SJm [,^a(D!ٴ/jNDGH41e}jȶ$>x Y6x<,:-AqpMqOl(⍫wl]Ԏ.&J}_5'X+@磢((e}QrT):OpOgQ|M2VBՏby=!pو\!f܌*r3:b-<)c)g0>;7p~LGY^ǏGXjvF}!+:(ܾGԎ&}TYV eh *ҰɃp^ҝ1i܍B0YyLw6n5 'R1Ր:ɠԙvftӄH}2vld4o w)դBtNk"ôo s,)fQ;t%ĐQ7N1x^|.'lJ(p2yPPP^=0 dVR6;aaSZX l īxwR+OBHZ MO5萨iЉR^.S0&_l94nK+H,r…Ik߆/zBa{/@QJ®#4Ddb40k|EK ZV". yd·dNG۠*AX(HځbnI2I :"5mB1 {I)3 IpCA*0<܀ 1 (,d֠$+R ( Rp 3 jPZ̑-AiEe CՆ"dB~e38coPdVD0` ̓R~Pİ-}c#7tM"gd싉a[a鋴]0ݾX>@9WZfЇo#Lǭ;{ ?E}MF'ѧ#oq` .wig$MMSzk~r؎?XcD.p>.OyVͨ~5ߧ̶z@sGCQ֬Hb0?7KGk/2Pc -WXJYGZU҇] _f+b =-Y>l?R{JOYlrzOex.Yy@:7yOs}fӈdli\`ßS iyW=͈4w#{k=z]endstream endobj 272 0 obj << /Type /ObjStm /Length 2768 /Filter /FlateDecode /N 89 /First 820 >> stream x[n}WBX`O`C."F )`9ftShyaU$g|C@mI)%͆ 4?L&:ުD}j>l~Ur{2==lk뗧vs{9rM}Z5;U 0>) uLA8׾ߥںަMǏ￁?eI6AGF|TK>A6iRgD Ҙڳi]7>ܴv5ӷDofKf,¹-wĿ > WA B`i+ J o8܄. B_3bE(-AD^d7 g4} .n5q%ASWF&sY0:b@ˀa@93-ymi^j4-[Ćز؞_ <ɮt`ү`5Jn/!g"-@HI6 X sN`Ή0֏qDz5:,T0xm1w@R[ ϬJUuuLB$I`ӧ@<;93g lA0I)6Gr 0\ ųb9(5=w~%,1 y?qz&rL,R5zPz2zJa_Tc_NTl:}X8Q7]ɔ22dh|hv>|aK-Q6$"z= R%(q""ĸKp $bz@zz8qHvâ\"ߣlCzIR_nf~HGh UFY^j!]~n AMlT`=g$ūOf&ǔꇚl|.#uD(1d"`u}9{F?",|6DX[E>gQt ẩp-$[G."d(H{䜒 )f[AjA@UJ'#JM|gg%X'P0E0:bj7K݆j>vjéb O{z!eZjr3MTA'ıLA)0r*zOssA/ lzx2\}' >2TN)n|\sTG -DF~m#܉jypq >\K3viV;GK!2UEamh"k"a"zcN]v {>LH 9?1GrGxn2\a֫ q) Ԡ4(P'P a~/´ϡ|W;.!H?uyw2!zDu b붩ƄmTgQ-l#"p GnB%4/q<됼X-endstream endobj 362 0 obj << /Filter /FlateDecode /Length 5356 >> stream x\K#7rIm1-ݴ>8!#lP=;XǗ_&PkŪW]V{}^ Ja+"V^Ftrhׇ_ Af;iݵVռZo3m'DNY)#|c:~GXkx?u _7?;|ye=|{7?ޯl nMa÷8Oɾ67[ Tdivi/rFX)BJX$ժH(m7igR62뀵`럢1aoH| ZmlA7Z lM?$Dîi2wA J =O4L9ܯ 4_>f8=ÂJïͷl؜d? ?nҡU>iغUZ ^"lscI۾x~wF[6DYv/XϻQ6Q~}+ٯ CZdpe_}1M m!.]h+#Aj5ilя.yJc'9 *fPd)߼~ BbGV|X!&ڞ anP |n>f{AoPCp>.9IsL&,eViiZVr?*Q=.z(8\~}QLmH#>:U 6Q? ({Mq'Bm P m(i]5_ dW7bZ˸67<| 8+7K)@yR8 jǴPx@.]J.,9$\6 %L7 R- J (Ei{8dB_a-g%%FLQ l OuJdQҴjQJ(Gc( VW0|qꢈaIY:O3{~" g^f$TT_FX?N\Pϱ 9@4{ӹj! HɘQc´SKeDBW7`injxwFuuS t!>ci)ĕt6vq "!lDhUF~ e"9FycUMs 6,f|j{`Un7n%uAQ@߰=ܥJ`ͿԦi';vp v4A.ZǨ`)^ a'\5PBT_I0YR3噝@)j}C`5aCVH@_*Ɩb}ò(2,%%'wxe>TUIgs3ű(^( 6JI>*,R[*ٟYhhYCy̾L`(!Q2zD(ƤY Y鼦Ory]U+r q>9BIᑕ FrOuI4PW:`qRK,NPdDE_]!=g)Z<gX:Pt^,dPƘ48ԅ Ka#M8lm {xX VD+8=3BL(IFM6VqIb*-,T,5v܃mBcϛoQktYЪXx.? yFLҢ~<㮝Wyc[ҹoBya>C%ƫ RPD~-jgB{XF(Lu"tގͷN3;piWe 50k jmK0`G:z F+d~:Noy2H-]盗XD-GsaMTz0FY1£̄*8luJ[ ]vz"|NJp`ݣN]>Qc%=\jQ *#,5ONa:I鲖fJ+x&GȺGVH#RV'"Q+Ts.a?T=vurj;gә0Ȍ/8eW1$Q]}9a*ԠKRVm{2 (Qkla_q(eZ#Jqr=I:mơ_[Q7hp+9pABIX|ߜ`5LyL= e.H1WYA)C̷p#xa6W؉A{zc%Vj(|*PK}}F~,׭k'N\_e~&K RPה^ x@q%hh,=IGϤF$Pܼŏ닓 ȌC:ZCZxqlVQԸ#4FյPCRGŌc,rhWsX}6vRzMh'3c{X7}N*+fn!Ps PKLz9֪&z.hcX9!Z(a2&~[OX\}/:=UYH(}nz:k/tR#9λN,9ts~Ӂs_AΪ"AlQX0!,L^Aӱ IF+PV)mڲiYT3<&/a70=nZ%dcqDdr')Oc2a\Jb귦 ρfl=,gZD{Q@py4E'u.= @eߞʎ^p2.9%O0 yTO 89W&G>$Yt9GG" J݇Se4&~Ja@hE1B'=ao'6uv`TX62ښXIhٶ9+^T0_IKC9UYjrfVH:bT,w6 3FT $iۥZEXQ.0`Im#ӏJg^7 yƱq8xp't{-1:F09 BGZ.ieuyhRWt-AUNܦx?iMNQFNCM bOWMAO]@T@E)0ElGd6Z2.jυS4e05$SĊgv#l_! nIgw}NxH<;S+aʴlL,V*Y*+KDrfv^,t>ҍwj.t-]ÈiӴo3viToKOΩ[H'7ƻQ 4ĎaRGvܠ|eAd&vaaQPܺ$AAh,7wYTKC`˨y{2JM++!!MwbK?\bbSRQ@ mJy/ _\.C܈.p+Cdn| \h۔hx1U#O64׿`L:^i)X&zwKꪴp荐Dc~y>R|3B ]>'[;e}5?)WX1uŒ9U֥u?$ak|DCaF9n.̯ٔ HTYޝ s7//8O ;ī`GNZc)EP؎eBȻ K3>/!!cԕ;f?-x2[Z+:?ݝ(yxInE^, lJ$㒃(J=#RIZ~$MgzDҘwYQr. C5Z\ ΀S>uendstream endobj 363 0 obj << /Filter /FlateDecode /Length 6622 >> stream x\ُ7z}Եś pb^Z q[rW[c_ HV3@tw?]t_Iwq':\<|ooqq w^\8ڠI#7?B[mof t†k;Bf?7~(y*%`dmëOgqtti|C_tޝwk$]g#\a'KusIYlÛls(lm[eZo-!mi42&4A V_gᄴpyq#"|zZŸo.&N m:~>m. p~;#pZQoLUТ9mzsRCmvEtWKƿK8Ds9lE| $(Z?h+:}>hXzFZ5.^68~7[< _APőOpeǴ8 ysZfwͽ)pS/Utl VU|N"޼lPZKxsx] r ,WOcLk iimh %1%@r9ey4Uq r^[EkNDr(iUПb ?GI8mPhW347L,pn,Vɻe>u"N|zCɑȡC)dQpq}n;3 3"nG}2x]r+'F+h\!( Z`Oh+a/VT' +ֆ=l_I*hFY]JY|k%Q))& rMNh=R#J-؀ AYeUqf{@C1O?ɕk^+FMV)_W-b] w쭜W{!C|1 x dbVmժGA)Zu.6a  4Ā w>\1 nHK7q'Tgzܜ)lB9<"8Jju@296ywNFxh Ih0 mv|?ZbfG 233pXf)+/2&JG=:,p)S.|;h N 1zCWl<[lhX7*}A4_ͮ1 ޤI ;$2,%y&=|ܧzM{T&7w:䟜#r}虵4HR-N*Zh'@7aw>  FX>K sEW E):6Piɠ^[ԯ[ *E…4 xe *^\> c囇,`rI[d}x K<Q):GD{d^υh]0)zvH,*y[:YKBpqڭbb\ظSt,r!镓ryPxP=L5U*{Թ+6E»q8%Wp|09N4*]5σ|UwŸT|-\om䨿x| c"P CXuG@?rFz5E5&nO+:;B{((ĩ?\r>!i)MltmJh5F_A o>lP󛴂rxJ`4K*Ms&I2ٳ A.) DŽnO py]PLp&_pǾ'v{U4H>BW8ЅSnc|>p- -5eP걞n<*ʈ7" n$ :Te[*h %fX>c xY&h5PL"4):L3XW4GױUY@ AB58̩a! @{<}qXD>;Pi [H2Wց.)ƃɳҁb;xt]T+·c=/Ǜ{/ߌ)TƬP5Y1 EMaKpN5 Oi.jâۚ0fI3OM,L!'zST N &e FLЀx0 #~Cգ9y1X3 _ et*!J 2gw s}QE?[UN/"݋uw$Tj{Wɤ8>!J;v3lLEYGPw>3{wE|ZW'/n9&~\8Zl@F!ly١%ky>~ yER<[X넻Oo ^duK? ˭Ԭf*CNµ.t} ٍ"9>?r̥D\%rQ~M\ F+BTٿ` 3P0yl k w`[GrnL̅Y\b,n̯0af~6Ϫoc]kmo(G|VܠhJs7`k퍣kc c knN܍0\0PͽSݢ튔ad\?njYJ-0y+mCqZ )"@")Y"vM9õG1 Fv'u-rEY?K_5 BVjwFX<-丨{j@k_2BXQIa{JHN!) اȈi 2E) /=pN*Szչ4<WyrtJ>i8[c:cD:M4C'f)ѸE=*-$A;L.:n,X]Ay 1_ @ED[NE ɐJrDu#Bp )}E V, yVVd(6bYq׌u O}Q7m.:t[pYͧ=7HW> vР+Z#A]_rG]kb9XfNIO`?|YPKrq)]Fڠɒ5|1J,Ңc 1XCw>̥L[5R@ir<}/j ~rvMd_ }D~cѮ_obH¿'͇_$+S%6a8JDdQvwz{ ٢{j_.RrHb;l%u!:E Y֥@3>SipoNT$eWz!VUmL:Q0/%6D D[[/, :G01 -DQ%Cr&aM"JdtN [`MW2WǒW>e{āy^{Uy%)jjcZ 7cn|zgЮ)sZrn5t{f1Pg ҄ϼ?=1 UbB >8bx;8FS|Ay>REFՀY-@48UpH_R몞e%*nN#}>f*~ؠX|| 'FԆXW=돱հ鐲4V3τW\tM|$ @__N4Ar9d%HhdA 3.!38W<ԶLcUBhY(̎C%q02%X|{hi3K(5hxy!K=7dG]qC^HdBJ+ eg,sI<,֤vg%M+5It\4i}%Y`3Qf)PHAqiD]4eO$Ә#5-D ,' jLO2 cAH.\Î?ҏ۔"XЗC\{w[-7u$}Vu,xO7M32[3A0ٗfa() DAg1xKiD`;` Yg ,FȘ] y5{g~Gk;sz^<^Z 4Sph37yh{$kƿ*`/ڗaU\J%Qp=n*`.FzG2Q,iVRaytSSaA ߱O"}?Zz;55aJQr1ͳVm (LdeP2܏N+brrG(Tr|)X^#Y#uT â>S`cOZ ܩȞaY]+#nRks)OOLi`P6&a( ybhzdAˡ+<{ -苉ɧyX)6]obj1V)i~ա:SY80#"-c5w,`Ӄg @gFY|y0WzPB$z,^|hD >EWd`Q6QrNz6+ }kjcY?,xJ}FS|R-DWuڡR3eT,_R>3*ŷJ^9y@@"検+%={DL;di6ꅶ_x7 TK]^epϞX-HyckX۰*tSCpuΕ;W;SߎM+4 ɢ 3J&~\zqԨ}cnWTʐbZ6J_%dǥ)➦.*E2$yGŨ  ?d:LjqĂVRMѪ9rBDW~%f?'][mfۓj-`o[1h\Ģ<Ͳ#~TOwu*%_=_zZ]D@P h[;"YK [@"mpczztz&<~8(Hļ:^%L(Rɓ'0731N6|xO-ΪL5CDrVBӮ;ӡi679IPzB7P>Q!L#ʖw ʰ> +qZ:J[#k0bz18hqT'sgX~AOKe!F4e~̣sEe!3ЈoUY1iYqURLJ֙!H|__'n\8Vl>W&i<+ O\_;1c=bl*y-Hѯ854D):Ő%Ųz,iUCrn''g!LU[Q벜vBg~L X~XSAOى mg {n9o*(:Ǯ8^5c Kb4 O:aütǂ.cAaʕPO9 iƕ80J6grF֋TZY[~'endstream endobj 364 0 obj << /Filter /FlateDecode /Length 5838 >> stream x\o=]rm2W pv.p$:ܵ%Y;wZOUfgdkbX_USU7fuㅠnշ7^_Wʉ5ʬvu {VZX _^_J#Z_^6uc. ׺j~ٕ˵RFV߲7Oq%7RnLWUw7f@/ m6{|I]IJ6Ij#LdmZ5V]]ғ圚zap9]c].jX.KBvqk*%ɪ뭪fmwoj>"pW= <҂53[{]FhS?ZٶVH ֻH*g|nRNylk^Ŧ5Xèk ~I? ~&PC3.(3/*1ւu>?ñ-/n{?%ڥQUuDrz;>F%7@~sWʅEU.<ӇnMI/muvl#RC^IdfJwr`ւ 0"#QfhyLKj}N@l}-WFVLnNM{fCR8ݰ g\TTVGFqu&6dOjq;}gۖ@^v}?lE͜Kzcp ,jL0YX'lr,eL E-_v 6Ԏ7ovm:u7,|Lq7C40ҏi4q; EZ0;sr'뒦ѽ P1vXlH!X /ԍ !sQ4-e#$"tvRq]7 Sx|io@ d[QdL#Oq/8>D"يhv1es8ϗNT@<&!ZtQ39knG?ie1\u+n%ځ+pN*D0_k+'pHH&Nۻå=q?x^JJjdt3> YKUİ*Sd^`Xx$bHkضMOؗ/d1kq }ao|gt!v&D-{}I 0IW=%D9_fTv wѫ_Z@.WڙX}nOmUja2/mUvdуTMd`ptܲ }-ic~3Na$7*)L a*:  )ȊM}<Y$O/AdC<7dlR=K\\IA$.yS4Pe6u臏˷y]d\-!_qŋu}׋/1#Qڦǧuy5mm>tU)m't,c'R pX{6WZm_5h[T~DV-*u`X-Rŀ _De*Zz>yϳ0F!wDuPLàESn#oAXIg:A5y# c_l/;=mL*4^OE?N.佈 ,]-s`CT% ? $N ub \01yoG;N|9V=%z 7deql;fTw}>Cx٢r şsݐc`e{ HTIo+ cMB*jh=]ښt 1\䴭De}>댳]g%JZiVK@oې}sjD^: 0y$$$Ze _ctR_fJ[feBYROy tgq󉮬Eg,f6(r!,iLWO;@f1|L@8,(Q5Qf!Ooxchch[,6?PGiY81ų"v0u. s{+pޒpZI [ isl.g% J?%\Ni夭Hh)W鳞a7sp)K\!F/֮p8 RB}IxeS$u$A! &d ʃ]7=Y]Ap\kXDtc: 9$^bB4./Ф>@bTu/Nχ#kf<# W>?̋L=-8_:a|C#< ܑ`64n֑ ]XjBhЖqT _Va-g"B`PÀ^q³ %c8^nV_B?SLCV mT7~Tvj$3lɫ8鶏>ZzSO}-:qP>4cIY@v%SON5!_C-,ϟ c_S_AgSDP0XCi<=JWSA9œh㼂I'YߓS'J般Sfr_H1>>.ϝЅswgT|$@D-,N[Aۻ-v=͖ m^;*__n"Cp  ծE~aʊaz<@!!eB'_D03+4D߾$3טsCt?0ΎSz;ٺP~,J7:ҝGa{z& Vg\-Qi3B܌ZQWcSO-wCal:]7s4j]yMC#aB{#CĊOj&0pjܗT#y?\K?`MS~XG zŮ+{tg4'?aҼuI,+[0J=Cgh"$A eWq'}D:,G9Ol5ǔs1 D0&?x[- { dbo>9gRIb=[REpH-$c_M(Mˎco#7_OQSK?@Sį-a;gAgp,,`qXJ5veS$)ia)#buHTW~sa{>~'a7.;8X*3qRĿ\gtendstream endobj 365 0 obj << /Filter /FlateDecode /Length 5839 >> stream x\Y8r~'kOJK+60z0]GLfeMfQvAJ$%eUu`C)% _ԏ]+;mϺ۳=mϿ<=iC"Υ¹3 ʜ_n^7߬$J7Jм_umg]hՅR ׫ |ⅷYoʟܲLsxL :VwGws0`Zp:WgY]~v8P0 &i_zԪgSxrE _۬3^3 dhՅqǻbc lcuǕ{Qnf'4[qث9LVmG>a\!tȦ?xM תq}yB9EE$)=7)Fthn/5>1Mq#hЀ#wFRI:܍&5ײٽ̈́pU*!D@U>_:nV؆w7 ׸Alt J{-9hwU"9bh2i-Ϡ~{y3ֆ|LZPa][#Q 6vA" 3я95"h }ݽ](s58dХ:'AtA ?Ah?x`kwS^!gl(B"KosbLsC;EI&1+Zy!{]TIzD Hu7+X3hGH ԯkD>v۶alS- 豵XofՂ @":O K;YFX^Llrn#U wcFWSՂ'qOs(A WLHL+q"F &:)$GGI7%Tbf(0S0 .ŭd,}떖QG sX 8`.vsqu%"24\ rφZ3{TVJ|(<ۿZvNZ~?cx|5$ois|sT SXCPcF ̡~}D (Du_tyB7^#@+#="'WT<lUĂiQ)CãD"K H,9JUH"9TZsPbp"cjN'K >̱*v N5`8T^__eI7M>M[hh$G`fdш7lFXɥ!rޕ`3݉=ZZ @.y PܞW7 @ܧ(Qrw4_;~Bd-F?9 g 1T:V'\U龜&mxf-;yO@)I9/Q0vRc~D} FW}''F?#U# W.^%+L t3)`Hi{XRT'J bσ{vsЦ#3V=KΒQ-{ҝ"']cz'xT I)}.IQHidjOiRqJBaBuyLJgcKca=[ƙEyPnck6\h0SǕ Q)`l3cWA?&D _DAh'8N4k( rGS_Fp|HSpNJ8ݣrn4stCt!-EH{jNs.]` 4Gr/*P:ͧ4x7N~ETog =ҞþQ価a}-.16j>k2h4BeIW^ɢ$u, 5EnY>.Su0qnOz4v MgEt䒀?cv¨@?r\tا>+okZ@bw^D8Q8S"AUh-ǾTWr/k"A SyPypPpD <%L䁥Y\0@,ZS_U&AѡEخiNUA+?ML^ᬥ2`h!/ln7UhS.ʈ#Z OEC~U嚃 RB ܧ`)BpBiw &" 0e)_*H5\>ƙy?*T/d]m6/j ^)N1)dUQâPeI3RS bqڰ'T~yvʰL&Jg&$ 5:%uи(d*l&t|).G"YMU ^JDiNf ?9 a.0氋0G[{IS{c+>/-PcF *8xQ6m/G>aDŽQ|UQ8x_mX3O?f%:*$&^P~Of0J-FBӻBؔ;:Q8JK&o e~SEn[7C"DP@[e6ֱ*ƋvÈJSh'9sB$Ib2:$Ӕ5g+ʰtC0Rqr]pt zcR[- k9d~#v @ jAg*Q;xwzyrRM*fT_ 8v]F)(, OlCc_e aS(q55'#ߦ#dJ ]@arh ge_dkS68혉!4l<d֭lqX4W~&I5ppܯ` `SQǣH1K&y 72@^nj'eM m\q-!Hf8hBɓ;HW^/bYr ST?DzfWӐ %|&Hjmjv1o]]ߏZ0|Nk\A&L ͚SmJc8cŗ-zP=~j`,ײױ98e@=#ibˤ>*~vxN AW6)g Kcc*pc߭UckYV;5gp"':z@tV Ue%2JMc#G&\>+d3nZujaxN9 fCk-we{c/ ~`Fs!F0@ö85 r+š2"5i%T3o 7Zׇ/c+}YXyB V YC<ǔh*=*nV_|bYчy0^z1`Y7.Sb>V|)7+W+~EbP1\Li(ס?Flv3_&#G_p[:7z)nGK"OtvB;% ;r9r3Cx/\'qo+, lDpc+te%/)Iwm&|$*NO岊cٌ΅(/߈ #'NɻM9CS{G(z\,0W:Ԝ8j'.[D܎ցءZ,PϫBrWK'#=Q}D3mqAKYO I'QfQƺТ4v*Χ}WInendstream endobj 366 0 obj << /Filter /FlateDecode /Length 3772 >> stream x[[~ߐ!/ \94AR4I\#= 9CR:(Z)r*r*w{*VwW]1zlx% maVJUV*cf}"i,D׷W`f"/(Yaz? 3dU]oU<{|?ۮ~\LGB慔襰"ھH,c4v2y_p<٤1bm2{m9r*7Z;qХIo7k*x6 \IWUe ˲ b/.N kB7:r(->Yͳ?qp Sz CqTVk!i&ʬɹފ =rJ"x -b )ågn evnǷAeu yCW*GqkFyo)cMnA1%8JoojYxM&o{-~_2+XqbD}"<ح\1W1SZ"\aDnr /$9б[?A@Kpb9 X(^Gzࣻc;nwBoVX׷U?_yÒȗmT_B7O&01TR$u/O_wH$oVI$U-\#@ QsIV/ &]O5n{`z3h2ޯǾ ɦRkHЊe3;/mmT;h<ځKM=`4I0NkmBa\27 nCܪ-M9etcjRc{;*BuElȅ6M ֍`(%ѓ%.&9WSOW>;fcW7هtjMɼ 2` ,=atX@ȣ^Hb w(2K^Cϒ"7mwfI3kͤ@`Jz 9@ވ{uP_M=SL`^ 눵<%A=2F||ĖSd]V-5xڱl,[LbCI\=$ځŪ^"l,NdN֦S>%`\G if]N'9Uya'G\ŸJjEo58"L(sL!ެ[\3[jpИzKF#1Kh %#0G`^y%iDQ_0R3R@:Ź.VBBUҜռԷ?f ;H<'.=ɺO-ipKl A}u2u쾉ߢϔe !G"$*Rq`l -MNjvօջF7<, (7yqbH-c--CE9:?S0_ȗKJ%hj;xJa{TQ}[lnEݝ8-1̀6K i-J&m1JPqK"Uߺ9\l0Źʜ^` ry'7>f^%OK>Vz&ȗ0_\}񔑂'I"<ҺSe@ H/#`6aႌfx]UYRt͠WxQx2eíjd+W i$- g/Xa,MC ,ڲDQLqw ZZC N:X\7IJ`u2UB ,&ƗRBsbTLJot {"rtOŔ/ଃg.:[}S^nbd)-d3889Q41I\V dVgTpoҳ.]q,\kNW!XPI,M[8Di;T D^@`tx5WmPrҟxIOFr {37gN::U ,P%UO6NTyz+j6OS )@^) bJ/Íu݇[:*{tE>Kz˛ȟnxW~x.ŦX_cwR! DgG+a7\ڀ3÷ m /E)D`L꤅dR,.l_R|۶endstream endobj 367 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 8367 >> stream xzw\T2 j`KU:HU`(Ô53^⠀^bOԘDcbԠ&C6}}4&19s^~ֳ6ʢ %Vtw 4qWKu7P ½#t_mIC=,N {Њ[UFkPB`w^a'N2~<;5ve.n;l]mMX9vU`$vT`mZ N m;;v=Oz}(G 7ڴ xaȢaK—F,tY"me*{^;}:_[YX}!oīkQJ7I= u 5pӃ 'Mfm!04jXaéG(9q䒑[GƏ<2*r#ݫ- Lh)hso!.SYJSՙ *EjvkNm#Zei7NvY["J6 eKpYۖX=&$7X.א5kq-WDb# WSϴ,glrz K=Deh-ƙ˗rX]&Aeͧ)2"=„'RjSת1Xrষi jul) '>5 l P_˘ho<_/+OCiJi ZMR<EoIHoР"oت֧e!S&dR $8Xo:Uj2Y!]tɼm2\f~yOJ]O~]*Etr/Y{% aa?eZ|t,dpefQ֓*]ɂ3h:s UմY˄%^Jn&5wѮBHP/qOw XX)3$N÷mΰLTmIpK6Ir 3^D `V {qts Z'e2] )} %Ő)W*!!hٰXxzOBHYGu&4٘V/>\ gbH*-~Iq#S]zd[R|@g-NId3 ۹y5q堅2~kxlɯm{8;$!d,W̞!ܯ6E d׊8(DD3 'mq4l,""P??GIx)E>@,VF,f0#:l~./ؿ:{sW1 EEׄ\%^'D;N{Lq>f}21כdxZ;  ̼UFݯNu8 DEv@G=kici(C$EF"̒mh)AW .} ;b-Q? ߕS嘻$1UQI~:V L>~0'hY21Iqdkzy,q. (>c7 ʯb6{{Q*_LdATʽut 71&^dً,L<*C#KE͋MW>{{۠,c0;sb-;&J `Ug/*>H\9* }gd*l0/ȚUˉ5 J8! # Sh`*_5aIjR>gISCMU p!i|?4 #iF.5ȝi9ݖfW↑_) 7pB.dՌ,#l<KT.0<u-kBq+u;!,P&^#nL v7[y\VE [M7%@BNh5P4hS'l(T6 HCUh#sQpt*K#oL{u/AeQu|EOe?49&ʃ,BC 4y57m, E[TՔUުUͭY2Ozjj!a;#zr}KY4 R~E:wzϰhX];YZڿ5  Z6~ 6N=Weh#kz(a+ -j:s:BCpG\$PFFr;K2j |}a6qĥ/ 'v](mG&@wݹta%N;b( vUפ4E1KԨSF` AN#WУ#$o4] Y6prJ%WT)-ELUTQXdxcϞdnNե"޲ lF[XMA%9"P%xn~4 Md%WUx&$xs){6pw@'UUR֠W[- ФDRϝM2H$6xk+`0vuգ_e\FNk \i)նJF#h+9~/ Ȟt3t!#;,zĪO#V=Fԅ8׵LRm2*:MXKmUkWVr?7*'CFc ?D3ʖB <7m<*top,4C|rݧZvƐUEfKQpW^_ Y䊒4(?jEP)TbKb:=UISpڟHL` T 5@Cl~:/hY4z^uYL7gHd]Cs}! xaŠ"k **tdU_ _,8o;,~/ HMlX-@2s +,ZEh O'kr8wAEBygbZEs$ u.wNX Yh|S}31EP߮;]WVQsoZ ꈿ(.k lVkcC*d {Kn[2A+S'fVx$Tx^Q+4ėyY5>a2ԥi#?yho=>i5|edoPm:lb4ѫ BG*˱_ ˽A?4tcsi[7 ȍCRU,M|<;˛v-}RyfǢHoռC"w?Xكj>5vW52M, G䉠 ]-Y(p@r#%Zս_fe3" -U78!->myd+^E_=t-:Gd`HPE=e5FcoHЄ.Ь]F+. 9%Z%K^+ O enrTJ,f]Ǯ9i$Uܧfju,>mIӎ^ tuuH)Epf`e);Qi|Vw Ք3cG̱c5jm`OOJP .߼CIքS YDF WGA;-[Vj2^!, 7no"яU4ąXOfJL#Č$?wXҩ߳c#x>Ax 4v|@/0IJT\WKsӱwFi`MAiuYD{ϐZܯ|uScX3劲)uQ3T)2qW HLUE&m\BY fn)O+yxDHt4$dilnQ/fEy܉PPwD@N|Ȉ܁1F82qtڵ11?~#?KZa@sIr%C:{G5dʯi)}SX)KH bRҕw?GX53ܐZ"3$=.ܰ9pEtm~; Eo?2IG[4~O$MJ`3lJ ?(> w]a!XibK'ɢ ?vS6gu[ epoF# -*X_ݺ&I'=U[l - Or_reX2cYca+]nckc{Eڽx#f<ߴ[tPlC;3m¶b4^RE{hȥ8*Z:}&ecUr; ī0Q\DFB yK`a%Ck/l>rfoQʓptį;# 8EB.EVh EPo79J"qb,^n]ٹily,4}&U"#G}LqM/{ߵ)GsnhL\"?8qX.;aultt*f)X|.ai@VOnW1⤹e -m{)pQ,%p[zE+(J ԥѲ)>*ciʌ#q% ?!;ޠ{~~SV PM`Y+(dNJK542S,]N*<[SufZw ~21Qk^jߒw( @zpUƴ4xq\C4:331o!7^DЭG|'JbUPD NRC$0;%䫖+Gk}UGǻ _a7AS3MSvFa.e_R?`3>6PN Hϋ-Iep4MV֧V ba]vXv{УA _NУYi=zR~endstream endobj 368 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2226 >> stream xU{PW{0MI@Ԁhc5d B s)08́FAg M&1Fd-&Y7Ik۰[}s$JPL 3°[ha*qW~L4k䫄ǟ?^W%\5Oms Ն] . XvUv~G!+-)QOӮ z3Hސ%_&j ;ڨЈHmXĆsEyܓݱp%K_\,ImUjj A)xj:E͠)J-JPMEI>WIyD9撤U LaYl][CC!s'/g)\x*eKv4/ ťHcƣwo[YiaH?CM-,wQgFC<6%n+LP ̱a` qOgXijzz4"~d1-eBj; 3#l67hƜ"%l&k#a+ CX N kӸI7 R]1(טJ(,XLLd!EsI>g=dk^PxnG0 7sovini a+(kY ,)JhHsjS ˠHS ln['DcC{w/lB5 V|^,5^G+)4@f-:d#}2&S\q(sJQgvLX5rs}~AJ8n vqsdxd^$o1'/+;%7QuVVW`BMDv--5EVK<(ѐA** }އ%95-^]Wtv~0-wkew#&Lë>G!ph@2[SMBN7!=.?AȜqS13B4xO@TUfVZjjY@l*kh^ٙƌe5 $ Mb_3 Ylbgm|}FmT@_ S14z}*7r7]pu &1wDJLE*y\w8Io&$yf{ね0~y`N܈9*oә6Ўn@q֓}ـ~ i=C``UĽq] FUzSR>@‡-n=-*`$nu|Azfdprj-/,N}*VP]g= SNmqendstream endobj 369 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 455 >> stream xcd`ab`dd N+64 JM/I, f!Cß <<, }G1<=9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C53000303g } ֫ ʾ_<}aߺ>tqެ)gV.m{;DZǟߝAn5!s%˛hj$Lܜ(5n{eS;ͯZ՝id8\۵%K> stream x}VkTT0{o؎О4+k9#fA.m.N,+4WZnX XiZ{}(g'FP А7q¨ aIe$?g \kntǕB4!}amzR\Llv҄ KtqxC1>N oHqg zmxTlXB]L"휅 B=;/k{azZckSR#"bb-OH0#L0:4,fBg%Rf3,gf3L/f2La1A|ƝyqfKN#)mJ֗-sܯ34,tsi`vf_~2 $ǥ*z"J/pdmjk !#r3,f95?2qY%qYP)hE D|TSu5A+\'|6R|cUIqY|YOSP)rֲz+&ftܹbԐs:=A`'3=E/^[Un9M85| #(2{ u+ԊdHtgNh< ` 6Y&t@4t |dBo6x hTqаMhGa6CƟ;hmi]~c4dP]dD!6khE}IX&yVG.R)\pZǦϑiD[-+8*Z5S#!+ofު z,x|89F]w~:#y;8 SGV 3^bdcP86p U7 m>)6atįVR8@NR*UUf:A nl Wr'&cĉcrXtICWe{Q3 *4B-׷M) 2 i>gffo7J59i}*h[mmA|phF,1oŚr5DB(fm3* {')9LN>.JNI!. ElAtEac8}%̕||TiF#=C%?FŚ'B&Bu q6M:6 6:t?l\uȱ'Jvlt'5悲U#3PNnV,+~ nFd.|"̡Ltr?JGI P|% aUHG,y&$e ZU$U;S֕z(*߾}hk* _Ju'/75exHLJuFv6'BbAbl{SѤ:L4i={]o(2K\*nJ6 e֒:t+-_mW5]QpJ9y 3 tV;3N53*[ھƦM lÊ940vFL% ث!Ȫׇ'zU4!*'MI-I~\$kDl޻ǹRMqн+8Xj򌨌5h{ֵX5wh;4VDUELtv؍OH,@ [4_ IcT=Y덁[R +b6 V!ٸ7ΠOԵtT-xWaM6ٽMLPʓqz&0eY٩΀HMoMo9;ŭY! g4xM@䙻i8Ft.X:滂,86fvl}esN `.n5ON!c{i9U{g53&9 - } [U[s};4=c_f]׌ˁ4ݐ)W4=%s|l}q18'ꉓiw858LMBVT>d~ &q1v(Spbtt]-<#% Ι#(2A\;@&!MGfPlYpc/?N##u&_WZNv=6ShGŜ &>iWzCî{Edzs'DԫoC m ueO:v%vulfΟ@.|uQxm60,-x:^r5i~uBɑю}Upܭ MhV&>.Śi_R ֟<5 /ZG>7^A' xi4r /?8C 7vf>q'7d⩥D@^h}ߜ\%R^"3 .Gur ݽt˨ ȷn$0{%1sr"}-Ib99 Rw<9\ @/V0eڛ+oO6%&?:Z|QGob=eU'\x,vO3B~ԕ>`c?#zWD.]+]nY,\w{g&>w+'(:q/;bmWƮ^m:Dr9CkYG ]\fkQAaQAqq;Jb[endstream endobj 371 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5758 >> stream xX xSe>!4s*"" BeBi4If4{ҽJӽhR"8TDY\P8q?{0>eާ} $9}},bbMټe{ZJTs mȌJN8(L ~0 Ǟ~zz*>IB 6 X&MOJH \`yѹ/O'Fne~ִbRĨqCwmn{psX? S_N[#X.3+{cN&aܘ-[%$nOڱ`f=5o>A 'mL"xE vPU"xEL%vkyD8ObXLFN2RW*TH-TUIMV jԒ_(7Whe6x+?PRs} #e&c$u!d{}ي)|O}}˅,O( ]cE޻lȰ("G$@ԠQiѡ":\yZFp 4NFK$ádx ۺd:y'13 `ә+|iz~?='OWrsvy1323Y3 OQA]\̚Nݹ+"x;}|8ƽh ynz6{»+֙M RWG^) <&3YYBaR)@w1+)t4Bz#4s lf~%ԴvAM3-xpxdBR*%9H@HF3y\b*Js{# jNC]`et;eΫ` h6C31빒Ƞ]@nZ :BE! NǶ%`&n'yU0fy6r/R̥y A;Pʢura[*kV98 gm30p̹~-^ð wrnKl\ԘTC%ndL.FۜAHSi}E1} m<T.kY/gi--@S8KY+3hR[jRb]qAA"P'Of: B*f NtPZNoG 1F݄-}~#d GyۿѾY"Jz2r߿)M=u ={ xFh*qT%Y`WK|8u~Gh`3hls\"ښfJazYRS^mypotf|3a$n,zdJ+ffOF8^YLˋz6mt'ԋ+EbQZkQ "! rv(-'kjE bPe-HS"cwJ“-;[]GߣRhG3qf``?vj#@:*p 7ύr0γg$͕SŬPfnC}~79vB+8hvq ȫ3eTbE~K8yw!g sPR@'F>}W?(=l6nNr?4<ԭ7`9)TzQ悦'LKM dDᑖiK*ɾ}K)@285Ϧ:TKU.+uWt:@=삁3hgl3&qfgf&U>)fƅJZ6nx2J(Krab9b/zjǕGf};ƻk-2%!=|k)Z|Tb!Nޭ1"NWk]}3[ Tů\EdsRf9s37К-qyȋ GnQ!~>^4l1p}KUp3BE6B xy=ǔx<AIu94CDiA98nB$ye3~ohIJ-%~wd3buB兝@ks躁޾n~¢@[Ĉg]v+\TNbiͫ|-Ϣ頜4t5dRg.*Ԫ5%ZkLn^ ޱ4[,o v^X: #}S]AVb9өXMfc݆f"*ٔ8m֐\Ycn2@Մ R ĻC4b"%%x~wl9GnE(o8}x2q p‰G}Bu>ܒS̴a䀮H7:̘ Ixa<@1{E0Ԑy%Mk٦}2{t6SUۏK^Eƽ8 GqI$ j5jI2VM͖KR-yR+djCV-8CEcx4F}WX m}iՁ@w~.z<ޱHA-Ѫ 0!pOnymm3ٮ6RPEQt4Db`Dž}=@0Q.W9XԧٳHCL_JQEjL6_5]tRq{w:YG(#E\(-֝t/KH'Q絞uIk*V&V[24ɆzhJwA$ƞ.iuut7>S'ߖR=ڙ" GYi@G=0Oy40' esV`ޯׇq O.Vqn֘NBok `*.Csl{{Ye7Nsc>L 6jig> Q%볹+~Mf-PHl V)"#rf{.In|ɍId #jj5ljFΌ{ʋʴ:)?| jf; ^z8+cNS*s-G|` n+?hއ.V tk.?ptMt$͌End)}xYtQ6OT2MƒZ"]6QzzNbQ|&16Jfa?< Tk8rȬ YY]]UYij#fu1@:?,ME5p!'N` A09Źrb&_|̋6s˳'$!ɔ(A#8f6뮞8pK%Ӓx1{bp+dث,jؘ?ᐱu%F}&4(]wHyR977A ZLzZV*WV;0Z=U͇߼򿮁>OdpOP{'Z?_M5kLZDMHc֦ zPc<p&Ю 4}6K^{23b~Ir GFoFw:.2?DpֈՅtJ Bҿ{M?Zx.懆\,ɢ7yf}3Ty7JT𙣧nsRźzg^NKb(a֖/ S!MUeq*LR^lmtW-b?ȭwfjdo.hd^ 6TȅnanИlUJ󚡛n~ոn~BEi~YQ=#R#kĎ?` }a?\&Tu\ПoQ,H |jU v#P$JiZ5EFɬ,Qlsv^sk5p{A^ ie1`XB=m>XXt}}x dht j;G|9]T(T՘uFX :p`PfkMIuu\Wo Q e"ȇ>5Ȩ$j(1ﯞ#'E7zۡ ! o:FzE.Kn4<({^!uiů}-%vnR˳Ǝ2e.3ܹwx8eʋM'v㿛%xTO| xendstream endobj 372 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 6561 >> stream xYXWמ!h4(* *(*ttKGz/.E FX%q5j4 IT&&1y/({==yEB$AAN9^- _7؋#Ń쌐21<7fVSqH#(+hi/PӧϜ:εie=c_lGN+iӬd䦏Ġ@vY9{nZjkޞf]Se$puݮ˂Y26\}ukvZ?`13fƾ7ksΝ`ᢉo/ySݦCQc5\jzZGͧޢ5r&R멷 $ʅHYSTʕZFM6S˩w(j:zZI͠lEfS52R,Nq(ʌ2,(ʒMN@ PoPʄJ-QPéʁ2b)QR1Ann8|h(5 3FwUr&9C,[x ;4edlsWFYjjjzYkK_qQQ*fNۛ+-FY Kc˝GOp̤1cy} |%F <U%!5aġ}q9)Ya(by!h艇TQ(JIOII@L@*+PS y lv ԡ g5 x!l91|b]U?Ym ͻC ƣ VDD2]*+I5a96{̹5o@AQ ]1!( E0ި57G Ta \nF{>+N Oaа1j *pS~fa>ԛo̫^s,q<QG{s2h6t?ޅvn$Mp4{{_Ĺ\Yf ivӬ*E5ԫ D/`NGb)0}Lyy{#fa++2ӊe> 25!9OߋcC|[6"s KlWyQ<~ԁgfH}ј^'<(Ov-+،nBǧ;Rs^~C>$ kJ+Q7 KR ]bRY C<~D&% vPgJqWOdB JA >5y-t, 9xoLGM<#iZ7j /cȣOUP2a$~\_Ί"E#JxETfTso©g<9wvG$Cz[SБE,;}S>boa0b4&IQHSA:$2S` $@v \aޙG8leb}L_Z(ʅ̨ܸ?BxjO ݴԃi&m__,-yʘ uTO(>^MCb#(BUXQU(6<8;(6U]s͛ Jw[ezZ ф#29".<rx^5~s[::TYЦQBQY(F2/O7 os綫y'yvͩC5d)( [冒Fo?Q6x+!@rzW3~:A`00]/̽A%?ɨWa-1taxef`]@ÑwFA}<ӬқwU`K0_ \Z !TRZADEh@NS(=[.h_qLUfil+6'vWJdEZX\9 4ůPB°Ɂ^1 )(!<{twTd/yaxQÞnqH8e JNH%)[ f[ߞR]Jޕ:U75xLl[` {4We*Ӌ:1͌ ‘/ʥ- `gi;RWy%lK89sB1NZO l#IG.Ӡ8D7yBZ:vΎ-IM*J.BŨ$?$+-:(zi:m"H:N`]kO\#Q]B彚NmkȔ#\tNN*T%M vܿaomI&9&YxēIwߨY/$?r4slۜE~~ƭNz?NR: 1 exw &k7X1~i*T auOZwYFh*:$R=ЕϮk*SvdIi|Ah1Z|:!gJ(l|7>T{X]6G;@3QHu3'/7u{5Թh ́$ Z#V<]/a^&P5q<\ayI'[L+*V Mud+bْ'XRDs3BuL߀Gm6hI) ,x |p%iV/UdƎ\ќh^᳕gPޕ[GO]xrPщaȻ$ Έ%nhE5x+yzVQZey :(8=e͏K32HHJN0E2e3&::}/T=EHUhW@{v9 hl8u+Dڪ=UD|/V>ZHN4r@+*8w 'qBJU/߄"PKQ<, +PFD̵>~\M痂4|)&V+N\}+.xT7\N+s \SJ(ӟ@IX&caQ<Lk :IWA>Q?%bvoX],㒎ύd ΃NNZc `8HZ(1S79vR#w< h] ѥ[CBOvZ.>mcLl]\6؝?k67i-Ө4蝗/=RMcHYV[^UX*z!_'y$جBhrDA20OEH$7)g>z{TiBg#oU0K%y 'p~Z#GHp@TC&' RB[*s[+.hlA/5$r0/`xtJn/~B"zR3 n| ]ct礒=HX ' }f:.١ uuzg_[DpJrL}Q+3{R"^*TPN%xލ F|[ h`\UIVE 5˚L%_?ށ.2]`cly'6}̳Zrҳ0L>9G{wk=`ml\"8[9<8ǶStۧW;hK8):u'?E,bn WzS(g#t{HxP`m37`l0~q;x :{8G,8%"/ExYvNN.*g"CdQ~ˈ86'3\9sm۝UH3-; "YjOFH l@4(NLH HLMBܗ yIbVᇲʢZ#]nuݒQ)׺4w!oH?US [}Q|ɳ6M]zAgZ[2 C4)A& pb5&2 KQPC(՚1e z&gG_o !۲¼lXVm`nYsCLCNUvG 7I` wwALH,)09'M9XRgE:a1 I(Iʕ76q4ɱo;a9/8eJJC g|$`,Ͽ('8 i̷yw;%7Dex Ha zF ¸yn۶x\y G[7OcD~l n_+BW.yQ^qdQX٠5Z71Pacꚼ %# YldLDaJ1 d-%Ǧ ^xgآ@D{:PИqzUuct&GLUqEƳsTB$K$S^)][kg?7 [wK)bMOca_8.xpVJhq)m4k3676gh+'g%4 :0Lk;]n߃&55f9lz5)%ĦVMrtBIQU5yŹ<|&LPŰBqi!,,.UCC PYBSkbZT;`P endstream endobj 373 0 obj << /Filter /FlateDecode /Length 3423 >> stream xZKs7=[[<["4xcTU++NDC+8{S4)*3#9am~Fۍ C)A 2((?w/;?xZ%W؀sMeQ2j0&GCd+尠%ÑXt8'YmI=eQ(2Z, T)kla M^,:?hWgLDt"TT8png$%VktH˒tMs6qkiYjr5L]Ӓ C܂\`t)`d6lMx|+ K@G}A~&`!1L#o^5- y~~;*xT8겡iyi:Hɣ8'k]۶'-FzKA91}!Zk@[jl?A1- `5`r a?b7Rfs:^$R}[8tfWxmҐWbU3s?I} z͟}eH yG VX?ə94YOm[*0͛|->)kV> R@ےcO%ܟJJ%hI_L_่d\žT&!CjXDp?>e*mpRxIǗ03ͪyV%d|>.!)t@?SF'`ea`b{L) Ww 7H39Q jrU]Lqi-,)kI^@;ؾ^=+N0{e[#WL@˳Y (`/$Wӄ6>ﰠࠡY3Ylܤ62X"K`|UymczXP*$9v$Wg'nAw)r2c Ws nb<˼캛Ã㳣o&InŻ餣?۸+K!QJj2 Ƹ |䀍nl]xL _Xk^V-q0䣛Q"nd &E4 d7Ōetp< m흢ZqI\dv-Hk 3͐&S\JFquqJָi|{hϜ޵f C\4x |dEz1v Z*K_9y?dS-}Rɋ˭I$3)lH$' ((8s*9_ԇД8AZT0p:~"|02 e`{Dڹ^[q"}%:Ò337F6yU@z$q1;N)c$8:$!_rδ"u.8t6Tt~Ym ΆրKx*~]ס}w#r0-)6\b"Xaa v`sT0dzC $/e*s/4eeNa: \N*\ro4\D_#9= (Yi͛zmA ]7 eX},h6VT۰c2[A%04BxGl! Gu_ xH%wʳO,#va- vXK[vVAfG ̒0^A{0ږZ ll2 6ا=tHH Iz9;xGTh`2E_"3Zc @%oWOk%v/4x>r*׾SօF~{L.QG=i4Sy8g/re>̡WsKFL[)1!kyVk *PȂ؇7=ʢ+kz;΂/B22U<7R<EBZ"3s O[HH\iZ >`PT5H!l|,)qװp88Q݆#L"W)w4^K^Og}r;BuOB} ؍VU#'e~1aB%ƕPBeu}O^ɮ;zn"_< ʒ-ep@;AQš2}7mH s^h&]ҺyaC }`8ٚavB2'!%JK*U5vĝ]>jŶ+@"#!h τTOEϭ!b$&Q +bpa>f'ۃX!'LA*6A^5**'Hss|vaRƫ}G.'.OvX~!~"HzXK@ (v_ݤ\YA3)G %8y~:!Op2qq6LV|/6xs{(mF4^e)nyqŠˬBɪVYC<ʀ"W2vv Z:n ^@kS\9$>H6NP N 7ʁ)Iu.8W)NxЀmhrYOS(9{2X/"N69INoh5Uw7 ?|9=1H<( R 'Y=z1[\(@YhC_ŨPw, MCOFH^jAGu=_2!rMOy!e_ Vi+de6r'dO 0R|sW`a(ob@@<%07RlI{rN:Kz%\\ Q1endstream endobj 374 0 obj << /Filter /FlateDecode /Length 4269 >> stream x[Ks99<f5vGĎ=Zj, da2@ N*˧1+>_dWOId1y~wpRЅOXm+/xǤ ]]42Cӽm; Wxv:ZKkΦ3|qǮf]t&pdg8bG%o%u Ϛe69vT[qؤs:ls&o2Wj&u 1qi6sZ̯=t<ي0 M^6]j>fмPdj^E99G]uv(x5|Ⲽ;T%| a>zCx/{u գ^W+DU.ßtt=^:t$z~ŗ~ W͒%꺲Nl $]t+3=} Y)?:mvpܚ=π&Ot^[v& j.G]+x)^ 5WNC 㴚άgO^<+o}!沶 N$gϋ"%ХB껐[-gqpgl\N[#w8*j P y2y߀LLԑpߊk<͐4z~CndpՔK`c VAE:fDSJV^B?"D=Xs2BRC '~o[XQnCH4[]ީW(ˡr '@p f|_Ia<(ӶyM= *ZWRЯ]W}οalXw# ?Vkw4Z 29.UIU"lZ 8 ԚXH\=)b4_pI!5/jNw*/Щ]k]r1UOW'}swY $j{A@Z"OZ0 w^`C\&s/JLfKvR=oNd-tZB;}͗&f2DKBxR>;j$ůbe]4'!xf3NoNv2ͼFLxCKsv;E`*rF&B=3sKk[6uuWlGԸ+||켷$eܲ'w]^ekd␵.n}7ٻB ^ap 嗩CIT7^* *>?g+jWw  lcF:~{/ p4k־#\߁i֧ũ@N+F7]<"X#}(%[n5@ݱ Żd76"{ %+#ҵHHx{Ywth9->Oڄu!vݿ-orl_vۇ7S+N=”@\=ЁRn6'y?kǒk?E.뛞(I\MYP\BD"T T6@ M֌xʤ݉2m7P&ܗ' pY_dknW;g I/vehOOc'K`~QP Ztζ}59NWp %PŨ/p3c#ت;#*T iJӠ4y HʒJZCU=g;XfOP(!@XX$bWT8.GOr+*f\WM7FEPNQ!#D'$"@X!'!!Zlvm^N: , ٰ_ex;gݺYAl'G zTTӳr .9^(;~`L8YDYQYU)&awJ=έ+r)3 =߂h-Z% f<9=O)q|fst ^a*d8P/.ִ{GBlؠtTLI F] t0,;BD^?yf]fJ/Acpht B2-?{N74[|{`,kUIlc/%l0ĸ.YOBGeh <Ħa8-Yh2uWI8;[fZgn(PpEv~r,awdۭ=@WƒClyrx5vcVCS.Sg]S"x~-LʈzY%/*>_F1l ]}>zR>[@bwCicr㵇h5%H-{@WqaNku':<+KvG t*j($ S*Ki,DP7"ӅLqGH,!0Vϴ>Fr"~e<A[)@҄[F@ߨ 2Yc'yc[F6c1/1"4"S'𷇄Yg`?Ї Bj <"?a$!ٮ.1(%+If#ʳ:Gn}LLmƁwKFpp_ X Hb{pw¤#ʘ_WX~j? J a:CU#ҳQgH̓ sӎM$tnH'a3|_Ǭ2wRePem a:V: T3 /Z$8t ĒLop2]hF8KH*AY{y~rQ ܍KٲO\La,ZcХ.ؕn6# R՝A^uy{H<.$qGG0%RHF!X?mQD|u)`ݮhAfl!ʖ 2YAcJWJY!IF"̦>4նDR mB^fk)0HPQH`_g#ؓyr"lkAP @ռ(2㎀S!`6mOgeEU*B ej苷?t>̚c,SmZ߀tS~[vUצ6ĀAq m%醠(>{͊Ylt?\34L%(K wYUB Y[NuH~@@:et}cz5cNF^sW#ërkNONԦ[endstream endobj 375 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3197 >> stream x TSgO9*rSZZX룥FD)E^)@EvryHx ЪcCk;ZJ\ulߡw~Ѷ:{ZYYY|9>?CD6gť+sϛYTe{o='>/ĀWJO ~'O) @)(v*%"NMN ~i޼s+C%۽+58.=1xMȺybjxyJ")8#)x|[pDÃؼ!bc_(+3w)s%7&lNݢH{q.E͠6PPWpj AͦRJ5*z SajjZHS)*hCR"Z#sW{E*9MУ*籗'FOjIA'/NRcЯ^¢ov'qZ?Pkie^lѺPT뵋,}m(ph*;s \*(5Ջg5h0mE6ҬcY SB/'xiJ,9=h2v!Y\!&FHJzHwm=ʓG~Чt:cK6i Q$a:]_="/QM¿Lב^bJLvB0[(4-Hr*z4WR5e .`8o"秤wހl\&vd%9S: O]%leL\IB#+"`6J.KPhu(v[Ǯ %ՙǚ3΃7@|)uԘN|ɮ&A9zuΰ- CTXI6:IٖժPGl[\R`AiucR`X&35If7ht߯7fMJ݌^Ce6/Gp@vJ+OKivtjE< 0(34?C?5 7(e\<只.BEyA]fGQ2 d5c^kM/'3)X<>ٰa9~D\,t*_,f'Ut8o KEJZ^w?o.js̃yl=gy4oxqhX "fX`4eC/w W8_FrpC([( d7 fJ4cp {9R^ ԡ gm#|W>LH49Nqxm#KIW\ *Uh=,nj>4b;tS$ͥ%ѝ`4Y;Q>`K]&,eպhW\ o:p _bI oqKRS#5;VsA#p(.O04 rګ ^0$e/.M TsZb{<ˋo^C+%| h\U(ޠ S%VxP Z؆JxϸZAV^ڛ-Tomg}˂胩\<5?,z-Θ#B/ ΫWߋ,'^,%xd ON Y$7rW 2]fY{d"L8jmFFO_̗VḰ,3s/>އ=AQ]"Yjao J:5~X#o N$f4;Ks1{u< uwWI|cyqSoʣA1@AiA[oٞVϡΓ M1Pn4ZIPЈ,u,j e[g·){z#/PxW[l1E3IO@ly$Iq 7p&ѫ~ffs$sG<)hu^t4h?$Tȏt̫03(^@=~ӣ4ZOEy 7g4\m8f8\@G8.̒ڎD"cQ ՙ+B`Ih2쨓r wԦvy[ڂXmToAAh" ߡ˶nPt냲I3ט=kbijl8hp—pBG^e@WtCȨuPPA|bJ.Qef$ÊK V[>9̱I҈Wφ`P G{Ҥ_BB Ae2cϠd/Đ-tJ&paܸx|u'SݔlfG1yXyi&5y~6Di%se|lg\?6GXE䅭x/Bð M`SIu$k0mB;.k Ф%xKLBՖ&swg(={R ݀## dWjwxwP-bbʻpD-淤A*dguάv6K7_n>m%Q502䌙mR'RJ0x-tu9@eK_&F".P4"8R^Z626Xjs+82Z5A_P _|DjІ3W:6HHp͞($WU(asӞeod2fSϯyo oyjMCendstream endobj 376 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 484 >> stream xcd`ab`dd N+64O,,M f!CgnnC?܅ ~#_PYQ`d`` $-*ˋ3R|ˁ y I9i i ! A Az莂L@?SUe/>0K|o﷾3{i V[Cs/~7b"Dk\~sU> w5.@+J/|_}?,WG g/d;[%$$P>+{z{\^^endstream endobj 377 0 obj << /Filter /FlateDecode /Length 288 >> stream x]=n0 FwB70'%%]2(^@Cdq޾CGErfuNqʏ&=ߦlS~Mc׸|}/lQoGӜS7y1tD`8Rxa` $z ՉDǠ@=F@T%Q F B@El+гh 4B#TeYibBN1өTN@F =*8Adzʊ\WΛQ$2zVendstream endobj 378 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3213 >> stream x}WixSיBr L *RC5eHI'0$ )Kfb;^/lY^Jվye;L1ĘNh'Mi'M9\w:G?:,?WG"a!ٻ7W!ۥ-[:DMInUb/b^DHBre .FWCEHw).U7V ULڵWoJٶ&ewn^qymu<%,?ekR~R^SV[ -)L)/L9PrpSv;5;4O&-V:J^ B\-"NJ:UxG 6iFA""w="&X XG|׉H J1/BM¡Dg^~*Oz;ɓ|ɂS :/c V?&Z&b-0 &vG, ޮnO;Ϣyp3}];zt݁cp *1̤N@|MEJFtNLQ&*kC./9ÿ8ΰ+pE20W@^W:4!٥'%74F#tT"n??&d$B 6B w&*[jѴ /Dw3r@Ģ~gUOD`MkclXGA Jckh*7^6e TPE ㊁46Aku,zED |x?FB /f`/WRZv]Fl F LItluz,@zItN:%5g9K6A6tF !<¿ P @&X?IڒyD~Y8J%odD[P_`4zOI-l6kN0{8OAHИϢ7\tWvHDK4$}]Mr9?=2\==-ҡ>WYjj ޏ~$ avtV@eˎl7onL'R j jZuɪ 4~X m Kb" s*C 츐 4.F%18r=&mivTfT4/9z\f?p4pe&Y@5wa8p[ V򯢟eh6;N/p}TN Vk5͔-u ׊&~_"B6+TЖ&L{4q_ŲȗE: н2PH6p*ºmt9(m^/:lk3V' !h;?lyL?ޜf|h} D sV (eG5Yz0mw'@gS I'<>z-5(OR4SUSe@HUq"9o@v Jw)z,7@# dOؕS?trtDnLCW; >7|YĤoB='q'\d{A66(I_bVnwr mw>3_)WꞪmuP=OF1HwWi+ utrU:%_GmT欼CcǹVLkEw 6MԄ1uXߧK71?ϯ`=Rwĵku/AiCw d . ? й{`nv"#Ⱥ&6{pwO뾁 6`~ P#k+k9yV'#Sˏ7ny mJJoX/4{2kRL-ry6hsuvG԰ ǴfK|Hͻ:nbwUOo:RVV]]VDpI_Őpz7;4((iracRitc@¼m &#a^s>='%: QMs*pT o#7kWzar$"җ_/},Am^e[hL8:(>*˯<&2^7kw;Onŭ lZ}kݽ~*x8Q_ˁX[n7gl#rg{ 1H} w]}H$NC4*J?gPtJ;cS*Di~ ?īV/r E eE1_ j }:Q \1;YUX9|`lGAV6_e['?shO> stream x\ݎ\q'ȜFb M #d7Ѭ,C-3O^4WEj%]8@XH."tXwX_t^_ =~_ YW:K\ۡ/NWcTC<߂k?\˚Bqk;9]߄Ryw}_߼N15_\W%ǎZwX(.7Fb--q;/^]?^(1ut 5qxwߐo!ů|!Pp8]R ROqBm{$xD -}\ J[rRHZ\VH[ 'L\BR\?了+LH[H DKT\@R9ˇRP[i:%0@ ۲:HuY.*DʕS(@’PM* $fn%._ tаGbIP"VpMT,!Pa!?eS j^A0L'$M&RJ"$enjUm)$^Ź&0`6Y|廬 oSSiŪ2Ľ!.5Z{-4k39FbX5L/SWy$4&Wmfs^\sz mY(/[X8:fp6\2OY2jnq(L,w`fO7B{9сr72w. je{(not_^~3٬ dDPdXoƔ2֖ܬAr6ժaפpZ!X"j>h;?LPZzwՄPVufBwc¤2\i}&#B-]hpވS#N;4"Tۧ=?miV#LfFӄGƚf>t8=jdu[OopX3y8mE}"آ)d9K =n{FnP̲,pi 'RDxIna}*{1d%/5(g+ r98̬O,..8T\  ~*L&qE`a_eM_?gw~s \hx!V)/?Q}""]敻?\.baLi[X"kx|y{5Kgtgs{MÞ\s)s͝_A+ǺWbJo38đ"e7 [A Xѱ;," ȡHe9R% !  HJ ИZ[5S!+ "[5 0L2BI 8RȄ@4H Y!X4ӊ7"(-B_ xdBbl<"%/E!_BJ eYuN+DX1h\.C*Wʎx*2n*>b'8Ԁ4$f(ҁԂl sVGmA23iAzx."m_ N>5۔a!Ue:PWPU bF< i$Ҵʪl i%g)0$sW"BA )gm֧ $|UWv~gJ&cq^t}K)XICXǭ}& Q!q@ֽVRE ~hEoC|j$i#xӎY j11X@Ђu≬HwTv7t8Y*h:" zwDul:A8, f` ?={2рg1шGM#Y&z5hpe\` ca=+yX&c={knzȂӌDȥ|yYN❋ә(%wRZ9a Qԇܾ\b_h eP)ABf{X1Ϟ|ɫ߳|3F+ Fg*(K\Bٞ–GqxjpVǀZI1"rPq'G/ϴœ3E0ˬ-}J<~˫=Gk-go]5D߼\]P k71o߿~)BzǛ;;|>X~܍:kku<\ordЎ/.?֛K6"W/!C>*ySK3#v+O&7쨀~X3˵3ULWP-Ixk{<7;7]3 D~XA.'ZnwhuD@jLglV^+bR?Y}GU[;J'GB.Z%$BU{ׁB̊ : &cw0ON*EOHydPib~7%';( 'RYM 'V@jeREU!zZ $*tJo5  i: ǡ'+*.:γR'vmx#*~Cߏރ]NH[)q퀀oSEa?[2n9n 5j0Ad ^V8rsR0Icdh!F\3jIztFvȼ3SL"椳6ظXfZY5?; ͈#l@z3|!ޱKlEz:ҚԬ7Lz DfwP bV쏄f891{%DhqR' +uY! 48$ H '\o~ 7HYLz-oԘpE=⌽p^pva5mE; Qdհ<(TOOzֽ1X@B >-c5GCGP0 =PM]H31M#dVyzt6(Gyc=W(5yɘq]{~3s'W\j<[g9#uh@uv wJ3Jl |WX)Ɵwx')9G`̺? x,Myb'l{G^~ij{~s9MX8Ňx=>2]窢?|;.6}})|zԨa3 o/A3D@,,Hٲ^'>";j;xOڟyʛuY9}QV<l,c3v>+3P=Oul;zF3:j6k<(<#]-/;i}6HC{y#CpeC# O7'һ8z:iB ֙`Nxg3]Ms|򕏈4_T.g읮~}8GPƳu>Ϻ^v.hDfpf߫:_85p1ml8J:`iBҹS8ix~_=ЮPU F'%HAyo V*aUy`4<†͟sc/>aQf۫P'J`N丆|0%)C,GAc ȄqU$ \Aǜ1XAa YpY> >F,\3 ƍӦI3?'Fw 2C!oa0c\lˍ~P%;uS=@cB`:/Q>᝶[}q6׆CdlPcY3RcP~ o&@;Z 8KJKB#mk8Z9.neCdui$klj_ lz ٟ_ŠyabH<%Dv`'kHvJ-v-(tkk{BZUn>*ҟFOpT2=M:iB,>ObN? PÚ=_A0MAz\({<] U}m̖pRj̲زgle1eʞcʞ=ǔ=gp>aAl⯡lQr w9(ykk_y ?*$MW  $>%S&F=Av ckpO6 HULs:ņ)!iiS $KHgq,}H|e`}O@2RO 6 {lC uoi R\njٖcLlǍ~O3(E((H H?|0;/:x9ҞMq7͈Jۖ޼Aۛ{#'IVG|vzf]GcvqI~gT|@endstream endobj 380 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3788 >> stream xWy\ײqqT!&,QVEAE@@DDYF%&޸/(kA DE8*/hn3`}o~ӧ{ԩꫪE J$ǧHY &"a a89U-P@ e( X$2eU">5#(I|y1k)fzzJ[&u1Y˳cW$$&Xh?%i43fZYL(3*2Bx* ,yDj>NMPVBjIEP^T$MR>KS~?5 PS@*rFPT4Q#)EQ"j4eLLqCɨiJJ \92(Y(+\"fȉu{pR(ᱥ>*s/>,;j(<<68j[~4>" FPi!X4ÀWH0Cy-yV&P }J Xc% >ڰ\Sƒg{%#A&GioA8;ΏؘLr#1M 0zV~:b|VY`FrK=F\-w)jxŚ&X ,s(,9.mg8kwkx4!ڎ?U$B>aq!g}Ml `OmǕj-4.ZWaPGg g/DةĶLVf8yMn, @';%~GN0Uj>*ԴT:=G,R~~wPuՌq0\!o˺w|ZasIcdn>u)HCBaxtWûWO]J=J+mzP:L 2 VMN1&1LxZS:$ؑ˚/n؞؄{J借4ǍBQZBXw-n&[ t3D=Сe :gqYºQB3dk|f\/g%07݊*NW*Z0\E&  xX(-$NgEzOmũJHhBΛ,v[`8jr=` E%VQ#D * N8 hI0\% Z' yE`t599B Kڇ{E:COUL%֌!FjZ;BPK,tNhaV%ПVoVc.U6X=GXAgE ߨ-9jٯnbw4w!n @o/S IYkyͰ-m+r+e37<0 ؏'';y- c"i{ GwDۏ2Y6>tǯY)DNm}.qcKbs]<sX:͹@^]~ G׊6i 6[h>_6UkШt cKkyU6"-ʧtQs' $A'ONdIG+{{ǒ928K:Qz-`L(+⾳izͺdHǩ5.r_1 Yy+* flf~ľ(}$ e F٬ F)d*ScCRp|DMcUS?*Y:M>F܅<}ޅx{[7[w+c^WMY)K9XE^:}H8S; 2 ?orC>1K6BXzʜ{)dhI; œ W;t]=Ò!wWO=sF×zt}h%օ$p4vÛ}Ǿ!,'HСPr K{za;2aNGW,=8Z>syl<ώh_/atGl݌K2po/rǬךo\ksZ=U}t0u]j? U"z썸fSP;j.pB#֘锵6ƽ60A۱P^r)$ &5zc|jtUWU&D.MKB=AoJԸ?R\〷؈M;y$"pBXn*0cu&#KPk | 3'o> a.L#v>w%11\Cf̨ml<Ӹfw1H4Pt%髇40c0yv[endstream endobj 381 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2207 >> stream xVkPSg>1CTIF;]oUug[EU@$$o8@&mEluLvWgkG:N׵nw|κ_@[u#y}<>H$iwkV'N_x]9ɞ_~!IęğI ߞgG >^̜taLeI䮂`힂Դl՛/]~VPZP>>1CHWkTn\ڤͣ_k5])*m* 1)9-=cnla2aL8lg"UL0Ŭf0k?0Pf# 0^L1dT&͑~>{]$=&!0w[\ x~z]˝Ɔ}W5!izJ^} `HR h^LcdF|P#>P4UTMX_dyD7xc!r>Z#GqK3/"GcE 䧊P'oy+n/xCRh jJɢ/ϓ_?QX5 o{0򑝸]SJ6|CFgզQŝѩk;A\Gt_~#Ӊ o E 1( Xx%} e\'hqd=1&p5@%<'@seuE'\gtI1ע fn(Sn{ ;5A-T5x $@ᠭ0N+p?*1#^pcj,y;.X6J$ EI{b j3: vvz5rS[8Z*M]JP he3%Yq鬒E^fk`;nkM-7&]C\kwMQ8 ;Gm9 H0jqT bzX[%yVB*h[JKg:.5[__\X-{Yʚ+kG>"XYR3ۻȖAJ2E~u 3$(wSj⵱T6cckz2pmvz).C{m:̇L6&]8zXUc w q"YɍK@r9΀KT6V 9UwБ)I߅!x׭t_;,2|٢=q`x)ֱ t (_$xD#KtzE#$}?'5?S>5HJq2|XE/sUjUUXC`6V?Ow.W%C uNh+7d0-d9 Phȿ8)ZP1(F-Fy6= @Ţ|AxcO2U@I_{%c4JWFxЈOn!")5 !~y/&NַFR͎= gO$pD#TZ+*v6$55m>SAendstream endobj 382 0 obj << /Filter /FlateDecode /Length 3981 >> stream x[K丑N3{3D_iwj79wL0TlFRwu߈ $%eU}(D/_VuW5oj{fſMkWa _ a*UնR.؟~9 =Iu]ZZ^{)% q3g6k.fǮ89( !,i_'0\Έٹ`/?](W+g {[oа%ˎi;ooQ{_ye..<۷fިdm /yhfk+R &Gsfh?ݥ<+W _nt!`[ں?Ȉf$E:p.!xeL s |Js6ڜRzԉ/% 4/iZωkIZEy ψ}f&P]Ya6 *|'$]MQ3W;?nÍ_?VNZ#Om1 &ͮ 4M aPdf?f 䴊`tDAʱpUaO9zHx$wj>G^HxC0Dgnst#ˋ]Wx_.{%Deb5wu =N$\%DN0 B#`횃6I[AA9l5aTTƈF!kJZk=dلGsSP^ c /ւY+}uŬAF.I7I..Rq` ez{b+>l˟}8-6[x'VECDŽ3V"I,_?.|2sTeNPֲ)GMTi9lоS\k~J 2}6)up)$P*FC딶(hvwc&`,mY~fB h\=GyO#-I\"nG\\d^wH_jU% 6z2t7 M(?>s<,pT^jH[n YI#e0/HMOR(_ŗ9 I)+JxrI[L!IMkXc']R} HBXx1rWu~RDնKsQ$oNݖGN;>g㩡#S brNY1sH`-$ !UHAN&%>E!tƅUELG)~F2Y =&Jp009yWa`4Ba˽B\ʑt:O箹NIiC"n1Vv$o<Ps%/R@𳧓l&m sypasb26q9U@%g}/$׹=޺尘򱸾Ζ{Aw_ϺEgæ>Ŧ""@TLH EVhQv(_>SD-fC,dyt.KYy)ᶸ4_ =.jDn/ i?PPs,L"o8>%ֆD$^XRվ%CIMvh' f1~-Y*5Ra G<0,9sx{< /0?Ku8 9*ԋ |g>yMPb!RZ;0$xlWqTXҼָɗJ;;3=gE)\$@ LK,48%CBLr]?Kȳ$MwQXI&J;BY82Y߃=xibaJZ#~Q#4/D *±!g5:Ac=b??kE-1zB+N,dۮ-5 03=\G ;kUYf5 ,ԋ"@3Bj}JT@~m:wH`$}:x)C}@_N0;,2UgJZ.BdbovCs`0e}wz|?&^"42utOW#D7g.L6<#L5iȦj)  .2x^j@OqjSb CZԾ>!54WPԒ  -ijW ֗ E@P}! Z!-axx(&#"}t IR!R"8^ڥs>m8~v=*!E@iC+r >Jx |sM#L% teR |7Rv^};X8cx u?bir$F`P)b;4\ܞn>WMP;?K#P|(ȏk".^EݺʂjG\8{}JS_;iwFr90; j { ˳Wc:\?(׮_-ИH˂oZۙ@F߆nr܂0t-SYulKhZ vESp #-.-"7u+NS7zWk6+njWgfwKI8+=uC_(%ʁaB@XPx|I$RQ)RBU;%w 濤C }}ASh4Vhald(=GA t^Ï-7hϯ]aUӽ; m,*1&-%ZJ߽*RKE)vLbZF`YR/@Y\!Ҫ<_%jvV6Zqߔq6іŝ@2P۵?Ji uG(IgXj<a7qCPP桛:tDq.܎6PFfW3&#Z檤){١fF]J;xA>w4Ւ:O1J7;Ҿ %ʋ}]:I/u$W Rendstream endobj 383 0 obj << /Filter /FlateDecode /Length 4227 >> stream x[[\q~ߐx:p~ ` N`HZN3^+"{G+jt)օ,_ۢ6(OWjyw+]Ks<-\_˷.erKKq/קՆwNjv &cw{6C^_ԦZnOD)vq5[fvzp7ߑ%<$ֺM9wal|sWiM^o hqLi oi0 3q1Cˢ#h喇7_x6Br7ݜ_'ߨ-)I~7v^;YSW߽9ItI).8 EZawlz~|8<4Q&DL1kVZ oR[tKa VΤGDG7[,w6m),+ی۫k39)/֑gT$tQ2[3I)Aq&)OGƙ 89:?Msr m>e1>&q)f A8ɄfA[/˖ XI7o?R&] w V,ePlI3mª+T([)wq!1[pCRF'M0;%c RwuiW6a03HElKճ ^dy"ϼ3X(=#jK4<6;y4h8AA K$ tb+ t(eU&8cHiXMKi[([;V|sӰMޒ$0ߘgtA#" 0&*M `'9Yml)-I .iؤB 0jF0flE4 b4?>Gp, (`Nu Y9t 掲A'> f© `/YGA-Rٹ rf3h%$̺R ($рr&*I`YE,1ER:` /Ȍ X4F: E0Y-`o LΛb49%G0GqړvФ4K9'5$ŻOg,^5$ղB*cFG BkUQCTsZpg8@]D#};]Ut=;znwWuS곴ϸ`n>{rɊgjC;ЧDTcܥzܥKK ssA+gTQq~Y˲嗵!_"e:O L͆L)&Ś6SI}zHY?E-!&eSriIbFq֔:8, oN KÇ؍e)F̈\#fA3܄PtO%ѴX=X4`{ˤvH́F9jAraaiGra45PU5tLfزYLTF,N)c(`[)9 P seNT`hL10H  LW495/~KLT,N6s%2 RSnGlO ~V&OiHr/c dN49NE4`עNJ%K0QbCŎmw3*CKhЙZS3 >l`6\X4;evFiDK߬aĖA*RSH/Z`ST:aSWrvT+ >BW+`(uUJX4`X߿gu7ݛisֳ jQ;8H5$ R3I]D$1~]L7'S3aga~g$.zv< s7{vWd9υ=#W_=tZ0(U^LR7J5$EeRK͇H1gjR_BZz6vѭ=cl'v||@?8. GLEu9Z T+tҡ&Mk:$:= Î8jmh@B. ^zR:T wkͶeał8!1ܞ¡]ijcI{Р -aRph(sWjBp2)f* % 4?4ՌtND`EfZ hhfК9P-YZlTZ0h`/YBCw).SAADJH5Z@h gb]s7A!;cgGy]P c.`tiAEˢjCh Zim4Zhh^v s#KP S>2:̤"P>j@g\ Nb?{ Fa4(2(i/0Rɴ"QetWva" \A nKag>ee?3P[^*D9TxssF"E4C|ԯƳ`?g};, (+-4B3glBhBwBwRC ݽ-4K-׵ D?o |@F>ʥ"Fe +ui#CѹOojBXahC)oS7KQl(jд @RضgE6R(t,(RB ӊ 2Z=vFj;Gm &L -f LWDhh@C5ۨ]{]A@4bON6ێDcQ iyEe8Հ8#9+ *yPiE]d s#L9Qo]׆M1-@HTY44 څ PdW@#@4DQ@4ei`@4 rxDDEՆ%vqh8bB:zaĠ A`46% k ye8ՀХgY R{܆t}z`4/vP%ӂ?3e t5 4jX-PmTZh(. mO:gh>{) R}ER"ŜQA3J]D4U3O/|mv7醴TͪտiEKEFo{p~OB~' p]?[HO/wMNu[dO[Dʍo7o'U4/JC}0PfOf ݉>[>>B$tu/}] r`(N3ʖ^k$@ͿC8ۮD6/{z u#=TSmWGjf@tP~1ԍl}Z3 >讜&cAIyv1d@ehL4!)2vf2ePS[M&~Xru=s|xxx~:߈CoX ÛFeVH?*yޗApu#+>vMifk?5jW0|L~APVs5G, Ưm3ԔImF>Zoh3bg壾p7M|]$bPqTYs! 8S؋Up? ʃzigD;䤅{YZ/4y#xj=^7M^XKӓm8;9嚣_|5> stream xcd`ab`ddM,M)64 JM/I,ɩf!C;ׇ<<,}=Q1<9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5p MH1,c`z#5|Y6UR+wE:ywھm׶ϗy{fƟ^DWtV[]^>{l3uϗkyOm-.býo┾ީ=z,?}ޟ< |#endstream endobj 385 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 533 >> stream xcd`ab`dd M̳ JM/I, f!C礟<<,~}G1<=9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C530002013ȁpQL k~^s{-bk2u:o}YgO\RrXN7GGqʞQ#Ŷa |Խj]#t/^ /Q]49پw|gm]3{#u?έ~㷠poM-3Q^8kdw܊+x\7o^BX'7twIglww~3l5%%gd5{ E 9Arb'۬@9?g}ϟ:yr\,!<<{@`„GxxZ7qR_ yxendstream endobj 386 0 obj << /Filter /FlateDecode /Length 5680 >> stream x\KFr>{~z"!:ݵjN"ahHo @O{BUV>2 \ =]oWݹnOW7W W|Iis]ԻҔyt&n/J>)Qg0ER .JTc, +L3A* ſtOX…ܼoWZݵ2ye-~&1t%:5-ayӱhY-YH 6Q˪4<PXn?~{h;oO aCqh-$sdzƍh4Z#@cts4/ goPm]FdM0nl Y% h d};ή }"޽X&92vlW[o:zA wfioyT.غ]J'I||e ߁GߒhˑKM Πej$"PwV *=?\˛L;0D>8 -|>o9mWx;t_iX+7xhcen/)Hdl'%sn4w&VB#4l`=(vߺEE+]e)|\Umw0+\M*8](d7ٷka-̩1?~;_g ~q*eikZ}?kdB `ԪBHF3B 0C@-BPН/%9ߴ25ujwBO4cUM>)>3+RM"Ed ;F"[K'7'<"0.I+r#DdK,c]yeuTG6?(+-S~7QED/p~M$P@w%}5j"E-2'J߻S06NNnso>2 `Lv?v| o>ֱ6Pc#(JYd'f3wʂn6ñDLHuBU At ^1u6kU2_S*,n\[S0!ҭrõ&EHq FE3 u8`g$&>#R!Y| D$`p:2W [Nl˃9ptIÄ4. 41Y ( ,V)CvyBC#2yvYeȍ j$q*qjR?B=CQ6G?p3>sdxhW'Xp|pC>Ӗ]bZڅ a(5yw~5c^tʣO /\qL%8Oi7u=nHPNtMٵKa"81p` gO _^@޻X@K-2aG矗dxe>9pZdz {4'x_k[&sf5& ojAܕ@-E  )j#fxh\hqs+ͮC Y!jvbqVR^P6MIdBEzT‰-uK{ꚴ5!^=("~6 aHO1) 0BK:ד@9\ޑtȺR3i={Q,?zpMDt' ViHڟ6~~=Qg2$^|5bj7/*T&/IT8!^Nm\.%&.A*sgLtE?uk͋W^f/%d*WB ! * :8A?Amq`XueHT遢hplflXQSDEv<]F)ZGq}v_ ޱ< )pK=9RbZ!)Q/f 04IAȃ)NF41}r2@7R1Lv`)F]r zfCZ %"eTTJ;xp QeӚ^ҭ@֓ +;ZXgs_'؞-ġ'L\ i[,HH6 ;>c=[틼r>*@hewZ @XN}06^6*L>Te1%)q8fcH8ad 7$$$I8.FeIA~a@IW྄T Z15ئ5] \XjlڏϥRJtU /V<|&[]֡$WXp񢏢א 4 DU#-jEAH1g&m~nSIW_a4z5{Àׂ/&x=Xs{yU͙^sƒR.->3mUed>'ޱs<9 nu̬ l(wCC~|ԷM9.o$] o飮o滸s ;PO ӹnztJ+W{H{ƅr1i8}>RҬ6 JሖHO$^HHJM6٧!})FZ^pF~M:qCPn`ta1:Y@f{\ $dn'`c}pO}&# vmd//b;nҞqf̼(8 $+Cm{{Fε^oY|UOI%88d - 㻔,59@ MG_E\&<]urKK߰3UX,/Өg xxZP[T2-măgfMdNI'8RLм kS#@M!\s+#n$]Cfc+er_Sb* ͍~$!M58n>,xK&AY5E(8![Ƿ{12Cq~ Ϛ\Wu1u^+x]Ay1^`!99&nFiMqYz0zmhzwXp'obUK.!'  >4F\lԒ.ݙCK_-:5ͿLAjnB#eA/NM,By8N7n #mYEۅr'0B"A Y˒A~՝뇷Ⱥ{)B>Ңɭz<V01Xl>Γ:pP#9Z=wyx[r_`n`$d7T4Կ."iCHY"afǩ;HT$ޏ;4⧀)5L"!u23%,}"E)]"qI) WGk-Kzf*qx἞}vG++UEҦ1t:cG hj6i;8ףd'(V[-W8e| YJ݇8t/0vo8b.Ԡ\}ν0 ~WnP9EL9o8<TrnpUZeaĝCT*meMٱMR' Oo 2}i ]9 1 ܾ8cgKPA5nƉX$q*+(!u#]Nn $KI%rm%ͨ`y+ۢZ\x⏂_endstream endobj 387 0 obj << /Filter /FlateDecode /Length 2979 >> stream xZ[s~[bXOdZOq&U^*zZHh$$!e{ = v~[_/sX݂er۟ |K!LrfNaqž] UHnIrޮ,ܱZK)aK]q)XO~gkv*AjV7miw Ȱ?ԝʯq *bAәv(/R|:+W^`XϠUFJxoϜC-{'aW@Y8 ͳV"qx& \C1RMuWՃ2$C ]aY}eu|c&ڡ"Wk|d0cYWrnY9aF^EOұp lv1K#kX%-;lQeXCBí9S\,\fZ9Q{k+vYf_r^Aj Ie,, - ?0)mc Օ&.ٶ97.O?y'^ZRi@y-;GDv{.^c3A4g`G$ a@: | SY4~mج1g3 3R(s?{<h==\IGdHxZǺIw)K(Ђk\PHT/GȠFͨMp^:ҹc%/ r/%a#*1"wM4"h 5(A#/4eQטý4 OOF{rN^7g3 {l@%G9ƛ5Y]C}a3QVD088^*F#mMȪ1o <`:59%^ Nʤ)t5jcBv]p%=Vk2<( 8hdeTe0jOQ'Dy y}po߬"@/IU\X28 Rq\kJ4CODO!ΤmT }8Ϥ9~J`{GWn@jCz"jBBii&ôLɝ ` Z[RC$%UűQt+=w9YqnCɬK8!lJ )bˢ*m׬tDζOh*y{*09_1tJ 0/T-~bF;:&;lUf*\J(|Ȓj7؟̩6iˁuI{ݐon$Q)2v'"4[!ItPPϳTڔxU]yKDxh@P@ l+R\F";=] Dp#m"ɥCm2?Gw>琒A @tT}퍡N Lc8DiSNSt/&JTBI(W]hÞ.B?\;B8.}=F~::vov\?kQ3ӝY0?^/A׹ . 9`8Z(hS~ձ>TQ\d<󃹱xyпkb@< O#$6bٳ8w&]trG - /uN ~ɐXOѠiMIw|J:,>fjNvA0I{;^Bc43dsvI8KPFSw:2.ՍW@dCß ~W7WCϛ8t~s\D7tI0'e\W%p`JRG]oR7@µ/@3]|7J>*MC4[!C!`etgncߣSsNCZjbhQ &b\Gtm&x9$Srߋg6uG:.xOX5_`IV}q_QDW#OST2ri0a*yiIښh ʍU鳙/?._es&t8_JvgG~ϦدLL." ڊЕ7sXÍD}yif)Bv__vlZqoĉq&(6!j/gFXba q~9Ŷ}h]Sl9ZGN5MМ7sdmK>Z,wP;˪F[XRWj늿>f3_7#L~'?/ÍɃ{a^m:(|Mffk5qf |+biYi"&"BhG"suOWY$YLT)Ԭ^焌 2B<7K =͝NV/rendstream endobj 388 0 obj << /Filter /FlateDecode /Length 6225 >> stream x\K7r>6uxBW;B1B~H]yj͋ELSMRԯwfBzf8 5( y׊K^ޝug z{;yqo?hoq~qs?^;ڠY#h;X\\|[o;aCs('\f~97WR F6?.??bJӺ3TA5?{Hh'C=G Hu^'NRIza$:E[ˠ[Z[?n`kab9AaX=ouͱg!رaͻ5[*M=-u+caY[5_'N!E &~q,ZfwSȠZa|ڣ゚$),ypñg#Һzݼj6%aWyuzZX+~i%HZ #IE;GzkU:Ɓ)?_\vXMzó&DMPWz֏U({xeدjv=0afSiCZ[k\sMRmwLaQˠT"Ѱ^eg\?&2]@~_oނ U԰⇿~;\+ʝ^;A5P(`vb5Kpcj k65i|*Uu'~}Հ!3R_2P5%?p޼=f5uCԿJ*ni/x#[ZNmҨy 8dO(qYCH 00pY(7K8t`R! v*֓eROJ^S"<X)2h2ѶqȔ=8|PS52g"MBC`Q#]>& Dcx0bEy$gߖLySIM;4Df;FE0.x4K>rSMc1@pOl}*?0b$ZZO Anx u&glxëua3-`NUU; Lal?=A ʁu L4~|jB:\TJK|lHJѥA:=}>' W$4.( P7?l! X67K\.Zd/vd7kϻ4.{%{ 6u^Zvrʃ}slɜ?n^8t" U$Ar ulIz\[+EpxWp_!ZIJhD {i4u@a̠*Ykx:062X·nWQp&flDks сD,IURt 'u%Cv/4']tCݔdl}M~"ИNUxp_&~tT@㮊l8Fkf[=D92f n OfFVWaۗU%V_%{2 C;^}6iQC YSeWD9[c.E!Zl[Uy<^>2V+9 fqZh)/Ǭ `A2.;YC+|\DTA5zS(pF =%a~&},r8^Oaw“h>m`"VîE3LU@FQ"x:߈R>ʰHV 4_H<^\&"BjL61C0.MAXcj? ֆ! /t35:ՠU_&F!?Bɡqe >>5m,uhDq^,mAFc$\c{n*@v0ר#b8ɤ@#@<*-PY]JU8;XZ=BMb:oyewit>y-/HYP'+B%v2A..ـ F-l kCW9C0]qr`VQ gfh:$,v{at{]ߢڞkQ LjmkrrYiF97&)-]a]HlRٺ ]G^7['wl?@vSI}?u-rlIRC(@˗o@I.p8r%ώY0M .L)E ̕FgdW!}ZW-bxps<1@g,k&9|x骶Uv4%KB0g_0GSQh"`@KB2AGLQ󵊀skPIӮeW%Zj3` 2,ASKYDRjV2&ZwSӘa7Ћ`H(bѭ+twӯQ:"3;Q+TI)QjL@@Lt6/ Lbv2łZlygϐkT@ eO~b2\o`(Skg650VO_X7){[ݥFgGPb]ފZN]IQ`-; mV94Z$# 6 SEQ#nH:֞ of@v{=̯/_2$ ٗ P CXnj ``ҙ!BP Ye0 n4v^ay*Uhsܼ ArxSvN-rnޏK%?׬ !Y2 N~7PN < ZN1Zts15 V$SY+chasHQWJWeh$dCj8''!4glVG ˂hr(1 *4ej6a6QGtPL1߶?N.-Ew"UAugbNlIBe*`9P,{BS, 11E_^FSrmL)24$W%4Aβ2xa$VK ;龓/_.iNrx!Ԥ(+W@f& ,ǡ=ߘK4^oog9jcb9)mvs[FEa.hXe,Β8˗1?ou( BypLY-ffRV\U Yx&  Qt@6[ DmNR]ku\*`4л%H&שSUfW&UA:W 7V:θF,o1Pileer:'>oQ'Gy~cNtF{XY?b˲1.M+%#çtI>*>* juSXp}h $n3HԠǵ󊿭בoXih /UG%CVjg?z1Ċ S&7e!\$@+]sLC&1Z!-~`6+c]E'h&y;畴7V^5rPCB#Q9}8޼DS]jl!mHUUJrC[̓ 4:NEoQ9`SNUęViY0 Xm):'"@T?jb$h\*~b4M|{P=/ t=|t-Q8^Wƣ<.?F1rS--aDUs6ޡq|ס rk>gV:T&\SH_[RzJQs̤ u6"Ynm-\kCjd'1qaձD| w0')~QE#[Ɠ>ښIBjbAq5d(We`) ]y'|Z©řB:Ii:sefmI^ةo~-Kq lpݰ|_"F ٭*HSbG!U735͉hsnXYxjJJ)d2Cy4Eq_Sܔ6ӲXI7tVpNa 0P|kl}R2Ϥڢ*1mdr@e<gnН3Rx$;?F/Sr,cѮ'5\K7 1gͤ뢼/60Y*%3zR|obL ]]2qgOp;^0GI[S*}Mo7}RzUkN=c94-. 7yz{U>xU4p?6.O۴<ۢQЁRx'S<$|P`W$ef~AUjUTB'Ѭ_ YcBSvC);0#z[9{Qi_c1^}*s5!9lP+1װG81|^)9,z~V77 D̗"] 'F8Nh0 ΋?2bVK{EY-w|6x]+E!Aѳ8-taɜ\1{M_%CQYU}*?{ &^jgTrXh%0Suqv,ll_u Itfi!æS)4y}dW+1B7 ūʛM.g_oW d. Mu6E9`G@j`R>3bݒn gOJMGfH6Q 18{YzgJ=[߇rT`U>+|:孟VJ*v.K ھ-8L;亟khl'SpLб:L*i&rY^Xc?WT*>o9qendstream endobj 389 0 obj << /Filter /FlateDecode /Length 1407 >> stream xVnF}GaNg_@8i =.ZT\r~{eH n]yI0]ł,w ڝ.u|Zxc jU1K-5\.W1.к[qjDrMEYŜs14ݍFyK"*2n%r 0R:)j{WMUVa@XZgY *էE,]\b;3. WB!!&q QPPa'tJy!AS+l:UahR f,3ZRpԞS  4XY)Yޡ1q̖ -**3a;$IT/<=(҈3My DMKE8PQTT m=P RL%1#k`5KaYOOVΞmۯ&HڬVH8ȮTguNFGYxIfyɓڗ ըiҍW% *~}a0l,ڻ'uIAР;WMu%dNȩBPĎ/6C'EڦureF;tY:ݻh>wa]A-vc/@,j̩ǡpTWbs*?6`f{(׎>.ą,#cRʦM> stream xXYoF~_(P/p˽w6@8 MYi@K̆:B΁"W=|Oqb5Q2^>{:nLW_.'$# k2VBaj9BDFWNaư>ћuS" E NS$1(b{˴ ̢12x1U~YKjgs=d:_G+jPiX؏A H .}DQ t<٪NWc.DŽa I;|ѻz;#iYK{+ \5˺7o zI0Мܗ :[Y965H6_+ Dh I`N͢e@1X[kJz\cgu-ږ?ښIFEsGcMkqy*.M,$i<|0AhC2 Y`Ei;v)L8]e]$!= wIΥa`$5x4h~(GbCR:<*C{De Gm]*#1f@8 zW p m;L snzE-t_ӏYOanE ɺk`Jwjjt>Dr,d'U+4EeU7y'9W҃[ImYtቅgt)]ljnyv*zWw2_-:99:ś"R]0v/wv<嫳ׯ?^j|[t})nukj܎wk׶av;[J - *L8sswپ3: R:=m/*֋%B2`Z3kZ 6_' Kz'M?"rc֖T(j/'TrӧC L,oRXjLŴjSi\<]^ 7mqJl莂w( }DR&`*_1U-hB z{Ic0m ahP_,3Qb[s&j++͠CdHQ-sTޛP!߮"-| 맍8 w 0(=9D ^DcS5 8Cu℻N6IFٜl}܅62VY^ن`ʂ^F|cԞтJC#>Zм\MHr` 2OKé.knଘFC=͋gȼ~}I­%%AbE݄erj8+h;}N]6K;eCYaAej!9z#sKk+p&]`Q [wWGCŹTk@t_5Vt|QE'曠ҶBէ^ۤJͥvv^ a0Δf'ޯ; l{ > stream x]O0 ǂXҡU 8QC$@w}wYv˕]_:6&?G$ip,ôMqAup> stream xcd`ab`dd74 JM/I, f!CL<<,o$={ #cxz~s~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+k꡻ /,/I-KI+)6d```Tg`b`bdd ˾*p?nv.WVUUY!> stream xX[o6~0RjU*X t؊vXb-QaK$ 0"t s-_IY2;ΰޝ?ŧL2x+xNY")OcI|yЛWFDIpD-(@?hN2 U2I2ԂrԴ]odVT]ӛI@c.:bp- 'Z0 LEB^G NmrUWߖ:zѝkt.M(2bP,fZ^L?)Kl&%xYv+#iP;x-%PaN2"[ߟ$3^yNBMPXNf;Fgaɿ:_O~JkK9 _)]osuX3i!"YX}36iDd̈o- |`ˈS+RPjxp"8>cu沔)sM;0@pbF,6yM92NײZOeCuny|0:]iӘU;Wp^8Mӏ'`S% Z(Ϲ M^j4a>*R/[0r=9WGt*"NUFX#HP60I_??ՇPendstream endobj 394 0 obj << /Filter /FlateDecode /Length 43881 >> stream xݮnqv"XٳBcHX:/$_Ћ%I&q'/1FUMR!SjVW}W]?O߶_}j?_?}ُɟl|}qk\O?{~?L{+Ƚ3?~ߟ[;aF|?3ny/-gؿyWDwiѨ~|n[?YڟDWQ^LȽyߟ /~o<<sܟwܮ8?~ˏoc~?po}kcq^gOc;?1νO`u6wߙu=-Ohu_}6>[--$~̖}Zþ[lU??oo}tֳs\5[{˾Z묖szu9-Zg¹k9e]sWs4c"uWt)N9\{|>rmlG i2ΟlΝϞ9=~Zd-y6V1?Yp9,Wӷ[꫷6魏>Ͻ& s8~2y6-7 Л!?1NV9۞{MJSy4mf˜kib}44f"p}Nǵ:8g2`7_\ 9+-r>rc- ,ܿ쏭DpkA"̙D)O &1{ǯu^s/iKH??vq9IncwMsp49ιf9)S<[isZ\&ΓhrZ `u^{_yUvnb=y#E/m ̓]i7܂İ6) Zםѱӎ_XAJ{S\{&[:M4thT4MAI-+ZzqryO_o?1ՈlͱcJ6'>icw2UgS 8TY}KKa֤,?i\Ě_S]yx愚s6~=19;sZ_ E~Nlk3ɪf#&ל='v\__|C֏?~O0%zMWL_ꇏ7\2yxu淿o~뇩lm{\^7ij9`L{m7Ֆ@f=l?|4<9m>ԘGl6~˯C8Fb`*Cߟk7B_ZMG90%c}q~]mfzs9~oW '09o*>u;rU{ޜgПIe3qu+l:}ASMsO?Ͷ ޫK+vïb~k?cXx+s_K646~_~ 1(vӧDc?8m^3tjw,w_~{_7縓?.f?Yt_-1\/\q=:lօm~I8yoOzԲzm-^2nf,Lf*T9[srl2c:ܱ&)Y?ڼm0O̖]-~Ka[lWT6;(sܺ}4DfE}uݤ-!ڼ @? aͅv٦ɛ 15V/ q7uG8r̤ha]9{؍ry7lt˳-7;"4nj[mcKwS\xϖnjmɰ3_~{JF=wfW85fMy݆Le~nz_o^ww ~2gdK0onH1Pqi0gmi}|#Mug4qֽirp+Mr.!8>/IS} GZ20e(l].Ͻi 9[.1s =-6- mv̠M , k^)[g^Pѷ\eN~82ϖaZflifLj동Zr',-gJN fl 3%kpҎӶ?PafϖۜO/+Lli͖ゕ؟3ly5Bޡ3܁_R!ӟj.~lqόj (1cǤYEL.)1yhdYK]A-ZT:Ltrmfe>Ϲ>W[`g^_{.~G[w9t{燠);sϩ#A8Se?s=ls][o尉tWgs2{cOq,s:j䰵X$u_+Wm}>U6LeU˱-uj,^fꂿwB0k.h:R^R|ٜ"Sj7gY蝟9_n4aLZg"{0|4t'GddKkLq,ZJ?&kO{h'E¾t@~/;0|ر9߻8-X8 _vzO3h159r%3_=@t`l1w ߷`,<@[+R;iM92;+KZ"6ymmA$0 $]m*ssͱRaS:"Iv+RCky$5 T)du^kW˼&ب6ӞIm><ZX:R[6ĶzP0sDp! p) Us6 nvL*kPNS L&|O;Xe[d3T:y>>ͅ-'i>A 4-)?1(rMU5m쫭 )"alN1G)4Ǒb^Յ}Qq2tp?A~]ExBXY Xue'.!HE5b]9r-IU%q>}dѲ"'>mx ~܇]~8clZc~Z"_+A].0$T)aZ=)qq8cJL"  mavjkc?˄U[,3<\\K:lvGh'E៏IՅنOfȎiu4*K~%b<OLCsy8&0@ MS;޶4H q/lz^-ۼʚ"&Tڐl9adB 3xS-&ө%3l2%y$*ȉm%hH^phDdo{df߻l#UWLU XgJDBP9*^1׃G]{yݵfw- $_YU#yWpoÇ!>dp\7]c.R@,J}9ӆxy^6/}! ۝i[UqBgѶ*@}A0H/-mkZqcC)o3w2-z-X6gՖzl_aiRBԩї'vnp!(L5PЊwX3.$9dWTBN[q[ R0y[0DwWWP7.LsQ e0W񙶏^ ;`",'k]`6R03-{+L -|:!C>ua=80"E(2TMqΛL S`B\;٢PWJ(c6*EqA_^* ;r0 9.׼6!FӐ AwS)hY֖'@*M@4 ]|E"qf8V}Hy$*E 3]k9 NC̤`;_G  Se[?R17(T92YLޟ/;Dm^{zo H+\:^%ϡ,Yk\Y;3&`«d0E$Td ~Ӵu]2L-8mũXݪńpruA@b}c=8lbGR3qe| `6qAQ{nKOf5!2n"E(2d[Nse Cɐp6R by-3.288Ġ }:[ h<ky4=N^$@ػ˓@y:' 1# T)5®}}JHyc{@6zXa]f] {tY;jTͷ3μSLKK #EZ[|H9;$G @IJQ3jBZXJ=%$RjR Ђ2hҢe΍ھ~ȩ" F멊yE,DȊG(>-kǥ)CSB )*UU\$Mp8"A2-Kd sU2c4d $Pe,lhElX%(`U%[neƫ?Ȳ@}žY]=ۂ\1?{z=F oTr 7uE ?A~]E(ռRx-*X9 5^Ӿ(.xS-IX%tc*EV:8džsU#СozFp;B{I*(H}8TaI(B2e̩82Ѱ3UD`" ^]$QEQƬZr?A~]ExUU:Ћsf 1 4\sXv~c9v0tn@nV(<9ybLLXB"@ػHji-p0-2!GR#-,eO[Ӄ` A$]#z?=GUI]8h!GR|DlEW=#i]Fwi^Sa TLwSKwK#WĘC\v*oEq3qi >)cs-VAGtVبyfug>A'0ˠP׳mqngv.fd ?Nv&ܽD!]6=u9Dgup ,@@{ٿ%*hϰC;VѳE!lRs5lEUz9r`xԜgzND`dD( =G:0ѕ.s0r 梾JUړ`ViE0_!6 .`VveU`zp8IF xy]<^9x>uq SIxh8 f %CrHSDD CKDD+Sd#$r%N_W^>۩w<{p0p.(I?G: 8F݁k:V{ǖ*<UZ^QNvq7PE cq=_C*>#(2Tq?Ye.Cel#L(("@ػH*=1K,*5l7o>G9vߐApť3NO& dlԙ m)|SJ:D P0cn`hvu\/\k~G&>0,~$O2!/}8l_ "GR 8x\xR-v_1>jCH^r|16Ϡ@/2U`H}A.A.IQך?e>68n2" VokCv}U.1_,,@qla&j p0}AA JY4|7V# T)Jհ%ʂ[J/e+8dEw\cjVU%8zp8l!AJQvǣW6+D*0@xV--VK3tY'bD1Z- V HQl$ɢ]Ge,.GLAU010@[KA5[,#vMMbjA﯌ 7pn"@Xbh/yH=,\  '+0*˧tYGC[)9 H1^c8yHkOIp0kD ;H[<%-;R߻g]"ñ% HwnQr`K # ,*COFQWlZ2zs6z2VF,p#0d˅L]jUZ GUz*~Զ*x90 +%鋀AӵZ/&"]8l:2A UWIcm͹$%T~q-P>? J%E/K],+"> QVԯjy\YرǞ($@ػH{Ⱗ6vqu8 $Px]6V/( /'+ ]6A@"_6}Nlp3:Tg,u}F32ѽ+E0:\"18H! #jٗZ*~RFdef὘JDS^ Kx:@C(3w#Y9m]Ey\чƜna!f^=)xt/p!V2na$Y$"ë KI3$p,YpAIJזܙyDIc`onJXq6On!&P-󞳼$`C0Rd~):y?S`a3v0oDfN_±6luq| DЎU O77`>hYtJ}sl\a5z |'(A.x"AՀed=k}Y*@nXA*.@] VdH ^ AR˘=s7=G{L@ j9:NAU&ф@IJQtfN^KA-cw׼Aq"@ػH7M{xA`.NWMaGRëiժh1Inya`&CxݥzO.lqQReWVG .C[kզbG! a}! 2HU5v j jiM_Ku!  [Ɋ-J"wB86ܲ_eãy?[-p#;G 6v.pC fuVt[t+¡jЬR Zf(VϺυb{'YR 5Lx4étO„O#LT=Ä ` <@7)ok!D $P(;G™N=yr#hO8<#HA- Џ>FaoPr1CUي}. Rb>M lA>( _](]<<@g˖E  t+gCB1][R spi>JMqi'n}vaB) ,EpC6/+gybdy=4<4Nv!Y>]]d\[}8I]Dz'ջk+Vrܚ'7@n^c @Tb4"ea5|=y˺ :#{`"IfvƑ nW s(?A~]Ev. %>\e VQ ,_Z%p 91#/"*UYZhʇTF4ZDP*]Q|lRCi@IJD;V TV,ݞǍk<<fKUJc*{ GJ, GRT~:٢Sq[Mn0A)x*Ay2i2lX*kSd¾ |.|gr'PDH>t@@HUrٴPd%>bRfZP.KGK+A-L `l A\ע.IhWbt Wb4 IhV^^\EoY<<@|i#Gs|fnYgQ0z0G!GRO<XY-x@> KWU |ZlK%ӕ@v2"ԃm-*~Ż?zwՙ'`UT<`?Y{h. e+9=/K1Q a# [v^PWLF],5j=9Xʰ|Xb} x!b!aΰ|XLL@m^N~y\`'kA U*st0mB $P( ʹ>]bb{;+, ϯZOMvKǴպHFU& UXiq0J:av!A@@ #X2P,bOߥ"?DMBU["^ T; #mȀcs1-Sqv6zR0 <@2wWE?%ݪ_g.h0VBPeI^`{31Xgb"[ LTIz&ꢤlڝ3?mS0Dȹ%[ucx&7U}Y[_.xc\;5Ow޼$rnWY|7p\еv^VF:^ DNAaw#sр^rE#fN-y{ 37允7EԂ7Q@LPԜ $*jxŵv qo_- wa+¿1OuW <"B}}oKG)"9߬\Ww+o8>'|r$cx]d7{C ZAzM(9?h!+D B+93瀓H /)J|MG6a`GD̍V&)nVM^rTÁG]x f?彾Q6]@ 0l)n^)>&ӁUj|ޅ )`2`1>:Bktg-\`5SX @ub[Ar`[Jo*WcJiNNlb@8g)6dJBG芔bRRT,WH=g̒d.(pɼ$j^ȒN LBQcS-(s%4yFMY, UdS-) >TeS\\BHVH27;E;;VEXbA-'40-4!A"-~MYAró s9>+&xRvZD^G" 507e*l.!A?SK5Ӷs5y#nT]Cyŝ*c:u0wbyTB-HZgINAa' - ཹ)G}8 PK. 8S.iw#1'DP0DTKm5K 8 óUb]b.rp8_cK )Fic 7_ic*GJSOy(a+4 ]$=oXlNP`2<@W]I˖ Mɷ{΋s \PgXkN?m4ҖoP-_d>8t>GkN 54k֘KF'ȤZ]0]H_m&З^.",RF9FJ"qx/Uףt-؃o{z|~0F\NEFI4s0Tdf?pfFa@㖽Mc_f xz I%Er6YM @=u|bd̟tjXgHL>%—.e%2T{7e8N3!GR6Bz׳ [)I0DkkW^63 Aiԣg"gG-0 6扅dB@G-0ѐ,8A6@ HU~2S:S 4y]d]ߨĔ"$ސI@PR])zAvcQܾj>د֟si3? w]8ri@Jh+27Z+672d "0{_)rN%k:!:! z`<05 =^]`xrgw{ ʴoT0e'l4=\-VfOЩp a~@Hw3Xxn0%)T9l;VF'<56#{0iBN(fŒhawLZ# T)YV^`[:M &GI_хiwϫq麟ν>u>y=tc>{k~:7Hwڼ<)sӫ JbQi*IJ ;5>KI,!e" s}bSyc/~/YL~N9$*CcUELx>0_ }F*+^q#V$?F"HaK|n l_.iM=u3=w';mPaL?z}[pg%F F| hY֟vڋ>غmw+lqẽO-_}B΃O,,KTuX WGTgVuRԟ!}9ድr> ^z]=,.IHPɕf)8օu);8Ï@dZ" =R L' c'?1܃BO8" 8Q}D$Ha$e bKPxQv z0 zOJ`_$02@ HUף>-#M+{ 0DPMyx+VvE7ZK5ly$*EN3>S:"g,"gD!׷Բ-YN1.ag("n.p\}mB2+ɧ8_\ (蚂r5 // $"EE— *og14"z;K-xJ4Y^rקpJW}^R;̈ &or {L2ENN"GRTkw3mA3=ݷ@ LϥxVt5x-նٵdp0 YlOecJ GO%y.PǘIwUOT pүA}]unڵk C̦| DYA'[Zr8F"둓"\gV%MIkɍۂ㑎݆Dy\7@AP?!xrC]Q1 1^R_E$Ԃgp]upܨ (nPP]oJ0PBWjbKPxQ-m f bЗo?{8La!$ .e֘x# MT?5~Woyw Z%m22〿}K"J |1*\Iz8x y$*̽Z8t)}]dlvv}rV}??+>>':[l{Z6tO ϫr{j(#{.M=mG)ZPZ\SJls蹒_-1)T ʲwWO >7l܈Vs0,!`݈a",+qR1U=»%HUZx|W;Q JYGŻ<ŀGlNvL8u"qGEEQ㶳3eCk ⺵ ΋NY1κ|#LGv.,S+KmPZ2v&I_-v/T}8&INchZJX۽RvVT1& Y-:uR~@yX.Z9*P(T9^is*_ʺ=k<> W,^ʺ}*ŖA5؅@"GRT`7G U+jXsp9Ky`D@Pѳ!"ZPޜIuCIzX 䇦z}Xxȼa)C%+|^lV?e푕8Ha"\wyeČ9|hy0\{qoHEkq$@ػͱmAKx *E a4U Xa X-8@ BERp Pxe͝QΚtbHis0bBP\+$HZ]9 0bB $P[zȾ9CYҽ`lBPE]ĖhoS~fXA &nAHf+1HO\LjuAiCF >`灠]ܿpcV2NSea/`DPŽ.Vylr˧S4aE V?8mM1F`?AAEGZkޢpn~f'`e>q7gYޅ pB Wi0K;B#N;03}{XG 0OK&a"cm)b? ۏr{3 o'XC6Wζ#_Wzsw ??T-_Qx©6k`qEkJ1M9`-w)j[Gp̅h w[ ~st->[3Y=Esh#FZjvmYo[m] m U׼O h uF\-k_+շLz-ͳ W]Щh[˹f2+r+R,U,f{UhU7m/8J-kã<ǷWd~Xt쫫aem2<LF{ơ5jSSqs#Qs~2.kƏkBjϼHY%OG^,.Uj)fgYz3-S+܃m NYS }7jP@L^wP ,wY}yBol ZC XX̅7#u^gy J}iZPlZeׅCB{Y(oe^PllPϵ&bjah[u((&MXq~mǟ3ܧ9~kv)\0s`4>~_~~پ$ÿ_}?~7X. }pP{ɺL7<\&e&m-}x>Ҋ/_}-[e,w/~?o>GAvXu-ckv0uDMת J ey_F,,ϫK4u\vh8-b9 iYu_B` zJ-Vsd^l*bSq `P ZnY `LL@.תwg[?~NcF )LH܏佩 iЄ&A%Esi"z{p-aP$$0%(XŶv]uKe.Pu&$ٵDꞅ.`Y>Ҹ 3W?yX)w?iw ?A3^iЄAA%D f:-&8aivqRrԥ`׎ԇi'3uÿZGѲ*&Eq]i;0@Aضu{#FK^rÕ,[_דp:ci(CB;׊{mwFyhug$}HX% >$1V( L3Rx=D4ڶD$3u"ȣf`i^DF!΃ )>`V#OkE{Dt8ODbKPxQnWV>.V|\m3C4IT Q>qާ+b`I&*G9,r/tq8SϽcVZ;MuOt Ҩ1LPh}8FM$ yPZ6a`{  yeܾ i s_g_+h9W8z'f>C XX#}֣ PT?쯨SSԩfu^թ~թ}TuUj["YeY/1$ !J!υS?8{`Ff# `F^#D U5bAhY} Y zȡdaxׄ~2MY84e ˖L)!A"X}eOcF˽)%.o-@pvvC/KFyXіa 3X YU_`0/ =H2@igelB T7m懺p0I A%Ivm=*;Yt{^lI^ˣO;nKb `ԅ y$*E9,,Enɠn.O4YF U HY?W\P+)y .!K|u'ͷ-±3o|A[cUcCepA rI U|]2`#^ok3a'󎖱aԇ0$"D*}cǵ@#dӦ/$@ػȻe<@unG+B n}SnG CeP}v-|&=y Z6/6fivv ];VdCP8VAu` A%ED˹tj=1`B圣X.AaCW("Ӕy$*Ead,?{.2b:!#]8ýP'xyfl"j0  (Z%qb3TʝlbYIoۖUNIw2IwQ>oOmt'ԅI4?Bʲm {-VjY1=ۥ|gg?ӟ -&9?7̝;l䏟W laD-$a&iqjN'0pGH~ q0x$,6x?pKe*场 &;|/aE:l, {j@-K F /נPxS+qZ r:=lTdv N +D2kcM3d>&Mص>6r/;Mq{1g*O/qR/زN +tJAؾp.\B튴gaG۲U&]?0π[_y`7䧵k2}aLLBX-,ssŜ>'ēB'ɄEDʤ`1ੋ&wϫu28c=, 8 ;2+.v bIRv~9d}ÉbnbX9OF%+M[H8#*A}o-}s2fy,W 4y& 4M5\^hR4A.IQ*+#=Kؓ۞-sTPGЈ"ÊHph%a˼I3#bKRrTTfVW<,g1hCx-{5>.b떽G5Mf2AԚ'٠Aziz[ř@[хīAIJQX Z/&x1Bs Al/v%pRBA&Kb^lwe=)[94?yٍh6RUOS $0"(Hiaw8{k1)ܸ[:p|!]V>=k'x=@GZ_}{ݛ1% M Uj8F2sle ;ǵ&a`X ;0dp q2KŖB̌R1Dg#WL̕.Xݘ\^L.R1o$`)vW$Y"q,rέg2]%7V{I|DVN-& VI.4|i~^(Z29"aI+1)}|}#XVO]8l] bIRTGdDH8 =!;G68l̞'=-x9=AHJP+%מhL9pZf""GZfqz <)gԇi \Kzh[=|nm+|\B\{ɵnYl[ .=DdEicxIh9Iԟ3nN |!?[ <.O> \'͝K.A.A%r h~VK_"k̎'AIA:2Z(Ԍ> c`,Ӎw0D˵nćx q<&|tRb3c2:A Ḳure>u bKRr :aKKVoLsOOs{8y*OV`ѲrzsO0vM /k\5M#>ؔ4}):\p{oc/i1J>dY$*D5[5^ Cfg+p"]l(#`voq`D Ηߒ*LomR.@A-V:[mHf0N 0> Qly꿸s=].lKEr) \Eaق@_DN8n!AQ+=7CrognLhh€h$@0Z67-u8ݛ!AJQo^aa>+À gV4ݪ+p크 NQddC#>ZGx(ea% Jf>2v9Ա^Ȏ@t,p,9KĠ#{if! N' 2 U5'AԂ0*^hb:~ 8(V [A `B..EQŊl"nPŝmREA0K 7#{ P{ ^c{Dt[{ tn-"{w5VNĽ`A\ߜ+EH9FRjm!5|!F>}(M{Fi;ʤ2BҭlBPQSBDx,D-B~1Zp#|b޾}ֱj_;YrR&wkMж3>lR |35ZGE|C' PxXT.,tJ;wwsu䬩t|_iOͤk~uʢxw/~[RRT{hh [I`HMijEOyp?A&>.:+P-p oy=!a#]y>Q3PCW SiwWsH~QG6x; {1\}[o?ᵢ`5)1A 2^R-ϫ^f<ؖz2'-ҡ24K\w=<yHDk3AQ8Z²ٽ+ +*w uE@*&CTyt-us 4 ~&H 8W@/GWΕ>,ZA2548*~Erw,cU\ω- 93嚖N__xSBA㤳=Lmvp<tq%I*n3kό;UXrvmz88rJ|[ږ p 8`R;$ʞx,#ĸ2|'@(l}@:qƙm`n*%yM,Lʺ3KJ[ҨPaћԒa>!ݨC;%ah4]F0eAityaa)7GFQPJEڬoP;RgH9%tQħP4'9dN|x,Gjw̙_7@Dw$ûQ@}tCjїIIjT8vt!GW~tGuY'דY<G~tAG9T?+qiў0I E[!KBDڹ.I]U"|G6܀C99 :1vDa_#hQBkޱ/Z;=`s{Gn >ޱBae/0n ƽ8rcF⏚eL쑛0kN =Γ#oSbޝ{L#:Hz^'~~)^ Ԓ)-ChSLmDN1ZN6ȂD٘d#L+tM`:;͌-Ol؄ 3e`?'8*F"K6`¦c.i)ʵcأN{DzrPDW$6q3#M+x]߾1ըg_X[.;p:*h:&MAl# ]$M9>70奄"K %m84;‰9ide?LmV9$.@ZIrXQ2R+@.HܥG:1keY$h8XHg6=uN]Ј1wO8n9^Jhz vcUOaJb88A h䀽%+WDV%#RWCIH –}m=ݡXF.=i[O 5Zs]·;V\CvȖb3'3[E6+sQ\$ yT\e}0̳|F c% 8`8G KɛЫ}xͻۛwW %QB԰z <:ڲQv0(taX!V;k/a u5#PK G8[ݥ90 J U Df]pR Stpow:=BgE 1z6)\%ta+`ۼNFŀMQIuR%%y$xg*4V.N p_AlP C H u0~ajZU%@?g8 @ z^,HrYϙ, R<27,Ý y è>Z'?_w"i v9\3tҐ:Gسa)QbwW[ҾcF`W=<]$Jm8RϠz`w]rLl@l[1hWJ ެ%IJXq+f98JJ(8[?I͗9X>жā$ [b[Kh"Ikj}$mKL%%y8vWzZm#ه-sKM7$y>}?ݼHNX# 69Hg@[vKΧYImrpPQ4}j_}:t񛜧(_7QCg$yTEd[a-OZWi"r2@8@fl(CEOEH(}mkHSKݲ,F66]K'B>9peM0=.YWT` 5Zj">pH$ַe2*Nw2ùDٙ|aQ5냀v39p: Ԓ!6v?7hɒ׻ywɞgF<Վ#Yr(R&L- 4>#g'ɀ2p\,<k,%46^inRbo)I . LBf%fZXȤ>٤Q#}.@mGE9!c3'h80ZJ*[Ш-aM9@<DZ(1#sbBY'&/8fYupZMzm/UqpG Dd\w9`Yr =n!4k .@v!z)Ia꣠)~d2^y&s3^VJ-ў-ȓ78O<9Wx͢&GX+g~Jl6OOڔ_q0Hg;_{&MGI u25Q*(vX9YkG IfN.,adI~R;b)Ρy̯kn}+}Z[bG33UfmkMqcʼns w!9SmH/{}f 98%. ,#RL ߍH:(QC@DMOgK&0Mҧ ψӢ .6e|:5Tog[hɁOMH.[lQKCM6ھEqpPfa3+KXpP$M,Գ`MU*iW3AK\[$tlK=BF%mq0nD/S˲zsx=$9D>^'Q1Ў92V$ ;h;g r37%lreI,^pgjfSܗ'+(4IgӠ8jm/Ѽ4(N$9 2 ]ErWkyJk0hW SkjҏX6H  2|6 h:-AǰZ5rh)5 Z 43$&? (Y30#N,d%ԏ]q`PPQ={Ӽ6QEn1cc<𰁮jr(Qyx͢VYۣgm%xv @:7WͲ>ݢ@IeUj(t]@UaҴ)1@YңӦo ={HҴ)1pPPK|K|t 'G.|HP5hHP-hUz޵LC ]>*ۗmy~<,eFo1Do*ħ :&ƽ:Ò6{|,Aˏ>=. أ8w%!e#tBEgZi'k}5shx37+#m=%~ݶi>CqppP_9K[kW>R.[}V^KSt`[^f[[CҶ׋C$JpT{,m ݵ A SM鹐0q]Lmc) ҧ9< }u;^Fh6wkU)v*W P\|>HqpPQ/wTQrpx9c@%KA"nv -a~>~iǦ֬#=V9hqkȝ^e˽Fw^}:+ppEABǘlXІyô{&k&=4837, yhW-gHK@D%uAc:twò:r1*M\9V\V3Ց6UcˊuBYxl5hH!Bk5 ᧖ޫd,YApKJ }r툃a"e8rp@$όJIeߏ$D͍a뒶7F  W E1'(@+P Gy2 ƫF4V@YrxҥTE5*}I x!/YWZ_:rНG~}]-cŰ*@2{Q2A,c:s?PKlj]bѠI;#o8PRe͉e7McsȡACB g[}I NHҔ}1+Hg]8"$qbI/;@@+Li:UYdMMȴ;-Ub@.>gl~f$kD䲋$?gl4Fx*I2*I25;C8^Z8@@y$!RBDu[\f~ 3;ԒZ> <gq~ > rpD]}vUevvyBPYۻNp@Z2û]6_Be (>8TS 68 3A֡3O#;uCMxQɁ6Wd9BIvAbL2qX)A1S`)JŘʞSp(ƴ7pd>sSClv} {ʈ>\^RCMe098JHxͣ'wRʳ?݁H?BDӑXf(AR}gO);ZZ\&6&&92w]㢳o%orЇ,( :%&QK򂁏ꯋE|?3А!y ^"P_ԎcJ%$6k6kFX,( s֬*Rs֬`jFU8#Y$ITGs2-*q4Km8pFI.aNJwzM*17qN!M u $R#e 4`O@ (tvV$X$UÐ.Asu5`iθQHZaH (4W JIfFtL^Ǧ@K^sF3{-\F G'^)aB- %̅0XX&}>֐TbFKL&mkJ,1I [S[?2S 9D>^'Q6g&m vOSt*5`ѩtUF q6s+!ȠB9`YyL %9ᓤ+ROqї jY2_5RMQР,rgi%#Vn` )@[ JC"O &HuU%%kZl,5x-Ui)ajxfL(R<t1/x&fQPQq(\fTL(iUt1+CvEHM+ni]qͮH+CvDH(5/_.ϋۗ5 Crb!)cFcϽgJc #R:bx;=}-! %q)E %]ngŶ3.vmwLqp`3pLv8*Փ iҞ:@*qsD/38 JR](90F )To2t3FDۖ6; vw9mه-ylުN\%Vl:lXR,3"nX&h!\|>p6+s~OQ7$y )'K>4j \pHȡE _f pd/2.|H<^'Q@Dk>śnS)9oJ ?Eߌ@}ҵxӸ:*mL 0+`}hnE]av_pÍs4n%7?Ճ)@u4 uZ@zNM$nD_PKK1~kZ!9QBk/a.h(Y{؝X'$S؝ljt$a:)Unw1GqFu\cd/9Vբ\*(#G)Gm*cD9 #R[䐐6l#r7?A@E=Ҟp'990Їiw+߭i)c>(9$i4lf7zB%$Qa_ܙ+PQ]w$fL.Y@bÇ5%QG]41Bk1#iP- Xo;}Nď(3b%ٟX87s&tOG锰E?H:(QRB+zi}z]4š^4I1.תS /T˝PjLl˂ʋ%pU%em0gU(8Baтadf`Lb`0YT=^ u _^L+ %tP"Ӎ[wF6_UX>Ÿ>,ehQb.d`sb`j&SJ׵1xt~SHYM^3)<PSx}n.ҟ i9 S(@On)5$=[ GH#M{Z턴 'Ym ̠2QKxuk㺵(OK3eZЭan-Э$JeɀF07[Ȃ<[20Dg3pKywחG6{Hsيc,`^+nwK)WhûY@%NI,q' )/g4;x {JDSm'ڽ)-jgVPٴ!xNJxͣŷwݏ pu WOq3mb!5 /\9#HzC"]@f"tBga6$ <#МKVI{ʼnD>@\L?@rpԐE ;.V``Kki<%גZ=J }TfW ,!Z-8_'_'qB3'uB 竰<'?85 yXrXb6XnVY A+6ݷQP`v3798f(SXp~)Pʁ7FUpolGvpZo WT7q'xKkkϰĸ1:7QmI-3Pux& h}RI)2,`HaKۍۓ 78&K S+G-_$%lOrmZ88JJxeJ\+i.YTCUSpy*Eчm+{+}Эҧ{M:S]D4"xeIwuA)^ADpG('m/LL:*Ej"I}C𺭔"GBuwR;H{[]wq&}Oڐ\!#U~3RiGѝ^ǨS?9ڒkHfZvP*AC:Z\91%^ޒ[ܮ0ĒS~Q"E/+#L trp||eCûbwCn[r) Ӎ{"m:rb,!v-8ಽ@冎[sC\KRA|!'sJ|nےcQ"G"4A38cDJmP3$^e:[%cH(S coj33Dߥ,$h{S{CrQZ"Ȩ&9D<#Nٯy6nAG.406z@(`YJh`C捫MR%VaȺa4]EYIۻM :;wED6I$2Z&mJJ"5+,}G[%gX:\^%Aa;6 s# Va7Y8YI/km2vr|3J9_~Et{S%s$͢Iۛ"GVǴt۬CwnD쇺` se] ړY#H=+EZT[>|fBiIHmhEjcqYHih[;-H H4hZQBknܿ- q!$'i'؝$bw͆{H$U =5%жD*_Ŗ-ݪ8XYJGr*jz0k<0@Ru"HK-yBHRQ)w*;84l.YPVB? $+N4IB$i(+d ^e۾䧁AC_sq8~S 6cB!EdsDg΅x\8r(D}G>DbfV$߭FۥЁ[yP$ITE>RQ7jםfvLD]'tJ }"Rw!vM%%y]䀘Qn?$7q@Las$n%i&oQue05ω@Lsw q ̖u<@NBqhАP' O>m!ZKuH`<;9h] !7M~ O Md U8h_kG *uE8v,~֌F7#NV˪E}<7 @) |9l"k6(ȁAR@GYr9ofq0UHg~X"hIe<w-ڎcq0.4f1W˙d$ h94nHa|g/B(!G>5r(iuդxդع|nyv"8܄sCŤq9127nR$ƽר>̤hՒ‚,.r*?*PB0*<1%29 r $y\P3 L<3}ƒ8qB<pD/8(^0 ڗV \BHuu ̲G.=#=!At2GDb7oNڷHrЀC e~E)Cۑ{䕺@ۑ&X@:#mg'#i;āAR@D )2WADENbpzO)0G ዪ2()}p~cfA{JtJ1m1~}r ; bpWy?0'+@<%|P{KCDs],mσ{`^9d\ }؛:1I^,`ġq/;0s$U|(21-~Xl\)@rG-+t X.Z{4rpPgQFulΖU$!;)tvaΖq7gK$9[Ƞ!9XQ}@sqE|Em =ACVW/bNYmxoYV az(>rp0l=<*zxh9Yllyb5m9f%X чoV hFUw&Q_u<Í`3,Z%*!9QUQJsw 5B!::GFaiXیLMsƾwq+BuҐULCҟ3U"%IoE` S3dJ&;\T8 Atab hvxGC^Jf1δlx?aڢ ~m8pg++Geýd6B0٫m@¤y/aÊ[,1݉B,ʾѮgnR9 q`WهI numGI u? _^ e2)2Dg?`ϝk@Sc,ޱdxRm?Ȥ7Hd#~,k% 뒵=GEC_Y`1P0.qg+X0BCj²?gEq$>Yd -!Gc7$yd Fկ hujUAq{VR όW濪e(z[Zϙ O®F6sTxrwvra|[P\}p>'H u5Fx#_2gJ -_ZM؅|xDJOnxf#S[3sxVlġC`]&}TFԘuh9Dl(d2TAЦs#}ϚFq٪Pr_}tU5;v0G͕+/ !;ǿr .qŹ|8]i;Ƹu~ 1sLj{@h~(%Σn:!mqKLbLmQ$EpH[iJ[ZOxT }"Sݩ\jjvH -4_oCbJJx߆bC0Z"mZf͙XM'pw0ݖ-E3~$/i7䓃Vݰ2qoP1crH[;PdA]~k()Σ c1ќ2?0q$Dž0 Lm[𷘀l)L!бZemϲ`J"鲝*鲝*I)PBkn*U Ft΍Xsn\(As#V[ڵ܆jN XsfSu/7BoϖہBo;_Y3Wm $g|kG+(h]s$\m<ty< Ϛ p|p=ݓCM PO-At[+.i@=J h5`$ VRA4PQB 0_${@hxL(H ;2&l9;~ű/r4%] SkufN fYiy+O :4@5t]/ fDz ua2[Yxb_z@oY]#6n .!P=+R-:+̮Ka@ZjA$ R}(R GI uD{h ڔEq(Ot z0]1*$=vՎ+,1I{SAN"u\{C!C@A #t*HTۨ<=wXD0OC"(A ,1Zg 1KxX()Σ܍sşe.}I"%.|u) 疐Y#i_] )L"'"g7Oh ȏГX<%N8Y\ (4.,EP)!.@~Rb)bLmv?l;3q7V"6ѢwܒOD-LW!UExILn~S`!*FXBec 1- H}j^灦>{ DÃ:6fӔhd^?DKH["#*D- erǒи[V4zQ ޲?zhVžh*gy->jhKЀ:]G5YE| ϊǶetoisg "ۈhI YF˹%m<qawr%@XXcQ8cӊ m`wW-wexz˳Ak$xڸ0e0Z;5wŷ[ye_ewj'jevlAt7[z PL+lsB1Lҹrq[([Q..(eLq:uzoi>7_׵2cme -HrF9jFSiܭマY>__O?|sP6r6>[q8\.w2iQ_}R}2}.?*Hn?o>h_t nk o7}/oly9;[} {W?w߇}.Z-x?:<߿g> Oez_~OYwwן~~rK \;##~~`Xc{ǫXӽ$Oxg3}]K =??:o#/^/?-~?Cψ_N}ǣl>̻Uǟ{nl0g5e/So`endstream endobj 395 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 658 >> stream xcd`ab`dd N+64 JM/I, f!Cwҏʟ^<<,/=3#cxzs~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+k꡻ g```/Ia``e`be`bd,bGGO0}M DK_7o5s~yỘT\n·~罾Ό3f0 zxp9,>VX]-VG+~v-lx|v.[2c|W|#B/_~qEqa?dDNvVIɜal6#}~|^RwJw[wᔼ9e¯sc ؍򿭻SL=i59^dw醆Y] /[mL~E_aۮ|[Dݲ,=\V>sS)n|=fXP#kO, n #OD*gs⧗_/v҅?|_8{! r\,!!<<ܛgAoM92ryx]endstream endobj 396 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 617 >> stream xcd`ab`ddH)K-LNuI if!Cǒ?xyyXT({ #{$РpMmmʢ#CJKjqfzQ_W◙TZW0<XMD$X~e`ahax8*JU 9+ _%-V&usyo.[sjߵ<.w/&yg,qF;߲*6qv9ru%z6͛4wƪts^a!__ 2g~6?߅f[=o[7ǥm .~tc-:?fxLF}Nw̞wV|dchΦEKy6vNIpIt-o-WSV|wSb{f[0ukѽrnѳ[#mbC|_iyk KeK5-RW[hی%W;|Wdž)=gb.];4yxendstream endobj 397 0 obj << /Filter /FlateDecode /Length 4645 >> stream x\KsFr>/>76F^Gh6#KS{ؙn@ͦffcٛYPfsa@Y,hjh?Yl.~ s[W\Ó4,o/'dB U&׻J^^mu&C4Djuԍ`4Z_.Mv'%c6V7Qr#K1^7Wۇ̰ݡُWT]?b0U<"iHkA[dɁHY2"kbDtxoKAym4öŇN]N V]v}X 7$ln(/~kӇ~]xICݬ@;a._^\k6E8m ;7ںEϝ|ђJIոh5-z2n'4{gU ;=J!R{@_a4U'*4p^}(y ha7Al/)(kjjZ5u1ߺ%+fVQ#aH«z (nᄔKAowzUa9q>Hk4fԊ:]⒕ZcN[6Ƙ{~ ܩ  Pnֿ:iД(K-c39EW ͓ :W^ls3n[i b,>1(Jf\kbs*qKC_2[^xzޤ#fؕAT:DUƝ|;IǤxxٻdp+-v@UT%,+mK;/Y(׫p^F䐡-Rvsӻd;T\ ۶oq%,u߇.4Sr-#x.HvunvUeG~oDkVQֲf;N~aZp#9u 0`c: H:`;5s^ŀ~r,Ɵs)@d_+8?ӷ߽3Do]twU)Z\s7(>1MC&j0IkMuR} ms̲h8T i AZH3P8gqKBp[Mq&x?|N:A *18tlpœ^m)j % NӐ 0nj#C!?,jbA4,>.!=0]EI4aX-x{ N`WpmXpl\ɤB!V"8xt @4weLyB"e󻽟-{Ȼs`rZ2O)d0ˆS>*Ϩk m E{I:L$Pixެxw E-!_]/And)1bV!~|2 < DTVXUB%gCPX`ⵂiM$S^M*08񜿛~׏/_^M4/x0~XwwazvXʩ%[u`=\Cpp7(Zƿ򿿾ؿi}SK$~{Qq?*qkEf}O0ZQiz嚤h`ɘo3z?⛄ ,aIz;\Y`}`Y[I &ma}4 * =>8JBḨɼk>ZYb-xD*!ّN- hg9/l8G-Ղn뇹~OmRfrEPʙEhdTCd$Rx)%i}AH-:]ϊ1K2bҺ eٹLHxo:'`iNOƛww0?xԗqR?Ӛ#a,*} ?d?մb7};ۈZgd!8Nn īcWԁ\; "vwkI ЂuiRzzq9($S5|C8Nmkꯥ FpM o[ߕ"Yё1DƋ^4sKt y9b{wI嗪eCfagv?! VL- "{L9~zUԁ'JbCƝ"e!gQ@pr.Qnas.Tz|AxZrYVz U+P;т-œU,A [\B{ly p4I b,z~*)h*ɨf\7m 1bz1٣r~R` *^Pb_$Gq@J ^0sM9aGCdtQvG)H-mJf0.eLuUjsG\"jxU>}hX4_hbU̗Szڀ x |+=t;I;,S8/|N MFG+%HՏ_)U1V#C7dW?n#X\&a`$H9S#p G:ˏ~ xWk\"S{ p017?V"M/f<ݮS*AlSa&dKTQk~n2WA%%o">CY&^ 鈸fC"e1DRs zfcVsiZD 0f)eKsf1W67UAѬ$*l ';ȃ`d'qxW(H&xMv?N#nYt0g|F~H>7GuPw9#%dI/DH16ѢR{,OW6.]{tOV} S2r0*YTI(\)3;Wa+"6hgI35#i >y~v)6znY/-hc^<~ReLݵܴ'jѓNOʏa۳s/2WsŶ4|iؤy#Ye٭,7pb@Qvx~ %]KJ Ǭjez4yf,#l3&mJb+nq<uV8%,j-N߳{yV岓*+AfO\llIv_ogݛ!a"]Y7‚2T>sq[vTLivXVL3=󳗾1gx.;ɚ@l<82S75zܱn,uRP0m=BMIX b4;{_eqvRw㹞cIv8мNp,[=IOEg gMUw峐2W_q O> stream x[mܶ~-@?TdUt )4I(hF\V: IK`Dyyf٪U]}*wsX}p}7k[]?SʲQvBW]_cmfF۫oN iv% k\]oˬ~Agon!x>ܤ'}r+G.)/pjC7t#MbpWuDŽ' `dyW$6im򛬾rP6Z[HWKgzVMuzϲvV:n]\\֮?ô}|#G~|@``H'ߞ}8U7xOWBZsM1t6rAÙ (N*T䐏TpNVCQXNjw>'Y98O n 8 ->9"}'939C]{lBUCf>!陚uMP5!щ.T %i qY-\lq@{mǿ ^ťL<?{7] "q{ZP]<v`i#QRO~ D&EZsSl\e;!r/=g )oVy>d:ލ_M%{pVm7h%,麭vP2ܗC#KMߠ{MQP}4TFAR>1jsm4uvbjFIѲ)-޲hF<ֲ@$y]g^2Bj31/X{#~'^>gz+Eb*b!4}E "Eİ~!3oG DÒ5K!$VX' A(agnDN;+m.2|OD ;V΍o_$FV9C'vQeW}U F ]AK0ۙ$1vdeTQuD'qJ _LjUQ {AUlCh]rGb FE(1Έ&LA˫pn{棉K"Cw"t2R.y;MnϦ)?OLǶ#n ACU@lȳvg\yޚg5f15i CIpȐg3ʦXTZҙš`EB$ܥn$"@":]w"J'SlM F {:xCwk0sj5~f"&Ӯ. 7a_ Q h.]ad$ݘu}_]EuΚ"QfP>FFA^q]Lxk`ZH~8 -Oi6^o!۱`Q7LwR!䝩P3MgrX"nwD;{ݥoHGn{` f5vh'jM}O caػCuӡk` K1m⎬9NJ-lkPct?6--%X:nWۛj$+ ?Ǩ:2t]#E}K1F~:=99][1ƪ~Q1#TXBzGmSt?B]Zx<Ε(dx®^]2<^-q8X,pF; =(`hBrwIݹ=@aj8IS `UB3fa}j3_v:fgh4.|Zi ]r 1ס̥A_<ÂG2v @I ҃h<%~b*:d,ھξtN0ITgH2,:';6@m`#HNd^IJbrC6Uzi_Şuf#jqU3(e2j jشwr@7upF=@*2;C} $y.ͣ[h#!bHME}qs38N-Mg#۬F$(O R-|:0dScVm:/_!嬙$kSxb"fE]p]9qRKWT[vx5Gt7 >M`s44Ԋť&x\,5 Q0ĆXNK5 뵣p`lKYFRyR 5ݕ#Q`GOC@}{^ uK%Ǐ{`>I/Q,]bDp8m7X?`o[óӳ4 rEHAƞY;.ϣֹutL< J?phjeT6)~>SS3H[BgggK'ōn,$(G~$iYqٿMdR&CNRF4E D%`*OwȲDr.ӔD IL`BtrY@z4 0yU7.La DiaFA#p27\ !)0iY6")iC~&.eXM?WyH!r}K-ār9/G]- *3#MnbUo(vi2IG2~ bip aSKa\Gѫd7>9kzmUE+%${Y\4cSD%'" Tc]Λq1h9,-o8>C=7*?^=@% %KUw*-n!A!s3Y F*&urd^r}u6et|wfrpH&Ͻ@xS7KpU1:@RQ^7n `Q].ӻoyd9MeꞈZ:&ӫDS=M]+Nj,/JAVm.;5s䑠~g(Y: J: B6Xn&hu, MS砘ݴx'-qHZr)r y ?H@HY2^=mӇP0)ϳx?YH+ BE+O,8],(ojZbM%Y)O@4Aw {LyRx ikcC+q)9Qꁌ ܷO o\Z+.r|A3$^\5;El>^xK.G.orQý GYsHt) t̍xZ$;9At8ÁuI.CR.Ҷ(V)Xi[C 1KGn{~pO̸tFYDEa5kxǛ}y;oDɼdKf*ZG,輵p#cl6}_ L\j@aZp|cb~}AɆumY+ԢhOjػ[Ek<}Y%QN$d+[51!Ўl9)SE?7_(yB/Rx+Hs~v9zWϛf%l:_eKh`,1<<,8fy96mv5~JFOGp ٍrr˳B6Tc[r_ܬKD=y?Hcendstream endobj 399 0 obj << /Filter /FlateDecode /Length 2842 >> stream xZK>ߐ'*Y1|?l5';g$˽H=ߧdw{v ,U_}U[F~önӟwz&N[! UoK߼&|sRIrOeZZ/|(DU \>ާ,Sr<Jm\7jh򮺜m8d(NQA[6ѫTYʹh_4o6mEq" i@Kɇ'^cTF $` RJo41|a9QQe.!p+T  ʹT9 `)nC3=B=N|!%a'u䷹E\#jx!QSxXkR3 a%4`|_Ҧ$RnB{}T\skӄ2nwC:?Q5j*LP.TU%F}TU u+]3|^}:\cMo#fIx;~`p9zĺxT_Nᓶ}Ľr|p;>>kq<'r_Pmc⒅3kz"ER̈́J 2C8&h8BQx Q)h#;N@<wΩu8⢰ 98A-ÊFjbO3 ZIP.W1w!xά"B"kQXyiu8Ԡ$뒊ߒ,,q阭4;TKβ@Kg݀Y?U`x^Qw1tsͰ3CS1Ds#=~2 KzH}xIB{ $U}.!0DYxC˨pT!5rSj.usG~)#Vh T¾O֩J_,}.1Sc2ndڜ#Zgzn!p>p֖Ps| V֍s d439rC2V;H6^ :[f@l(;daec!̀Լ\<_ YeCևذ}D+]f *!/tòoH&*he DԥM]l<],vZ%@RFO #1Gҟza,~)_j4YUU* VgfTƍf†eE&%:9]j Dy-2)R"+ǾX;UH~|=|Z仡RM)>V.}>u&rۏdPoN65JR6%Z^2uHBT HWE(6aQ˲{6+0F ["]gӤhyu6~]^Y_/2W>zU*,(+AB+ /!2;\.\[3k^m޵) 'CTIcMzAmJEL2eH`ibq);a*ج͍vO9"{K-`VX;k7@w1'0A ?eb8n7#!;3T.n6@ $"xR#?0ԬcWw64-!"@Z:' * 07K[P@29Bx{o _-jʯTdu/mx:ܒo$yδ+x/߅#wvQ:O]N.=ٷXkҺ=hb}MSϥh-|0*> stream x\K6r>elC'*bj~ U]#VF_@"Ag1"LySwgٯgw__ۏk:q~yw滈s'έurs 4v kT:\ޜT~s!]݈n6MeEU k]?'7 dY^\?g8Rn~SU?NB[UC2=vRT˞|I6\m~tDPRB ej׶h\d+F9mYݪHNVnl؊j8ߪ:QiDZ04-tշcqUOuVek%a^-S7l$818 &鱍{!v8 #Q<ttE<ֺNn457Bhi[ljTe-[g 5K #R:Kj@.U e}z&x?ml}8Dq83p|YeA\vX̎iao'/0sSG佻PWXU+`_'8JHcwv.%]تM:/6eLeK?xW2bRqUJ`^ž^ڳje6-mޭhcw}8<(mPt#QuY̝a ѡgO :e<:]DbOS (hz\ZF~=m5՛\.(>`H*4DMTR V(RM&'0}up+6zF$]m`mjMUjMڞ׬)&Gjk`u٠b.AMim5AA5rP .P"aGN(ęd)Y ZX>~Id~d{maa8̘fe0qK0j&F.8D*3w M-C! ^ޥ&1a=!}4o<0N6DžtUMSD*ADVPF03 lrͺ㆑/t:J0h?+~zA j%ߟ]~9"EbѸ&gW\_?qf9DLy)~$8,LDIJ#3ɢxF @aW=(Q3T݇QpD!YxE$3΅cp\O Q5zjg^8'D7 O -<6 *6LOnC7c<T3+BqgiRt\ax;k^F*@=TeX R-X&nDa`p3ZbA@'ۻz}5Z-`tiU pt!'/ ]l G $znEp6 (~;gOZkV Áʸ~#("l5pj3kF4ˡg p褳wJ]x~j]ٳf,/fAG%{(`uӱؤষ`7tAVxNVCg cȄTKflFᗎ pN udB;=#di^:|8}ܧ\{g|qrK򰌤J](s,AW} (M7]8u=`rX5a6bƒGNgc3yxI>tYnjWWиϓBPτUBz$tfHFСBX<ux8 `V~_emAѾ.ąjicWg Y!q {ZRM8+qG MJ9̆f>efrGx!ҐȺblpx{[ -wnӞ'"`ONG'r^z^,u &D'aVý b42`ִ={-/-a=>m=Pi7Sq6rŕt #ڟ/rSr|T.ks>!4N;h左VOY>3lM$EJBڂ |PiU? OCTi5z*}ʷ#F" l e\ ] #5%ܪjt8VےKeG7S98+8>Q]5Q}%Y`]\'xf/ ,5 Զ9>{|xFu$ZK3c4_a4cwnԇaG17ZZ:Neh1Ax|yb1X[6Y`M)qTT* ,USAp)(ZbUiDP 74iL1AGY1$lx.#>O [NՂ2ӴNbXet^yp4/̱I5NKp{"e=}܄Ƹ2򭖎uhy6Έn#M:zc1QƋ֮Q0B.¨n-Lz V"0qgҋ58U;'<j0a ȵ!,cM]'kl/"4 xyhfiq&}!O0|2I ?~ֆ00F'^pzn\ 5q̟r+~NߦH~ @ ,4*F&SF|k񖧯|QiBN1t$ d,H1F3V q%)2 5yZRhE,myUKߠ;ҊBC^xELPyNcPMeʈ¾`QxHp`e*Q;i׊WYf֏ԴT=bSj)^:Mկy# E@ R "Q4KK\GDnEd~8{&x8Ä `ƻȊ vbQpqXF8Dd]Z˽۳VBxQb|Aݺz[1zFtQL*D?57Ű!tm^xO`}eC^Ƥ>@ER3C%̘X.V=EN5>9SDV^Jx LM  1H>z*s)y.3&E+Ȩf:x')NF| ИI3(eϑso߮lW Mfcvam h2@ڛ6 tmmc*c||(:8/ ՘@RxBg[_/NôZϩLJkP#R?0Usvm'~͊p`#4wo_{ c˕[L*<:7k$=hb)}0оDȡޢtU'Ox.CܪL#wUh))0#8 7="AaEE2+A޸^XtxI \uJ}\ZqRޢvsYR3])$aW ꪑeّ(vEkqg#<;q Wnҹ2e'm%dYK[[%;=K[`9ѭ|NU.5%oc> stream x[[o~wBS(v*E[I}hRjl;ڜ#n}gDb{)c"s!UU_OO'/N~'-,[ݜOت,U. R<Ӻ f?\f~kÌ2YKl_E!\fǦ8iLrQ%,[ʽ96a&Hie.-n$c|}0WVm` Q ǝgoiyv덖 m׬%cɪ>ֳ˲Pfuדߜg”֋i&/Q'IiT<pa)δ2pm}Z\Yle`YS Ufd)fϺ[eV.bÇ7o[c/U$~S&YL[SҠjH]ն{JJU;?g Yl`Ն\ [:K%Ul ̆ܭ ,bBPQD i!nvJseI)OrqjuVfd:R~sSͳB1s3kê1 Jܩ ɤyL@`Wյ_ r Qهl.+CJ+lBJS,,TEod#OԻlރoEO<|`lH~~q6_oCPe=tGK9vWcDɰ Ȁ`Gt8MTf~Y@t <C1Dvr1e2qݵў L2ū+DY@:"'.:s~ڰhUdݵ ^9oG!gGoB!g>瀤k4L$ilquW_A~^4w+ D%D}p]Wuu`% 'oA',j ka^ H9CwZѲ Em.DoKq Pc;3{ zCqOD<Pxՠw/O/yf)F"b`|1}c\ዒvr8a p]n!HhV޹!L=>>P:P%mrI`-㾗z.a}EBE%䘖+\,rPyac2R!Y]a:S<%fS0*¡=" 9D7IjR#H硇dG %tv {L6kYr.הfGKʱIЌ{J`Z>)7.; pnGn_chl0ѵg96p?bHJ#3:CcL$J˓[Z0iR2 +<'+A h'y\,;"FZ1ր`݄T<#qT9u!!t*i?C}Gv]ۭ_O+x%5 TWUZ 'Ջv Au]|M-ZO:`-5s$+ͣ&4b3:iOʜ= eo'zK)=Sς.+O/,i}h[ȍ,8@? nK!)(,ڄ]t2ҥ`!/}%TB[&{Xh뮺vs 0XZ`N/N}6ᒎ16ԡӅх.xcҡK=BW@f,Vjޫ\Bs, 1n ⤂M~ ge1v36S؞a`IrgSwn+nZ 3]θ޸kFaA?AI:yc0FJ\ '?xL/Kۚ8E+Q7wj,kA\skΝ ac͖U89OrJ+".2髳oN!\5ˇ_r8&gR0~@9 -9!F:clǧa^~&OLEr HBX'^TЗv (-šqpI݄2x '/CQFLP%~GQnZNRӰaIs?gQ<UfP~ aR~=#TBBtu#*?x-].;K4|8?Dt01咫6`Qfx.޳y2bePHߩ t5ף.x`kp;@+2'F"VHp{I@}y|2B̡3rDa\ 6\6`!)\M~^ =?LB;g ɧW`ԟ$Im-ͤvnP?=Os}}xC="`ܻeni=]pK;yʵǥUW$AUVi0XՋ!r$Th0w͗'yBF_Ј7x~D kd0n4yi L*D_.dNj tT%\}gKQs yϮ?`HOre9 K I-7}`ށ|}>8f!AO'qZ 6/;$J/ƚ =/ \( \ETn_6Ǻm+7e5"9dDblf:3Ekzo@v4oZ1uu~aFMڟI 9W֠ (](w)#$a7KP{{I]$Áwu۵O8t_ZD(q.M'l]HK{w<\hC޺(2Ը#[s "O/-u!),QWomM>mM)/Szr0 ',BՐB(]{͡?1*K,jX!FUZ06t/)׳y5 KkG`{/|..MgP#8Y7MX"$`Y*ETTl"9z 2wz>5k>sw+7k<[ޮsqƦn40p62SLA˨? uM1g $ St H_*µ aAU| Z}4[65$z/ Mvz?T)~ M}UoT=;w7B0p{+:AJ?luxٞ훓ZF2endstream endobj 402 0 obj << /Filter /FlateDecode /Length 5496 >> stream x\K8rɾ#:2,&f;98TWu3U]"[L$֡Y`H˪d_/ۋ/=]/',pK.kUV˫EWlh^]rSVLbJUoaF'V^Zŋ/Og/, +ܷ}{-ڻ [|IR_'nG4TLM?:>L K&VhqKȃZjfQ .\77u|ڔ57nDL.ƟLq]0Nh! l%SEsZɦ']-efigg53pn?BUqJ1]nYa~M]8g҄l29.'kЭO9nz]/IŲ~)H7<rDnݍ"e*y!+}cY6^~CRTl>Q%Y;Rx 20=&Xa<:# T$;1`IN&DRVxFpbTu`#SU-cdcsx pMzZ_6%r5upk8Dsids(e/x i l'w@֥KѸ(#U<1|k*Fk8jƒVk<:9SDӣh蟀˓Şcě~&V7S!m`GUoɏ=Ffߋis GcfOSҷm&࣎\s&:EO^u *VU{ĸeQy<Dz#?(yZq*[=K[(k:U/w$kaa} *v--4 [p껋^]tX(E۹`e?!5yV03(Onڣ$H=c0UF˄ёp Uzqֱ:i7&$`H[_/X8a#?9FGJ .~]2S,=P~hɰZedɬD|?|utu~a@!AZoY ~;SMaU Fp_M rZEN]L CA K )>| :x<ꂠu Jb0 907BgX㧉1AFW2нۃC >9ʸ#x#n ޳ oyh"v^w"j.6)7#p,w_uGn7Cht) )To[X%bo} 8Wҙ15/nQ?G4^ϛRԓ8 ׄiK/*ě4.9spЕ:? yu [ /#5vͻar4Ph2.þwkTu?X21oUN.y}fg>/2gM Jx.l_Ίk)@c5!EhjĸɨRU_g5O:)0WcKa.!0J+4} ; % "q"v()W#W 3q+cJ@3++LӉy9&!H(]ҢZv^= ~̽!hY|[tHRLObkej,W'0;ŸiL}:Io`X"'1$"+ 6fp$X~"#(0^J*!IMѿmeRDk?c? 3[ %E8eD_ .\>iWMzkQB+ D.Z<چ,H"ByAwv_⋌V5No_0Myl7M ib /i G'EoDKTj2o kdž"!9?RĊԯ][tL}GH: 0.dćQxҦizq[1@䰣C(Ő.>F=ُ?I"U.x.Ou 6hN$܆%n=H嬩S0{hX կOWȡxQw9%E\iwVb#"%QwY-Ym/R>d5_b[&nL))X¹ž<@I[N`7dF WˬF3F|zLNXDELdFϥf𫆁_M#.WbϷ!۰MHî雐 Sş`Z;|^E% n#1)̹//q̽+2 R)&G.x&%aucW̝߽-L2›0sTt2'<?N*'*m14nTRX`,N-(>CGbKۇ.N깎8WA6>dKZs n/]HsTԴ[e{@Ts6ۭBgBR%"M"l^JjVеZM:BC5ZzkW|EChNE&Tmt[l0 y)P%X;>Ab&L9jL̤Ag^6/i$BhX)GXe{P5_>5wCy Fv.?0F \@ZLU|ו!zlQf%:6*Cӫ'7|h~eeibAyu <þKc,wV|X /*t"`. +Q Ŭ7U]TQd(0}7+n#ʍƗѸJ5/A(3 X)+xAҸZjOlI-q{ kRPX6(1$y,R\1 ]7ĕ9(lc4pՇaU]`H-$Aж HyK3qf^Au"2Df<<?~=ּUHNdH}8 1L '_",Ld׷%:PT)2(r~ aÝޘ -!Zq9ceb9&'[h>ߗw-udr|=Ȥ.N {C;ddH^pK{s ]몀>.{ 8^p5CU*͉Lc]p߆iG;]*2xa6eMQi)ji! ()eۮw#ufx VRxQπ \45>C~U S'+@BDqGݖ9.adY۴Pb! _"Hu'm}jW؂iJSAnwTBycV5vr5#{'et`+lij`m9E0)7_Xp<c'g0C0V˒r]+>EWEL(~ߴOi*>hksI ҟ9R`iu9?J\ތҟtI w`V]h~j=EM/+xoDVD BlX{TE8l##j@V~d&`ԓ7m>ozfF|8)Ʌ'su-?%I[M?pvmCwD_DYJ$Rmɹ0 L]ߎxi6ҕ2UC84 $ $R,q0\Q9.Ɗzcmj K10]r W$|TNkoZendstream endobj 403 0 obj << /Filter /FlateDecode /Length 4123 >> stream x[͓ '4$U .Y.s˂V$iz$ML棧ן]]/Og3AowϟU&Z.n溨w)Zy^_%=)QgE^U!UTUùY&WLǙZ"w8JF6VK[8\\e_ c sЅͭ2ye-} Ԗ&/D&G5?̏vdd+bw*7n"/%E˲Dke s<[<@e*Z? +m% \rw Z׎@Z9_? 6fl;zepU lS A`ܺ߀tYt%:v mދV٩i#eW|< u7~+77y2G'Zf7єב㫭ŐNEcsD*+گGC?jaډ̞~@?s<ۣjBoQYcDOjgϳ}KiqBoy $~O`숗eSn=*QcV 4Kbld,ł4Ɣ>CLq<=݉䓋 ]U蝅ˮ xA8 Pyv=d:9Dnj2`#"jr-+,*Z.Aum9/pX\X&PSxe%#2|%*'<ekQH/0N$NV1J' [FQ5bGA̚?Ե:azĖ HJfDMVn? DcNu_ h`u'nJtm xd>_S-V C8~BaVu7{cmF.g@V[lj`Է/0 `N$\C@Up/VL3\1Ga N Ns~&ugG>|a|KGs{(k7d.ݴ+99PJjFO3'̱67$=Yͪ V%! B9r[2'1ΤrsE'U"W,#@Wl78G4"hʫ¹õ{k@SnRnIu G*3߆E<e0lhIw|ϛ-n 0>cl|]ɩX qzqMaO&(v!.c`LK :<@a ^`kSE$:op/!wQH=2<'|xEJ0%XWc3ٹO|[A#bsw~A@[~q5`ޡ@fqnk R@gmLUX+^KZU M6>1%J8iU!?QT OnLȍ tO,X`&S-ӦfgNb$Q`_yZTrjMz}lǸL/M|N`d~:7Z"nJ#H}xNҔ#0c323,D~.Y0:É}G`+g\lI>s:!b>jaiZg KB7v\P^D-y|axJWJp:W""ߥ3g?ww@[<>z5،.n;+*\Tj/C3ğb҇cpܷ9 0xs߽K|Kc?i&^cm,Dd\vM5(ɨ,n,CIC/kQ),f0 &s0J6y xɳfgX$'V={h&xjIc"\yR{@Ӧar2xF(͕ ~:5ӿ L.] PB4i.Ч>qbYf 4up9> TwbYA.q\&lܞi!)'(!=&"`&b͋|Öi_y::U9J^Fr.1X&C`Pcw8D_n na ӓ>PJ8sZ\Xd+=4m7E0 %j4s ÃΣ+mbEMqj'>oD\)apeddBovƑʕ 1`Eeۦ'B x6zNEEu#`7_R`ݥ~*PŊnǣ^7Hq u]a ҀWT-+~ fm}ʄeq @~AlpHՃ Hy`S͆:Aya)У htώ`]__vwc B0;li,W94pL>!Ѓ/ĆzJErp~$˸lPa$D}W?^ڤ}eBqkta:(\+Z۸ݭ<||:ɂk4\C7ɳU_D~p0 Jpdyt\bFAkc Bw+4H%\vk?u7D:Lb Ps6 -]soIS7g/O˩Է+)tl^y7͗&7 n͋ocW边t E_>y\3xlxxNbx>hzNZyj4995EdM}n5-~P/o_}6rR Lendstream endobj 404 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5592 >> stream xX XWDܨ4KFAqhw\(*66¾un]dYZ%A\bu&Qcb4'=8Iޛy+ks?%c,z02᡾ac5=8<*28PA=oh{Qd5ܭ= kS1O{>GWw[?~/Fm1_@6n]}oh"ft3kd,k\ KM!;@ۀ(?kP6`4f=).7QE4B=U:|JK=ɲO%]|aA9p-\'=fxL C?$,5lؠ"W=4l 8@=x` _CfۥeSRKhsR,Cy6T?#sѹm8=p:F< nա5\p%:%&(6SN%y|P =Vbsа8|?*)L0RQft Vv&$@^H$#g,̃q% Sg/xwn%3P\+UV@6a s*I" Dp \bR$eft19)bZį1R{kyTz?"~`GΟdp [%#pqXk4'BfNn+:xmgqxَokz"( Q9ʓ@+td(Ie?rr mqùARAl(RyLZ1#Z.ȋr9%#/:ܻK]KЕT 0(:`͜tG8\q+] DISnTf,2ѽ77/ڗa DKmLGayŏy~STX뫘;B"tSM8 L 3a`+'M% Av)^ZD'jq*[}z'w/L}ݠ[PI3籼)aOaW|vL۫LM (iGʸfTr*z);tkO#*0L cκ]AMOZ7BX58Xj^қ$;ƤZX{Vxw\P[LQ%~_' Y"!6G*2ȨP}˖B$SË6eJեSM)p4hrﺁvGB>a;pZHߪ", ɅF('/=pJ /@ZS\emhIG'@{;^lەf6R` ^F{ :Q! \z^p,c@kxR|X۟(֥~U֤:|.2+Rp6wrkF(_Pیi=ׇ> :3zzU\[Nt{[^I?fƒD{ym[虙 C aFN󌔐XR5@PCK Mr)礘6Ki}E8Hz&h&r^NYiUgdWM`~:2 } -?"ٚm_ 3  thXhchchDǢ6H+7ODtMp<5&HOGxYU7 6C,-YamL"1Cw}vafE&k:R s[lTb9"REp8f$LHɋԴ8)daTjn6*VA(}yGuώL.|Zy9a3RMס2K.P]Af\-4I9&6+aEPa`MR'T֔5&lLP ܕ,y[GnE}[@7UQ*=&3v ]95yK&9tߓ5810@AÖќ&t\eKBa)|΢YLzhܮ@yh ?O0f%ʉFQiRg-kUZLR0K Rȁ VGsx}U$k]v&(EtHf-,juB0̆M'ws@:h-FY \[ (f̹}t6v Ff\ )+z}\yo&G;o@;>KNW='n6k)E%~Cqlr4#T'ħtyDY-$B$w'DZZJw>U6~KZ.JVe-Ӗle7"32(3:J(b۝= )O =BoT%ZKl%A%5{t!k7q{}AۋgYxEgeeLOxoCrG",ywVH_sj{tL&MŦS|dů{] ;o|&@XU9AT&;0-gP3),6)4޿oi@6WÌώ5*}ό'g/]B*׮"_f!+gJ'ſiLJ: t3ix؄ ðS5:y,Nʈ'!pɟ&=HiKN:6Awayڝ؋= q[j>~p궾{U^\O& '6`/NpM4ߢ =㫰)`s] A5 T WeS`F ~CMG7uSs=.Gy\OdUd`kyk5jbW&dhA_ѫ'ʈGS3"F;cI3eLZI@[s(N>dZ2=A8KM<%x \*)X#0`VC#/g*|TWzGvCACjҶcxoŰ*uq1ݘ\$lW򌆼`oC74M00ݴ`@f-WmLÖMA15{ z*~t^n4ZVQy;Mï^QB5K]ƅ˛[\ؐ^1mG8l7|A?<i O_ZEx& q:'Mea߶SIC; W+Bz"oɢ7+"ȰqƈL].UCÿZ58n)vGJnN+Tݓ-)cb ਽hqyr(d'nG74J@ٛ'`%dL S/^x}@,WD{5)7޽AJ,"+o>7V|sr\Z9iR Wﶯ;~Z@S9;t#J7tAg;8eSP݆ A!~~#GLuMiù{Z\y/t36m?QSR#&yzMLi%$d:]YsZoJp%ri2G90Ւ_Ft;QBHBl$l~# Ӂ3k?B{fd OC S}ت,}#Ki/qcrR%Ē)S'JN 3=?ׅ>b/@Vmr3H7p⏸1/߿}C'/^ba FK4&- YmYtj!dfvGehN-6'4CnY\^n_^l^Œp`ݫ&Ða0roX[7g/m0fZfdendstream endobj 405 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 371 >> stream xcd`ab`dd N+64uIf!CO/nnC/ }S1<%9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5P0000103012_i eO_^Pw*ˋ T\)S^m. =wnw6/ i^O mӺvKc?{oi~}/.cA<_qsg.a][9\Ğ{z{&>&20endstream endobj 406 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2491 >> stream xV PWaFI {DJ7DAxS@CF~h! #(V9Vcqy>v+TmU][BvoB\hB߈dUhDc&A +K)XΙU 5 IK$w$JخINR:;/ZP)4N۔ Eh|bb}Z܌Q8&+"CUH&E~5>~'>;c`bTq./-^R[7Cxk /b=aCr!fv=1xM1DsBK\|jl:H+W7wH#R.V0jzd6'$LZ-2A#vwY&j#$B!Qp L؆ IPV>)F*H B2d&S G8Ο eqƯY :QpKGѡQD zjC<ۼ%3?Ghw]Z@$'onޟg``n AOa{րiEVL]fK:8',cmkh(znw&AUaR{*C`?B~<~=f ^$* )&hb05t%ndRgZghr;-@)ڼ\-dҩՙ{`Ĭ̤m@  [9ymU:Mt&cW?gϐא9,Irz?-`'7"|#o_'H)X1)py($f|;̖ ?0Ũvjkh6KDp[$;Q٬5?=qD`#{ljj/CwjDuʠ_v~{[3Y?nt2њ!3^<[m(xaNչXQ{>SAKc߭}Kzi+`qA>Fm8/ʍ 4~RZ.^eRR.NN8M5AQ"PDT.ӅUv:tuuSHv ~vpN!dܸ=Yo@2ؓ|wءA7.W7|]{Ú|(б@|o'W6qV (rjIHG8yqvcLsb%i{u⡉ տDEkß^NB6Pu`tŔ&QYF_МնwS]r1ɟ)Ƞn05$-:E)9ݘК‬?Y]ۗ-{=Ҍo7fyJ1JY5E|I1[Y9c`6(63tgx@ѡ'S+ xҡԔj͈G^@戾[ Yg 77v !0HzKDnڪf(Tfvo͉ѳ HՔ=T5Rv ށ'?GK![asjTw`npޡ/ܻQ^&H[&mR"\"1&4 #WӉd,I\uUiem#9vuf~8RlPs#|˫驉ǭށ@HDƴ7?_(@]N&3vZ]9{r=4p-s,L|V ɚ31̳!&jRtg3CQjAJB@+TOӥy|5XnfX*fJ< akk+.)KD^3pYf#7^<蜼k;E#)~gbݙb⼒#82BRJ?f+]FDdݓkEN0\fIm.[R3 4H_}߳+l{i?*2*1cP}@}Z~P׉ tj ,-),-r*Y/C%z4md:;?, K}%Ŗ3Jendstream endobj 407 0 obj << /Filter /FlateDecode /Length 170 >> stream x]; D{N Y4N"QxY, ¸NbVvf`t=FU7@:b,i9UʄUzƛGٳt婭%p 7/ iĠ hߊ¬dYHE/3/eX X1M"_$Vendstream endobj 408 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 389 >> stream xcd`ab`ddM,M) JM/I,If!C^<<,^!{+#cxnuCs~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+kawhAQfnjNbIIfrjI~cc73##e5| /+2qnrcV}o?n]5ݒu&M6A uOlưNR;A`,V[miwIwV]hQ™r?~|>sa"yƩ'Zi!Nr\"<> stream x]A Ej54l Q/@ahX o/L[.$;h^ Qc0%*^SmUd Uw @w9Alg|k DF -c5FpY9OYTs~/X@eA2ǔ=%%Fp %u> stream xmmL[eǟVv:655kk\ c&f,L^-Ж-(PRZn[v.* 2!aAɒw,Nsr>`@"R :MiqfPw+/bK"e;@J%l{ٟE `X~2ͺv+'$*McБ*c YQ,!+|RGZۮ2T+Ym jNWאUW՝y4X4f (0ʚ``O^#u-JEhhh 8^a-1ϣWer\#太E ~7Hg 6FbhiA`誇c5Omvo[.k ;Ad(zV#엍M1ZݑfZNDFr?=%zJ@ &CS"ޞHD#c*|b sdktթ01>iu>1v3@hFr> stream xcd`ab`ddM,p(I+34 JM/I,ɪf!C_ͯnnn? }^T19(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5p:C477,I(a``` ``b`bdd)?|?ÿCd73,ZVgWV[-?'Mi  lٺW\ϱ{ߋl]]9?tǻ]aJ\PC~j_f r\,!<< gN7i}'̙Se`endstream endobj 412 0 obj << /Filter /FlateDecode /Length 7740 >> stream x]K$qI>f;XxA2DI4)K*0W첩Uw/)L$!KB|!/Uſml&_v5m^]0tSo>xvg c<{y%$fcm7skQr~応×87)s(i%Ӱ_i óD0<²>DxxhcLħ~"61dγW}ugW,CNc136m<_~FFc7+71>NvD`%\U ُ>%$La4I q-8md 0I&R0F+?ċ ]wM6 8fR%LA$DӔTR 6v*B7 ɂC!c@l,D  M)q2 'e@D9aQ\ddKtLSB "~fT bC͟RpEY$U PBeRGTsKU柪pQuRujjʬ&֬Pn]R]TV-'TE:q-\ѵXկK5ZհkVCc%1M7yYoy4iC0? WcA]v[Zu º F?ZJ<.{ωRb $a)&-Wn aBJ2@G3!u Lg{ ŏtRg @E( 1: „ĕWY@;e!PG$Mg< i,^-g (N +^Hph:0@p@?@Д[0 {"9cSF'$&&6U'j̀ͅ/KJˠI-&涔rko.E։ZZKj<`C|~]@o Ne0Yn S$U@=>I4:?C {6Q ie n-Х4P@|LgYBoo3Hl&l+Aׄ*.mR50NU2%it,"@5o*^A P*- s@3l7AZJ$J3K!eajt,"Bԫq@·ݛ juaLX.S42Xk| P]M@ jrXC&hwC'-Q)_C֯q("([a¤-dLEz+TY6-%zH=IŠ~S9Աȸj]eɐUB1Tl2[>->R<{}xH3@SxeoRHu6n* Mt\ХZ r!L2gfƦ ϱL'D54xlx8I?['7Hbj~f1~ ٙJ#;®ٱHoXj1O gͶG#ow?yoH7d[UڞIe~?;28hDyRZ]EQ(D6<dɐ1QZ*<8MYj}z[Oxy1;ڜ 26e2B!(|p.Y UƷWEP y|';\ \e"SnvN7?G0`1(C@:*1ݨ2&@Ũ dR!:՛uax;]k/c )H%`cA ˏ<52& B1TK尜Lnw#63mܩ#]7P1ϖkOp EQ($}OUBP R9,!KލVS̾bK"&e$ D1096:dWO}&AD:(j\94Jfڕ,tBQcKa):Q7wlsiHozc]6/ۜRa;]K횓ْ-*λ69&гO49gR)&/iʼnqaőGQxڷnq=;edskDpp^䁛\`*[s()*'7JHg&B+&=H̏55e| Stt,2B!3f73_72& B1TK尜({WVWLp%  UXzrcl e5^jd~cQu2E3*1(C*6ȘTPrM6AʦhMN>/!X~ ICg߆ۛtܷ E/j1B09ba_ _lw@{#2rӳOKGRJ^в72@߻7/\ѣ~;H\BZ7|}Ͽkb)Dtxezrr!ʄȁw}g$D@qW׋g7Y -Z}@_a#Їk=ˋnXFHB1N7|/eS~u4@9+Lw -SPEɚ"ht,]233e^_Ţ5Wg=dztڝE:yU  i52}`%wĘK~qN/8x #o,V`rBl_ZLOt7.o)ZpN0.>ԇ''q^7~n}(2P Z]z{Kft4KIse/źEbY+rYf13yؽZ Ymΰ=(x2O:R #lIڪ%!Vpp\z#'vo/f뵂l 8}{dACy_ Yq4 w7O}b' /5l"˜ianhKEy{+;V|lnp0i-V9pp-VUKSӃDZOhwzs:!4A\6}j -g=<ʜp@M}GUY̔C@:Xnݫyr}|]Ll D~-ILu/+a/`Ue,rUtvwSIlmy{uPlH_meAOߨ_\.nF)&Ps Z>__dR.wr2j׋$FtSF*f~SO|9 /2fPSxW;g;zUzd~.wE_p^TBtKvY "?_n;l|x2wPuP~K.2G_Sgwx>?uhifﮩ}1hϾ'`5Ie":='3Z Hw\qY՞m_T:6 _HWL0nKEV/6uX#wGLvH3"{y$w}chKlUw@]-}RZE+5:1Gw 5ܺ1-xpEYvZAO/[6zHґ#Ϙt沀n 9i\8%Lˏa=w4|+ /vޠ~ZhO y~Iմ?Ӈ+pOU]~{aE8|=֛Ug ݳq÷0o= @ұ'@ܠCӷaFIWキ=~nNf8ݍw/޼]G>^6Α?=`H##YQ7v0뎏 &qPe,| ePHQ &qo#[gu%as2Ŏb:9bitQO^0 ֨EDi x˺/a+|6ɔ >yb)!qٖ7ֆ>M(Ikrm*_Asw8b"2\pĉm9|㜖;NrV}ZyIXdS=?X CR> 7|$:^F4A ϥm םaߞ.2=XE:Dz}Q/;~;'9^vؤ0:ŬIx%2-lG M'r~=;,*?y4yV8snpӗw%šn{-C`)O[Ū<)85.nwg-߉-/]5S? !M?/ ΢7mmoj=7x`B'EC%HІOwrCg*<<=P;*;y!m3Kf V5\!&m ǵ[g=3WדO}<"DW}E|cmEeo o=v7mendstream endobj 413 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1420 >> stream x[LSwO)3pls:eA#eVK-Pz)AQ2.jg0sMgfidx|^^>?KL8΂ ,+;c[\zpC/Ir@y<.,I~? ю1.rZZRZ#ܐ s sE'jET( wP*\- %BDXT_Bւ{vYWw RdjErHZa;]X!Vbk,ΰDȱ$pܵӉ$^KڈR鱠ާмi.}-@z0J+ 7y}d9_$pѓ5^>xjʠ:4&t8MDLdtJIi&Ni@ӵGa77u]E e8P9ë;H)#C+Fz7J[_E yK7^y?eR4]f5}.JEih9ZI ᘂI*+:eu)"˧QB494;yn2/NX`}.[#}8sۋ[(j?gK[OiWZۻ[YcU]5(oK/D˖CʦX퇣=2/QB*^mG4p+]qLQ DTrp2"RI(9_:`SE;KA/*3{^6ؔk\vBkr޾VwJCSI?%4Cqr8Aܪ6*YjLVZ#h >h#&ofF-jб]{> stream xZ|TU!QsȋDE@4%FZ"@&fL&L̜ɔ${7 E0TŕOp]܋}MBH⺟0s\ѣ(kcwǧ>?wư“ (1d_D0Ə>v7ꞈv>Df5og?{{oL4%&kw>/9s%H`x=acý½¶xm \1km6HQW}^M\2yU5i?=k3g[>< "rcT`tP̦ظg`ዋZ)˦ggl9k9QSzi*Bm6RS@jDM6QRT05BP[W6j5NVQsʗOQ/PQ BʟZGMvPnNBPJLM)\Gє'%Pcq2j< 25ZNM72U2(vuգh7dY>n䱚qǝ90zB%{({$Ťn9n~NG#4zQG?zǓ 7ҽ{rSO>SMr癥>;5uiLKV9M<uN;ԥw mRMaј N_nxAV[!4*WkJ`NWAX,RCBtHA롍k*aN%49 ~mcFc" =O r|YҞL6dB(7ΰ|-d`A0o(t O9\ w*>$%Rnkf['ۏR8xnba-;?||%w\Ǯ` -$icfz](qa G"Wzٍ{vf ݅BDh^L"> VmY#=N*U`Ǝ>bŵh˷h>.%xB@~_ܘ9ޯ+jo?"\~Ysvp23$Wǧ<0e̅տ4ٟ#; ʿ6vpxݡvL|:O7'a;l˰SV wjBɞUhOC@.D"Y5fʖ| 7 \I3O}^G/$@)]蔸$X{_Li fl,ͤr4Hbf>q ѡ#Q8Km-ͬ6<#A Kk oYеDOc=ލ1mt`lY.FYbƵlPM뎿Î /+|$͎B%#F孇}jbxDBD'Y4r{tnsg60؝dAir.=/ <\k!٢;ܟfNW97ܿt'Y:!4^t t?NlѾ ߵ.u[xp|%#TFO/I,JVq{.TuP_ai Zю@K-\?II=;sb4`u-B޵fkuN>?D:ߵQݕOEĕjc-%\ٷ;+vw&} h:PH"k"d'?ܬ =vkJ_t6( cUϛ'-g&4ߎ޲9Pcqw"qCGoܱD5ih?]#֞I5`ʐiiaI@Dŵ<þxu{pd<ۓe}̰+ZвKGϓ8A[P#Ħ*sm$DVTPtȰ"-N6/Yzj/ab Hhݠ`lوqnY7rIPbwow7#d'4{3("‘4;{o0SM[%}&&GoL)g]ðLc3HHb7ͩGsD 90!@(D(Yrb<6% f~By޴ja51yPyiOHI G"t)Fp|E !xMءR%mSE 3mi|UQM[ى߸!>&@gwч:Gm0|[{^uw|"m:xHeNiXL dR1w܁>TďDmC :nw+7ݕ +H?@gc4|\dI{X{HuP diZZZh=:.:6(ESӡBq YZ-a*+ct^p*ʬkEabPFozn.V\2nPZԦQ,W|qx g GW-k i-*/4kˌ>#9+Jf2b={\vܩ\MΝ=?#(>HL@f[=BcQ'X'ȝ _;rJw ar.kI$Kc|d3tAf;CtmnhIܿ;13rsmZ$Z83f[8|?Dzt:j緓B[q.$]Ͽ_V"t$cpeFNjmm)@HMX}^D&Qdv4oúQqZb'k9N_ǿr :}/f& ET9*ٓ}+yI{qb$`S=#%4Ċ\BN ,ʿ-8US7|:->ސ` Dh-47"q &i`dIm;e_[||3%*t*A9ފu`Cmvd:V}ڝ7Ķ,;/(7sF5?ҬEz( ÕT]s #@)1<Ӿn KˀmkHgwq$[SDMZ1p[6)҉~UNNx޻ǽV~CLD[8!9wsbs}(`!8a?W,9^/T*.Nϖei4䂜!z|w |8[GΎfFQy`V*u~VnT[.l.KJ=yD<;/ҖךR_`.36Bx;v%yph0l#E'޳)ANzc:ti0 VY𖩪.M}lBւ89y_Ѻ?,BE\ŝ?} ; kG>}Klr8J PxXpl ڜK=Ce__c V?կ5`9ZMZ0J᧍+aq%.sQ~fIa.0:߼D_Q7+@}0CqC&GwoO ihS#P伐Hv&NlnɨK HJK&T@ 4矓~Hq7 ^t):ыƂa1֐f uS@\B+_P5k>~ ̰aͦ7+b4 \0:N>.EF>H\~ _WԼ<&&e>SK09|e&c@hJ'kH̼?!@@/_QQ?WW(JIωĥa:ao *:!'Gqv=V>ӏ5xzھ#|^w7oV,=uB[n!O=|w3 m4qQZsu઀USo^J~NR?+C`gCꂖ:oCQ-;8<6C769Uߖw৛5hitkO+;xs'QMC@w{ ۹^4N~53q1`Wv>eWrU4Q14$ Ϙ@ЯN1X%j=W~!z(Tr.}(^ }d:?Ӈ:"fHmX(Du,^.b41kxB<%Ҫhz+2|6O]dG>$XliM6*{[ڛh>pcmQ#scAsanB +VZʎרj40پ$5 h 6h2 Jޔp8UȑGyp h 6pu8|e?!z*GpBgX k+D4a=%<([\[bD<)tH}[s4݄%$ DSM7tm㈺K}P4~U<HXPޤ$SS%D_*;|]ҷcg|ʀ A؂q Fd  mqG('@s!ň] z[RR&s$d#): czM6:/{m1R0U6^D6ᇚXZʿᬯW(?jl}qh>cQ;Hy+\ ?=*1Qx<=g6N^%,Ϧ3_"`[m$2.-<)Yߐ;LE ֬ {8RH0sC*,9K5 h" w&J^WTȈ|QkUxu$46 !VJddb( kwT 9.hʺ:SPv1/zzwDŽh=ȾDFvj ThECN.T V S"]3@Ӭ_:@2~]iԅ.J- @]M bDŕ?0B!ih##n0넺ƄjNAb)uvUuCOtIm/Lj)* mqBL(5.g j:Qgh1f&1[>B\g?zQo@)ZV!K}cf <?C;>WQ 9F_?;k4Xlg|k_ IĄ+;`WZW*4]z7_I_M.vNrMt7ɉbK ԃ3U{Y`G;nj~F,̂ҫgV~|X{e_&a2ƞW2O@lƵ7*DŹW\zN|p3Ƕ+(|@X/@“Eۛ1(5wCϙ 0ʢmLg/\ÅkE|-v E" gIB" GIDMt;cPΈK5|q9E:"e Kեljdþ}sB oꍊ9APUNj>-̓jFQ}5f~{ƚsHD}چ nxa Z.NO,ӀvIטgEd7yђ! [)֒D Ql%,:1 I[e9y "uR}VIf%tr=UF?;:[__hgxoY#}(drt'#Cb<3I j^,,<-=בy"nL7b|ibSU4Re*.WfJQYu`+/,7UAE1j1z\L:=>vtP10~ Qe1[Ǐ/6mͶR4endstream endobj 415 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 283 >> stream xcd`ab`dd M34 JM/I,f!Cܬ<<,7 }_1<9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C50\``````(a`bdd?3qG߷0~բxy؜u̙[r| 87mBU\XBBy8yL;ódKމ}}}&201g>endstream endobj 416 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 420 >> stream xcd`ab`ddM,M)6 JM/I,If!C<<,~ }/=[1<9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5 U4$(8;(2Luo:cwCu';!]'uϗ\X1^諾3X̨mn[ɝ=-ݒuef_Z].Y:~Ƥޞ徫> stream x]]lUBK% gN6ik@H-B]WE uf]nm`aذ1VD1hdmB@o4ghL \|]yߏyau^8Z;`yږ|ǴPb'ſ. m\Q)ʪrc> WWzoqx{6\_P ]2}7B͸Ҋq=h,h a@P^;tj6GTPZ?Ƚ hi}Vv>뎵#Qt*pA '!GZhT4(DkL Ҽnƪ˺"n[[ź *S&u.mLnm}\Ց8{V!G{C LWmKx9h*A1"q[)rw V1*]:f~x ЭKkZb&c6 Nw>27̒"rz8"8e 9߇[wsWj7FQ-=cw'gZ/}ԥDH\9kL z~svLe9~ND"䌣%~I3"I-jd9ɏtV _t4`3cD9DI^JOl49GNhtS*hvplŊ[ۓҶT2KEhuA`[ElEI|WleP]T.k|endstream endobj 418 0 obj << /Filter /FlateDecode /Length 3846 >> stream xZmo,7DI )\9-tO'ɾ̐8v9 <3U ,[ݞ}8vm//>yͦJ9]J|crUbSj<_rڈ-=iYlY]Ȭa}&N{/N܉zveYqvhڮli@[)(4i4EQչ>J/60F.ݸF 2q%=v֡eľwm}cߣRf VE-J 0krT.O4g& \4үLs<)Td|Y9û];/Ds3-I}r8T8j_wK׃ɵ( {X`3~EvR 藹2`;fCTBԱ@wq@=,xC`dcGs|娭I<羭e} "U|©;!nfnrkfn&*M}|Z4kYE)%w>nr.nsǞI5ב`i G"s#;?evej67ϧpmv7Wnw>E S|CXekxpG&B@n]קRC|F,@*4דAFm[QDW0G=}3)m&uWˁ S!˓^mGCYfVGZE &ElLj=yf@&vX>U;Ws@? gθ_i BK"J׷ $xuE2GHE؊1 WmRicQۥ6Ȍ3 i4y ۖvUʔY/C@ kDY 2O\=0"-!< S<9;r!'[*Nf KLFE` ۲0_D] N&/91ˇEnUqEB}Q@(h.x[daC@~B9Pbyr d&915ܧ/TmBa L0(I'~7#.|b#Gr6.qڔ40GGrt讣f$rQQǹӖ"2l/xRd(|䰆S oaoq bw e ,cx[5jk6GU;_VY$v!K H 3â8 uz\()WHxLycQJ_M JBDlT$E y[ǩ}_u Gj75nMEHhmu= ǩ*X]^iRYҎ{Jd lG_tyܢ• 5,_C&D{J0 PQ0V`? 1HwRRhcw[5IBmQ'O{,аɏ\2u[qB+<q& XƪEi7Yqc }h ڔ2&,€oP[9HE >^$ĆHd(Yj V%f1qZKurm#c.YEXH l? lXwď}d[F'Q ')4²6F~PIۈjA  ^K<F!ͪgKηBG;ڐG#t? zua2~^ml1 $TryS5,YƯγʙ5 I"*$d~-tӳz*~yb2>GpI9*t-v>8 WfR,$?kR n|nUIHJ|y2ME¶YJNbZeZkMˊ0Lua/T(Jq:szeYH9D>WRgrbV G Y:\F<.?ҫ-?֭GOqc`j^Q*'gxA?+tp|Nbԏ5Hgl(j^puFW=s4vrcOdpe)g?].eL{E{a,@cYw (.ŒWoV)K|7CL_b0ZJZ %ҤΐۥʛUMmLIܨ"BZV7+( č kaMU=˞"$4ӳn/NOuۧ)ytY?@ҡ3KBv|' >0r#;2J@',7-BIe>K!ym&s1X=P%0B,黳Nendstream endobj 419 0 obj << /Filter /FlateDecode /Length 4190 >> stream x[ݏܶ<~DMH W/-ZEwfHJJw|Z-97_ϋ\ڟ۳_=_]&Z_2albtke {ydpl!}Ǔ@8\uְjf{ M2#?9 \y1*g|x>`Gz,i!^ZLMŧo9^beO܅l$VR85f6n)U֥@poL΃( Jo^(%&N#~_8H(CHo|Tq,,^>`#)¢$Λ? %U0?漿pήqT+áNQdrfZz5֕`Q\VsO8GN{rvZ"'?KOb֐`Ĭ@:eIJo=JI©Y@67ziWn4GX`;O߼Md>x*`*L?rI>m;mftYHr·ph 3X-zce1;g`bFPV4ylf=( ;,HB "lRI~mZ~WH{ >~^԰ذ}]vxsS:3q& .dƵ(X|c\V#|Q\SBąR̠X%,N\6IM_WE8ی뱛RkInV~J@BU.*Ht~IӋJ e8_/6ȃd94׮*,,ds)lnq ߸o}R]K3_/Wۿ9p`]>wb*)(N5AGMg6fWR|H[ֽfYv ]By;}=]ܼ_\7Wuv>~B"n+gB1cx7/2K֎7q/t=_d<[aK۱zpdPdݟN KwjHh[hvt-nN X2P;D߰# 6)jv٫pq<.v%;ַ_ɷMi:;l'~ Cl>BKm]JQr?~21ո#:~@Jbԁ3!PA3jvC`Bߺ*}~%?H]ie!e!t1Dc'*|uh\H;FЙ{a<;,ʺ^< x@A,{:WOLRd:)\𪥰qA2u}%!fM׵J̍vm*Mk8 ^tR#endstream endobj 420 0 obj << /Filter /FlateDecode /Length 2673 >> stream xY[H~'x^Z#ٴ㺹AF hEya:31ۓ!ho眺Ud~Uu|$1$ds{p|x&/qt0G膱4IQR9<e\~4'$N$W4Iusؒ?W2{bv&$(.Iv'sDθ|Yi|EX.c:a* q.%=[!fe)n&"q NU}q !# 2FۏFTZ}R̅"E'DGIA/vvF)i-c`˺Lm820{,N(7d``+k՜H³#,eP:1rI*ӄ6JEzw>$Uv_j !,gK SS S|TiB1s#??ꪌp!ɳQ&i2Ȋ7 % :NCCTٴ{Sm$]6/چo;M!({ ?*: )՘Д lt-`(%W fu`ڹUJw㕫=-+QP'1t".j3mǿ;a1!7-Wɯt ̺Nx٢V~\ Ta r'(8E('rll:na9͌o~ CƵ{ri]-/0>$D9y6>^⩮Km}0 |pD%v\)xe붼zunUWm~z.W"392[ߕc^_>Ew`8ߵ%s?|LSݓ% $GKlNWE=Uiܸ\h5{@CX֝R|޽K43'l]CBAد OOF} UGZئSL2?ƒΞB[3JI̹ <.濩s$F$ԯ3bE 8w(UGn9JlaaJ og bÚ@"Τk6ؗ޹Ƙ0.Ҙ~[Ǹfx43uQ8>Z=>R0㮄c-X1`0! a2B#7>BDoŎ+άdI]2c8&4Co"!d pn(K B8B& 2' Eo)Awt,`&ͷK)`d< '>` "9Y`Sb N F bob*3QNM c_?R4WJ~Rw@}"rXoiXpstJC*p@N ˆ%c#ܳF1y(C\Xw`C09ԋȉ/,Jlں=8hV00뙻2SQTxXCm Σ\%bI@nلDMJ+‰/Tp+-0nM2D GtaE݆cf1T_mv %rJyxq/))Rpؿ~ށV[{M FB]؄bh2$#)ՠ bY,!=}1*t1S9i=(*a=8WX馬HSzl>U3 n*Go Oi;զ=~fk\Et(ӔN*mv'}ӢY-RIS2H2LR1L<'v)ƽav( :lfߌ+ḗKa哥ݛ՛\q- {ss^:gϪL~ 2$.ۢihչ,z\|jJWcuX烫_uqT?ӹ̻^3υ}UhH̢?]o*Qi%@D*?wyt~433;m08ߣ_^v;/^YQh+a8ܗ29b5 BR1+5s^/ #n+bgBqy*I}*! jҘ3oendstream endobj 421 0 obj << /Filter /FlateDecode /Length 5495 >> stream x[]#}a_<,Z cA,BWsGt5dfSEIvc?AiX,ObJr%;z۝Uqً~mF(\xuU+o]8 *_| :aG"&xfި0 KzCAyXoVcj}Qx\JkmFa<?=$iH4LmRu aҦM_Wg' fT~e 3nuޭ{tgFpp_iV^J?J:)-hVE1b-eQnT+M2-o1GX=”##֌2|ͳUnF"?B$0F hE/ydIpPj0UQWӈmMdI^F+I?x4dzeVJ ¨ `$˄1f^'9!$o@ZcSJѳ}ӤGQC6nhW8fbF͖vzNF2+Pt'^ujwK(5'@qkukĐ[C`U499S7(E\DXfPWPyVN2`+"a_Gh:zq>zz2 QP)X S4EӔ)"gQ4+E?l/9681# ħywyBȩ,yAQ+$O(=>:$gQd]>]G(#B)OJD f'+nMoTU/m9痙f9>?L~s;鐶BW-d4nQ)@ fE8ޢW>QÜ60x54$ /$P[i">H %\v @/Y\Qc8;bj2i>F\$ClOtˈI*(i5`KFw(i ۳s”밗20`c,2NѲ͵`1 JSb߂ H*UjȦj*@جmZՄG%'B UI!P!jL!jp![#g V¬eF_PazAv`($ H*r,· jW#dM%ֈ+YF,dyyB -̭H TZbq@$T 1v(}4HTDR:+ZVv::lDJ.֒%fy8ЂzPTE_N^Vx\|4 O$ ;:@  kɬUw"5GY=& #AR+f%%gi.H42* CΨr{~8\֚Øaw`!-ɫqk>%YaeIL 1%h b_鱕PTȏ~4U"?T*[HmRȏD1>K{YQN. lRlo!o :΃dXH|tPpM'EדrBcjH i+<˱rRHAȴ)T1@e@t~@z ń"15R5͈sV|գ9OuTz'ыFB1@yr\[F??x1 ^+Sa+2\2ɌA*34I1W9)|TV(1PvCnLoF5'i Ǧ~'mіa[8-JTo j+8@&"-Aݐ1tm4[d&-2 rLCEf""lFc? JT *f0#U*[G K*AP4A)U q53(Vdʬa&)tbΏG³z]Э;NrrUz$ONUY%ί#bJhu|7&.&ͯ.~E5H\_ hdCnH2 +$Lo\}ZOkd3b$KQjH 6։\z<@abN+_C 恖nXT_9L\d.2E"3qpi8xIc9fO+;o\zou+=lXD7=Y$9W 9A3A_T 53(VtƏS.ze5Ybu~yd$^atPj?=ӄbA(xW_O ݤa}4@".&hJ>=/}*jjs޵RJ76ˏgLjz~̑ëfg0\__@a;_d{RK?1?lYqiv\o Nf%7tT]$a0MVávw +6o.L( ݋fx/.O }+Pv&v|񦳻MP1Nwt$.ƒu%(=e!,Lф0==ΩO6J3mE=|Zskrx;Y~:V`7|)?<^uvL7 ʑ;,J?^ѿD4)4]>o:Ee(}fE v C)3%B) =Cj|  Kz7tR=<$8ӟP0PaŎC\wubd&o$[\vV rr ضECRAfrbYO F Oj]}֘B3;ڌYCXYiοh~!%(^fIZm<a X)Je.dͤ1ր<"]D`}V L0*pvN0Iks|wCEy M>+:l!aYiPubUˬ:_$՛2m o)}[GsB^)":WKA^Mzy0/U~6En8\o~s vԷٵj$2!㦁brx8r=nFh´j5k-YT~do7(_23Ky*T ,4UnnQd%X\YMیE *fkl'HbCm~?wSTT9\nÁGf|%!G԰;5[oϻe]P/ow쇇u{fPAbpMo+\Q5MuKAA(hn3j6wxxmC:Mw+b'Es ׻u)N(Z§`~*X Wwhendstream endobj 422 0 obj << /Filter /FlateDecode /Length 16228 >> stream x}]fq}\eOi~  vKBjyfLhNd9zCd1?Ͽ/)ytoH?hqvC>^}OB|R{Ro~_|x21}Z3|xz7/o^.%?Ζ~q~c?RIr/>>7 ,o>|zQ(Ցû7i" ~wjdy-53Z?j}sGRsY?|{?3 uw?ۻr&R1y?\cMG De8.DIm>svJtJ(qIJIj-WÌr FUؕ& D{xƸZ # QU"0R#U0]0<&R?0㱂|Ƹ̑F~<0 [ F>gIr̭UtBpʜsk\E5}kih}㒥 i.:S~y0NUu<4T71ѩ~cğ"JCRKGy6Nym{UҢ[۫됆2V}}vT64/ܶ9'xZ Ĉ9) ZkLy,}k/^Vۧlt2zH2sE}霭 j_}Q04k W&/ŇcɢY-髖Y/bV[\5HϹjٝ[I'$8fb5-)ŰM4Fh1zES.C ebnito{ގOw Ų:iMnL2|F"w1Q&bǑ"VA00Z<Z÷fcI)NJ7b$_w+IZrH͟<_,=, i~bk1ꍪ]- h^/7SԚ{ghWKS`~+xo_?||j)"2>]Dt^d24Kot72!%#FXcMZZZՎ<'~J{u%KsQcC=Rb[(/e@ ǜka^3d8%\p2{FSԶHs91X[Գ:E!cc@ b(rMZZ"vW;`T5mJ$ yL$8*ڳ]h΀EX"oQHm0dh bZQY XGd%)%9\mEڑxv=o9X!I* -2RI(3ɸ8 W0!3%a-JEh.VaⶴUˠ)yCDDHPAzS6eUbgwR  wL:-gq `w$pEw3G#v'0S^*^6Ͼ~,#*pD+TMԀ\M0 WҘ3 ̴$u(,Av"V:j66CJ8F\_F "eZZM*)׎HyLEDmh];j\/ah- ^!`H/Z0ٵ $fRCCTj]jVTX0ŬsQe1 l"12m09'<&`T)AHW+2aṙ~a9Nӳ'*tbUF2VCZ,4C.\RPCgp5͒ID1-{!+^Nt-{]U|nADa80%ڇ}]GT:eyzyyZkQeXsQTF`x ۪4.F=v] +Ua psiZ,&CK1L 7 QN 3KքLޥO>/|Z+,CJ.Jai[(-h0^aP_7{4NƠa`fBR%8˜@)bPSƾQta%pC?5Y2 FŹpb)#xm UQ:춥Ql;s5Aih'Z2 l jIW;ܶγMiRyȸhEl0=thQX{n B q|^\\>7*HW,>2Z[އ*^bЃ#kp7dZZM>Kcg0a`S5T®~$|WـGɘ {5X vWpX#[ǻIlrPU=a(`Q,'~1~1L{np_0J/eD9s=Nq̓#3Y=iԛvmUl>0S t3=ie6c2 MuyPyc0dct^A>24 @ RPKr Z{ HE .޽$9'WV: E-B$nC BFp یK)$9\pæVtmHL,/4qJɌ&ѧ6 hƔ6(@́I7K0u Eh VeRF׍5##k9k.߬vhPԦˊ.CK氮i-e8vaZEvm Nh \W ƭN 5פB*V`@$h`j8lB/L Pg/1%;D;C# mڔ4IKDJSR*t`yQ86(dC›QDPPIgp-Ok 󆑯%-YxbRP:q l212Cܔd8%\pmG䃞nc%#K-L;#o H=Abp I"9ȧ]A7l vW+2qiDkܛhQܰ):Z#Eq3 Z U}7 ;XL"ahꭆ8:WqVY),Â!vi e\}kEAZÍn4* !M"L$04X0 ,iC&%#Gu;76)BKpclS߫kuIײ;.3 2 ]9{"]89,O"vW#ܰl4>Z`Xi:>IGO>ZFJɢh?eG -⳺pld[`}h"D; M@&@dh b%  v Bz f.!~m]Sk 8uVMIAOfM!AÆ>//F> 0**7bwlnW+vD#?|q }`<0C RPKraRA4 сIw_*isH1]C # Oa 3LBLTF`uH#[+.ȬE83uJn"եZ6;6zFl$¦M0&0΋Ms]$kaTa14/LfkͺtyCxWWOw e7oDf<1tf-X^?tei?t1Nc$?(~XpMOLz Wyֶ!|Y[d|ÏĄ6C"*N=vb^p <1^9F+u%,zhT | J;z)jb¯c{JKM=aY%05?u ~Fg;Jn6?E8Q\a"u:M҃vB?N|)0OT,v^1UMdU^'G2u҃-c'^I6Ҥ AZP3O;~ѬSo?" m_dUY17^rÔW":ov)Im魂5m|ޯMeY N *GWu Ԣ@0V ;V+.8-;af+dpXrs0Gh'24EU@$aWREJLs #Hb .$TzvX̶W$hOt:ZfaybcQݺqpeh bdA[VAAj٦m[۲ +0I*D*x\բ! @Yq`(zb4{*C/_*8\p7 zh1Hre\=GQM" TIcqX0dcd ՏL\# ,LM~Dƅfh8pF )=RXffp8{zAh8$d.3N67v6*έ k#0ڢdCz@:.B%JWv:4Y p Fš/k jA jIW;6q-կM>C=QnC#P㮫GU$Ipbi1 }paD]KZ:: Wu/8a}ɀW48=xXkv=sP- eύa%Xwx72M>ׂԒvmN͵pݾq9Obz,"='tŶ `!%&Y%vW3u Ah VecoS\-PtN!GD40m8F ]٬mq 21'EItKhEPPopc٦[z7!wyr nOaQ䌳A #H 4\ Xz;6#yhP1uQkDwuRI T΀IeQ`1ڣ.L=7&}#7*%!z]PUhmޒ^ ދO 7vդ֒/FqG J = Tl]F -AR sI0P `vz 8uatnĿ6<p?ЮI;i;hYOKh Begp5͚  H1JbF ̸4%tUdl pLÍLw$B{p g*W¬"wz-xj(ZvF0t`'ﰶqumn v ԏ .M0+I, 1 l d l80DעЍq8=DT'dq&`JJ 7 9W]/p>0Bse&IdRtζ~?Fq${ΠY#Ps!S:\Qka&n&`LZLZ)Nd,ŠXa0ܒ+A HW+2]SvF*Fm$pUY4hULύ@ƀ@nji11e 0Ew*W̬@iY,Et=Qņ#騹l"@`*KcE0(#\pplU #ͻzѣGit)?6sqd4ѣq8Ӽe9pl- D9ܹ&$n׀]Om9Ѐ}w+'|t'rð vWܦ9#8b? t*TQ.č?d-ݪlVuЩMŗvhP2 6M6U0OCFHz_w]N *G7II 0n, ;Eg =F.BK#^Cu ȧE&?^Fyx>M 3%YsQ↯ZEm>9g@bFPpqл&`hA jIW;6[?֫@0&HqTM5`s彴]P,g Uz`XdI@઼TpVn}aF4HݦzDJUDoNtd.'6{plAT8a&+VS5o60: Mm u186ZuGm)%a|e"(%9\0ۜ& ݈)jH*&sa{z ik@ b>8$dR,\ Rjfz',2&# u'1QŖ$BO[;4'l0`ٺ%wKRPEraiwP+fʩպ訦GCSdb"[|q l2D` 589d&Z"vW;̶][и# r- MӦly y^|{49{!WΘC>):]D3AkBn{՛FP0?n׊A Ws`0lrHaZ]yXz WFnLz~vcd9߶G MLGā)KkiwXM ~^j> c58ĂiOQľܢC~mݖd>ť)%9\pےS-ls(XE85YBz/]rp 4o -ALYš,x0$dp-LM>/^P2[!?Fvun$ 6pMrD)_Ah鮂E3II bR9|ʵ0E!+7M%4~AєD)Z C`,]G-0ׂԒvm]˴H0Vk2؅r T/ =7Ml31qX *Lp-VL%^˼!Ʒ*j CO=P;JM^G+^[TqS<|$ttԦ3;âClA=Xq -9t-=p%be$ b!.n(zZỏI]POh9rX 쮇%A,%HA%bY$,zObv:^UeXT[/A aja@ HW#ܰ8û3 h] ^%.0@$ / ׅdp,WܒjQ/-5NEF?zS̔=>1Cc[6%HZfe7(aDRteeJ7-Hz6  =!B ѐE=J8E(VaCyCTɳfVO,& >vmzp"Ł0D0GHh9zG|O^8@jV AQ8:q)`pMMs:ύ• +ܰl5}} 5|C(ݬ' )"|}(A *nVv:.~1gXf;8} /5?ٔ)e_v nšԒa-HA-jۆkD04GkF8Bt6l&{[VPɁ0D2G$l -p" M Lz1sg-`«a#~b'Bk@YԒvm6+[uTH ]8/u< a.-ߒw)bR 3,I=my)Řd_ĮvaBщd@8C`JtMp5 K_Mp ]nc--h٦ m厓i}Y -'8M: = Kypm+v8/7]6$ֽO䀽mQKs@d6b8 ] RjۆavT҈i aӵ 6h 6~zAG861eZIm\*Ո0ƌyÜera:"@d0t$ d \ RPKraw&0XЂƖ_>-l^;4X{(i@dcn7pkup؇ s jIW;6=̞. hNZ[Iؑ߳(F+dȀjİA7*њ/&Y 3REs~NzfF0pb@DY4|šilhܞ H@jEXfUN[Ls%>QIwW% a8{bIKRj[)i1vkssnӴ;SPÂMLspлDtwW#0l!aƻjM[Huۅ\C@k1 6napW.m"]c*{ n@Qk1ACaK-diIŏږh]`#AVB 1*Az;n:8ˁ "W2Q,\{n\db;6 6 01E GrC]0̳GUd nƢKwcQN40G5=`QMJ8c-崕 a rH@]p)H'1̳Y"'9wĝf`&5j`f)4r,A´D;6T&zbP,Zϊ|Bxd`hiq(Ly g*hoM0dz=a (K'…#UO JÂB1d)qmvHM 1yi b\C^"DİEWOɀ0$h"2l4䍀*3+%{˃0՛W,Zt.ƃi+m#>;@5Fi t{KRPA2f!%d0 =? ޯבElÐ-v^5^ŗ"`P)2md,n h7mi9UEm@8Zl8dEQ RPhnn9>œz=6Z1Tm9 Op 7 A*f2FhbJ7=V\!z _!QkՍ`1`@8-y3H{${{i࿇^j5[c# j~32Ŝ8,9[9m8!*{nrz՞ OڔiY})SA8O+XE UBPPireK񯾋0Hpz~RY&3Y+53 MgB1” kI\ Մ0 /'džp3s@(bhu! #Nt, ~cSAfU*¾EX0$R+j`v 601ݗȡ6,Pp)%9\*Þ 0pbW,q5ߕt7P"@69H]=b!@X::Պ aV-LYY,ΎMA,Rx }QwC<0v,jqcSKV--HA-jvځǞ7l4c+.ߠ07/%re#jA jnp2x"S`al1HDsO@;VrK{jJX06,*tߩ1 F '9tzAA݈户hV8#Dq! |H^U /t1yJ."Y)U*.0 XsP{$86Zš#{螘 $n%;-fwpMkIvO0 WA)~HdXG|N &]*7kZvvaN4Xm{3[+)W|:Ac}qhT^2 i)%9\0۴A>GLk6gNp8O) iȈgNCp-7۰)af>]H =Ozo -AL>Ci2`S>~,~:mj]TeEQn]MIePA/)e}m4i's7IssaNpmO~= tx[ u@Uo{.S=+}_I0vHK.aWTaم$Y0 _(‘Wpcl˹^bGanΫzv-ע]{HYkzhgp l21(9iAk jA jIW;`[I#N8N{j#cI_!yЛD!`_r Ad0XKP RPIrXqy~q=uxҋo*??>[$vgMyk8y_VLa4㋩Owz?b#uL%#Y0qpN1?Ǯ}[7Ϩ-0Տ`]1DWez5p0xň;49:!B8AF~qta Z0~Z+dxnj.8{xTKW;4D1SeB³/iq&f8Ti1s>~fN㇓jJyGw#1io?݌V(R33'ia Y̚36y1wmi-P9:1+KY]SJoڞf5ƺp;>4 R*3YVn$t(5F&; ٕ'W6w`<@m@NN m 1ճ nط<^L%Ʒ6q,{i4;}Y_7! T=D˵d`0"2be}Տ5:kezDF*u|X(͞=ma| ]{3ϦJ40Θh1< &<6ÊЁW2mkl:\_*0ۛ%7^iZ2_-oO:bK,ME*mTwWJKMأE-)-Ҹw%tkJIw4VyEUoLX9) ͺo>pA|w?~|~/Ӟߨtç__nj~{:iغkѕbz굾C2zQF}݆~z"Jza+OK߼ҫtRJ2T.fzs|4<'3>R'%-UQo|bw_?|y|xWܧ_R"4˟]ԛOu:d<={" d ûY#SӌEwHϟD5W~z2_tJ=tio>|zw!?۟2pULio6hajYT7u5>IJܷWݝΨ o@O2wxQ|Ƈ1a ";C?Gۺ4׺L)b4~{r.#9m}o?w닿| Kza7/eO>~QAW0tWб0Z}uD|wV&Jn5dzJoX|ַ̟3%m~{-Si_{]ɰoع޼{4mCwnB=\Lx7hٯz\ ~|w'4A&&h#Z { xi-klPvoAaw$oG{ >ZVbO׸̛Mmo7Y+` Ҷ<1F؎et-Z۟qJ,)(-?'$˝k`3v)5:m]i;O^ ߽eHک.RKݵ3R_olK= }Y=}ty!=F%"H|yxj|903wRF-0t,;%Cw+M&.lކceS]fgRϕߟXk7 zͼѡX7k\Gzy :}h}>c D}aM,ݦzʮ 0}܄A^#qh@OMQWj uk: fqӻ?RUtXLjC_XoXa|l3um|q Oɤv/_kg׉N]!Oohv/N5T}|yjJ57ucF5z6RjK> stream xYK7/tvNMb ĈIvcmƻq{%g [G7)800(V}U0S_Bεԅr~`)ɜYXp]Œʒ,J5--,P ._W]ֳ^,9gVD`w Q:( rrR}-B3K}"qPUgFHc I78-9cb0Jy8@0# = #JX`$I]Yf-Q}h o \s iC6N`*Tm]]%!ŚN[aRȓ RA}CHR/=jI"} I͇jqB򮫽gRAR%3κQխ$)G'IBAf`іw DrXYWK ),Tip<ksWwa$i{%66ygYPd`q Cf(l[^Z&p_h+ Ґ3 )s L%}4M9ʠU7̴6ٯt%m6g*э i][caU:=q˜O]_ԋ+\80Pjr{I% ́n``cߥyiwՐ)xX *GTz{ergKNCRsq'HA+"J,n.>%tƸ$rU>Ryݗ9l ޛ4b?> Sy@ne%+g)ɳ:CV2&`KLM9mpj˅'w晴YRwF{XJ&\" vHPvcdY߅l",8%pf~wol{tQ_v~%UEKJȒכtrWMar!_n@CX,jrrj5I;ѩ+p 46bSTmDZC^o'D}!:㊟ n)#aP>Bm 3d8  C/<La)NՊB@^ڬGl}ܔd=Jj ~5S#08^F'RR<MѥTl~Ā7v78}iW7Zs2O7 4/j[0.l\grKaWŗ2Ҟ2"BYXdm{ǙB SlO"OOt3í ,odSz T=4gHj-ɒ<'~SZgXJn;.̓"Hx4H86`T(Lnü>-qKI#>v6+SR,\K*Emfj\qϰzCpXo(&_v{wڎ(VD>yH΍{br'{_؄էͪ%n+r7]4nfԉm/3*s)&nS5%J#UК$7$YA;]Zxoyjk1=;-KY^\Y י/y.>?s* ,ϗg l* AJi#{2}Vp벲I ~7c%qN8 B| ߇v-u7n_-'cDȀ˩0n3\?i#$zDssJ܁vYy?{GdUC)&?2\iWI O,?Vۮ u0K3qv#O,kӠO,YXbI/R]` lqN%ASOZ^,ހQ=Y?Ax}Dܒ{ 4U¡,sTVk6 3 #=ɕyCåPI#46W'+N+,KPcMw,&J]$\(pD^ Y8٩\^nd.YG+-1A4!UHTȿc ӿ)׵ðe -shđmP(atE6|Hc4Mʀof zn[,vxpK/G{8$aDg?IΝ{OH[/L|ڜuX߈-iNvLh:,wu2endstream endobj 424 0 obj << /Filter /FlateDecode /Length 72160 >> stream x۪-Kb># 5z*AЪ~(V]ܙTBfc 3;Tam.~ws:>aoo/_0c|!*h|~,jӧ8zcUu%??qk'7<ӯ϶R%! wI2ݐ2GfίOʡ<_8Uq~ϣ|\wϯ|k*cWu|}vlec)?HULU_WGH>KZk}tGlr. S Ccuqjj 9G5qO c\ D 8bdHhy}r궀t06%o9a&ϐ1>Bn D: Y@aҲ9?4D]zf`I6.'Kȵ[VȪy(,+hl/rN+hG[5'SEӬUw6"U̳kwUoݦ!(߼V#{ϫ\eseVV9o>cb. fW9 ߜG*z+sj2eM_*ɭ1\YXl0 , 6̏ujMs!G|a(lm՗7}kUMz7 ]^Wm֭(z&Nζh_jR_uۗW"?}> [%X׿ڣ2Ռuz۽EJel[bf9JVv2-ZόzI͋M ŎCd"}q{},Akv*NunY_9n*:*c6ΰnc+6^lc6!mc#6~Acs~oOΜ*՟k_36&g[r\s~f ZbG[F^fM֎9O 1U=9cuMRꭚ{V~z_D˾3sȲJz%ǂՑ6j&?u}ZCVkZun˿} 漯ԥfa5|U4Dcv}k,.Őa~\ӛ!/+r}5~{ݻu Y \IkUThs)̀f#a}B$ҭK)jwrڀ-\~@㻋uUV-4k9dʽJ>dIv~_ J_,OW|!CEZ\[cQ9Mjxzե{۹ƴ Si֧B=V4!Lxb2O4q)3Gmw\ie3W!W5@Rr}gyliU[.eV|zY!iB4^c-^r[!F6fjB|! Dl- 8U`dX h plX)~fvۘ,lԱ4ڮٸ|i?bYhә{/f5Vs,_ξ}7v _tk\sW6¹ .{MۚmH)XV1W}o9s[޺_ևd Yǘt&~!Gh݁De!uWȪ~tc n y+_js5~_|Y+5gXQ5pIXKyX׷1af*GmeF/#3?9}UWUdO_gjvk"<9UjxEW ,·ê/1[]%f5?dחU9柞({-S0[#ӏwAiWp?[AMYs?9S,W֪ȼWW_c5/Qǟξ\.vc?oU_o^u9T)K9tԺ3(Q8z Ysa`VЖcDf !!DZ|f -IM3sulWZvuAz,RPtȐeBI˧f[։U {@i~s%zۆ6UHM3BOn68$-P@-n݈WY\m ڶw[=xw[SʔݔBIB8H˧OVUm@6ۦ䶒m[YԶ:Iz-RHsqBFF-d|Y.ʹ[BkzbSV&VA2L9b.$-B%!|XX2e=Ec2F9FX"gb0ӛ"H[bRzI$7 BO+`4k5ܲR"nTԖ=m du i (nخvhؒMB ԁ Bǧφ&˲ٚsh e;dY3`+hv!!f&V<-&Ȼe@6O[lnٚ\V|',sr7.e;C@ T!zW4aj{6 #juù~5GIk soJz7M)8u&ZWO;7NZb6/Fduu fG>M i@OUI IϳT;5!iH:$4a+kgǖ'EhJF9>l8'5Sn(v6Si!i&Yku|=b{!.f>&b&Ga-g5m)B)Y0K/nYKd^>D} TM.>I' .R< ;>TT3/$-Wm%և0,iGyH6sK[g)M;$G]X+F6.6lv_)IK *_T/NBHŧR']iɍȵz1%R P:+J^:Me}VJ>{)YQα&TȚvo>ĥПY+pw :er2{Zs=Yu6E}oAOAJ`(-MbbD@8H˧60cqg ]~j Yc8MS(b@2% .Fa֋nu}7nGH-Yr>'65Ddmf)K\)#(A 2gQv0ȢO|hAkm;PmۡA]k$ҟhQA)7uis+1ڥpg¶Xbc0;m)8  !B3_i {VQ;DV qQ35~rb(]PivV#EuYAt Z5jmGH~Vvz`//sZ+ds;D%!#h!~`(`d6L ?YSddP/,$WUƖdp2P 1O+ּ[gظŘmc>D!HChK2"E/2B@*>m]ϱVg^d!oc㤹JdauK X{i(9b1O+|ƄF^y@wodc;VTBb :$ / 6py T']uэ;扬޸)MbKQ@dJ"@:>;-Ô.[^Sιѫhl'f C2@tsd]q2H qO;m?\R ,ҝy,/b )5q {BHzԁM D!RBn* ݇@wݖ܏묎?E~+sLBvOiӁڪDXYY"UWWVS."@{xCKX y!" icXw۔HN/>eqr Q)4e)#j!i7}4nS=V;dźwou`J}72Ś @`@XA1/0ts]o-JNN,a_+2~L@sAX)LA@Dp_`w|Ն@NF&_=o4s‡oAOF\uKD;DJ>^።>6_fvX"=lJĶ+9+E8疛d@-pUF;H@Ë ]7z-![x0GChʈ @t"%AJ>GGh`~FG%zhkz'ÆQI̩7D(4G&Gz)CiYNUԧm>n-p(4^yb5SG!BtزqaرF%' nav&2DJ{>\Jq5 :EBA*>'Wߪ/LcG3[v{UAt?\7d`(v`_@2@rնU2HeO#p=T36߬$V~>=6oGp .M ,__d )@t"%AJ>ekNpBf~F/\ 14Svl kE@A@EpO;6[x6㴭ZjGV@"F k7/nLM m[^ъAt"A*>xvp?F [c~K.4 7{zB]8N{R qO;Ԛ_j]+#>_ oNrXLdU (li0b<). D@Hŧ lh7DIp椶'C&:ʳc z y2K) 3m۞$M P嗆Oh׉]j w`ZF<^}` m~La}-<{=WvVaxW]-.&=}6-n  p Ryy6sK 3k L܁,ڏm?x({7OM@ڻ;?L 7PrFp:z}~-6Yt7/#1"# ӣHqLI%sO*Wrhsesٱ(,GN߇^>|8R@t JC(A[e̜@ҙkmIk0 tЋ_ 0|>)* i(<-CF[6Aqڻ_fϾq"H1O+ѳ1O.,l@^MpH+4*Fk2KhΧo)}Ȑ *Dv4ew!v^1mm PCϔrܾ x]C)Aiţ {ԭ !D9voGm[P!SD GvSZOw Dp59 2@{ݗrdJ@]*>` w$kr mjhBx9OR)l7Si!lt-@Gop~)hmޞ_\@AoE`o D@8PLJ Q1pxT+6,Y/f^}oL Y8X$P+t"-AZ>me޳Ȋ笁x'ĜN6oC; ׎xl  D@8Hɇ\JsJ]k&mSD ]As_Дڻl6nEpZ2J>]h7lIa|T?̟h>z"”H:ܽBh1PJ`ĵ1"d V_UtI| 2\U+&_Dn.&ȡ f躤i'R q:d -vpr}xqۇn; :WS[:m᭐?Qn[t" @>L;v?{pF o;r9ao}¥߸r;}q&LךI# LB9ܹs {!~o3\p(末oi{g#NeOd OK3OC?>9|%M1kxQ8✞i&C,` gou#z`.GoFYiϗqBh](Ȕu iŧ[կ_+,z|a(yhn;]HZl%fl5&%AT Pa:ЏfB@~Ns?#bq)$DQ:(&HD8PɧnGA~\϶@dtr IV̽:$Жa\Ƨ59NBH \WeHݢm'YF{"J"[ٶɼ1 P喂O`VtYl f Ҍ 6i7 f_#^)22E\q"HqO#P ;UÎDiۛ\{(@y&5x^*AR!rL$_vz. U䀔SOZp/=ezv3KEtZj|R}6;*)m"dY惕^ J4sUA4terOXQO5f 6dW3D.njɸ٪s)ʑAw5p@塡p!anTt1@qCVP")"k(tk8-^|]N4Luxu{CGr=$fs6Sؐ[rHZ2AZ>mkEWS{ǝf-f+pFXN% ژ"@{w8x?)d 2%B@:>`Qb>rَi;jLz48$2}eo>fWJq) Si!il,b J>Xg}mR趄dNCeԐA7b79NB9O;`۩ ]>g .vNml<4v#;v;~e b (ERiD}Mdz`O*@i%-Ͷ*SD T Bǧ̶7 >~ lz A@Hǧh,bU;V JuPk\*n-JUx%w%('kKQ)CiBZ\˾B# zr z)gUvrr[SM=TTC]3h=F6r"rAv ]=9ك4Vr⪱8@ gқi;T=-,@<Fr#egb kp:d -v6vž-Ehc$UvZ`[E,]s] A!TA ӄҥ^υXXs zL":z_(&AtH@N\!<ϿCG,HMWnkVH M,/)O*r DRA٥"{P?oal ͌4$(1QdR,dg!CDKD!P/VQ*eGɠED=üRHo\rNP1On?y2.N̉cZvA|!tqXO%4یGS 97A !Btܷd';lh8&Z<[}1p"Kn=8XWpf}M2|~O `@6~ѥhBCy4<'T."o p m}!"SЁ BǧLh)4;`|q" FpJk Fxw~"XғQaxB?O,#5i0VXZׯl6g݋gOAa& w3nHМ4LfoM@ %V"plI itfBqqC~}ƈGL16Cr:d -v.VB#UPA_`7r[wmH].{DHŧ 0%b77168J>8ʒX'Y)N{%#hW;p;؇ ͮeу}w2 ƉeDHc8P1O+8hzoid#\Ij. N&C'bl4Qb28NWf~O *{PF (E<0\MP~L8r3؃@w@nw=3h6me6xO)c1&'ཆrU/~ -S{dd" |?[-&:U(+UhQBcݕd<b8NH r-vq9 uH"+kEJz0R ~_!}~Ү~r[}߫cłҸOB +?:i/̢Of6 )~29%Q'r\Jqc&8NB8H˧&fqkʣQ@7%Xh [kwAML)؂@d " @ >MY>O\s`vIS}8~ glXHזo)#j!Ta/skxY1pn'%~bGVM]b]+[毼')B)YkcȈI@yp$os.hfx~2{bGy[\sC%{S }q"@ x[ho*f\` @[@~ Τ7<9ہ8~ftv^gK|\C61j gF ۧgX/Әj;dΧ1@LbAɐ:;o+8[{(^wRVK@"cp. !/Xq+977ΐՖ}Y˪++ư7]ExJI w?~/JD̘6N4E!\U b0;Qɞop͢Y@n0{8?L%d5gsyqZ^pK8|UT8bAw&oӖ!Sct twgʫ|b~iuG2G~٦# ]x?{m]Ί9C(Av:BoL|Pp2Sq/fcB?S]Kr.Dm1q6 MOh8μ}y+?;O*^欀Pgu]i7w߿ %}ŽhNæ~-}Y zzU~[eVD@[v$Rݕao|ݏQr6оI#z#.LG[NvpWͦȳꛟ@[)zmE?e/n>"ۿl_֞-5GȼQ,(ygM[s$o YmopZHI:|^_T&fzk =RP}oJ=Gp!cHUi<&{!(Tp lTgoo=cs:d U $X껍Gېf kh)ƴlpϑŷ5_<1.;j̫|RO϶(_s_xjMWszjS)6f*c%Vke#֪ϗCb[qզ.hI8a<,ؖ.[,Vk ]WW5^< e_퓬j_a=xcfS5Rjrn+?hE{٦uOI5/{xշ6" VvaB5B܃q2749=`g`ZZ#͜Q yջpf]|>"YX#.VE'Op(2{&ޭ#|cPӀ(?.8<ԁGqKD!iRMva7n x̵D\=#3QҴxc}W\kɼGm^T1٥ӷԎ\ҷ7J>BǬCPib+yV>w ;UP"j}~'̭snOQl/roMʝb{kv~%-x?@$^'gad{d];;Gs[Gvm/ JJ˶R\(юV궹2c,^ ǵQkh}o}ӧonGuZ6ْ#IvAϐ6ٯHzܢDdBŚ]$=;Q~:c~f5:uԔgeVm`Vmb*6mJIO _U)g!!DZ|U =TQ'4hq'ڕ-^NL6D 4|L BHǧj3):l[:P=IE$5) DĻU*-JS*!i_/?G9ޛXWz o?M9ގ),ldtJ0VPzhf|+܀j.t~с4A⥪qn)l8@ `tfSR9O񉬜n8 ә2@{Qtb)yr2 -vճmV{ /w *}1L\^o)wrwTOQ ;Z@dO҃U)F猪 p~uiI?cSh6:2Ɩ DޜprO9${"p˖w>Ki%iDm[WfNz CD ztD:T|FU=ds60?ZKo7b="xL <@2 B51"H r%Vo/t/eyFO>/9g16 '<煵'92 -%@-l|_'׼L}Co5-9x|2HįD> A$i#+;a+"5N“D_g~ P $.b{)~nPE"9\xBMX=mP< KUO"<2vE/$)Ci㱛hŅKP ${O@_oDb#0Rp08N .cj4o&ruPWgRF=l%2NP 2O+Xڗy>NP >Wl|: f&^<>ob RHK喂O8阘⭲e Z8m_s\Gҷ;x#1YD #Km^)Q2wh|RNN Ym8 fEL֊FNFq2b V˓P{L>iظ4PvwZ'ى8CBTA v'-NPhJ냘b{e Z) ܳ'%#iA~2ZeVF @hUnS`؎8KPқ!ҁBŧ0l`$%{*̗@<^I$%2F)9_!w;n=@$T Pic0,0cHc;I+_2X ډqL"Ho␴dSBXOvzFU088>7A[ jICjXoQid: 8s2"` &/хaz~셆co'͹sYvuXp9l郃A$t Pi keѶ&c'iHicVv['^9|eQ.6lNؕl@9,b݁DIc'9~ 5 'Cp2H qO;'zC vD7r;H&S$ӑ@i߷Vv!l?OL# gxL=v`T›gȤY#6y mJZ;ǖbS78NB8Pɇ<]X|̑>} /Ot8| <,k!DJt|ZN@ 784! WF'' ÀOrCDwWCҒi;TʻNO2д.1WgJa{%L P1O+#7Ղ{pbN5pzZOp+d~,p0 li{h)0Tl;,y8jf Pç rG4mL$Viv9ԎE84q$JWs!E@Hŧ\խt]jH "9DbDr~w.eգ:d:X08NP qO;`j>DB`AV"7qEOMЅX`E_Eq g`"k'%Bz`[d{6T{rq;$ϓ DzUg 4 B9HձNʉ\}d׿C&,t%{j& `3^E xɰL!Ϯ'T: NO J&nV B.=jO"eStx0]Ęy癎cQgV>$s6;>2|qlXow&`ܒxo;ok.c5 |c:F3Ql8{gC׈ 7M|+2bu4s[ֽwVd?lZG1 ={Zсfiܩ^*N4''gIm9)SX6Si!TaឥxۖD<-|t:it-)9?`v^E#)B o3~M[IWRMqX}{'?QA@B0_`UǂرhNlvҝ7=6Âc^ܼ"A!R X}b䳷Icި%]JM"^^z-E/}2H1O+`ЍawFoN,4i\2<8 M"{K}8E({!@T4; 8ad*wTt 0kU\pğ|b: b &->q_VGETZ[\l %I<ه@SSlHFD!AxK0^%+aM'4k)c;vo)OHSi!i"^U댣g_n+8Jd\'9ӎRh/ $F ;/k)#j!im :ƀs~ &h݄KĎ+9L2@wO8NB8H˧ow|rH /?8G z3tڵ8UAtH @ >M`y]{^[4Ϯ7zu Lwi"6L O#`d82ک녶 27N!S2X}Ҿ*=xC)AR2HZ"J>`GlXy]4Wu,ҳ&2|O2Hs]ZږQ& !҂B˧A+=1 u hk16U A,Rp A樅1iMm<&¥ϓ%u2hE_+DĻ6EL >{pVp]7@7?UIZ;+Q '"!ѳD;1C(At "% t|Zm9s[ʾkt=eba=(8Ib/A-S?At ZChяĪVeUjU;(aPTٸSr $-ER8 A !TB Bǧhhǹ_H;kM@=hgю0 ֤?1qo^8q3U@(_9@_ǣ$}6x.&R|89^>_K :e -v"v\; WDWCewcH)Ke $YZ3S7~ hL)sό.υfGokkEDpyۅE|A{G=2?-[v! L]qTeZG؅;[D.O#ђ4uq $Go,R4\+ Si!iY5~u(e3ύ8AOY`rXSn[ о^\V D@Hǧ `k=q[#>(Tco_fmx›pa18NBH 0Qo,iC#X%bw,g ;v' tHZicEx; H~KI6d|P34Ph*}8NHIJB !P/Vtn>sNDV' OÅ瞢@ DKD"P"9Y/V_v=^oiv HP3ru qJmΏ%*@tJt|Z@ia>: C>@r'3{pz~oރ(q%DBA*>a~0h_ybY+> @8  ]OxBA!B)ߋU_}vL/a_F_\:]r/ ?rpBJG8NB8H˧Rk\*: f %#m ےC:EdPK@?z%{M'-k0Ɣ&)Cistև"x:C]YSb0=JQ D@Hǧ϶Vm ֒B4^{I bౌo8 dv1D0X^!'|w*IK2_`wxbXfUZ4$2`C8$xƽTIBO+e va.Z:~A|v`2hO@"S|BO޾0Bxt" T|i?O T@ np7GtXEHp3F"H 0V`xMEr1AIga:W#( $x?_)npSF }~j=XtA"T>N VƆKlph|pCO>^gh@B0_G`+@>}HZ78 DJo*II0"H q+n\;}KGwh9KM"oPi!M#mrd$-%ӎiA@$;6 f ǀ!)"NK"SC!CiW{yEpy#΁m&]F,ߗMA%F BHǧWz2;v&j41 ؝!'sn *MA!R v"~K0#UZ@&4tNQ_!OZsF?i a[Y]Y/k K(4"L߂.!d G0He hB pxyuyʠ[]@XC'SOTҷ/)Ci]>bZysNDdѧ.5!sc9})'65SӞ_ %!١W#yH-.ܴOz<7'E>1SO|(47<^%5S]Vۯ]X u|.s0i Bvb~\ȿV@[v)&+ D*T|ސs7lPxc}K0J2"`:>eիbҰ5/0Bd-p+R0Bhnwxq2 -v6 ̫v7E?d1,6aeX|At"t[#-M%*Wpazi;Oݳl*^m'OG??nSWzuᨻBu $羷o*7_uWt|B4d2<꯻nxA8q?I+OF+ksl:oYiQTs=[tZu:qyD/I! C7qgKLO\geozP{O%g8FP?p>;\'$b~cK {olUo {c\1ȝ7v }O"D/2EVb0 B T|o^ެ9Yt]- 7z^܋b7=19xː (}Tq "-!|WJpJQm/yYZPW}:qk+I mVW)ZgYMD G\F O+/8؅6SBo*Y>O9M.\|R'LkՐA-h[ xAt ZCh=ZܾR&^{{I2wLiŷ~b+9 H 0bޠ9T^;'"%m +BɠL>v *W0E_d "@*>l@q: ^/vds@0bFIZ\P+WDN#LqhDCr_a,#*G h0vIN>H|Q IS|M?:ܢ P@&Rf.>]WNw:e'K?Ыo Пx˼#=;T6SF B>*Jī(x^M6D'!Έ^xnDA .̟?4 :xn+8>Ļn'i/P JSi!i_FEqc^L?.ZtXLJC>y8S Ri{<?-D[7 WΝflDɜKHɸRWg x̬lp5K;myUh0!>R ͣ!!DZ|1_/8{Kl(>ܑ_=7oПxg+J=HrH1OXO_[W=PkcĐŷyk/I 8 wKE )yC!CiwnU@< >ovVDnD ?/%.&B|E9_)}#$!AURi<ʹG^Z>F^ TQ% | ?u-ŬX+!DJ|Z~g .>86z2a«t/"H 2O+~"-W-zYtMd0!9Pل7sW!!DZ|AȱwR`yxUۆi q2@SS_(m DRA٥ӈ!WX@rvwtO.KRTK,LB8H˧D =ĠeB69s*F,VnQ~x{+|wPr gn}xq #>zP$;^ǟAިx69-O+S.FMRMi/dO[R4қ@9HÇ4` 9Y}:T=h.7'r 4BNpVcl)"SP Bŧ aݩG/Hۣ[즄' 82ͼe֚ق;\ D"9H}K?/^'=ޛEṯhCm270 ҾLxAt ZChYgDdE[5pLհ0G%xUBԟd/9(/Wl7n'rʕX_!'Hv B2 >Mxa#$6wzeF!'$듋u~~b?NP%?\7'8@&&|>$ڜ*Vܾ !'@3-AK@Æ.Gm )AC'Vi"Rp#8- v9v`75TY}t&zA e \AK0O!"[v- [D B b B@#D]LQT D!A  ԡ9{O ov4Z5m LӼƢ|ܓȔ D:t|Z|]^\ғgAlYb^ * ) /G HǧUn|s/|Ubՠۆ wAŋ!r}fHeO9YLt Sj T ,JHN)n B8e+QV}~mzPtځRn8v@zێl)Atsҹuf_ij+Vb`ReAo/g~) zi]k )/6^xGg*Gޖ ПR<9NB8H˧fMOc DgbRF.t;5~M,`{ МJ~pD !B4+{*C߈!ϙ00{M榈(EAt"A*>at}ͣL7y *G] 4>'!HO4o_(E1)CiG+ ά>G#W}t 1l͘"' ɨA|2*4Lk'CxQT7*=4bŸ# z@M)Nq2@%FsM˅P%n};U٣SSB0/H]~ &e ǹ~O `"G9rIqV.;=u!ͯwOVWl?Dn:>?A۱wXtl1?Q /2 b 6>۾~x'YHAڒev_)몥xWbJDSHWv]#N?B=iߠw$ux/ɡKFrL1D !B.4 6oNsYMA@Yp!#l:oJ&)TPv4ɑH?"z|JtBzp#m9ϓbvLAtZ|ځggG Y`BQ6-~h Z2xCյn?s')P`@wt`:'x!z\ޚ1m"O92OA|_~| HI@"T|Agx: ډ; m3v2lp]זeW,^ef 92P$YJ!I1ȈUՍBc+`0HqspNBHsUa@|XJ2 8+=$Ew@oV mAtD0rXuxpWLfL g7k6k%Y=9%8eA?=t" @&K]|@< %#jīp>#~1*Td" hec|VByeGӧ؈Ȕ D:SHLGJ>/|d=C[|XNrx6xn1^`½ :e~Î#m6H$䶁 -!#hhoS8[KqnFh~{:|!vb-x)I_qIJ* :8z2 oWMD/]VE_#&9`mm8{28EbxܢZ?N=!hH:t<8xʬHpUAb1[>]-X>֫rq:d -O;snE;࠘@#-\se?m7]Y-t,A@Hӆ%1=JDzۈEL!O"&Ij!w8$-m: P.UK0~TAc}m~`} :E@  ̨z9< 1{u}}rڕrY ;0q‹NC6.2awP&VT"wnG讽2cVOVEXhnjGvmF䚼gPyb7X/4pX ([5&܍[;kTmTeUYR._:<ӡ?X*6!}oS״ohHgjg`/Yx? ߭O܈CA<ҦE)zqߗ@zK~_HyIr )~~6?NB?v$>9u3c\k.R6Hٽݼ`> (!Ϣ,c8Hjg]`oy1UL͜5#wu8nxb ק\.c>JS` dtP<~Y2x%B^d刳t~}&? ]ypyKEu `6?5\{HS.XNq<.MtAm?ڙQ#.j" a̟3 9b5E #7W&::?]wϘ.i,UwQcch3;|W>Jr/ ?7$E]D__\]W{\@NkbU"G+>x_wûhz*w͖M6_׿n/WLCDb;}/Eh?[Om}Lh;W_|ц._i=s!dtRN_ÆW_jS-u]l$R- 2wG?KD,z%1b*/ R kpDZaYH!r7qOҶLȍNqr ͔kkS :e -!jT+}ȫBiU||صa?qk!澤h`acc :EB% t=h-lU37SD AaBPAVu4oȮ Wȡn}AtZ8I*T>P2 f5/ԢLKuxq.B*ȶx5sZ"m?kcQ~.B f}Oswzi#(k$O ߝEGtL dV;bs*MUO"ن8K0{g@sZhCFnPB i!z~CQo.-:OBtGt _:Q0/I(r4dAADb O+#Xi 5pT-ȘsKróvJ!!D:T<}&VV.uӲltmC&0ЃBh 4l,Ci!Gw;ݑN}8}ݱ_t;CH;qdw c^kq/;`دW-o\:ߐ8# 6}Ԣ 82H q?hIrS'1G{Eޱfh=&h>t c>~tVuN 7v^w ~ і'nP"_D@k"ԟIoK>dKFmTH,Zd0|j1oS :e -O;8..\nI }$sE9qES뉵%ܬS R4]t$US}y~5l a&E/Ko\)A@Èsm~죁dQE#6xG*i|%ΐ1)wj]8NN{u_Ksx _,IMQ|Y@MS’  D*T=H#@shAtrwZ#~cFIKC7b"@~cۇN%)B)yXuT5:s*V~rO+db S{rA óHD !Biyg ? ygn2qK$8ح~:)CN~A,͵l쁸?j=2$b95ҾR>LFE`A@Hӈ/-/MzIVdA㥵o{ct lolu@(?^;-8E@-ou̎M8zwܫb@2% -~2-NCO97 \ |!(X3d?NpHZ2Z~7$0{LHXq!zW*w]Y_4eZ  D?vADn e˽j9!DZ<8`Nlɻٷ-Z~42@0>ooawaYfk>^ٹ>:"AKFV/OD !Bi1BҀ BDfD En!:DpU-Y6>C,LERM+<*SfT9Z;g'CP 嚱ԉ~MSI#-^W !`UI3hIqHZ2y ]w^.͒#;Gq5ϣ^cHhA4t]ry}J"qi~"|pXm8<>%RQd<.: b O#okhHsۇçq rCQ-4މ9B#iy@-ٹ%ʮw Rvݛ ľdb!=`^ܶEO2b O+8*3-N|zAj'< '/7q%Dfz DHr.UvEv0f:fDdb 6iU;l8b9l1|Kzp] 'тWFx\q)w8Gm%S'rOI3@z7%CF P"+.#.\x7OjD?q#G(d0VFAt"-AZvp܋7>^`w =[+9c`({^hxpLkuyqӶX)- Ŕ²xl6aZ(V KG T=`Ѽ7 #jP]¢@Ha80Hֳ˷f :dB-aDZζԡN!S292m&}GƤ2$s:w:8.`gG?wwAw^4pGd)_oPF ްCF "8pXݑCds W\ЖkQ zj@4aqΙ};M^7BWEbifKE_NAtB%@:V돻$3@r}q䐚 ×xNU@KCb" O#E"IlKb!zIc9T4QkɧZCВKb@-qxt؅7N|U< IB„ /TpM{tBrHZ2!>,^̶VԬS7≮8g=  mCiù|nmb_|qti_wNna(T '@t-))yZ9<}|U.^.LAO-߅Qrw_)_O8e,C@"P!HtEzb7IRIkf r<Hox| D@PXe5Y y鋕otRša M-ID@8HF?aHy,SYK J"]Aph/2[TѢ 28NP q e e AAmmyHC2 %TaĹyޑ @-J?xD&jj zĨ(tƔiSc%^>:8.ϡ]o8'׆,ZFM֔l. *< 8,8! E3`;ڂ!j} Uqޤ `P8P@q.tV{pƽҨbÌ7%j8N\VR7yiđ.̶wӅJfcvƤkW6!EMmVd ,(LD !BigiTl\,:)l-I;= fO[gאY'V^jgq2 -O;{>HƵc9NljT CQy+}It zZ T? S*!1Hr=EZGCI|JZ-4ce9hԎW!kXxp任(vpb4vnCF""8@FSv>bddBғY T+c|7!:-("vkU&LU3`'1`km$tR@t:p% O`3ٱgv]XyWaܝ%ND r_S@ T B~bӗ 9 sh?wDSn Mzl` S R4 ?_3)PIw\M \KXs 1=5 ̙bp y>7|.ѽu9!V"x8i}1I+T(?OmBvG:kQzsG("Ȣe|@tf(g`4TX9Ԩ͒{WG%#,EQN"틵,Y‹@A.tDd[L6D{q<Ϻj(zgH]ᕼ //arPT"^o ȗ}E%rF"p=# @F!/d@"(Tw t!^y^}xqCm|)#Wݑ[kOՉl gHNH?tߛ2$O %B.[" `6ȠdK?2.v(m'BB ;Ҙ~۴XlMߦKi -0Rynጞs=A# MbMhwwޅmѦ1]hb]w@xJq+ &G!'wAKmݺH@xD?~\'0 "j_&(ƌnr}+lY&->'|Gb?f _} (CuG7YU62✙ o~0wU4vƃ+#G^b ? BarXbWR-4^g|mAڝє&._SgQ K3d >O⭂DnxwDYgg&%-8RDADAH~=]㠀SfIUS" <zX'>8qDcpH/V'Yn1NfG094Ƴ9H'CXnC:w`c|: )%HbS5%ALs`H%?*zXNaDx_kU}7҃h?ݗ/f߭{Ufj!IG_/__׿׍#AOSŜ@V4 V?ye /K/~E7[:wVOn+uv|aoow|%(\l {Gn=;6?y\_/׿j5SDJ4~HI 7/鵝;hk>}M-GA!RAio96(p<R|gL"DPp/`z|zzh)BU)x<V)5{)Q zT Jn~~%IDBHVa"S Rf~ ׼au..d7 b2e3\>Q^d;`!h >LjҼ>+sQg =w$/ ,||#-J D!RBi{x&:uRzXղ =&T 𲋁gUA"H{otHA "R B 3t";-H_\ݏ`@.lFyl_>:ShGe CϓJ nV/VY8q/Ewr$D*G!=aFsk܏D@8P~`,#bB|(n{$V5+yף_ɠ'3EvrT9H1xc&r]^CYHƇU쒮Hyј..d7`ۇf8P@-؁~|B|l}V~AN\OU27E`rhr2b O+hd!7/>|wnuM!;kC-†VC!#i!򴃶ac?5c#F2YnŌ}#枡ō$F,ZpNB8HӂӪVpjܬï͆[O%?><,ޭR vRqjlrXCmgAᶉ`70WzhQ.vdrH"b O+8.r&(}zŊS4mQ|zƯ0YxwD(?~?,<3m]7(7Wd0,%L-vj] xE/ӄ^좚/E&VzޒDٻо4-$!ATx}٦^]C'Y"=] IaƗj1'9NP q5&D'nGӈ1||UV$[u?Zx2mx\Ъߎ/CMjIr>HEL/C@cv(@Cpq ,\B.͟.! vߨm+D 1ZhGAJB !b5 2&yS '6DLgPo70$fתmkq)NP q?e%&Xl|9YbXD_nXė :bqB<.:$!$n:G膋+Vv2壆`ᐍNCHP-ǂC%?zB8*~ao3<@w 1(FG(_!Jt<cf6:FM"5nJAsl$dCqWC1}K'C)ACKG XTx. &R<<$dT@ޒA!")!R򴂖uO?֠z0i2"|^6. >̂0վV)$m8 tq~ оŶ0Z<_82H q1+(/ Wަ@TWI}96Si!㈇ٵ{q|9U%Y"?O"JNxp<-2 Poﴀ_K~HO@^sT[q?ZB&2\(3I+C)!RX/(}ޜj7>ͩ#噊R͛ՈC!"i^Yaa+wOc`k!z%_yR GX1"H 2\7v >ThƲѫj%o1vЮAK!w.?;Qr "-!Tа/]%R'ꎫm$ ` :E %+(5`Y0Be[:LjN2@~F-`At"-AZv6~pat+@CDhx<{Mp',yXD@9@Mҳo;"m `Ӄ9=m+EpYKDAɫ::JWyW|.jpl= Ad8c-VXB~0Z0^LǺO7R5SR9|Fj܈t5tj -G96}V/do'd,uvօY^onVEeXcҳx35*qœ;lwc,烯ywɋT缛un^g?( yۀLSZWeV,Ŝ5oѢ{|yK4ӭ!6ѢP'8- H~`1{P7VUUQFWMnb' !0NU BHӊӲrÙ,CpRiL*:4-dmBi< IG6 s6ې8mCRmfmƄۨig1t"?7D^M9G-}CBhԳgmfp2 -O;0_\%Ƴq o|Dlɂ.RD w-nAuB36=Pg^0Uj daRqe2zS1NZ b 2$ z\*F5}MzܪTU/7D&9=_*-P>;NB\=.NaSE/1|T΀@<(4 ~Js!vJo̠ZͫoD !Bi;g96W|ub9V:&| !/%ٞ& H~ܶa{}5VF VZ{[{O2%%>c+#ѯ^}k D!A i9pT+lC qF; 1l,V a-8,0b*qjxXe0NO jעdž9n@@0Tъ?5[Wd$@T@t:TX}ywz-Vr:zz&{Xz:o7UZQć!7"H8 %Cƍ=}$ȝJD* 5oQ%EVPw^8FO1evI'bX y`?%bnpYt̥\NՆ,h\=d:vF$˟@Ř@T<ȉNU񥞧]bz=<^-,s3~Ky'սl:r=e=KLuϨYXc8^ی `ȋ}KӰ$ì/17M[=%ikĦU> ?VujVGE`ohUѹhUUە'/FV䕧O/Fh}1JE_/FEߋVu~5UE>UzLO.+Ҟ[~Ik!^09XCJL@ir:d -O;Ҝ21f@RΥۍyCbkr>̦ лmj!!!DZ<8m6ɕ+1oaW"C%)nZHsq2?%n r!}a16FQ!Iš3cdi:@i!rQi&A-+%!"@i;\M@13z Cp}׷!\H6.X-,OwC2H b*6YԽ/r QncFt$2=YMt&QLP 2O+h&Q{b-,{Y ^u> <O ʍi\-@<-O8 rؽ L6|xH|2 |^6+`or'ַx5 y}YX-"} T VT?>a%souFӸ(2'APE guEHM%e9G}RDTQ r#oCXPU)攊p:!TR4bO~n Ӆ0!Ku#' |Όт уC!"iqjdĉN/ B*; uuJE )#j!ww߲kY\7ϯ8,>= 4vd WRn,wZ+jԨAVK`0[&\D"Lh39ڮYvkAy)9ETV0``08-H z@=zO+Ɲ{-)T Jv~']O=C;IK@ RA n'ʬ- ^- 'zqj$?V e5Xinl%#maQfױ 8RQ9"OS5g.E4!vkw c\絴h#8NB8H Hig#:H]#;>/{^('L&X[!䋃khk|kͫR#Ah1xuˬZx94bCF;tU2ѳō(L Kvcل$x7\e{ ~۵=.%ɡM2@sK+SD T noct72wf΁WATLU y#)^<%?@@%?Y U[r0ఄQЪ^:Ⱦqx#<_9Vw+wۯ8%/*nms\q*bug.:rW '-`]m=G <Ӹ šB{hnŰml`#/ iJtܭeU6a' %,$UnA&wURyŗlacNCҒral}O]tv@o8կSi$ړ oRS*!qbrױN;7 Qיh*pRFk .x%juC!#j';xNJUAGRZ=0>*P_e.ۅU~-: b 7`8YNVLIX!9PoP+#> be.: b w#*b) Z\x&CvA+' &$tE \7<1- @`@w W$Ox~-BBd^[% ݉Xmm'CҒTr3_Ř젷a įHm\ "(CZXFA/R":oξqa RHK 4 oyJ 7 q`%otKħ^ )#j!r@|hc^ˠ.+\0J?\miQ" :eB-AZv쁀\ƷuoBfH3@zEm[ۄ@%:VAk|<֝Y=øyGe ֒5hפ%)#j!r]+7Y3ےm}k$zVB']Kua: jB92H q;J̾~{ZBw'0x" $OkK AK qbwĝ(Y\ŠOƇ$/}Ol\592AZvl6#+&=ƣUyz͵*&P*82H qsR?0|ôͅ -d0KDG1}7pc i<A!RBnH2heYt ~[Kr jKƌw(B8Hݎ~ Y|_׷`T+9̎/A2@ΰZp%#ch';LdSj\I(}tꘄHJk=_syrQǁᲈHB$]ݥܮ>M:LK CW}:E*B>|sGYZ "Ww[pYcV,)^ L? &E$ar_$Nj8NԢ@%7#hVF.WdڛioD&Lr{o=&4[EoCSF ԂBӉM s|D7:DԔ ~g =a!萑iɎO_YcY zSO!ƉL|h-ZćF񭅌@E|kro̩]qj\x]DHW (*LqߐtmRϷb :EB%!ܬazc*@*஋=u1Ε 8T;  ߭nԵt: d*FmXlÇa ^,@AD:SKDTLt&D)@*FlU]iy/sF3D=$r0knK\ !DJhcZJnV;gX;g@r_lTxй$O r7ߵ)A!RAfRq7bw-on0mȑ{Ǒz KJzqhA'78[,7( -?ٱg ^K)@2qJ,llTik:K^Τ$ (E &N#vVQY,N" T\L.iF!C@xT!6JnĞ̘zd2l NGA9Tԥ ?2'8Z078(8e  h?|c5~OƪK[\z!6\j)*h+-וIP](oKF(ܞXXibC=Pe7Zp{68h6eB-b Zv6'lD={ X0N!΢{=G?C-PJA"9ܽ~LTc)p@:Jl!r'ؔA?u :e -!س֟%NE9IU탏cC\]A=;6(Id`κPκM}kVh7<ٟ݉}es^2 SFwz]t *Ȟ/-ωCD5ێL#܄  ˆ:2yh@$T Pqadg\+:uε'mrY!``zץiP.X- KO6yuh*2$8lZ"ܮE]yQ&LKtA+AsbYSߘ %Dvg3T“% C qc#dtCm n]|eﹴmat"%AJVɲqհH Z2 ê0-2:wҰ5ghڕ!MhaȓL @`@CDZ,c3, :,B"Jw+8jw8؃K#}: *>&wGҮdܼGA9.D  [/X"R$f,In$f(J7wPC@ T!HlUvcJs"ν8 ДQX؟llQl½C!#zZuS >.RSDa*QW,NS*!qCt%B|9?B?0' )~59<o |V-)D !BnZn7#;n.uHa $'Rh 3 )TPwjY_c>R0m'w@|3')pc@ PJiK6)"paKAkHCAO_$bWrx3 mUz@L SF Bnǿ|m\l6٥m?Hٶq96Xlݶ>|Hﱵ^D;!V}r<^#}8+v,D@8Hz!ѣ֪@Mk7u| g q\9sߏ_Jt^̦ jKED !Bn BeH%m =EځP ;#)4d$$u3SO6#3VD?0mu+񻭴i~*9t| pxV xAtZ#|`VR$rGMkYA;wĽwg(Ve!DZC=_ +EHqbO:Vb4$ҙ).s8 >^|lq At"-AZvl2lD⸛^INt[C-]q HFW8GB!rᜃn͡3 "pܑtB{>PA+@s dOJWo3ഘ6Cf]]b~B 'k~Z(@ B8H݊=ܼ ^J{A5lKY6%R zEz!萑19HݎmG\lyGBq34rb'Vz*A(B[ :|qr /j}>-uJwdrn^X$ȋ7sm@dJ:A[˞m `\aJ~voO^!̽/-ם>q2^=-C%ض~GCHBy"HH`[L2H/hu0`,;% nK݈}{lS!69/5E9tSk,c`A/cj/q1[`.YV40/x$L+.v̠h1PJ " "wp:Wk+8Ҿc`؎I/aPbp 1π bhG ~o@6GXåzʸF|>lިݎ 78\]W NFQ| ޸ Rη:BjFP\1i:9>7 -]1'˝Tfqsߨ'p%qy5$WPH b.Tj˳MP~Z ˓QI~KqqNAC/i +{gHLA~\wr#HʔYku& 3./HѓE싾x}wEgvW Kۍ[G~@y3MMD&6Q<_k?G8#p8rǐK(𹤬WiBX@ib< = yTǙxB(y %K :r\@T͟Kg1WoSPYTiD>w^􃇽[h3~ʛ0g*,].fi:<Q`W:nk)e+gB#XFS4?kqn<:A? HknTBW"{MC<ӈܯ7S>RwGf ץzZW.؅6 8 y<{QAfL"mE‘rqi1wau`ތ[ח/؊߈\׌eK}cKOh Ƃ רϗDW E ǻg0qłdhR՗SX影%GBr] =lA=^oj;imt϶zf Y[gZy˗pϘ|x/mFnKB߾jݜ?g͗7Y'.3_ ^5*ox=W^?l}S͑y{?}/?[!ik>k-'7/Ӭtà[G?><?hka-rTz,\>cƟUJC)[#C RqS7Nô\ѡx[]ͰDp^0xFdэÅOtr]ʻA^HD>p9BE9`P+e76 &8NP qJrm^.;se*: ASDZVQ>T2SD TBf H8m, yօg XL=8!@|5[Lw;!DZChY0o}p.\>r9wQÉS' &k5:Zt\ӏmd6_̶7)ov/LM1>G At"-U\ǧd)'Z{gC}N"> k4 & &T1"* }` -JCDA n93~)6@4ZȢj ,WU'ƅMp:D w# o,t!]e$%։ (W/vA(ja5 A@Dp Q6+×DuJ롻yIPHxMr@QP=T_ F At"-AZv6 ȋfhFcDDw"qE%-~Uiɿ[/E!1RT܍5=KN]csđbBGdOVIhwȠ2A @*T܍8Qы}lXD1,vf3-tGm"7qCRhQWL-T{!萑rWP%b ?tZ fXɭ/Ǖ@@~t5nK@wyJ! ?z;+%t1~F-[DY)H(9@TR Le圁<4l{җQ'-o_AiC=7إ@tH *hۀא)D==Z >̎@9bGUSjS . )H(n93F3bxg_H, w ?SLSnOgqn1VzK"y@z` :EB%b}@%w+v y-ه<v^՝қԅUaSCC!CC%w+a՟=gdkK:dB-AJnF;“9>O?lY9vr!#cq18޿Djq D@C0#e<ŲrxVRX&:-ła /-@dJ"@:Vl~=e9ѫ9~}r59} ЫrAtZI-w;p)1q`6mI׶U`I#BdGG8q8$-9bN:1R/mۄP3q)c6]!MHFm_[q8XGί#6X=G*_I]@ur:D w#Y<`X&w}PgP.lBJ%#Z`gwxbO3< ٬+;tf}h.{Zt/u ?b_CuT a185s2z`XG 'lѣۋvrdb l92b  -w;:S/(A!RBfv8aLrFgYL.+ȠVJh&۪<A n\ w$Z!vu]Kx-Q IZG`oi\[.oCHn b'2+9{e@f{ :e -w;8waj(6rf-j88NB8HAy`?鈐%#TTKh>+e1E IAt"-AZv^]pc:@'ԠzM SDX^J$!pXs7_Xr!t,|"2 F"h@pP=Z :eB-AZv,{2A<4<@5IW}Oy%x6"@~0jp3l"S)!Rr.7Gy8_%(_tֱyF6`MjҖWrh+ml;gRg :e -w;BN+nt# O<;1xH {$?NZ7SD AnڥՒS+*;BzRMI >zG4<֪7/A!TA n>0Q @qT"&|)JQ 4A!"N*Aqfy0ߎ~½@σO̒Od ܫU5OC!Ci- \n/0(QQ 8iZO9nTw+JN~ yew_[@w򃉆\RW|@|Ёmpэٸt?M:[!+׎ͱ@At"-AZvkfE7~E"fLleĥ\;M2|~F4BF4hsۈ ײ^ ^B :$b w8a&CV'L#ٺB:Ϲ_%஘k@tB@*n6Ь\5_"5X8RvZ ƛzy ?"@ז?J{/@ h5rJ oz-bGTcq -.9Ta)b?E݈}329wfs[Eu&"'{T:/^B;tB@ &lFv~K6r 3߽tB7xo:+\S@DZIgE1{Ux[L#ju3B 5 MPHvtR5H-CHڙ32S/b>{!R&3}?AZpfMיϱ w4\Gj`V-NBGV Zv'BCepoX-L1H1 :x(#}1Vt,vYB`xw~ sП50w C4A?j4öj""t>H7' rZ"H2w+1^sP ?XϽ\<2*q+h eiQWM@7gA\ dKS;TtJ ě{PR3hJs!ޮ?W&v@Ր"&bC;`/!$8n7ȅ=goe;{oT' vd=o&hݍcQg |sf )ۛAtZChxon%H;d{!b)>Gx֠*ciQ} KBDͭ'}lVpe`9$nN(Aڊ!;;X,)|U4&ҋ !҂fyf\X)8jYhK^o 䞡n "H $Gt qgEą5Ϩk-.̑n%9֞4 S]lS@ RB5y][/fՐ!= Ʋ ^;Ր س%ҋ !҂Bݎ-؁i| vĞQ5ÝK%]"$`(!k8-SCJnVp:l:L;iiDw b n !vKӳ'EB ԁ B݊}ɂݛe\L=c!bz%ˉ:,'\$bKHJĒEJVl%_JɊEAk/4KM#7\)4g4`Ţ`F)"ۢ(tܭRc2cȴy"k55>j2mh=21G&F@cj§IӪI&ۆ1g8 =N,v"+&fi19J,:hyZ4F-w;ycPw3^)VM~BH-r -zDA rbg.n(g 5q-7¹ <H+ϲg %@P:6+qf1ƣ@#/ڤXJ |AbkN5>n$CPB͊}錰tV =ƕ^MGYVgCAg9L ZQS-n.>#P]AaQ(!2tOֹ#""(@RRqEyO:)W7A/!3Д@yGYZ\29ܝpun_d 7Jw|^!rVntcWp'_dE]t *C[V|n@"sҗ}}Yo!B/ׅA#r+3'`rtܭ0im@"i~Յ!?ȴh512$JkQyU!(Y2wL8f_K2<BNܮ>McNg WU ˍwD[&FDn!dp-@t"%AJVl5otkm"QAۮO, Gl5Jh?/ Do*ɄNax`*sK$Zʝ#b (E|Ж,"SpaKֳQw#ݎlX^ طp":0^.ԁK^`.^p" w#` ~ #gBⷌ/}X] u7"@)vj`;dD_6l[Զ!-v s{r~luNQ:'Ȫ7\Ɋ}kH~L'c rG;u4Rqqb wU: ؝_&?R+v熟a оbeт!#h';¶!j <XdC5C|KDa^P98X 꺃UpARrb;0#t(@q!+3$޽6̛3Gɔ@@*UycpM3'YRЕA=,؃_-X&8NB8P͂͑ @M^՛B,ͱ,|;Nprqg-:B _ &!G\K :.7^ݠcLKdxMc #&RG : B8P̈́1ԛ 0"qEIm˥bwEHgHqx( )-`)TPwUVЇoui NpBhajQiL K݈/dzu_{|3~X5ЫG!!D:@$w;Rۓַ!br ==@*FloMv6],UT/{r(SiPs*Z2vpZ2 -?ٱ*-(":Tl{&y"p) ~wf;R/q)ZSp"Hq̳A}?ĽyoS|wU%l!%KR8:C/qoཿAt"-āJnF]x_y"?.<_o/XW̿hҽ.jGܲέD7.ܡ۵  7SK;xa\'m"ѥn8vQ'3Edr7cL6.~}cą7aہwt\ W@1p)\ѩ9H\gH ޽_ok$nv2oC57bz)C)% H)w&_nf_UpY;eqx?+4Z7u | MnzB̃?Xߧ 7bIY]I,"JXo8X9jіl?&;TA7}"\o$ͫ|[Ӑ'odYֵ)؈A7YG՚ص#ˏ1 A+r3*B q@H"FE|/&4Wg!#  Yː]x*v Xs*橿X%TRofJ?jx7]>m-V~Pi%/A׸1܆&OwP5 Z؛BmVqg H w$=C73Gꥃxmx.奣>dMx/uA3,|J G/>HsV|/ į~vdd0E Z'XC@E MޮFqȖDrFז'ssEE@|B>_l AA-3[7Hz؃91zX1{DoD;_Ƽ;Wc-?gNNNRj˭u0١hZ.|XN&`3$`~#ܶp>1Ԋ&*Ctߥ`!BqFfWou!nK{󼫈z. spG,Amjռ7.Nn6qGsͭWA}~^r?i.(ϴzC6Rhr/1_zF4}}GХw]?gl_m͗7af>zUlܽƻjU"v@=W^?lУv}Ƅj3=}=_~t/q|=:6 ݎ?7>b㦙:Xg4q?dYG|?j}}]q5GPLߓX5w~>ѿ~s2{_ҤGf~lldw=[_s𛁞~?x`-ףYhN~u}5zug?,?gO>2ϰx{ Ahw_iAxfZ[oU5ʦˌf;yLi_3Na<_z#u?x3K7[8pendstream endobj 425 0 obj << /Filter /FlateDecode /Length 2061 >> stream xYo׿>q՞^HMD@ڇhSQ];䒻e>K|fgF4aKrAŻsOrO?$Բaѽ–DR4$V\ܐoWB{I0KޮhB0ZRHR|Ɠ:%>ڼ()UdJPSVRqUۉN0 ~ "nU,.Wͯ@ô RZ$n߬֊K2AZG2ڬfz$j*%bmӀi6ZDb{R]9˳cqm^š="Ciñ?hrj-8'{$_T9cޫ.dA]#5h@&iX؀lDpدx x<[׼п k6PK oڢbyJEqj8kzKP2%e !Mv*|ZT"-K{/l`^~>dk'q-)OZҴch "pLArd K#|ź"/c4 "EM\aOC@'%amՌ.#vjmI׫ 7|&b)5hɇOQ.Q-Hk ig-ۣ'Jbzl41{3侙({q\ܠfU`'k(N24TH~h@AEÿd E8ŭR;֓gԳf>I{{ 2a>Hf:QǮsˠb=yDOun G}G(ւn59Ȉ)& vd-~qu | JDw~YDC!2KCE^XN9]*|lIMRƲ„\2%Ȣ((6)E#'e*iWmPMEމ3Tn6zz|)h`|9r)f.u%lMISl]?vqA Zi {l%XFیX32}j{On_>Xw}ܮVvr2zCգ1eͻ?d`GWu$yϮ<ۙ~v0cp 33~.>A.6ߎ=Bt5L*7WoNt 3Zd>crq_}=j<8̦g$ má[ O S"cA ӿJ9e*͘Vஐ  FՇhރB,Bg>ûf))a֧4 1Fq(+p1kfrc.D%L/z!: @h?^b(2"(ӹcy%pjl 䜯6]7\-I =ń[3^qh`;pz_{vWpFx޳)&'ͱ W-GӰ 1>MPj?c@op/`ֽLP\ 'PldhK@w:ga2 Az1'[N'/VqSH6nq2H-`7Û]hg=W>oJ#ؖnsOĭ?u W!x'k~7OMoff{puSGۍN7st0=m ^XWDJf.hj '܂2UL73MfKS1CkN]FkE|7 ߝ D 's Xw7Bԣ?-!Zendstream endobj 426 0 obj << /Filter /FlateDecode /Length 23873 >> stream x_Gr%ί0/|ˁsU ` 2 J?|8De/%QFe/ĉ??Od߯>>9|~]rk~%s~~lZ_}v_sW>,]/~vަy~1ݦm9{ϻ7/En~S~*0KGC_63˵ܽz÷?|qѼ]tGgNy޶ys'~cy;.tkuLvo{xݳv_~c/ϖ}[cnm۞}6~1ݕo]jEkvizksٵq[sWlm9]6.W&9o2$=X!E@2$oCes- 5I۾_c:|s ~]:˻.i~Umd-IV{,CүLw#8WumqщuA3Uh^nIo1iA*Ynms.]b{&m@nL7ۻnƊJ7tlZdiguK)[7ٛ$klkm[m]o_G3?mQoJ.{WEَT**^&VSN\uޚ[v"5W-1Rۧyj~Dm3ߏl|:-dg٬$'zdG|{1׭m~MFGqOrۧLmOY |[\ Ɗ2r]mZSz>[_ ,*}D1-94_+7G! +AczܞM&T#,1`^= 870n ecT=FxR03G`/~nCZN+j:h {F.4Y{=g>Wo[M)]V+, w_~o ˥s\S~9%&xof%(#3XF{{`mofĪͶ^V߿^o,^{XO11oa^Fw]ǹܽ~g-f?EBnҸ-S}.(5ĽiK#Ey]9nڅ^`f =fGoxmΛU$-‰Kz%=B4o.֚[`ҭki7u{1np\Y0͋έrX=_ά?Wϫ~j:m =/f|<>oG[mx̶ٴEyoas`M+(ip,lxٮ *5_YvLY1f1@[{XE9y& D5[dȑՋ`Z{?r~f!n"?3@O-Br3 B}`Tz7ْ[rv$M>7XOlN?=QL ?2.֞kvkMu ޭ海ܒH @a"?-Ks Qa-yQՋGG6k[0IfsUcY<6X/, lI^ /dA $BZǾf֞#|[{&PNI̅|[Qaƃ /'ߤAD~Z[39|i)E9& 0n#ֶ1HÆo K"T?oBݑP]ɮ:41Aevh?+P& K"T?LlW|1V33/XB F "6r,bs.g7j7M`;Xz7HES#6je:G8w6<XP,P(I Pa7H0 06"D5ȒՏ[ # UAvS3iTVA a,AD~-ur&a@ݷͦjd4\,M$6t$^NI,P( T!1&(̤B`YА RdʆFbA n9a_|[)aN9mFpj0%AXN$mj7÷>o&Io6"{/_\*wmm=41, B cN@6lW5Տ|dBH|.@+]&5Ȝ*s6N d! Bi2%Ls,v#M&3iPL9$0mDLo T?ܷsEv|$[G櫐f[$Nlva;xzngI2N`ܬנ XHCPن96dkep5h8T&gG1#^NICP( @eO1 1j8T @B@/5ȒՏ'S!#QNn$\dF 2'JBNɆ.xd[L((ύ 1!ʜPBtlhBA,AD~ $gBBf瘔y)f{A46T0ˆ| j%ŷXi eDBRI̅$b|-M&&yyu8kmR@&Zl-j6PŶrFZl#.Ҹ:QkVn$eTSrD 5"I"ȆVnĂdIfۜ:t%6m1 ^>6>2t4@oLxٮ j5ųH)azKT 2I̅r$!Li#dxTZ;l\lP٬3=g66iQCPplcY1XXe5M˿*G!1A^ώy6K.ϙzղE9<x @a"yvLcm^% ^NI Px"=ڨTg6xIc,^5Ňꖆ2p BPThVCiH0EL=0jRfȬm<6^4uYݬ6eu1Xg!qbD qA b E,%lP1O/*XtH|̇')5ų!FT=H^Ro( hBQ@^g( ⚞⢞D$kB@ܣ Fq9zQkjf{lfjfT`#" !&=ZP`*3O=6%-$m{>lmgn`R>' ;+UVCh?-,=B?{+M2р*H|yyD ׈5$ڈUA?GAsEn!kQGUV W=#T,=zמۣ׎G24H{lC;deYΈ./Ia[|$T[IAV@Ka+T GT/gӵDt.|/yI@?4g>K8+(Bq+$rrzܢ"Z IÝVhBa@@aIz]|7߶~X S~`.V>f?Q):Q7$@vS fp`Q r0/)HPpv;S( -ONom~HeaTV전M ,(Nd4a rA1!)iXP$>F2HP](NE낀ml:4AD`9%lD`롍h_dA $@qT.P8l0Vk!EquPqU2. ƫ/˧@Ir]x൅}ދnǯ-{u;~~Ӵ끣~A '>c3O<x;9vlk-To!4CaVX8qӇZkX#'lP4Z/{x~x>=ckQ@y;zTzG!+|NuF߷8dM"num޿Y|ׇZ-G}l):فvmY4nHl3niuW؉9Ug!YqvT`&XpS|Vǵ#~Y=$/7l~M[FcӓMciqc,~|J7ܞɥ]‹?0ٛXvxq}nډ-&X.EV%=z}SYe*g ͎%gxY8Ms;$?.4 &lެYؙ ,)K53ӱ׎ ʖdOŭ$vVΒo~mv _@;Hfj&8'1EzVsi5˕3V5#לg E:سR6JyZǂ+.RdO&٣_̸Nڲȼ^nKvW)? V^ywrv9"^։Of ?[~zG-MWMXOZ;l.U6lTFlUmm>헇%hmp)f p mqCs\gfmlI!`=#La ʌTC0&2l-fh!:&x^hW}έ(֟]iD<܃Z{MZ8no޽3m ;&ޏ끭=B-6Zr*vL*v@$?~no>A]l6Ե頮6Mx/$^)^kS&^cHc,$6(g1iv8(~[Ȏӡ<X$3"9mcd!ɛQ}iI2T?k 4`F 2'8) $~@ Ya j%7m*iȮvr4\,sELx7joQCPx2M[C2v\ eV[EL N:IƆ a[5Ջf%ĵP1-3iPtk!ԶLp[HDqlF6K[VQ ⰐܲnSzd('ǤAD^gb4'?#?{%U^Z{*Ų7DuBPyذ+(Gvݞlxٮ j%ۉs:BtDlו_vq-IcG@1*^x9.cAʞ9g&^Y Y¨Oy5.MibG{99% =ܫk(JB\aխ$Waam|#XV C6SF R(ŐۇˉK-vaH@' ( {.RHr&#"4׫Ȉ( h"""8( !beKk|E(꣞sO~y9E */OIlC&a|+%lY Wq ,Ȃ( Fu`J.FL^o8$*n UP̸XW/DEL/%*-j6gQoHu]I1!̭I|TJ69XPCP(i7m,BfYvZ1 Aelv ,66XP,P5$[8-n٨U;[1GDP%f!`lhXH,Ppl͕=(ᴅ/1sw-9-)sހrL|ħ. Ws$xd`%&@87 n\<0Z>0z>PvIO)D,}l2v+,#"AAAD"T1$ef{b& '.Jr\4ADNtV8-Ձ[b& '.q~VV\giADNǴ)?$^s/ڕ/fp@;%qoܒADN<6Z m,ic|+9vhv-K8`= ׿M 1)QO lWid uH"/n#m·%{~~vT&螢 eC}% b2ONm4z|rc4yCJ pyWBgl3{[Ns︱s;nv96UIlHM9 ygyϓH&TfG+ Iu q=/FDY, IUrՇvc]Ĥ,kYH,}dBb࿋ Bq+AZȪdE&1 hA=(\(n=QM%|^Ո e`‡_J}p8ճGbQH|QCvcI2I @ Y"q89v?ifWGטn%1kfm4&vYԼ>)1i+j4űTI1Q9dT4PԠ t9L2A(PP(E ۾*6n `& '.; `4A >ʼnXtcD/tnLN\^Lp9{1G/]b$XֽZVuAV.p50-QCPpckp/ gѣ>0[l Oב4ͪG }H|t.eC{xd|M)`[ Qf+;hr+El*6Ȃv5HՉX(aOTuT20 $A_DUYPCPpߎ˽%Ζ{^rev{ĤazR3ImDF K"T?o)BRw"$Q̉bdH†)Hu}BkAo :g^^;yҸs($)H4$U$kGl9y%X%4c{\ !F^:aZd-4]Pa螶miZg5V|}*s\,|  㲡sYQ|ӹ!eWgC4\,$?ʆΆ i7ѐ@*Q̅2`$)4eCcQY$x/A3Y`"j<MT%&۞ޟ0gz;BeMeI(!\Lp.K;)Dq,&@1= @-j6P)$0G@C .Ҹ:Q|DT)+i5X|D#@!GDb {hKae(}6Wtݓ[!Q0 I b E,fC<7D8yI2g%D0- ' *#l'"K>aWzy;>% D`P Ar$@x3`PNjL 4[,k!$>dC$A@_\k1R%Bv9g1<+^<b$&@Tn#gbRo}`@@A^RBt.h$ĸT!) 0݅HR`I&U%(oLy;5M>sLؽ.cT]SjkT/),I0 *ϘT %h!&ȁHE )Dr=/Ť B)UjK5)"kV l73|#FO9ѡq+BPYs"F<5sK"T?o>Po^ξQ̉2e} ?e߼}YQ|K$5~fs! uH@PKΚT?o(QcojL }U_V9U_[mD{# f=?jNwD},xשB$A:nURk$=^C,~t9;h4 +i\x(xIp:xzM$! r$Bxh+u,8Cu'x.Ej\匏(IpDpL9zYs)aWAW諯߼q2B)( {Z"'wξxau#c+IF[^]&{(eXmJK?$*# GL0 T GT/gJBdBEAAK -H B0hB)8HPό1$L_lqǩ'B6R)kcp9zD<:$>.*4qxI2GI2Q}ܬ ρu*5Y7ĕ$%xy@bly+L. [ @Ed!A/dBHHPgm}ڻb^Y'/)szy_;89u| T6 QH [Z2e$.qNfox\.ib,:nzDtf2lp0ۇpYHCPx:1JˍS0*Q"xj: &WAH{foViDH|bԎe=8X)N\9Ls- !M0D L ŭH1]f$E &@-rQ0^g=,ńYBb(^ oյwJa,Tk5 9mkd_y÷qfRLM<&pf=K~ik'5Ic9tl9$cr&|&lpz'XPCP(ECjGZI̅r4J҈MI&"/N" F F BVkD$`A4ȑՋ^NZ Tz z9A̤B`/_- l`A $B}Cʥ J!EqN<|v(-: jXbP42wnO i T'cP$L2h72# 3^ "!i41mJoJW%y%fp`$]Sq vADNԪEF=ԔK@U#!`\{ď ˫/ܛ+y3jV2'w$܌0w# j%ŷAB 0`7 `& 0A Q rX Q'* T f s")q6Ig6&a8~8Gm+S%o~QIz :>o$l?CȖ4$ź<$~Y$4#Z[1s KgA;RŲ50-=ӽ ƛ/m^ak'E宖.o?Snn}K6/^1٠o?ȹȣdzͯ9v끺>l>$'/G[dģ.9mfHvk^8Uȑ/Iujp7x笳xp_ֲS3SLC1wg7 -&A_Rncj> 6Gb :BA*zH/nbBNex2Cgz _RTD-e5Wvtp Fa? ]i=>?ң'ȫo^/K_rtS#tghNۇ̎bt]RK;^>׃V{c߭5;23eV?ٻ_5Rޏ*a&#+*8P$ysX'ǝ%NB `>ߚU:kX؏9ˇe' Њ8PAP3zŊ%'*a6K -cI $>OD, Ջ}f1{38&̨gF9y. qܹ8P P(^4Ij`Y{B[Ɉf0{A b S) 66&`#vF.Qu,kg$(l| *#=6>+}%,^D Ų;;L^_ [v[6Ze2>_ JXXxQŷ\hʥ57 Ae.Q¥3"pi6b,B~tgHN23<ŋ.gkO ?3, Ϡ@ R$Buck^lطgHtqLSb)$/Iط$$o T?oGO|xHޓ__-꼝096烛|IO_.~'A^]](n~v r7~ H @en% @ r$@xK Ժ]X778rpėl7wQՅ$a b TX&&7ȂZ8PCPpϖugI2֡{5fq,s,Pc0YHe6 HP PpA8'I΁a{:f0qb۬WG qNH@y  K"T?o<[$$~4H!ag3j9X!A <]$XP,P(ŶOIiI̤B`Y>%M!`SlhۧXP,Pplu>%L׏>y[5'P|?$+J}NӁIDzu԰/rW0C"(P yuuj1&s|%#E &) yę!8,ʸJ$S=Q>֒ܒH @ee'"{|%9zQ<ӑ!m neU'⊗4[,$Y ܠ0w(] j5űS´Ja6% F 'J%aZN=YP,P(HՐBʼn3UŌdNyiL5@#ST o T?FL1J8"(Z41Ae$XkFȂdI휶<6I0d;^l/ߒ3[==MY{")0#% j7ŷ$0 Uab.a#& 0H(A„l(5ȒՏx.TL_̨ADP$HԅD^65ȒՏ[JeXrvc!̤B`Y `VX 5ȒW94C=bܲGX=cl7Y#ecB"pB1! i7ŷ'!IqXrt9N:<q')a$l89X(N7d#5I0Rm@LEC5(jXP-$|@Li&ߨ!@~b$جBTnfBfs!.!*Bn~xQ[(9o๥>M}D}F%`>pwzn5s6x"X& `#=7s#o>G-7v?h74\*sk|M[C5 7-LJWV囖5 Tz$XNeC bA $Brx5Ȝ,G r}?o9Pr_S3iTV,D%WZP,9d[˷⎩QO,G- nW>D1I{x'11!a<<b119Ys,GQ$X(%ŷK$a,9en70X#F"0RF%ǽ,Px2-VB IDBRI̅2$J$Z j%:Ʃ9٠}\cN٢ǰQhcP,G>) A"0['ɂ Ǔ-ݒzfM}7I̅nƞgow7j"T?sӎIC"2"f s"-#`Ӈ|OLpˈ8wRՉXl_IHK-cRH|=6bYHCP20gd VHjHLi#dA BW)EsG5s_]j86VEڇ5yЪHPP\H^;o`4i4u O݇\@X\l~H8Vjdu rsӈ6rjcAm 6R@P_<Հ29z4l)*X!$AHCxQ|!Dvڍd& 0. eCłdIǓynt/ z:.=I̅r,Sw!`a^6t/ K"T?ܷxwMkyMrxG(3{D$$|J~'?^^=(^E wDH@ЊxJb .`0ADN"YP#ؑv(+[I+ T+@EM" DuL8%K9rL85@(j&{˱7S{SADNc6ޱ7$PqEd{NyR~r\J.u-]6"% e`,5;4Fye6;#Ɩ^@2@e9F ii# yy}q!{~GGNgE?Id',ɆH vيYi+ ^)HZ.;m+yu!`V6V,AD~o#;Kε?1^b.Yێ*TF)W A4RՏ~%ԭ|Ԯ||sIQlܭ0+ j7UI|i }lt|r8ѿ%a˄E.$XE_dZ ,Ck_E,0*BU(fs DI]H<  e䀬5V'cݴ\rwS MWD|7$4qwya #'!I2znw)6> e~'9!4$wa}uYQ}cJhް˔8Q̉23$<9l(+ i77f!6|7|cVQ̉2֐xZ &dIGMDŽ_n*^~]#fs!WWd/_ ߨ!@~u$FoʬN+bq/džĿ-0 j#?t+PK[s\j_ [[ǒ4D`seI0&'5ŋ:$~ `5ul% &(aul0M$AD^ϔPinEL`.#rIW'1;-Iv[b#նr*q/>'ѫI>i+FB G-=4Jxˁfs!u"Є9"/Ncշt~jɲ9Ul_盓gAe4$(@ 3kNd4Lc, r F4*k1  ҂4/Cq11nM5QȚqlhd-IT'ʇ%87@goOam?GaDo,!rkOHwIR&*Gm@T Xv;)IbJO?d'Ƕl*<%ع7>Qq6$Xpò'к`)yH8}j%Zm%edk%ʘ/|TC >iDmDZ!ό޿2c䏑.t'tN By|+:}u3>Fj[1R1s#>G,]vtG#}tj] \1=7v|8PWöq$@6fGלLxgA ]M)=cɩm:`"Th8g©.iOBɄé gWeuszV5p/mQt#QNJxB`Mu3֒ /% $@q:q'J$x!l| c| zlqjl}f忋6.Wq %30a E si8:`Vݘ!3j9TּNH|ZF 5tbfC2&zlAC|I0zHFRpϋfg|s$/ ^ah}<6@4BPK`iHX: -.5ȒՏ&%tP1]/3j9Xք~H|:' i7OZK 6X!ZYr(4|!,kB,6"hKbIWW[:< 3e)*4P)Ix?xgQՅVt֒޶mF_ Ju5WS¾i@]PSg\(nEW-Ih[lK -=5ӄ:jqXGW(I?ܿ`Y\$!` Mh8P Px-̶*iqH|p/oW<;r x9 R$B@. ʊ 6"bQcP%꓀9̨AD`9z5I'}mDF)+b2-J'H'Qn7eZ`& 0ˑiQ<̣h#2-H`G-2-I'|Ki5Ȝ*+ӢyGFdZdrR+ŏGP'Ӣ %ZSiuQvӪ I̅rHE"pх6bY,nCޭͲ,Y,yRV$"T?C:J4.oiLS,t$mf`#ׁEs\.~RL [2ȐɌ`.#C .<`֍HY{CilgL6v &-͋lޘاqX)`Ӈ.\1(NR "$hQeFH[ǛW11O 'bR‰1ߣt8ʚD>Mhޟ;)Dq,%(154+j5a$%hq6IPPqwHuqe?G}{wo}N@GqKgu~wiAHDuL$kXv[5@(;Z^Ύ&i4OıZcmMvaL7Tkkp@Q+k`YLcL& E"T'c1"*'h7LN\,r"BrRɀDHhc4vҌQU,rarȀeDH;6שF ?3\X8Z,k~ڈ YHCPCGo7j9Tcw|*ύ,ғӊ=?o1% 柈)ڍ,2 e`I'!`~J64% K"T?o1>+T_4>S eB+!`%5Տ6Dהv_֥q!,GM ;\"CɂdIG-lc-M=I̅rmko[tn G-HJ7-HF 2'ˑBR i#rHYQ|WcT|VvX1 Ae|5$@o† ~56XP,Px2u1ǒKJa7`& 0Pi#FdA $B}㔗P¬hUelju3%:Q5+D`9JUYmD^B K"T?o)WDU& )W3iX\Yd@P& )W i{~<E<7E <%|nS!K(a$ #mD,! ET4*~bXNUðSd& 01uL ~S2cq{=BjkEH|c6Nhk5X݈2VHB YQ|ӔBr tPDqI "OSg!g%DD G"T/gH%4i3ij6INMH|l"]dCXzQ<$YeL#4[,+Gˆrd9zD<( B@h5b#yIb$nB'IWW[WKi3jH euՒ:bPWMT GT/gZX{ҴuAjx$G{yN'9=[Ue =CG"p`I1$ i7շxj7>OQ̉r<6Jx׉BȂdIG-5JT4\,Gcm-ѷhm G}nZ^ / g51 T$XdCkbA $B>ȉ)aJƔ-b>7jH)aNK漴I1YP,P(ŔxH|Bݘ'3iT攸$&eCSbA $B}|&0s>1;.e7q^x;}ʩ#37OǷ(aDԿ7o` ԿAމߎ4ȒՏ[,e"tǰP{ ujTR$X*dCKbA $B}e2̦d{uvNh{uvْ`,i#dA @Q|$+>D+@/ 5Ȝ*%+>B+@Ăo4wL ~a؍c2AeM~aڈcxcQ|K%은 v#3j9TV woѿ7j7{VXʕ%A{Ai#3gkD9i eʒ 2aP, K"T?oIїP1:]ČdN5~ m,!@~<s{y:;{y"F '|//V֝LC8?>o\bjdM+~{Ny\#86AݽoNj͚]-/#v,74VܟJu Y'~7{z7wzM狯m&ڐaَN?Jc=vM'g'kֻq;EZm1O/^i_弮mvhg.y}Ɗgw>Y~x_~!twq5?W/Zok~ b:nf]kQ?$w?kw#ݛ\ֻyay+ DݸjݟFm//X޾u] ?d{.#_~vo+մz_vKOZӅߛuW]>{QPn-Fkm㛐E}Ch[sː_u׫vo{@pZCL^z [kշ|߇ʫw߾n?Fv ;Zܮ:{ܢ krֈ?F߽WvV? [p9.^@}C*_d]x75Z\/m{^?ӷxo?׈]^Zb_~ym{[)W?G7Gz3w@wM|go~ 9GU/_x=OJ1(-߼xzл޽=߼?`+1wԳ~?~ M[;E.pv^wXobcQaj:? PgBp!12M^^e1Jۈ*Vױj/ʌ r6kgm60a&H/;kGc}es{;pq\sFSkVSe({;5!ވX+{L{;|/ν6ٺ\ǽGrфzfxtS3?5՛VT> stream xYY~ߐ@>,2 '0%J35ɕ9SNq>c~g)g>β~󌚷s8j9ߤ:t:gL"\rwz) \Y~)քDyx[F0<Fcȃ# P+n䊿ի`ӇmӵiemV4M6p/& iK/DF[ZMvC s'?bV@h ǐ<%!Ȩt* 6$+A0i!drp2'Q1>ln*mjnx* 㥖X5L2J}J=WջK.͸:FGiBq2Tw(bc^D1),RY"NB!Iȍ ,c?ʲܚrm60#B7rz^@ 2fnί,'ɥrjT]1Z<=9Lsk}v&iaD!uo~gpzw^_ <pQ{mvAևm'+O&uӔ(U[**8'^ '4=7ܐcL c4~U+wчē\! l g\1Pi-BǮ)(gTaܺvuȝкU 9aTӤ-u,( Kʂp;!ݦK18ƨ9.l'9\nR*͡ jۤ8B`FHi2zpN hm1dVs&ނ4Șo9$F7lHYʰg"0"7ִb$(_7c\5_<#/f;BQ\HGm5Oϓʕ=ۏ2C-,B)yV`V͹TP6s=]mVI֮<pLE2<5Vo+#C۫jEFM U4Ḋ{$ XVy!BwX *VYr:MS|Y{u[Vw֭]wAV"ΊCJ[~#_>.^GDۭ99:$U{` ֌Q X2qi;#.a}LBk4@?zɀk5yl0dwOg lWu1Ƴ"$GM"5%Z|a ں"e`E 79œ/m}KwŖ,_1)CiK F;Upus(2C?Cȇ N"~R6tf 01g} T0]DT$?4 4}& Hݟi}XmO/~1M%L H-ۈ24ooG˳ݩlM/: h ]]ن5FQLtFG>Gfwf vO X=&'h'߮^ 2 >A&Gy00 (U& } 5$}Gz&`˫G?q:Ò+R1*ܯq_Yߵ|hg:< (s\)=q8e9tbY@H&1ɝObiP:` }|Gb" p$~N ×T&#OC뺎y;"*`~nVj3lF?<׃m ֠27s^8c/^ (b4(St q)?ȟNݶYo:S:>h\.TW·ų OisNq4/\ >BLf\[{}c~9 "u{HPV<R!ݨ362(endstream endobj 428 0 obj << /Filter /FlateDecode /Length 4057 >> stream x;Msqw}ˁv͇|c+֪뭔Ҿ,S| GH$I_C{f@I^\:fzz=3y?,?;{{&tMo:"+y^2=< v`qZgan,E-nvy[]ʼ*Y85{sk*#p?C~'GrcĿK]kc;=mTh#wI%{TUYi%ŏh{T&9kUEqJ3 JShwe *+OޜQyv` eQnML[֦r|y .: Ζ6t<ݭ`DZo3tp%GC-EsR9o C/hM 98[d6^̚Z9ܘ0[U5<*qg$pK@mp;Ua`p3/K Y%~8|]Y:-@)YZY)@pM,˝ՙe8ހhϚcusWp7@DlâʈF^k姊DlS,鏻J!+-&^j7K9N*UgsuU®hV F)$ 2Yk~)xHj>idnZhi!tZ#[ЂhzBpQsnqQoX$ D3zR\otX,nz;* U@BDV<LQ$&~~v֤ w•$Xؼ$7nI 6mù<2퍩;l)C4w^1A/DFR[-oc?<#-Pp9'^aWJgG#IV YZiE]_:Ci z~0uIDs&j'y]UzAkkn{;D$ N[ eJk4N_G`;T-#2WB^<vN +(Tο﷣tߦXSzmENbߺ+o`-؇@Ob4KFj2m׈BAJ(Şq1aM@R0ׄ@Z@efD;2 bHXוA2X=-t| 򺡞}nknCG!fzi7irA^^*עD7땨Lg}syJ;*5p8'ףMec^bL# кZ `T!q."',p>H%}\~F ⳆSbZ$('  w6 ^& K;~j: /Dtˀ[gC@)*BeFˡe1֊v; Nơڔ+p4bJǫmDkAֲ'lHx: \PCBQ&~wy3W"F D)Z rBWɨ>~.@+%$ W.뗅eus\W&+ڥ.?noxێ-ݾFR\NjBOйOϟGq{á{KW]<$Էa񟶫$eKX#J½Kf-uE旃YvXDn!fi0/8V] rc I-唆O4'q8֎UV= ~5Sea/"N !g ;g5R)N‚p܇țGOC?\'u7W,|W:qV6?@0RVP}HWME F&wt%rWR%ZSټe;0*"~<~ǩsVeZE܇c9S~J!v2ˁGThl$3 :!ǪRJ PZHajK8xs"âܚYRU "dm"ڕ,!jv[Z&/ր-!K R>{m(58yT5܃צ3ς'#7k1C-vQ>F܃e F-\X Cw^lrOo'_\ ^/m$K=W#mj.\Β T(X$uZw//AA.qI@2B"S'd`rZ4:NYĚ/ @>\v˒ {WԨ\~BmDr˼6$/m PM=C`_TЇ05|Bj8-zvBBj"zQ$|C݆Fqp!޶W0s;ͽ5bǺL:Sq},4CAher{R'1!7ЄCs/ CRd5fb |{Ók*Xǹ00;Vﻙʴ@ۘ2*;W6c;gD3eCT* IIe5ȤLJOV}( hYV`J@ۏ/[Pe9xGI Te7**״ԗFm@]V-'* gCa7{p=n/u= 1*]ߦ(7\[`2Lnp?1Sx# 'I׫{9!RDe w)q8y wƑ,NN8#,bZ ,RҼ #EhwRf+VJs8laɲc^4O7eTVT%i\q'o jsFa)M^| x^Upu@aFEZ@ yã2YS q~tа 9$e~J\OoO3k 6{i|0j`]vůe}_OoS{j3S4ı] fup;?!WE'a=WٝŚƯ7$t;kV9H{r\)Z/&0Or2m-fߧ3nA9YGETH`ܔRWiZ1\F[5 n/ ;+snw oaLeJ{7}Y@Ntٱ;%o0F %Gði4 +47bt~ o3s9%tr5!SUK|Z-:at"Mzc26A)`AOh@x\~O6شӤF` d%Yu0W3)tZ"W'vOpDhje.Kl{$&J> stream xYݏcoXC/!) Խݵ7:֞-Eʲ7؇1,Ŀf(w Z~fՏ[ [Z~ ]2 Qڥ\.7ybpAn*RrMKKj9!{ZcFR7K?,%٬ ~pIڮ8i9( )m;|Oƅo¬,Es6 ja.\F)l"+fR1CVkh74S +5=vUvY^b~h6w ì%v7dhܪ`Qd¢Fg]柸TJAndX Jw.өs4fsUa"-uI:]:,ldjlJO+2ZmQvW[<i/RZH  tî+PN Zp)k ),ޮ l[ $*%I ̗A(PQtnW{8sɐm]yGfJ/ jxGn_ n]vя;oOB$.;*=UO>Ejx2N9*e~4P2JrUҀc.)3T]%KRU񨟗 cPKk5n`{.4:= HAS`@4ҠZEF~ja`;(+'Gvʄp,8C hԤݥ(:.[#9'_5l1""#ܻ#Y 6cpSD!1J&E)\Ygf ePY%gHee=/clnt*ex P^ 2qg>x!-I(So6חE=9fr[VIeW_MҦ4>@OuTMVQFsEJynKڸoaO(FH~};.<)~;ruZҌ#]8uȹKWU P>ma+rٝ+aC-)+AbľXԄN]bVZjwUM~X5a]K˹5W4QXPԙoyMO٠:%2 y H}+oIC.sW4 S0I?&mo Y$(n$UJ߳; Yaf w8U ZOù.oRV\M9?I3LNܠMzS%H!-)l- GDz'lPg;c-uG{V=)A)U,#?"ϖ,@l,xp. }Ώĩu?IRQ8ۨ.4N]p$MLJ2DrwaX4.1[2FR_&nMAYNY$Lmc}+(lE܁d lp@RA,1gI!h`wExP<î}Rl^ߴ^-K:ﵔ/~H@*{Hxʣɨ{0Ր2^r#C^cEN*sM|;|K@BsM!Qd򊣼ݧ0endstream endobj 430 0 obj << /Filter /FlateDecode /Length 5815 >> stream x\nqCs9 IB@s@ȹz.)t=O^4_urHˁ ,YՇ:Wy~?gn3?;ϻo.?QuY.rHjw~k1?E9wc?}>1bH}|+mf?H1e\ Ҩwwrw;  =r\~8|~o.94H eRP}>,Zh>~@~,J>E6v%vuwsQx(y3C%u_ ]>vn@ !0WlPѠT:D)E(\2s᳂]-1\(Pà$Gk/"}Bi0r(<'JC h;%.\y:(F ^x@I¤6\i / b)DaREk@.QLuqPPI s!r\&n8wYnla9Báb_p(WQ JbDZ췬myX ̬qKsͯmYѯ6yj' Ս-5EjoUnrCh/PG*?SY|ݱ GQ^=(,euDe s)2DeVvcz&&B&f -ӦQ tfx,kYf1cvj lْٻ%: K70ͷ,Y5}or٫T ;祔JR/U!(W oTdRi/ܜVPcJ aPnv8.w׮1<>@ 9eecY8HEl >V/r؊$`kH"H [~3<Ȳ{>*fJ}3Ȍ204/+/Mc`-3s)VP3 L0!4(U(`1WE.'B(B}A{QxfBo@ahXȥ(i8`DK̅<;"Z*t\tP%F4EuPߙF,ȋ@eP`) 1@n J%J ܈RTEB x>R^N֊kBi=C(UR;ӾjX]XXy,tZ^l?l\G)#ڙx,-f-,,>2--ΛQX.0ñ|ae9 Pӎ٨e&c^j,X4\j7z瓔akPLrQJ\s- C_7UP>:Q*"pR$&w-dh):,̱IўȲwjZ8ׅ |׺ow_>~8EÓJ]6RGfQ!q߱e>j jC CH:xA.m(((ލ Bk`^"(/DR1M8ԩ@asQ8 uKv"\i:sLWA;Wq#fȯRKzD$ZM!ZI貨-!lzt G3SBVTt3hS"14MF@EӪw4-OI:4-X1N5=AR[O5=JW5S[/P#w];4!]^9EoD+A[9,"' E1$@/Fu1H#%]4H ;.c$]͂b7aYPG(#,Յ@[u3ܦ\#]{Q:/=(,dqu uR_v4-k:Fx7ţ1qPIY"ԃߩ+ S§5O40MGS4/M'5L+մ4-YS״vMo#4h~t̶O3\xz+-@D+@HOWN d~ɵ۩\޾ʥ5ބr;ķGF)k@@}ZC7?? rq.OԠЛn>cDOS7(]= ܫ ڝSaNAI ,yP&pks &/a^X\{z8^[<({P:u}G|OJA PQ@PlI D' Z$76b3'28sPdc,T$FMF xLj1%3ƃ!F0d =+eA1S< "Tpp*3ե@RL h(h *4iک—-+]AP#Jj¨[)j±{*dkkG)U93}N:WrU.G,*i**€dHD78nE)U\3BQm ^Mk+J3"dVLj6Gڕbфj>w6A+J,_3CKPԣ ss-0s?lXG)L<U6MZM~MYMM.,X0b&hǬԒY/vqk,W[Y>5׳k4/P./E58+зhN Jw@lr-xErA{|}IP.(RHDO뿢1F Fcko4ĕrY G @G!Y--_!Yޕ\} E "&\ia:_ˍ-!5-y^ך?:Vj*"$ ɔF䚩2!D6xG[J -b7]4g@oZI Yxr$<FLk)r6P%W3}Ck.7s|[kŽj%5X1Ntw#X<2nNg~N$&~ /"J|Wu~@㡗7WưBwz^=^&zذ}~n$PzklӘw=>-\F1뇏fln_A `"Ā <&W9\yTzB 8v8u#3$ ?_P&9="l澺] >yg @4U6`OT)~"Few|LQh" ;.xb8?lVғ?*_6ߊd: j Wzbj/P~ɡJ~X O:TBkz|JUX˵/:乖ǗeSOzw18t~/[8o$ŭ!_}Ha+[x`ipendstream endobj 431 0 obj << /Filter /FlateDecode /Length 2532 >> stream xZm۸/Fv@-ڢ}vu_") _$R7Iae3<3ʇee"[Լ]?oEoRi\?,,2y\ E~,y-)Y"ͨddi&yN3Mv PWߗmf8gFᏏ Q:"̈́ 2/lNGiR {\Ak!IZl`\5%AK՚eS"]i %i6nWpK ̊\nhBZNI7 +V) 'R b>Dg~}QLBS%X H{s2+^Nd8\6#"UsK_-HjЌXS/jv[\Kk"#sCԤJ N03{q N^ Wz37ܛG`dx`[c]PX[V]⁌! wy >G"bًILILK%pF9Md*3"@6ej {C1_ Vit:pkUL~3J,Ru+uK[ei G0Gy>ΘD4e{2=y8DT1oal:]i=l~zUpCbs"MJt(Džhr|)7ƻJwY>H@/G9O{l?NPo[\TZB(7绮3CVʣRQЮ1a_!Dhmkeha0%\ĹRb2 {3>"d*XfKEG r">f?XWl-J0+U{q gm\, io\NX`yvxv|lgw|-hVzaHm֊Y_&Yd6~!w\Rxpkmh 3 7պS‰ `O-k6.ÛC:xB hIGw8 位/X0&pR\1+fƘHQ s`o(c 9*T,s\#rks3釀wg9TO!!)qWELW~@;ʻfXNޗnKC!?Y@|72Z}ϓٴ\u\ ee=Y.rl2k(q&Q0#JfK 85#pR@_޹-Cm]9x6vgaOYO +|m UNڃiP]9ړ*΄'Zk!AhuDj;n_v(Mڵ1Mgkzqko6hy'^dEQK 0|<`?G$OHc]hq>UE5RcNtoVy)9/X 8B3;_M#U2fyF{5"Y Z}9icibE۠ur )sV@ޝa`pؼJƟf>҄ȂV&NM4pmWjZ@1%[h_4R&"W\Fmp&~3]Lo}!hv> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 433 /ID [<1d3f125f1bceaffcbe7bf4eb2c7dc038>] >> stream x=KAEg6aMB6DA h֩b%6Xi)h#dB;+Sh!{Vf͛{g }5&ߍutGq/+!O{.!Ʉ Qˆc2Ue1-YJFϐUU1@ȉ^M̾2svO;&'"As/1e5 *.oKmX-&qt) N<ۚ K.18CPF##tnu|>:v& 8} ލϊsE̸<< endstream endobj startxref 388072 %%EOF partykit/inst/doc/mob.Rnw0000644000176200001440000024212114172230001015100 0ustar liggesusers\documentclass[nojss]{jss} \usepackage{amsmath,thumbpdf} \shortcites{mvtnorm} %% commands \newcommand{\ui}{\underline{i}} \newcommand{\oi}{\overline{\imath}} \newcommand{\argmin}{\operatorname{argmin}\displaylimits} \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} \newcommand{\class}[1]{`\texttt{#1}'} %% neet no \usepackage{Sweave} \SweaveOpts{engine=R, eps=FALSE, keep.source=TRUE} <>= suppressWarnings(RNGversion("3.5.2")) library("partykit") options(prompt = "R> ", continue = "+ ", digits = 4, useFancyQuotes = FALSE) @ %\VignetteIndexEntry{Parties, Models, Mobsters: A New Implementation of Model-Based Recursive Partitioning in R} %\VignetteDepends{AER,Formula,mlbench,sandwich,strucchange,survival,TH.data,vcd,psychotools,psychotree} %\VignetteKeywords{parametric models, object-orientation, recursive partitioning} %\VignettePackage{partykit} \author{Achim Zeileis\\Universit\"at Innsbruck \And Torsten Hothorn\\Universit\"at Z\"urich} \Plainauthor{Achim Zeileis, Torsten Hothorn} \title{Parties, Models, Mobsters: A New Implementation of Model-Based Recursive Partitioning in \proglang{R}} \Plaintitle{Parties, Models, Mobsters: A New Implementation of Model-Based Recursive Partitioning in R} \Shorttitle{Model-Based Recursive Partitioning in \proglang{R}} \Keywords{parametric models, object-orientation, recursive partitioning} \Abstract{ MOB is a generic algorithm for \underline{mo}del-\underline{b}ased recursive partitioning \citep{Zeileis+Hothorn+Hornik:2008}. Rather than fitting one global model to a dataset, it estimates local models on subsets of data that are ``learned'' by recursively partitioning. It proceeds in the following way: (1)~fit a parametric model to a data set, (2)~test for parameter instability over a set of partitioning variables, (3)~if there is some overall parameter instability, split the model with respect to the variable associated with the highest instability, (4)~repeat the procedure in each of the resulting subsamples. It is discussed how these steps of the conceptual algorithm are translated into computational tools in an object-oriented manner, allowing the user to plug in various types of parametric models. For representing the resulting trees, the \proglang{R} package \pkg{partykit} is employed and extended with generic infrastructure for recursive partitions where nodes are associated with statistical models. Compared to the previously available implementation in the \pkg{party} package, the new implementation supports more inference options, is easier to extend to new models, and provides more convenience features. } \Address{ Achim Zeileis \\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org} \\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} \\ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/}\\ } \begin{document} \section{Overview} To implement the model-based recursive partitioning (MOB) algorithm of \cite{Zeileis+Hothorn+Hornik:2008} in software, infrastructure for three aspects is required: (1)~statistical ``\emph{models}'', (2)~recursive ``\emph{party}''tions, and (3)~``\emph{mobsters}'' carrying out the MOB algorithm. Along with \cite{Zeileis+Hothorn+Hornik:2008}, an implementation of all three steps was provided in the \pkg{party} package \citep{party} for the \proglang{R} system for statistical computing \citep{R}. This provided one very flexible \code{mob()} function combining \pkg{party}'s \proglang{S}4 classes for representing trees with binary splits and the \proglang{S}4 model wrapper functions from \pkg{modeltools} \citep{modeltools}. However, while this supported many applications of interest, it was somewhat limited in several directions: (1)~The \proglang{S}4 wrappers for the models were somewhat cumbersome to set up. (2)~The tree infrastructure was originally designed for \code{ctree()} and somewhat too narrowly focused on it. (3)~Writing new ``mobster'' interfaces was not easy because of using unexported \proglang{S}4 classes. Hence, a leaner and more flexible interface (based on \proglang{S}3 classes) is now provided in \pkg{partykit} \citep{partykit}: (1)~New models are much easier to provide in a basic version and customization does not require setting up an additional \proglang{S}4 class-and-methods layer anymore. (2)~The trees are built on top of \pkg{partykit}'s flexible `\code{party}' objects, inheriting many useful methods and providing new ones dealing with the fitted models associated with the tree's nodes. (3)~New ``mobsters'' dedicated to specific models, e.g., \code{lmtree()} and \code{glmtree()} for MOBs of (generalized) linear models, are readily provided. The remainder of this vignette is organized as follows: Section~\ref{sec:algorithm} very briefly reviews the original MOB algorithm of \cite{Zeileis+Hothorn+Hornik:2008} and also highlights relevant subsequent work. Section~\ref{sec:implementation} introduces the new \code{mob()} function in \pkg{partykit} in detail, discussing how all steps of the MOB algorithm are implemented and which options for customization are available. For illustration logistic-regression-based recursive partitioning is applied to the Pima Indians diabetes data set from the UCI machine learning repository \citep{mlbench2}. Section~\ref{sec:illustration} and~\ref{sec:mobster} present further illustrative examples \citep[including replications from][]{Zeileis+Hothorn+Hornik:2008} before Section~\ref{sec:conclusion} provides some concluding remarks. \section{MOB: Model-based recursive partitioning} \label{sec:algorithm} First, the theory underling the MOB (model-based recursive partitioning) is briefly reviewed; a more detailed discussion is provided by \cite{Zeileis+Hothorn+Hornik:2008}. To fix notation, consider a parametric model $\mathcal{M}(Y, \theta)$ with (possibly vector-valued) observations $Y$ and a $k$-dimensional vector of parameters $\theta$. This model could be a (possibly multivariate) normal distribution for $Y$, a psychometric model for a matrix of responses $Y$, or some kind of regression model when $Y = (y, x)$ can be split up into a dependent variable $y$ and regressors $x$. An example for the latter could be a linear regression model $y = x^\top \theta$ or a generalized linear model (GLM) or a survival regression. Given $n$ observations $Y_i$ ($i = 1, \dots, n$) the model can be fitted by minimizing some objective function $\sum_{i = 1}^n \Psi(Y_i, \theta)$, e.g., a residual sum of squares or a negative log-likelihood leading to ordinary least squares (OLS) or maximum likelihood (ML) estimation, respectively. If a global model for all $n$ observations does not fit well and further covariates $Z_1, \dots, Z_\ell$ are available, it might be possible to partition the $n$ observations with respect to these variables and find a fitting local model in each cell of the partition. The MOB algorithm tries to find such a partition adaptively using a greedy forward search. The reasons for looking at such local models might be different for different types of models: First, the detection of interactions and nonlinearities in regression relationships might be of interest just like in standard classification and regression trees \citep[see e.g.,][]{Zeileis+Hothorn+Hornik:2008}. Additionally, however, this approach allows to add explanatory variables to models that otherwise do not have regressors or where the link between the regressors and the parameters of the model is inclear \citep[this idea is pursued by][]{Strobl+Wickelmaier+Zeileis:2011}. Finally, the model-based tree can be employed as a thorough diagnostic test of the parameter stability assumption (also termed measurement invariance in psychometrics). If the tree does not split at all, parameter stability (or measurement invariance) cannot be rejected while a tree with splits would indicate in which way the assumption is violated \citep[][employ this idea in psychometric item response theory models]{Strobl+Kopf+Zeileis:2015}. The basic idea is to grow a tee in which every node is associated with a model of type $\mathcal{M}$. To assess whether splitting of the node is necessary a fluctuation test for parameter instability is performed. If there is significant instability with respect to any of the partitioning variables $Z_j$, the node is splitted into $B$ locally optimal segments (the currenct version of the software has $B = 2$ as the default and as the only option for numeric/ordered variables) and then the procedure is repeated in each of the $B$ children. If no more significant instabilities can be found, the recursion stops. More precisely, the steps of the algorithm are % \begin{enumerate} \item Fit the model once to all observations in the current node. \item Assess whether the parameter estimates are stable with respect to every partitioning variable $Z_1, \dots, Z_\ell$. If there is some overall instability, select the variable $Z_j$ associated with the highest parameter instability, otherwise stop. \item Compute the split point(s) that locally optimize the objective function $\Psi$. \item Split the node into child nodes and repeat the procedure until some stopping criterion is met. \end{enumerate} % This conceptual framework is extremely flexible and allows to adapt it to various tasks by choosing particular models, tests, and methods in each of the steps: % \begin{enumerate} \item \emph{Model estimation:} The original MOB introduction \citep{Zeileis+Hothorn+Hornik:2008} discussed regression models: OLS regression, GLMs, and survival regression. Subsequently, \cite{Gruen+Kosmidis+Zeileis:2012} have also adapted MOB to beta regression for limited response variables. Furthermore, MOB provides a generic way of adding covariates to models that otherwise have no regressors: this can either serve as a check whether the model is indeed independent from regressors or leads to local models for subsets. Both views are of interest when employing MOB to detect parameter instabilities in psychometric models for item responses such as the Bradley-Terry or the Rasch model \citep[see][respectively]{Strobl+Wickelmaier+Zeileis:2011,Strobl+Kopf+Zeileis:2015}. \item \emph{Parameter instability tests:} To assess the stability of all model parameters across a certain partitioning variable, the general class of score-based fluctuation tests proposed by \cite{Zeileis+Hornik:2007} is employed. Based on the empirical score function observations (i.e., empirical estimating functions or contributions to the gradient), ordered with respect to the partitioning variable, the fluctuation or instability in the model's parameters can be tested. From this general framework the Andrews' sup\textit{LM} test is used for assessing numerical partitioning variables and a $\chi^2$ test for categorical partitioning variables (see \citealp{Zeileis:2005} and \citealp{Merkle+Zeileis:2013} for unifying views emphasizing regression and psychometric models, respectively). Furthermore, the test statistics for ordinal partitioning variables suggested by \cite{Merkle+Fan+Zeileis:2014} have been added as further options (but are not used by default as the simulation of $p$-values is computationally demanding). \item \emph{Partitioning:} As the objective function $\Psi$ is additive, it is easy to compute a single optimal split point (or cut point or break point). For each conceivable split, the model is estimated on the two resulting subsets and the resulting objective functions are summed. The split that optimizes this segmented objective function is then selected as the optimal split. For optimally splitting the data into $B > 2$ segments, the same idea can be used and a full grid search can be avoided by employing a dynamic programming algorithms \citep{Hawkins:2001,Bai+Perron:2003} but at the moment the latter is not implemented in the software. Optionally, however, categorical partitioning variables can be split into all of their categories (i.e., in that case $B$ is set to the number of levels without searching for optimal groupings). \item \emph{Pruning:} For determining the optimal size of the tree, one can either use a pre-pruning or post-pruning strategy. For the former, the algorithm stops when no significant parameter instabilities are detected in the current node (or when the node becomes too small). For the latter, one would first grow a large tree (subject only to a minimal node size requirement) and then prune back splits that did not improve the model, e.g., judging by information criteria such as AIC or BIC \citep[see e.g.,][]{Su+Wang+Fan:2004}. Currently, pre-pruning is used by default (via Bonferroni-corrected $p$-values from the score-based fluctuation tests) but AIC/BIC-based post-pruning is optionally available (especially for large data sets where traditional significance levels are not useful). \end{enumerate} % In the following it is discussed how most of the options above are embedded in a common computational framework using \proglang{R}'s facilities for model estimation and object orientation. \section[A new implementation in R]{A new implementation in \proglang{R}} \label{sec:implementation} This section introduces a new implementation of the general model-based recursive partitioning (MOB) algorithm in \proglang{R}. Along with \cite{Zeileis+Hothorn+Hornik:2008}, a function \code{mob()} had been introduced to the \pkg{party} package \citep{party} which continues to work but it turned out to be somewhat unflexible for certain applications/extensions. Hence, the \pkg{partykit} package \citep{partykit} provides a completely rewritten (and not backward compatible) implementation of a new \code{mob()} function along with convenience interfaces \code{lmtree()} and \code{glmtree()} for fitting linear model and generalized linear model trees, respectively. The function \code{mob()} itself is intended to be the workhorse function that can also be employed to quickly explore new models -- whereas \code{lmtree()} and \code{glmtree()} will be the typical user interfaces facilitating applications. The new \code{mob()} function has the following arguments: \begin{Code} mob(formula, data, subset, na.action, weights, offset, fit, control = mob_control(), ...) \end{Code} All arguments in the first line are standard for modeling functions in \proglang{R} with a \code{formula} interface. They are employed by \code{mob()} to do some data preprocessing (described in detail in Section~\ref{sec:formula}) before the \code{fit} function is used for parameter estimation on the preprocessed data. The \code{fit} function has to be set up in a certain way (described in detail in Section~\ref{sec:fit}) so that \code{mob()} can extract all information that is needed in the MOB algorithm for parameter instability tests (see Section~\ref{sec:sctest}) and partitioning/splitting (see Section~\ref{sec:split}), i.e., the estimated parameters, the associated objective function, and the score function contributions. A list of \code{control} options can be set up by the \code{mob_control()} function, including options for pruning (see Section~\ref{sec:prune}). Additional arguments \code{...} are passed on to the \code{fit} function. The result is an object of class `\code{modelparty}' inheriting from `\code{party}'. The \code{info} element of the overall `\code{party}' and the individual `\code{node}'s contain various informations about the models. Details are provided in Section~\ref{sec:object}. Finally, a wide range of standard (and some extra) methods are available for working with `\code{modelparty}' objects, e.g., for extracting information about the models, for visualization, computing predictions, etc. The standard set of methods is introduced in Section~\ref{sec:methods}. However, as will be discussed there, it may take some effort by the user to efficiently compute certain pieces of information. Hence, convenience interfaces such as \code{lmtree()} or \code{glmtree()} can alleviate these obstacles considerably, as illustrated in Section~\ref{sec:interface}. \subsection{Formula processing and data preparation} \label{sec:formula} The formula processing within \code{mob()} is essentially done in ``the usual way'', i.e., there is a \code{formula} and \code{data} and optionally further arguments such as \code{subset}, \code{na.action}, \code{weights}, and \code{offset}. These are processed into a \code{model.frame} from which the response and the covariates can be extracted and passed on to the actual \code{fit} function. As there are possibly three groups of variables (response, regressors, and partitioning variables), the \pkg{Formula} package \citep{Formula} is employed for processing these three parts. Thus, the formula can be of type \verb:y ~ x1 + ... + xk | z1 + ... + zl: where the variables on the left of the \code{|} specify the data $Y$ and the variables on the right specify the partitioning variables $Z_j$. As pointed out above, the $Y$ can often be split up into response (\code{y} in the example above) and regressors (\code{x1}, \dots, \code{xk} in the example above). If there are no regressors and just constant fits are employed, then the formula can be specified as \verb:y ~ 1 | z1 + ... + zl:. So far, this formula representation is really just a specification of groups of variables and does not imply anything about the type of model that is to be fitted to the data in the nodes of the tree. The \code{mob()} function does not know anything about the type of model and just passes (subsets of) the \code{y} and \code{x} variables on to the \code{fit} function. Only the partitioning variables \code{z} are used internally for the parameter instability tests (see Section~\ref{sec:sctest}). As different \code{fit} functions will require the data in different formats, \code{mob_control()} allows to set the \code{ytype} and \code{xtype}. The default is to assume that \code{y} is just a single column of the model frame that is extracted as a \code{ytype = "vector"}. Alternatively, it can be a \code{"data.frame"} of all response variables or a \code{"matrix"} set up via \code{model.matrix()}. The options \code{"data.frame"} and \code{"matrix"} are also available for \code{xtype} with the latter being the default. Note that if \code{"matrix"} is used, then transformations (e.g., logs, square roots etc.) and dummy/interaction codings are computed and turned into columns of a numeric matrix while for \code{"data.frame"} the original variables are preserved. By specifying the \code{ytype} and \code{xtype}, \code{mob()} is also provided with the information on how to correctly subset \code{y} and \code{x} when recursively partitioning data. In each step, only the subset of \code{y} and \code{x} pertaining to the current node of the tree is passed on to the \code{fit} function. Similarly, subsets of \code{weights} and \code{offset} are passed on (if specified). \subsubsection*{Illustration} For illustration, we employ the popular benchmark data set on diabetes among Pima Indian women that is provided by the UCI machine learning repository \citep{mlbench2} and available in the \pkg{mlbench} package \citep{mlbench}: % <>= data("PimaIndiansDiabetes", package = "mlbench") @ % Following \cite{Zeileis+Hothorn+Hornik:2008} we want to fit a model for \code{diabetes} employing the plasma glucose concentration \code{glucose} as a regressor. As the influence of the remaining variables on \code{diabetes} is less clear, their relationship should be learned by recursive partitioning. Thus, we employ the following formula: % <>= pid_formula <- diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age @ % Before passing this to \code{mob()}, a \code{fit} function is needed and a logistic regression function is set up in the following section. \subsection{Model fitting and parameter estimation} \label{sec:fit} The \code{mob()} function itself does not actually carry out any parameter estimation by itself, but assumes that one of the many \proglang{R} functions available for model estimation is supplied. However, to be able to carry out the steps of the MOB algorithm, \code{mob()} needs to able to extract certain pieces of information: especially the estimated parameters, the corresponding objective function, and associated score function contributions. Also, the interface of the fitting function clearly needs to be standardized so that \code{mob()} knows how to invoke the model estimation. Currently, two possible interfaces for the \code{fit} function can be employed: % \begin{enumerate} \item The \code{fit} function can take the following inputs \begin{Code} fit(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ..., estfun = FALSE, object = FALSE) \end{Code} where \code{y}, \code{x}, \code{weights}, \code{offset} are (the subset of) the preprocessed data. In \code{start} starting values for the parameter estimates may be supplied and \code{...} is passed on from the \code{mob()} function. The \code{fit} function then has to return an output list with the following elements: \begin{itemize} \item \code{coefficients}: Estimated parameters $\hat \theta$. \item \code{objfun}: Value of the minimized objective function $\sum_i \Psi(y_i, x_, \hat \theta)$. \item \code{estfun}: Empirical estimating functions (or score function contributions) $\Psi'(y_i, x_i, \hat \theta)$. Only needed if \code{estfun = TRUE}, otherwise optionally \code{NULL}. \item \code{object}: A model object for which further methods could be available (e.g., \code{predict()}, or \code{fitted()}, etc.). Only needed if \code{object = TRUE}, otherwise optionally \code{NULL}. \end{itemize} By making \code{estfun} and \code{object} optional, the fitting function might be able to save computation time by only optimizing the objective function but avoiding further computations (such as setting up covariance matrix, residuals, diagnostics, etc.). \item The \code{fit} function can also of a simpler interface with only the following inputs: \begin{Code} fit(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ...) \end{Code} The meaning of all arguments is the same as above. However, in this case \code{fit} needs to return a classed model object for which methods to \code{coef()}, \code{logLik()}, and \code{estfun()} \citep[see][and the \pkg{sandwich} package]{sandwich} are available for extracting the parameter estimates, the maximized log-likelihood, and associated empirical estimating functions (or score contributions), respectively. Internally, a function of type (1) is set up by \code{mob()} in case a function of type (2) is supplied. However, as pointed out above, a function of type (1) might be useful to save computation time. \end{enumerate} % In either case the \code{fit} function can, of course, choose to ignore any arguments that are not applicable, e.g., if the are no regressors \code{x} in the model or if starting values or not supported. The \code{fit} function of type (2) is typically convenient to quickly try out a new type of model in recursive partitioning. However, when writing a new \code{mob()} interface such as \code{lmtree()} or \code{glmtree()}, it will typically be better to use type (1). Similarly, employing supporting starting values in \code{fit} is then recommended to save computation time. \subsubsection*{Illustration} For recursively partitioning the \code{diabetes ~ glucose} relationship (as already set up in the previous section), we employ a logistic regression model. An interface of type (2) can be easily set up: % <>= logit <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { glm(y ~ 0 + x, family = binomial, start = start, ...) } @ % Thus, \code{y}, \code{x}, and the starting values are passed on to \code{glm()} which returns an object of class `\code{glm}' for which all required methods (\code{coef()}, \code{logLik()}, and \code{estfun()}) are available. Using this \code{fit} function and the \code{formula} already set up above the MOB algorithm can be easily applied to the \code{PimaIndiansDiabetes} data: % <>= pid_tree <- mob(pid_formula, data = PimaIndiansDiabetes, fit = logit) @ % The result is a logistic regression tree with three terminal nodes that can be easily visualized via \code{plot(pid_tree)} (see Figure~\ref{fig:pid_tree}) and printed: <>= pid_tree @ % The tree finds three groups of Pima Indian women: \begin{itemize} \item[\#2] Women with low body mass index that have on average a low risk of diabetes, however this increases clearly with glucose level. \item[\#4] Women with average and high body mass index, younger than 30 years, that have a higher avarage risk that also increases with glucose level. \item[\#5] Women with average and high body mass index, older than 30 years, that have a high avarage risk that increases only slowly with glucose level. \end{itemize} Note that the example above is used for illustration here and \code{glmtree()} is recommended over using \code{mob()} plus manually setting up a \code{logit()} function. The same tree structure can be found via: % <>= pid_tree2 <- glmtree(diabetes ~ glucose | pregnant + pressure + triceps + insulin + mass + pedigree + age, data = PimaIndiansDiabetes, family = binomial) @ % However, \code{glmtree()} is slightly faster as it avoids many unnecessary computations, see Section~\ref{sec:interface} for further details. \begin{figure}[p!] \centering \setkeys{Gin}{width=0.8\textwidth} <>= plot(pid_tree) @ \caption{\label{fig:pid_tree} Logistic-regression-based tree for the Pima Indians diabetes data. The plots in the leaves report the estimated regression coefficients.} \setkeys{Gin}{width=\textwidth} <>= plot(pid_tree2, tp_args = list(ylines = 1, margins = c(1.5, 1.5, 1.5, 2.5))) @ \caption{\label{fig:pid_tree2} Logistic-regression-based tree for the Pima Indians diabetes data. The plots in the leaves give spinograms for \code{diabetes} versus \code{glucose}.} \end{figure} Here, we only point out that \code{plot(pid_tree2)} produces a nicer visualization (see Figure~\ref{fig:pid_tree2}). As $y$ is \code{diabetes}, a binary variable, and $x$ is \code{glucose}, a numeric variable, a spinogram is chosen automatically for visualization (using the \pkg{vcd} package, \citealp{vcd}). The x-axis breaks in the spinogram are the five-point summary of \code{glucose} on the full data set. The fitted lines are the mean predicted probabilities in each group. \subsection{Testing for parameter instability} \label{sec:sctest} In each node of the tree, first the parametric model is fitted to all observations in that node (see Section~\ref{sec:fit}). Subsequently it is of interest to find out whether the model parameters are stable over each particular ordering implied by the partitioning variables $Z_j$ or whether splitting the sample with respect to one of the $Z_j$ might capture instabilities in the parameters and thus improve the fit. The tests used in this step belong to the class of generalized M-fluctuation tests \citep{Zeileis:2005,Zeileis+Hornik:2007}. Depending on the class of each of the partitioning variables in \code{z} different types of tests are chosen by \code{mob()}: \begin{enumerate} \item For numeric partitioning variables (of class `\code{numeric}' or `\code{integer}') the sup\textit{LM}~statistic is used which is the maximum over all single-split \textit{LM} statistics. Associated $p$-values can be obtained from a table of critical values \citep[based on][]{Hansen:1997} stored within the package. If there are ties in the partitioning variable, the sequence of \textit{LM} statistics (and hence their maximum) is not unique and hence the results by default may depend to some degree on the ordering of the observations. To explore this, the option \code{breakties = TRUE} can be set in \code{mob_control()} which breaks ties randomly. If there are are only few ties, the influence is often negligible. If there are many ties (say only a dozen unique values of the partitioning variable), then the variable may be better treated as an ordered factor (see below). \item For categorical partitioning variables (of class `\code{factor}'), a $\chi^2$~statistic is employed which captures the fluctuation within each of the categories of the partitioning variable. This is also an \textit{LM}-type test and is asymptotically equivalent to the corresponding likelihood ratio test. However, it is somewhat cheaper to compute the \textit{LM} statistic because the model just has to be fitted once in the current node and not separately for each category of each possible partitioning variable. See also \cite{Merkle+Fan+Zeileis:2014} for a more detailed discussion. \item For ordinal partitioning variables (of class `\code{ordered}' inheriting from `\code{factor}') the same $\chi^2$ as for the unordered categorical variables is used by default \citep[as suggested by][]{Zeileis+Hothorn+Hornik:2008}. Although this test is consistent for any parameter instabilities across ordered variables, it does not exploit the ordering information. Recently, \cite{Merkle+Fan+Zeileis:2014} proposed an adapted max\textit{LM} test for ordered variables and, alternatively, a weighted double maximum test. Both are optionally availble in the new \code{mob()} implementation by setting \code{ordinal = "L2"} or \code{ordinal = "max"} in \code{mob_control()}, respectively. Unfortunately, computing $p$-values from both tests is more costly than for the default \code{ordinal = "chisq"}. For \code{"L2"} suitable tables of critical values have to be simulated on the fly using \code{ordL2BB()} from the \pkg{strucchange} package \citep{strucchange}. For \code{"max"} a multivariate normal probability has to be computed using the \pkg{mvtnorm} package \citep{mvtnorm}. \end{enumerate} All of the parameter instability tests above can be computed in an object-oriented manner as the ``\code{estfun}'' has to be available for the fitted model object. (Either by computing it in the \code{fit} function directly or by providing a \code{estfun()} extractor, see Section~\ref{sec:fit}.) All tests also require an estimate of the corresponding variance-covariance matrix of the estimating functions. The default is to compute this using an outer-product-of-gradients (OPG) estimator. Alternatively, the corrsponding information matrix or sandwich matrix can be used if: (a)~the estimating functions are actually maximum likelihood scores, and (b)~a \code{vcov()} method (based on an estimate of the information) is provided for the fitted model objects. The corresponding option in \code{mob_control()} is to set \code{vcov = "info"} or \code{vcov = "sandwich"} rather than \code{vcov = "opg"} (the default). For each of the $j = 1, \dots, \ell$ partitioning variables in \code{z} the test selected in the control options is employed and the corresponding $p$-value $p_j$ is computed. To adjust for multiple testing, the $p$ values can be Bonferroni adjusted (which is the default). To determine whether there is some overall instability, it is checked whether the minial $p$-value $p_{j^*} = \min_{j = 1, \dots, \ell} p_j$ falls below a pre-specified significance level $\alpha$ (by default $\alpha = 0.05$) or not. If there is significant instability, the variable $Z_{j^*}$ associated with the minimal $p$-value is used for splitting the node. \subsubsection*{Illustration} In the logistic-regression-based MOB \code{pid_tree} computed above, the parameter instability tests can be extracted using the \code{sctest()} function from the \pkg{strucchange} package (for \underline{s}tructural \underline{c}hange \underline{test}). In the first node, the test statistics and Bonferroni-corrected $p$-values are: % <>= library("strucchange") sctest(pid_tree, node = 1) @ % Thus, the body \code{mass} index has the lowest $p$-value and is highly significant and hence used for splitting the data. In the second node, no further significant parameter instabilities can be detected and hence partitioning stops in that branch. % <>= sctest(pid_tree, node = 2) @ % In the third node, however, there is still significant instability associated with the \code{age} variable and hence partitioning continues. % <>= sctest(pid_tree, node = 3) @ % Because no further instabilities can be found in the fourth and fifth node, the recursive partitioning stops there. \subsection{Splitting} \label{sec:split} In this step, the observations in the current node are split with respect to the chosen partitioning variable $Z_{j^*}$ into $B$ child nodes. As pointed out above, the \code{mob()} function currently only supports binary splits, i.e., $B = 2$. For deterimining the split point, an exhaustive search procedure is adopted: For each conceivable split point in $Z_{j^*}$, the two subset models are fit and the split associated with the minimal value of the objective function $\Psi$ is chosen. Computationally, this means that the \code{fit} function is applied to the subsets of \code{y} and \code{x} for each possibly binary split. The ``\code{objfun}'' values are simply summed up (because the objective function is assumed to be additive) and its minimum across splits is determined. In a search over a numeric partitioning variable, this means that typically a lot of subset models have to be fitted and often these will not vary a lot from one split to the next. Hence, the parameter estimates ``\code{coefficients}'' from the previous split are employed as \code{start} values for estimating the coefficients associated with the next split. Thus, if the \code{fit} function makes use of these starting values, the model fitting can often be speeded up. \subsubsection*{Illustration} For the Pima Indians diabetes data, the split points found for \code{pid_tree} are displayed both in the print output and the visualization (see Figure~\ref{fig:pid_tree} and~\ref{fig:pid_tree2}). \subsection{Pruning} \label{sec:prune} By default, the size of \code{mob()} trees is determined only by the significance tests, i.e., when there is no more significant parameter instability (by default at level $\alpha = 0.05$) the tree stops growing. Additional stopping criteria are only the minimal node size (\code{minsize}) and the maximum tree depth (\code{maxdepth}, by default infinity). However, for very large sample size traditional significance levels are typically not useful because even tiny parameter instabilities can be detected. To avoid overfitting in such a situation, one would either have to use much smaller significance levels or add some form of post-pruning to reduce the size of the tree afterwards. Similarly, one could wish to first grow a very large tree (using a large $\alpha$ level) and then prune it afterwards, e.g., using some information criterion like AIC or BIC. To accomodate such post-pruning strategies, \code{mob_control()} has an argument \code{prune} that can be a \code{function(objfun, df, nobs)} that either returns \code{TRUE} if a node should be pruned or \code{FALSE} if not. The arguments supplied are a vector of objective function values in the current node and the sum of all child nodes, a vector of corresponding degrees of freedom, and the number of observations in the current node and in total. For example if the objective function used is the negative log-likelihood, then for BIC-based pruning the \code{prune} function is: \code{(2 * objfun[1] + log(nobs[1]) * df[1]) < (2 * objfun[2] + log(nobs[2]) * df[2])}. As the negative log-likelihood is the default objective function when using the ``simple'' \code{fit} interface, \code{prune} can also be set to \code{"AIC"} or \code{"BIC"} and then suitable functions will be set up internally. Note, however, that for other objective functions this strategy is not appropriate and the functions would have to be defined differently (which \code{lmtree()} does for example). In the literature, there is no clear consensus as to how many degrees of freedom should be assigned to the selection of a split point. Hence, \code{mob_control()} allows to set \code{dfsplit} which by default is \code{dfsplit = TRUE} and then \code{as.integer(dfsplit)} (i.e., 1 by default) degrees of freedom per split are used. This can be modified to \code{dfsplit = FALSE} (or equivalently \code{dfsplit = 0}) or \code{dfsplit = 3} etc.\ for lower or higher penalization of additional splits. \subsubsection*{Illustration} With $n = \Sexpr{nrow(PimaIndiansDiabetes)}$ observations, the sample size is quite reasonable for using the classical significance level of $\alpha = 0.05$ which is also reflected by the moderate tree size with three terminal nodes. However, if we wished to explore further splits, a conceivable strategy could be the following: % <>= pid_tree3 <- mob(pid_formula, data = PimaIndiansDiabetes, fit = logit, control = mob_control(verbose = TRUE, minsize = 50, maxdepth = 4, alpha = 0.9, prune = "BIC")) @ This first grows a large tree until the nodes become too small (minimum node size: 50~observations) or the tree becomes too deep (maximum depth 4~levels) or the significance levels come very close to one (larger than $\alpha = 0.9$). Here, this large tree has eleven nodes which are subsequently pruned based on whether or not they improve the BIC of the model. For this data set, the resulting BIC-pruned tree is in fact identical to the pre-pruned \code{pid_tree} considered above. \subsection[Fitted `party' objects]{Fitted `\texttt{party}' objects} \label{sec:object} The result of \code{mob()} is an object of class `\code{modelparty}' inheriting from `\code{party}'. See the other vignettes in the \pkg{partykit} package \citep{partykit} for more details of the general `\code{party}' class. Here, we just point out that the main difference between a `\code{modelparty}' and a plain `\code{party}' is that additional information about the data and the associated models is stored in the \code{info} elements: both of the overall `\code{party}' and the individual `\code{node}'s. The details are exemplified below. \subsubsection*{Illustration} In the \code{info} of the overall `\code{party}' the following information is stored for \code{pid_tree}: % <>= names(pid_tree$info) @ % The \code{call} contains the \code{mob()} call. The \code{formula} and \code{Formula} are virtually the same but are simply stored as plain `\code{formula}' and extended `\code{Formula}' \citep{Formula} objects, respectively. The \code{terms} contain separate lists of terms for the \code{response} (and regressor) and the \code{partitioning} variables. The \code{fit}, \code{control} and \code{dots} are the arguments that were provided to \code{mob()} and \code{nreg} is the number of regressor variables. Furthermore, each \code{node} of the tree contains the following information: % <>= names(pid_tree$node$info) @ % The \code{coefficients}, \code{objfun}, and \code{object} are the results of the \code{fit} function for that node. In \code{nobs} and \code{p.value} the number of observations and the minimal $p$-value are provided, respectively. Finally, \code{test} contains the parameter instability test results. Note that the \code{object} element can also be suppressed through \code{mob_control()} to save memory space. \subsection{Methods} \label{sec:methods} There is a wide range of standard methods available for objects of class `\code{modelparty}'. The standard \code{print()}, \code{plot()}, and \code{predict()} build on the corresponding methods for `\code{party}' objects but provide some more special options. Furthermore, methods are provided that are typically available for models with formula interfaces: \code{formula()} (optionally one can set \code{extended = TRUE} to get the `\code{Formula}'), \code{getCall()}, \code{model.frame()}, \code{weights()}. Finally, there is a standard set of methods for statistical model objects: \code{coef()}, \code{residuals()}, \code{logLik()} (optionally setting \code{dfsplit = FALSE} suppresses counting the splits in the degrees of freedom, see Section~\ref{sec:prune}), \code{deviance()}, \code{fitted()}, and \code{summary()}. Some of these methods rely on reusing the corresponding methods for the individual model objects in the terminal nodes. Functions such as \code{coef()}, \code{print()}, \code{summary()} also take a \code{node} argument that can specify the node IDs to be queried. Two methods have non-standard arguments to allow for additional flexibility when dealing with model trees. Typically, ``normal'' users do not have to use these arguments directly but they are very flexible and facilitate writing convenience interfaces such as \code{glmtree()} (see Section~\ref{sec:interface}). \begin{itemize} \item The \code{predict()} method has the following arguments: \code{predict(object, newdata = NULL, type = "node", ...)}. The argument \code{type} can either be a function or a character string. More precisely, if \code{type} is a function it should be a \code{function (object, newdata = NULL, ...)} that returns a vector or matrix of predictions from a fitted model \code{object} either with or without \code{newdata}. If \code{type} is a character string, such a function is set up internally as \code{predict(object, newdata = newdata, type = type, ...)}, i.e., it relies on a suitable \code{predict()} method being available for the fitted models associated with the `\code{party}' object. \item The \code{plot()} method has the following arguments: \code{plot(x, terminal_panel = NULL, FUN = NULL)}. This simply calls the \code{plot()} method for `\code{party}' objects with a custom panel function for the terminal panels. By default, \code{node_terminal} is used to include some short text in each terminal node. This text can be set up by \code{FUN} with the default being the number of observations and estimated parameters. However, more elaborate terminal panel functions can be written, as done for the convenience interfaces. \end{itemize} Finally, two \proglang{S}3-style functions are provided without the corresponding generics (as these reside in packages that \pkg{partykit} does not depend on). The \code{sctest.modelparty} can be used in combination with the \code{sctest()} generic from \pkg{strucchange} as illustrated in Section~\ref{sec:sctest}. The \code{refit.modelparty} function extracts (or refits if necessary) the fitted model objects in the specified nodes (by default from all nodes). \subsubsection*{Illustration} The \code{plot()} and \code{print()} methods have already been illustrated for the \code{pid_tree} above. However, here we add that the \code{print()} method can also be used to show more detailed information about particular nodes instead of showing the full tree: % <>= print(pid_tree, node = 3) @ % Information about the model and coefficients can for example be extracted by: % <>= coef(pid_tree) coef(pid_tree, node = 1) ## IGNORE_RDIFF_BEGIN summary(pid_tree, node = 1) ## IGNORE_RDIFF_END @ % As the coefficients pertain to a logistic regression, they can be easily interpreted as odds ratios by taking the \code{exp()}: % <<>>= exp(coef(pid_tree)[,2]) @ % <>= risk <- round(100 * (exp(coef(pid_tree)[,2])-1), digits = 1) @ % i.e., the odds increase by \Sexpr{risk[1]}\%, \Sexpr{risk[2]}\% and \Sexpr{risk[3]}\% with respect to glucose in the three terminal nodes. Log-likelihoods and information criteria are available (which by default also penalize the estimation of splits): <>= logLik(pid_tree) AIC(pid_tree) BIC(pid_tree) @ % Mean squared residuals (or deviances) can be extracted in different ways: <>= mean(residuals(pid_tree)^2) deviance(pid_tree)/sum(weights(pid_tree)) deviance(pid_tree)/nobs(pid_tree) @ % Predicted nodes can also be easily obtained: % <>= pid <- head(PimaIndiansDiabetes) predict(pid_tree, newdata = pid, type = "node") @ % More predictions, e.g., predicted probabilities within the nodes, can also be obtained but require some extra coding if only \code{mob()} is used. However, with the \code{glmtree()} interface this is very easy as shown below. Finally, several methods for `\code{party}' objects are, of course, also available for `\code{modelparty}' objects, e.g., querying width and depth of the tree: % <>= width(pid_tree) depth(pid_tree) @ % Also subtrees can be easily extracted: % <>= pid_tree[3] @ % The subtree is again a completely valid `\code{modelparty}' and hence it could also be visualized via \code{plot(pid_tree[3])} etc. \subsection{Extensions and convenience interfaces} \label{sec:interface} As illustrated above, dealing with MOBs can be carried out in a very generic and object-oriented way. Almost all information required for dealing with recursively partitioned models can be encapsulated in the \code{fit()} function and \code{mob()} does not require more information on what type of model is actually used. However, for certain tasks more detailed information about the type of model used or the type of data it can be fitted to can (and should) be exploited. Notable examples for this are visualizations of the data along with the fitted model or model-based predictions in the leaves of the tree. To conveniently accomodate such specialized functionality, the \pkg{partykit} provides two convenience interfaces \code{lmtree()} and \code{glmtree()} and encourages other packages to do the same (e.g., \code{raschtree()} and \code{bttree()} in \pkg{psychotree}). Furthermore, such a convenience interface can avoid duplicated formula processing in both \code{mob()} plus its \code{fit} function. Specifically, \code{lmtree()} and \code{glmtree()} interface \code{lm.fit()}, \code{lm.wfit()}, and \code{glm.fit()}, respectively, and then provide some extra computations to return valid fitted `\code{lm}' and `\code{glm}' objects in the nodes of the tree. The resulting `\code{modelparty}' object gains an additional class `\code{lmtree}'/`\code{glmtree}' to dispatch to its enhanced \code{plot()} and \code{predict()} methods. \subsubsection*{Illustration} The \code{pid_tree2} object was already created above with \code{glmtree()} (instead of \code{mob()} as for \code{pid_tree}) to illustrate the enhanced plotting capabilities in Figure~\ref{fig:pid_tree2}. Here, the enhanced \code{predict()} method is used to obtain predicted means (i.e., probabilities) and associated linear predictors (on the logit scale) in addition to the previously available predicted nods IDs. % <<>>= predict(pid_tree2, newdata = pid, type = "node") predict(pid_tree2, newdata = pid, type = "response") predict(pid_tree2, newdata = pid, type = "link") @ \section{Illustrations} \label{sec:illustration} In the remainder of the vignette, further empirical illustrations of the MOB method are provided, including replications of the results from \cite{Zeileis+Hothorn+Hornik:2008}: \begin{enumerate} \item An investigation of the price elasticity of the demand for economics journals across covariates describing the type of journal (e.g., its price, its age, and whether it is published by a society, etc.) \item Prediction of house prices in the well-known Boston Housing data set, also taken from the UCI machine learning repository. \item Explore how teaching ratings and beauty scores of professors are associated and how this association changes across further explanatory variables such as age, gender, and native speaker status of the professors. \item Assessment of differences in the preferential treatment of women/children (``women and children first'') across subgroups of passengers on board of the ill-fated maiden voyage of the RMS Titanic. \item Modeling of breast cancer survival by capturing heterogeneity in certain (treatment) effects across patients. \item Modeling of paired comparisons of topmodel candidates by capturing heterogeneity in their attractiveness scores across participants in a survey. \end{enumerate} More details about several of the underlying data sets, previous studies exploring the data, and the results based on MOB can be found in \cite{Zeileis+Hothorn+Hornik:2008}. Here, we focus on using the \pkg{partykit} package to replicate the analysis and explore the resulting trees. The first three illustrations employ the \code{lmtree()} convenience function, the fourth is based on logistic regression using \code{glmtree()}, and the fifth uses \code{survreg()} from \pkg{survival} \citep{survival} in combination with \code{mob()} directly. The sixth and last illustration is deferred to a separate section and shows in detail how to set up new ``mobster'' functionality from scratch. \subsection{Demand for economic journals} The price elasticity of the demand for 180~economic journals is assessed by an OLS regression in log-log form: The dependent variable is the logarithm of the number of US library subscriptions and the regressor is the logarithm of price per citation. The data are provided by the \pkg{AER} package \citep{AER} and can be loaded and transformed via: % <>= data("Journals", package = "AER") Journals <- transform(Journals, age = 2000 - foundingyear, chars = charpp * pages) @ % Subsequently, the stability of the price elasticity across the remaining variables can be assessed using MOB. Below, \code{lmtree()} is used with the following partitioning variables: raw price and citations, age of the journal, number of characters, and whether the journal is published by a scientific society or not. A minimal segment size of 10~observations is employed and by setting \code{verbose = TRUE} detailed progress information about the recursive partitioning is displayed while growing the tree: % <>= j_tree <- lmtree(log(subs) ~ log(price/citations) | price + citations + age + chars + society, data = Journals, minsize = 10, verbose = TRUE) @ % \begin{figure}[t!] \centering \setkeys{Gin}{width=0.75\textwidth} <>= plot(j_tree) @ \caption{\label{fig:Journals} Linear-regression-based tree for the journals data. The plots in the leaves show linear regressions of log(subscriptions) by log(price/citation).} \end{figure} % The resulting tree just has one split and two terminal nodes for young journals (with a somewhat larger price elasticity) and old journals (with an even lower price elasticity), respectively. Figure~\ref{fig:Journals} can be obtained by \code{plot(j_tree)} and the corresponding printed representation is shown below. % <>= j_tree @ % Finally, various quantities of interest such as the coefficients, standard errors and test statistics, and the associated parameter instability tests could be extracted by the following code. The corresponding output is suppressed here. % <>= coef(j_tree, node = 1:3) summary(j_tree, node = 1:3) sctest(j_tree, node = 1:3) @ \subsection{Boston housing data} The Boston housing data are a popular and well-investigated empirical basis for illustrating nonlinear regression methods both in machine learning and statistics. We follow previous analyses by segmenting a bivariate linear regression model for the house values. The data set is available in package \pkg{mlbench} and can be obtained and transformed via: % <>= data("BostonHousing", package = "mlbench") BostonHousing <- transform(BostonHousing, chas = factor(chas, levels = 0:1, labels = c("no", "yes")), rad = factor(rad, ordered = TRUE)) @ % It provides $n = \Sexpr{NROW(BostonHousing)}$ observations of the median value of owner-occupied homes in Boston (in USD~1000) along with $\Sexpr{NCOL(BostonHousing)}$ covariates including in particular the number of rooms per dwelling (\code{rm}) and the percentage of lower status of the population (\code{lstat}). A segment-wise linear relationship between the value and these two variables is very intuitive, whereas the shape of the influence of the remaining covariates is rather unclear and hence should be learned from the data. Therefore, a linear regression model for median value explained by \verb:rm^2: and \verb:log(lstat): is employed and partitioned with respect to all remaining variables. Choosing appropriate transformations of the dependent variable and the regressors that enter the linear regression model is important to obtain a well-fitting model in each segment and we follow in our choice the recommendations of \cite{Breiman+Friedman:1985}. Monotonic transformations of the partitioning variables do not affect the recursive partitioning algorithm and hence do not have to be performed. However, it is important to distinguish between numerical and categorical variables for choosing an appropriate parameter stability test. The variable \code{chas} is a dummy indicator variable (for tract bounds with Charles river) and thus needs to be turned into a factor. Furthermore, the variable \code{rad} is an index of accessibility to radial highways and takes only 9 distinct values. Hence, it is most appropriately treated as an ordered factor. Note that both transformations only affect the parameter stability test chosen (step~2), not the splitting procedure (step~3). % Note that with splittry = 0 (according to old version of mob) there is no % split in dis <>= bh_tree <- lmtree(medv ~ log(lstat) + I(rm^2) | zn + indus + chas + nox + age + dis + rad + tax + crim + b + ptratio, data = BostonHousing) bh_tree @ % The corresponding visualization is shown in Figure~\ref{fig:BostonHousing}. It shows partial scatter plots of the dependent variable against each of the regressors in the terminal nodes. Each scatter plot also shows the fitted values, i.e., a projection of the fitted hyperplane. \setkeys{Gin}{width=\textwidth} \begin{figure}[p!] \centering <>= plot(bh_tree) @ \includegraphics[width=18cm,keepaspectratio,angle=90]{mob-BostonHousing-plot} \caption{\label{fig:BostonHousing} Linear-regression-based tree for the Boston housing data. The plots in the leaves give partial scatter plots for \code{rm} (upper panel) and \code{lstat} (lower panel).} \end{figure} From this visualization, it can be seen that in the nodes~4, 6, 7 and 8 the increase of value with the number of rooms dominates the picture (upper panel) whereas in node~9 the decrease with the lower status population percentage (lower panel) is more pronounced. Splits are performed in the variables \code{tax} (poperty-tax rate) and \code{ptratio} (pupil-teacher ratio). For summarizing the quality of the fit, we could compute the mean squared error, log-likelihood or AIC: % <>= mean(residuals(bh_tree)^2) logLik(bh_tree) AIC(bh_tree) @ \subsection{Teaching ratings data} \cite{Hamermesh+Parker:2005} investigate the correlation of beauty and teaching evaluations for professors. They provide data on course evaluations, course characteristics, and professor characteristics for 463 courses for the academic years 2000--2002 at the University of Texas at Austin. It is of interest how the average teaching evaluation per course (on a scale 1--5) depends on a standardized measure of beauty (as assessed by a committee of six persons based on photos). \cite{Hamermesh+Parker:2005} employ a linear regression, weighted by the number of students per course and adjusting for several further main effects: gender, whether or not the teacher is from a minority, a native speaker, or has tenure, respectively, and whether the course is taught in the upper or lower division. Additionally, the age of the professors is available as a regressor but not considered by \cite{Hamermesh+Parker:2005} because the corresponding main effect is not found to be significant in either linear or quadratic form. Here, we employ a similar model but use the available regressors differently. The basic model is again a linear regression for teaching rating by beauty, estimated by weighted least squares (WLS). All remaining explanatory variables are \emph{not} used as regressors but as partitioning variables because we argue that it is unclear how they influence the correlation between teaching rating and beauty. Hence, MOB is used to adaptively incorporate these further variables and determine potential interactions. First, the data are loaded from the \pkg{AER} package \citep{AER} and only the subset of single-credit courses is excluded. % <>= data("TeachingRatings", package = "AER") tr <- subset(TeachingRatings, credits == "more") @ % The single-credit courses include elective modules that are quite different from the remaining courses (e.g., yoga, aerobics, or dance) and are hence omitted from the main analysis. WLS estimation of the null model (with only an intercept) and the main effects model is carried out in a first step: % <>= tr_null <- lm(eval ~ 1, data = tr, weights = students) tr_lm <- lm(eval ~ beauty + gender + minority + native + tenure + division, data = tr, weights = students) @ % Then, the model-based tree can be estimated with \code{lmtree()} using only \code{beauty} as a regressor and all remaining variables for partitioning. For WLS estimation, we set \code{weights = students} and \code{caseweights = FALSE} because the weights are only proportionality factors and do not signal exactly replicated observations \citep[see][for a discussion of the different types of weights]{Lumley:2020}. % <>= (tr_tree <- lmtree(eval ~ beauty | minority + age + gender + division + native + tenure, data = tr, weights = students, caseweights = FALSE)) @ % \begin{figure}[t!] \setkeys{Gin}{width=\textwidth} <>= plot(tr_tree) @ \caption{\label{fig:tr_tree} WLS-based tree for the teaching ratings data. The plots in the leaves show scatterplots for teaching rating by beauty score.} \end{figure} % The resulting tree can be visualized by \code{plot(tr_tree)} and is shown in Figure~\ref{fig:tr_tree}. This shows that despite age not having a significant main effect \citep[as reported by][]{Hamermesh+Parker:2005}, it clearly plays an important role: While the correlation of teaching rating and beauty score is rather moderate for younger professors, there is a clear correlation for older professors (with the cutoff age somewhat lower for female professors). % <>= coef(tr_lm)[2] coef(tr_tree)[, 2] @ % Th $R^2$ of the tree is also clearly improved over the main effects model: % <>= 1 - c(deviance(tr_lm), deviance(tr_tree))/deviance(tr_null) @ \subsection{Titanic survival data} To illustrate how differences in treatment effects can be captured by MOB, the Titanic survival data is considered: The question is whether ``women and children first'' is applied in the same way for all subgroups of the passengers of the Titanic. Or, in other words, whether the effectiveness of preferential treatment for women/children differed across subgroups. The \code{Titanic} data is provided in base \proglang{R} as a contingency table and transformed here to a `\code{data.frame}' for use with \code{glmtree()}: % <>= data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" ttnc <- transform(ttnc, Treatment = factor( Gender == "Female" | Age == "Child", levels = c(FALSE, TRUE), labels = c("Male&Adult", "Female|Child"))) @ % The data provides factors \code{Survived} (yes/no), \code{Class} (1st, 2nd, 3rd, crew), \code{Gender} (male, female), and \code{Age} (child, adult). Additionally, a factor \code{Treatment} is added that distinguishes women/children from male adults. To investigate how the preferential treatment effect (\code{Survived ~ Treatment}) differs across the remaining explanatory variables, the following logistic-regression-based tree is considered. The significance level of \code{alpha = 0.01} is employed here to avoid overfitting and separation problems in the logistic regression. % <>= ttnc_tree <- glmtree(Survived ~ Treatment | Class + Gender + Age, data = ttnc, family = binomial, alpha = 0.01) ttnc_tree @ % \begin{figure}[t!] \setkeys{Gin}{width=\textwidth} <>= plot(ttnc_tree, tp_args = list(ylines = 1, margins = c(1.5, 1.5, 1.5, 2.5))) @ \caption{\label{fig:ttnc_tree} Logistic-regression-based tree for the Titanic survival data. The plots in the leaves give spinograms for survival status versus preferential treatment (women or children).} \end{figure} % This shows that the treatment differs strongly across passengers classes, see also the result of \code{plot(ttnc_tree)} in Figure~\ref{fig:ttnc_tree}. The treatment effect is much lower in the 3rd class where women/children still have higher survival rates than adult men but the odds ratio is much lower compared to all remaining classes. The split between the 2nd and the remaining two classes (1st, crew) is due to a lower overall survival rate (intercepts of \Sexpr{round(coef(ttnc_tree)[2, 1], digits = 2)} and \Sexpr{round(coef(ttnc_tree)[3, 1], digits = 2)}, respectively) while the odds ratios associated with the preferential treatment are rather similar (\Sexpr{round(coef(ttnc_tree)[2, 2], digits = 2)} and \Sexpr{round(coef(ttnc_tree)[3, 2], digits = 2)}, respectively). Another option for assessing the class effect would be to immediately split into all four classes rather than using recursive binary splits. This can be obtained by setting \code{catsplit = "multiway"} in the \code{glmtree()} call above. This yields a tree with just a single split but four kid nodes. \subsection{German breast cancer data} To illustrate that the MOB approach can also be used beyond (generalized) linear regression models, it is employed in the following to analyze censored survival times among German women with positive node breast cancer. The data is available in the \pkg{TH.data} package and the survival time is transformed from days to years: % <>= data("GBSG2", package = "TH.data") GBSG2$time <- GBSG2$time/365 @ % For regression a parametric Weibull regression based on the \code{survreg()} function from the \pkg{survival} package \citep{survival} is used. A fitting function for \code{mob()} can be easily set up: % <>= library("survival") wbreg <- function(y, x, start = NULL, weights = NULL, offset = NULL, ...) { survreg(y ~ 0 + x, weights = weights, dist = "weibull", ...) } @ % As the \pkg{survreg} package currently does not provide a \code{logLik()} method for `\code{survreg}' objects, this needs to be added here: % <>= logLik.survreg <- function(object, ...) structure(object$loglik[2], df = sum(object$df), class = "logLik") @ % Without the \code{logLik()} method, \code{mob()} would not know how to extract the optimized objective function from the fitted model. With the functions above available, a censored Weibull-regression-tree can be fitted: The dependent variable is the censored survival time and the two regressor variables are the main risk factor (number of positive lymph nodes) and the treatment variable (hormonal therapy). All remaining variables are used for partitioning: age, tumor size and grade, progesterone and estrogen receptor, and menopausal status. The minimal segment size is set to 80. % <>= gbsg2_tree <- mob(Surv(time, cens) ~ horTh + pnodes | age + tsize + tgrade + progrec + estrec + menostat, data = GBSG2, fit = wbreg, control = mob_control(minsize = 80)) @ % \begin{figure}[p!] \centering \setkeys{Gin}{width=0.6\textwidth} <>= plot(gbsg2_tree) @ \caption{\label{fig:GBSG2} Censored Weibull-regression-based tree for the German breast cancer data. The plots in the leaves report the estimated regression coefficients.} \setkeys{Gin}{width=\textwidth} <>= gbsg2node <- function(mobobj, col = "black", linecol = "red", cex = 0.5, pch = NULL, jitter = FALSE, xscale = NULL, yscale = NULL, ylines = 1.5, id = TRUE, xlab = FALSE, ylab = FALSE) { ## obtain dependent variable mf <- model.frame(mobobj) y <- Formula::model.part(mobobj$info$Formula, mf, lhs = 1L, rhs = 0L) if(isTRUE(ylab)) ylab <- names(y)[1L] if(identical(ylab, FALSE)) ylab <- "" if(is.null(ylines)) ylines <- ifelse(identical(ylab, ""), 0, 2) y <- y[[1L]] ## plotting character and response if(is.null(pch)) pch <- y[,2] * 18 + 1 y <- y[,1] y <- as.numeric(y) pch <- rep(pch, length.out = length(y)) if(jitter) y <- jitter(y) ## obtain explanatory variables x <- Formula::model.part(mobobj$info$Formula, mf, lhs = 0L, rhs = 1L) xnam <- colnames(x) z <- seq(from = min(x[,2]), to = max(x[,2]), length = 51) z <- data.frame(a = rep(sort(x[,1])[c(1, NROW(x))], c(51, 51)), b = z) names(z) <- names(x) z$x <- model.matrix(~ ., data = z) ## fitted node ids fitted <- mobobj$fitted[["(fitted)"]] if(is.null(xscale)) xscale <- range(x[,2]) + c(-0.1, 0.1) * diff(range(x[,2])) if(is.null(yscale)) yscale <- range(y) + c(-0.1, 0.1) * diff(range(y)) ## panel function for scatter plots in nodes rval <- function(node) { ## node index nid <- id_node(node) ix <- fitted %in% nodeids(mobobj, from = nid, terminal = TRUE) ## dependent variable y <- y[ix] ## predictions yhat <- if(is.null(node$info$object)) { refit.modelparty(mobobj, node = nid) } else { node$info$object } yhat <- predict(yhat, newdata = z, type = "quantile", p = 0.5) pch <- pch[ix] ## viewport setup top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_scatterplot", nid, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = "white", col = 0)) ## main title top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) mainlab <- paste(ifelse(id, paste("Node", nid, "(n = "), ""), info_node(node)$nobs, ifelse(id, ")", ""), sep = "") grid.text(mainlab) popViewport() plot_vp <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = xscale, yscale = yscale, name = paste("node_scatterplot", nid, "plot", sep = "")) pushViewport(plot_vp) ## scatterplot grid.points(x[ix,2], y, gp = gpar(col = col, cex = cex), pch = pch) grid.lines(z[1:51,2], yhat[1:51], default.units = "native", gp = gpar(col = linecol)) grid.lines(z[52:102,2], yhat[52:102], default.units = "native", gp = gpar(col = linecol, lty = 2)) grid.xaxis(at = c(ceiling(xscale[1]*10), floor(xscale[2]*10))/10) grid.yaxis(at = c(ceiling(yscale[1]), floor(yscale[2]))) if(isTRUE(xlab)) xlab <- xnam[2] if(!identical(xlab, FALSE)) grid.text(xlab, x = unit(0.5, "npc"), y = unit(-2, "lines")) if(!identical(ylab, FALSE)) grid.text(ylab, y = unit(0.5, "npc"), x = unit(-2, "lines"), rot = 90) grid.rect(gp = gpar(fill = "transparent")) upViewport() upViewport() } return(rval) } class(gbsg2node) <- "grapcon_generator" plot(gbsg2_tree, terminal_panel = gbsg2node, tnex = 2, tp_args = list(xscale = c(0, 52), yscale = c(-0.5, 8.7))) @ \caption{\label{fig:GBSG2-scatter} Censored Weibull-regression-based tree for the German breast cancer data. The plots in the leaves depict censored (hollow) and uncensored (solid) survival time by number of positive lymph nodes along with fitted median survival for patients with (dashed line) and without (solid line) hormonal therapy.} \end{figure} % Based on progesterone receptor, a tree with two leaves is found: % <>= gbsg2_tree coef(gbsg2_tree) logLik(gbsg2_tree) @ % The visualization produced by \code{plot(gbsg2_tree)} is shown in Figure~\ref{fig:GBSG2}. A nicer graphical display using a scatter plot (with indication of censoring) and fitted regression curves is shown in Figure~\ref{fig:GBSG2-scatter}. This uses a custom panel function whose code is too long and elaborate to be shown here. Interested readers are referred to the \proglang{R} code underlying the vignette. The visualization shows that for higher progesterone receptor levels: (1)~survival times are higher overall, (2)~the treatment effect of hormonal therapy is higher, and (3)~the negative effect of the main risk factor (number of positive lymph nodes) is less severe. \section{Setting up a new mobster} \label{sec:mobster} To conclude this vignette, we present another illustration that shows how to set up new mobster functionality from scratch. To do so, we implement the Bradley-Terry tree suggested by \cite{Strobl+Wickelmaier+Zeileis:2011} ``by hand''. The \pkg{psychotree} package already provides an easy-to-use mobster called \code{bttree()} but as an implementation exercise we recreate its functionality here. The only inputs required are a suitable data set with paired comparisons (\code{Topmodel2007} from \pkg{psychotree}) and a parametric model for paired comparison data (\code{btmodel()} from \pkg{psychotools}, implementing the Bradley-Terry model). The latter optionally computes the empirical estimating functions and already comes with a suitable extractor method. <>= data("Topmodel2007", package = "psychotree") library("psychotools") @ % The Bradley-Terry (or Bradley-Terry-Luce) model is a standard model for paired comparisons in social sciences. It parametrizes the probability $\pi_{ij}$ for preferring some object $i$ over another object $j$ in terms of corresponding ``ability'' or ``worth'' parameters $\theta_i$: \begin{eqnarray*} \pi_{ij}\phantom{)} & = & \frac{\theta_i}{\theta_i + \theta_j} \\ \mathsf{logit}(\pi_{ij}) & = & \log(\theta_i) - \log(\theta_j) \end{eqnarray*} This model can be easily estimated by maximum likelihood as a logistic or log-linear GLM. This is the approach used internally by \code{btmodel()}. The \code{Topmodel2007} data provide paired comparisons of attractiveness among the six finalists of the TV show \emph{Germany's Next Topmodel~2007}: Barbara, Anni, Hana, Fiona, Mandy, Anja. The data were collected in a survey with 192~respondents at Universit{\"a}t T{\"u}bingen and the available covariates comprise gender, age, and familiarty with the TV~show. The latter is assess by three by yes/no questions: (1)~Do you recognize the women?/Do you know the show? (2)~Did you watch it regularly? (3)~Did you watch the final show?/Do you know who won? To fit the Bradley-Terry tree to the data, the available building blocks just have to be tied together. First, we set up the basic/simple model fitting interface described in Section~\ref{sec:fit}: % @ <>= btfit1 <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ...) btmodel(y, ...) @ % The function \code{btfit1()} simply calls \code{btmodel()} ignoring all arguments except \code{y} as the others are not needed here. No more processing is required because \class{btmodel} objects come with a \code{coef()}, \code{logLik()}, and \code{estfun()} method. Hence, we can call \code{mob()} now specifying the response and the partitioning variable (and no regressors because there are no regressors in this model). % <>= bt1 <- mob(preference ~ 1 | gender + age + q1 + q2 + q3, data = Topmodel2007, fit = btfit1) @ % An alternative way to fit the exact same tree somewhat more quickly would be to employ the extended interface described in Section~\ref{sec:fit}: % <>= btfit2 <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ..., estfun = FALSE, object = FALSE) { rval <- btmodel(y, ..., estfun = estfun, vcov = object) list( coefficients = rval$coefficients, objfun = -rval$loglik, estfun = if(estfun) rval$estfun else NULL, object = if(object) rval else NULL ) } @ % Still \code{btmodel()} is employed for fitting the model but the quantities \code{estfun} and \code{vcov} are only computed if they are really required. This may save some computation time -- about 20\% on the authors' machine at the time of writing -- when computing the tree: % <>= bt2 <- mob(preference ~ 1 | gender + age + q1 + q2 + q3, data = Topmodel2007, fit = btfit2) @ % The speed-up is not huge but comes almost for free: just a few additional lines of code in \code{btfit2()} are required. For other models where it is more costly to set up a full model (with variance-covariance matrix, predictions, residuals, etc.) larger speed-ups are also possible. Both trees, \code{bt1} and \code{bt2}, are equivalent (except for the details of the fitting function). Hence, in the following we only explore \code{bt2}. However, the same code can be applied to \code{bt1} as well. Many tools come completely for free and are inherited from the general \class{modelparty}/\class{party}. For example, both printing (\code{print(bt2)}) and plotting (\code{plot(bt2)}) shows the estimated parameters in the terminal nodes which can also be extracted by the \code{coef()} method: <>= bt2 coef(bt2) @ The corresponding visualization is shown in the upper panel of Figure~\ref{fig:topmodel-plot1}. In all cases, the estimated coefficients on the logit scale omitting the fixed zero reference level (Anja) are reported. To show the corresponding worth parameters $\theta_i$ including the reference level, one can simply provide a small panel function \code{worthf()}. This applies the \code{worth()} function from \pkg{psychotools} to the fitted-model object stored in the \code{info} slot of each node, yielding the lower panel in Figure~\ref{fig:topmodel-plot1}. % <>= worthf <- function(info) paste(info$object$labels, format(round(worth(info$object), digits = 3)), sep = ": ") plot(bt2, FUN = worthf) @ % \begin{figure}[p!] \centering <>= plot(bt2) @ \vspace*{0.5cm} <>= <> @ \caption{\label{fig:topmodel-plot1} Bradley-Terry-based tree for the topmodel attractiveness data. The default plot (upper panel) reports the estimated coefficients on the log scale while the adapted plot (lower panel) shows the corresponding worth parameters.} \end{figure} % To show a graphical display of these worth parameters rather than printing their numerical values, one can use a simply glyph-style plot. A simply way to generate these is to use the \code{plot()} method for \class{btmodel} objects from \pkg{partykit} and \code{nodeapply} this to all terminal nodes (see Figure~\ref{fig:topmodel-plot2}): % <>= par(mfrow = c(2, 2)) nodeapply(bt2, ids = c(3, 5, 6, 7), FUN = function(n) plot(n$info$object, main = n$id, ylim = c(0, 0.4))) @ % \begin{figure}[t!] \centering <>= <> @ \caption{\label{fig:topmodel-plot2} Worth parameters in the terminal nodes of the Bradley-Terry-based tree for the topmodel attractiveness data.} \end{figure} % Alternatively, one could set up a proper panel-generating function in \pkg{grid} that allows to create the glyphs within the terminal nodes of the tree (see Figure~\ref{fig:topmodel-plot3}). As the code for this panel-generating function \code{node_btplot()} is too complicated to display within the vignette, we refer interested readers to the underlying code. Given this panel-generating function Figure~\ref{fig:topmodel-plot3} can be generated with <>= plot(bt2, drop = TRUE, tnex = 2, terminal_panel = node_btplot(bt2, abbreviate = 1, yscale = c(0, 0.5))) @ \begin{figure}[t!] \centering <>= ## visualization function node_btplot <- function(mobobj, id = TRUE, worth = TRUE, names = TRUE, abbreviate = TRUE, index = TRUE, ref = TRUE, col = "black", linecol = "lightgray", cex = 0.5, pch = 19, xscale = NULL, yscale = NULL, ylines = 1.5) { ## node ids node <- nodeids(mobobj, terminal = FALSE) ## get all coefficients cf <- partykit:::apply_to_models(mobobj, node, FUN = function(z) if(worth) worth(z) else coef(z, all = FALSE, ref = TRUE)) cf <- do.call("rbind", cf) rownames(cf) <- node ## get one full model mod <- partykit:::apply_to_models(mobobj, node = 1L, FUN = NULL) if(!worth) { if(is.character(ref) | is.numeric(ref)) { reflab <- ref ref <- TRUE } else { reflab <- mod$ref } if(is.character(reflab)) reflab <- match(reflab, mod$labels) cf <- cf - cf[,reflab] } ## reference if(worth) { cf_ref <- 1/ncol(cf) } else { cf_ref <- 0 } ## labeling if(is.character(names)) { colnames(cf) <- names names <- TRUE } ## abbreviation if(is.logical(abbreviate)) { nlab <- max(nchar(colnames(cf))) abbreviate <- if(abbreviate) as.numeric(cut(nlab, c(-Inf, 1.5, 4.5, 7.5, Inf))) else nlab } colnames(cf) <- abbreviate(colnames(cf), abbreviate) if(index) { x <- 1:NCOL(cf) if(is.null(xscale)) xscale <- range(x) + c(-0.1, 0.1) * diff(range(x)) } else { x <- rep(0, length(cf)) if(is.null(xscale)) xscale <- c(-1, 1) } if(is.null(yscale)) yscale <- range(cf) + c(-0.1, 0.1) * diff(range(cf)) ## panel function for bt plots in nodes rval <- function(node) { ## node index id <- id_node(node) ## dependent variable setup cfi <- cf[id,] ## viewport setup top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_btplot", id, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = "white", col = 0)) ## main title top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) mainlab <- paste(ifelse(id, paste("Node", id, "(n = "), ""), info_node(node)$nobs, ifelse(id, ")", ""), sep = "") grid.text(mainlab) popViewport() ## actual plot plot_vpi <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = xscale, yscale = yscale, name = paste("node_btplot", id, "plot", sep = "")) pushViewport(plot_vpi) grid.lines(xscale, c(cf_ref, cf_ref), gp = gpar(col = linecol), default.units = "native") if(index) { grid.lines(x, cfi, gp = gpar(col = col, lty = 2), default.units = "native") grid.points(x, cfi, gp = gpar(col = col, cex = cex), pch = pch, default.units = "native") grid.xaxis(at = x, label = if(names) names(cfi) else x) } else { if(names) grid.text(names(cfi), x = x, y = cfi, default.units = "native") else grid.points(x, cfi, gp = gpar(col = col, cex = cex), pch = pch, default.units = "native") } grid.yaxis(at = c(ceiling(yscale[1] * 100)/100, floor(yscale[2] * 100)/100)) grid.rect(gp = gpar(fill = "transparent")) upViewport(2) } return(rval) } class(node_btplot) <- "grapcon_generator" plot(bt2, drop = TRUE, tnex = 2, terminal_panel = node_btplot(bt2, abbreviate = 1, yscale = c(0, 0.5))) @ \caption{\label{fig:topmodel-plot3} Bradley-Terry-based tree for the topmodel attractiveness data with visualizations of the worth parameters in the terminal nodes.} \end{figure} Finally, to illustrate how different predictions can be easily computed, we set up a small data set with three new individuals: % <>= tm <- data.frame(age = c(60, 25, 35), gender = c("male", "female", "female"), q1 = "no", q2 = c("no", "no", "yes"), q3 = "no") tm @ % For these we can easily compute (1)~the predicted node ID, (2)~the corresponding worth parameters, (3)~the associated ranks. <>= tm predict(bt2, tm, type = "node") predict(bt2, tm, type = function(object) t(worth(object))) predict(bt2, tm, type = function(object) t(rank(-worth(object)))) @ This completes the tour of fitting, printing, plotting, and predicting the Bradley-Terry tree model. Convenience interfaces that employ code like shown above can be easily defined and collected in new packages such as \pkg{psychotree}. \section{Conclusion} \label{sec:conclusion} The function \code{mob()} in the \pkg{partykit} package provides a new flexible and object-oriented implementation of the general algorithm for model-based recursive partitioning using \pkg{partykit}'s recursive partytioning infrastructure. New model fitting functions can be easily provided, especially if standard extractor functions (such as \code{coef()}, \code{estfun()}, \code{logLik()}, etc.) are available. The resulting model trees can then learned, visualized, investigated, and employed for predictions. To gain some efficiency in the computations and to allow for further customization (in particular specialized visualization and prediction methods), convenience interfaces \code{lmtree()} and \code{glmtree()} are provided for recursive partitioning based on (generalized) linear models. \bibliography{party} \end{document} partykit/inst/doc/partykit.pdf0000644000176200001440000041376414415225046016227 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 5022 /Filter /FlateDecode /N 93 /First 788 >> stream x\s8vuwW{TA &@0LķC,{2/0{[TʱlKSHFF*rE:̊D\iوk"q#\F Wx)"!xV)HXQ6!0xv4H1B,RHKT*DCa*Q1΀hdQQ$LdegYdidSPY8jG-Ca)TQ*,Q4QZGkeȔzjD F+)&H$qBБh:7xЋie|;)P͠F ‚u  p%C]%,Է R12ei8(K@~Xl@Y PVa.2΢p` ࢽh5P}62)nd(cxdAJ{oEs2"SNG*g`.)c&rc<4"ꐠ)y 0B^ &Qu 14>J c_8+Fb`DɛbO~;ă*}ɢ'COmq5G\d)F0#pcp0/iލib` hXQ*ʅ*yM\ͳQϦOFEt`+ߙc9?>Fwyq]]yv/wj6Ynoěexp'> >MwlsM.Ӿ]Uwǁfy2|S;ҭƠj 0dzmCv>;g÷ë٢XM1C/EboK<}Y65n4K<]c?&vZКEsc7^ބDP TwJيry+VMRT}:įDPY>P120!CR{]d'=Y51Г T=UE=@Oz*Ӂz`6-)]B<=}C7P)h179 TB$[nc!u3Pu|6> J>yϾaۘQET6$y5B єе%dXg<1TcN&k=@kd =/1^c%a0a $v0mXKUMŞp}55/ܽ{͇>0kaćG̗N~8zqrW'Ivs$:eGE|rA@2z !7KH HY!xWY~^\x 3u3Uؐ" JJiDI/΀(Y~yGTԩ?%'Y2J$O~Od~A@z5 H߮Aj~+>'(aWGٶA9ɐM/|7Ev/.nN1QAq˳U\ܽJjV5H[w#7 6c G!' 2Ƶ^"՜3B%N)jq! CNk6L@7aZ>0}*kץPIw5VI5HYC5*"AZW4W8i3wp%Mg_4 o =aE;3r4QTӥ. A%7 YrsH^&jk@X=?yA4:ϳyd1'_j4]_&|J?nG/ k`Wo)ؿkI66Hq;+/z(% EU/obBEm $$泶deʯt RZb?7/_6*h`lACYPPTFl$@J%RC m޶hd$1" R0DZ yk,7k9ZN`izx!E*n}9V$tP-ro6&8 GcsӞ>lLJ5m*JE=';ŀY'&TtbY{gTִB5]B9[`][?_l%Oߠt%U42(/S>.i`kɐ:YBn[Q_ur5Xqӎo͗Im6ЩB2_~^!#WQ_t{b܈^~xڜNFbgYJ *b{:fj0`ޡrdTxhX`+XXmsB@{ Xn4_ds3@SGϟ?4*ƫirM. JX>փ LV4ƃ5V:K+`8XX퍁`@OAX@zpijM맯:MK\˳FͻZ6dyݰd̗Xoz᲻ٲ\n7SҶJ\0V)3$I:xr_U~L1]Y4V24YR^aRP)ʩfʨ8+y)1%S b 9V&R,K$LS |䕐 U)^uAgZZ&u7*7%\÷v~ztiP[5~G6ѦnS[\,.ѳNoY'Vi#"faKBùx3g+"V,mtFAt^C5kti,M_f9 IK$uq6v}bXl S1! |7 gL)hEfiHTsڋQ6C[$7bJkϥp4暂LыBAKxRc?WqQ.:_=CB6n%1>)hKXP W؝}Fu(T_CJUYضt4,1PomSvZ됀N`еla8O{pZMѮ;n3̄&:S 3{?A5CC?Z|5_!!<{Nk;gsLmqЉö$E׾6}}{ k֞EK }"vJ7$lVeYLn%?: o?5a{AW 'm?V 0NvXPI缑 SE.PW+' zk'dž,9 rR6QnTFMcS.QbUWʎ٭ݡ!@V/_W;(kLӸ򻣳7OH\YPZ[vWV94a ۱>ym~ζ,LV- -қUgXio=`p|LF4O!O/i^|fQ̒|zHf7ٴŵ!8{5{!n!{ዃی7W]v i ` ;m J*bVf "wZO)օZGs q+yY?CĶE$-~2`$ZO"kohȒߐAGX#c|'6)٩.i8LJcE#.yXiUf]٩XSNڭ?J^2&O%2 n?9罃[4rq/޼:~[8_*cHOh/-V!r&JMFƬF!CܷA޽Y KƗu/a۬6҈HI2Zd$yũ F[Ұz+Q@ GLdxdsnTy4Jޟ~ |UQ,$'^'n3Qx6L?G|F)0w߲M/ijc:YIX҉i(쟘]NU1NS.0L#yn{wpǟr.g1pG9rStXXяi C6v.Xc(,?I^@YWL3c +H:مSYqU/XR@;ף8;MW"Aܜ_W^bh+ۛ>J,GC'ioѤtCmNem:}hO)\\{F-y]k*AJuOyog5y\|>sLMU^=)5|{j "6:FÎP ']\qMJ,4j=%8t}U&pXIVendstream endobj 95 0 obj << /Subtype /XML /Type /Metadata /Length 1541 >> stream GPL Ghostscript 9.55.0 recursive partitioning, regression trees, classification trees, decision trees 2023-04-11T11:36:38+02:00 2023-04-11T11:36:38+02:00 LaTeX with hyperref partykit: A Toolkit for Recursive PartytioningAchim Zeileis, Torsten Hothorn endstream endobj 96 0 obj << /Type /ObjStm /Length 3328 /Filter /FlateDecode /N 92 /First 846 >> stream x[r}ẈS.r\!)VJbP%K 0~ȷh"69ݧg=,Dd12-B0=YqTFKaRFˤ6O&'Ew8:|K FR2nc,euߐ)RZ;0FL+CmW %4L4J1R$1F҉eEp&j㙉&2&UhRk +Rsϥ pCx'0Hy~`. +F3=1y q;Ɓ xcX %I}g+X0P$ab!ijEְ8kY$u,Ow^%ptoBc}"G8R%F Wk"LlhLkc Q}$TlRF7qxS{tc'r^0LȲ5urjȵR6'AU1l1tA nC5 ȖDɞjXeXq1bGD[xo%bPrrm%\漸mmCh?i Sf-nc w6欆ctl:vX&)ɒXu)4#]G mwvhmfC1VfL?iNqUGnC۲m( ?lt!L-%OkK>;#v4clG.%w\Lnk3jVDX"? 01S:2Žv1ɗz;Dh>9I5˧ǐqMN]]䝨ߙAdj_)wjwshO-w5Lc 4֙(\7Nӑ.-r1}!Ci6v̨ܷn#f1׃LdNr+:׊UOh~0_bB,kցAA읇9V id[~kbGy("è&|xt00Jr^&]V:Xִͣ=M4qʤ Il mUk(^lu]۪દ-Qi*/;oeUIߔ]~'sSfkZ #f j$'pL\[.Z fWIr_Vj(2=[]KҲͿ"QlJ؎T²h|c>.!4Uv$K<;dY-e?l3kɎK*QҟtXY&=ʧώWezu2ηl5Nfß.`6񀈁;eRbcumRY(G$K(\5Y :()(PCm#F3mTJhq]èOg*iJP7k;B!rIk̩,D~O<59"џ<Þ<"lV4i*سp kX2Zyȩ5&&=c[hD:%:܋=aB0*ȫ@@8<8eQkPlt "g @YX`ȱ Ja#y4M1"|5e`:>KݡO b\0p# `Rd~ 8.q@!{ǔ:&,`IACTF4";^?(PRXh_PF_  e/9ED2HL".p J)VS@(:˅[Paߨ"w !k˝ 8VE$6HpAW2A2ҩ ?(qښW.Ԝf? 25(d2=gY*S`H@ވo)iI"m*LQB1л69Yfu[SŅwsL}nEG튍٬ؘff}Ȯl972*bRYf"D2*ʔ"2_.RLx2/nƋ(f:_~x{Zwղ1^]ף u}Ot{{8;RyjN fQ\6jxi VHt B >Cj?r?r:`)TpkS-4^ i!4& hϦ˛R#V>CzUiMBbg ' @NOz#>vi Ì-fhj5.j(=oglW\ ^dwZMh[ClP:>iϯ]3=֩uA>g7<]|U-Uv/gf f>Ŕl3U[Ir'NGO~qzBl>6ڻYa..؍#]Ll}io2o:1mS lEwyD/*5U}7a JtzŻʧ^fD6!X5WF9kfI6&)r{i&ax`%ѧ!k{JX!Np큫BfNbF1&\nɲ =Y~>_\`|v3lD~RnQE Mj"M MAk/Y<JNdz%R6:;k5tb0vG'V/9)dM|f6ѧ 7-dPˣ Bl+ҟj5`r9osP:]}ñRFn /6ēӒ;?pbh |2|. бI:Z(yQ#bO9$(j[@SOwTJUꏊIO91eendstream endobj 189 0 obj << /Filter /FlateDecode /Length 5517 >> stream x\KsFdfGfUޓرgTn J3YU@%&7zdˬ8mjqۓt}ljӯO|pF>S rɦ^mO~ޮ1v߯wTwo~_t %jufz:SN|aDU v**X;]_}zl&8#LMca@SNVݻA櫟VTt(41T}n!q#Y LaVо[S]wۼ~6WGȴJ Ud\pO%=l% _]G'ى`]<#ߝ|4`*=`"V?ݞ)?7'8nI4* ET=}uE:xqڙ0Rk%FP. 'W,VJg&6, $L_yC'mzӮ~t h~] j c@8vQ':!^6ykF> rwuKY ^DmAŃr۾|Vc cAt/M1)欟#K F;@tRrID\OCu8@HcAۨr L8 5zPpvNwtlQ0mO[(  toQ-Hz͡kIa*JfehKm@ |j_ҍnVpz*6q\M۩GOiS"ٯ 0-D aw2,N:t6VNfF02}k`_YK 2V8vp81RÏF v`SY,ԜGLC R ]]U0jJ{@DJ4Cp离g:E*zq8j!iP}pC0 j-eB=Eӫz+%/VBD u-]ie@2Yx\ ϟ\hKAi*=4Ļۉ򍓷@Xg$ր:^ؽ׉ m̒p%HZUU^_E8X@P70Zo 2WbWG@\`j@Xiӭ'es" t0d >Qa2hG‚fVB3EeܔƴxT,JLaB02&7pI۳J!RF~L%1x)RY[3}˫Md^E,_ kۈaLʍC/nMY':uQZ)ؼS}MwdZmwlCQz*(1[@45xa%0ހ%PTXf,ŢMǴ(C6γأAȧ9EZ?"it-hN&xJȣ9S-sCRN$DO;벱X1~4ދȻw1R2ں#6RyI*+v$ 2}&p1ױߏ^g(g.>AI4ҋwgo3t;#U ]vIf|md8UNm5]P!E尳~w~Q΄sЧ[P:s:AP'GFy6ɯ1p3yVwGm4 S‹co}ƑbRMd~=N!\.E1?[Я :?@e%TccܕA+^@ 8+ckunQAD7zf܈x6Ɛnăewf(EI@;oݳ~Bl3NV['mM046SƼvmi"0tm91r#9i9=dL-™5c 5澚s2':ZD,Q:QJm3W¿yn )!TO#xR#8=é 㟦y1I I # F㼹p|IIb/;~SjD㛘+UkkJ7 $fEck-YrmlU3xbns#Y@W9uXG?S=2i4c=;5<&VybX<~&}A x#Z,SA.#LCA㒾L㡁t0 1}QDOrHVÂXH+ny6?nb`ڳdۓXAP9861E[;k9^2yotmPn ݏ|yl'>6"] 1֍Ȯ9Ͽ|GVaR8w-?7 Pd=ۑAS0F1R<)t %of&Sb:G@#G{%Q]㡭0ZFfJE8ho/nt<<`)#%XMh!C 6wX?Er}@ U"hs | Jx(E{(KM6LP6Q[hHm@ǢK䩙FPmbk#03E,zH{=bi*/7EMD/CE5a~;VH%p1XnO5;>L 1Υx#U"@+n腈Jn5I_" t>1 x-b旕+ę%6 h:DRrFZ(VdRI&6X&L0!\0wJI@>RB0O/m)S5>33ҹx!ޣkV<:~6vpEGE0WaEGz}aG3% *}z>"YyE=TS1~5ؾ42J7]9䰻I~tAJD /Ib%u-:Ie -"OzZҶ(xg4F9`-~-S/Zl6NF $\ʲ unt.F3 9<)OӖWܬmf z~TB@1F}0( &xGtCfl.2%off@)Xx}҃EÏGI x2ÝYq0dՅOc-k> sRBMk$uV }uyf>M;mF 'C%j987~秭ރ+ݲ7lTjo\8%B?W ̢}w_w)62x0h` 'Qbsn:l?KVBvd\fvj;~ڢN[H7zu~ոI5c0>׶蝘UǏVĖH72> stream x[Y~'9yXŜ@ðO6 $@s9"0ZӚY*Cgj{ !yU /gٿ΄>]lK%k\I1ud ؎K{^J '\+ǘX(ơ?8Exմ:k~ﻫbfhUn{Z|V "`uq|饢LCT%7";CL0) JF/"1nјsx#RMIPS{ 04밥U"h dHkDZ[1 y>li>.V`osnk~rc5p6P,C ! F(1,^3{< |B|_"x{&iaC϶L$ڨ2rEU1t#\zө4w A5`^,(B-iI%Jē,W#xuAJIL1}FS'pjBA-=xC + y CuKū/,F\hWZ+]֠O">!Ki8 612"Q DNPr. :L)tO HyM G߆@3vn DJ]G4@fYkWV (S_|t;@vF):{ۺ w^\͌T/ZcW((ى9˛`z/ӗՕ]$%|ն~V8VqE啺MO9b:Ɂ-]8@e&6^c R_߻7979Kn?b&N^X!Zi<wZ_ =3ߴ7,%;-tvCK&\pdJ} hpv0X  TPw:%ℵ,cxCl\=ýPoL NS2)_#yA8gyI햱ld^b-SJE Y409Z]܅M*QXKT=c!\UUG *{.@ dŐ^1%F\Zz;#c9ݿ?mt-\-]nXE2r)%B2ĵIzqS> wk2f/*"anӨq]bFxehe" &va=2u_JqSla 6vI,˅[o|F:fJjdԊW0RLr' ႤE״\i`nˀO7?G&j#(ir' #3;O`Nj;eP::J8<)Jn16j0A#Vv.E}ƺ!"ն ঢ়TGYۀN3xUqZ?0?ΦP= }9fHxN荜C%#YYNӜ[$y} Bt֏T<,#2 ,c;<%)}!&au |h/Xvb~ CDMj"Q NwQeK@UoXtQًCCFib{&p4\/v%ӔT6Ӆeam7QɬĜ,cXt{3& ~҂ &rnRFX iwO^+Fb[UZWeAMRCz9aȶqNL|*Iu)T'72ѾK+U]tR*)k?>]%6T{z_ZC,eRDY5+)Z"OoBR-3x&h'u 0ռ%V*_utf}X14v yi0?/<rC9\-a˰蕬?цOPкcdkBD g䴪fl ¯ehU>z⍵+~^BՔWW=0%sWB+ ZNtkGՈ$@;`t\Tnw_ Ϩ.zFZ-UWRΔipJE-/lFtX5ߵ\PTQ, 4\w֗2]||&ޔ`Ҷ#Q{oRKKzc?'BE{Wgv5TWDY˴|=F$蜒 0N9PQr $§bHMWtoA]z'kx̗@ml4dp iziͦ:P9LeDroI|y@#Jb0$ (BR ޘ(F?̪|VTR3|VSzP-hubk]TJ5GP:Lcg*CŒuJQbBj12f*C}P{CgVJ:ہ¸i1nu%}>)~;Uʏ!A~O۰Y^C6,JQQ;ͽU0axl97%ZD<d 5ZuHXRfZݱgx'c⊏bZW4C $Yg>؈Y$upSqޕz?PHX~p`@pYr:*EhY9Ծ3FW4j>\,8z2$S%1L'QQhU_F1AbQrvVXu tRhQM9ГHdʄĖ)0ͨ5Vpn*cبd ,w{ )*"g׾}v =hH)ݘ^PL(QEm~fSd^zo\d'6:{*A? ,:P#R@ +]'O,C+tF[F$xu ßHPVY_0'YǷ*8lNe-OLn~UªԶP~B ['#޹ny =Δ&?}^\b5!c 6fSÕAa&{i{`Ȍ[CN>Mny ?_IFZ$f}E BC>XC]/QJts@#)hxzMiV.D ݔ 呂ZަuE#~,7?)\kRBWG~l W Z9#׾|fL~eTWPqG7?TT@@ " 1U^HrV܄\/xnlq w~(M=WD+ų_ק/ݳ)1$5jL<%~67Nendstream endobj 191 0 obj << /Filter /FlateDecode /Length 4390 >> stream x[ێ}S|0N1r8^ @aL{whNuOWCɖ!TթjkM|XW:K?/_ޮ~!¿W6ƏVupaLַ7"eD: mԨҰ{wKaw?zMYn7?iZ璅G^e?_ǶnAb]ܾZ ~,m q4fMG50*>ܭ~\YRڬ'_?Hi7*n2J_a4i}faH>*Fg4bgq#FfaQ1BhH:(eX5K; ,qEG!0QK%nR3EF;Cx DqT$8dM;1ZduYby5$%qbKp`:l勄7NmCLc`{aS*#f y# 獼"O42Q(5'戃Ió yv$>A$$glTc64S1Zyt݉$@g A%HHF&vĖ3(@)LBPBxu 7$&u )ت;h|i'$J0L:9$n}۲ յVI+*L'%u>H!=2dL# Y>;!>aoAa2] 14-K2 \H QHJ#&YKC5$β$gƢstYN#$77I b꒽@Ԓ!Ԫ [S;ςdr/jlմZ[kn"jFӰYQomX 㵧<}JmN{քk&Y_}rAj&pJOP>:8jؿ;?KM?g)hV?O=eLkAw\?(loBOٗaX!P=>n Oq (y5sJbVYpڂ?n C4^nEdN"AR|Iٙv&6Zx(ss5sNUlN~MG`z}3 ː87|gNAf ! Auu΍ԂXX A/[!B},o,RHw, T71w*[&H|T\Uf45zlnxĭ;IM=brQ6FP pHe-lAt̝' \z=>35Dg@֠sU(9x]"lʚXUAv16%tYk4-I3Xj{đ: ùK qf0ArUH YE h(Of5Xn YDn[ }FPHGa2?n87H% wJ W)H\w./Ը ɗYJ>{Z}5\_$Q3I(LL VSVA DLc|\VFV$ mc#v;e\F(MeXX\5+)9YebI}mIDU^Mpd'@tHɐ}-Rz^)OrEI)sZ }R,RPkJ,K,tK &nMj'IJCKKcl'# RPI(Z&J)!Fp CU#Kxd,3-rK+$̴UmuHZi]nsL ~_lnd?L %R.//n&ҪydmMyșuS^=BVE/W^߈jV:=h{C~ߢm=}wmtq sSݛU3woǪxql]շq?$-.o{ڎD "˵3ۻQʴb7.?S9м 8\| wћP]f%qE^|R6q_L.Uk|.5D)zx*'+Q7*F}\Syb:[VcgI*;+Jpy6UL̛9..G3qE+Jˊ|D@ch=i=?cp8mt~&)Φ0,dW֩J#|eutX:<+7̻ۮer}{3XUSg(W˗ l|jS?yem͢jj}gL3+Ϻ03sXxx3im!-5[*;O|9?nݶN7ޛyEi YV jAn7uC86,Ǻ ,)Dwm=w6\gcάyg,G\&晣[ebjx ?յũkԽ͍5GJ{쵡>;F7fĠ ;vofh}ZB\{$OioU'N?`Bj54b?3T&U*,$얼RҒ\o37Pӧ/<<  UYCt>]|;κ?sm:\ly)!b2:R+jS (OǷPD"=%b6Oog_W14Cݡ\e(78qn<2[)n) ػ;rrss#9YpoчmHUY~E/TN%?ٞX[qY+ߣFV*eQw 1;8~~N᭢Mc o+gw*@֪KK]k~ޙr$`ǝ23 ߼ŀjH?@yiw8251e~8ü3+KyJ~b.ͷS ջg+L&2!ȟGfr ٩z:5-um`'kSLI~1|+M\O mYv=endstream endobj 192 0 obj << /Filter /FlateDecode /Length 3463 >> stream x[oܸS{9mVC[-]>E:[m̐HڬYI$g8߿!목٪fusϛ|)5]텟V2juywQ;k]62 /wuS7Jָj{8&M=uwH)vWk4&.qM4zJFW!gzyLj[I>$#q 0]57uciUǶ wU{,u6 uÔFjc{quUzy˅WZ@T-9hюPa'ǛQe S]&{BTteBO޿Iv^xa:V5׵R̞(T"U~ߑ&էAoZ Hj 57AZP|g+ g ]]gDm^|<ӮzF8H_‚ͽ˙Jlq4Mɠ}exC܍{s:Dّ-0g0cp >'[oJ*((it#T 5%Ŧ- j8,}8}i} +9}G+5K"%Þ퇻v 1;`0D`0/ĵ3p+2nqLO +sr9~(ZG ėŠW»wgQT!h.\Dp 4ZJeҾlosf72LH ZOn/i>B|PLXJo\0*}h> !XޠTQ9uFE֕vuj`WO= cp0jnz<\Vܙ-pOdQ)'<*gخ&nB*yvhSCjP-FW$cĐb]3Ld1#ԡCtRu-˓*{~wCztU|̡$! UAsa5(䮦! ,RK~H?]*C;K4KBO%nrƇZ1C&M}Ƅ82㾻:3Ea/&M$t;V6\[ppW[+$<Ք!lv{ ֒6`'*e1ckm&tIWaC '"{{~q݇j10 b律I`hx\kn"X!AQ_<< %7D3u( Lj.'Ut}(C2 T֧x}% kᐲ吘eP*jCb \tWyHv?S}n HRkfBFdƦu@x_Tl?a6ϲk}'lfo?OQO&@@s7@F\[n_^ެrBUs2m"mmK1j"> R\-oiL4{`QYYGrw|0-㷙G1v׸ ^c#߯vX'ͪrnQg ](aCan4l;fF\M=w (êX]CӱB@S$ڼ1Wȳ,ufk-DL-4\؂uȠ̕6.P&o feBVJ"z:VIAt|pieL4~C0k ˜}@ kY0>1chNXkhS"@huO4Fp^ -JXhI9S@ה;>y"-v.L28Tb38:`! `fłwI3Hct_O,vNr#IF3CFS]JZIpmlA_ȵdj)ŤVDLSd  mv_MPcRt.d<]N^&VYјgOCvF V-i_)7ﳎO۸ l3"cbx4lۈ ,4\d[J\_3Zp*P,É6DLn!NS'kY^suUqU~ }OY#DyQl֙G}q'|f 7t|b{Aت]LGIҠC;ϳ"Qy18wR-AH: O p<!wU00{AZ]tId! ,{)?ᰦ lAX(\_Z``bbiK_<3YV: S4<,wWA~dn)bJŰYj8Bhx14cB(k j0'EJ~ Oc'Mu??7UJoA4s9<=ޚ|bby㻓nh bp@q] /(ϕο鱁YԹ9qlcЕnd@1lL<(XLvev|ɴ 32gwֵxHU7C`|lL:MxqŊP(藋dpendstream endobj 193 0 obj << /Filter /FlateDecode /Length 1825 >> stream xXm6 _ofZ.b- Xܼnf;-ǏXٗ+!LE>z)e}g0i9m`)/w39TDP{S b3. ~Vƌm/j0EB_7Dl}p+#c<#ݎMK 0DTt!հ2 Hm Ojɤ.bbf`_[}_5ByU#E[x(5Q:Kf9g v lE%Q!pr*)Abb˧n񈰖 n!}Qn} $ pZM Ku[b9Isrg3uAT@t] Vů=i,,ٱ0Lc1ŧV/$sr̜;FddXB@f\A&Zp>v^' 4vȌv.7 -V(I[ھ`} =m}âKˍoyRVB}r)ʂ\bCb+ @̹}Tq֟?1qr`CYyo1|p[ IR 9Dj$@xd,`aY {D4/W1"8`DzV>λsp//y㦧aHq][Pp 7NYBW}U}4-Pn4i/zHw_H7]}i;IR.J㙢_HirWSoq5׵Jy+u#ɯk 5>OncRP4jYT@MVXLuM?={zR"B )RQ}=Ľ9 {36E(S";<'F`Pfگ0ES<q#p -/F09If?j˦r=iQI=xY{hIK٣q]āE MÖ*v օ}9+&e?ohـuDK2:w j2&_;!)Ø.u3$W?7=S|cm C̺ tE?PC=F7U<@vH[,c аf&3[> stream xZ[oܸ~䥜"dPؠ]t- ;J4GRNsxѐ$E2s΅+_xUo>_Qv=n^__F(xSݕB7nԕrs}"j{2 yU-%M?nj*49j`?KsSimjBTu缲wvI:Ե!wPRՊjj L*CnӇ/ ~uGr%2]՚I/h֔v'̒!!u͕WfeeUdO I2,hJ];7F~(Q2nBUjtHQ%+).dU!?Y%<Lc<<32:NTe dO;MƯ>FQ.*ƻ;b Fysh~AxxOANEad8gwWbJ1M@ M;'ՎYm6;+),3zpN8pQYav! k|THUU%R]Q⚰Bl(e>N@n9I]i *YmwjFդ8`Z=ʩC;!ܗr}.el;be92?ސ@QRw^ ( ikք-`&0}Iq`x5 (xu.W<.e5Dlo3q"lbW4<;$6ç2nr%ȇCl(nLI}ߒے@/#W*;%`CD B *r;`vM:* ]KOf">s=8@37dh3P GQn<|)d=<)! `qJgozr5no<(Ah |NX2 CVE*3{4C{"!x"tl<2axme*}tJ REE;n5zjlkwz%{̙k\ToPƘ{!,8})WԗpSn`yXj)2Hҥ95bRVX2~0V*NLmdf qJpùQ(t786OYY4$Nx7dac"yfܐr<kD#. 5S f#>^cJMP}spyLmELoIgP\1܁1:fKL0',"ɲb^e?[R7`Э3WCMs M>#\OUm̹5h:<qϳhrk'VbskCBX氐_̘&OᷙCl$) @)A`qr?K"ߕq 2%0cuz)sφ)h/C1йs#?tWâOE22;5jxj[XޔpBLC]XjR>ot Zy\AЌ~xUē2 T0ngEL: ~~;*=73>}:+޵/̷I %FNE 6w!f!ͅݘ%16f}aL>w87kp:.+p].lB+1ba(6HkJPy^ Dž{>]nh?V\ gypoO <PM^fvps7:"٢"Ǹm#;l= $F лQa+˪cYv₺\$^ 9[y^;k])ϺD.È}_AvAV*G 6 ߯gMT Ҫ]Nrm?LOc)oUΚW|Ңf߂}#e-eHyS=q#?%~ '!2l- ,R軐-DŜ_uTݝLLTuWZYBݏ N/3o5}})oZsl*3|J2^k|P"d$6ݺ%X~3+Xf_Z~1Z^x@V_4M~l ^ cERoi~tH>`bϵIU6/˹/X>A:}0/S!endstream endobj 195 0 obj << /Filter /FlateDecode /Length 4036 >> stream x[oܸ{Z D[duH =EW}V7[)ɹ}gчP+g~˪o~n[]/z{K'.WpQjs<{YV\^.6UYeEo++mx] ølru^leUV)Uz/jQ64is;U劷ʧs[|lvM}6ܵHXxXZH[VV ,`_5|uط#"I_lһcޭ0\n)]]8$ȜDVr$5+gˈ7+$cd.s'Ӽ=sRÆ^ưX.^iUqpR;ųWQ3 CO/QT42qiBڨafkES+q榆t-iAfE44 G'&?wsŜC%-Sk~ m6ƁJ=ɠRr+@yˠfQ`hsh,4N_qqW? vǠ4]"(;V˰=.=H璢t"JRGПM߲#jQdU⛀\N ~sAWMsHp">dQzmF肌q}KzvWx]爓(y._b VÓY.ΆV[ܷ 1후e&@]2p olKLq9*%Z"]v( .`SPK5HJi<Њ O`{)#-liC~vLmO€tgc WUk&UZJG#.K-M4Ć& oF(Z`?VyaC.ʾiW6metZۗ['%U W{!Y%%(xd4Żh~*+&9呦G;FrAEKD‰Wn\#@M?+C %=+.9n8q+>#JD,^F359LR )q,DDe&IN4QQss;*n}:sb_Ol+zߤg1W<زC< Zԥf97D }`gԦ7àM3,zv1ˀʺQ(eVa!,gj*BJP&L2amZ@Km ~X\٥bTqev%\2/DIif1QYHADJ,8ukcÅɊχ DkY -RŠ%[XB֜d@/ ПJE$ E[LhXvu<+i0:zXؼ:Jз=-pL5>~o l֦K8U|\c* ;7Y B0=S ?4SF8RCz Ƅ?3>ΏaRE~In2-+mT[ ɝ5dq) 7'jU=P^HvqZ|F>iZ*]ye2^X(笴-CA' pfjI~ ]Z.ŝYNX%n@3޾?ޠauGjqyO a0H`Ƅ}E ρĠ .xx=:‹ ?295O1.(~|V Y~*3ªZpGޠwlG2EgV ;T&UF \je,'Lѳxr(7di O*7i9º&Wp4h%1B!&ܢ{wRH@]>an L~xڦOQc\%㵲W}s? D 2Ti 綽wgJNܼ=JPz4 iJ5vے;=2/+8n W $ZX~m]\rf\EUӀ"#lHkyU?òp=U,rmBCOzj*Ϭ $G /:B#&$QfJOr>2)T6%@ _?g̹on\ِv-ٵNM;DMϑIX;7mf`j~5t'qVgBe/7h%ç,ڟXjjf IAfi´ 2̒ ʏ6Ԇ!as;2IhПgn)BKY~]D&.5 _JK=э >.'mtR8uC S: ^(}jǩ#tJ~'YkJNCGP<*/EpAjx0 Q>wPYxLfBH@#6"6!c!!^AaU-22zfjJ*E^ >+w`>3g/ƇD0vtJyCFD礩JͮpjyFNLq>pϮ9B4xdV~""?xQ:޽?r>~=$U۞he(6TsvEA,vTU,PN.o渒>5DXAApm5;1ZʀtJ6 be qNI=4f3Os#|<15Ʈdh*GΡ]3ůԟS[b+ЉNc7ݤ5_c5-> stream xX[oD~g~Eb ]3wϤ VH$U%1]SIϙw"PbϜ9|8'slU=هsoU\ξ} v涐92X Q䚉2 oqOht VQUg (&[/(PK_'Nc2Lz/'4%{#E ^4;}i˟.cGƝzɖ̂s2_0+)]Vk#JX.stNf A9́@|e_mbrS!vUo7/_’sǣӶS#op6oi\i5FjH,iA5ښu-*Ʈ3)(q"tw:7q re!&Jb1 '0)D>;Y¿EEBO2ŨMb ڶNm#c c M*)j.#(K˄0 ebu&6a(_ հf"XC'2Ph}P _sC<@q-IZ>eelc4.Zv?XɋZի nAD2e2KA )a8viby0R(rl'Rlqg%t=)` *9cj=8Bejxn!%[bEGoIt#:ܖ*wP a17kJdq MBn}䒍!u?`[Nq lHPí ~@0,H]Gua.رwP0s`d#s4[`ḥ7Ѫ{|z 1 Xbd,A"2"/ C3ֈ7jendstream endobj 197 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1596 >> stream xuU}PSWz/#&Qjݭ Zk;; ttJ@K— $ ʇ P);Znv^vufys~WBR"H2m{Mm֦dK*LȣBDH ˀٶ`PJ*I'1ؼ -Ѹ{)I$yu[m*K'֮]"鷤 bn)כ%zCjV~F,fL{=/ssҲs;rw2MBj_Tg.#CrIB^&d=1L1)P?5:Gy^.bGNI|w4ZuW2>Kǹ𶐘|Qn WXn*ÍMPgr&Ob<߃PZ4^3::>8[3H4&`3951W1_GQc.{ZsZHFbuoQ6e)/ %V}T>}2Am5캡= tQo0TYP]ǼRcH#+/Y{pPSr ⃟PL]\Te7N6Fpy<==pR9a.YkKS3b;7p   7,s7bN`׷ᶆ#0BW ]ZAInj<'b}׭zP|?.W WLJ엉&;ٓ"`| bULrc༥ƺnm[aM |sn_ÅЮ!%w监+x3-fx=Li&J>a݄{ǭN=!ŵ1F!p#g YH#ʧ?~P. bMS+}=ScV]+Ha8נ;MWayvwu.Crc/9=1CHH[QQ !厐qOgõ|)"p ZPwfvu!{.7\nvءnp-\Mʶ~gRu}KxVfe1e?RDݕGD^">W]n4F>x $h+7B4 oBc_Njٿ0$ýX M4 o`^4Na,|ʇK/Tzh{^{Nu8lWEo,7oendstream endobj 198 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4580 >> stream xX TS־!$8q7@q#V_ն*ZSQq(2CAAId"SpCj[;Xェ[Z^}-}[׹J=7콿oG0dy~.&ruj&'و@ A /OR 9╉<L`I@H})qa y{ϟ=/vNqn]1IAѻWBL w=fƐ6X}7<:緇03ٷuy\|ªDuRPr./>|ƈȨy_'?:G`Of-Ϭcd0&QE&YeGgb1xfcˤ3$lfl-=*vmL)9&,{nG~'njj|q8o 'qbccoˇ9y X"H :YfdpRqҥ=dC"p)*q >9 !S[ &S^:`--Z{s2f)!9alܠn`ęQ܁gXw`MKf_p6rk$Cb,J򮏊5]tY}dn]:U@~dl2mfI3:`:HQt"@*篒EGuF uq p5O7|iu! 6ﯯ7.L3>܄n_W⣨TXsRepkx5kKP҂q&ZeUCnS f!eT). Y=K&i{JA+Pӥ1V`p]Ho9Y<6ZtCS%Vq`txoӿig Wњ۬:-˛/>%K/ ~򍿾N{'^p"YTxYz=_L.*&KҔĎ.X aRcbqcq)\+T| O.yEotvt @lKӔ0a]E{xC\ds3Ss3K!+[ YGJЯ" /]dq”<] R.wIEqk VRx45l9f߶HjP"E>.dr'a1øĢД,͡,zG JMeΙ㫣"z^=  ]qbZ6I;-/+^*Qi!tVͥ48E#:sE}z2'' qAE؂MgoLf.NyR|Ίt%LY5CNx2B $;rH4bSITZ?Kχå'zύ3/Y-H; G$m\V*7h9E{3nfVT?9ElbFϩ;y*s2޳^ڜF&iiW6r'ż{@n#鬘yڠ3 |~ k < 4l.1hDnqvSO+5sb1bץ0AARBxmvj3w1 d0f W[kėPߤ2{uS#qgw*碫M]Ǝ궪5J߯M6ɛ!F`-~0"TGd2Pt'wPxQt->qUK`56~?1[ C2]96*@hxOZ45M;YEGpo8eq#J"Ql4, O p.*ES)z9~S7cO򯒧~+y6>'GEWxsHp]-[cg,Љ>7D/q%ԓ.kr|mĹZUjTlָ-3(W=<"Yն! w5é1S" fJMz8GX\"mTk}] =V"?Diɢ" d?M' ()99c 2 )~~78 |ނV Pϖh98I5!Ob :~_VRZ|*bIba0seu9ٙT:dLT䗚jiX: Їي58xK 3 iIT ?Qw@#XĚ!2zSAcPEA7 a59rܟ2dw'S8 de ~@n?4WPr[jI΍$Y0t\˥$ BTLrɴr5!Bxv Z;dU$tjR&hе"y]&fZ0-Cj5WN~ J? ߺ{ąf`ms[5Pi).o&+1XuKD~uGYObmp@ye,[oȋKA@TxȉjQNkZS Gd\N%{Fy 3.μ`-LQe2Z܍2u*\u4m LCs!+M/ؾUm=n;3r@~%|=Vb2 eGz>aO-G=G^ WL%Ǵ6ڛm q/9_K^K"ۼ{`sdGK }i~CԙmhO2Jb*\kK8ڢhQ~akSMܤ YTN*"~E`9e~[_`S뿿;:覈J?M(J%w/8ڢOiiDbyLnGvc8i5MƢygMŅ< ?: }endstream endobj 199 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 8219 >> stream xzw\W ;cWƕE,vcQE]QT){,,{vR\{h-bILr1ysEDuD"Ŋv~.S&Os u !7nX=z!ck-eQU_%{- j=ui&]O^+'Z [ vur^};{vߜu@Q 7- z?xQ%aK×E,t]rǶU=xm^o)SMfΨ9ym7&H'NQ0ʖNަFPkw5FSk1&KQxj#@mR$j5ZLMPS4j5ZN͠VPoQ+*jeC,(@ITeI(+j5BG1v;ՃO]ޔ?Շ RD=D=){iE%vO|lY0 I? ځ62K:A9gJ{+܏Z7ZJCNgrlSvJ5h٠!H̹tY[7 V>ᛇql9F3nTȨѾc> `DQ@cm 1zn.KO͌hP)c[w n;Ԍ/*s#1PhI*!9_Qw l) 3t˼6NG77*U~Ւ ] }c|f s_ZV&9.됙% 8 G+h/_upkw >@ލQ?dr)|9S,{\z2||9ut*<g=.ė"aCöo']i&sx$RK굙8O|:y%+]~lIͬ*f͞N\"ë~^Ts+} b?CQ %Ops stTx0x?\Fh* a_Xs3wƴ"{ noiT7u `Z'["#x):ZH*7j>l<[BY 䁿/4ꮓ7uhT1P=UN9}t\ZXԯϢŒ] (F PƫD9;dsac@(\kWůknK'* ,$6'p 0W!vۭ rL6ɀtq5%8㉡WirɇRMNXNrqdk/* (?a; mr3HNN&XFtjA[R债}Ï /QA1F~IWjdBGoʷ~Sxȗ l?S2ŧBU-<`4OCv7nW- L6d|9-(hEOW";+Im=2F<\(XӃ%~o0a4kk%7qk_:E#I$N=U|%ݨͽU%^*p'?KV&X|=˂A {Sh iAusUBdȪu]rAª?'knϻVMD,'d1b>ABilRB$$(F,6Cu|HjRHn?/} ҔhFmr>;r%%ˮ(wE#Rd|Ѣ-Gf?aȻ3\`6O Kޱ~Sb<˰#j ( ö8Ynkr,Rw3j.q*2E%6v{Sa$0(ڨG?(!59v2ΖAu)yjT7Ct;mԜte_f ,ʒ^KPHT> y<dD?Fُ)M!\Rw1D<~=<ܮ GIOk n=5o, E[))KߪW7ɭșmS~'U8ҕ{r|jC/|! ;nrm8z.A w?C  4ͼz"ڳARA,TQSUV룹0OCr6L*TX*HIQ8 g* @2B]uGj9ߨǦZ.+-{4%/I D~b~$%;{;ad{eD/?8|XĪgXڄ"ຎ HdL=JyڈNV Œ@[zŒu+_J'-zؗotr^=M,1Hr:|)I*$5(HU`~a΃ B@ 4i(7? к蘻*pH ?X] ;_DBP]Ҩ!(uXQgSr] sW:+] K&'*S9S 6ۮ&pT'cw̤ǒ~$./EVR/@o3yMީaU Mtz.nwG#2Oӱ+qwd-C4ȍ(IPC>%g ˟5@eEʣ/Ũɣ~oa]>E#Ç !K`&({B 9nn+O|x$94ꅨ/G $3q7PEg&A`&a:]+E**,дO>diŏmpRp,VԻO\='!\37aܘOע>On5PíY9C'-u_U5J՛MMݍ%D-S+Rȏ+)ͬBLI!P381.4 ZSWhyY5{ C[GOoZt=Mu9d3x=jh_H?[ EO4r x5tps-;2^P4n_Ƒa!#+_0{K1PC焝9 ήTC6h86zYr<_nI #',-o>wY+5^Rv?Lfm'F?H^A:i񿜱 !5zt@Z4rcD[ X7eQ7կ-}\ybǒ{x4?|Ӭ^:tq x/,eΰ<[N)w U|FiE!o1y<.G[ eV}ֿRwXZiuh]j \ސ}#k`Do׈N_2ZqY̧URx2<([Y$鲯p dz38]m6jjT$ίֵe*hiCg+Pr,ڎ]I5A9,ܸ`#5'UՍDP춷L67Х՟0nFjYOP7yRbѱ_hCHnf f,O 0|z;}ADp(j46eI"Ms4P@(Cbqnݏp<7z\삒\m5Hx+,y5/|zDw"a~hLM 1KZ}WBq+1}.U( "bPmPWy|V{ܑə,q-Ԫk%nO3:۞_*Uh)%y-2].> @f2vGFEΫ ; Ji6 <9D>֋Z^Z3"&^ԩjR 2?tQ' tLfrZb\öq_CIuGG]5EYwż3!ɷ>"A}%ρw`^ڔ޾qNg~ >gfI +o`!{yx2\:Yz~mzU:& a@d!B>Un?KW6[| my*7l֗|i,'||-џ _[h>i"w&%.%r%dĝ? ϬdmLjt y-UQU^Vql: ޞ-g?w6v%^e axZ"`WsW#*P.Dh#3ڶR;gL;=n\۹Zc\oTؔ5ANrUDuHj$(2/ӴM1NYD_șPE|uk8L@̈NP CV|c/*.V.\㤎 nw9/F)VInnu{2.ڨGwPEX}S$md#oajs',S,O^:?C$gS@`*"aSb̺Qn5sKy.Ej{Cb SHrN~5+C4)^`#h+;1yjN;PY㕴UΖf\%_ =GRǕ =r+*0(8 'T~V#6&'i8*&)=%=g ofBVqևaCKpYةcb #J~*[N7pܩ/ڕ|,<&}i.Co)$[$OHa3lgxw^YunC sâȕx$$7WFˤ8E@j~J),Ʈ늲/ef܂|M$ O{c9ǃ@wSSY'* 쿈#;Y:)QHuTȏwШ8Y|MG3Gm31Jغˍk 6X?0C\32/Bmlݖmݕ ^qyC*~|Ω<Lh|t)=Q?dQwH鏦̹:<MdvlC[pgC â-9zII5'=>txh (yb;2,C:ܿ@/D^rGZR_R[[YY[fE{qWc|h皪 hƻ*h׹6q XawbnoXW9CR7NWXi XET!Ŕty?BtN˓~=)֤h| \I "\?|fϓbo~|vݖ PAX) W:P(Q-%kh#"-0e}aؙqyK1o/MVĤǫ8oc!l";! -'Gǡo`']mJ׋6\3}^W;$sMzL[Haz~A1K=z]ԫ;h:.eheh3t:]zFZPAendstream endobj 200 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5541 >> stream xY tSeھ!4\AF^DDPaDEePjҦ,m&ortoB.2 n8?:̗E顇{}}c<o-S-ؐ$9390?0iəNCLE)(~%IIK'$fZh fEZpƨIJND<+J;k- gmMogKΊKJ?kGY!Cf2Ok I].3kCƜMћb'$nHJ^W?sBMbK;yD( FsLNeߪ9 &W[@ĝi%ڲ*K:\:K<o Mr1S dDK:|5{3GƼ{-:2~Nι#t?q*p"H;v26&o>m?GZ"i %r{yOcޕBC $Ee1yUm@Es.SpsP⡽S%5z'Y Yz ;Ј@c+_~9>=,D JGŽFO$Mǂ t$hwdXJ)΄(PМ`(\bbbL ҌBC'4c2l'fKSi%͵7FD4ͧ)z"=2p'ۊnZYk҇6k'A4`.J&J7ѓZp{ynwG|og=. Vq7C>:f P5uA% 6(~GR.h㻷z9$`-fn0ӈuY  tz'Gq=5;WM3+D6Q&$PִW)nz[蜕yAnғr|b3cib}>" >=mGh|A^B:^`B.0zNCb5+9'nw"߻С~f17rK&u﫨SKAZ_ҠS1 ;>RGVl 67k+1*@DcTɠ%b`HJ FMP =bi<Z0,G5 {6z&gFޗveP5{ChZeTa`jeJF%ܖT.k)gX)N@ ŴXx M;< ӕѶsȆ+7bDJ"Rioj*޿d/Z4T@dm3+FLz&mD{!F2;?:+L z ~ zcTYU1IϾptpfB*nhO`m*sp+B8Aku_AwD-.S}Jɿؾ#h*.WlYsE7E^`'{waFC1`PXnn:[ڌ\9Yd5 PEZ&uv:T"ı9*mz]/+▗_X \GXۭ֋lPPq 1Ǝ|׃؞^Y΂S 9j3[Mth4;\:l!8h^ڷn V mҊz qQ*a9,N-So;s)jJW!WCaad@LQ4ĉ9]4GODzwJ[^ hK+j[tyw~L3w9Ez!xFgrՔdI$Gr|.WDu>JІa5,5Ql̽@;/ \Uא$s \%Bz (Og)#CƟJ!4&(DWt78Tܪ]@*1h1nSY3Tu<ߤՄO~o8RIs}`dP$~'4*^_V-X24}̉4]>5%j@WKO  #ݛLn =*|.tV(#sOseЅK؛E?*)u"RKm,qejn5A`.D"OKAp~[c>+@#CBݸ zB#-DߥGÝ@`MjeM07Qϕ{lmН/}Oj>7%§򂫨+Q/h752Xfs^H#U쥲}oq%ԧ}H-q'׍K]w_]=?{P1~|5`T+EkE*<, UVt sE,Xy8UQ"nlj} BY\"ˀ2aiBhg|.x%Gq'a25-ci9}hw4^,qrp f> [6 kXF6<}͉5a<K+"S%R8nC;[VFg?إNb4!$HuZ9kd1yjnJ̠P564z93*7"YD yCuz%~Ti+sV9X݉}v"cFdpOq4Ou~1ݿʛТ3C$KLfۛfMPF]%xJqU ?D c-Ď˨ ȘbYܣA.߻mSx!h CC29W?ei-F5@^pnߞ8ut^!iꓸB*/F|ɸbn~ɏchjtJ23Ru.lWX#[߳+^A-;#tU6Zu{{BV "*Om__fÒM&YzR(ޑY\{%&3UMFpr KCȭ2YmP Х<(^tԛn4׬D-7jA'h Q߿jk^ΗSh300KwQjq 0Z WBڥVkk4EtX}bd-ع6<&Ύ#Vgcm qMk}<3L,Yݷ֋)߱oe(69[ȏ(+9(UUvJvCGВ ԠD4B OA ohI*E£9hxc{Z{jIZfkn9폭sH'FOP?Z'*2`Ņ(]QE9^KfĒ#Q %?KA7QE.E7yoZu~SQX_PB$I9-v(4bFpDz…"q7^w PJEglST߁ƮVNo:]:w +k4,5SJPUퟝdLh84GCOmM ΑbGR~]yr$=]_zkiFw..N>Af> f #1la\0܎r$׷4B5vj0ٲuq cKpj"5aä.;9_Uj4 b,7j> stream xYXTG׾+p* .j,bPQbQ}iKYzzk#vXh~4I4M/<./| 3w̙3y{?D\`gT9K"^KÑB [d/M}Xua"'9{ z{z/^hɂmV mFz6]h!0tz 0?aa|oٱiHw ڳ~:dc0p7ACQܷxlo7c/]l[+򵙫Vܽ_ NmަfP[k6j&5rfSNj:K9S]ZG-P멅^jeM-6RoR(j eK-6S(;j9eOE9P+I1b)W^L(Sʌң&SS(^xJBQ(CjeDDS( j"ORz̫c\|gwQ\_CړI lb c>dhhlxK/}:~'1!oLtu8˾xAn#^nˤLL%CÆ^Lc$+Eab{ w8{keSQ?sa8oB!ys2i6 n > =A_kh>:֥ׯ]z5ZP»da=q B:*!baHh$XŽ_1LA)(̻+YPtd4NDJ& De.،G̯ô-b?<sXF,c 4`Wu(O+.dpXZAuOE ldGrOܑRa_k 1ڝi(AO0a т!WwbŮ͑vNQ1P=#姸ZfzzK|VHUDbk+[Q}~VT]=!VHF 5sHʅZ;LSɣG]T+Wġ_0W盷4 wc)zi>g9|VTvTp(&O]\`з=5\қI,xx,XHʧV#Fu\h$m/.{=/e/>9M\R)>vbC3OqXϾY( >C1U%Ɏʏks{^*܈F)ZI V ISGș/&fcydGB]l@"GQRMBQQcNOO:-J ^dv Iy$u܄]hhK?s_8xp)̨٤ ְЄ:T.0@atMo]: "z2^OOqk7ͪCSѕM0)AN|%PCrL鴏&paB`.q!j+EVǍպ1~Z]Y j@% oMu3EBtgR0m6 -*Kڋܼoxaix i Q% yL=EXLG5Cލ/diͱgz"O/B $ғa>-ɤAFL"d:b <sG9EՊY9L܍&FURԍr*soi{ "(+!0L$h -!/'?DVuэEY<*ʪ.*CEE!O؍1l?wtY sǦ Nݿ9" G2lY Jb{_vQ%kv=;c>]h2, -#;"Z$d<"58 </38DM0Vp'& #bK,_ws$LԽ%Y^5F4Uݛ\郩 4#_^"] Hg<1xv1L H іpv f'4J1jOI6nG!W6O ~@CY7Snlah{^r~Rir)*C充9_@~%&k(VMQ PW ==5qbuY9jX=(Z b| Gd(r&U0#A Һ V iHJ͛Y '~=-mK.u5?Wx_9\C߻~6"e5fSB 95/VlÃI|.NEGw;/FK.|G%gʮw+©t́L" a+=FxEfR~l ɟ<; aN4?K?iEj*[\A*XpO-b7 v #b{_?%T<~Fz"o+7` mdJؤ v̈́H ) '{?ώJjOYb* QщaW(DK1~_ex/xuG[V&b6I(%ejr_Y&✌cyr]lۢZJs˲SP&yK<{+S/ط c'OU9R7U{l8?I"NıKp?gh c00,,0>^ nu_e< 'J<WvxPզn],sW/ +I2L5PjkG D=U7,D 5峈l]'֒v":*w*¦겨>H_}hM2Hs`|񇏠 6xxeh{WQY(.;&lTVElQ|nY$ A|B :蔿#0;\XꔥDp!ᰕױQ-؏ƯNb.`Сr<~՘cC=:NmS`\85nHJ';oisg睶oՎveziN9\WF!Rp:m"HD*N%sF1uI;ek[WZUb\̔=U7l3u&>.PU{%jCf-uPmn݈kK}`6a{2|!hS= A_ưgD):_>L5gK&F1;s<ʖrli? Q{s!@a\Kai,5a *Yr*֢]IΙ=)7ĆPHʬ@ʬ}x_=~(/&`}WiʉVT$ɢQ"ks .ClqRp\ƑYfT@JFuW5-iѽ${*0L?[}361&-o]9xն0,ngGxA*a^*ZOT}s,#:3<2ԊcZ Dփ܋R兼?֊WW*^5 HyXyH_ 37? Fxܪ{W5T%gv\AK6f$!1)%T7<Oh)i}(O n,qCĄ!8tguw[}mk$U-XRwtQt K3<3 ?C.lhК"G+?l#4eœ*wWSG bKc"Q  CLtEteI~^~\YI-+ ?ZPkeCUmE[=V|Bx~"`Wa @:fF`41eƧ(Lz5i22~R_cHؙYvp@/c0ہ(K%_)ę!MUؙ_.8 s0"tu{|Bcv#*goק6Y/)DWRw)( 1(L&qw5]pnjųV.սΒrgm㸂gS*͓v(Ίp9]d( >ǵ f䄷&WUpGh6v?tQBwL_ )cY+NjaŋU=PU\QFjcgp9PMK P xPYA>Y6<ޗedd#+I)#!ڊqɱ)(, a݌L`|:;QgQ[ͼۣ[Kt6*DLmYuʳ+/f,%s翘u/l49b> stream xcd`ab`dd N+64 JM/I, f!Cß <<, }G1<=9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C53000303g } ֫ ʾ_<}aߺ>tqެ)gV.m{;DZǟߝAn5!s%˛hj$Lܜ(5n{eS;ͯZ՝id8\۵%K> stream xZrH96&"T>ƞZ%%B ;Y XE{Qk˗/qF+6/v}@gu;=>=8:q ~O.lƹ$u3L儚^%soVHrsrN+aԑzB@K/eV[\ahI"sBN9 4TKۭ9lD|#ܩJ9an~BJ6[UY0jGZ` U&/ӳ!oFa;LƺL'uo[!vL0pJݻy5_f'CfNXA12+~pVC+&^2L { jL!,5"We:?ţy8%ZT\x>'xy?==V3w"zli*] aV'+s!7]lSeZ\QE{BdJ`*_ x Ҷ8*T*I!c3ʔxZk^`Ɠ{x(t#y&fVr7CFJ:юS\appGĺç.{;xZrԀIoE 01.{$S2#ęHqUhQ{͂ӁBnҘ1z/`p`)]戚9Lkwn_}7n4׸RVGCm_@gԴ^fнN;MG:#dփWA6u_ xS /QPq>BA@ߣ{W(Ģy{c4D;ij[,@5~# 9PfZ1xjS.(M-$ xduKՍS\B,lGeqX03~%]gjң|GDY C 1.!bT~c(p'pb@0 %ZI~|Tk'.0ևpF^y& _41`%;JPP}-ꮩ  .uc1nFp+~^Pή9#,3v':ׂV<˫F ɀPxB4+?l}) f6)܇/}b=IRĊQPr'3K}>W$[# qN62>3Ó{GPJS Kp6qx²F<(= *e2ldg,Haհ2_PqƅE lD&Fɝ!KL8%N! #z4MIhC!wY.gɗɒ;jV}W1@ fG؜$0;W)3r{fKj9XÃ|\_5Cٯ`05( yAVK\wsjf c"DŽ;9kY2H+X3M~b{B7|>.]ruQ![$Mg䚬-jf_> G buY0F&|~:& B˽:%o$]qM^Շ 8-Tx[_M?H~(Oc_.-Cvצ62'|KɡվgRs}mS%mrqoMC6 PQ{7T\jNWb ,E7!)Ȉ\P]=21 >,*XJ;Wx@He HeY)H, j(t- VDYZXK?h\օ-YYQ)Pv/mpκ06VH?GgD%)PoӪʫ EҎ'UM<6œ5`XKR{j`q^faVb:V S'˅B #gV-\]܆B % [}jB-Bޮ!uI C vyv(j`3nnGu=`szՙ:5$ 4D",˂7Vyǝc ! Mk.mZn0naTz|0`q2 =ER4;g\AkL뢁fo-e\tB1E32q5n3(nK,<_b6¦i}w k^6!'꠻%/Ĩ(N1:Uę8_F7x?#^&1`2Ay,k*̣īX|i~CC qACpr°q8p1cS6A "PX,2ڑM2jy~{twG첻4nMObҘăiKIa6C)]VL쇘]e>pDOcb)CmWҫ 1cdD,o}^5rkVKgC^iё<6ޗL`ĵn ǃi/.i_o ӈTVJhYY> stream xTkLSg> t:.ĩs2s#VrU}@IS񶓸e8^6~.fYƘ-1;Ccߗ|})yEt)qm~aIbbLZ"+;Dt}̀B (̊d4QlYcg)5k?JL\/js- d"Ƞ [Lf)h.4=ZmZNmz꺔TmRm&kA+-[ E%Jҩ j5J6Q[pI%%|#˖P䋐Eu@2| +ITX zpoA0"Տ`dMԋrUմLȂ\lC"+%R Cj.+=fGqÍ5SQ> stream xW t׹xc'5qBHi( e 77ٲ*Y:4Ƌ,2a0{l($$P4 8M'W,m8stܹs~""D7ERr,^}DS~Bd1CPfQ,/甯/ggfx҅ syxjiEROaѦEJ`vYFx^Fxl7cEo`ѿOۣA< /,Rgl̊Ύ#YA%[׈"#ۈxb5@A%K(b=@DMf"IalJDd~?#bD^ *9} jb7AA GI5xNh2 G\JnZ]0)r(VS)`{rEIp4X=;mbL柣P)[Xz3<}@AA89<أrY/v}8xC1n<5-X qɻ6$<>Z:I5*F'C$q^QcL/({vŰ `SG*flq0oP.oA%N a&ADl "h&r"Z^'frrrw@29/=@P:QR8oi)۴_v#|?{ (U&S-õhX2APd^ -!TSZ,[ʬO!= Ul'3J@~R:J-t}b F# C0d`0 IH@Z$m_C-XRWkpAo͉B2;9z䵓l1/..ξ=`[z^FM&{+TGFP*ΰ;*@mVc^`RKIrMׁZ7&R Uj A*5;X13cYsPk%ƃ6]GP:M$rQ*#33ߚ[O =CbgH!SzBz|G)fVyp"uOazЀ'-gQ&~Қd ɕwaݷNc`:HH&VA6I~ f(9)K:zJ` I+,D \,GQIBwM VRyNzl87AS[y!1tXCˌ\x%`©+HqY牆b[|^2'z9l0x^Ȱ1 zJxVn@}&0֮!OEϐL9f]N['cnRi5zkڌJ;GL\eIW%g1c*b1ۆrv aNz]NkYtenwL#>8#*^7 r$VR~!l NWSN9¾})a鈄VTzvbXd ֽ[6BB$OF(}_1Mez9cf0W`Qel`-`ymtx.emŦ10t2XZGVr(bw}9 #)TOa_x!}"?M"uhP PAo&.Rf6xHFƇOC=|`jPt%^>sڡa>bbG'aq1|am@5쀬r} k.s9)Dp([ ȟsPIX n(0._%kzF+d`lXrlgP:&gIl^Y6xn+W:qʑ"8yׇD5>{(04>MJ/5hktHKB<"wH(8R:pj5;KBX{<:l\ `IJ$$&vut Pv4_I}4q4 _P:?ϗpھ]qڄTFgrEbmJ$;+* wktei4,kǢ04PHU۠ndg7EI~ 6q֘drdt68KvcWUt xmr,kTF̮lprM $|y2?/ (ZD-tP4k9 ݇3({^_D!Qǽc<[FOcᯪ=~{O?$ƅ2|O>imQdR,JLQx%GL>Wj+nNO &i[o M*oKL6 /fT5o!L#/k:ot?sej1|dra! l&Ed Co6ETQ ڴ3^ X)a1T\BcGPs@BYj%V6D!fJ`׃Z;| s1?:mM(b €qeWҮy^w-n߉^~ls1چ!w8tQn<&Mv)SF~"e]Pot*p sI` s_q`c':+ >Eg⮂kYF~lxUBrϬ rk ux hkL.1;M8D 6qIlʈ=\B_[Dz?yN1-K9lyp@i>s"_M*G]ȸl޿qLy M'o}w 7 X{J:s! uݝ*Nz%E;{ Q܄w$~pdAQ@_ИWf[Swj, zƪB#|R m.3}|bcA d6ͦz3APqgYf6ΛMendstream endobj 206 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 283 >> stream xcd`ab`dd M34 JM/I,f!Cܬ<<,7 }_1<9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C50\``````(a`bdd?3qG߷0~բxy؜u̙[r| 87mBU\XBBy8yL;ódKމ}}}&201g>endstream endobj 207 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 6068 >> stream xX \SsuptSVk@IH8¾(vSڨ}6}Emvyܾ{̝9sw+D"Ѩ+Wڶ;iSքJ'̌DAq8Aa |bSNm~rRވٓ+,}i3L!oOqmGd4>2}>SWNup 1ݷm u uYekVe EQٳ$ni|Bwt[);v [6*:pkg͜5{/̝҂&4i)S)jGQx*ZK&Rzʋ@AM6RoRKW25j9M͠|,j5ZIRL3T0%FQ.G \)j4FgsSPj5A-FR': 5҉Ɖ8Jbgq-rd}*h<}4|#֎8'pq.|f3%/K GºsrJ\#GSWYc&9϶ueޱ8o$__RQ+Z=Zg7KruJƐr8ENCpȣjN ѧk23i('lj.8 fӦwQ:֔CY1hs4.6so6`sa%SK9 "y,><1am&C7/Zqd{`ޣ9qpA4.ٻ]3Z"f>,y d RngcǦ<4VUT#E`> I) MF@8|_eyTOŰ6^/_']+pG>M YѫVpK8~Or)~Cbؗ&( Ulj?-ê{NLmZF,tEMYw]X'ق'λ]3$ZQb`&>͇$w ƚpp $4})(Q\hvXc,* dae vPij.9+ \Xm"Z y-XFkfz#8m ,S+Bh )ta'aCmXSW8b"Ad8uPM;tD%titbI"0؁&-=ᦋ/C Ԗ{,>h6I~KFRtf_b&-0J/6ޏ"h]kVgwUױWݮ}clEr$`(w]w|X}jvj !4 z{u0$jv^9H4:Mֈi `XFl"e5r*:uBh:y>&lr,1T ITJXzډTbIYV72ul2+z;vM:*^;6$@3ESkTv_"15ǂ-)t']8\̾#=mZC[E6xr!xP.̪ tpnD 0<>P(@[Bë\+!O-ph'U9 9W!5N"B%0G8C OUcR&֣c⣽ܓ@fnS `wwv,֦w %y5LXʹV@t,1.L,v VZ@6PԆ(+ l!K])#kɩ-)&`G0A6aK}~ry[3H&REȑx]BVҶ0ut[ am惖:2܊6Qh7mta^tǡY94AIȠ>O`?ٵn+b`'}O,o = $ߐ#1vnC6'ïYɮi~dI Un2eIȠ ,F2 #*ϴSX¤$4YfGy=BN"`+du6Mnʽh}uPV*9T%R[UɰN:3TD]Ti LEkynD } n윓gYr z"΍}}HSbwpqB$HORRD$H$15 "CfٴfêK9 7Y![ +Wԑ-7e[{\C2r|7 ?| _M7YMރ ) XD4dHj᧓Mխ 7eX]I,#aU~ބ˥w˾%UO ]8~D=Q _xz°\oFq_`q#]^XYv6C|\>C W{`J_+Iy5wT":< 0Iؑa;H qpk´ \I7\%8g2_Cȉ:[mE64 oOJ >O,7+fqPi$q?919H}9p񍋤fgvCԗzl[aE:.Y6𞒲~_!$DD-h9ш;_''s]IB!W{hYZgӧ>DsC6m6j[ֿsce-(acv`8^Y6x*fE&њ[JŬ|3 |+ܡ`S#Y0KLHu=DUb-c4 ]mK8vB;Ԝ7XF]@Z"8;HTka-`ؿ=}ػNB&r#Ks일w UMeJ%zbO`s] SW׿hmm&[)2w|}5D(Cw3U T|mm+{yJZy %[2tyA4l` ]I0SFt*FD2wzYyh[f/SPS钛Yu*f37==OA@j1oCJoة[Ux 630\ׁNtd?}h5~ Ŏ_}{U z@}ܫFQx2w Շpq8߅ (_!l$CZPEv:DִHEL"l6H!-.հHq IKB–h[z!Z(LU .oaJ? MRB3Oah ͮln_@?֓?vzқ}+ Ƹf Pj)[x|%9ܓ%{^ vJ'?#yq1>J+-e8%Gok<2_h_űLaoa;"\ :G<:Da߿c=`@h47兒8vGi8PB LI t菏!WN_({>: oUք6(ˉn(763j?r [`,\3/hu mTDӳ((hux7.vm#x3]=|nik+/! ڈE\SSnIVrY-褰8.,9hwTi:g]b”fSdu8Bqrm| x.b%B%ee2jm&CϡĚ@k%y%uAҨh5r~|G{NN$<[v^/Vz}G3:s]nI9Mx{yb$ 1ړ NR !+Qu3l;**A4ފWAz&B gk+rs %v<+"~"Nb9è"m[j]$NR]l~0[:Ŝx)g=*"cQDWm:_& #5ў[.Q[o0qbjMdž {uA_lB<;e`P$c`//Xr‘ R2Du2]7p_+n"> )8 N^IM$frBh_}PYG[덋U#I'LM!#1}u:)TCQ&$Lf\X"!!bMϧU[k<`lX|ͮ+%IvߴG9!o$G%y Q(uhCl+" >)8'Ѫ!?|&z]4volC;}Y땙t].8Q~EO^LGFAVN 8gŧc ͉ r.R9f6kMIR,f{Ԅ%kPf>!ʏ*`' (ش?XS _HT7y+܅-eRPțCwQ^iXZ$#e*xgifEXm!UXkwE[DaYbn^BA GA`ۙX<,t_t:DEڰ|z@0+Cg%ŚBU>Bt.GER9)=+A\YF؛×wZ5++0(/ह`bc endstream endobj 208 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2771 >> stream xViTTG~Ϧ_?D[P*EZQ@jA#b [d (ˀ@M!Jq8՞L5$3g9}^׭}﫦)1Məё5oN )d(@z% A9} (Mwij3m[!qEeE*N&֧ĦfLLژ.LMowEQVi37EfGǬMHOJNϱw;O6qՌCR ?@RAjKʕ (eK-;5(ʛZASƔ ESeNI(}ʀArHT Ho?^ 8k"s>"7JD*jm: 4pకv %6\E ^ bHmQѰZ7jx!08^ "גgn{ꁜzP#h@/h]#'ܲn&m;-㛍 >sv0DQIά%aoU vox~E,6ZmJ K*d8OeJ}bO%kc[`2brURBROJZU޺~+#\ꈧ1ͧN{]m#R $:~ͽpwq9/v"q_C /rZ:Q]Y]몣8&@8_,`+3d bp=Rk3Nc>Ė긝=M)i1rcL$}>?*uҍ[wb-{ܐY- %$ɸNcˏx:shݮiQ_ +|ҁY FXiZ< c@-Ir̉I@f9hbQ΂P:{wg O #ΓvH7/n:_}֕aW<(  |'* O`R~-5OK2_"3*IDWNq)_ gN4vŠ~LOe5ReEx3 Yxn0ݿHFjj^ O$k5v<N ?VgF IyC]oNw9~,,KA V` ea(El 5=C&YD̅=P]O9 gs8[8 g< eMҧjAa)k% w ^,!OCd$;h51RPR#ЁBI(\5v vmX/"G{_400$oxA6sT_Ca-z䅝xaxs=8 AP'P;_^IF~L%F3IJP;jjӖDd,9{>GRs X^Ff8EoECQ&Gͻ?%qZMj_I3T~92C1S3w"'Tpemrkz_s6~Y_ XT[QW}=D-Vexy}iR9jd7 lꙹVwIS+ R! S(cpN5_klH):FY/uď~}X {[ޯ-ɢ7g("3}C$ɍ(lo ϕA@p<|RB—gDx"ual8 /Z$qg=gΘB!vhiW _%c-xR6\~g?{T M}1@##V@sGR̊ɥl~iɵ5 랟`xm .lg'Sɫ;yAql~Sɼ [}-%7_^lAR-a6_ayg-e;&¸O9 'Q3>vۈUֆ9Y#iy}JCK9T K?D6T8[7r84iRH>s1Lv\}A#b_6yYL]1%+[Whd_I[S"I%*r hrFH,{M6*pA2L| L9/X!(V Ao,g >3> h{>xJ0*P)Hu vƻa þ`aHdGU?JAA8@LC9?{\SRZY`bc<~.+I.uMl Dٯ+iexP==$bК5O|U>M}MwFa;}YZcb=`wv?8mb鍎pp-Dcob؄؃e,B`K`;oLF-"XFP*QF _|V'}th>Q243KQǛendstream endobj 209 0 obj << /Filter /FlateDecode /Length 6114 >> stream x\mq~!_x6ݕƷh?W˼8Ԓc ?_]=_>N1_W%ؼVZ!ٰB vv|UBDZ=8R}p5"e0I02B2zY$A n?H1$a^ |NxJ/Ze7!1&@c M7z1KAI$bG)bM%'"4D@MzQ`QD^v)+xOkpbF<4NbUH4fW' !Cy(## pnIH-' RLX UHl!{\OZN ABuDS1V!pgH%5,|RI^$&/U l\ (Z2_<t9&'9INbT2%KrZpƩۯ&nOjy;.j ةeVZm:HkAj85C 𵀩T)=jyRwo/~}QpkAT  4}޼k+>Ajkm_xa[.e`4~\= zHM2iA,zg+d$*5mv55}ۦFTs~uHgバTAd#bŒ3uͼJ|k%8WP'GH<3i )HX$\YB|zM_![%XґDgjC1Yh)4YgIYu(TaU$*#R&4DwcXfy Х,y>bIGrDW|a!dlksdBPAv$ 6HI7R \Iw*~t [ k CV` ?J,k}GEWCb Xow*-,g] :HL] LHluuAfLڼ/z%[`g#_oܰGjufX|XZA5\ƯZ'F c㗘'$$eb 4DsD \ #9b> P6ڤ|者$.gH-%IO$  ,:YOP4-3(EN8 )R&\0ބ՚ P Gzai-:wWQJkSc#CRJ@.ِT۲`$Ҍq"1|"-r- 8$}c:m (iG0J :ʎo |B|UcPu>p&2Ř<5ujzi 5YjER]M͈~5kvPoUMݝ5wDaQAN-]tֺ@JSr+_µphUL+-Z1m͓P Sá8I.:gs#I 9l,z\ s ,Y*, ;ZΦ~ha?ZDM" Md~6 Q3x\rtR_}f(a7:ZFQK:A\?a#:G}&mtwՋvR\'sgFCj#u3VLUf9(>OS~ Ŏ_F;!!0N(Ҫ= ՔDzSS6B("vǏjw,sU Zʨ9?!YI\Q~nZ ꩖$R=uIQK4AV-UORZKjAz-QH1~gKS[!tsp俅A~RyKHIX*Q6 a- KE,ؚ5 5<eK.ǂk'dIIvK\bdGк. 垯 :ٽYR׶V0q6R`q@喯jMbn˭c`@Hȁsou_ ԓty 2$,MsNڣ 8$ SuH !zHu 8zdEpE܂/{DfzȪ4mUR\__RĮ_}j}6M*m&mqƟn.nOM }c65 u}k{ZmSb_͜5v7]UtwgM5wXԂСSFW-,4ՠ܊XE{s- Z-lAe VRk쵪2?v:X<.~ 3@Y,ϳA MjglgH}bxZ 4M*hE,Н~FN%ʵF!0Iv )?1|t;}JGeH:2|d;QA.4>b>bB *I!o]ë':鞞WWO"Bl߶rffKѕt@ksn|< /gO{Uϯ˂e˲USG:OAJ<^QR v:XF,GM^p V.Rn=İYwmY#9X}Jc" $c Otʠ<=_th5θט<.߂ŷdwDR>{O@ AϦaAK)y&o,ܳ1?]o~TnsW|›yb<r%m=+6ht݈aŧGVS@MpB1iW%P#~ !>).nBD#MC1|߫1ns8_Z/=WXp6MB]f|'tNJNr佻ܒ QO-_yAHy>m\)r"0=2bz1b+eНm=Dewb3@a#k-e§!vg$yg !{vVRM(V[sJە Nَ$1(gc\C5CыQb6zWZM?lWJtKc&'txUjls]hӓ1$n1Niˢ ˞zl{[ڟ|J@`T`V */܃?}y#hEAf?l߬Ԝ_Nϐ L~/9!hֱ#4(ں+ 7 +Qsf[NxKq/wS3r͌YpԿ5p{%㌧w#(bwpˢ CV*ЮP?%V\43yP"@ q8 - 41j=r1jei$5I]5K nڛ l YːZذ(Z0=V]K/یcv҇n-y4\K/rp>jj-\r`\'Y}rp.S3fK3:|JI9$;b}_oۡ{/àD ^X+K)n2m3?ZrWA% %v&j߼`5>fڨy[ĵ̚doK+ŃFx]}UNu+thˤȵty 3qPCHkK>dt"q4orOpM1gRfזj)ycjy=tEi;~sOp JuV L7V'm|W>T7/>X9w8iG5pNZ]H%23(B`/.n''_6թ?ֹm+ƙ6:Y sU=rW+$Tl>u(Mw)Nylo֦91[WKs 󼦛b(&g?>OUU_Q?"/O%7yq6b@!PY##0<̜i}V+7{hLsv.jO'^^IŅ|}®T+F~8vC1'M'Q$%`e˾.um0[0z,~ӣ2@V2q_N+ZOod- cbe;VU,;k3ŚC%fL#8E'7U+u@&WZtFӪ.teO`7g͇Eh+^RCm'ԭٱ9VY}~ Ylw{4gW5uYFendstream endobj 210 0 obj << /Filter /FlateDecode /Length 1962 >> stream xXm6_aJݭU u^=/zڤ )%eiЃ?Xgfvt_gyϟ-g_FR9~vKI.>q7Ifk' 9L1_d_ 5ʐr,d|Ti\b"W}0DThr=#:YpB:_pp-:YH&Fr(9]Ҏ|3^\/7Oͫu<"g/485%4Ѻ[qͫnINjXcIMTjT>K]UdQNʃt8{irDV(o7r]6nD/)zޜ0ɷkoGǡ[\:mUqj:yYeX] }yX[Se$g[NЉ}YAD\&0P/VX-Hm F0l]Il>kK3DvigZNBoM]B4x\HtqH2Tlg3(;H 3) 2)xQG4G9gfǍg%|rY޼0s`ۃVG>GKLBq okf"ڌ@tvo8bBP ǭ1Nc 3|I*y 80 8Ə L6xhw=Ɏ}rBq:b*W{a,G z_\n:VED  prh;lȼf)Ё,'(P`μ4w)Lu'#)#\pM pAQTTYT4]CѴ0 >A?H*495ֿzuP؆#z-Dv ʌތǠuUt&Q#96a$4DU#e؉4U{Zc@NeVfAˮȍ)+)ζ3q4:DGVyIv:`낉rjc>Gv5UrgvRt%%U[pSu@乻Tՙ,5b_0BbK[ $J V{Gg@Qԅg{ e \r |lKS'_O\%/)5,? $ֿczJȽ'<8,BCD>hU0RN[Aoz>dL!#\m)K>ϔgzSTP7eDCbTC"F!?|'cO$jUa ?9oNO>g=jg+ ?}yӮ8fU`'WCY8Gm_unDFQt "DIendstream endobj 211 0 obj << /Filter /FlateDecode /Length 161 >> stream x]O1 yNQtЪjbLPI:t컓r/#=>)ul"-~H0X4-i*[!O |oB -A#E3NOݝ,P*sJM5FT&c=|()_*[S&endstream endobj 212 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 311 >> stream xcd`ab`dd74 JM/I, f!C?XyyX|_(=F{$0F ʢ#c]] iTध_^竧_TSHJHISOSIP v Vp Cw^XWRl} ߏ?˾K3<[{ukvwwuwvUu4TwWwmYp?MbF̦g,%0-ýq0"ϺzL=f*/RwBendstream endobj 213 0 obj << /Filter /FlateDecode /Length 1723 >> stream xX[D~_*1\1\)vX0nu'>jcYBш2cf5(V+}k)dEaH6,Rdi# ԭZ*KcCrMZ m|+(F;N V?`>@Sm7>(MtAV_L# fiP&XPkw8)m@SFf0TT2@Cy0S`I֋na&lW}3G"#}樂ޓo+л=$WjU#`Xg 5H4%c>!9ouؒ[j= 9[КZ~Gôs .Y/"X7b\EHfOv#Fw+Os O,RW2r$0)s `fklAF7A s@ Bu\@gSp7Pk ]y&`u}k=AJ3&`^.|;Ai_5ѭ 7TaÙfy`@Bz MJwy06zPgYލHaH P`@0NOZ)$Yyp::@Sh#dSeeuP>]ɯvfSVm^k@ 4|L u7E| |k[9rfP_v[4sLa/ ~iK迠Tw`cufDY lwU'—F=i7M,Wܚ_ FQ*/O_3C@ C4pwhc > stream xW TT罿0 i&&i]$/ic\QQ1 0 0 IIZD6sғ~9is9 x<ފ{%ى96Qqf }6.#O@]ӕy|E>EyܭbiFZzA_\?TG3%̌Ĝ䐝ׇDH͌$9!I)Y!Ԑ!1}od̞}ku N$wB<(hxrJdZތl$QDXCD1D,G'$≭[zb6xAH$^"‰ "?5PApWKRIZ|ٖ'~d^~d'~rn'A-yS @3r7TcW"9Up'Y Py*ّpRSir[E]j dT eܨ `W8*uZΡc_.TrVK jGu6*5. fP աnџw]| Vr^k1`=¨]"8 2/M21X+ @Lt9vh/ vǾs g ス;nVOϤd^s($ZICIgTVjϑ1U` 3HZ / 3 F+(ȝ>IzRj6ZV `5PB KPr@yШ`|V4 .^f`D9mNkPD]{D풄¸TJ}H]M6=TkEO~ J耖RCQ)HIY».Y7/ w> -0HI0N744u,,3\OW].רMjnJ]DJ\ T @&'x_ZKT&0>K0} ]Pm }moߪ?έJs(rΈOi l0J{;vtpz$ITQ &IqDD/riJNbdCtą_S F1}(xy>(&J^M7Фa F %ka0nS[W$UbJ6 p+7C8=J|EXwiώ>9s\.Pܴ[-X*K`+w&Xah/3[Yr8 nN_7cQζ/.YKUy(:ss~H&7]?s3Md}0_X`6vq'|].I =޾7ך 2//;5| h}Qr|CHЛ16*xz&sm˟]Dh \&nH )Md{{$݃VWwʅjќTm,1QʩS z>Flǜ&!H#pr?yE7aZØ?g] JL&8S \4Q b-qaw_i*ĽY(En2tl7ZV?LMN}6 nty9l_Sm?}'n]}e5CcYh<ڝ[J){\ωK}%y^`&N^QfHcXP\s[l*s s*n?B9_{p2ƪS 'Q.Ƙ`O:PP!bQרWf(& kςZ7iz*ln: @)ih#zz4;1nmuY\Vkʭ) M:k r&Ed8tFYb!s/wb^>{` jJͅEOJ[N@x@ăz%c?bg} ~V#qBAͽ:jj13 M;@IGsߚsДmUbl貀|cwjHK:mu@gA#8wKX blӕvljF=7w_o>L}@t8ЈbO;{ npB,H`Ex"j*;54za,oDUc6P{8uYwq3H JzPT$_Gݧ!_؇Z9:y y<dpB&%é}W#^I$8vlxw91'wp;҄›5MxۼH `#1rY2 U^i/Nq$ʅm81侥Jɫ?Bnq:=PK֨ Ғ̔!ŭ?x#.%p4"^q ^N$ONZ|4=w%fH蜥&JL*L .l܌ۆYQfP-VyϡUS2`:yX8y>Z;١2OٺhI;H|~LqwN.(iЯ$#J-uQbS Jԩ؄_*=q矝6UTpR_GdvK'49'JjWB7M{TVT7/-S6''o8ƽ$ ,l"eD[L)rPd=rUH;&W˳s$9MN{2lpܜۜ njѤŕ5.8hmK+z^ ZeTjT[@\n'8XPIr/6 a (6X =ˎwTU:,v.?ѽoT&@9㪊nm9GoЂh(5Df/k+ڨRqloXQK5Ծ^# aVW߇Ӣ(Cރ?wzNʖk> stream x]n y H/MӶHSq(A4=g;4!oŦ=OVӾ%~j攧J^#.)7̔0]u(M{|w!hmROn e["!_9XyƆ8*8@VB<Vס:Q gzx+p)T잵Z^Y*֞QK6T *hn_sP&kxu|2R$ey-endstream endobj 216 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1962 >> stream x}}Pw9\Vh2 4f$LBcABTK=88^;w{oȻȋ)b55u(clLjv6C.jifvv~g?$bc$srsՕ%2iHHnf @=O2MS A f//OU:3?QZ-(+/Z`y5C\**޹[]!.%JIo)bxJ\")/e%[rklۜrequmX.)!%uX*J*%UuUUujY]V-*J%uA$,X%\DH!27I("@I^GLi!%8[{wJ֔(:E=F 4}s)IƘ`!LYv0ok-@IWI`Xrj\6Lr:inf㴼4< N9NpUl)hQ|M>UЧ8 Ovq6 5B9Cn{JtӘKrFc܇h`|Ca6}q,<^|KO J:j/6b*>`E_"-J8+I~de<_+t2rpu@&+fk2&;.kWlft7t|goo+xyǁ7!WE~QƗ\.O/T dBZIQ}6Oi:-í#(%oWRFvu0PDi;x^Sɥ^TMRA rQ-J|TB脎XD}ڕJPITa KQ;~k5jl&-2&asp8]zt@Bo_@ۑ_y؋bO]T*`g8_f* 8s5`-JU5{4(,5 [L[8PeY7n'}2[,&i[TR-dmPjl֤`ApP`>_dt"jtJI,eaGX8D`8C mFCph.n@WϾk^?6~΢L'7j5}־>#w/`gt‘~秾Y(pKO`uy9:\⪹L\N|´-sRo+mpWX]wrPu9zB}~;1BCll&!$`N$xwUgX8Āq躛;.h릣%@]@0\l}sfe-?4>Cb̔~Zx^, %b5Y74fmBU-nnfO7t+  >>vwJeUpӤ A}Ksendstream endobj 218 0 obj << /Filter /FlateDecode /Length 268 >> stream x];n0D{76v"A2Th3SjXϧs7[}%}f9o˽$_lƎsq5-?+[{rt|[cMOi Saz.| *j Al-EDM"CDapӻ.@tA􂇠1d'] *`.JACzd!"GSNK@$$+IMR8oz5$>guYBendstream endobj 219 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2620 >> stream xUitYXBĂdFY dCsB8 MȶUkZG}6`K0i4KKBJ8='?OڐG98ؼ$qLcd`Kג^Os~%)Y);_' 1^"_Ms\ƛ v Cmpdy*\Ҽ 6i} }pנnTFH ߪ.,eౌ gV]L~ 4TJIȠ\NPN⭊pEMBu7-v"v{+ŵZTWdC"'XP+vj.qOMji:c·GVh0{Eƽv_<?]$gSd -4q:!2'ܑߞH9R&{S3Em-j Wu E'; 05d13e.X,?~u!oK|}_:;u mwt h4Ѐޠ4[@DǸ<,ϋflk,uP)v{ WY0f:f0jA1.> #ީBI1fo-Mu+i م0k}أ#CMT$Q+L}k׃ lE 6K\Mb<3FOKZ;}8U8z:8\>e7pE8lEV>xv}=OmvBRZӌy}4:- JZ#^3 c6֢;FsQ?]u4"R(7aXlqV#Mowdz殍?2A7Or/kAF0_j r*Pz]Ad"32EF\֪8X|G(WĬR-1*\wG<8e tYix![גM19+u?#1/0\f #ZadDIwau<b9ᔟ߻JȻ<΍;\ xC4??oϞ)pmXo.0d;òp ck#endstream endobj 220 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 787 >> stream x]PmLSg}/V훘EP&qCc력>:>v@KPMY?Z4jb\K1? YL ;I䜓' ot668hMazZj{}޲nڬtVFBnu{s=鶺jZU]E%TSUyJ_ !W߬X,b"I'z"hVrA\L3}K vsyQ*c]wEE|= @hE*܈ 꽞uŒW`_-˚[^/LQgdn_7@'{0s"|>6ʹu5x&a}fLL\_T@hd4[;‹n`zaaY,{)Zs YWO0#M29]t c$|D,̡Sr·Z"wt avj 3oþq͍p5 0J<4A@ vTK,Q9_2_%ǾUo Pyz`hcArNYc_gxA+HtE}%8ݜOU7G\-C0tKE uSnpE"00uT 0ʣ#|L d1Dô/5uQ#A@A;diIendstream endobj 221 0 obj << /Filter /FlateDecode /Length 5364 >> stream x\[ug=)1}/Hue`؈bl&iafF33-w4;>REmzPO7";/g]K:{֝]?3b=]ܝٿ%|Ӛΐw\rə5L=k]IӮBgS3M/n;Ux/~-XIՂ\ r*1!o 9я/kJtp~P _?\ljV˂ ӺhF1uN6/h xS4 .P+o?[1q[jZ. aKQ8Itֺy?haF"B.u'yNN&E"A=GW'NG7N/R)0*IhS<:)f[O6!& s*s'RCׇ8`8Mʾ6&dz+oB4`#6&P߹AU L@O`vMM=$` Ɖ|>k&\Lqa&!ďTՙ|Y&4'NvF_LY$\N3kn2y*p.>BQBUn MYp7)Us/bp:g@ 4һ]7DIZF)gncx aBG'2Q)1D z=߻3Aj ȧ;`m& 뛲dj`, " Q]H{U&\0"9(O&ۥYdA\E"bMG|Ҟ#x TV$H* KJZ0*?g!@ 4n?-R@sOXea?+sJu}HH@lXK^ARdyW̊(*$꜏^ P Br1,MjlO- ) 1jfMrKN[ U%ww !$4vSmǛ5s~zE8XQA\+iu)l`}^S]{xJ$)+޲-"n%dwj |".r#b3K|N_ȱn>Qcpg(ir:Zmh0VJ2e]N /cC[~wqtwku"o}g +?a~}|-C2a))P/< 'KR;jK&~iQΥ 'GRx׊`̡ªpkDG˨Đ!~+%؞S$`ݪVkXuΑՇiR&Ď̄t׶~iCESĔ!!J}kzmŢ QRA^Džcȋ3p9X^Ec@$e `DșkiȬ:OzJ` se 7~ݣ1ٝ>l ѳʻwh~N/)+7MNaEۑ@/Dzonnm5廰/>|"=ipx8$tT3A3|A^)Bwgm 5nEXtP;Kg*\se]pz@JCD^*$_gplVS@yw!m3p%R$ ['4]ǂC܄>FtWW#Wy)OV<.M v(wd9ILk=g Ј9-x+P{r={7 y<}KFu }e O0[xգ~?g- :a|}C|*ɏa.jalnײz} 78ǫEǯ{\)EALMs\]rljyڽ({T#Uendstream endobj 222 0 obj << /Filter /FlateDecode /Length 3636 >> stream xZKsd2١7<ĮڔqapޙᘤvHhN C t_w˪d7 FO/ÿ_.|!5<)]݅.-4ʔN˫E'xٺe^ppu{8R°u7-+&MVa\2^XVk)eYUzBjefEZ)-IT-.-^lVk2mq<$#yG&*YÊ2\nuV}iֲxvOH>>X;^3JZj7/tVCz.6mc6u~;{[uT6fWH&J%ꋗ +tn`d<ӛuqq.ws]hWQP^[޽^_8ӳ//NH8&:Nt鳧z{EK+0x89WQ q/z;`R\NVHB̷+ӆk৑9M8XQlj]60@eص3OopjW35YstPzа}@-s݂޵>,Fh婗%݇ϒ7a+u,uVhf4p䒰sk+˦ T:ۻ 6u !fipw=2pdc&Qc-84]ZZPnft}WrvёY96ԃQ?=[_ap4}!KRxK".5>h龗_,R4B*@~ <)O7H>S[ImSMooæ tx&B>q?Ж{C66WpS̃0OhACKuU A)Z|Hn?1k9gP$Xcx65ZLJ;A6ROyAD-VHOPJ NmbnA6KgTh0w e2x C$*c9b1EAkI~'+M<ǫz cx@ 9'NNl᤿%K7{Hb8ZcO㞼T)Ln/$.園P̔=ilCH1•1$0<,lƙ0O={q<As&jo0'5<^:YVt~@ KpqF~Qr 4b^ $rhIi]BnWB/UN|JT*Wc ET>iߓőp>F5$Fy1ώZGhFjwJ>)Ȥ7}9lp:UV\~^WqW\7[.u"/Z|[r;?2Fr)B?丰3X&VR9VU X|+~̨: ߳,gms)drĄ.6$GLQJ"[OUj_+Q l} ӰvZL8bxY}O+Wc V3?'r>דnQj3!s9<`%ػ|}L0~:Q q*ȍT^ &LpoT[EEaXD멖ؗ'$h<-GLCW;y%LZ-a԰7䄭*at!6Jֲ^pԒ#<ۘ q%'.F('c4=[P\HK'јCяI:`M \Rؤ|O 88xc(ɼ cp}c_`\87_~2]n Swrzu}dPׇјZhFM-s8qm&@KDׂ{G~ђjL0e-{#x֎`9 ?{; O.8}|89ts3&kioǗręv4hn]PA%z[!3z&ZM]S>#xV|r8mW):ok9~g!#F!4w-G3"4945*pN!Jm`~!SQ'z5?1XK|b2*kb|r2]U?"M~4d} E_۾ #OEil>L6O8r-AUIڇĺNhI S'HґD͟R0K֫Y.L7}g1fdoMtu0GQqjS$ǹ2/YvOրdxk9VMxG.6TҋDY!RR3o^ҡh38G1T&5~o,m-3-B%{J %#| 9d\oF{ y|ԞHT`*d)KLQ3#ʝx~$ގ2:u|6iRxyc)n_cYq!FA?nQ٣uB{⡑/ŨzN!&(O3YED{Tޕލ"J*TSFVX!V侙(giTJHK, Ь.ASO m;ME3+-s=sy}Kߜr!̍ $dUJ!kh`c.rXmmɨ@xHt~a=:{_4_?!.endstream endobj 223 0 obj << /Filter /FlateDecode /Length 3461 >> stream xZ[o~oH'أwrؠ `[Tm=rq^$Rc>C s͐=_rRޞrB˳~o)l ݜO)c=RWӳ9ya\'N-yZrMkKf9!z_ 5ʐv9#Z.I0NZBp;/]7Mw҅0++iq9gW''[!(ɡjZՔZ(N4'Y:Е 7ᮻiIZIjs K6[gX-n}0kWFՂ v8 A10Le Mk20|i[FV?g cI!5-)kstC?D r~mmG 6I繝ͭKrWL)+-,KnO-^f"]:#ONZ(ܹGAht5shG9BFs&~ &h? sE-JS-ZۣX$h#86*CǏM{[5$q+!sKDfh;AOv>4b"10*' ]apA.6%Oa5ްlr+8wK yD-DBf4}"x θz`nŽ6 `>[K0 /6ͫf3 Vwp.:tKׄ0d$95ͲfhTn&̇ɼ^4Ծtp:ӗ[q 'Ӹ RF?QfD<)ee\i2p^ج0l^ϒRd/.VqBn}8Ԛ @Ham0'n?ͅYMAGcUΠ5T،sWh/€K~~\=WWu"p^[󜶕M6 pa}Tqu2ΈO?MKwB%m9H6?%_y*pAoT8AZ9e1Ե rM2ıaꠓhKt@f崜fXF[1BԜi+cfјr=4 5ggPb>RvϣqT!Wkk^,[smzy[ 8i1$g9 ŋ0LOGCK Y %ve0-j#hp#o* jVYq2 0i2l#EeACME%UļrC u%v8 E ?rmhUO?OY~u&]7%PP]6_yڍ$P_A22%|sQ0,]`VV.bivv'ˉx~),kId!rj `S8_`}> stream xZ[۸~ߐc_ލ&A[` tQmMC&hձgĶ&&){/2IQΤE"Kws8VuEW5է+j߮o^ LmM+MWJp>^ڬ?`mb0z{<몖\ڐLW5<}܏w0/uaFQ5'?7F5tMX;vL]kra.y[o6g{XHv~UAOkZ1 pcx#xnyɮGbOѢ^T*M6\Vi?5%? }p&lC''V EyP^Ia;]dJ-$τ/ /(EA^SݕT#)/y C CcS:'j SLhɿc"XeQ0Jeřv Y$ =‚Xϼպ-8%hŠM4G (QoZ+N,!q9#,,ѩ̅T-5 Ұa:xmi{a¯Q~$eG*[J R>.Wg.b'._[P\MkUd쓥I!ڻ vlB~AXM3ag:Y&8Fg P ߐ17Ijk^f*E"ԂyjykԵ뵱v]@R^hV-&8ރlӬs_j-@X1 @ij81 /keH~̯g$MfIlRB`\UL'%P1sQ<"@eUVZF^wȠ)CĈcELܺ|ʴ|ʳ| :v܀ s gf#_ZS`Dz6*'+JhJnќsD ^1mr0*Pm#=O(͜~#>NC6 6?Tf)t INș#FcEC Y^l P :^+kb_E>aʹ}Gaўiͱ4,ƗABB5f\Yx{5$|rH kǨS6<{dΔ* m\ h0OH %@҆/NuW<5o~\ 81芞9?DuCNexg_F_㣴];?' 0w,Idg~[quc vP8-ƃC}<붰x:=|gWΗ]oa|4x=TX]WyV?1`ĒAe. eھT7T[G5M%Au^ۣk`Ǣ"}m@rWɔ :K"feԏ6jGJ?@ٞHд 4#,I9,f-I > stream xZ[o~o`ak1fmҤzUú@YvK3CjR@"Ĺws_Yw N.ŋk/,_n/(hZE -Y* diee'H3 {7eaR)fd/2VURo9gMlx&ɲ77]W <;ڮ~$a!0ifm`2ׂ^9|{fOH²zz5ͻڦb)uZS;磐FmˮZt=ংm>J?$it*FµhT+Vmʲ.#Xe)?_㋮`].`aBđCa,WSۦسֻe ]tq}k (ypy*Gef 0ĝ<e7?owNRUA'Bȓ !7;8$'J M+]:M{K`3 K! $^ XJ!$Aɗ`aQ@H'V5"N`w|RYEB&6z4>\` - ",: }rȁ!(ܤD١6a7C?J#bKxI{ G[i'x`J{8anN*cb,DX)B4e!S*UIta+6;0UϨ:$>G?N#Y"|Vݡwl(C9D2"!pװ)%!Re:UvC(#L]ճhQg4qG{Y M8B@Ccwêj$a IBN7DmEї6kaɬ3B>񳮆*̍m+Hr5#`# E"`E=`Z d$ SlW jN)*1B" 1Dmٮ@Sql.KC* >?ny)2m]uu6=>doG(ηRㆭoeX/s˛*L1߂♵Ȳc;ݰPӯL7 5WñOQ@fPo@#yr.l 8o]XӘp3#prߌ%#|}'$8u<_d9'j;?FQȁYl(bNG9}>͉R=@?z/)Ҕu-\gbYxg:/)'s" >:m8/PШ$_{>gs3Fôѯ2LftPXO=p u0-  aTKܾF]Ixl3t:ɜ8F,h%?3=i5J񦮎//1 VGͣ$`n&b.GS,1`POU'QXQSGCG=\¤~dC"B'L7D{TX e2c.(lUa*ihUhL=aC0 ?(_sޮb!>Asw@獆=E8[]B7Ad#0" ]3K-H8?sL|YVI lfQfm[ܳ;Iy> stream xU{PSWo!!7ZjVE)]Qy(X) 3R$EMCKYߵVw]e>]wÌ{uf;sf;{~GBQd~Xdi/KKa3wgbd!+ i{ŋJ$uLY35VX*oiRL0͖l!/;KKl b&DӤg&34鉚8MT춄qK_'<7'\ޤש8*J"MfJA))KS\ģܩ|(vW]oYl_HQc/|h1aFf C0-#-8>Sk*hVGOv7I -oaʒBE4xV&!l{y?yUsE(S1rB45AnKx nb}.9ȉoRlO)jԨ`<֛]NscKg__يmvC]LG4g֧{K8qX=oeyX P(gbl`&'5pSZ?i;pԢKoRA|cAZ~iA^D&*;Onwq+&C0NT E_Lzhwx} ,'Mל v,2=αޫgK[_,m*лW򙐋sT-%𑩺ˉ,Q^EjmV+MEUsg;8e'H’0\{YZ.<^ ,yRܗ'a99*(ލ] t+\}ζ?F>qQ?\=rv\AO&`JK[ -0[6@:. _<*Od ݺrXqwKɭŵ\ow ةѨ GEnc#ɥeP6ү0P EGHK @4Lx驪VWqȴ8D$]j{51IEF/eb?WAD L'rL٫Bg$DӚП9]Tu^ 1(QTffulN>X;s6+%`.R JO5spW}#/zZyU=xy߉]1k'׊Opߞ\Bz ->:Hp]ImamuCU#3CӍ_574 mwhSTo" נ=7}7sMPN!> HƦLaTm*@j=":I''uI%H% |8 N`ONV,{_Ԡo콧G)Q\<պТإ<#rs?llH=ǼsvVSks8/47ُvO/TSendstream endobj 227 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1129 >> stream xmoLwڎX̬fzwSsYŘlsNA[d"tP+`k[JWZhEZaf j ]Td&.ٲ,[3G%I$1q|r~JU_lдT6nmq&q TryĽY^BMkz-&#:knjjN۷[\,z+q ]R7OsПZ } ]pRkjrޫpf|+g.Mq6b6&_7KMn5NtE=P~aJB:g-E#;9by 2ڌ^vȠn>ZU[w  u )CHf3灘OV? k5q[Kd#AskmЖr4GdAv1yg}3<>Iy*//aH>MOwqiD@49'!#{G`JӦV}%i͍eHC!I\Zj10!s;N9B{EMim`dhĨmo1O5L]G H(DE ?Y0s)Kvk'32 !nMUGF&'+sS8rC-6dύLOUS*Iis?ⶼIuzuLVz|^ _.|+o^鵃@~&HOKojϏP9Cx⻙|%G>BwfAt[ D: }t;3Ƃ,(S82~%6|i~639#S!,ս?7b!,k3$[~U: BEW,: X4yl'|_xn⧙>j'Wsb1d..$ % ]9q>6 &a* !/+endstream endobj 228 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 478 >> stream xcd`ab`ddM,M) JM/I,If!C;<<,~ }O=N1<9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C5; UH(1,eǃk30.}?oVW)]ݺe~5#[޶~˱}Aw_}mbmf\soq߂Vy$ u7uM<5$6;~ߙ[Y#?{J7l}%cLK\c}V]]T'3ֵvVql|'ϒ}Jk\f-.)Y=Se 5N> stream xcd`ab`ddM,p(I+34 JM/I,jf!C[W kv7kc7s7BBߛ7``ad /h_PYQ`d`` $-*ˋ3R|ˁ y I9i i ! A Az8݈!Q\Xdd$V2000F00v1012t}_uI!/dX>f"eEemC9g1I{'HvwwOh'ďlߥN> stream xcd`ab`ddM,,IL6 JM/I,ɨf!Cw?|YyyX!=U{fFJʢ#c]] iTध_^竧_TSHJHISOSIP v Vp 4AtHfXN0f~_i+ճ_2x]EkfemgKS\Kvb7Gj­&,N~w&]XrVwO^ٽ&9#{i+o:839AnIn3f8O~ɝts왕UԜ#_WjV_ڝ]2kӌ5ݓ9(-M :UȖMOܝ;k~?;aw?xW38Q6]} UV5 to߲e4.ܿk5>S7T{7$'f$wvwV/ٿ{*IمY>~"i?D~۶UuwVK'Fus%,}U{7ۻdS7ǵm]m|e ~8O6{\XBy8yW͚3gr?φYzzzLM|endstream endobj 231 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 388 >> stream xcd`ab`dd M3 JM/I, f!Cw՟M<<,&=3#cxzs~AeQfzF.THTpSJL//THKQS/ f*h)$f$))F(+k꡻ g```d`d;+~W)g.t ~37n{&YptM0}r}߆_~Ѽ'ʣ2oDݨknS57upmUi +[ym-ýwRO<<z7O;Uendstream endobj 232 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 433 >> stream xcd`ab`ddd v541H3a!OGnn?䄾 ~ Ș_Z_PYQ`hii`d``ZXX('gT*hdX뗗%i(gd(((%*@\KsR Y{%뾟Xn݋u-}\} {8ֲ}w";VY]Y5{(?QU}_6wV9U A>St־Sݛ(pfnZk\~ ooz_H2ON۽{Ǐ^݋r|gc.3`r%_~'Mg̵[|> <<@Xxendstream endobj 233 0 obj << /Filter /FlateDecode /Length 1250 >> stream xV6PL\Z-B'q&q4Ї%RivG$~{ix/d04ש+ӟɷ7 ×X%'VO 1K4i(f-1"[Qc )NќR "UFss"Up^Y$(YPN+FvF#~ueOf7:~D!\tae@_fΰzNy,0}ќlf -Cpq8eLc8<JbSuRN$pO~!$)0IB.'ڙV%H=h@^))5e |T1EnV[Q nl^}}d 8./TCv "VA$a)􇻹vo;:a R+#u(Ds.uUʺw>V+0YV݌)* 13%M=M޶KdEgObzcު3f`ZMlC5ۻ>urʙd oIN6ãvYKͻ7'j&E#uC|B'$fGwxR0WğNC+D&R;3!m݋x[_{'fN_}uέ9NuN`rn#7U~gzH $mX!1vwyD tđ>[FăS56U0,~MEC/Дk`v>o݃%‹IGkpp?g7y3o(u>cC4|[^ Y7uqvM\nKagl~=fgop/XcHkX04߭I͉n nm 0*cX TS`H @N1ӓ+՚G71QlipM~^ᨯ\_|2|TC]D+F{endstream endobj 234 0 obj << /Filter /FlateDecode /Length 3384 >> stream xZkoPDТg@m4hj(#c]E{ϝά ;3ucV?ͻ;?wny?k@i]9׭(:旻/+ds 暛EvJֹf[\!b2m?OgשraPM8"r쉋 ?“s("uwUԹ\f?>}EvЎezε-йo6?3ksfLtLܹvnfa;m}3)sYa[Q11[X;(e +O1]io. N(EZZ]k"[e@1ŪVQƶ 6U՞@!ny8I/I#tk;M)QGYt F(XTDѭ%(Aڸ-Ԃ(<pG ,7BF% >W+Q,cq,<{ Dm-Ch*A!eZ?E ^f}7&ȿP$F@qPRe:t,(Bf H s)u`WpEJɥ;J?J)Xv>At1@Szh(G.HT/P5޺vA8E4B(1b+ :@1Øs| Bh)T1EA wIAvcw~Bf\23WFf*223W,hFf*YS'2tDԠ3Ev2^ڨGHqb#~ @iX)MaAoS%J)J_/%?D'Y_lt܏=o>ZmZ9 z DVU\4HYGSp֡`GE|Ȑ74##`O-}t5rZVwfr<-ս9-+Q^E!#yw݌qT ! dmE _LmJº9yu䈪½tn9Q$+ǁ(VʅDx( "g ʿl-,9[>vޠ)2܌~s{_y/"ۃ1H)f1fBۤ U<T Q`vz6u9ǘs˙&4nG$'O`B(x~]ND}"Pg`}?9Ie``469|^tSwà W#͏2EሳOGa%E QCG*MoB1xY}NM{𱎆t>0.,f: uYƖN (~RT'Cm-)Jdw3>,䖘c;-&LIq&5N\L%Z.:S`||I=EeuZ5Ĭcq'MYQT" LJ"^-A763豭I,U> mDu@SV26aX1V)]Y74~bl ~:\n`K!y.}ylz1hV Wmh{_TmO6>-7v玂+7wjsJEכ*x ^ 7ɤwik)EhHrs}mUMf8(QhU1ᤂGv&+Z*:{|Լ #PX{N: '+SAiGnȗwׇ!DUKl\OMC{t/C-bz11.z1&4YlܻvzPNLYcTTLݨ?G%{|K\YuM1.'UU^u^YExlOWMOD({Nz>{B NyD(Gu3IwzT 1.q?6P9׫rw;LF ڄMhGW2 5MHoGBݦwrLEA耎iSNh[ɚ*Xx/ ը5듥Rޅ9"kqLd㸃6u#mο?ѝ42`7"_?^vb焉`F#M7<[caoɳendstream endobj 235 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 346 >> stream xcd`ab`dd N+64O,,M f!CgO/nnC }_1<=9(3=DXWHZ*$U*8)x%&ggg*$(x)34R3sBR#B]܃C53000103012_*ÂO|qwaW[ߙV޽4w~+wsne׋!۹Y}} 5.v*T];G҅?|_8{! 'r\,!!<<܇zl^}?20lendstream endobj 236 0 obj << /Filter /FlateDecode /Length 940 >> stream xVr8#ZoK0Tblb8XtlPɂ3Xp%rT^Xu{]J0Mg$$N%Q52Y ;C*MhiZ.ӲI#Yk3;f2@7DVݐ1 !{]`s mdr!&,cc*3EmO.ۭU&[trAS4}d,|DUP5(_f .#fwqflƏ#j#ᏀaG`Ưå 8 8~f5xW^#ܼH>bNkendstream endobj 237 0 obj << /Type /XRef /Length 218 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 238 /ID [<1d3f125f1bceaffcbe7bf4eb2c7dc038>] >> stream xcb&F~0 $8J "KlpPyu4匒ӌzR [:(ŁHwDgH)aAbZ = 6"؄4Z"yHR)6S_D`\"6`5``CA$ , RDׁ:6(d ش{`~V{"[22 endstream endobj startxref 136711 %%EOF partykit/inst/doc/ctree.Rnw0000644000176200001440000015516214172230001015435 0ustar liggesusers\documentclass[nojss]{jss} %\VignetteIndexEntry{ctree: Conditional Inference Trees} %\VignetteDepends{coin, TH.data, survival, strucchange, Formula, sandwich, datasets} %\VignetteKeywords{conditional inference, non-parametric models, recursive partitioning} %\VignettePackage{partykit} %% packages \usepackage{amstext} \usepackage{amsfonts} \usepackage{amsmath} \usepackage{thumbpdf} \usepackage{rotating} %% need no \usepackage{Sweave} \usepackage[utf8]{inputenc} %% commands \newcommand{\fixme}[1]{\emph{\marginpar{FIXME} (#1)}} \renewcommand{\Prob}{\mathbb{P} } \renewcommand{\E}{\mathbb{E}} \newcommand{\V}{\mathbb{V}} \newcommand{\Var}{\mathbb{V}} \newcommand{\R}{\mathbb{R} } \newcommand{\N}{\mathbb{N} } %%\newcommand{\C}{\mathbb{C} } \newcommand{\argmin}{\operatorname{argmin}\displaylimits} \newcommand{\argmax}{\operatorname{argmax}\displaylimits} \newcommand{\LS}{\mathcal{L}_n} \newcommand{\TS}{\mathcal{T}_n} \newcommand{\LSc}{\mathcal{L}_{\text{comb},n}} \newcommand{\LSbc}{\mathcal{L}^*_{\text{comb},n}} \newcommand{\F}{\mathcal{F}} \newcommand{\A}{\mathcal{A}} \newcommand{\yn}{y_{\text{new}}} \newcommand{\z}{\mathbf{z}} \newcommand{\X}{\mathbf{X}} \newcommand{\Y}{\mathbf{Y}} \newcommand{\sX}{\mathcal{X}} \newcommand{\sY}{\mathcal{Y}} \newcommand{\T}{\mathbf{T}} \newcommand{\x}{\mathbf{x}} \renewcommand{\a}{\mathbf{a}} \newcommand{\xn}{\mathbf{x}_{\text{new}}} \newcommand{\y}{\mathbf{y}} \newcommand{\w}{\mathbf{w}} \newcommand{\ws}{\mathbf{w}_\cdot} \renewcommand{\t}{\mathbf{t}} \newcommand{\M}{\mathbf{M}} \renewcommand{\vec}{\text{vec}} \newcommand{\B}{\mathbf{B}} \newcommand{\K}{\mathbf{K}} \newcommand{\W}{\mathbf{W}} \newcommand{\D}{\mathbf{D}} \newcommand{\I}{\mathbf{I}} \newcommand{\bS}{\mathbf{S}} \newcommand{\cellx}{\pi_n[\x]} \newcommand{\partn}{\pi_n(\mathcal{L}_n)} \newcommand{\err}{\text{Err}} \newcommand{\ea}{\widehat{\text{Err}}^{(a)}} \newcommand{\ecv}{\widehat{\text{Err}}^{(cv1)}} \newcommand{\ecvten}{\widehat{\text{Err}}^{(cv10)}} \newcommand{\eone}{\widehat{\text{Err}}^{(1)}} \newcommand{\eplus}{\widehat{\text{Err}}^{(.632+)}} \newcommand{\eoob}{\widehat{\text{Err}}^{(oob)}} \newcommand{\bft}{\mathbf{t}} \hyphenation{Qua-dra-tic} \title{\texttt{ctree}: Conditional Inference Trees} \Plaintitle{ctree: Conditional Inference Trees} \author{Torsten Hothorn\\Universit\"at Z\"urich \And Kurt Hornik\\Wirtschaftsuniversit\"at Wien \And Achim Zeileis\\Universit\"at Innsbruck} \Plainauthor{Torsten Hothorn, Kurt Hornik, Achim Zeileis} \Abstract{ This vignette describes the new reimplementation of conditional inference trees (CTree) in the \proglang{R} package \pkg{partykit}. CTree is a non-parametric class of regression trees embedding tree-structured regression models into a well defined theory of conditional inference procedures. It is applicable to all kinds of regression problems, including nominal, ordinal, numeric, censored as well as multivariate response variables and arbitrary measurement scales of the covariates. The vignette comprises a practical guide to exploiting the flexible and extensible computational tools in \pkg{partykit} for fitting and visualizing conditional inference trees. } \Keywords{conditional inference, non-parametric models, recursive partitioning} \Address{ Torsten Hothorn\\ Institut f\"ur Epidemiologie, Biostatistik und Pr\"avention \\ Universit\"at Z\"urich \\ Hirschengraben 84\\ CH-8001 Z\"urich, Switzerland \\ E-mail: \email{Torsten.Hothorn@R-project.org}\\ URL: \url{http://user.math.uzh.ch/hothorn/}\\ Kurt Hornik \\ Institute for Statistics and Mathematics\\ WU Wirtschaftsuniversit\"at Wien\\ Welthandelsplatz 1 \\ 1020 Wien, Austria\\ E-mail: \email{Kurt.Hornik@R-project.org} \\ URL: \url{http://statmath.wu.ac.at/~hornik/}\\ Achim Zeileis \\ Department of Statistics \\ Faculty of Economics and Statistics \\ Universit\"at Innsbruck \\ Universit\"atsstr.~15 \\ 6020 Innsbruck, Austria \\ E-mail: \email{Achim.Zeileis@R-project.org} \\ URL: \url{http://eeecon.uibk.ac.at/~zeileis/} } \begin{document} <>= suppressWarnings(RNGversion("3.5.2")) options(width = 70, SweaveHooks = list(leftpar = function() par(mai = par("mai") * c(1, 1.1, 1, 1)))) require("partykit") require("coin") require("strucchange") require("coin") require("Formula") require("survival") require("sandwich") set.seed(290875) @ \setkeys{Gin}{width=\textwidth} \section{Overview} This vignette describes conditional inference trees \citep{Hothorn+Hornik+Zeileis:2006} along with its new and improved reimplementation in package \pkg{partykit}. Originally, the method was implemented in the package \pkg{party} almost entirely in \proglang{C} while the new implementation is now almost entirely in \proglang{R}. In particular, this has the advantage that all the generic infrastructure from \pkg{partykit} can be reused, making many computations more modular and easily extensible. Hence, \code{partykit::ctree} is the new reference implementation that will be improved and developed further in the future. In almost all cases, the two implementations will produce identical trees. In exceptional cases, additional parameters have to be specified in order to ensure backward compatibility. These and novel features in \code{ctree:partykit} are introduced in Section~\ref{sec:novel}. \section{Introduction} The majority of recursive partitioning algorithms are special cases of a simple two-stage algorithm: First partition the observations by univariate splits in a recursive way and second fit a constant model in each cell of the resulting partition. The most popular implementations of such algorithms are `CART' \citep{Breiman+Friedman+Olshen:1984} and `C4.5' \citep{Quinlan:1993}. Not unlike AID, both perform an exhaustive search over all possible splits maximizing an information measure of node impurity selecting the covariate showing the best split. This approach has two fundamental problems: overfitting and a selection bias towards covariates with many possible splits. With respect to the overfitting problem \cite{Mingers:1987} notes that the algorithm \begin{quote} [\ldots] has no concept of statistical significance, and so cannot distinguish between a significant and an insignificant improvement in the information measure. \end{quote} With conditional inference trees \citep[see][for a full description of its methodological foundations]{Hothorn+Hornik+Zeileis:2006} we enter at the point where \cite{White+Liu:1994} demand for \begin{quote} [\ldots] a \textit{statistical} approach [to recursive partitioning] which takes into account the \textit{distributional} properties of the measures. \end{quote} We present a unified framework embedding recursive binary partitioning into the well defined theory of permutation tests developed by \cite{Strasser+Weber:1999}. The conditional distribution of statistics measuring the association between responses and covariates is the basis for an unbiased selection among covariates measured at different scales. Moreover, multiple test procedures are applied to determine whether no significant association between any of the covariates and the response can be stated and the recursion needs to stop. \section{Recursive binary partitioning} \label{algo} We focus on regression models describing the conditional distribution of a response variable $\Y$ given the status of $m$ covariates by means of tree-structured recursive partitioning. The response $\Y$ from some sample space $\sY$ may be multivariate as well. The $m$-dimensional covariate vector $\X = (X_1, \dots, X_m)$ is taken from a sample space $\sX = \sX_1 \times \cdots \times \sX_m$. Both response variable and covariates may be measured at arbitrary scales. We assume that the conditional distribution $D(\Y | \X)$ of the response $\Y$ given the covariates $\X$ depends on a function $f$ of the covariates \begin{eqnarray*} D(\Y | \X) = D(\Y | X_1, \dots, X_m) = D(\Y | f( X_1, \dots, X_m)), \end{eqnarray*} where we restrict ourselves to partition based regression relationships, i.e., $r$ disjoint cells $B_1, \dots, B_r$ partitioning the covariate space $\sX = \bigcup_{k = 1}^r B_k$. A model of the regression relationship is to be fitted based on a learning sample $\LS$, i.e., a random sample of $n$ independent and identically distributed observations, possibly with some covariates $X_{ji}$ missing, \begin{eqnarray*} \LS & = & \{ (\Y_i, X_{1i}, \dots, X_{mi}); i = 1, \dots, n \}. \end{eqnarray*} A generic algorithm for recursive binary partitioning for a given learning sample $\LS$ can be formulated using non-negative integer valued case weights $\w = (w_1, \dots, w_n)$. Each node of a tree is represented by a vector of case weights having non-zero elements when the corresponding observations are elements of the node and are zero otherwise. The following algorithm implements recursive binary partitioning: \begin{enumerate} \item For case weights $\w$ test the global null hypothesis of independence between any of the $m$ covariates and the response. Stop if this hypothesis cannot be rejected. Otherwise select the covariate $X_{j^*}$ with strongest association to $\Y$. \item Choose a set $A^* \subset \sX_{j^*}$ in order to split $\sX_{j^*}$ into two disjoint sets $A^*$ and $\sX_{j^*} \setminus A^*$. The case weights $\w_\text{left}$ and $\w_\text{right}$ determine the two subgroups with $w_{\text{left},i} = w_i I(X_{j^*i} \in A^*)$ and $w_{\text{right},i} = w_i I(X_{j^*i} \not\in A^*)$ for all $i = 1, \dots, n$ ($I(\cdot)$ denotes the indicator function). \item Recursively repeat steps 1 and 2 with modified case weights $\w_\text{left}$ and $\w_\text{right}$, respectively. \end{enumerate} The separation of variable selection and splitting procedure into steps 1 and 2 of the algorithm is the key for the construction of interpretable tree structures not suffering a systematic tendency towards covariates with many possible splits or many missing values. In addition, a statistically motivated and intuitive stopping criterion can be implemented: We stop when the global null hypothesis of independence between the response and any of the $m$ covariates cannot be rejected at a pre-specified nominal level~$\alpha$. The algorithm induces a partition $\{B_1, \dots, B_r\}$ of the covariate space $\sX$, where each cell $B \in \{B_1, \dots, B_r\}$ is associated with a vector of case weights. \section{Recursive partitioning by conditional inference} \label{framework} In the main part of this section we focus on step 1 of the generic algorithm. Unified tests for independence are constructed by means of the conditional distribution of linear statistics in the permutation test framework developed by \cite{Strasser+Weber:1999}. The determination of the best binary split in one selected covariate and the handling of missing values is performed based on standardized linear statistics within the same framework as well. \subsection{Variable selection and stopping criteria} At step 1 of the generic algorithm given in Section~\ref{algo} we face an independence problem. We need to decide whether there is any information about the response variable covered by any of the $m$ covariates. In each node identified by case weights $\w$, the global hypothesis of independence is formulated in terms of the $m$ partial hypotheses $H_0^j: D(\Y | X_j) = D(\Y)$ with global null hypothesis $H_0 = \bigcap_{j = 1}^m H_0^j$. When we are not able to reject $H_0$ at a pre-specified level $\alpha$, we stop the recursion. If the global hypothesis can be rejected, we measure the association between $\Y$ and each of the covariates $X_j, j = 1, \dots, m$, by test statistics or $P$-values indicating the deviation from the partial hypotheses $H_0^j$. For notational convenience and without loss of generality we assume that the case weights $w_i$ are either zero or one. The symmetric group of all permutations of the elements of $(1, \dots, n)$ with corresponding case weights $w_i = 1$ is denoted by $S(\LS, \w)$. A more general notation is given in the Appendix. We measure the association between $\Y$ and $X_j, j = 1, \dots, m$, by linear statistics of the form \begin{eqnarray} \label{linstat} \T_j(\LS, \w) = \vec \left( \sum_{i=1}^n w_i g_j(X_{ji}) h(\Y_i, (\Y_1, \dots, \Y_n))^\top \right) \in \R^{p_jq} \end{eqnarray} where $g_j: \sX_j \rightarrow \R^{p_j}$ is a non-random transformation of the covariate $X_j$. The transformation may be specified using the \code{xtrafo} argument (Note: this argument is currently not implemented in \code{partykit::ctree} but is available from \code{party::ctree}). %%If, for example, a ranking \textit{both} %%\code{x1} and \code{x2} is required, %%<>= %%party:::ctree(y ~ x1 + x2, data = ls, xtrafo = function(data) trafo(data, %%numeric_trafo = rank)) %%@ %%can be used. The \emph{influence function} $h: \sY \times \sY^n \rightarrow \R^q$ depends on the responses $(\Y_1, \dots, \Y_n)$ in a permutation symmetric way. %%, i.e., $h(\Y_i, (\Y_1, \dots, \Y_n)) = h(\Y_i, (\Y_{\sigma(1)}, \dots, %%\Y_{\sigma(n)}))$ for all permutations $\sigma \in S(\LS, \w)$. Section~\ref{examples} explains how to choose $g_j$ and $h$ in different practical settings. A $p_j \times q$ matrix is converted into a $p_jq$ column vector by column-wise combination using the `vec' operator. The influence function can be specified using the \code{ytrafo} argument. The distribution of $\T_j(\LS, \w)$ under $H_0^j$ depends on the joint distribution of $\Y$ and $X_j$, which is unknown under almost all practical circumstances. At least under the null hypothesis one can dispose of this dependency by fixing the covariates and conditioning on all possible permutations of the responses. This principle leads to test procedures known as \textit{permutation tests}. The conditional expectation $\mu_j \in \R^{p_jq}$ and covariance $\Sigma_j \in \R^{p_jq \times p_jq}$ of $\T_j(\LS, \w)$ under $H_0$ given all permutations $\sigma \in S(\LS, \w)$ of the responses are derived by \cite{Strasser+Weber:1999}: \begin{eqnarray} \mu_j & = & \E(\T_j(\LS, \w) | S(\LS, \w)) = \vec \left( \left( \sum_{i = 1}^n w_i g_j(X_{ji}) \right) \E(h | S(\LS, \w))^\top \right), \nonumber \\ \Sigma_j & = & \V(\T_j(\LS, \w) | S(\LS, \w)) \nonumber \\ & = & \frac{\ws}{\ws - 1} \V(h | S(\LS, \w)) \otimes \left(\sum_i w_i g_j(X_{ji}) \otimes w_i g_j(X_{ji})^\top \right) \label{expectcovar} \\ & - & \frac{1}{\ws - 1} \V(h | S(\LS, \w)) \otimes \left( \sum_i w_i g_j(X_{ji}) \right) \otimes \left( \sum_i w_i g_j(X_{ji})\right)^\top \nonumber \end{eqnarray} where $\ws = \sum_{i = 1}^n w_i$ denotes the sum of the case weights, $\otimes$ is the Kronecker product and the conditional expectation of the influence function is \begin{eqnarray*} \E(h | S(\LS, \w)) = \ws^{-1} \sum_i w_i h(\Y_i, (\Y_1, \dots, \Y_n)) \in \R^q \end{eqnarray*} with corresponding $q \times q$ covariance matrix \begin{eqnarray*} \V(h | S(\LS, \w)) = \ws^{-1} \sum_i w_i \left(h(\Y_i, (\Y_1, \dots, \Y_n)) - \E(h | S(\LS, \w)) \right) \\ \left(h(\Y_i, (\Y_1, \dots, \Y_n)) - \E(h | S(\LS, \w))\right)^\top. \end{eqnarray*} Having the conditional expectation and covariance at hand we are able to standardize a linear statistic $\T \in \R^{pq}$ of the form (\ref{linstat}) for some $p \in \{p_1, \dots, p_m\}$. Univariate test statistics~$c$ mapping an observed multivariate linear statistic $\bft \in \R^{pq}$ into the real line can be of arbitrary form. An obvious choice is the maximum of the absolute values of the standardized linear statistic \begin{eqnarray*} c_\text{max}(\bft, \mu, \Sigma) = \max_{k = 1, \dots, pq} \left| \frac{(\bft - \mu)_k}{\sqrt{(\Sigma)_{kk}}} \right| \end{eqnarray*} utilizing the conditional expectation $\mu$ and covariance matrix $\Sigma$. The application of a quadratic form $c_\text{quad}(\bft, \mu, \Sigma) = (\bft - \mu) \Sigma^+ (\bft - \mu)^\top$ is one alternative, although computationally more expensive because the Moore-Penrose inverse $\Sigma^+$ of $\Sigma$ is involved. The type of test statistic to be used can be specified by means of the \code{ctree\_control} function, for example <>= ctree_control(teststat = "max") @ uses $c_\text{max}$ and <>= ctree_control(teststat = "quad") @ takes $c_\text{quad}$ (the default). It is important to note that the test statistics $c(\bft_j, \mu_j, \Sigma_j), j = 1, \dots, m$, cannot be directly compared in an unbiased way unless all of the covariates are measured at the same scale, i.e., $p_1 = p_j, j = 2, \dots, m$. In order to allow for an unbiased variable selection we need to switch to the $P$-value scale because $P$-values for the conditional distribution of test statistics $c(\T_j(\LS, \w), \mu_j, \Sigma_j)$ can be directly compared among covariates measured at different scales. In step 1 of the generic algorithm we select the covariate with minimum $P$-value, i.e., the covariate $X_{j^*}$ with $j^* = \argmin_{j = 1, \dots, m} P_j$, where \begin{displaymath} P_j = \Prob_{H_0^j}(c(\T_j(\LS, \w), \mu_j, \Sigma_j) \ge c(\bft_j, \mu_j, \Sigma_j) | S(\LS, \w)) \end{displaymath} denotes the $P$-value of the conditional test for $H_0^j$. So far, we have only addressed testing each partial hypothesis $H_0^j$, which is sufficient for an unbiased variable selection. A global test for $H_0$ required in step 1 can be constructed via an aggregation of the transformations $g_j, j = 1, \dots, m$, i.e., using a linear statistic of the form \begin{eqnarray*} \T(\LS, \w) = \vec \left( \sum_{i=1}^n w_i \left(g_1(X_{1i})^\top, \dots, g_m(X_{mi})^\top\right)^\top h(\Y_i, (\Y_1, \dots, \Y_n))^\top \right). %%\in \R^{\sum_j p_jq} \end{eqnarray*} However, this approach is less attractive for learning samples with missing values. Universally applicable approaches are multiple test procedures based on $P_1, \dots, P_m$. Simple Bonferroni-adjusted $P$-values (the adjustment $1 - (1 - P_j)^m$ is used), available via <>= ctree_control(testtype = "Bonferroni") @ or a min-$P$-value resampling approach (Note: resampling is currently not implemented in \code{partykit::ctree}) %<>= %party:::ctree_control(testtype = "MonteCarlo") %@ are just examples and we refer to the multiple testing literature \citep[e.g.,][]{Westfall+Young:1993} for more advanced methods. We reject $H_0$ when the minimum of the adjusted $P$-values is less than a pre-specified nominal level $\alpha$ and otherwise stop the algorithm. In this sense, $\alpha$ may be seen as a unique parameter determining the size of the resulting trees. \subsection{Splitting criteria} Once we have selected a covariate in step 1 of the algorithm, the split itself can be established by any split criterion, including those established by \cite{Breiman+Friedman+Olshen:1984} or \cite{Shih:1999}. Instead of simple binary splits, multiway splits can be implemented as well, for example utilizing the work of \cite{OBrien:2004}. However, most splitting criteria are not applicable to response variables measured at arbitrary scales and we therefore utilize the permutation test framework described above to find the optimal binary split in one selected covariate $X_{j^*}$ in step~2 of the generic algorithm. The goodness of a split is evaluated by two-sample linear statistics which are special cases of the linear statistic (\ref{linstat}). For all possible subsets $A$ of the sample space $\sX_{j^*}$ the linear statistic \begin{eqnarray*} \T^A_{j^*}(\LS, \w) = \vec \left( \sum_{i=1}^n w_i I(X_{j^*i} \in A) h(\Y_i, (\Y_1, \dots, \Y_n))^\top \right) \in \R^{q} \end{eqnarray*} induces a two-sample statistic measuring the discrepancy between the samples $\{ \Y_i | w_i > 0 \text{ and } X_{ji} \in A; i = 1, \dots, n\}$ and $\{ \Y_i | w_i > 0 \text{ and } X_{ji} \not\in A; i = 1, \dots, n\}$. The conditional expectation $\mu_{j^*}^A$ and covariance $\Sigma_{j^*}^A$ can be computed by (\ref{expectcovar}). The split $A^*$ with a test statistic maximized over all possible subsets $A$ is established: \begin{eqnarray} \label{split} A^* = \argmax_A c(\bft_{j^*}^A, \mu_{j^*}^A, \Sigma_{j^*}^A). \end{eqnarray} The statistics $c(\bft_{j^*}^A, \mu_{j^*}^A, \Sigma_{j^*}^A)$ are available for each node with %<>= %party:::ctree_control(savesplitstats = TRUE) %@ and can be used to depict a scatter plot of the covariate $\sX_{j^*}$ against the statistics (Note: this feature is currently not implemented in \pkg{partykit}). Note that we do not need to compute the distribution of $c(\bft_{j^*}^A, \mu_{j^*}^A, \Sigma_{j^*}^A)$ in step~2. In order to anticipate pathological splits one can restrict the number of possible subsets that are evaluated, for example by introducing restrictions on the sample size or the sum of the case weights in each of the two groups of observations induced by a possible split. For example, <>= ctree_control(minsplit = 20) @ requires the sum of the weights in both the left and right daughter node to exceed the value of $20$. \subsection{Missing values and surrogate splits} If an observation $X_{ji}$ in covariate $X_j$ is missing, we set the corresponding case weight $w_i$ to zero for the computation of $\T_j(\LS, \w)$ and, if we would like to split in $X_j$, in $\T_{j}^A(\LS, \w)$ as well. Once a split $A^*$ in $X_j$ has been implemented, surrogate splits can be established by searching for a split leading to roughly the same division of the observations as the original split. One simply replaces the original response variable by a binary variable $I(X_{ji} \in A^*)$ coding the split and proceeds as described in the previous part. The number of surrogate splits can be controlled using <>= ctree_control(maxsurrogate = 3) @ \subsection{Fitting and inspecting a tree} For the sake of simplicity, we use a learning sample <>= ls <- data.frame(y = gl(3, 50, labels = c("A", "B", "C")), x1 = rnorm(150) + rep(c(1, 0, 0), c(50, 50, 50)), x2 = runif(150)) @ in the following illustrations. In \code{partykit::ctree}, the dependency structure and the variables may be specified in a traditional formula based way <>= library("partykit") ctree(y ~ x1 + x2, data = ls) @ Case counts $\w$ may be specified using the \code{weights} argument. Once we have fitted a conditional tree via <>= ct <- ctree(y ~ x1 + x2, data = ls) @ we can inspect the results via a \code{print} method <>= ct @ or by looking at a graphical representation as in Figure~\ref{party-plot1}. \begin{figure}[t!] \centering <>= plot(ct) @ \caption{A graphical representation of a classification tree. \label{party-plot1}} \end{figure} Each node can be extracted by its node number, i.e., the root node is <>= ct[1] @ This object is an object of class <>= class(ct[1]) @ and we refer to the manual pages for a description of those elements. The \code{predict} function computes predictions in the space of the response variable, in our case a factor <>= predict(ct, newdata = ls) @ When we are interested in properties of the conditional distribution of the response given the covariates, we use <>= predict(ct, newdata = ls[c(1, 51, 101),], type = "prob") @ which, in our case, is a data frame with conditional class probabilities. We can determine the node numbers of nodes some new observations are falling into by <>= predict(ct, newdata = ls[c(1,51,101),], type = "node") @ Finally, the \code{sctest} method can be used to extract the test statistics and $p$-values computed in each node. The function \code{sctest} is used because for the \code{mob} algorithm such a method (for \underline{s}tructural \underline{c}hange \underline{test}s) is also provided. To make the generic available, the \pkg{strucchange} package needs to be loaded (otherwise \code{sctest.constparty} would have to be called directly). <>= library("strucchange") sctest(ct) @ Here, we see that \code{x1} leads to a significant test result in the root node and is hence used for splitting. In the kid nodes, no more significant results are found and hence splitting stops. For other data sets, other stopping criteria might also be relevant (e.g., the sample size restrictions \code{minsplit}, \code{minbucket}, etc.). In case, splitting stops due to these, the test results may also be \code{NULL}. \section{Examples} \label{examples} \subsection{Univariate continuous or discrete regression} For a univariate numeric response $\Y \in \R$, the most natural influence function is the identity $h(\Y_i, (\Y_1, \dots, \Y_n)) = \Y_i$. In case some observations with extremely large or small values have been observed, a ranking of the observations may be appropriate: $h(\Y_i, (\Y_1, \dots, \Y_n)) = \sum_{k=1}^n w_k I(\Y_k \le \Y_i)$ for $i = 1, \dots, n$. Numeric covariates can be handled by the identity transformation $g_{ji}(x) = x$ (ranks are possible, too). Nominal covariates at levels $1, \dots, K$ are represented by $g_{ji}(k) = e_K(k)$, the unit vector of length $K$ with $k$th element being equal to one. Due to this flexibility, special test procedures like the Spearman test, the Wilcoxon-Mann-Whitney test or the Kruskal-Wallis test and permutation tests based on ANOVA statistics or correlation coefficients are covered by this framework. Splits obtained from (\ref{split}) maximize the absolute value of the standardized difference between two means of the values of the influence functions. For prediction, one is usually interested in an estimate of the expectation of the response $\E(\Y | \X = \x)$ in each cell, an estimate can be obtained by \begin{eqnarray*} \hat{\E}(\Y | \X = \x) = \left(\sum_{i=1}^n w_i(\x)\right)^{-1} \sum_{i=1}^n w_i(\x) \Y_i. \end{eqnarray*} \subsection{Censored regression} The influence function $h$ may be chosen as Logrank or Savage scores taking censoring into account and one can proceed as for univariate continuous regression. This is essentially the approach first published by \cite{Segal:1988}. An alternative is the weighting scheme suggested by \cite{Molinaro+Dudiot+VanDerLaan:2003}. A weighted Kaplan-Meier curve for the case weights $\w(\x)$ can serve as prediction. \subsection{$J$-class classification} The nominal response variable at levels $1, \dots, J$ is handled by influence functions\linebreak $h(\Y_i, (\Y_1, \dots, \Y_n)) = e_J(\Y_i)$. Note that for a nominal covariate $X_j$ at levels $1, \dots, K$ with $g_{ji}(k) = e_K(k)$ the corresponding linear statistic $\T_j$ is a vectorized contingency table. The conditional class probabilities can be estimated via \begin{eqnarray*} \hat{\Prob}(\Y = y | \X = \x) = \left(\sum_{i=1}^n w_i(\x)\right)^{-1} \sum_{i=1}^n w_i(\x) I(\Y_i = y), \quad y = 1, \dots, J. \end{eqnarray*} \subsection{Ordinal regression} Ordinal response variables measured at $J$ levels, and ordinal covariates measured at $K$ levels, are associated with score vectors $\xi \in \R^J$ and $\gamma \in \R^K$, respectively. Those scores reflect the `distances' between the levels: If the variable is derived from an underlying continuous variable, the scores can be chosen as the midpoints of the intervals defining the levels. The linear statistic is now a linear combination of the linear statistic $\T_j$ of the form \begin{eqnarray*} \M \T_j(\LS, \w) & = & \vec \left( \sum_{i=1}^n w_i \gamma^\top g_j(X_{ji}) \left(\xi^\top h(\Y_i, (\Y_1, \dots, \Y_n)\right)^\top \right) \end{eqnarray*} with $g_j(x) = e_K(x)$ and $h(\Y_i, (\Y_1, \dots, \Y_n)) = e_J(\Y_i)$. If both response and covariate are ordinal, the matrix of coefficients is given by the Kronecker product of both score vectors $\M = \xi \otimes \gamma \in \R^{1, KJ}$. In case the response is ordinal only, the matrix of coefficients $\M$ is a block matrix \begin{eqnarray*} \M = \left( \begin{array}{ccc} \xi_1 & & 0 \\ & \ddots & \\ 0 & & \xi_1 \end{array} \right| %%\left. %% \begin{array}{ccc} %% \xi_2 & & 0 \\ %% & \ddots & \\ %% 0 & & \xi_2 %% \end{array} \right| %%\left. \begin{array}{c} \\ \hdots \\ \\ \end{array} %%\right. \left| \begin{array}{ccc} \xi_q & & 0 \\ & \ddots & \\ 0 & & \xi_q \end{array} \right) %%\in \R^{K, KJ} %%\end{eqnarray*} \text{ or } %%and if one covariate is ordered %%\begin{eqnarray*} %%\M = \left( %% \begin{array}{cccc} %% \gamma & 0 & & 0 \\ %% 0 & \gamma & & \vdots \\ %% 0 & 0 & \hdots & 0 \\ %% \vdots & \vdots & & 0 \\ %% 0 & 0 & & \gamma %% \end{array} %% \right) \M = \text{diag}(\gamma) %%\in \R^{J, KJ} \end{eqnarray*} when one covariate is ordered but the response is not. For both $\Y$ and $X_j$ being ordinal, the corresponding test is known as linear-by-linear association test \citep{Agresti:2002}. Scores can be supplied to \code{ctree} using the \code{scores} argument, see Section~\ref{illustrations} for an example. \subsection{Multivariate regression} For multivariate responses, the influence function is a combination of influence functions appropriate for any of the univariate response variables discussed in the previous paragraphs, e.g., indicators for multiple binary responses \citep{Zhang:1998,Noh+Song+Park:2004}, Logrank or Savage scores for multiple failure times %%\citep[for example tooth loss times, ][]{SuFan2004} and the original observations or a rank transformation for multivariate regression \citep{Death:2002}. \section{Illustrations and applications} \label{illustrations} In this section, we present regression problems which illustrate the potential fields of application of the methodology. Conditional inference trees based on $c_\text{quad}$-type test statistics using the identity influence function for numeric responses and asymptotic $\chi^2$ distribution are applied. For the stopping criterion a simple Bonferroni correction is used and we follow the usual convention by choosing the nominal level of the conditional independence tests as $\alpha = 0.05$. \subsection{Tree pipit abundance} <>= data("treepipit", package = "coin") tptree <- ctree(counts ~ ., data = treepipit) @ \begin{figure}[t!] \centering <>= plot(tptree, terminal_panel = node_barplot) @ \caption{Conditional regression tree for the tree pipit data.} \end{figure} <>= p <- info_node(node_party(tptree))$p.value n <- table(predict(tptree, type = "node")) @ The impact of certain environmental factors on the population density of the tree pipit \textit{Anthus trivialis} %%in Frankonian oak forests is investigated by \cite{Mueller+Hothorn:2004}. The occurrence of tree pipits was recorded several times at $n = 86$ stands which were established on a long environmental gradient. Among nine environmental factors, the covariate showing the largest association to the number of tree pipits is the canopy overstorey $(P = \Sexpr{round(p, 3)})$. Two groups of stands can be distinguished: Sunny stands with less than $40\%$ canopy overstorey $(n = \Sexpr{n[1]})$ show a significantly higher density of tree pipits compared to darker stands with more than $40\%$ canopy overstorey $(n = \Sexpr{n[2]})$. This result is important for management decisions in forestry enterprises: Cutting the overstorey with release of old oaks creates a perfect habitat for this indicator species of near natural forest environments. \subsection{Glaucoma and laser scanning images} <>= data("GlaucomaM", package = "TH.data") gtree <- ctree(Class ~ ., data = GlaucomaM) @ <>= sp <- split_node(node_party(gtree))$varID @ Laser scanning images taken from the eye background are expected to serve as the basis of an automated system for glaucoma diagnosis. Although prediction is more important in this application \citep{Mardin+Hothorn+Peters:2003}, a simple visualization of the regression relationship is useful for comparing the structures inherent in the learning sample with subject matter knowledge. For $98$ patients and $98$ controls, matched by age and gender, $62$ covariates describing the eye morphology are available. The data is part of the \pkg{TH.data} package, \url{http://CRAN.R-project.org}). The first split in Figure~\ref{glaucoma} separates eyes with a volume above reference less than $\Sexpr{sp} \text{ mm}^3$ in the inferior part of the optic nerve head (\code{vari}). Observations with larger volume are mostly controls, a finding which corresponds to subject matter knowledge: The volume above reference measures the thickness of the nerve layer, expected to decrease with a glaucomatous damage of the optic nerve. Further separation is achieved by the volume above surface global (\code{vasg}) and the volume above reference in the temporal part of the optic nerve head (\code{vart}). \setkeys{Gin}{width=.9\textwidth} \begin{figure}[p!] \centering <>= plot(gtree) @ \caption{Conditional inference tree for the glaucoma data. For each inner node, the Bonferroni-adjusted $P$-values are given, the fraction of glaucomatous eyes is displayed for each terminal node. \label{glaucoma}} <>= plot(gtree, inner_panel = node_barplot, edge_panel = function(...) invisible(), tnex = 1) @ \caption{Conditional inference tree for the glaucoma data with the fraction of glaucomatous eyes displayed for both inner and terminal nodes. \label{glaucoma-inner}} \end{figure} The plot in Figure~\ref{glaucoma} is generated by <>= plot(gtree) @ \setkeys{Gin}{width=\textwidth} and shows the distribution of the classes in the terminal nodes. This distribution can be shown for the inner nodes as well, namely by specifying the appropriate panel generating function (\code{node\_barplot} in our case), see Figure~\ref{glaucoma-inner}. <>= plot(gtree, inner_panel = node_barplot, edge_panel = function(...) invisible(), tnex = 1) @ %% TH: split statistics are not saved in partykit %As mentioned in Section~\ref{framework}, it might be interesting to have a %look at the split statistics the split point estimate was derived from. %Those statistics can be extracted from the \code{splitstatistic} element %of a split and one can easily produce scatterplots against the selected %covariate. For all three inner nodes of \code{gtree}, we produce such a %plot in Figure~\ref{glaucoma-split}. For the root node, the estimated split point %seems very natural, since the process of split statistics seems to have a %clear maximum indicating that the simple split point model is something %reasonable to assume here. This is less obvious for nodes $2$ and, %especially, $3$. % %\begin{figure}[t!] %\centering %<>= %cex <- 1.6 %inner <- nodes(gtree, c(1, 2, 5)) %layout(matrix(1:length(inner), ncol = length(inner))) %out <- sapply(inner, function(i) { % splitstat <- i$psplit$splitstatistic % x <- GlaucomaM[[i$psplit$variableName]][splitstat > 0] % plot(x, splitstat[splitstat > 0], main = paste("Node", i$nodeID), % xlab = i$psplit$variableName, ylab = "Statistic", ylim = c(0, 10), % cex.axis = cex, cex.lab = cex, cex.main = cex) % abline(v = i$psplit$splitpoint, lty = 3) %}) %@ %\caption{Split point estimation in each inner node. The process of % the standardized two-sample test statistics for each possible % split point in the selected input variable is show. % The estimated split point is given as vertical dotted line. % \label{glaucoma-split}} %\end{figure} The class predictions of the tree for the learning sample (and for new observations as well) can be computed using the \code{predict} function. A comparison with the true class memberships is done by <>= table(predict(gtree), GlaucomaM$Class) @ When we are interested in conditional class probabilities, the \code{predict(, type = "prob")} method must be used. A graphical representation is shown in Figure~\ref{glaucoma-probplot}. \setkeys{Gin}{width=.5\textwidth} \begin{figure}[t!] \centering <>= prob <- predict(gtree, type = "prob")[,1] + runif(nrow(GlaucomaM), min = -0.01, max = 0.01) splitvar <- character_split(split_node(node_party(gtree)), data = data_party(gtree))$name plot(GlaucomaM[[splitvar]], prob, pch = as.numeric(GlaucomaM$Class), ylab = "Conditional Class Prob.", xlab = splitvar) abline(v = split_node(node_party(gtree))$breaks, lty = 2) legend(0.15, 0.7, pch = 1:2, legend = levels(GlaucomaM$Class), bty = "n") @ \caption{Estimated conditional class probabilities (slightly jittered) for the Glaucoma data depending on the first split variable. The vertical line denotes the first split point. \label{glaucoma-probplot}} \end{figure} \subsection{Node positive breast cancer} Recursive partitioning for censored responses has attracted a lot of interest \citep[e.g.,][]{Segal:1988,LeBlanc+Crowley:1992}. Survival trees using $P$-value adjusted Logrank statistics are used by \cite{Schumacher+Hollaender+Schwarzer:2001a} for the evaluation of prognostic factors for the German Breast Cancer Study Group (GBSG2) data, a prospective controlled clinical trial on the treatment of node positive breast cancer patients. Here, we use Logrank scores as well. Complete data of seven prognostic factors of $686$ women are used for prognostic modeling, the dataset is available within the \pkg{TH.data} package. The number of positive lymph nodes (\code{pnodes}) and the progesterone receptor (\code{progrec}) have been identified as prognostic factors in the survival tree analysis by \cite{Schumacher+Hollaender+Schwarzer:2001a}. Here, the binary variable coding whether a hormonal therapy was applied or not (\code{horTh}) additionally is part of the model depicted in Figure~\ref{gbsg2}, which was fitted using the following code: <>= data("GBSG2", package = "TH.data") library("survival") (stree <- ctree(Surv(time, cens) ~ ., data = GBSG2)) @ \setkeys{Gin}{width=\textwidth} \begin{figure}[t!] \centering <>= plot(stree) @ \caption{Tree-structured survival model for the GBSG2 data and the distribution of survival times in the terminal nodes. The median survival time is displayed in each terminal node of the tree. \label{gbsg2}} \end{figure} The estimated median survival time for new patients is less informative compared to the whole Kaplan-Meier curve estimated from the patients in the learning sample for each terminal node. We can compute those `predictions' by means of the \code{treeresponse} method <>= pn <- predict(stree, newdata = GBSG2[1:2,], type = "node") n <- predict(stree, type = "node") survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[1])) survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[2])) @ \subsection{Mammography experience} <>= data("mammoexp", package = "TH.data") mtree <- ctree(ME ~ ., data = mammoexp) @ \setkeys{Gin}{width=.9\textwidth, keepaspectratio=TRUE} \begin{figure}[t!] \centering <>= plot(mtree) @ \caption{Ordinal regression for the mammography experience data with the fractions of (never, within a year, over one year) given in the nodes. No admissible split was found for node 5 because only $5$ of $91$ women reported a family history of breast cancer and the sample size restrictions would require more than $5$ observations in each daughter node. \label{mammoexp}} \end{figure} Ordinal response variables are common in investigations where the response is a subjective human interpretation. We use an example given by \cite{Hosmer+Lemeshow:2000}, p.~264, studying the relationship between the mammography experience (never, within a year, over one year) and opinions about mammography expressed in questionnaires answered by $n = 412$ women. The resulting partition based on scores $\xi = (1,2,3)$ is given in Figure~\ref{mammoexp}. Women who (strongly) agree with the question `You do not need a mammogram unless you develop symptoms' seldomly have experienced a mammography. The variable \code{benefit} is a score with low values indicating a strong agreement with the benefits of the examination. For those women in (strong) disagreement with the first question above, low values of \code{benefit} identify persons being more likely to have experienced such an examination at all. \subsection{Hunting spiders} Finally, we take a closer look at a challenging dataset on animal abundance first reported by \cite{VanDerAart+SmeenkEnserink:1975} and re-analyzed by \cite{Death:2002} using regression trees dealing with multivariate responses. The abundance of $12$ hunting spider species is regressed on six environmental variables (\code{water}, \code{sand}, \code{moss}, \code{reft}, \code{twigs} and \code{herbs}) for $n = 28$ observations. Because of the small sample size we allow for a split if at least $5$ observations are element of a node The prognostic factor \code{water} found by \cite{Death:2002} is confirmed by the model shown in Figures~\ref{spider1} and~\ref{spider2} which additionally identifies \code{reft}. The data are available in package \pkg{mvpart} \citep{mvpart}. <>= data("HuntingSpiders", package = "partykit") sptree <- ctree(arct.lute + pard.lugu + zora.spin + pard.nigr + pard.pull + aulo.albi + troc.terr + alop.cune + pard.mont + alop.acce + alop.fabr + arct.peri ~ herbs + reft + moss + sand + twigs + water, data = HuntingSpiders, teststat = "max", minsplit = 5, pargs = GenzBretz(abseps = .1, releps = .1)) @ \setkeys{Gin}{width=\textwidth, keepaspectratio=TRUE} \begin{figure}[t!] \centering <>= plot(sptree, terminal_panel = node_barplot) @ \caption{Regression tree for hunting spider abundance with bars for the mean of each response. \label{spider1}} \end{figure} \setkeys{Gin}{height=.93\textheight, keepaspectratio=TRUE} \begin{figure}[p!] \centering <>= plot(sptree) @ \caption{Regression tree for hunting spider abundance with boxplots for each response. \label{spider2}} \end{figure} \section{Backward compatibility and novel functionality} \label{sec:novel} \code{partykit::ctree} is a complete reimplementation of \code{party::ctree}. The latter reference implementation is based on a monolithic \proglang{C} core and an \proglang{S4}-based \proglang{R} interface. The novel implementation of conditional inference trees in \pkg{partykit} is much more modular and was almost entirely written in \proglang{R} (package \pkg{partykit} does not contain any foreign language code as of version 1.2-0). Permutation tests are computed in the dedicated \proglang{R} add-on package \pkg{libcoin}. Nevertheless, both implementations will almost every time produce the same tree. There are, naturally, exceptions where ensuring backward-compatibility requires specific choices of hyper parameters in \code{partykit::ctree_control}. We will demonstrate how one can compute the same trees in \pkg{partykit} and \pkg{party} in this section. In addition, some novel features introduced in \pkg{partykit} 1.2-0 are described. \subsection{Regression} <>= library("party") set.seed(290875) @ We use the \code{airquality} data from package \pkg{party} and fit a regression tree after removal of missing response values. There are missing values in one of the explanatory variables, so we ask for three surrogate splits to be set-up: <>= data("airquality", package = "datasets") airq <- subset(airquality, !is.na(Ozone)) (airct_party <- party::ctree(Ozone ~ ., data = airq, controls = party::ctree_control(maxsurrogate = 3))) mean((airq$Ozone - predict(airct_party))^2) @ For this specific example, the same call produces the same tree under both \pkg{party} and \pkg{partykit}. To ensure this also for other patterns of missingness, the \code{numsurrogate} flag needs to be set in order to restrict the evaluation of surrogate splits to numeric variables only (this is a restriction hard-coded in \pkg{party}): <>= (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, numsurrogate = TRUE))) mean((airq$Ozone - predict(airct_partykit))^2) table(predict(airct_party, type = "node"), predict(airct_partykit, type = "node")) max(abs(predict(airct_party) - predict(airct_partykit))) @ The results are identical as are the underlying test statistics: <>= airct_party@tree$criterion info_node(node_party(airct_partykit)) @ \code{partykit} has a nicer way or presenting the variable selection test statistics on the scale of the statistics and the $p$-values. In addition, the criterion to be maximised (here: $\log(1 - p-\text{value})$) is given. \subsection{Classification} For classification tasks with more than two classes, the default in \pkg{party} is a maximum-type test statistic on the multidimensional test statistic when computing splits. \pkg{partykit} employs a quadratic test statistic by default, because it was found to produce better splits empirically. One can switch-back to the old behaviour using the \code{splitstat} argument: <>= (irisct_party <- party::ctree(Species ~ .,data = iris)) (irisct_partykit <- partykit::ctree(Species ~ .,data = iris, control = partykit::ctree_control(splitstat = "maximum"))) table(predict(irisct_party, type = "node"), predict(irisct_partykit, type = "node")) @ The interface for computing conditional class probabilities changed from <>= tr_party <- treeresponse(irisct_party, newdata = iris) @ to <>= tr_partykit <- predict(irisct_partykit, type = "prob", newdata = iris) max(abs(do.call("rbind", tr_party) - tr_partykit)) @ leading to identical results. For ordinal regression, the conditional class probabilities can be computed in the very same way: <>= ### ordinal regression data("mammoexp", package = "TH.data") (mammoct_party <- party::ctree(ME ~ ., data = mammoexp)) ### estimated class probabilities tr_party <- treeresponse(mammoct_party, newdata = mammoexp) (mammoct_partykit <- partykit::ctree(ME ~ ., data = mammoexp)) ### estimated class probabilities tr_partykit <- predict(mammoct_partykit, newdata = mammoexp, type = "prob") max(abs(do.call("rbind", tr_party) - tr_partykit)) @ \subsection{Survival Analysis} Like in classification analysis, the \code{treeresponse} function from package \code{party} was replaced by the \code{predict} function with argument \code{type = "prob"} in \pkg{partykit}. The default survival trees are identical: <>= data("GBSG2", package = "TH.data") (GBSG2ct_party <- party::ctree(Surv(time, cens) ~ .,data = GBSG2)) (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ .,data = GBSG2)) @ as are the conditional Kaplan-Meier estimators <>= tr_party <- treeresponse(GBSG2ct_party, newdata = GBSG2) tr_partykit <- predict(GBSG2ct_partykit, newdata = GBSG2, type = "prob") all.equal(lapply(tr_party, function(x) unclass(x)[!(names(x) %in% "call")]), lapply(tr_partykit, function(x) unclass(x)[!(names(x) %in% "call")]), check.names = FALSE) @ \subsection{New Features} \pkg{partykit} comes with additional arguments in \code{ctree_control} allowing a more detailed control over the tree growing. \begin{description} \item[\code{alpha}]: The user can optionally change the default nominal level of $\alpha = 0.05$; \code{mincriterion} is updated to $1 - \alpha$ and \code{logmincriterion} is then $\log(1 - \alpha)$. The latter allows variable selection on the scale of $\log(1 - p\text{-value})$: <>= (airct_partykit_1 <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, alpha = 0.001, numsurrogate = FALSE))) depth(airct_partykit_1) mean((airq$Ozone - predict(airct_partykit_1))^2) @ Lower values of $\alpha$ lead to smaller trees. \item[\code{splittest}]: This enables the computation of $p$-values for maximally selected statistics for variable selection. The default test statistic is not particularly powerful against cutpoint-alternatives but much faster to compute. Currently, $p$-value approximations are not available, so one has to rely on resampling for $p$-value estimation <>= (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, splittest = TRUE, testtype = "MonteCarlo"))) @ \item[\code{saveinfo}]: Reduces the memory footprint by not storing test results as part of the tree. The core information about trees is then roughly half the size needed by \code{party}. \item[\code{nmax}]: Restricts the number of possible cutpoints to \code{nmax}, basically by treating all explanatory variables as ordered factors defined at quantiles of underlying numeric variables. This is mainly implemented in package \pkg{libcoin}. For the standard \code{ctree}, it is only appropriate to use in classification problems, where is can lead to substantial speed-ups: <>= (irisct_partykit_1 <- partykit::ctree(Species ~ .,data = iris, control = partykit::ctree_control(splitstat = "maximum", nmax = 25))) table(predict(irisct_partykit), predict(irisct_partykit_1)) @ \item[\code{multiway}]: Implements multiway splits in unordered factors, each level defines a corresponding daughter node: <>= GBSG2$tgrade <- factor(GBSG2$tgrade, ordered = FALSE) (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ tgrade, data = GBSG2, control = partykit::ctree_control(multiway = TRUE, alpha = .5))) @ \item[\code{majority = FALSE}]: enables random assignment of non-splitable observations to daughter nodes preserving the node distribution. With \code{majority = TRUE}, these observations go with the majority (the only available behaviour of in \code{party::ctree}). \end{description} Two arguments of \code{ctree} are also interesting. The novel \code{cluster} argument allows conditional inference trees to be fitted to (simple forms of) correlated observations. For each cluster, the variance of the test statistics used for variable selection and also splitting is computed separately, leading to stratified permutation tests (in the sense that only observations within clusters are permuted). For example, we can cluster the data in the \code{airquality} dataset by month to be used as cluster variable: <>= airq$month <- factor(airq$Month) (airct_partykit_3 <- partykit::ctree(Ozone ~ Solar.R + Wind + Temp, data = airq, cluster = month, control = partykit::ctree_control(maxsurrogate = 3))) info_node(node_party(airct_partykit_3)) mean((airq$Ozone - predict(airct_partykit_3))^2) @ This reduces the number of partitioning variables and makes multiplicity adjustment less costly. The \code{ytrafo} argument has be made more general. \pkg{party} is not able to update influence functions $h$ within nodes. With the novel formula-based interface, users can create influence functions which are newly evaluated in each node. The following example illustrates how one can compute a survival tree with updated logrank scores: <>= ### with weight-dependent log-rank scores ### log-rank trafo for observations in this node only (= weights > 0) h <- function(y, x, start = NULL, weights, offset, estfun = TRUE, object = FALSE, ...) { if (is.null(weights)) weights <- rep(1, NROW(y)) s <- logrank_trafo(y[weights > 0,,drop = FALSE]) r <- rep(0, length(weights)) r[weights > 0] <- s list(estfun = matrix(as.double(r), ncol = 1), converged = TRUE, unweighted = TRUE) } partykit::ctree(Surv(time, cens) ~ ., data = GBSG2, ytrafo = h) @ The results are usually not very sensitive to (simple) updated influence functions. However, when one uses score functions of more complex models as influence functions (similar to the \code{mob} family of trees), it is necessary to refit models in each node. For example, we are interested in a normal linear model for ozone concentration given temperature; both the intercept and the regression coefficient for temperature shall vary across nodes of a tree. Such a ``permutation-based'' MOB, here taking clusters into account, can be set-up using <>= ### normal varying intercept / varying coefficient model (aka "mob") h <- function(y, x, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ...) glm(y ~ 0 + x, family = gaussian(), start = start, weights = weights, ...) (airct_partykit_4 <- partykit::ctree(Ozone ~ Temp | Solar.R + Wind, data = airq, cluster = month, ytrafo = h, control = partykit::ctree_control(maxsurrogate = 3))) airq$node <- factor(predict(airct_partykit_4, type = "node")) summary(m <- glm(Ozone ~ node + node:Temp - 1, data = airq)) mean((predict(m) - airq$Ozone)^2) @ Both intercept and effect of temperature change considerably between nodes. The corresponding MOB can be fitted using <>= airq_lmtree <- partykit::lmtree(Ozone ~ Temp | Solar.R + Wind, data = airq, cluster = month) info_node(node_party(airq_lmtree)) mean((predict(airq_lmtree, newdata = airq) - airq$Ozone)^2) @ The $p$-values in the root node are similar but the two procedures find different splits. \code{mob} (and therefore \code{lmtree}) directly search for splits by optimising the objective function for all possible splits whereas \code{ctree} only works with the score functions. Argument \code{xtrafo} allowing the user to change the transformations $g_j$ of the covariates was removed from the user interface. <>= detach(package:party) @ \bibliography{party} \end{document} partykit/inst/doc/ctree.R0000644000176200001440000003625114415225016015077 0ustar liggesusers### R code from vignette source 'ctree.Rnw' ################################################### ### code chunk number 1: setup ################################################### suppressWarnings(RNGversion("3.5.2")) options(width = 70, SweaveHooks = list(leftpar = function() par(mai = par("mai") * c(1, 1.1, 1, 1)))) require("partykit") require("coin") require("strucchange") require("coin") require("Formula") require("survival") require("sandwich") set.seed(290875) ################################################### ### code chunk number 2: party-max ################################################### ctree_control(teststat = "max") ################################################### ### code chunk number 3: party-max ################################################### ctree_control(teststat = "quad") ################################################### ### code chunk number 4: party-Bonf ################################################### ctree_control(testtype = "Bonferroni") ################################################### ### code chunk number 5: party-minsplit ################################################### ctree_control(minsplit = 20) ################################################### ### code chunk number 6: party-maxsurr ################################################### ctree_control(maxsurrogate = 3) ################################################### ### code chunk number 7: party-data ################################################### ls <- data.frame(y = gl(3, 50, labels = c("A", "B", "C")), x1 = rnorm(150) + rep(c(1, 0, 0), c(50, 50, 50)), x2 = runif(150)) ################################################### ### code chunk number 8: party-formula ################################################### library("partykit") ctree(y ~ x1 + x2, data = ls) ################################################### ### code chunk number 9: party-fitted ################################################### ct <- ctree(y ~ x1 + x2, data = ls) ################################################### ### code chunk number 10: party-print ################################################### ct ################################################### ### code chunk number 11: party-plot ################################################### plot(ct) ################################################### ### code chunk number 12: party-nodes ################################################### ct[1] ################################################### ### code chunk number 13: party-nodelist ################################################### class(ct[1]) ################################################### ### code chunk number 14: party-predict ################################################### predict(ct, newdata = ls) ################################################### ### code chunk number 15: party-treeresponse ################################################### predict(ct, newdata = ls[c(1, 51, 101),], type = "prob") ################################################### ### code chunk number 16: party-where ################################################### predict(ct, newdata = ls[c(1,51,101),], type = "node") ################################################### ### code chunk number 17: party-sctest ################################################### library("strucchange") sctest(ct) ################################################### ### code chunk number 18: treepipit-ctree ################################################### data("treepipit", package = "coin") tptree <- ctree(counts ~ ., data = treepipit) ################################################### ### code chunk number 19: treepipit-plot ################################################### plot(tptree, terminal_panel = node_barplot) ################################################### ### code chunk number 20: treepipit-x ################################################### p <- info_node(node_party(tptree))$p.value n <- table(predict(tptree, type = "node")) ################################################### ### code chunk number 21: glaucoma-ctree ################################################### data("GlaucomaM", package = "TH.data") gtree <- ctree(Class ~ ., data = GlaucomaM) ################################################### ### code chunk number 22: glaucoma-x ################################################### sp <- split_node(node_party(gtree))$varID ################################################### ### code chunk number 23: glaucoma-plot ################################################### plot(gtree) ################################################### ### code chunk number 24: glaucoma-plot-inner ################################################### plot(gtree, inner_panel = node_barplot, edge_panel = function(...) invisible(), tnex = 1) ################################################### ### code chunk number 25: glaucoma-plot2 (eval = FALSE) ################################################### ## plot(gtree) ################################################### ### code chunk number 26: glaucoma-plot-inner (eval = FALSE) ################################################### ## plot(gtree, inner_panel = node_barplot, ## edge_panel = function(...) invisible(), tnex = 1) ################################################### ### code chunk number 27: glaucoma-prediction ################################################### table(predict(gtree), GlaucomaM$Class) ################################################### ### code chunk number 28: glaucoma-classprob ################################################### prob <- predict(gtree, type = "prob")[,1] + runif(nrow(GlaucomaM), min = -0.01, max = 0.01) splitvar <- character_split(split_node(node_party(gtree)), data = data_party(gtree))$name plot(GlaucomaM[[splitvar]], prob, pch = as.numeric(GlaucomaM$Class), ylab = "Conditional Class Prob.", xlab = splitvar) abline(v = split_node(node_party(gtree))$breaks, lty = 2) legend(0.15, 0.7, pch = 1:2, legend = levels(GlaucomaM$Class), bty = "n") ################################################### ### code chunk number 29: GBSGS-ctree ################################################### data("GBSG2", package = "TH.data") library("survival") (stree <- ctree(Surv(time, cens) ~ ., data = GBSG2)) ################################################### ### code chunk number 30: GBSG2-plot ################################################### plot(stree) ################################################### ### code chunk number 31: GBSG2-KM ################################################### pn <- predict(stree, newdata = GBSG2[1:2,], type = "node") n <- predict(stree, type = "node") survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[1])) survfit(Surv(time, cens) ~ 1, data = GBSG2, subset = (n == pn[2])) ################################################### ### code chunk number 32: mammo-ctree ################################################### data("mammoexp", package = "TH.data") mtree <- ctree(ME ~ ., data = mammoexp) ################################################### ### code chunk number 33: mammo-plot ################################################### plot(mtree) ################################################### ### code chunk number 34: spider-ctree ################################################### data("HuntingSpiders", package = "partykit") sptree <- ctree(arct.lute + pard.lugu + zora.spin + pard.nigr + pard.pull + aulo.albi + troc.terr + alop.cune + pard.mont + alop.acce + alop.fabr + arct.peri ~ herbs + reft + moss + sand + twigs + water, data = HuntingSpiders, teststat = "max", minsplit = 5, pargs = GenzBretz(abseps = .1, releps = .1)) ################################################### ### code chunk number 35: spider-plot1 ################################################### plot(sptree, terminal_panel = node_barplot) ################################################### ### code chunk number 36: spider-plot2 ################################################### plot(sptree) ################################################### ### code chunk number 37: party-setup ################################################### library("party") set.seed(290875) ################################################### ### code chunk number 38: party-airq ################################################### data("airquality", package = "datasets") airq <- subset(airquality, !is.na(Ozone)) (airct_party <- party::ctree(Ozone ~ ., data = airq, controls = party::ctree_control(maxsurrogate = 3))) mean((airq$Ozone - predict(airct_party))^2) ################################################### ### code chunk number 39: partykit-airq ################################################### (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, numsurrogate = TRUE))) mean((airq$Ozone - predict(airct_partykit))^2) table(predict(airct_party, type = "node"), predict(airct_partykit, type = "node")) max(abs(predict(airct_party) - predict(airct_partykit))) ################################################### ### code chunk number 40: party-partykit-airq ################################################### airct_party@tree$criterion info_node(node_party(airct_partykit)) ################################################### ### code chunk number 41: party-partykit-iris ################################################### (irisct_party <- party::ctree(Species ~ .,data = iris)) (irisct_partykit <- partykit::ctree(Species ~ .,data = iris, control = partykit::ctree_control(splitstat = "maximum"))) table(predict(irisct_party, type = "node"), predict(irisct_partykit, type = "node")) ################################################### ### code chunk number 42: party-iris ################################################### tr_party <- treeresponse(irisct_party, newdata = iris) ################################################### ### code chunk number 43: partykit-iris ################################################### tr_partykit <- predict(irisct_partykit, type = "prob", newdata = iris) max(abs(do.call("rbind", tr_party) - tr_partykit)) ################################################### ### code chunk number 44: party-partykit-mammoexp ################################################### ### ordinal regression data("mammoexp", package = "TH.data") (mammoct_party <- party::ctree(ME ~ ., data = mammoexp)) ### estimated class probabilities tr_party <- treeresponse(mammoct_party, newdata = mammoexp) (mammoct_partykit <- partykit::ctree(ME ~ ., data = mammoexp)) ### estimated class probabilities tr_partykit <- predict(mammoct_partykit, newdata = mammoexp, type = "prob") max(abs(do.call("rbind", tr_party) - tr_partykit)) ################################################### ### code chunk number 45: party-partykit-GBSG2 ################################################### data("GBSG2", package = "TH.data") (GBSG2ct_party <- party::ctree(Surv(time, cens) ~ .,data = GBSG2)) (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ .,data = GBSG2)) ################################################### ### code chunk number 46: party-partykit-KM ################################################### tr_party <- treeresponse(GBSG2ct_party, newdata = GBSG2) tr_partykit <- predict(GBSG2ct_partykit, newdata = GBSG2, type = "prob") all.equal(lapply(tr_party, function(x) unclass(x)[!(names(x) %in% "call")]), lapply(tr_partykit, function(x) unclass(x)[!(names(x) %in% "call")]), check.names = FALSE) ################################################### ### code chunk number 47: nf-alpha ################################################### (airct_partykit_1 <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, alpha = 0.001, numsurrogate = FALSE))) depth(airct_partykit_1) mean((airq$Ozone - predict(airct_partykit_1))^2) ################################################### ### code chunk number 48: nf-maxstat ################################################### (airct_partykit <- partykit::ctree(Ozone ~ ., data = airq, control = partykit::ctree_control(maxsurrogate = 3, splittest = TRUE, testtype = "MonteCarlo"))) ################################################### ### code chunk number 49: nf-nmax ################################################### (irisct_partykit_1 <- partykit::ctree(Species ~ .,data = iris, control = partykit::ctree_control(splitstat = "maximum", nmax = 25))) table(predict(irisct_partykit), predict(irisct_partykit_1)) ################################################### ### code chunk number 50: nf-multiway ################################################### GBSG2$tgrade <- factor(GBSG2$tgrade, ordered = FALSE) (GBSG2ct_partykit <- partykit::ctree(Surv(time, cens) ~ tgrade, data = GBSG2, control = partykit::ctree_control(multiway = TRUE, alpha = .5))) ################################################### ### code chunk number 51: nf-cluster ################################################### airq$month <- factor(airq$Month) (airct_partykit_3 <- partykit::ctree(Ozone ~ Solar.R + Wind + Temp, data = airq, cluster = month, control = partykit::ctree_control(maxsurrogate = 3))) info_node(node_party(airct_partykit_3)) mean((airq$Ozone - predict(airct_partykit_3))^2) ################################################### ### code chunk number 52: nf-ytrafo-1 ################################################### ### with weight-dependent log-rank scores ### log-rank trafo for observations in this node only (= weights > 0) h <- function(y, x, start = NULL, weights, offset, estfun = TRUE, object = FALSE, ...) { if (is.null(weights)) weights <- rep(1, NROW(y)) s <- logrank_trafo(y[weights > 0,,drop = FALSE]) r <- rep(0, length(weights)) r[weights > 0] <- s list(estfun = matrix(as.double(r), ncol = 1), converged = TRUE, unweighted = TRUE) } partykit::ctree(Surv(time, cens) ~ ., data = GBSG2, ytrafo = h) ################################################### ### code chunk number 53: nf-ytrafo-2 ################################################### ### normal varying intercept / varying coefficient model (aka "mob") h <- function(y, x, start = NULL, weights = NULL, offset = NULL, cluster = NULL, ...) glm(y ~ 0 + x, family = gaussian(), start = start, weights = weights, ...) (airct_partykit_4 <- partykit::ctree(Ozone ~ Temp | Solar.R + Wind, data = airq, cluster = month, ytrafo = h, control = partykit::ctree_control(maxsurrogate = 3))) airq$node <- factor(predict(airct_partykit_4, type = "node")) summary(m <- glm(Ozone ~ node + node:Temp - 1, data = airq)) mean((predict(m) - airq$Ozone)^2) ################################################### ### code chunk number 54: airq-mob ################################################### airq_lmtree <- partykit::lmtree(Ozone ~ Temp | Solar.R + Wind, data = airq, cluster = month) info_node(node_party(airq_lmtree)) mean((predict(airq_lmtree, newdata = airq) - airq$Ozone)^2) ################################################### ### code chunk number 55: closing ################################################### detach(package:party) partykit/inst/CITATION0000644000176200001440000000536414377411074014253 0ustar liggesusers bibentry(bibtype = "Article", title = "{partykit}: A Modular Toolkit for Recursive Partytioning in {R}", author = c(person(given = "Torsten", family = "Hothorn", email = "Torsten.Hothorn@R-project.org", comment = c(ORCID = "0000-0001-8301-0471")), person(given = "Achim", family = "Zeileis", email = "Achim.Zeileis@R-project.org", comment = c(ORCID = "0000-0003-0918-3766"))), journal = "Journal of Machine Learning Research", year = "2015", volume = "16", pages = "3905-3909", url = "https://jmlr.org/papers/v16/hothorn15a.html" ) bibentry(bibtype="Article", title = "Unbiased Recursive Partitioning: A Conditional Inference Framework", author = c(person(given = "Torsten", family = "Hothorn", email = "Torsten.Hothorn@R-project.org", comment = c(ORCID = "0000-0001-8301-0471")), person(given = "Kurt", family = "Hornik", email = "Kurt.Hornik@R-project.org", comment = c(ORCID = "0000-0003-4198-9911")), person(given = "Achim", family = "Zeileis", email = "Achim.Zeileis@R-project.org", comment = c(ORCID = "0000-0003-0918-3766"))), journal = "Journal of Computational and Graphical Statistics", year = "2006", volume = "15", number = "3", doi = "10.1198/106186006X133933", pages = "651--674", mheader = "If ctree() is used additionally cite:" ) bibentry(bibtype="Article", title = "Model-Based Recursive Partitioning", author = c(person(given = "Achim", family = "Zeileis", email = "Achim.Zeileis@R-project.org", comment = c(ORCID = "0000-0003-0918-3766")), person(given = "Torsten", family = "Hothorn", email = "Torsten.Hothorn@R-project.org", comment = c(ORCID = "0000-0001-8301-0471")), person(given = "Kurt", family = "Hornik", email = "Kurt.Hornik@R-project.org", comment = c(ORCID = "0000-0003-4198-9911"))), journal = "Journal of Computational and Graphical Statistics", year = "2008", volume = "17", number = "2", doi = "10.1198/106186008X319331", pages = "492--514", mheader = "If mob() is used additionally cite:" ) partykit/inst/NEWS.Rd0000644000176200001440000005455514415223742014163 0ustar liggesusers \name{NEWS} \title{NEWS file for the \pkg{partykit} package} \section{Changes in Version 1.2-20 (2023-04-11)}{ \subsection{Buxfixes}{ \itemize{ \item{\code{density} now gives warnings when called with weights, avoid this.} \item{Check for tied p-values fails on M1mac.} } } } \section{Changes in Version 1.2-19 (2023-03-19)}{ \subsection{Buxfixes}{ \itemize{ \item{Fix documentation bug.} } } } \section{Changes in Version 1.2-18 (2023-03-09)}{ \subsection{Buxfixes}{ \itemize{ \item{Register default methods.} } } } \section{Changes in Version 1.2-17 (2023-02-28)}{ \subsection{Misc}{ \itemize{ \item Update \code{CITATION} file. } } \subsection{Buxfixes}{ \itemize{ \item{Allow \code{NA} in responses when plotting. Reported by Tyson H. Holmes.} } } } \section{Changes in Version 1.2-16 (2022-06-20)}{ \subsection{Buxfixes}{ \itemize{ \item{Address random CRAN errors (honesty checks).} } } } \section{Changes in Version 1.2-15 (2021-08-23)}{ \subsection{Small Improvements}{ \itemize{ \item{Update reference output.} } } } \section{Changes in Version 1.2-14 (2021-04-22)}{ \subsection{Bugfixes}{ \itemize{ \item{\code{cforest} ignored \code{converged} argument.} } } } \section{Changes in Version 1.2-13 (2021-03-03)}{ \subsection{Small Improvements}{ \itemize{ \item{Suggest \pkg{randomForest}.} \item{Test constparty vignette code in tests, to avoid a NOTE about missing \pkg{RWeka} on Solaris.} } } } \section{Changes in Version 1.2-12 (2021-02-08)}{ \subsection{New Features}{ \itemize{ \item{Add \code{method} argument to \code{glmtree}. The default is to use \code{"glm.fit"} (as was hard-coded previously) but this can also be changed, e.g., to \code{"brglmFit"} from \pkg{brglm2} for bias-reduced estimation of generalized linear models.} } } \subsection{Bugfixes}{ \itemize{ \item{Fix LaTeX problem.} \item{Better checks for response classes, fixing a bug reported by John Ogawa.} \item{In \code{lmtree} and \code{glmtree} the \code{"xlevels"} attribute for the regressors is preserved in the models fitted within the trees. Thus, predicting for data whose \code{"xlevels"} do not match, an error is generated now (as opposed to warning and partially incorrect predictions).} } } } \section{Changes in Version 1.2-11 (2020-12-09)}{ \subsection{New Features}{ \itemize{ \item{Add an experimental implementation of honesty.} \item{Add \code{maxvar} argument to \code{ctree_control} for restricting the number of split variables to be used in a tree.} } } \subsection{Bugfixes}{ \itemize{ \item{\code{all.equal} must not check environments.} \item{Non-standard variable names are now handled correctly within \code{extree_data}, prompted by \url{https://stackoverflow.com/questions/64660889/ctree-ignores-variables-with-non-syntactic-names}.} } } } \section{Changes in Version 1.2-10 (2020-10-12)}{ \subsection{Bugfixes}{ \itemize{ \item{Deal with non-integer \code{minsize} in \code{mob}.} \item{Handle NAs in \code{.get_psplits}.} \item{Fix URLs.} } } } \section{Changes in Version 1.2-9 (2020-07-10)}{ \subsection{Bugfixes}{ \itemize{ \item{Fix an issue with printing of tied p-values.} } } } \section{Changes in Version 1.2-8 (2020-06-09)}{ \subsection{Bugfixes}{ \itemize{ \item{pruning of modelparty objects failed to get the fitted slot right.} \item{In R-devel, c() now returns factors, rendering code in .simplify_pred overly pedantic.} } } } \section{Changes in Version 1.2-7 (2020-03-06)}{ \subsection{Bugfixes}{ \itemize{ \item{NAMESPACE fixes: party is only suggested.} } } } \section{Changes in Version 1.2-6 (2020-01-30)}{ \subsection{Bugfixes}{ \itemize{ \item{Remove warning about response not being a factor in \code{predict.cforest}. Reported by Stephen Milborrow.} } } } \section{Changes in Version 1.2-5 (2019-07-17)}{ \subsection{Bugfixes}{ \itemize{ \item{Trying to split in a variable where all observations were missing nevertheless produced a split, as reported by Kevin Ummel.} } } } \section{Changes in Version 1.2-4 (2019-05-17)}{ \subsection{Bugfixes}{ \itemize{ \item{update reference output, fix RNGversion} } } } \section{Changes in Version 1.2-3 (2019-01-28)}{ \subsection{New Features}{ \itemize{ \item{\code{varimp} runs in parallel mode, optionally.} \item{\code{weights} in \code{cforest} can now be used to specify a matrix of weights (number of observations times number of trees) to be used for tree induction (this was always possible in \code{party::cforest}. This was advertised in the documentation but actually not implemented so far.} } } \subsection{Bugfixes}{ \itemize{ \item{\code{predict} did not pay attention to \code{xlev}; this caused problems when empty factor levels were removed prior to tree fitting.} \item{\code{nodeprune} may have got fitted terminal node numbers wrong, spotted by Jason Parker.} } } } \section{Changes in Version 1.2-2 (2018-06-05)}{ \subsection{Bugfixes}{ \itemize{ \item{In \code{mob()} using the \code{cluster} argument with a \code{factor} variable sometimes lead to \code{NA}s in the covariance matrix estimate if empty categories occured in subgroups. The problem had been introduced in version 1.2-0 and has been fixed now.} \item{Methods for the \code{sctest} generic from the \pkg{strucchange} package are now dynamically registered if \pkg{strucchange} is attached. Alternatively, the methods can be called directly using their full names \code{sctest.constparty} and \code{sctest.modelparty}.} \item{The \code{prune.modelparty} function is now fully exported but it is also registered with the \code{prune} generic from \pkg{rpart}.} } } } \section{Changes in Version 1.2-1 (2018-04-20)}{ \subsection{New Features}{ \itemize{ \item{New \code{scale} argument for \code{predict} in \code{cforest}. For simple regression forests, predicting the conditional mean by nearest neighbor weights with \code{scale = TRUE} is now equivalent to the aggregation of means. The unscaled version proposed in can be obtained with \code{scale = FALSE}.} } } \subsection{Bugfixes}{ \itemize{ \item{Bug fix for case weights in \code{mob()} in previous version (1.2-0) introduced a bug in the handling of proportionality weights. Both cases are handled correctly now.} \item{\code{glmtree} can now handle \code{caseweights = TRUE} correctly for \code{vcov} other than the default \code{"opg"}. Internally, the \code{glm} objects are adjusted by correcting the dispersion estimate and the degrees of freedom.} \item{\code{lookahead} did not work in the presence of missing values.} \item{Calling \code{partykit::ctree} did not work when partykit was not attached.} \item{\code{node_inner} now allows to set a different \code{gpar(fontsize = ...)} in the inner nodes compared to the overall tree.} \item{\code{splittest} asked for Monte-Carlo p-values, even when the test statistic was used as criterion.} } } } \section{Changes in Version 1.2-0 (2017-12-18)}{ \subsection{New Features}{ \itemize{ \item{We welcome Heidi Seibold as co-author!} \item{Internal re-organisation for \code{ctree} by means of new extensible tree infrastructure (available in \code{extree_data} and \code{extree_fit}). Certain parts of the new infrastructure are still experimental. \code{ctree} is fully backward compatible.} \item{Use \pkg{libcoin} for computing linear test statistics and p-values for \code{ctree}.} \item{Use \pkg{inum} for binning (the new \code{nmax} argument).} \item{Quadratic test statistics for splitpoint selection are now available for \code{ctree} via \code{ctree_control(splitstat = "quadratic")}.} \item{Maximally selected test statistics for variable selection are now available for \code{ctree} via \code{ctree_control(splittest = TRUE)}.} \item{Missing values can be treated as a separate category, also for splits in numeric variables in \code{ctree} via \code{ctree_control(MIA = TRUE)}.} \item{Permutation variable importance, including conditional variable importance, was added to \pkg{partykit}.} \item{New \code{offset} argument in \code{ctree}.} \item{New \code{get_paths} for computing paths to nodes.} \item{\code{node_barplot} gained a \code{text} argument that can be used to draw text labels for the percentages displayed.} \item{The \code{margins} used in \code{plot.party} can now also be set by the user.} } } \subsection{Bugfixes}{ \itemize{ \item{Bug fix in \code{mob()} if \code{weights} are used and \code{caseweights = TRUE} (the default). The statistics for the parameter instability tests were computed incorrectly and consequently the selection of splitting variables and also the stopping criterion were affected/incorrect.} \item{Avoid log(p) values of \code{-Inf} inside \code{mob()} by replacing weighted averaging with naive averaging in the response surface regression output in case the p values are below machine precision.} \item{The \code{as.party} method for \code{rpart} objects without any splits only returned a naked \code{partynode} rather than a full \code{party}. This has been corrected now.} \item{\code{nodeapply} did not produce the same results for permutations of \code{ids}. Spotted by Heidi Seibold.} \item{Out-of-bag predictions in \code{predict.cforest} were incorrect.} \item{\code{perm} in \code{predict} was only considered when \code{newdata} was given. Spotted by Heidi Seibold.} \item{Don't try to search for binary splits in unordered factors with more than 31 levels. This potentially caused an integer overrun in previous versions. \code{party::ctree()} uses an approximation for binary split searches in unordered factors; thus, using \pkg{party} might be an alternative.} } } } \section{Changes in Version 1.1-1 (2016-09-20)}{ \itemize{ \item{Proper support of quasi-families in \code{glmtree} and hence \code{palmtree}.} \item{NA handling by following the majority was potentially incorrect in \code{ctree}.} \item{Minor speed improvements.} \item{Breaking ties before variable selection was suboptimal for very small log-p-values.} } } \section{Changes in Version 1.1-0 (2016-07-14)}{ \itemize{ \item{Added a new function \code{palmtree} that fits partially additive (generalized) linear model trees. These employ model-based recursive partitioning (\code{mob}) based on (generalized) linear models with some local (i.e., leaf-specific) and some global (i.e., constant throughout the tree) regression coefficients.} \item{Splits in ordinal variables are now represented correctly in the (still internal) \code{list.rule} method.} \item{Kaplan-Meier curves in \code{"constparty"} trees were plotted incorrectly due to use a wrong scaling of the x-axis. Spotted by Peter Calhoun .} \item{Use \code{quote(stats::model.frame)} instead of \code{as.name("model.frame")}.} \item{The \code{as.party} methods for \code{rpart} and \code{Weka_tree} now have a \code{data = TRUE} argument so that by default the data is preserved in the \code{party} object (instead of an empty model frame).} \item{The \code{predict} method for \code{cforest} objects did not work for one-row data frames, fixed now.} \item{Added \code{rot} and \code{just} arguments to \code{node_barplot} for more fine control of x-axis labeling (e.g., with 45 degree rotation).} } } \section{Changes in Version 1.0-5 (2016-02-05)}{ \itemize{ \item{The \pkg{partykit} package has now been published in \emph{Journal of Machine Learning Research}, 16, 3905-3909. \url{https://jmlr.org/papers/v16/hothorn15a.html}} \item{Added support for setting background in panel functions.} \item{The \code{as.list()} method for \code{partynode} objects erroneously created an object \code{thisnode} in the calling environment which is avoided now.} } } \section{Changes in Version 1.0-4 (2015-09-29)}{ \itemize{ \item{Bug fix in \code{plot()} method for \code{constparty} objects. In the previous partykit version clipping was accidentally also applied to the axes labels.} \item{For \code{constparty} objects \code{plot(..., type = "simple")} did not work correctly whereas \code{plot(as.simpleparty(...))} yielded the desired visualization. Now internally \code{as.simpleparty()} is called also in the former case.} \item{The \code{as.simpleparty()} method now preserves p-values from \code{constparty} objects (if any).} \item{Added a \code{getCall()} method for \code{"party"} objects.} \item{In the \code{predict()} method for \code{"lmtree"} and \code{"glmtree"} objects the \code{offset} (if any) was sometimes ignored. It is now always used in the prediction.} } } \section{Changes in Version 1.0-3 (2015-08-14)}{ \itemize{ \item{Import \code{logrank_trafo} from \pkg{coin}.} } } \section{Changes in Version 1.0-2 (2015-07-28)}{ \itemize{ \item{\code{nodeprune(..., ids = 1)} did not prune the tree to the root node. Fixed now.} \item{\code{predict.cforest} used \code{na.omit} instead of \code{na.pass}.} \item{\code{predict.party} now features new \code{perm} argument for permuting splits in specific variables (useful for computing permutation variable importances).} \item{\code{NAMESPACE} updates.} } } \section{Changes in Version 1.0-1 (2015-04-07)}{ \itemize{ \item{The support for (generalized) linear model trees with just a constant regressor has been improved. Now \code{lmtree(y ~ x1 + x2)} is short for \code{lmtree(y ~ 1 | x1 + x2)}, analogously for \code{glmtree()}. Plotting now also works properly in this case.} \item{The \code{as.party()} method for \code{"rpart"} objects did not work if one of the partitioning variables was a \code{"character"} variable rather than a \code{"factor"}. A suitable work-around has been added.} \item{The \code{node_barplot()} panel function can now also be used for multivariate responses, e.g., when all responses are numeric and on the same scale.} \item{The package now also includes a new data set \code{HuntingSpiders} which is essentially a copy of the \code{spider} data from the package \pkg{mvpart} that is currently archived on CRAN. The documentation has been improved somewhat and is likely to change further to explain how the data has been transformed in De'ath (2002).} \item{The survival tree example for the GBSG2 data was broken due to the response being (incorrectly) also part of the explanatory variables. Fixed by using the latest \pkg{Formula} package (at least version 1.2-1).} } } \section{Changes in Version 1.0-0 (2015-02-20)}{ \itemize{ \item{Version 1.0-0 published. This version is described in the MLOSS paper accepted for publication by the Journal of Machine Learning Research today.} \item{The unbiased version of \code{cforest} (with \code{replace = FALSE}) is now the default (as in \pkg{party}).} \item{Register all S3 methods in \code{NAMESPACE}.} } } \section{Changes in Version 0.8-4 (2015-01-06)}{ \itemize{ \item{Extended \code{mob()} interface by a \code{cluster} argument. This can be a vector (numeric, integer, factor) with cluster IDs that are then passed on to the 'fit' function (if supported) and used for clustering the covariance matrix in the parameter stability tests. \code{lmtree()} and \code{glmtree()} hence both gained a \code{cluster} argument which is used only for cluster covariances but not for the model estimation (i.e., corresponding to a working independence model).} \item{Optionally, the parameters' variance-covariance matrix in \code{mob()} can now be estimated by the sandwich matrix instead of the default outer-product-of-gradients (OPG) matrix or the information matrix.} \item{Reimplementation of \code{cforest()} available with extended prediction facilities. Both the internal representation and the user interface are still under development are likely to change in future versions.} \item{Added multicore support to \code{mob()}, \code{ctree()}, and \code{cforest()}. If control argument \code{cores} is specified (e.g., \code{cores = 4}) then the search for the best variable or split point (often involving numerous model fits in \code{mob()} or resampling in \code{ctree()}) is carried out using \code{parallel::mclapply()} rathern than sequential \code{for()} or \code{sapply()}. Additionally, other \code{applyfun}s can be provided, e.g., using networks of workstations etc.} \item{Bug fix in \code{mob()} that occurred when regressor variables and partitioning variables overlapped and were not sorted in the underlying model frame.} } } \section{Changes in Version 0.8-3 (2014-12-15)}{ \itemize{ \item{\pkg{mvpart} was archived 2014-12-15.} } } \section{Changes in Version 0.8-2 (2014-09-12)}{ \itemize{ \item{Fixed an uninitialized memory issue reported by valgrind.} } } \section{Changes in Version 0.8-1 (2014-09-08)}{ \itemize{ \item{partykit now depends on R version >= 3.1.0 in order to import the \code{depth()} generic from the \pkg{grid} package.} \item{The print methods for \code{party}/\code{partynode} objects with only a root node was modified. Now, the terminal panel function is also applied if there is only a root node (while previously it was not).} \item{ \code{ctree()} now catches \code{sum(weights) <= 1} situations before they lead to an error.} \item{ Code from suggested packages is included by using \code{::} syntax as required by recent R versions.} \item{ Argument \code{ytrafo} of \code{ctree()} can now be a function which will be updated in every node.} \item{ A small demo briefly illustrating some memory and speed properties has been added. It can be run interactively via \code{demo("memory-speed", package = "partykit").}} \item{ Section 3 of the "constparty" vignette now shows how properties of a new tree algorithm can be assessed by using \pkg{partykit} building blocks.} } } \section{Changes in Version 0.8-0 (2014-03-27)}{ \itemize{ \item{Major improved version of \pkg{partykit}. The previously existing functions in the package were tested and enhanced, new functions and extensive vignettes added.} \item{Extended and improved introductory documentation. The basic classes and class constructors \code{partynode}/\code{partysplit}/\code{party} are introduced in much more detail now in \code{vignette("partykit", package = "partykit")}.} \item{The class \code{constparty} (inheriting from \code{party}) for representing \code{party} objects with constant fits in the nodes (along with coercion methods for \code{rpart}, \code{J48}, etc.) is now described in more detail in the new \code{vignette("constparty", package = "partykit")}.} \item{The package now includes a reimplementation of the model-based recursive partitioning algorithm (MOB) using \pkg{partykit} infrastructure. The generic algorithm, the corresponding convenience interfaces \code{lmtree()} and \code{glmtree()} as well as various illustrations and possible extensions are described in detail in the new \code{vignette("mob", package = "partykit")}.} \item{Improved implementation of conditional inference trees (CTree), see the new \code{vignette("ctree", package = "partykit")} for details.} \item{New \code{nodeprune()} generic for pruning nodes in all \code{party} trees and \code{partynode} objects.} \item{Deal with empty levels in \code{ctree()} for \code{teststat = "quad"} (bug reported by Wei-Yin Loh ).} \item{In \code{predict()} method for \code{constparty} objects, \code{type = "prob"} now returns ECDF for numeric responses and \code{type = "response"} the (weighted) mean.} \item{New panel function \code{node_ecdf()} for plotting empirical cumulative distribution functions in the terminal leaves of \code{constparty} trees.} } } \section{Changes in Version 0.1-6 (2013-09-03)}{ \itemize{ \item{Bug fix in \code{as.party()} method for J48 trees with ordered factors.} } } \section{Changes in Version 0.1-5 (2013-03-22)}{ \itemize{ \item{Fix C code problems reported by clang under OS X.} } } \section{Changes in Version 0.1-4 (2012-06-05)}{ \itemize{ \item{Added \code{node_surv()} for plotting survival ctrees. Accompanying infrastructure for survival trees was enhanced.} \item{\code{ctree()} now checks for (and does not allow) \code{x >= max(x)} splits.} } } \section{Changes in Version 0.1-3 (2012-01-11)}{ \itemize{ \item{Added \pkg{ipred} to the list of suggested packages due to usage of GlaucomaM and GBSG2 data in tests/examples.} } } \section{Changes in Version 0.1-2 (2011-12-18)}{ \itemize{ \item{The \code{node_terminal()} panel-generating function is now customizable by a FUN argument that is passed to \code{formatinfo()}.} \item{The \code{plot()} method for \code{simpleparty} object now sets up a formatting function passed to \code{formatinfo()}, both in \code{print()} and \code{plot()}.} \item{Fixed bug in \code{pmmlTreeModel()} for processing label IDS in splits when not all levels are present.} \item{Cleaned up unused variables in C code and partial argument matching in R code.} } } \section{Changes in Version 0.1-1 (2011-09-29)}{ \itemize{ \item{First CRAN release.} \item{See \code{vignette("partykit", package = "partykit")} for a (somewhat rough) introduction to the package and its classes/methods.} } } partykit/inst/pmml/0000755000176200001440000000000014415225047014047 5ustar liggesuserspartykit/inst/pmml/bbbc.pmml0000644000176200001440000001226514172227776015647 0ustar liggesusers

0 1 2+ partykit/inst/pmml/airq.pmml0000644000176200001440000001236614172227776015715 0ustar liggesusers
partykit/inst/pmml/ttnc.pmml0000644000176200001440000003467514172227776015740 0ustar liggesusers
partykit/inst/pmml/iris.pmml0000644000176200001440000001114014172227776015714 0ustar liggesusers
partykit/inst/pmml/ttnc2.pmml0000644000176200001440000001431114172227776016003 0ustar liggesusers
2014-01-22 11:51:42
"Male" "Male&Adult" "Adult" "Child" "3rd" "1st" "2nd" "Female" "Female|Child" "3rd" "Child" "1st" "2nd" "Crew" "Adult"
partykit/inst/ULGcourse-2020/0000755000176200001440000000000014172227777015347 5ustar liggesuserspartykit/inst/ULGcourse-2020/density_1.pdf0000644000176200001440000001615414172227777017750 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20200419202300) /ModDate (D:20200419202300) /Title (R Graphics Output) /Producer (R 3.6.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 3465 /Filter /FlateDecode >> stream xZS'PY]0A*'ـ"2,+ٟٕ?}}]qwGg:ZzfGM/??y?q]?÷}G῟^v_^g{v$&kt1bn<,?]|X}0aOf&=.~';S#=j9Ry';S?hGz,~';#?s:e#?ٙk?)DYOvюdJo'JB=Yn2z5wfyu?@SrGmz7Y yU߭܊.f;nT>zK9)ßyGzχ?E?]9-E=ёl==W%_'3`+{ޠ_+G> s \Wf"DH7ضj WR:"-Jтc3|o#[U -+v$t2̷={!a=ϠۗjWn&wR|\ N۞|m3+H }x;)N ܐ=~]Bopl:Tr;)N^if~+&lnp|H`L+ `aa+οp"!Ez'8Zp,'q *9`ZnJrCO}JH R?v.{J DVͱTF#EJl2a- (g9 [cЛ9a>Ed9'Ts,E+/RJo2&&sM5 㹨;RӞ'aQ+CX:~k{NYѣu Q0E(A0zԧ_5R:Xj0!#))]ӐGeHh [ԣ1]4`O\2"R)HZ$#@y n,PB?me={7B]C$ ̛@O|F`{Gz,UlѾz0\V,p Q`8'T; }## y J1R?KQ'r x+\83p Idh&Kv.?gc&|YuF w C41 3+=(2#5c03퇥x`y.QX.2P+L!~1Zeщ 1 ulh=E!oMZeET1">AU(Qd__5zEbE+8cc;&@Η AHC|LWC|uT?Gݩ p[?"a3xI>1d|%*RlCҬnl-K-oՄ&C_$R$`=3p!qF_;#!Lp߄0Jz~g`Q RkfGZzpR.`=q.bHCoWU0SP278M xLSy(qV~Z4))s>Cym89"1pJjx7{K@aH|LGMC@α|%vXpLvM_w;7OĨv`3xpJ"ƣ p#GJ#ĉ AAc/c?1+JA?t(XڿhG? hΉGS z>1 uf~ߵ~*qϣ󥼨a=( x/'Փ ^ 8?9?PeU$}¹_><_#?wLT'ozXz Ro3NWnqcBW~i 2BD"soę|*CbJ1•KM~[LSz+QG-d#'U NyvGP=ۓX灴}Z iREC?UDc=j9&=JObdZc-C럱PdcK6Ƨ3B`Ym0CpJE:<%mp/ }#&jz7^> jR/[%i i&Q9|F -knH G6ur88SHW ]/<˦ڨgGM+9Wa }N]sB,{(F+4P:hF&>{c{92 1&JB_osl-S2\#RB4^Q m"Ԅx´&ı+5M8I A_c3eB9j ǜ R"Tpmi8opEߠm/8dNؖ m!E0 (' 7l]_}~&B) AޅC <^~})~}q"8==3 uH#-Ų-e7RH!RzLkƂ?np{X7OMY ;))xs n_3}?&u#>Wu:0댏?YWax 5 3!͛41Tendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 792 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj xref 0 10 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000003829 00000 n 0000003912 00000 n 0000004013 00000 n 0000004046 00000 n 0000000212 00000 n 0000000292 00000 n 0000006741 00000 n trailer << /Size 10 /Info 1 0 R /Root 2 0 R >> startxref 6998 %%EOF partykit/inst/ULGcourse-2020/forest.jpg0000644000176200001440000062570314172227777017370 0ustar liggesusersJFIF,,Created with GIMPC     C   * K;:c-|ܪWG.#D[3E~7TMvB2;H V&v͇;=;z>>9չl (f^49 u|\sa(!\.E+:M1gdӉm dE=ozU|Y|efy}ݱֆ5~tMsLb3Achϱ %zPyD&iha9ɔs NcaԫBN+Cw YAEBC-v%rF `FktbZIN#lޥb٦%/Thz|2{r:3c繿;0=aS^v1{/4},GF[\KvS4k'y0]jЉKBmG~ɥ132֤尵1/xϭ` rc:;\9I&W#Bo;fY*\Z73孞Kw.+N2k׳{[W<{;rk)Fb%Y:-~6IZ\ɔl.܂3RZN#Iu$%dC.<0ޣ$ {(+hMȡ˄1Y:Ǡ{>pXNжdH*"9M{RIjU^{wIW|ZB΅{~CU7fY:WOrɛ|9 /^$k3_2T;8nɳkcTr^A 9)K%i"r\#M9LJWRTAtJ/IeE bhҏ@1 !F•NAnv>kYzg\$X䈚z\yҰp)>nߪ9>bGE,ʍ6m%R}WpH6u6mQ=WvsH Ъir&ͨvJW#?.'RJMZө<9ңBV+սk;aeX8j̩qFjdEhVv d ɋ\nq.c%,c6jSu%җ3-.e)LF_-F1^1ђsnEeɑS c TVem(ZX]yX̒pK.B8VX %ss`<6y*IF Qeu,WA{f+p#N"B(קٺڸ[UzarHMj!ViB3V[PVLS6]J-~פLަZsyaޤ% 7^DA-p<$642ыnW'hO)-yNPbWkԁFCW;l*m0]E[މZyxy ض$HmwSj+N{E;09:#Ȍ%1sjօDc ܢ } UQb;d:NmbSh\eK65~&Ц I,1-sɁU<scU-r܉8zV>]hX,W\eq2 M21\z9ٹDq\6AI-Xy]Jd]t6q97Z$N3nw=.DVE9@qX33O}&~[uޯx0̯JI묌uQ*2cq YLUAlĘ^*S5~f$ds 7{fY_ޕ`}ltA~hԖ*b3AWj4qIfjWK)V^ANmU/x uX^}9&d>H\>>:hT=7cU*K_)y4a.2֋4o$>8`Kj[^H5L:ƆueTI-רr{NVQiNUOH ][ǀG:Ģ/ y(n+FH0B#n\&PF,]߉8!;]<\'{X65מ6RKe !xt{U)t[ W z\h;'ǎ@D%V›9,;*@/N;:m|]i4ub`ڣN18kSdW"5P2:{],hˡV4!zOJnzWĞ*Fu [ ; /Y3&e4ChYxꘫOUa(s L% rUo5~ڋ9E[M.ZwNcdGS٤KNu->C Ba %[J5N + LY=KжNfUo.Jy} 3c\Ж]. u>݂s6Xe'g㮀} FWICR:"<U+_(t fa͹jTx-wNv{ѕKscUevvV2eչnLlDOCvw^z>/=nf]3ǖ m%&$}AzZUʵ.;vd0bQ#He-تj֝z1;Vrؘղ*N=u 1hZ4s.j.>tUCK`}Z7qOИʀjUb X|wо,UďL m!C bY6!K[XFeeʴdvEx}k S53WI sQ$@{.QT^^5lyvGk7*j֣On|<:3$~"ֿFܕUP0Vƪ}YWguVSZ+R!d`(ﬖK*މkLC6m4]W\s/jPWd}YVUh]8 +[qp<7{DSZ4鶡\ѦVy_%ok2SQ~jfE'5/WW17wDr1d.]X55Z|AWXҎll*;f͗o58ni^+mJ& >JЅkKc1cSSM"ZM6G?]x,Tga)ml \V}Y ]㭢0k8{6* (uU}|ڷ䱱yM0ޤGU.`0Y1K i}U,ZnUdCuS5y57d梜,"ħަrWy̜=q9}#ӯL΄:C4kյƸqj iX: / nN] J<6X>֕sMjćy25 GWU0Z 0чeko[o@^`ljDBFBٞwL' K0%L·;kdWC϶5Z[9AKS%DZ$M;%1 Lb&#ZƓM/8.XuጠCQx/a:.9Qƭ׮J'cmQybv\ZXTm=/)H PA*ݒ?;MTJF#D 8UzT1mu甾aT70cwKBES9t}6sg"ᣰ5ٞ}ew=ӥ]C٘Tʆ˺jԱI+ܴFZ]r+6,?KvףunNR#l ĊT. ~!VZzyRGe4X6Vٚm)͘yՂ!&{U2Q).q-W=/2S*K%m+mD,}myeyfx$sLksv:tSytLA^OV6bbfk&tnؔHe`P JA;6\m=(1)wmU[Kޝg%PEUF)eoVpIaI'(wlf+ޙ w,Y'Irznnꧻ#&y * =A;X P]KjcH#qBr_xhd]5U3Z+9avLvjsiDlS̆+Ncr!WSyu,wnu<]ZtlwҕNZn5.,ڱUlHF}Yہ- GιfN/%7EN=nuy_3{6l8,F)NpX%ݽjܱؽnksk)]n1[Y"+2WKfS6HP$ W=d՗DhRKަeSf_TSy̚<'oI,Sffӡkem@fѐgO^|uрjJbxK;oIdvZbt(ܺH^%lVu:ʕC M#:/Nsrڕm_ aӣ:i\6Ř5< YUUtN ejWY;zm<}W 9C%_9,DKBMf{e*& PE@&h<:Ԟuks^Ǘ'~+)[7UlίyU7G@2/)W2MJ"3xe H4M)sDT9?4,\y\'9=ViX] KRWڧ&g'9{_W*9'=x , cF2NRɆMkZ1B9ֶ2ac9`,q-su>;['Z‚*[fW87&>.Y*/c|F}[by"Ԫj[51SCЍ"zR13Z}1\bTrFH9Ƨjw9i&ncv`(ʽ~"YFy=v[emtMJg~jpy}TvN'G~_G4YUb[R^Qɭ.&qN3zF~JPɡSismVmF ƻE'y%-ML3/q׆祛3Uh6t"{^J5ҵZah%9kg-dW[*V1P-UVZrWkUsJ_˗hh`+E;E%kϢ5mV]eV6偠]5%]xfh8 ^pW}{yNqrfr?qv`Xzc;-عD&wx\h脜uh$y^DH{nH}ui+Q{8}sxC?Ai FL@Oc0@rʷ|L{?u Fꘂu,z^\.XՠVEWVh45m'Ǫx1m2Ug=NEO37mvqOC&>7DC 8ƅ^(Sj$؇@]hUriueDBk#pT 7yF)rԚI[KZuɤy%2fOK̙~Gj^-;quS[3 2c1󪋩ZE׫#|c[:c` t;7q ۢͱUu":WP`.GuګbH p׎c8s6s0Aw1AUw< 7Kj-)A9VMB{3c%MW|yʽh|UE[wD)Tu>f52Ww^-\dB'b#\KzVu^1z̷nuWTCɂS]#kf:HW=Wz\5uLJ\J,`S2DCO=#]KUa،O"Ҵ+9aV1Q#qs-  ڻfS(iԗ }$˥ Ƴhӧrr/r48>CD>Έj&؃@gj̭nحĖ(qiC 0:v$T3&f%R]$j˹j6 e-^I'6JLY9!Hjz껳sܱrJbnhVlhv!Y fbCMӍ-WVe ]bU^B0YhLHԧ@`z`='/ܒңU?~hT=@M9Ƥ&4ёf.(g 5Tn*h38pfꭍ2-[qҞY=9)oz] hǯZ 4)5tyփg^ŲKjI` ܵ" a !"6"$,1+oY,TY^ &(k}AChcђ;SG> چ < 'kJQF sZ5zm;[[܍/[;b9X,j.jAVpQd$\ͻ&d^.zMF:I$Id.MdsKMLəxzY 9n r VFӘ>2oYC8W> c2;0tQA&cD9j:$t9̀K&U~Kbo!{bZj4&su9ibmV Qλ{=5$]:z ctq2RUi‡%*l[v*r%˯\n708UEb@=6>=Nˏ2'P1v̙-([ bׯl^pWJrX:iaWNV{GG/ZWQuãR۪{2)y%6CajvC0++GTTܬ^ږ[5:gי-ϝ|T;ݮȦ7 ν>kB!R ^ekwluM.XLmĚp.(RdU,e= (SMۄq\MMzM=˹˦uj&ٚzqF lZլ*kӚ7;b/|;<GQwaVW ׎Og eoK:2t>Ocy1qe8B!ΉQ&B?;e{gҼɝ'aB'n=H)C9V=MR!Z%.u}9au":ԝ@1!S]₤bNuC#mfL%0Ŏ>0W9turlV\FWhv vlHa)ӯ]fvh}.^a97^)&y5YOWK>5ͪ($TNդhE$ɴrYFٕR5Ŭ]M$2 2CFv!MLy/W3e&&NQ!Iw6J1z IÛQ£$gkJh*,"믓uNVֳvE;XW5r:4T4UwM껠Y4 ـ+hZg B-[;U'J r7L(ħ+ +9 <Rj( j jR22s75>"Wlj\5c%c*5OA=.PݮMdHװh30ʎXY;ؔxӐ}ִ֗ܯh:S Im+&[mU(^(m Nh'?8#hӯҳ=;.T^3sg&Ic YΪ8,-)# S*иOObA&Uso<&3Qrc$2sfLx%ZCjfQ0nC%D֒YC\Stzdh*Y& 9 Id"Ȫط6f^*/TvXw{`۾q1-;kcjQo+l+. 6uEbܑ{DB#=Ne(4aeCM6 <;0{F}jDrs&[Nڷl=AHҾCK)oa._"PXڴbmsVU:maT.Eb`kkǛSPYw )5=H嫖meBpZ·4vߓ9e$"re2k\rIG&XL;Yiv-tLxN2{:,vȏu:Ш3Zi$N ɛKm&i$W5YXIm&$`[+1qdL\GʭEs\M6r2cZ \rbr̨yl[YHhz]5D˕zIөc% yzΑK@OjOiwEHVN¡&]K!*>o= p-h\g4ؠcfJ)kΐ(e6a>g:κ9ffɝV#%=Š!1Đٖ2=н%aK@eH""<]tw‰L #bD9;LY)qDͼS#+]/̥7D=>Rv6jXdPMN^- &7[9g6[ekBR i fm*O1JcITr5hf56js dB@8YB• dYW'kup˩d+gP՜2”G1V#j諢jTB̂^z]bB4aI ܎AQIFVs[VsKI$\*+j0͹Ij0=QH=vJbqf&KNؓ2o#as{2D`~k}SZvb4 \}ζ};.ji39ui P5)Һ[Dѡ^F hI 1^vKNk0%|+\hs4jP9<R—FSme5 HȌ8:%ٲ^Hޝ!9c( Ye\YNܚg^|thAk%m~ߔp]YN?M{in, /m99WՌa5Rag‡UwԳrln玺=uعNƛj>:1 pRKVuڣh"rםaC\z+5YTX&O3ZwUV女Ɋ~s`ZI$HnbHBMe1iʍ]ek&zS0 Z2-ƫ2#!5ͮKVhIPe%ٓ.ő*6Kf䅥IA-ѡwY{v&LUֽOMo7]4ՙ-'`8rޮCB%((n7+l[j_M"cU;,oBIͅҘ\AD^i]d`06*p@iY_6zuP˂Ee ”U*dvE>Μ[x ХM<Nٞ݃-AYNM 1- *RuΉ4Cu%dOu뀭2SeWC-˟&4-c6 ,b!VV{5V:2Tzzhmӹ` ;N[~J'W90n-NzZc7I0E l.|v]@"&Qkc= 5MU7yU0676',Gu܆LInfAipŌɉ^(p&ԷsJjLhri$"1rJ 4dwRUegᤫˇWc;&%],)Tu'L\Ι;3Gf3Ve\ܮJZ@cSh>^:w"$b(#m(u4訣3Mfi-nۡ-;yO(t3qm]2udXp iEf#W"Z\eaьb9ַ1un֗495f[. ,K%E b.(`6*[I*jP3[M{i>ADJ#]nhortV (deAق|ZPEgL7=,szmu\1hvѦF|ep$*J`XmMP:;kMH0rkW4-DfumYֶ9W~64 ĐAHM^cW.ߚ70z t-M:GjԚ bǞSC൧}43@m J)dgZ-au$HF[-soW!7.n,K̙]VX.dV!%bKCrޚBʀ*Ҳslh6@u=0VȊItv9x.kW%s_ǂvquYc=Z8+*IE =Y C'4^[ $l ˹, MncՎ7رZRu*T^C5a9[+,ݙQh:J{ONA4|BXk"櫀%UБmJ|Ni(=,c<SeQh(RĻ'ѼLrt+y]%Ɓ|ނ *&t),Nl8#n ܆5ALuo* Vk3*rָ$s-V0hg+l3L ū[2CA*bW鐐r,&:(+]<K.\eXRhJH5D媬F zh m1R >rI5=Ы`ksIZo׬ITv]F!K$d=hQNvE]ZkYd$mҨRY.IP35H|Ci/lj>{gGKr$NnNUج;4UͰtTlؓWo] K̥pzsAuItsXsp#V/Mv-NBDZx2Mz-9I==#4bK:FIR{oFPN٦7TVBz37vll@-0g+@4H5 3qdxsVld5Gl44ݲ邔 %H_~Mm*WtI4pcUeՙ]8¬h$ ʟչfuhlj5Ny𛓽==T v,M( /3R'e? J,/<"'n:+xSѬ-bW6֫Vsӹ.Q9µ,G~EoP@F HJƨ|( OϾcAbje[FE5aekP #oT=˞NBmd؏x6^hDS Ei92=0p@SfRu!AFMsLBR ARVRlcL9kMJ-:[8[#Tw=dRׯnmp3B7]HYnlʁ!_GK/3Fdھ;\Wް1fB-9iǭy4'ŋUY:}vEL|@婂j̑c˪֢7ƞVԮDk=ZG+y a.u`!AvDLh>#{{P knznq&)$jZuM[+=.}*6n|ڗP\ht^\& NbzC_I1+;˅|ݏ&VI5kZ\ H Dˤً xU`uSkZ(d.1 4ML6l\F;"\9l%%\3Um/$3]z^#ַ1s[Is3),IvMʥ |8j2rZV]pڨyGQw N$T{[<3`eh&5Ϭ5΢:z:l6a'%sffPh+,qk\nDngXXZ.W5"pSYu1c*-jHVeE7]Rf 8.\5~c'(bUei mZգ՜b` @LI9L(DX%sXoSp\FV[7VjTab}7\W7#-úMG-Ϧӷ76ZUWC`b3P5>WhnꮕXuLmZ/A=o'?eTeP0Jxo90l!`k>R'Vh6bb:ڐF M җK HxV6կ>._л6W7N_?b8 GSF$HdQi/ iO'r)k5+ f/U ђY YߢU}R#Qe˫N Ƶ^@hBNtlrJ+ u'CNVwnPC+{熙 R8N1RJ}Kph=ޙ =ěB+J5ic;к'=w.QA[I{]AXaPpj=vĭ00}}4NJFuuԵ!m†}.aJ2}}}?ů^-LɹHjfIn7Էyr`1X *62z沵JHiS2orK]nWͮi{JJ$ޯaLULܩ]]L7`Zװhs:lZ KU07V3<hY9;$(jǵ4Hr ?ea:3}Tw˶dxJ\JX C-sqBrֵ={Udluu7\#$mkj˷UhKTlR;㾍rĽpP4".mf*tA^NyUnB1A+ l2.߷-Ҹ;TE-;JuBWSv^`"LlY:.BN15M@-5祊ikt38;3h=zBGNv&4%Q;XfSL^2[(PJ8k۹5BZr׼O)MO?DVn 4ճ)JHe+owي-Zo]Y.)V{@gВSKKɭVjzM$ 4X`QdĪ9!E*()=˱ )7`XI&{b2k 6N=sg/`y nSIƚ;nj.7"AՍ&mú$A> XW ۺcaVWh\B3ls q,*{3ZAʋ2ѯR kqл{x:lǧt5I9hLZZu5Ε;wܠh:?B&,TVp-mѵtːYGQrT\,^j;"j~uO=]i?,%Fvôӹ.z-5c@GNߋ Cմ_!$9O"cCUz<9R.0]!iX9ݪoc!ߍ=m}zF]hR}|պ3.~xH"RI^Ǔؼ*0LVL@h5C)Z@vN&>cђGE ? }G}f5ыƧM=AoĚ]zOK\uY~Ίik c*Wsm.4DeVaRT}Bd%Xw&;j] KY,B倨!J>amtEu *Ss:?aʰ0M8kLܕZ^7dٺљ ܶbc'LW@K)j n.GG1m[Tk', >ƾe%W]q'wFkd)޵RgBl]+跟i'hnG2"`9%7ڊә:gj2Eܡ``(=VJˬCZ Pv`j8zKAXuS\g/_ZE]%UM*?KXQִbXᄄU eW^.{uKvKU)ec='W6\9=zOSǕa[;RzU@a9MQ5gQhҔ՟ ۑ.!{uW 9Se?i=&3Wתms7qITze75ϭ `CZ,H!7#괫.SSC ?{>xGh75}[6껖'kz\ͬ'zUkBXǫ!%L;z'O2oGKU3I! ];j.UG,vsbj1)U۽=YssC?ڭ'ҹ[cĻwFz>uBIkZ"Ⱥnyq]D^%Kf K?=[P>+D "-CJ`w A4!"#12 $34A0%B&6CDeX.}Dk^[楳JD<=) }c r15`&c\疤dDDK] ݊:'`}gsy{.Yv/H"o:gK'=3doceEXնKit.ƫMejzUKͥnzp`eVF) ,_ ԶP1675#ۻAԯxɠo{Ih>>YFDAqm gk)'?0X1EWQ'LI *<=MC|?LDzjʤk6QkyXPvjW}?][rFFAVR|$Lz9OQcY?+=w~=qYԦ;fp6, (Wb6rQ,tG̠;g#&_$L=Ɏ+bC mZ­tYdJ<"Hw%iiyK['%%{E: X֢mBm96Oj[xt;ow{HO&8k"0g?I3 &!mf@`ǬO+=95N ++`]8",3q|NQ֭ͅd"sFO\XH=6|8Ps+a8G)3Y;ˎDxJG-6+RTOCEuZ>P{:o =며/t Mآ0gĔV9r]>i͗['±)WUku-s35n2*zh?r ij\1*U_f!х$clDVXg;<%MTZmOϹ/XAyL)5H9,|s9g3#d&23gsg gBpU%$}*̺Nϧ*()LLF2s]r81X )yy 8ƸNiB,M'\X4e+uE8шCb&~cOR]nrl lZxB^\R!Lej#3mq-Oyٮb@x8[M!FiN|C->a3?^g KKArRI̞v(ʌm#2FC e ^м^FS87볒Q]E61foLrdӢRkiʰ%y-ls T?ǃ+6@+l?u=yk*;O#OMdQOT|+׈1{<"vEcNNsa듄,?.6ޢYW-rZָU&Lg$:kj5؆Pzʾ|L]U1%MM^B )2)@R8D?c'jmZvuAcZ%3``LsZ]o[]4bbC<|r;2ݎa+zlC18S9L@lw=hЧ:E%OO'hgjEQ?,ߨkXӴ5BB=z@q2 feqr@:sL99??!I%&z+FFDg"3uι:>掮 ið#]2d.ŁU*ޝsb R`2؀u!2Uzɳ):聾t1<ەL"Sqz`W'kxrmLF~5}ڄhaHm-D9n-zʾ'.mV%e)"nEV΢S}nu?)Ɨ3'cd-سM~het͕wKf⤪)&XRp)VX:^mqN U+SWd j33gsluˌ B!'꽚O$b _OMqѶ B?!U}1f0e fRγ鍤Qc[9B>4mm5bEjU"9!E/q؁W1~њ$.l&뎲Jֱ8\a <;7&XNoԫMlxmbZ3u5T\-$ "S@cC &~6.Vh:F< L2ˡQߧvL*1*Xlý<g)^N-^ͬ"+rY$Cg)Ե;!qub%$kHЫщD2,-ϕzZk&˷ƒI ͕ŵM ^݌&X(HC)ANRdψ,㴏%2Y# >g7գa\Mo:mYfh'WmMO5:W"QY/J͝zuԃEc<7C|K=gY zrO5D䯰6Եޤ*`>gbZ>: zNs3%|XJPկ gb9, )FյKvyvh 7-:C`[;YNV!@mB٫>0dݕ+I'Ҡuwz^WP;?QM2~ɢ'emgymPFnD[XPC.l*%ai2̯Q>11~"ۄc$ kfEƔ|N \s~UU7ë?2#"0c2#833=XO2_#^:dyCf*c?5G7PֶJ*vET|&$@C b}"l@5Έv{Z؃%c͔*Tb_b? 4R@­=l+EMhLmZ+&q&*md%-Vd6> L\G pqqs?;8EzpuhGv|Euͣ{ާk>oI:gmoUVq*{e%뱭pz03=E6U;;vmGӛ-,wJ."n"֫~h_zcP { Db) ±ʃpG0"d-לZ{ZT={ h9Xk*&g_)E'"k};Tk}fLn22f+)1fSkwC,n,nJ_Z)U5z ?ioIZ6\2,z#&\c֖ ۴x +"Y ͟׿v2eO޾M,&U?d` ` dFqgqNoɨ=F~Ұ- DESeH+zrzewlV̓҃fȤ(ud^9P(咦1̬D`&E-\@W]n}Ϋ=W.1^Rhk:MM uzdd!d%V_bk];mk@3'13/>rcHq[5#Qa=g,Pل]W$ 6μnZ8B-#]4K8K qi}ы&ߴ.@jK;tq~ewBT<`haHX!)EY|W[Hʏ]+&sJϮd$S:@Mcc=% 6Xy9~Yg9*Y {:!b+?S8M6ZZ+@DN*uޤQb17Xٍ_!2?MG?l|ԂIm&`ٙUJ߳l Oj lt>^/N dAeL 6y{^X`f̤ ] AT}%r+N:o??[Yeԙ}x?ѳM 3Xz"x`-wqBA>ؙ|ݦhTMwa%s-ʟb=2N/vec.ګ6ibۚhJ]&u +;kOw=AqIp;,VS\|v$}ĂYXiٕ?IG*S(W+[8fo]lO`H|ʵ Ƒz~^:X?Q~P^rVUm`Wj 98889s,dO .r?"+J[ru?'ugqklY:9UY+:Z nJVdbk9ӥd>l+15fpz^m+^%T"i;^s#9lJ/T!/ebplڸϼR՞?WW ]?| )MͮEAԵaX^(\ldF |=%~鈤)̈́'C>Gr>Dj)xFrfL!hLmR֙Fҟ,4]cZ FDqŴ,{D-']1k[Zz̠TMx|lW]zD5?r&#km/r&H}<~qDmPVv".1-.h $g @Abw/WE׭5=_RX*\P~DlBދ+4Ru%sf0SOYХ D-}Qn){QNS. ezi[dpl62-:3>cߴ[V!qf x}%lE)BcdǞ_4\Z#'2*S6ne"QgiU ծ.WւT`$Y9L~ޒWP/X!J՞ؑ"O0c# - [Qn]S>YixIPaRY蕸 +%LL2}Mbda@"sD%UZ9ccfGϾɞ>N5pm 4qYN^F\[ lJ]iډKf%E˜ʬN.>;̛ǁj2n\D!!}@Fu40+u0Hj9RA"r#r9Qw,؜N7vd6 %9豕v:6dׅ/OTR *͎ӬS.)gqC2zz1<႓mV)BLls{Y{(3[ɸgW6+Zn^ ހҞ,4)i\XB|8H؃c$46g1{K r*k0 * 8=sq^/t28۫#K4og#;"+/\x)ȳdJc2uUe:pJgQ+U-t#HsbȘ, !W,g[fMH /x,_] j4f܈M3)5x9Ut¤Aԫ;CiJ/0*]#ܽ_19qEudS$+V9s?sZl( c^QשNZީOYx-ʢ&*pw83fJLcʛ ÞgҨ]]0m`Kx\ۮënNGMaEc.Rd0#ΪqL7VJ!YqC$᫬XYde)K[Pu ۹Zcb%[@< _bjWeV#]^)XJr+C%:~5 _ITJ7.o]kv,eZ}mL:UؿhCE/b&0N"V~U^_~Vo9qe'?|b]oPHuP9vcf>;)+uR}pK ?3DŽomEGl2U^Kph6{U _lL/"ħc(^L2Sv~2SUϕֈ8ʵƽ]pb"[$u\bYƸrQ3T Z0Ude,YCkkbAn3 >0|W ߴl.檿C >VC=N_nr$LE\~ڤrɜoNy/dxu[ hd'Ǎ6b<+' ~Xvdl!`uRuNQR }u+9g:g6kELa@nlň[dıXU=6Rks ʭ/gyuAh%b:ťD-x5az?Yy QUMyuu~\2Ar=T0TD_DUS1grKybq?##s^|JG^X=k;\ItfX K$oRYZ GZG%>,ݰP,_.sH#T4aPk9Jnb-V9r#ej@֊&+ue뤜Q3К!b tpT˿qDFbsXu-?VwbpR9>bB>12_9_Of^2~Wϒ2Y`F8k6~Z|c2P&WuZbA LJl;R`fdҵ#-h??Eb{f)jfujkD2elM땉GWcW>_6,z팷? >A3CdΫZw'v}H V )XYWKU"y?ˌ~A3OM"kت3-_! nX ޥ.y5OQeJe)f߹m,={Vku-j~X3KLDdf&=DXߗIWMZhScV$LF{V1dqs82c8ɏƇԷbV?xUd][**Flܛs0UCdܟ dwx1#^Eئs @Pn AZe҇E'[KQszi6kWaǵ.ڿghn YhXs;@;٣Oqֵ;A^tZӻKg]6[hed܎&OO yevV4Tg)|?3,G!6M0I''~jVYZc1P#; `!ua|>v6;~ğL]o\G*Գ-Ԁ?*ύW^-m K ~aNZŌ$THr d#fWЭ:#&8L)"8mc[B{SY/X60?1onX6klvEiK5@خ0Rֻ :!d\7.S 22Ŀ&$kg?LkI_a??GO봛jupD xbQ$a2q*>2(\qV.B?䪸Miya؅.uF~nXʣJ<~J)6MnE'R0ưgYp.!DbWmISē0N۱5bLNVzHɺHQwlg$"~<@OVs SێeT5 ZV)Qd_1o.pZe%krV; U8Ob E &ik'ĮvѢ2*HKk,ƹ:#(k)G[[}n>(o$}VlǛ$ZOd[_dMt0_6>፵^.lɇa!u$B@UK,A5'Z EIJѵ[}UbBY8C8Ǫ3$6 rɞ1N:lj آl %Zy,reOIQgXuc!BmifM\ǏdM#S[l'}0v5J"m)]9nJ8qVqGdevxZЪ21 lddbU2윌:˽_>ehi%)s >ì*a/EOL\1\%WH:r7X$N2\ މw~5Űl}}CJ`EER8svJ+8ѰmjY19௖ࡺ'aXlVS f ʵWͅ1Y_"1#B\j^( 5RME!j e,j[%Ԩ2yww8yJ;`~%l!F%S:E(XtnVyTDvfַ{ʳWHqqg+e{l:mt2S ɶ4=HbڭPQƪĸ$ [%D=1=q=rzYibeѿ`8Og:{ d.҂6E[=ֶb|񁞋xyUzycI?2#WJ#i\.D80gRU6AD 1Nع3 ^˜X>2O)%>\Ľ5E++@ )(Bq=<\APXc**leC]kyze *+/}(7N[F\G#/[~<q?c3O=CbbKҌiVlBr߈˜rY[UWb 46;/sjO7*r< `^UZ H{A-& qۍdydҹU(Ynێo|-7YˌΙeohVq88xgOg92qW?cFFU:(aWn >|8ĈǯivnhlW2xe3I (|r.2./Ytu N&LSd:`[Ak Fsvlu9>=IMP} :mwm*UYS0VZuqĚS53߂!G %&d)|Ï碊Ca9|pB8cj{Ӭ: [<\D bV:Vٌws g{,87B Ka;bXZˆTV'_av"cmBjߪ>W[<5>2)|Z2W*{ZmYGF &555u-^0-7ZEA©s3`900nJYzr]]Lxr'Yvb 3WpWI㦺}E 3 L{Cp*ſOlh0 DF]1];5W^I9 fjE9ޠIXLl3ҟ:N>k̸ͱ x9[&6)6dNb'.izr;CJT;:L叱(NlM?\(QP2Q'V׼ >a[:u!$Ճ6j)͟/GC?]=dŚsQl%;/wĮ ^(lR+:RzL$? @*SW0eQd|NFQl2de em4^@lB&ֽ/an|z!6-¬S[_\+! .3Ul:8MZ0^-X)%!=.nbÈDs 1K.NC&ٴD0VR=&sY8s'8:dqe#?yZq߰ ׇQ(0J< hXzW5+¿6Tܡ$nT "8'ǒ 4P0OԂWӽ&}.0_5tYO8Vd)+h2}}KGaOa:v^|c3;:|ӯmBr ?)5Z¢q\$yŷ ڛ@x=fx\=$N Psalv2ZM|P͉H'-w,;Q|H_y$,_K[?R:Z;5Ūmfg` (/,5Vʪֿsģ˕(s#IjuDYgT Nϒr[\Lc\-GA&WO?h(r׸$xqGÆdA;CFAXby ͤvZSٺ|bQW~?/) P*vr2.?lY'*Gi'S9GgFIyRڬ̯Bk! dG=cTS WȮ&"2A)H26Dk>gljBZ-.KsgcO5"PW4ՓTң[{Oø^[%Dݍl*?S#?t{qy?/?n9埾GTxy2,l a:9+,|d@$&ay 0V<E۷퍕ҧ]Wje["\s؋#A-%)m(|J5.į":J菖MO|?$gT%e ?_aVr̔Ҍ*Yy(WPrL$Cb=523&3e JFj kDhkkS&tںd}8bڇ뤂l}_)w"AxVx'Uh:KC+ņXE-DI2^spyu~h`XFW.~#gN˰ڴs$|,3G,5wѪftW54Zk.r)ps*.|2kx}~E?93ZT֖//P1<|Erc_|s/bYř3sf3Ïc$r#8i{5Ojh([^MWH5d]eZП=o{Dװz=LIG(YXpJSc<C81[dApS80s$a bt6Jk2׵r2]ɟ5|V?m` ?)W6ϴjUs哗ZWRuTQ(ۺ]ݴ`q((8Ѧ3YXQAZO)B<ۇ/OE:\QvTeX㪍T+e6\g) &DYm4:d$/(:Gb\ذl!y2VDD;4݀B;m|_9 P1s`ibG{fg>jщJ׆QC,ރLpȈCxKtziFhhX)1Pس&^2O`qnZBlrg&N^U{#|Dz]{DƬ xyJ: U "%HD/83Tk"NjUl5R ZbMnnk)m(pOd<FTj>F@ \M|O,M9(8{>z՗Xڬm[t+CJ6 +&\trA@%U<:W&襅ֻ\g\T }h5UybG~/? ʰUXgX~Wi=%!]X5 bu}M jlڣ5,k&Wzxe)'p+8:סyzz/ӣM*f,tm ydP]|nombr$&ۅȥ+j<`6ς|e,.zBSƧw/Sك}7RN%X)jCz!tWDFnHٿFٛ*WNƻ:d=Hcm:T`_nIW"ea0 &qu 3T4AB,9Q٘_yQ?;/Is/p`gZref{yϼ9`CI23$?`WԊnd δ+RK%nEyAHd)NUǑ,o/TRoRj<[#Nxpʕ,:%bUCHVJ* :춈n⬾iL[ڠzvN hۉ&zefdE:b&Q\xFmUb1gkVg2:qx~OCj(jnV\'Y=?%%%Hr- eNq%¼&NI@Z2?Sm700pUvX:MS\uzɘ *K$jᬓFd"Ls]ƦC@=]Pz-y2A1,l'+>&[l>iV !L%%ײnd 7f^cR;t^Tߜ>)SW`kŽXM1PHne&=$TO&?'kSZʿM|IɹUKQY.,;ٌGȳ61OMUsdǐt+es.R^hWI̅93x$1 #IfsoAݸYBث6(IWBIŞ\#~$Q*8Sglն7;5;N1b-<͇HN=_䲩WmzF7f)WaB濨N-l"PsW>Kmѽ|j>r@_oDLq9 }sMnƯMf{w28aE%59&D1(Ay'_3]ee5•ng_ZāB%hE(c q?SK~<Nd/^ۮ(wQU|y9ܘ뫖Yq wnjek4R亸>I',"Ɏ0&|(<3žgaj5i$S+VC5pܵj0bD(kĚ='|U=8@Z-WU;STOg;`;DR.c6z4$R?2%ek;8#qJw]oK;XmEG/k糊c}Ȳـ*=M:'ɏYkϺ:ϙ⿏$;CιscQIbx+-ebcdP]9iRgLfO#=rS<('@1W%-8v{%kln3pAeOsc"HEH+F"akBF=34#gQgLguι9dFqgqDdFqgHGA_m_Y]Lu5 CPt&ư_j՚j#Ez 5[Ks]cY!e i(q`ݫ^HɔDЬcd~\k LDY!N&ؙ(_]`H n_,&Z:0W寨_Ȯ&P̾ ]n?fdX9s?Q_Y‚vnZidvKaJU*Nb19_uXkrGNy.u3%d(4QNiZ0=uleKf-WWc=tzS_{-VP@TeU r˰>E]SLe^xki\>gu[gנ҅os"Y "0"dme+{cl3_b۲UPbA(O͕\~͔jL ]\in vEqW_1}+n3 譂rgwqr=xLLvFվʬZ`uo֟~),(T-S +ƥ c< Q*,Y H =eIGeL~?njtXCvDeO݇+]gP:K"=mekIowtu#1\3$R՟ S|p$g5Yf(ؑbmawşn7;"m Y9Zvΰ 7$e0qf@x+8nn ]bk[I9m9Eu8X{<8-3vF*yď5ٟf=툲RkY˨Lq%m)eҀP߫'5+z0`+ ^u8@뽗 x)+6:̟Uʃ'E|MBvſT@->KGPxS`pa`;ytAuBw2ʁY3Ӓ9'CBZ=?Qmeγd<ʜ3~ 2l4O=~s$2S38 M .{"Fi,yObC!T*U{ R:Gg$D柳+EOw^+ Fק?"N~DYexLџ/LTLf5 P~J9~I5s]> s9Nx'%3 o9<d$Y,x%U oC*DUlݼMv)_h|FĩZncWW)%l yi qp*7޺Y0ُeo+xҹ"xYR̥,LC jD;R𜬢[]ZϨ Ȏ'?g 3`( 9)B/9Z噰w/NF#DGɻ|tT % =@H319T;:Qlk=vFqjx:a߷493ˆq'sgKܮ?QrLDp`׉ι6Gm݃2Gf8yQXa0vS$Fr?ZɐP(z޳]l/-k'?N3'js's'j3&'-Q6Rֲc'#yVsUG*/fD4%d-ǒtta׍5 Z03+Za3F\VSWbyoV?9:a\f"$xs琳d  sY=e]_nn3*nb7uw;NvU͏^HO3iO:QMoQ?՝Zc^ÁEV%zjRoJ ԺE?\RpՕmBZO: ፜OMF+a5sڵͩOA|%׫Y]q[!UKʤ0T%79kxcg!lS+Msz֪$̖bz[[(w7V&Z7V\ȡT3skb 4 &=\ĠjVV6d]zOy,KɉEůqvdr"RgRiŪW,|:p'b<[[ rp.:rJB[0d1ĉVtI2z Ƭ= O8 0*'v<(iv%WT:n{9(q_ηܞ0Y@c3:Ӳ)i[/۲0cPoX]{hg)Wl8wG44g`'o1/[;?gW3O(ֵKZxE86g$57̉Xs?a +@LO/Ǩ2O#=?ojG#?S>S$~[m/这$⣭:')eؿz?ܟuDش1#cJ`.͟㢏c,ԜWgeo#(6r#Sͷ_?,E_{Sk'(a.MOwng{ѧհ{oc%sS_p4r&?l<a=!1A "2QaBq#03@PRC$Db?hN=ŮkJ4'hI'쿮nGb`RU閚#iPT_eUG%\6}eCDad#vneR.>[%6&bC {e&{MH4D4֚چ&IU(%c#W)^+і[u7.*c1Vx6cVyGѓ?ڷղDSIn|\d╲>6l^;"[O윢A[,/͑b7ĸџ&фIFu%̿il,\$N5* 8y4Ւ4Q)52dKԍdLlNVyΨxwTkɶǡ.NH3SIqhtxk>a.$$蚸ОkLHea CseH^a>m"^hI . j{esK5r"]5e-N"2| gn4uRjkV8˅ .BpYe)GiԿ%*ơ%_N:w親YkO8W #͜F/ժ,PuMfg%Y_e. mO6{N J0#X%5E v=vőVj:b5UqU}࿱1)j!{ ~7qM6IB/y=(Ꙩ2>õqie^tF.Y%P\jԊ;QE(z7- )2LRIHov*#WEŚ.m46,qhz,Ԟ圡FmAtG_%ZH.$7F*LtksplN}iO eYTdM'93WMi"\\DYvIf1&!Aw4r=-6Ho"KR؟ޫ5O/m 4!+Bm*(S7J=:Uw9Z_Di! &(QJY#RFvpYޓ&WRKK'5\Hgy.U/k9E>l ri9mF"YcF/O9'Ir({%c^E+XH?'^ӹc|zt3$9f((ѩ+LͬYiFE5.ȗsQ\L5.Ik<ϲ33ٕ(^̑TKK q-YT,p6?Уj).MEqEzim(J)f( (M<[BJ/&6!]ITQ#ydHvKVR?s\ غYx9{h3ђtɽ7RTE(`HUA$XCIMP#&d`1_UQJx}sgzD2OJ\׿. QȺIfv85aپ6! I;; > BOjB5iȵanOJ-`EtU"0mZ%i+d_%5D`i#JIȧj;*lghw-dpf|!UO9/4IY87>s54w#-IJUDȥdN_Qed,RQstAǓUd/ӋP$x( %MlӚ8-\3F;4C'Oѹj4t^]N(/M(˱r1YQ%7"Lo=QNLSؑ$Q+݁R77 (ɔEs6n,t>}NXĬq74#R1UB ӴiN'Fk YUJ6)vc4j)(|Y{XDc'.\bǥ#($K FWvJ݆jyRJSIR5Dɾ"Ջ7E ~F9w6U/6Uj+kQ!jB՚q'jZ}lI˃ls_bn=;xw)dѲ5y5fzEp5ӂ)%}gJ%^f99-"B;H_PhmoTAI3mQ?m"sI ^RII܋e%,KwZ-K%OfB谉qՓd'(MDm!#*Nx%Y4v%q%)O-/"Tvme n ކMJt?l!x]m$"d~{%r6XE&IJ)mTN B/-q7OJVF>\TQE6P5cSI\GvFn$l+|:&j0ܓllٶ?Ţio_DJQdnէBa)8dp5iN#LS{&o6=.?Ehu5Tu_xi5ϿJ? S%z("_JF> '.Q)ȝ;RFɱ颩ov_M==*<7č7x<b $\ N#BiMy4301Ydԕw6\kX"5bi^ep5uRr17]# M4ZJ;xJB]F1㤧R}I߬kHafFRg$ -9*p5d6$8G*.K,ӏHi)X5%Zi2 vCp9/8[߹䚹#OM[O[Yꛋȡ8TH/fԭ2 pM^j-R4:{JN$pE+ATȧ(_L  5umF܋zk<+-YE-]OK_$<*O8E ԜĞht RBŧc\4me>-nYDFR"-T{l_QB+_'_,Z<ʄ! !HFfHdiQ+EEnɫSF*eMfF,->)Kˍȣhޫjm h[DC ؾ#XhB2x GƱ/tHy]#ӔOIȏܔYyO{J*r!8ճRp ?iۺ\cq8F)*%єGI˂ZS(CCQ~jQ5h_ˀXyX7jå$[7Rg8ѹei6,";z9)ci4截fY(;t'}*ʔ] ^lTI*tq (E|%rGFVFU䚡O8cZF4,ViU|㣩ש$J)lcBjk% N."qBRKQBh|gtOiAIFRnOF#=.CNՏܰ5##cCHiܟNRt\ߓPerRH>ģg~Cܨc[T/ %v"v2;hos♡ *PRR.Q4v~?l 2DtB}ŝɋtɫHEnٖI_KQMmHxB0B"8rDc~MElvQ'(Y}?B"E1x鷙N#\ IɷI)Ж,d%Bג%{ܳ1N6D(ԗ46mZDuO׼QM|F6b+rWMƫB2&r/R)yr[4哒\ 7wm*#1C5RCFDT;[{ inٷ9$iږOy,-A-.z~MȇyBMj&]߹x,ֻw&Gޜ~&iH<3fT +*ǎ{cd4lIH2vLۋ?=y4ߗhWMDž{˿ymeZMصk>$K B\$dY '#ˊDj˔J>SF\6Vjpwߦ\ʉE[_ jD2(=BՌyM5"zFTBx,Qj^ݨdaF9Jɨ,#}_)OT=2] Tp{L el~8҆CCfB]hEpլ_Rz~\$$e%5تodƣd?%V*/'JZƏ1ėY-kjJ<䞞pGGzip(2CQ'3S'Cf<k]`gqpKbq5zKy:x\Gҝ s4԰RhՋR))gLyCx)4)'x}ti͝3ZM-lT$C.ltBE[vՂxH~EHڒ<4wMvo^?1c~mFferqHܙؑ]2{Z1\1vKJIm2Cv)YyB(ٵ@$ lUcq(%]"$xO̗dmک҈TP~랶 봢ԺWN$Mmdj&hHCt+ 7Y"`謑Uɹ=cNW'Lftn#lmzNE^I#JW*"ɍ&D^;V$K9?"IIEcew!≬٥ɪ>\C=%fCg.w$HVi-5DFTjJsIbcV*n=<-CQv*'-;gŶ,E1F!e\y<$vGs5Nu PY؉ao<[55v?zŪ)]:dWwRHSYHw*d"MVӡk4jyb{EcZy%GR(<EӖnUE[*-\E 6S+E~t4%j}٧vJ>M`|:4%&fii-EzN#~%&?o_Z6ȭ#[CJ$a܄hԔS_SR<ȯz?XȠFEճO?骶Aޒe*1!b<4ߵ7)W;C禫[ 9R>WmqUClӓTO]=3Q)ˁ;5=ʇ-9>6(}Y!薥;%'&UwA["Vm%/Gث[zs49Q7`ϢDl_c®My#nG#7b[D,ȏc{O"8GV*%Z S%D_n.4Q969ESV3SO}de'CQݲ$Or9'ns}H%r © V/#Ջ9EX]ڹ6*#T>S(2k"K䐖EmJ/u ޫ Hh}-GM6I}9f{Og,݊-͈ڍYvXev#{=J';+3lu}k-Dhj^G8'/P"t_c+l)wTLkشJ#n Q9%vi`/T^c!*+Ե#v9 VYrܿ}M6Hݗd!`thZVMY$I}>\uKiʇEp*7gشn~id?OU"-Y=JS%er]oy0oŦ{v(g$֖x!nJr4ӆhRܢEOl| r_<4y$mr'}ZB;F,+rEGvر!*Cӎ1IV"xoSG]%z\f5oo,mgͭ G궺EңzGڨQ%m[~ӓJ5%Ig&FOs/l ۇȣxbO}٩.gXoOR&#![tAӱshs.',XXc~bbXLmmu{Op &m "?H^s3k4}|}eV6~I(j$43K5ܳ]E!16SoGjBY%oc С CR4=/*[HWsO"NEaߦ/De%*/NҔaq=Klj2(;/H"f+Nѹ-\9l[Qmq66f8bE9v%&/i ѦOJE4Dkr(lFU&F֞l6GI|!5F\t$%'w%;B74}G=ӴiFdɱK-bd}Mےr<[\JI%Y- BX!pPFAovHxrOIELVlӖՒ~oiHsH1B]j'lt8'kxDG&VqKIB/qpL¢)~DdjMaY~c^,|"p/Tɷ]n}x4խƣw'GaZnZ盪SOb]b?(cR_*4|ly*#BS펧PDdf2ưAQM8[yo̤8UB 7sQ*m} Z8dx'8JUHwUͤFwuۧ箏n2ilar>+mDiiy艶.4Dkp\ PّRj-x\V 7PdI{[*4E핏R4?ƪLO&"ljivIԈ$KYe6Eh!F-5&<.E%d'}Ѿ C,ڜ!ݑ$)^ L#5uv1rī#g{pG<, >烎;g;Π؜TPzgj+ҍ<"rlRȕ*QEwc'DIN<yviwJ$9Pq4󑩝?ܪTv&C PO=ldnqzj_}+;N'ѱ3gȓ+E`CEY$|MiQY%l?H#V? SJZ\rq͎fHN|DiEWH`vW؛58<":FhXwK5=$jK.䟾 }[> =Ĝa_cL/{JJtnNE˹]n QY8"4E"\/'(7qj%wA< }g9~U.DKeuW%ֲ?|QI15jݘjHOVvolrblO}$hҋהlԃ Dwb!&i%E%u~zy.݉;,݁:FD, T'ZDS! ӣS1zYlƚ )*BMl$,2I_DSUi8`^jb⨗()4Ylv!ri^HBtcӎd"+؂rVԈ&oڎ07~Bv_ٳQUDTMۆBy7}Blh6$4~2EdE{D"XEU4VDH%TnWNGVmp[6j5EZ  x/B2F{ J3Kԍ'/|M*y547(8O(%q-$J/وђdcF.MƩEPnMC;w$Rw# 9鈼$RY4EDOz1rjt}xgd`OL+B{&dF{F[+'"v.ה#-L`M7B8"},~K8PH-UY~ɧ+4|1aFFp>GݖGcVC8VܡqUt=4BR MSLq[S0K"%v,\t6.JEq.%LxC}?(m~+ﭢLxu$^229%,1ov hFLR˲v:URq'K&YUO/r64rJW2,hS9oXly)؋}9-Pp*;}w+6.6~N:H%sjor!H:䓡jȾ!˲!ЩXGem+j%8#)%r>&u41P3!m\NQdePo9:i.gC7y^08]u!_F=yInLrdu<!`HlK$N:GG~v,UQZ/5RW6>96W=nWHq~ 5OFPtݷ5jhGݡ/p(iw9"2R#QR5; M}|Dd}7Yfe_E]E*g<Z&Zs_G8*# <4ƞM ~iXGYEdq|Y<$}ֺY)S?k)BK%y9ډlw_DH.<zd~+DN46Iɩڻ$<߱I43j%8#$p?pGqpEo'WVG=k#9z2"5ܝv7?*lkCeb.Q&GA5' SY5oI`ԔveRq^ opE"':C$i2RH)ښV-E4Ĺ:4wQV'h" t iY±Q9\6C &GkfL5,H yc¢Oooi&Tr"vM)v y4{ rrQRr߮FYe<ў4}kc6.JlzlZ|RBpf+qQ$E]_sqQv2+ɦuD6i7PUNRRD}5}]Ag!`\zmXqc[可ќc:FF?{98U~5dKE#/]$3dut-F'<ѻDs3rpG= ?]rTy1_v1jCM׶-v99GjjEhѧi%*u{=\UV4HMl#Z#k"d53G篌̣Cjrf5R'sty;!A,"o49☒FO$8&$F>d۱GjQBR8f.cY:D%ljOYQf~Jt˼ۢvhk~t~P9/OZI䖶Sf8$Vi].rH#̶ğrYa~E$`Y}_FPr qiMiVh_"Ђ<}\>.?C҃C$S٫rGwdUՉlssOj{l͞ⓑ5Ŧ68dz !,4{xtcSKVE2LoUÊ*l[*!%if<$ Pf8YBuf9Q7"14:dP 8F<.=FRusMdn,n#?qq烸~c T&>WDœJ>IE`>x4FIHyC8 \e759y46~RJgRGCV;Y4ts&#1Q[}Z##FiwDG?G' EY"dՋ.E"2/h{²9'_ܣ/,J,ִ9w" 896/sDXr<@S5J푆4dȦѧ$yjfk=Btݛ^dSTFcHk ) 7"9ʣ/ɸN)[5V(Wyצe8$rB]|+5/9Ⓣ-w{gJ6gN;ve=gfɺj:>zW{$j-HРܶHZj8{J%ؕrqx.J294I,s45R#FyF*4ܪFbiGs\UvDG},}ңˍQr?*QJe`,,,e_{15pFq\6im齱c77CyȌdiN33R.\Ȍ(6ZRrǤs;MgN'CLͩP"IJ>[dUatᕌ-2~+&͒>N)LRf Rhr wJڙr4viMdKi,=mXO$=;_1t%nF_E:'T}3tWMYSM tIUj~p3B>^B͚0ڭiɥN_d5$s~\prvxi驨lzMtWdhq\Dő:I}8{Sblp7dU؏J?^1n7 v?7nBIE~1GN[ehnFnFnFn"jXG-+cq_Rd_cՊ)'KFoL܋EѽL޿fѺ7#r7"idn6YudnF5*',Jю5q`$ɩ؆Y웣OtH߸UMm9v<<&kj‰;!2ش#-8Ԯ+fcMU")JY5{HC;Ňb??mb՚!t$2o*V>F" |I¨QDۜʾ77c5Qwl܌Mmc[J;ˑGnxKX4tؕ*8DFFjTIt|Lܓ47cK6)^<1pQ~qFSE&$Edۋq"2qm?υB+hΜ_#.Ec(Ep62պd1"%k Rd}gNO}fiǔjʈؽ4!;bW?sijF͙!r'Q5hj-4얻JwȨw4xti9Ȍ#n ^EӸ4}$2GsGr~/4d8'1'}>"C>f~PsG͑+>OxTEo||d]>?&6G;2\ⳡ?cte YBYԟhBd]ʘA!#G4GOU&$d~$٨4\福DlFihi.!>WICKCDjri~rjq"//gFai>$2$L\Neݏ ɫ.zCScD}2;:!1"A 2Q#0Baq3@$R4Cb?PLxÁ7r56K}KG6<+7WTX4Tת,{C+=T6 7 E䢉J,Qc[16v?b#eK1LQ1"gtwܑ?,l#[{MNљ'ӵ=#uf}Z-,(Ѿ"iF%..O?rmY9Df׶FHFgw$`'vuMW Q=}ZR=Xݗm%zH1"%HzVHxٲF$^+ˣqedGD_R#Ԛ#Pwj|.8<l8.o+gQQ2>,omB<:%;5zyaʹ5Rǚw%gt/M %~ʋ#ӶJ &H% E>]&C4Xګ3evYׇψu;giQ)J͞CeD>1!""Irjiab9ldNJ3Nm ΏSrGܶЗ茥 ).̟U8q>'#['.m?Ѩ:CǕ΍&K$o0Ǒ|"K:76vmTzq5ViM^`zs>:"=“G/Ifuq#K2*ēF\$1<%ry}NE6b^>F!SK;'Y'FM-<*Nc[rI+$. F@9$=߱UuŘg] N 5H}v"_aÑG}/"_e#j6+[R͘F?J۶dW~e#)W=Vzɻ.ݎIq=EQ^vٴYe6!׋*W8ZIڤ%\ /i)YZ5XcVzQQh#MAK>=IQQG. ~F [jGDHGǎ_c"BBKtN7#Y {i)/Hf#02jfnLjF& :lx1,,C͎'ɵ3a\hVdY]L{n;'H.|r>RbHhJ+^u>ku2S`wǹ#[c6~jQMϣ܉M4K4lY?Q5d']'l!]3U7գVPčNXu-o.L7\y.3p?;jf>2.? (ؾBW|%DJtdmD#&z'-Mz3cy#`,\tmڹ5RZQ>j,#ǑGő˱!=z-$}Ks.vA*iIY".ƒDe9$rrG<SGHS<~ȼ|$qOI%)RՈNJY_`G nFOKe6NkfU6zqSBk6cp]bXћO\I# 䌓L}?6[܎DĚ5Qp43-:V(9D1Zȶ+f,yC"\F$F<^h0G'fGNѧ6%?s7lis3klIr|_#fPT Qjȥɇ2CS\^%EώѼ~m4z{dCldQD{UN'kƟ͒hƆNI:1ԗeŗ2$6+&}{H)(.Lq薿&EH혔Srp.jmcɓ/GӽbOko?bۖD8E,Œ#*dUN52-$jsndP'G21'3 ZMvSoj'Z2so\)0jY{7dc~1\Bp5܍F`lo$o:5|p$Xk~樢R[%B/ضd6i^h6(4zrj:Mn鯸M1ACudDSf15fj1p᭝Qfd^ЪqpCFIodž~'Q8|x];\;NdjPŞz#8$6W'$6hme1?)j'/UI W$:&GB OilpةDqɑ&z&0528ɱrqQ41mS&NPSFKtK10sOh8#Q9X1Mٺ~#Т:T3:#Dنbú^ތ!=6r)&Gsb(Oj5342Ed}da9ol|?-([.T1EEx5؞h?ݚ Y,4()ve5zoF)X%ޞ{d?Q Ge Sf ҜWU|Ȉpm2Pl|6GNDz6#|V>E#yDKedn,ǖ_r9JLiR Ի&IX>tM9xD)-Ėq𼝏*D1M%3r6h^-#4>.*.SAi&t<~UE%#|M~icР1Q;#h܋ojf{4'"Z'iudx$I-DJlAoofI5!>6B]G*|>J>)嚬{eF,R-F,QeeF.Q,snasm»^ɒE~Dh}>L 8b/m[W U8H35׉?ْw?߅ٍ{It<o;q=fy/oF{(4DVEf1T "20B%4q7I-ydaK$`j~pQF=5c٬4s5Y1ra{=%鋓NjFTzӺf/iĕ&l_(iviG6kd3Dɫ4שr>F섚Ct|6Կp\D!2am"$&%äAWݙ6;9r'frmY9n~(PVȽJ2䥒D2"pȾy';(j̓>Fy3('t\űReKTs=%RJ1$)1d[w G'OBHqە_ȸf_iХ~/tdͤ)pLqql{Q{i"8QGON'NjZR1`8HG 3UeC-=JĪ2(\V[> :z铚cʥٓPHIrFQw0.[Q%njYK<*(F<,RbrcoER[H4F w%|6jq%S{Q W?gÎ]#M/isbqfO"~-yc'\䏿<_6E}_tݙ6A(;m/CcI"'mGFb3qq!]^hn3]6}1' BOj<,O蛹a).Lg2E{Kbݴ[J%e (q!:{Fl|F^$r׉#-Wsx'QlD{3t?lJ82Y3Ms吖$Bh6Mgا 'c\FL "RLލɛevi>ͩE J]xq܏mS!hDGX+Vf{Lqt_$Nr37DGSZo lj{˗˷SMvBV;Xp FhǍƬosЕSȨMC!TN?WmiQđ/;$|{#& [[d:OnȤ!vJ<JlWɃP M"fRԺRi\Y{?ŴeKMA!iF[1BQ;J,F zvKx#&NG2RpDU1ɣ22C1xgiE>cGN ,%=e%h1Y<lN~<-4,i>LPtj2s4G's!ow M xvzHBlGXlřgŸT)Q lC*ދn?JXYVz7ėz!;/r~XѺН}|I"1Mmb$Sћzd[e(ɞh٩RqMص1!5,~rK+z.$| gT7DV] F.(Hƭίd9~$"=NI1ƕw3f8TK$AO7&9{b+]sD%Q*q+Œ S5"4ZbydcB3QYS_$0ôjkE#dлfDclǍCYFl,"1ڨJpqK.5pKv7J1f9(šj"Ddx+fciGq)M>ʌY'CƳʙGa:B!r}SE뫏gp6tcD#4#c)ɸR"+f59rGjfO͈d=DzE"6xp_s$g_t\SD]vF-C#=y#*'>L.BhH"Ԑ"SF3j='HÙ߹ FM9`#M?;x~ Mn6yHKW?"|崎%CҸr}20b<~MP ;DrOhqK Q1`.k3r膖Oc|ٸ˕]eɋ!QB9B# RID匕amжEW>Uу-solQ7 *"nQ|#q_RMm7)vV!gcG1,]mf DŒ䢨EĖE5Lĕq٫˳76J ̺%b/q?̊OeR79r{hzkuX$<)z?NJI(N+!K=?eWFW|2>ˮ >#2F$Q{#џ"¬哱(D51Ë#20r2Xɖ_&!C$&IY53~cHDF|f%G$1-|B[h<{'.G*(|GEY*|>F8߷VJJW?,lvK,%CS6F[.PQV2d!=¸26jrCtE^bK*%7";&KԉOqm_&r3c̒qQ!ߊ4N<9 NN2w ;$-ŴJ[]}3d:n_qQTfĿ(LpH*'Y;tbkI$ĹB >:67ev*^:1duʼn[) j1<{>YPMY-pGtnEݿCNeF5YНfFhJ(SCʉjt>_{]+Dfmmʐ/7EIU7U}Qr4I1q[I+4NOW&evߋFy!bˍў[#fԹ s#܏/Q8܊'I q[U}?tE4dB"Dؐzd}#ܢjtGz2\gCCNnGdv$MᑊEοffd)iSp诲ڍDblm:toO^%]x1ej4Ks苞MzhPKjO*9{Ip>ʋ| n!v=pF3)*f7Obi%\E=ERufPُc'e|..^D1ɓWtC\/r1h_ɶUr!efOdi I!p>Q׉O͒eRٽ=V9~1N2dmKɖ+[d%ʉA$q$엱nF|d[4ܽRm]KRv'%ǏdɳkaQW/sd|SУNvB|x$?m{bwX3|Q|nt.Kfd'NĬ BE Q$J{H14rz،؉W:_ģ&{"o%:k}Gu|fpLZt&F=_4"RəT55\FL[&:Ffm<"ɏcˑpC8٧,!KE-둓WcBTGqM4gIP12َ. dXV(τM\ș7t.#Jn|t4IOP̊YVb*b˥`B)22ݏc&!TXpNQE *(|mcЦE)"IK[T8e'f88.K}c0e܋1C=&qfW鈩~p|6=߻/h_kWak:Be_"ȚQrfl {k)m?O/8O3]y4x㗆O|e㔷<D?{1ay F(ȜJ,MYUѽQn&"Oo߈p$S}"]܇L-٥]3qeR0B^F>2+t\KY[de\16 M12ͱ{b6XٻՏMZ6- 3rH`3am OFuJ=^ILXg,|#\ٺu,Xt(.DSص0ngdcow$}1lReoHoF:5\Igz8$$R./".=9TIJ6FL|p194cv.OMѴT$q$^,*O#eHLض>]|ެimU,/ӱeHb6!FI[O/_] i俿Y <ɆV>U3t3WdŧQMQ"-dɛS-Of8;&R`[5D&d>J0bڏpY+UFn"FFfc~c"5ɏN7ON?#QCN5iK7S)MrmKC>DXɑ~q/f,LFl3G#BB~KĆa#c$OS2jcn5^ Ύ1F.e(6JT3!k1J&YGk~AR,(;!R2Ita!`De$ iGb׽=HЗW9|ttr>/аB"e-ꄸ"JǓ%v4FD#;I*QW(Erz{&]Mϣ#Eђ{N r}[,y$Y4]0~߶?%%ФjƅjpѺ!2lwveC'#ӿiNqw-}zM%"x>YL3XƽFfO RFS:k' c9%"Ywď^'ČxGZ'iC :ρEpOfᚮc DIй~/wrȯ8{l]̕PHQf:&4ͩ"1Q1ľ`2i-/H> >G%-܇7E&?d$̲d,4yrKfHи=FM.eNY,k)D#$ H~+YM#ri҄0U?&9RRB죡j| 6{WA_'vIk2vbQԉΈṟQȱCib2?ai1.vJ; p$W{n>c_l~~bCھL/ѩuOF̘a^,3HHjg\# "q"r),{f 4t"άR|ap=*&ZncM<tKJ/W֊3ka{3^r.fs[\dIdvK 9$gVQ$E r|^qg>ȇ.PM:0bj6R7ŎF\1{0j.WbǺ;7 IE 'LݵJٖrlz4#\xJbўI .h&eӲ+H)2 ^r()emWğ,|_g[4Xj(po5\nk%'LŖ> j[&,2m^b_dǸE>Jtm)t^'dN'ύd/q)pc\&&Gk15^'=RtYeGr܇};/cFCmGF3&|ZWq1>$o~07>Q3O>Q$#d;1dPtGdF<);4lefJhjtӔU˒5HWʤl>+tR#dhCܹ5F|Ӿ|HP48TB~X|/CkXfU? 8̗)hRg)n\a(qUok$C.3"iǨ>> ݜ. %d$QJj8TC\?&^ςo;2S3p'J,yM6n&VȮEȯ/[9RFRܣFL#l+OgDA^Cبh=?P{΅h".,޺7&IbBdّnr*1I74t#c*\2] hMYJ*JHYvܟ_~^em\?,V;9D&"RjKItj46! u$Ms#B;9lUFjdSvE=(Ը54p%CnJTt1}Pcƣ'dx(ckItAt3k/fM{]!{D~UѩWɑG{K;\hJB+1ǎL/b2aMWH613b 0bq[Q l^hnّ:E*$TE6fœ*F 2<%VGGsφS؏H[d罫'-u+KJ2{b۳Uy#՝%gGֳzXx+؞<I:tN8ӶF#$ĥvK".6nD`KIr#ЧCvΥG,}D|FWϋ&&ܢ Wk=űM+7IGt9eg]TzyQ.#Ԉܙ#r-> 7"v6ŒN\ͩx"io{ee r8Zuf,yB&A fY Dg4|#ٚ=^(2Վkmx^#'ɼmЈ7[NF.cRl>2sJ2!1/ LL̸!0"Q[ܼ?elܽbOq=B1eH<ɤO܌QɎwxȢ{4񌱚?DWF%NV>s&t7=-1#ڢB*f?G0qmOƿHx~-2)cJCtUJȾL-TD%VcT6%DS;%Grd7xh,orr<9H2'>Ќ|//p"E~wH{M؉9'Hѱ(n #iMmIlem8_k g'b O[[z]n*еo˗ם HYViZhiZ`k4,ȷKtE䆥MdN{%#;2%5&4ѧ|$bfl!#dJ Q*]8}%][%g2N!˲C:DʉB_e!d8CC_$%ܦl(A˲RP#sO}rNZ,܈9ǎ&nE?&$&j2I#tKPhQ~IcZ, JD<2Q<,*2;7\Rv$)r ÖdU^! /bˏ"Ó4أ"lDkع+b_FMH*DzmN Ȕ!'6bģ=T>bQк0rc(r.W#I?4.^r=yŮ&?e؊] HyDw'ǛxDX#]x^!>L2X$dԉsMN[Ӊws|EvY!>C䉨܌Y\!{T=,8d_ծ ^j<|X %fW{"cǒYO,p kH'r>O6dvN|&Q'6}$"JtvG;Q<Mǟ qx^șo«/ZDl+%&hzr]qYvBWPG_&'? tEߝv$]2OFcI(r.Dd9'ie\Ls4߉ F-Sڹ'/Q4#̖_Y᯾~B5p$ME΅*T;18x%d2}HJװc[$zqq% bα2˞Xgz' 3jMZ%FQv$BNn;/U7(RT3$DУ-E/PnrU3?~ !!/ 2(O&dSa[CʐxjLigqwroGn̑D5!Oh-kw"nwcfIp`N cV6YjX?GH,xrf=N*ڊL"%У$v=j=EO%F>MBdqߋJƌ\yZMՁ?ǃ6=fϓ*vdp#$Gpɽ1~$>6qo,^i9䖊3Q;!ʝW,rD%7_w.MQovm#&Hh6Yܸ{ٙlQ$bzPɝY0ff%2cSf%6J隬6I=89]eɰ匣D1{FD"҈9f_EHA˒|I܎d]\ۗ,#K E'藹JD#DZJ̫ ?tȾ >RFhd *9ɏ̘T-<DžLOs̋"Ւ4B7FI[,~;$aM|8!ǻAzyo{Έi \xO/ 茎'|sq\%ɪ$$2Voym+r&c(jы C~J&F+J/(]}Y cL•['{S1;Iْ[DrIʎw/1'o MB.638>#gHruD}}(lU-:fL^1jQ zn.<ʇ^'F(9]Y+䒑mD*y>Qom?lXdL.}Tq}.lo5D ZFXb(27aSY)sc^?L;0;f{ tmd/t/(h3K4ҩef?ƤsJ"1{7X&ڍ2YB8#'bleډ,Q%y \3BlӾ{p%FWQE[#P[Blʜ0#ˌbn1Fjc:Twb̤oT`J;fJF6F*} Y j0G<9HxEKqatO$e 1%ٗS,#Zv;N.Dd5Y}<<oq9i_ا,|rW>W[JB)ǃa*E_,5pK&ELMAmxKlSQK0C#^w%(LiϔG#S4}( Vy1bdvf3R܉dFcYN[ؿ"J͗$LU#i̐ 'D'푗j׍ަ=ݤF|C] ׌B'DإfefmD]3?c?93FB;K"%lF#k6dFٛ$zrU$UvZ_G#ӑzr=9 Hzr6dF=9ѶFmf$lӗ#c;4,3OYqdY>ڙk'yYG"KiV> lǧ;3-B+v52`YceegNIX͈+Fԑ<H]xO ntFUJ^rfR_&U m)q'ю;Uc+tEo%IcFOD?HcF5H)Py,sTDڅ|Ge#؍C~M^Gj(úSKF)]0r|[f?#=?mq?Ex1q!tGƢVCm2o'lT (ي;m̭F#u? x~)Ky=SFWNq&?˓l?G"H&LwV+Flx0E.MVK" thIArJ?7 jSXc1V?)tb>/ nW*Dd#D^ =fȠ2)CڄhľY~Q7 pc؈mbHL۹!pM2%!+*}e\Ɇ " _m%|Ɣt#z^f튆NLN)vC;f71e!ѓFN&/.G?OOF.fGu>e~L1'i^'ً׈jX3t> BR% ٝ#Dzb$@FNđ!Oqܘ7hm_#hMq|#鈿y#cO2:FR٣mb dϒB2bLLa] } gX8&?xG$c\>X0F$/N.2^W׏I !1A"Q 2aqB#3Rb0r4@$CScsPt?YZ}i={K&SNNWrODZeg2W*ϊg8P 0BO2L&ҧ`*NvNLE4)w Μ#ܸsL kp8e@B=Tt[8AR`VqjMtt0+y6o)߻1ݭ=Sss@>W(\i!r|ל;.fj#Vi/|~!}kUP׷wI# L?%}UrԪ;K`)ڀBЙ*sЋ{/+Of-9C"Ak+O(bwe(Y{EAN;E -4I& J%JOw)cE ᐱiPTU )zB{wB`F ߪ_eM0KRꇢ/{8zHDS}vxBjTS, SK9aV^t bVZaT@A) ໪\e')ZHBV&ƈ(²&8MkLfTWhFtF8v ;?6&F\ʅ٫@Dfl>VfCu+>$p OtZp@!h ZpkEY7ggk |(jҌU8XH ݖ<ƭq_גsm2x r9Y2FaVwFuFµ*uSu2ݕJ3!rL"Qԫe@2(qXa8fP$hU+)PSduW 8J<-ܨi8L#v7; uQ )\aZ!aaKn7WKNN?1XܐfxGB$9FDcE }}q v Xcd52y0J#hP խBxT¸aCxKA\uC-8jUMZ GrW4js4ag@;ONfL~ -kM@ }TZ *S=sygP*R*4in+{Y\:`3E~^:-8XN詼m>Ul7U.B('Vqw2-5uVWyNs1S Uk%)R҄eKSqk7r! QMqnS`,썻 Ѫh*HBv3b=+*tzj #NQ> sYBsTJ<Q8S݊p`i)sP(Q+<tX)թs {XKFE+x6N*_h*I?UB[Mc 6QwYN,.h#:D0, \CމNVEz) ڇN6<3UwyO+];(r@?F?4еܽO 021hM +7Rb*U BU[qSp+fSõ$!\P894R\J0jF V]ʘZEm8uLeMArr(2(%IS<uO N8[jVw~Ѷ~>za9WʷRh9*aX󐤧N'1<&qRp).Ȃӡ(lzIЩG\+H()]/;rEOPx]WhCB>,r*8ALSPx%IEaL.\x-R2QvB&xC[qPpe n ( 1u䛝xiOȗ;t׋]haW2w۳~G/7( *%hpBW+ac Ykʩh[*eeP<"UuNsIatr'$)~[9W20dܒj-l5z~TVt+{̫(d]^- Z"#RUjkB` ] Tpz)ytT.l&^MށR(6RAde*TJs7tZWPmV]K!I9㪲YPʥq^ᓪ@)jz+<]iEU;'eF`"˗37(pO~*N'ׄ]w;VW&N&8RiS*wpn\W!AM8slu3oU!JQD)l+E!as('(eZⲥZOW)*@=,!7NL'U-5eXRNvT\ FiHps Ϊ+U5M1fS[߸۹ kWq1Y1RjnV?*22+ NY򬕒\yr8H*^nmSŨZ`AC])PnGtd'+nlp(Pp<,bۀCcr4q51j7M=;}T)\=π7uŮ;*mcښɞ9ADCz'_rxL.sMug&S~k^AE?(tP n眹S{l4'}ZϒJW{Qh7"NhEz(feQQW{i> Z.8&7up"Z MiaW#Ur4)}P(<$STj퇊Ye f_ꕭx*^ЮRv@QiG3#V ̮q\媻i4M;$4h.GEZt* W'Zb?XrYONtMs pݸ1x~%(eΟt]GPdrTߪh8%NhcFNsF=կx%8u} ;~Q$vۭ]D!}}G柢}?Я>g%Yc@FP)"nWTA;2ejy=UsNBWi n;軻- Qt8"lP2rEdliM+o)Txfp+(=S8`J<\sM %Ot\[,w#SwҹunDu]Nkv18I4ʗ?qCsh*3 SwX !vgRxL lF4WStpLF5)wt솺%z, |&0FS N$-r rxp*ѢB^D!#Nd,>4YUN: 'P`:CW;)'2nA2Uwϙvz*kN {ۉ_[U\NTcjOVpV_нU_,&=T9{ZvC1Hƅr4/3cm.›aGe Gg}t_hZ ]?w٧QftWZKПIsKmЅ] ::ntTv0Gr˹z,/wlRQpg &= + Q-cdr쏪ku%sy`0$ea=xDCUkLO#m5Yʋ8z:,~8{9d껷vtA^AnݝwBz,.! lX<tYǔsL&Oӆ<$Ġ t}X~sN\v@+)r͜Z wZ6_Fmyw5ӬsQ?'n hW1 Uldzƚ,\5IO ށ8('5ڎra۔Y)<0v!5ށT}ө;0pc_ Xt,A`lrm9C|_Y`psai ƖvA>{?4[`I.T_U`a5\T){y5i/lN)JsX߬pS<2o{=QQwg;#gpvIV,ENgxBQUS9;(nJN辗*EPU'(Fw#mS=w;0ThGT5F^iOBT:QN*h&iEF 㪴~G@<8Z̚Ifppa' {GxȍPqOEj߲?cE`'0QeX斿$g*79oʻ~U)G{>ZPtad"Rzp9 ጠᐠ._W֓RO*DǝewԟފZn NС=x_v"HNre3"z 3w2< #egۄPhNov>. < "L7w8(I#7SL+ِl}&|EQgTR6MquاIzj,sNkAR21s*'ܭpϘq'NyXNYO(QAN.ňSJȅu2bzB0숩zc;;nwT >iWvNW{ɷZiúrnp0ۂ֣v2ޟMJ%;6/2+U MQ_}( 19G- c}^.:¾oU[tz*m*t)ֆꀨIώHR"=zj< m܀:8ho>ToU? sVkxITڥ V+2vYo* أx_IVʹtPB4ܜΊ闹 .̦:nrS? aʗ!Vi0U;T.Y]94e4*:cf<a~[R? WA?yCBPS\UܝB28c-El ;^ԝQqP8TidUʝ]Bb_Af\XY%EP2B;[U*bCG=WG9+dS' YsB,A璘_{!A)c:#f}D,.lحps(rz(tiR0qEڝ s7b%`eV {+`G~+Uc-.[Q2 :ynij=as.P7qS#+D .%@}4}k4N -!ݗȞ\m  l 9n M=4]DR/ygA|TisN=UJ@ic-:45u老$J~ `?SQ%YfcDGFZB 6kSFBT`hJ%9UM>UT5B`#:{"kC PkAB#gUTu #On.]28a8ˌ z)D]7VI@TL4*Lwe tPU<UD!BSŌwd§U˓<owmo Ԧ6J|ʢ@6m <{*l JTu(?mŽ?`e5ѳ) QjhRӂ^wO˼tX¶RXyEP#!'@  Ja@(gO ʧPᡎW?U*:m*r .Jp9MlոHqt ]rk%'S\ oq1ǕWwS?xG@1wuMFg Aah]#UP^(P TgJ]aKeIl 4bTntʈݝZT*F8XfJ+UiȞoa[*u9Nk^n 8ucklLgx 7ssHD&m?)49C]E?`{99.jU;Y>o7s U4.1i00"놻{q~ΕWyovZ7.̡Mp,XZ2TugU@MH3*%>D˻co*#kJk[N1wu᫻hpN =:tj(gvծxT*ȄGP$/[W @AÅz2@Jqjq]렿&Ӎz++@BgFrS F5v5JV AV/e *q.yY À7Xz=Wљ*ڥyRbQ *>Qe8믍]:4Ԟ.ERW.ʂJyLEsYKƈ+\PqǀJDz]S!*04 p̓==Q}a1}BnC4iPid8hD&~$OTqi2dE;Ѧ-C,PeePi@wۣTf*l3vz萯sUQ~)µ'U%ށRl4;iҴR.G']B,j-;һ7U.^J nObr*N5ڀRT:@eQ Ԫ\S>'p)>s? x;s` QIPaL a _Vv)˰K|#+(=癜¨FQrGj;E{WmU+TIAUnwU='Uk]qR~vD;<=Bc:zʥJOMo5F.d:я%r(!\Ue^ ˾I՟O)"n_%sЇrtIrNܗOnmFi&fU+X#;Ous#-ɍun~YPj 5޹F+`B륾e-X0u+xAw\Ql:c4Y} y o䩻`PW*RU ph3 M*DtWVIA Y< uE̡طPJm!rUJqF @rsJ\<`hĮ[ln[#41UJnY*Ni/e*,!Tn)]"t]02`n:X\J."AVr?Y(`á^Cܲ -8EgT]'3󸠨 X辵IdΞ-̠Ʉf`깛 ..8nPpѐ4 eMk dXU]_0\pVA`XpSON@B3uh^viBszx C8lB3R<_:RKܵƼ , ⭕(< ']9(daY7I@I_S$3 HNnЬsWf2=:NlP[}D^l 4SFTDFcN"o@ S"=]2h-cSB벰EeZM^LBvCdiVf6(HSjr,pa22 k uN5L=cDJ}CEc^xeDA)lћOU7Jj4 |TV&]ڙQsi14E?4AQ9B۸챺]J=Гa8T~Bnò;U^lkTs!C2 A@ʗDj8C\nL;Χݏٴݝ:lv臐0p2 Dmo ƨvET @ijVA DG ~_퓽C?'{.VRp LOe)q+pooީ0?`SϪcMs#;K4P|J!v>DŽ"7*⹵W)n꠳Z z(hʨΎP"8NWtSPDlc*uqly^W1S ӺPzNϙZvVTݓL\:HUX.| ƘTT(%9nn>}Bs)+!2@kOZ,s[8@D.\i \:/^p)lnS'[R:'2C%S:=vu>_Ey{;bqmiUG=0ۗ)`]̀и'D}W}[.r4̅T) XV;V9×+p ZV?KV"G aHXM)ڕ6Ԅ۴@JlhT. :#M;v_A‹0% a4Tu\Ս r8F|={[|Ix}O`>~>]gx$aZTpSrC*³ez"]1 YtRU I:ͨ z"QqeO2:#\ʠFD"g苦\@:8E%n%N򋔦TM~1Ƌ +Q< p + Td, 20;lhWU+ʭf yN4=2JsN?AEr6]OM~ʍFjŬwhju_C .תkͅT7*#+F@T͔8?IaԋJ~Mַ( Tn2WNT{OD˜L*H&8z_>-Bt 7TBp-ۢ$Җ~=QTrޔq?Tn] +AQkFLzOU)0|{@v2+F+W0WaLJ&4EEѕ)d9U;sTA\U,pΈ'),Z-R hfA":UrhQ>su4) >"P^)u#"cO1xx5iAeuH̠+mV";#eUaWU9w\ouU., xZ*a v(zO{YPQrn8 hCxC4R{U9^ȑPwhk̳fEbǙ}!πiE;5*wM(^dlSw1US4e91;鈐л]ֲaV$<ݪyiUC\=&z!B;lp;ntAI2'E{.eL ]9Po48 #L&w7S?09: 9QƊ8v7U2ؘrAXR2J22`JP' NФ J\M01_W7pS(&3`O)ZJ)J'eQ|8OD$}c vy=WFN^, S8ʎЁLMq0cG+Пp58Ws+}+!=Ep(2ʐxBu17jTJ×3KV\.VZ}I :To(jߧsaLhp:CڜϰTtQ{uAڡܵu-oKQҡ E#BiP N\6RS9ksV2\)!*%ZVUҜzWavΠ׉t{#:FN-ITK_:ִΝD_ c\9U X>_iR ^ߴӝӚX9d(mSNw;PNWq ׀Sӣw1q2Wߊ?H"^[MeZ7rȟu,?%¾ ΣH;Q1/꿳?Y |Ms(#|<xAp(x5h%҃ 5VJJ.a1]oYq^O9aQs5M#!G.Ҿhc:De#ah݅2,(Ş7kNJ8Њn 0,ò4f=g>*#gЮ4|Q|E0 enpȄ.WY8r"ye;}vwu 4iSwWh$SBs hzA%Zժ< V~ W+TpVN%F0aCһKWwWw@4#ݷa X.!AD1LN("Уu4+Z$%T+UmkYUG17O9:+iVyq!6\nmpXXL TkN5P|pQS4=G \4YXH@pʎhVfW h[L+CXmDzLvOY3 O}gSu=ntiUCL,wO);,$2>K7>T #]h7Z8|;[qoRYHQ贫 pj4 r+)KarBΜ %#({]ˢppEluV]L!7E:sg N{|94'.mP UC!`(5V[5]C4Xʺt Q|Cq"p&wzUkFEr-&0*5"HDDTwxM{ /%6Y!]} /^S5FiU@EϚ@jF BD[D) MG⼾&pEmOv# P}?E{;oU'4wGmt!\mDgTw§`,ShZ-5և[+|_ߊ7,rʹ1Tp&TTEW z* s? $ƨehPk*I2z8Vd;[UHdԧT72`aH?x-qU8\%6$n~ ?-t\Ҥ9ܡò?75ŧRf7\cGEP@4%]HemJB}hyNl -xBmp1RJ)׌l$e >W(a2Qa}t^&zyx@C^dn˻n>j5D|ǔ&Xv`F\]s)v ( a1.,P*Z<0*ڿVwUT]!92̘Nx"ss ‡i-!wy-裼"B-g<<R!^ vrwӲ}CZp\qU0 ̾yz`W0h뢩xQ2[d/@u \>1SyOUޏg7MO+<hQS'pʐ.^aGp@7h%@v5O~2?J0y V''tzE'7> ီ:XU*GpUD"`WE3AOeqM+'Y ~atFtWP:pD̋&D E˅%wc%ߓ0+:Ժc< k3 W{܈fU2\d,.^%C FӪl`rps)bo{PcE$;Ajk B^FWO_AVcei 7ԮݙN\^_ ?CLuΩ㚕]Tt&ܫ畜DN.li2n6)4]yʷoTa¹XQjꋆ8TpO򮧠Zڤ~?hdu?x ])l⾲N4 CNe7mz z(Dr6;=Gz*lːZ" ,y]L`q\j7D9*z yPk) 5\BrBrtXMٕ*:scVTMܬMjv%ZJ޽3eſG:j8 +Õe[8էɕ!wu'D ^7[s= =JU o4ɫkpdczQuWJԯ2HZ#=Oy%ߒ]]#EiOv'!Hs%V9 WҺ.F:uZĞJpkuO[wAEsJ6Sg$,/%J DT\(!  +NUZmotrʒVv H+ O Nf*}M3|ǂzgEQ=SߠӅ'XWʂc|B jhSCLk]3k2ǖ5wù6P#E:q,*$Wj{#:7+p;"^ml*Ⱥ ʍ4??xOcgZh¤q%VZ=7 'vzGyJnb)T]}+ $qc-.*(uMa#]U%‚(?z.WhIw\,.kkྮ䤴jV/)fivU?oZBƾ5 oX?0>iH+*`j?T?\{j_ =|ʯ}7Zdf hiԨޭa_gԠS!c}5s+j~ j~ /rzzU@JJ{ vxՈEV^ZJC&:G@ܭ]gH _HRֈ9[*Ch5l^i Wշ^@`,#*& U{^DpTʂA1:M*N LRo⯯4`'Gp5=W585O )MM4M ;E(䆔P`gt*2uа8S4@ J$i'=Z*7(F'cS)i{'"]Gʵ]UyF&\j gwV{[Q=eCgcv\ZdαVizq+Ɏ=?hkr>DB*qQc CAo_U5Qc9ySKL Qqi򾩫 娕Q{wihRnX>R-~Pp c,s]'ak3F8W~K i#yP߇ ITC(N=[ּTs~!= 6&Jm_]OZ?g=ѷKiGvPvZ=gq؛mWS;m]UHն7V0ڿWrhw0ܻEϱwv"lGn^{RGn'9Ԫ>[Cʛ{]sR(>ou0Z>O5\#XAs99j7R{U=~"p^ `R-w$=^Twtj7R( 6XÒou"T6yFI^IrBZIA8U/9RܒUNL5rάϔjfvJj]󀱖7)8UXvv(}Tʕe%U#uOSUiJCpkf+cRoX͙'8^wZm=]eO)P7i ekYYQjyqHԗS=&~c),dx@*qqQc<줳_8BǛWVιwcUǘܱ{+1z~g2wQ)Vi1*mk(r-(EPm;lSRڢCsZiu.er?<1U" J珜HYyxwEXzS0bW4۹ 1 nQڙ E:t2ap7S#F7by2x%Z)l!pRVScJ8r0 rPG:wJ.`Iʳ3*BAjT-Klͬnx:& Ar-YLfT㧈Xm2^vQԴ,AMw>_pPw0E A&MN"Io%:%4mP~yښƱSs:E پ%fl#BX#nLB2|B&8x:MALE0;SRDD ߖy쨞Qj A QxK[PrEKU}hB?;ݦfNQQ2sN3Sx͕X^PICc-U.3f_kFƒ/9e~+*Pb g\kb Z'#S_~ ̼|1sP yw6 9YHIO2oOJ `3p3p1e3ศt^smsT]>I&&Z_3f*"[0m*qq<* !JTgxY}{;'.Eyx1%ɿTo*#p>"J G(T=ςf~Bf]rvyNE]DF^Nu^`,wlK$r-}q:^cL_OL!7K,IJ-Qi"j8V-! SRJK1fL n\~N mH3RV0[-zX- %ewQ*n\4SQ2m\!o|ebX0jhxu|.RPAWnY11E҉.4Y\«<;#\ ÏH9x"Pxߩ(JIB5+raOݿ?X>R؇%0<!b[-K̿'’<&}C@\X/O : #GL!(—\0)!H\ uCr6%H\ GʧR& <e4C}&Ę!l ΥI3 pBڜF9#Z ne(ᐮRR:CP[XRPd6qu9)WmɊ4fo2݃XlDMoGRL{p@R  ҉yn&u,kS(E 19ZO*t|Sn)XPMK{#HjVZŵS@i9f4`Bڅsw.7 -0EAn|r"L J+u+}x@6-U9 )EőRE6 ij/Sjf%SMUc1e,q1KA7[!Y1`r9!KCEWC?rk\c]3.4s*),sLڼ~%m:پPق{hɣȯ0™eTL2y\iw ?[1] ]#\VPV/CQ:k{fs%NȳF/}vzOJL=J;*MOO Ș H.br$|&9)R{ci˜11FN ,֎ٳ1]e*XAb7|mT<,aqPײ-*$R@@)CebXlj[i6BF .&mx- p:J%(#N7&z QV]-µv]Ҳ1};F?J-Xrḏ yDFeS0rYT5Jj,[Y~Űe. m·0Iԉ}Jp,-J3eT*8Q[ C2bR`cU #V/3.?^NNeE~Xwn'@Gxg5r4k`0(et+±M\#P :fw>QL`"ĮRhe +FL_8;a_QIPt`Y^zcx:2&J~^rʁb_pPqs/ٴdGȩ6)u]Fe9&feMZb<*I`wRO4 hJK]MPVn205pD/o4aFrfN&f8C-kf+N\ (U)A\_(>fHs\ V[k{g; +,+/S=ƄÛ'7x{@`&P754RD$`KnseYs)06[bϩSp J)PNYY%!z&8'[ZW'rG88i38bbWN#֪X č۶ko[kl + b[fHslħ H9J2p.)Ee5MDCMF;c|W2c0cK]SXg̵<wY1yįL2M LC|*D>2CKUIjئ0__GK2+? D,sB7[~1-i#%ubQ5h;/Հoƚfx>|Ů."Bz(/vsӖw<'-ڲOj262\#}REp=WWAE`s~c/ -$F<:;3Π>)J1K@j2@vBt#ڡ/hjRd*1U[oƠM+82]YdC0 E˄4;I, jf$Ū;B$"Fw-3g0>L`* ,frUP'Y8 q?/du~'!tAkCŸb .q"F$3(jo*hTfSDŽ.@%P4{m#sE[HUՍL,L% D.ҽ5eʛTW)f*V_C'8]ԢZ2 Q'l[w}JWp >y!i|F+7%Z6WZmP}V ¹@ L˥U+L Q; G>?f2@TWW]1ݣbp%)aTJ\Lyҹu3M9 0R=̩ dC0P;]6Ъ~3P!вZE5qc().j>I(-W%>eq SLDZV gMbW$}5кQ>l ;Fl˄\=c\ 2Np?h| CulƧV MPs) E]#,&T"Rͼ#C<4MOu]dk<3b5]XYPT+*&e6$P!0 hv ng\KXQpDmsS-8`(ȹmF5 h9CQMLwԬb);x828%aaJV.&#20.Cf@έ(h s'9xF(Dl3`6ۯX0q}_B [*g7@s-foJ®9\mn$r.}֤ܿ Cgwv1gi7C. M*[?IX1+5ɅeսC(*\S9 Y* 8nLSqe4#}z=irBo70H4%f(^P+Ȳ05ZTE+,OuPL- 3 nű:Im f6 4}dژePԹĢZ`E,^ ͞eVhWVWەUNoQh⺚?RÃF!U0`5+bZ濉(]MտFlZtql7Ap*5}6MJM4mm Hc^F jʜ=1e,^ ʠǓ/ cNdX %ŗC\a5k$)kS-Iz+T^%AMN otsl #1u]ˍ7 P&J餫T+s\} 0bE/,Ep70+;DeHx&v2C2U}VBf;#yBA4 Ơ y&>9zs@ڲ\>/D:TbR ~ӱ4&ձ"Ҍ8F  DhņMf|s?XPϷ؞Y?qء9w;H *%hn]e͍12 pLq6I|,"4ܸfb5lPC1avQUhV`:̭|! "S0LNX:&bB-#02/+6ġF! 6"S!k>?ecЦ55wfg>aU]CvKe0}Ws2Qw [sSzHx.BnO0Ŕ̭_^op8.ޫ-S R\cE.}#ُ(|YL ֈ! fUߢ5*5n‡e33FF&%s"3S."JY7 2rDv6Ӌ*l&]<Ƽ`Fg0+='Dtyї&>TATܧe&_lL1U-F:FyVC ܨn g(e- akardA3XbSQ);= R}3Gl̓OIRrckhUw@Kƈv-K&9ʎrR |D;f]HbGVfSDP#%U)sp3 a bNrOFaJs'.%":I]~]ۇĀPA-xsQXr> dH9 = #kz;C ;6a2?+tv[&PF<;>ERaQ,5[ues+^GdP&Ȗ#j\,醭c3)7b8(5nK񑩃FوKKPLn2Í7bQ> Ay-BƋVG5}#L`ZZq5,Ul* b RWDcǼ,EM Õt@rJ fJmePb`{ClƏ(,x/)>H,Cv†? @RV+Plh -MpXͪ(fRط:3;k- LcJ™*Zqķg>]g&@Jqպ1TqJ۷y|NTbR *q̹ͥ '\5ݕqs yTCLlA7F 0t,UHUjQ[b)u&Kd|AQd%XU:q Ԧe e[+*v X W(q:ӈ 0d6hHhZVW?q|n.\k]˥2Ղ/Q^b1Őoc)kjT` `ZKo ";)JܵYzׄG>N̮u%Z'w S!]w ,WIWԹF<ȕZ.UU@ĝ\%pm/KSPlс}K /JύK|4TіlۆLxaA(E^3UdO1uԭY޺԰s/,D]YVCKbbWFhH$,?lz/grND * 6?#7l_Sŋx UbLBėmP/ HW- l&׻ V&ys WʘBRL5Mc0+Ģ!ryAD'SM5;B8Qlak]E,Qr8̊A+ɒԫZ^. aXi_8B!s,(=VJ&.#Q`,`E"M%йs՞b!@F6Vq= T%Fu,巹L8H7.PvI15:sо\I|E/Gd(U[xheʺiR Fe}>9Z>2qfJ*p1Id~0FI+"G16е04ъqu/@ݙ'I):3s 31+L/PUJ2}u`<٘Vˆg+`iㄳ^.w/DO ` Qh*(="\G%{pLMc2@sVZQQKJh܏փ6?꿔Fq$ȧE?RYPC- M$IQ AY&j􁒜d_~QT[T⇖3/KŒU숃g-nkl Bx)u}N.Әcd%_q`{{ፀZ:: FT]SC1ڗWh"^&2Kac}LC=Kh!)g! Cn!`fcfwэlLˁ&eRب0|BTt {;黂| nf3݌l2Ƅubì_̵=F25.MA:2+,TS&YxUf3pe+U}e>!LĠ#M,tsQkVb셋(Ը6ȱ5((kGQVw)=I x mਪk膥щb_j9V*1gd+ *a"p5fA)31eX^Tk!p z.f3\ P7 m܇MLI-{;⢎}r,:.5= Y:xʸQF15aKC<7uk E"2l ~Ӆ^8 :Hl`BK&<Ac@/0 h60^ayk2֗cʧ':|U~ڡKYX9J.2h9"~癐J; x]q,T7ps[e$._ʰiRzLaqQ6̤G:fdaTW?~g5C)5r!^bY/J j\}'Sq[B aw-g&5.,zJiG省n3DLiUCn0cy`^ %F(@!sE<`RCs\e 2dŐnv+ωqHxojYkk(l0̋(fR+,V.We\p ΍3w\mTR%{!*C|~"q̥EGT5&xB*mp1N<]x/ISQ(r3?#+HBR>eY`oĠ-ǯFI y3I~kKCqB"5U|jl'rՀ`iX@$eSWvZ33[ىf.NJÉs8BϹk)JjgR둸kXh65~.Ĵl&,PGb g#q-jy;`+c uuUW#Y9\bc 5 Zor\KsGÑ.xLA,j#(E$pC8[c].Sb+`m&.׫Bk5,x3\L^3{<11R.$\s;^/nLwUQA%yQ9c QFz 5%<,^ MsMEo-۬bϵ QPPQzvM}-|Gl%i)R8ҥ^!ɹtQQuDLR Vrdiؗ.Z׈nnUius艴<ܰyZWK0f+̀W9cp)_~K.+G61fQLHW*XPt)r,919`g\|W0/K&LfVwl4~"$] mxu#㘻 ?M@)UyG(F ;{_7#|n'8Z)6O)3.xn̢`Fp!lKV[L;Z GaQ"QS_ Ĺ . * ň Af\@{"}\2+wS=>̢>DGȢ]:n=jxj$3j1 \FaDfY 3 |pOׂkbv-+$+HU g&_4 -fw ,DO50Tf+[cexФc2ζ,/*t/~x&7V pKSU-uO3{1a K&SgD,e\ٲ.5 UȯD,o~Ye,a3 oy<[̱Q `os wClJk #4#eiIjs6,{&BfǸwH4)QLi] tXbq\a:!~G`b:|A[j ӘWJJ% hS"eA1.ݢsBڲeE.*Xv,ݬF#S9ycWD%?#ּpе,S,1!]G ,K-k=ʞ?VRp`&>ʾXN˅NTM [kKD@L5q Py@Ų&bKbAШI(Yt0_L.q7m1)bb7v]ax* ei܂%dqPYTXH4aA_. x0c8pGEtR/1R(XX|hiX@bxMAp#9v^1esBjo+j^\ QYcTf>26K .bWVK#ej&QdG%#}gN"in&,oEwHtJL Gm&c5E#};طɯP] qtvbj1~J TA/Я0U1>*ULWmDHJK-ӯ A% EJ5·ңY\6|OHB׈&O?ZzgBD&^%2AA2='mQ9[D`Wf4s<|nV뙹2+E)cIAEi+IF9R097Ud:aMu;]`pXx; 6 s3C ~zLXH.(f0 \IRKy{fP"T(8GV8_`@>ʜ]LJ!iD^9h3.;0\P#>@xYIP,"AdZUf."5 𜃍[0e b]Lj[IMa`Q[!Q"k8= bbQxI{'䕒ꬋji *n) jSqUo}KuUܪODGt(*uB gjFn''LT<& F0bCBN$8!urZhi4Jqla}]i($LaEZ2$&%EQ\BjXKtJG@S3G ':MQsdziV 9o" f=p)\Wni [0+@HE lC#9!0w`MW@<5+e̓/=0qey0 +U0p+Pj9/ԮUe,) A& 4rH g?鸂!*-C"0i)FJE%H2Q3LƂKɹ+F)ٗWh \[?3 awXn`f#mʺKis)Px΢VEtO(ky:V0& **Ubň%<^)HD8MT2fP?߈V% eNykIה!q\,)(_0nk9`ᚔNb1*WQ^kwٮ@%)xšT2*TzAmQmhTƝ+ۣP8r6GBZY/.<KWh 85!|bVsB&1`$J`T,ix+ Ĝyճ&.&J-U47^ 1r8w*el?ű?ԴU ΌΣ ׏˝u5H|g2%:1=~#?aWC|[?<<0~{iCWwʇ :&V0|c% 00jyF [E/,S (ޣb&V(s*oUTAo~aRDa> l],R(Xf(e)C 0č wɊ{`Qw)l BD:!cJ'-6H <2$we0.$؅Ar@!#_.zJ}s֠YeIp%U  Q|ƪ~ ;p=]ԥ7L6Eʋ阓~G"YM8Y&z)Ë{M9)^bܢ >4W /@ 5u2.i-uWiRj.?yN֭8"+\@alG,Ef㪆$ld.kڷH{݆ʖ.H-R%# sMN- t>>P'13 p=@Et:M&dBk0xvo"ᆫQ5#DDI<>FX%iȖahxDwQ=2Bd^aT!02 D %N@2@x6j1.5Cu ɂa#/c{3kr蔓Zw1+4_0\ B@kC5Q0.ģcl^z W3;RG _P]W.cP2 |N̮l[ޥfK* "] ]U)'bTN6hBGsD㈃IJB,iCXm R"eAutr+y`0G빜(>_/yGoqOdʡpU$M~sb0SR7<`ښ(-0 QL5kԾ r/wB(tkGџ__EFf9qJ&mQ7DZJ@ZUjºdy #㯒AxJYp}&-S>/M3M'i+ fY+ YPq2MX xa@PW4tK5 zs{n069A%l+#t|5APbQ-'aS d+y ,󩯙 nQ*3hrΏs%]Au C$5XRCHWA BDc#),CۗCk'1l+mBsPnw11=Cɣu>p4x.}!2Q0`MyxU,HV6GZ ~I"񯘵ƹ4)}s/C,@M;)J!4Dz6B gT1tN4m]j knFTreA*d|v֢FtCKe_x3 /HPc: Z]RK ]bX5 L񙔒7r,pJB6QEݹd@=ˮYT:̯(")>$pCDb#y…6EVJR;BCj_DQeNUpc3KDϩZ;TaM*T/,KIMU<40OXOL[閊TG-Km:csf--e[ݥظꔧcy5n\!a!QP0 Y zxtOypS?1J[Z&nM  e.̒apԒU<}JbpƻF FEoz%NGqܶ2kSl@;rG,L\#3[],*z~$/ d[[V1K I?߇E}5s$jQLΒ8L:|z In%`"JkP>`WQ 5EZ;PS\3,H#wاqFG6Ld>2bS9+8EۆP6 Dlw}3nwb[R^f`3 qm"j0ܻu.et‘_*i-GA/; ݔ{SJIQ6Psp)YqR 'w1ߙV2an٘;27Z53S0]M9-e `f2&j!8NCN(<lhx@bn ` ѼË G x<14:17Յ@p6ԡ~Yܷ*~u!AOK].8.S_2cS% G;e @*B (b 8 w,^N]{&neh< aCK<{Fܲfcq<8}2YFv2񭊘&&& 0ews5ȈJ804xGq/jp 1* Pl7^Y?1O,L] O nZ*{ ^TT_AćF 6S7*Q[-5Q#RUeNIǨ6QA]Cy{ǙXF-V.=L+#`1 z iD ba1GR*Pk(b]gGUKcbsYnXOn^.dPL l>=DŽT!\,4 oىL{Bryx4Nx32^w;ֱM=u.|ŔF_"OH;͋@n׹`igj0#_,[HUp>%.^<lL-y@Qq]' 1+}cS.`c.<励L?ÑE@pp.,;`8 Gd7jtŶ<*QZ~cp~3y#SWRܨj9CBzYjKHmaOIhƍQxjKzij BR$ !L ?Oπ%?Sиb (LLY~!3:9#986О{2*B+M̩{!(Mgd~}6Y %'䁗)SܠpFt9D1:K8bmڏ0kP%FZ凩ܣ37^W;Wgӹ@>&j,UJG(!d/ Xhnȩzw0'ͧX #Tz.K0 -B$^%wma}q)ԨQi*!7_G( lءC= |E}cTkJ(g\ z}"_\_ \]aݨ.-y2<<73o̮ƢF1S8I}fBl\~WCU +wM{Y# :#\azO00H,^t\+b=MK7<^g!Pi< ϼy)OO]ɒTZ28pCdc,9<^EtđkX4)M~_s?1}hRyI랙鏆zg=1"StN:'᎘tCxRK<3 l)aNߩj >f5ܧbSĕm= YL|K\FTgsL *(l\v,<.Xļu^ u6&A%yq-AE ܾ;ɦbLplE,Wft؁Ko^%*Y=Vg:.wҜr9[ eKQ#czE 8?݆<@7 ng w"`G,es( ]jo3;=G GV`U<+^`hE3;[71&nsr/CK? V10_l1Sr5`g|2\{>i"'?l$Lg Dvm{1 <M)K|=FdE 9k'!B.1=!2n?D?\^sX}eeL-y ˞a`d@ܰ]K~{@0|2FA.٦kPU$ٴ-ATP\.lْ<,vx2fh` !eBX/ \r{ܪ@[30Zݝ.W=[<|S&o23d/6lG}#> uGby!9 B uB*q"v+Wv6^,B 9btL1isa.Vo2,./ j^UZg_]oOe9hq%|qkr*Vp?ry9ESBc[ae'V2e[O$:߄8.嵍~7baW7 q0Y=b' L\(펅T؆*R.gC UZ.'>*]v 3`ڂpɤ)v˲ 8MxoW~n/=ogI.0U;Q*s˶Z $pY@\&A-Fjp :j[; iphӦay ǣR+gH6Z `DvF7Nq6Fb"4αR,MdJ{E:j 1hf/ Ĩ HY-7ML&Os\}D)#k8'8=EM"n#?HN|nt-3`4sB}Q!m&cKC|Cw74XOc`8q^s"⸚\VDžD^c +YҶd 5QU32f|dXgp`B #$؉MQX]5Z#ao[~R5Uܸ-+ |V%|1>I"}ShJ ,bƑ~ |6Pe—ΣcP{#if(2me3Dx#G6;w+7^d^p,20nA4%bkLq3\ۄTKZ)Ƣ/B@ڜ0AD-En9FsGL'Ōͭ ) Iq?&o-9Y ͽal}MO zFgM16X{s.3j31r5[߸rb&R_);g y.+EEN2*W>B.ێXPq+P:|WF ͡ppC}s% 8QQ`nxCָs|c_~l >QVEYmO2mB- y\w⃎A'>Jȗw9 O҇s p#V >Qgs}}"?1)%VBNF6nϗ Uv AqsbqQ2A\PzU%v p" Vm䄙1xrpr8jǒ\W$_ ˍ`*aEgwWAF)Vpb֓Wp)_|a\ɦhW~k٠Ńc5TN4ZSЮiٰo~tq 0 8t<t\o}:vl(SH)RNn}|f>-MatJ`q@Z@s#4kqDC_8c9B? AxozUى+(922@C #X3F??" JҰ#~61 Vkc#`E `pnȔ^ Tbf K DT +8E[Yl p4M N}EseGt]h3wwit JEr:](o~獵[jyxm:? A6BL?x*SXb/DZ׶=gX QS.1Qoln :5Zd &R\˅R( 5dܰmY styzoDsRdd0_TW\L[^0F;}]~0Q=lfʍ} 35Tp}ݕP&e*iqQ=75!# G?aWM3EFӮ7ap/&]˭PvI;J+6 ApoVx؟#xXF,::-LdTde1*AmfYl*Zف1*n`-I1IRH1/Ι ? 'S,c2xP>3byS^0ɽ73Y&z{ IátNqVo㛪 G>X^¦SBɚDZx"V$LZr/7+̧VilPqBrB!eSl:"dM@ = f1i7O%&q/ꖻP<*w7R&īq#xr xW3.s=Q78"1Fծ -J 〰׈#/H!i3 C/G$rndn=2#"0,a -KdLghH,/S qpy`Jz=PJJ&F*[63!,b $%H%-@{%aĢt*wJ(~ȇ]K/ n6`T勠@G2?QԯoX:Ebc*`Q(b'#`msuG7(Ũ&WqX-uRh.%sh0ax: (p̋,h(WFۣFu_hqFj;DFqH| .E.aRb/0]b8ے~IZ&29fZL̸eeVG-wP,*.]7AkQ"bUJ[fJꊳ<z&0kPJrDFb `ubt@b⭓)'v#ڏANDv&c ( b@%U[9!ĺAV e1zW0 q]He!e.6fIr>RN'dl3EYbE3t{Z>Vlǹ%߷]bW i)<Ǟ\@P=TagEff\7R@\̩^!ob:+\GscZܺRhMjޮAyd=B8Ffw^=iD2ˀ0KLL(.w:k89~`E\KmcaeJJ`mħ/ K^4YF.z5- cq-"Kf\D]CJ R%=/P%`( U`|OW&Ϳxp<+a0Š;rmj]0ࠃ2ßHjp/~.YW9/& "'DXleٱ\_ݦ>t.h|oh>%aRJ'\>:PC*0?5,FP"DAp+Y<&H u Y bF[0 AEBD$R ` "t1-!g2e b)qx# HRLMF,RpkmW[pB FFeVw kKAXB U!Zs6\4e.Q6FJM%92[+M?#­~lJO/8ظ EL`psQF*ù|NZf ]@SFV1_2 jNb`_\̹Vs*S]wR&@⥍ V6bs3yB^E1͡>aeXj'q|Lq`P (4aP!`lBwjcf JL&1,bTTRhn|q)'vBZcb!FuY …g&=PF=sǩgɛuiJLxǦ&׼ÒVb3H†UĨʜ@f;%o~D~QXTV oJ/c? b#V3 U"\`LJTeKLptQ<04Dz=.5>8ܳ CS/7裵s4(9 ڜ_2 (f5͟Դ# !,M,K& NKRqCyQxԨb5P!@̆)е"+dj)B l~؝ _`+`'6\zB;ɛ(P=9Ed)Gs&DyDEMruRoT ̩P%\ȧ&gLV1ҥ*C{dGʎVKB3S-ã kdlH30fb(BGS6$%!ap^mu(q4劔@F = .qj: ˄DHs0y"2Ml% 츬W_ DmƣĴ|vA-KKn`\\9!Q;qoL) Ps9+As- <)irPfW3YdΏ1KnVr a2cSDKP&`pr~ff轠0YwOĦ%hf72yL$.e7(w-c`nbx>b-`PfIMd*PG%fTi{% 0B1|Ż%/ُgcP}AEn4.ieF*1rtQYREYi39rh ?,h0hCWxBuXʄw#$& 0\cb\a *YU6b4k%H!*޲5N+rDf5 >s. 6O1$r.QEDV\dIUocKHR y#DCbC(6TVx*`PE˞eJ"F0}`;uR%^Ph 1h-M33+o,Sq͓ b߸s# (5(a?jUJ6#SR%B pT(*9Ħ%M_Ɣ)x>ʳR @wA VAfgJĪoAr(%ҕd,HqnTS0t#tEB͂p|]b+$jc"WnbƨR&3+n=fy0$ b,<Dbh2* _Ri(j#[ /_\`-u PX8(@^ b-Jb )3 =!(c3UcK@hM5<̻F`"-h*N҇+^?2Q0%2F!P:6p$B!% ٴf,g(n9*jA }S,H+ta rٰmDIV7ZQ)J*s%"r+ q s*9JUTT-=P_ڇrҥ!%1n9ebx3f% J]PeV5Ԯ?g ' &«L , 5Jm0P[1+ԸBˢSF 6Ec,R`;L 57Sb)"Rjs*USlh&*^\$koKe Bb[0vR..\IJ,ElvUnrݎnv%w6 v`0a   El /AWr7!! fCp e@;FZ~e]' . ;2ƭTz\;!F%7KO0)J[SN5s{a\^C@['bJTN#E |JXF](\Z." %oPBƾ{žK%9?K a2v2*W栜TK 1,h\mP-ȉpnZ>T[n9zk] lҖ9 6"L&|34 HcT fVhwÙGu/ 1k!0 rИ*A^ \Ep6b1(050B,3 0< J3*o?xTt6"~1نd>\)/#Z*ReB+U;N1q5C ye}8)v+Cr16Ը)=Iq[Us `s/!iNф6j0pbqdy%Iʍn{Hp.50p+\KE7(qoq3sqbo{mzT P`NY>TE}n D ;)bT'q9W3E0& lj!ә7rőGg ґEy~"LĐmfؽ|9ZzC\%=,qk\w]a[~vޟZ .s*i*$o J]ס:lS*j.Hrr@=;*l-vN' {#r{g}b"ߔAtr4p[ہs@8Cb .%+әb,$ࣲ) Oi4GǼ6̘,\-&cQ %XWw= *b0 8+T|E)#%ˢ/if-5ۤm_p z\ Qӿ6_b/yQ-a"F{d0s{Z!YeJGU@S!"H+[.EqWpXxI΁tSPHw+>#wTf*(~2> x#J@bW;H1f63t;eʂFWJԯGD(ıoQ9VӈT MBIh -T&DQeU3a; a{›nXBc1fX=ىc'ǘEK (t:dfDH!!JBUQc*ZiHe- A]w,)*v.SzTtJ*"Tz8] @ bT'C#*K~ݠB'iu6K>v.pʆy%%7,6H(F6ᤱc,0&C)A /d0Wr.SP+FcJR样lk%*k,4bX qWb.& V`0Lȅ}QYL` sQ9CDRxLyD Ʈ&a`c*Q]̩l%* #`XG2;D 6Ks7CQ#Q6#@\2b]Nw7b^{(%QqMS|#%튡YE P-Rչ15_ DGUTb* hʖ%ڈjRGGbTEJJ{ĢnTgSڑ- DBzA& a)6bJS[SL\B6,Ef; f D!C16X 31w-g,cq, SR(ьJ[X*QqrΌa"WW N5 k0C*<Ł5\I.UQpugƾ.Vla1*u"8nh)^PU3'bPGtϬ$e X`waD.G0ehnDxjT[-u!s,T}"  r)-P%𫲥)@\h@1h+TA,p@Q U{ "<"%K"aqD2P-TwF16葤hXmtv a.eJ3K/mOi\KXmL!lܨ2r#و 2i(t2.R[NYr%>" 5 HWҍ=ҙeIQrd@ǹa!@qžC=qh a>c*w';bjLťDDE4F3llOIApNeA% \N%\@SSg{KNenAi CHA_1 pC2uQ\* X @XZ,7 h`J]JT*Qi9 1ޜ_rThvavAyY&9JpŬ2QZ Pfyf\$`C2d@9R(T%0ww(TYA+l3/N)h Gea2J_0[>KUb._brd.m#*2AU+0J(200KPdj pp#` 0Y@osv1(2mr-#H#k aQ0l_3%,OSpu޾`#nS2S_F&Y]q?xJgw&F⑴D}*%A"/ad\w7Q( Xe& X y!;RW)a12Dalƴ`-e fF{"hJķR1a\Gk:BxJchzjg/vp&QĵZ{j]üeCa.2RO8Vc*1L%T"XݥG)^0S쉑P*aG8cJʔf[<ËKFf5fak`?[@|gjX a7fM΢`xjK̆AYMCs/!4 Jnd[[԰6w*THԦE܊@rCcPFXj@U1-2, Ė`=#g;g1QX.Uj^`6/Sxu*gV'JܮC(i, *Qnza@Lc BQfP5f!`]EHL#(]Q~(/|eC ̖dϽ>N*}'bd[&́ %q 5%WvP)BV@ZxX"@ cldX2#dS/`ۦf-fa4N4F;?XW5="bJRϊJjS0.h@GLQyI^:g:-rɊX9\=C4E'%6Kn,Vb,e&AD*X)PɕBMr6.R՗n_Hۙ zUHZ@vaKf6Z0np;%fZDA*]IT 9;1"`.ٟJq/ 9 V-ZAK A5  sj%EP PxEyM+D#B9[P{Ai.֍Lje8; n"1]yc景APќ?7Cw ĠտH|4\b<wRv_yuuu#4h2&MJ 9g GHS,#TVws*ٸ9":m H`L0 R%ڌuH*2NDj00@A̱0O䮃e{\T@m6NM[2, IX W*Kfrd뮚&8߃{P4YW9%2xUm%$G,ds\g(btLq"&5< lVC3R53`Y؅MGy (RP G Ƞ\boy谻(+-2Q]X2 r9z /{K%ɛ;d۟ %撬RbssdLM%nbPȇ44K#Vd3,WV ]Imuܮ*X%PDP/?iƆڠqr' *}0eS#0e܋=Ȅh5ZQ*6s 722'+}# 4&>ʬZ lM(edn+](.:9̺Qm܈(s(ni40ccgi;%Qqk=-cm3eX;\C#Un%e^b%~ ` fYWfaM 2ߧS ^6M9D**Xn!eǔr!vqdyX„*;i ]U^ oҿu4avPR5Ds R5QJyǶ2%N HBFf:afUepf1ytJuc}y?^ !Ź詒1aH'pZ]t`16"%w R!G 3Tfh`2BhbJZ$ĹٝЉ$h%+ľ[fX1) `J#=P>5D;#QfSycCŭz b% GSQx6F˻vAh +ƥ5Le2&D b(}c: ;,J~"p."D`2ĆdLƁڸЋ Hb%l h0 x~NIw!qi^US>32xB ʨM- 1aCjnqb`aC 53ѩdmḬ0-&Qnd JP5x9 dD=*o%s5UbU̮sR2Ù]VPC08*Upq*f8y3*4eOMT533w8fptXDY/u!GJ\J33'0]I`#w )h11.F UW( +QDeFĸ\JDJrO @V(.(V.YLGjjX>[l1v){Lho!y {X0@e= G q!4= +*` 1 ` H(^eTJ٘* 10La\WxBԡA=0@ADQ+lCulu+~{̶%lԳ%-Z}=8ƞF`*b%]㞍zB)p^=)4͸WICLWȵamw;qV@pLf=1 9F/rE3 s GƵ3LEm `l*iL%Ab19X!Xfj]ݦ7RJ85<:\M9T0(*|  _ -J#-&F6Ȁcr0Dy#`wL)A.4^l,"x8c,\C;wqMTFUvlJhl\0*[tDz \.]!3v0c&eo]!G)C q+Bĕ m֕.ۄ*^`1+»s)%`]u0eP@h# RasWZd{[ԡ`BpnU7 ޿1/-~bӟNZn&MDq&-%e 7Ai^zDq2gą)[닸PTwGs7\znX@uSeRŘgtJRGL̑!C\AjtbάYwbj?1*%uҸ}1zA\jlQTo1g(vf2̦`'F3fJ-LL E $IM"5"PTf5l)3( r @,ķ6gpAV Әp$,>VZ>8C&`C1 @s66L03#"J2J9NXD3E;H$N.4" =bqF`RzŠT%9Ņ^׏<Ū)S~K`RÄ\Gh[%X˗} Һ&:c[*4b CkPǮ?riPfi:Mn1Ը0mŚq.*_Tg2t1KԎG&I|nd6cMKZLsk8LERB~ 12&8[[>? 8Ae=f{C3<{LR0o{bʥe2YS5c7&e)rSR]K%ܼA%dY,,!-c1_1w@!s38e'h`VAj7]¦ȝa0Yjgʢ)+Q3fD1]P@l#"C Ǣ0-|KWg\ˋ 4yHAcf ms),*g9.&bٕԲfΑ'1cB J[Ȱ6[i~JtPV ) Q.:^e$*[0 /]+8VbلKYP%=z+׷hgr* 8@h{B,?VpAC :@DQ3CFbLVƫX2a5(- PZ$k2ٽ̝;}ҬpD#qn l207NV&(\KDÙe%GzȌU FibEÉ ՑU_ɣp\#a6FƦDbSbkq+[S ̫&rBwd8m~4ͧ1њ3Mp|~xi>fr7If>9fHm;hq? 8M:D + U6O9tnB.WjдpgbQ]1X1Unn`Oq pr[2WS~܄xt=*0=]Ӝq #ŵDF^Sdɛ'8BɉWƈHP.g΄42znBa+,&H\9DAB&lՄ"{hA46!3 (zf扴z43I=@}9197fXq'9Є&vfM(!1AQaq 0?s|a`U_OU0pB9SVk쇱b0>DvA3C, u c{gcïJD5nL}&O6!}'!x=.'iD˭} ({S\18;?  hz_@3 ѳ]aH0kCt؛M͗_:QD|lNs&22!Dr]{b(He ~*v$7~c7}dSrշy,i. ;#+`YD=kjU[,OƟ\v~{ eH4}C~+Lv-Xԝ5 W)e|)5[/WLj /c R8Oy l4_22IAM9l,!&o!/leȚ2Ai[Oo&g\'VLmh,` Ӡh_tɽ})<>x`S'eFli;\ܯsЙ=q?m!&3$G.M3?~+#%巾N4K'6iI+A,U#pF O@y>nϨ>P:fH[ e%{{*2OP& /fq%Ԫ6lAD/!:(3$tk[Dʐ#W ̗{&i G0xl lvs͙ =$dz\$Nc:Zwd;2$kfϤ;vOe{p>fJyxM|6EH<[ Z3q% i `~.I$ܽ^vAg_!z R6Ɂ7?ntBgǢpbǶZNf0n9[nr\نi=ŷ%%N3?f{`Z"|jnm~#-c`/Gpjr{^v,9/O(ȭI/I8`k(>gikKCd@t*a*P MXu`a!6;t6{/`Cv9m=-`)} c'Мn-X\2$>qNڶ`vnDf_%c4owmd94 _ŇBR6^ 6@`/X Lۗ#X~8ҸgԧdV=аXu{gv2Tp}혉"yq_h{?WS$ X3ɹgO%GL)[ 1mr}6!f$šz f*G`钻<6AO~,@|͂9e?$J8er,iׅ y>_sv@X]}y<3ٟSڇG#EijĞgs^ B@CR&ßQV۠S3IJ7 ؂,gi6FGwvnhG?["ݲv'A|dwY3Oýcce,b 7?r2۬E#x2GN2yHeק^ą9WyV=g3 ?"sc~ڭL ; co+a9w~> |0%< +}58͛nARnxLdG$zGbtZ:[E !NCpso͍n|[|KXAg>]pĹ͹n -ƚ;pg~[ewUݖYmmDSu]A~1p:FOwll }䳧9bc;?,F݀św:2zΌ- ܻp>- DXdvY0ue2,~p= -, 4/{tc[e&э.هRCnc.CYᑠdy3bokr"0.6lFGXq؏2_8L )5$rAB .zK0;hGZ~g'?7ND^υ0'U9 l.ߥ~lzyo^ 6=m|N;͐tݹ'|h70e|db\w"K$hF9 zYԟ; _smu,d`wqVdvgϾeǿ[,ŏdmEÄ(0 k:lu0HޅgKs ^ X@D3/suV 8x>B韨:S|,ؖa9=' 3ۂ_sɽ&D*  o#4?_Aq~JEȖrBx JF{h~;,;7&By!?l܆|y_I"22`tNVڿg~_i'*|ݶ d C(zxOP}]\a3*V]7#w9#+L]0u:HrBj>c=2)#O$^~`0 |#>|j"0gL^OK~?m!|+MVAaπX9;|2)=-Ϧ'y?Cl'ZƐ"& h `@O/&Y>q4ޟ$[N:EA| #չt`v^=ؒ31B^|$0lu~ Cy:+ 7ɼ^V|C 0 e9'#n|%ZE{9[}/"F <:/x~b?;̨/ݙ 0.0/P'dO8%F>eX%>'tW^|NC|h8;Ԕ̾ -F^,%6-Hh$_6eyO,3oA-~0pvҹnD@kŶ@_s؜Vvgm3%w$?bAbh0BZʹ<H8bu:RHgw.= :Law l|G`v.k/#ɰVı)g #(qg`tƞ}4L/ێ8?X|X:Y2frOB,|G6"sOX B#@U%a JSpWJ{!5.ۦkоGo-xݏo]|n[ZZ$LHoUj ur&F@Rke'"gdK'[xBy{9 ywgo/`A5I#XmpmH~ I`qmM,8=Cl6.lqo,X8K{#!8Nd.Oٷr/ۃj ۃ:[yǑ<vBE,Ou,A;c4Rdvw K L1&м%`W _aL0d~/ԶM6z5]9lQ9{}CjM;=&̹@v8}dO~-_7Ai* j~ܾlVhSPmeuidmZd_f}z|IUėhv,? {Y$@{2Y^OlBk!/ ? YwFp v].(G&yί%~a~)`>EH .{edO{td4:PH';l~ӶX$a |OpC y#gub[ ͺ)| |He9wPxXgŎ$*Ō e Nkꊙ{B䢧یl`v 7'ecapE@[8#X0$A J}r ^kE>7+(o5i1~5 -5gᓔyxOӒ[ ,+gEczn}6{M6Տe9A{fNy# η:|5!y`={]`^_:od.p/d,Y{wwqy+h%X}ر= z$?ؓ6@?'A p"=ъˉ@":?*~!7l =ܤޤgw#=E{`I =LRJzç}JV| yN i fdΏ+ &s7,Xly; $[Du9a~,Tٰe{8Q ˶PpJfo滖;)|WaxIgQ=-8#X ;1]MCx@y7wLPH3u~/i^K\`hlc6~zplU}~& DVϬ h&C-->g~w: o1˚Y:fN|6e_q`,2#>g~/C `(0ïbcxp8~F~x,y0R|& _3/?r3 2\2 q,<d_P{uY 7m'{Kwۇ>ԦiZ3UPSxo6 e;$yG381ہ>tlI[aϣ|m0r[&e=2H<8OjmIK@bP\9N,4cG8l7WLoL3cg~OG\m-Ņ:1fA% ^KbN<s,h=l==%Jv;dg4VvN\|ɚm'^_b_d~T'$lG\`e:'MNZvڢ~Riᑢ呖]$\b[ i,5%M\'n80qHCnl/ ^.-ьv|L(v}EşpnOh5v~İ?ӽC Ct~!+!ޡst As98;b8aòb[~az.\؃![]@u Zα 63L .;ĒEȾ{Ӭmd-. 65t;" d/I -gNOٓ)07nB3Ζ@w20 ̔L!'B$G߲ H+N-ܵP,c߄fo^oG󓣰dIP˂ {x-ؒzhc9M԰cg/+\q&_ vS I/8u%[9zCv vt3فoS'@k nBmm菪 w>+P?o!~=_wtp}:>a?^r -n^,p-6o'OpG#{ gWQjK -^u;WL|A@PyE4?a br`[]K{rgՂ6 f.j^,0gPD |H6>޷GȵmYMlX2h3w)I?8%iHC휼#&"_;~d_ o#{$ouO#!sS l#$`Y ix6Έyːw3"Al M_0i-X䓟ܭG4ɾB3W'y_mz#h7/؍zt-ٶ^G?OvAGs|V;c >b%&II7W,I .q}k st,!X!|8c4Sp0&O!"m1;%BN / 'eDSJ} QĄ6^['DFeoE(0C=Zq-%=bR oU0$$8\,$Ƭa]&tyS;l{a_8|~ ]O*ьۺ{)T m2 s\{4ؽVHǶݟ%E fQr?P;NسI "fDgefG la;r Ia;|l>$a`dy66aio(<=@0E^D<_&7^"۴,e VeE4fL+m"|#n^ڔņ͕0\վe[ R|l1A}˶"<"0q&NvOxFnod4YVh;|~'./'SX͑[Ao\Sl??-7ll2?蟇Kq;a2E{6 ֯hO$'n-zez1`G !o T jxX62`X0⁁_fXm m{`=L9/0 O^@l7_ _㥤6`Ówݛ+39J;"^ڐ5W @|s'vaE7O8u|]Zpu{=e~5 77|-UdEplcApN}N'D;'4cѸ#id؎D@D0ͪ"u<gH_~#.7S/;W,P Ognolm}vX7l6,7lnw7}~ ⊴BUveGH0ݒJ0FFP#p6勋wS:^G[l^c[6XrzȎ[;n_-rYkng$ig ֟.6r}܌\!ucٗ^GjéSN#Żqg 3lin܉dGgGCh-ahoV[[rmVWRCqH#Y  5Hy@ƾ6ö|6a`͔R6 sm]$bk<=nl1G1pg``'-m.NKnK& j ̌fopIVg3!Wy5D׻,:PKܘ߉(G |z`c5_j~><،خ|\g{^ى hIi {$$z46E!ulʜ8efP{g7ۋÖ7[o'!3rm_1Eh,)xaía0vۿ t^v6 { \50u=a 3rvŠ"' #5t#dݴc{\J'm{8/"pr.$MF漴[lSIב;dG0'a#O.'mڃW(3$A& ~az%XK R0e8B< .6]l^%,#W6pP.roe>k!{%>Rʟ >~_?06 K7uhLcGeWt `V .W^h-K~lO?!.œS/?r3ϙho]ϟ3?6%q$;tuR/2GA//>!aHOJ82|6yx[|qƒ#_/Ȋߤ&R\;.Z43Ģ2=MOvN!ccz9nɊ60B6G 9Q6;WUyqg'L5Smϒtv>A3KA^R 徲WzɎl0Г?vt{ ݏ4#̏~1c d!.Yݭqpߘg^Y3ih~f8C6p9| a_Dqd]oHcKW/? ,~pصbn3Or?O'V r2꽟-<e5w3hv-`!b±3"g@?WGMe۝= 䧰6$9y ZB( @:;:[3=[zlZJ .Eht+%ldL)F=s$s}h{I H9 N呥&i:%d RyĘF>ďK!!#fc[:avQ[^ .}W}َDnC!4/Kc a@/`䝱6|e| <5drbx?.| Do .ٮ^dzP. YFsEй]{נd|* 5'A۠{ oݎ٧"#2 %!'&hol #5J##'se<1(t#b]AYG?Gس~mEȟ&m~#c|y{~v˓#@ Wqk9G`9ܺ $^9lՇ=\G۠է.҂p7ȘpIlC%bԤSO ٯxOE۷ž>d:qNzg2&w$/no6 }\4)ـe:瓅D# K vp bM.+AH\j<`ˣ`bA" qD  D v]ޤg^Ι1Ysa$Iorp;告AaDzkkMYCI[{y'|!\#ߋ?p~K^N2O %2fGpN}N`Ǘ#%>[^42_tO͎>?W_H K"X E`{vYn/۩!&:ᑾ[(}K6$p!}Yr CJq 1>?p<2{.3jwuɓ@" Z9$(~ N' e=#S'?PX&.@^ CVOG `6?5ɛcjv <Ѐ.3mJ0W}Cs#?+GW~/!?U9!oԎ %v,I}/uYKGw~o>;t ?[;Ol?VvZ>[BoŲs{U#4ܖ=1`K,$= `1| |XPyiz -I L"/HP~L׳`aE?gg^?;^ "ݷ#6MoCmqB{ fg#?EiՆ# EMa>K/a"CUxϷ8]KSR ؂Ybʛ& X" @v5H%H/&<ωIE.tg^O,'V CY|-;q/$ >c_#bϝ, BLݓ{ĘCaX垢|?8H@"]?{3Bd'&O^X+17oR.uZLc>.=$c{.~>wǖ$3ȽقLxK?Q(nXy7<&+8̻LMܿD?00'-Е>e/e弶*1Qϐ:pnQψ:JϐQg3!NI兗ḧJ ˄Sa?vc-D_BF$o~/HE=Hmv8>s$8jKnEA?I;yoO3lCy#iy3D+ y}g 68ϋ;|O?q u_|_adx?FD0HlC%Xd:L_Fڢ9My<,쇉N$ْDn9vݎf>ƿ3q>nMɝͿ {䜲ď2Ļ,7=7tΒ;#cceLqP.b[c jWmBt,"dr=F!Eĭ1|d0 Iq;Q5`nɷY7%Kz= ZPq5B[G1r{  rs&OSLgQ)_`zM-j1D5o =8 ,`y3NIuMf1`l;?܉zGC 83 x  8vӫ?(?R.i?R| =78Z(w}Һ "rٷ1[KmeBĴ 2yAf7)2KFluC|?ͯ?Gէԗ@?ÿK|~N{y|~??uO>)rǠRZt?~!:xOgO' v՟w?YBwwG/&~)2\ܜ^w_(wbu͚їau]c~ɐr;#.OXn` \9lrB@1 >QbS|7),]2f$7B(\_ZKN][p&|]V%;ѷ`&]N%B $@l3s*>C?s}K;2G##?HKIEsC<=lȨ<4<<8{&6z1m#1!bI9kɎ:6/~!,I14[CxY Wh s_yK#q}~ےqxkM\D%-ş3%nNB V5O,ILOgd Rblω~3C@M A] 33#s WRX`2:31ߖ.W~~cCl,>o?xsOqJ2qCu6M:;y/Gp=n' Qj?{ oOxk@4/_蒝7qffob{'!1AQaq ?bObS'7~#T[Rd8H%c۪Xч2R8 [0~U,D`ůpk8R4}ʩK@w TY CvGnmy-?2 cjqEZDKTYIj@,4} 2{iL+%`-DAf.T uR[\JUۼ5U1PVj8[/1Ԋ&[~&tčDzwn3.+he7 a KBA[E=6 J oF3V)uT~RXSZ@TB RnݱW3ycsU@j`Vy mN;G }}FX.#=E'p ɡ٭:ݰ3 Z*mP+놟0 cw pvY4@KJgXV}7 iɅ/ Aqp NhgSH%1;_cL}en u U`0ڧlj}-lAm8qH>ȾSGw?m@YjCo ?}WV@ ϐ0zuB`FZ5$B[ 7~S.+1.<7 }ȕ_0@)LyR8 (9F ~ ͵Gb!Eq)gzFrn2D=v$T>@ P_1腨F1)Qݳ`=4Pfse'ڊc*-R|/z\Gq Pi2E0 !j$v ln&#zֲ.\_5*NOaecZhw|ĵ̐Q?F(2p3(ښ`3%AwK-B1 qJ9FˇsH;:Tմ`b@, #YJæʙPGs97 ,w/!0uqʌ J<@<{ہ&POv;{B)IC/+emGH]{^.d>#e* Os3GU}?1Bȇ6V>^ *AP]X2hW͡.jgot8e5^u 4\uGM>aWFc]ID"\FT z )q8qwD;L+CܢO#U&/ m*:lFѨlTqJ sdpt #@)`sQh5| 0%8Gs!<"д7C(jSϒd4kܪ/ 8ת!"eK bapJ2Fұ "a0wQ8R_&:BR~` dVAT7"=aC}W X (Ҹvo\2ZSƓXB _pddϨ8W'OR ʿ1 \"MSY+|um+}GBuR1۪>b>gicjk(*9S(bぞC}Cl2p/,"CF`D,A =N s1@Dಮ"PlBQM.aH%f]zC+pbLk:Y}Niр u֧orܺ 6SyEH1c.gRasq,K*ˆ-@7DƸQ[AHSHa˻lxXBeR/Q3H(¬Exo mSi$<@C+Nu 3ɩQ jJdcrbRr VZOgq K-L(ݙ~LpC*Ԡ^cJ*kB̵E!^PBX=aKo'(a_]5<\~ 3 ne,fe,X<R S: 1OگQҞ^ >Ӗ\3j~Y#'!UxV$ k?lapCgȂ\"ɗBU`ʤs'>_-]v]!K|0` P+vWN Y+&&/JGh}H s Dˬ ^kļ\v>Xa{ m1m9xص0M~@'9CjsZ~vJVP8^M o,!u^L*+@3[-%XOMa8rXfʆ+EW d4I3rֆ t/Us:_%ݯ1;;X$%i@n?55Jkj@ Լu jap4[q=S^ ênUbK|;V1Xtj"RR =fT<3U )Xu ߇/kʍgW̑>@n<~\ݭK\r5hBK8b Y3XKm־E>:D.pyL!r8`[/˶ !fR1_M^eEKJfmg<&3)Yp+31%6Š kS4\M$P(s #osLq0R&n +.Ptn,74g[q:Gphe3w5 4FfQZhEJ,L"j,rb vZ<YƋJ͔#4~"lFE o],-lBy,[ dawe% R: SJL߹ob̛Ece6>3}!&RG xDf _MCL|k#Uk.֡E|7"e3M3z9dyTnN|Y~e13&0ePiK]oR]*V!-~ mKZL7pl'"C3A_.+&nxiF\Ea[Ép7u=/Y`|=1f&l x{oQXIS cBK`4So4! f2 pψP % MO2! F`oxQh2  2y"P2ʒS #<RܥI+;~b+fr<Z| h RY &kR6g5?0Zc\qڥvg0_RL jyqC Ph kبpx+# VJGtF,1/AUULڠ(.@`Js\arZWEx1}5.%NX CU.ú'p o)0HnW&(\iV*%h(r`J/QС*0mV?~ຉ1|6BZST9y3tTX߉AW&>KCu@!E6g\͜kuaְ]F;@Y1W7~q븂*q 03FjXPj+|཯fWˡ|D4ȗ_>~E@Ф]k{Z pl0usp kU.°l_)_GEM.ER8}Deۙ.Ȕ ]}_"d)@5Z(lZr1v0 c¦o3eRɂiFɒ"SӘdfy@3ܡCb8!@W42 YY͒ iX a#\\GJfṢqS@08J,anJ2\ 'boW1E@z<9qu9BfNUGLoΓ\o;l xc^n6FC]"]nWF\-S*LRxw xnBҥ4QVq[Bƿ*15VCXvwS-Fj(9Q.2*qir۔*aɔ_>0BMz# !_0p)\fGyUX$+/o;2GVR(`n<+qhIg5^q >T/%Nh-f0_A;VikJ;\35(QSt.ecԷmFĠ.ĿQqE'U|-gr,5~Z"V{ b [Q p.Yj[> ,R1%8z5s)*&WYLU-m _a//KmLG*.eGJ؈t4}l6fcw>遼hƅEߙZA9c6*Akw7K!iD{+L0hv̑g2$6sgNnRu5Qn#!ee|TL}430[jpz P4nFY.^5̡.a`1:W蛖_50JԦnS$ wmӏ4.VhRz!P6ˢ(ګ3NSmI)h)H<2SԪf+ %e^)F;I>Ǯ3V غX0\sdV8͕*lË[ 4To& ¹RQg.lY~DI/ഫSĸr5rƵysZ(n  Hm3ueyCZ02*U^g|><̞%Bެf % 7PYGC Zlt phqrASw9 1 Zcb5nX8HS KJǀk]໅J=:3W~"e~Yt"j!qs,Mf8^Nb&YGfD-.tbo@3[i6 lRdj-*z^z߹_MJKĶ<ձ(SR 6u]Uƥ3ܫj -b&'aRD/زYǰ.1V8f؃!Rl0JTVk9%1Q.+vH؁$w@~H6ZF\J-[Q(.A 1@])A1r}bV(O/X"fw\OFͭ\оwĜۙF^Q S`V~"uJ@sPW'Zo3YC4 d\3fߘL3o`W@ Z%T6 E8iPQ,hr|T4@j"wA!xkTPolBJ A]AcM6SCm8QSbEr_@AXSvI .UpmW8KQ!6̵,Jk )0l0B*1ILv+h2QWkWzT.aI,eB*Q e+Z&c0QOاXp ?0DbÒ_QTv cؙ0ECep6?d TF [1F@T8qLJr0F%,ЊNaGԳ`U@Y 1 t)W0//,լPG1b̓u 0>H4n>@'>_:y&䆈V.dZ*jڮULr(8leY(hα^QrsQLԋ勌-rl2P^%eH3pt 졃5Hkglb+b {şc6cVG`#UPUz-M@ހn-rd_ĨqPЄ@ט*M jbjiUh]L1.@R&&XGS3q_{6MjsRm'hWI=̲hA%xqPK.y&dE`rMcbT52^7/{$7ya\,gd2kA,>elg/!RۈXk8&_$.=sK5NexW20*Hn!M9fR_ d;)I mMz%)o Kv!?nd 6`5 %mrL]7 Zvh7x哲v2`Ĉ7F{cMgYCશ&7 #Ya5E,nGqD4&w}SeE+vp!9f5pd6]ˮa -~Ax רS\0"J1IzzͶ]LT93L#tJ8r*+%Ab2MHN6 fh7 t V3"+m2-*s3cdf)Q[(?VϦt!yL*9޿ܨ_0K57uU H}cz"f|wMOXw}{ jYELED[_G\r)@mh p :Rj}/bsQ%3A$ĕWc]EM!O1OBbFpF)a;:7)g'1taD\)-I9-F `ԬN\AgknM)- :pǩ\zAF;#g !R^FYjMԩr.U~`׷\׋p촂c"*UZRtjoI*bZ㞜9& Ue}.)a]AkU]nWF x}ňiRKJ\Tt QmP/^HJN !k4 4A{}`&0ѪBY24n-gv ?M@%AԧMfs#/x)*64RtRb!?cA \CPfp^#ISg#ŎJwR\ 42j¡~e%ʚUZG AÉ]@z"V#,7?!KFՐAd|WE}[FnP@v '2s@,U4Zc5$%nZ,p殦-"qKɠY _U*1 *^ht)d6H@_k 0rߚ(cN Sd1>m ʿ4D ()}^aZPms2Mf(5&I `w(]6-r BʢVt۲.ùp`L׉NgʚԻ[8,9-ToCeZPwНX6^о=@$+ʷ+YSWJYP<7!p8m^%}a 0x&+ !|_Ht:EC@D{ 0-٠y90EA+17o50lbfZ  y#6}pum.԰ ٷ .1ݠ >`.%.? bXDtlo*0, LV"Ķ8R!ׅ9RJ=:z`y!( u *H> .H !VQ q `ۘ!uW[ qVbR Tݯ2ŴP :]XZ <ũr/Z{WcS8,\C[Qv_#ngub;!͏D \Xeb2BYpXE*0d(0kAc|9#uj节2bW ;U׆ϨkEt(aNhjys0$2y* AcR*K](AfF%(,a9q3F-[1@ۤ*%N 1ӧJpX0mn- ]Fl,l-E9 =ſ V1RV\pCD ѐ@y:c #䂦z̚ܩQ([nƛԧ _Y'_k~mXR~k5Լe=pxfRvŸ镗nog! #(m6öb]K.MF\n"eAy*`27vp`D(^b 2"KFp} LKmHvILK] VPM&aBᅉ)2%縦9配t.o)Q]""fc=LXAqL†:fzSGP؅wV+=Daj!~ Q|CCm qb;. Xm1eQP.Ҿp!i*}”g:-wRiUQ{ޑ~j*AYS/i/@Gx`K"uaEma1]|dʇjĩ[i12p@[ymXmCl +,Lֈ@n2˓xVŨ.dIP984kg 2{e)m{Dj&]R]!6IJE+%,#3>OT .Y vOUC{ B38~v&'AV`#B۰p:>VkWQ`­ U︚Ea4rMr]p^q.gQYtS=@z;zjWQw0(h G9EY[hO puk.MKX \2ݪطv r7zpPh;j 9SS\r@QsZr? ,:t0v]?5-T2'a*\ {%"Ct>z$&}c{ טsͫ i^#-/惇E`\a`U^a6ZΣAel0*%5%y#.ym ηu P.Pbj5UZ}(yGd;)q,륅aJ:;c^M "R2PXR HMk,rx'CKIF4D  {DUfV @pg&o"*7,y%.eMq?[ TR}Zn.R8Hu z\zFə8X \HdtÐ4CJydn7a!N/ z7 P<¶Wr:3vsKZyGt]2R "(-KǀY fu2Uru[cJ غT.E `׈GؖQV_k :fqdRW }9ݜ<ܵaQeh͔@)^\DEynoDtLQqqħ?sTfFngp=&GבrVSXS<)YuPDNB>\aBCb=uYS@/,_qNa f1jD4KˁcS]̫З)`g/dRŐ)n8PP |[VEx *yJeTAI041:xBזs鬀[2]#!oaD 3jĚ΋xՓͷ$﯉^@CQE.4Z/-׿&]D_$r0@8@dtD| w aSVEm!~ 2lkj*Y"\,$1(?QWO,i ȅ@8\mu M]G1`nr. Jn0SB켆\\ * @p⣬U~N%̇%)qɪ!5.jyj<FaEJ0+HvS3N 6c:7-)Vd[KR]#mיa34M%]1mU,Xzڣ*ymdNk$W=X7w/W$+?aoiӔ2* k7WϚkS'09q֗d-2=5G8s|˼Tƚ3(VjSz2/:tb]}IaL ro52[%$H[|$jTJ16;k< zO5f VlK -{ s11y-.!7x#RKٛa_w.".L$Pضm J5uYc@FBV6V5+aT2QYsJqk׍yBefr Nu++ma\KE!)Y,Kmc)p!R7)ҽb!Dee>({j >$QU-W7,3icS JhNR,q<]X, m~CU&BLVq{JIAS}.=C? .}8 `b;]qwYf SUmQA,2B+φ^8~LpkcfMRb*x;9*{=o`4VV1OrAF"12g IcK 2ݰ#ϐe@3XopqE},Bq3z4G/H|,5x FK/5Bx3*J] 8yb<eUz v`yjp햁Υ/gͯ[=0N#^ L\US+Hfvש>E~}ɖA5r b=/;D{n2ShmnjW=J>k\v)"pzܻ g@1Pɂ:)M[ ʻl1&e@XN1-Xu<%-T4"]PX/0*+_xvXz;`f0XEz&`}N3y8; xf@=4p b"uq CRT/ *A,V<RSݺ#<"<˅ix-5 0Ƴj̞NȟkҭCU2; -d/,xb5~#JQ^Ģ\YX-"_p.f>j0gpp@JielUa~ k֍L<|!Wvs&3}Q͛&n ehp/0 /h 6S`+!D{o2 C7y'ٝ'n67 ݙLAg=|X"dt@=AwFFnxJ~ܼ!*`P#^ODAT-hWze7Z2胕m\/w/0VW*f^*l fU; )X\1.v2[u%4)4eOhp+~3]JM%YTZPgbPdV5ydiMŠˮ¡,qÇDj!m)C :?p]dc/V >mu҉kJ.Fz io̶mTB*j%'iK x8{hXO3Զs&#]Q!BR1I(6uDJ0Dd|, B+ y8~+BMn*<L]MskxT+P M .C[P- a>&@ ᣻NtQw, T&v^D<0@S;* =2jgn[0NJ{bTZۘT-A 9`5qʲTE;njD2m#` Fd#t9|\%l 3]X[%!6rU#ffa7G 3<럨)fTf.MKTARF99wE}tiw6ʟyc`Uɹq_p\b),;T-n1Tʀh隣v>9\z\,|2P)(`kSPz@^Y)*כ ~\'e1ઈUU?3'>PBfrW*bZ@?]G3B*j `7VfeAvL5LvA,| ;oK4 @^`q3;[Zٛ+(jqn힜,PR-XQHjvulG8;%ǚ̞u 0/i7,4TèͨkYh*VàfY+U ADu|fbV+^U Le& CAL^X}M-~!)wi/XDt%a2zy5yn2Tuo2vFl}FEЈ(YK+6]뎳쭲tX@aJU#xnbV<-⸔`ZPW6_,VriU03%E38.E60πaL~Uavmˆw0]FYh4af Г/ĸnQר%WAH?Dܮa8O׹Ѿ-[Qɞ:aA3*ؑ;+0=Lh$wv|/3>Ȓ##3 )%_ Ϫa깚{\D®(,9KWi Dh^QwqؠYi8F ɢe1רr[@E2> 6Ag`ˣ-duH\mVz%il|R`PԷ xr_)s d4ykzz/W3#Ȩ+5P1f,@SQAR%˙Vd(_3[ k"rK1I:d"(@UM\@ 10QPHUPQ9y LYa_.DÈ8E DU5eH0BC6_Q c-MBtUh[B/fחl!HoW͋Z>)T?' ܂]p?$F K:ɺoh |FmKy̵%2gY8^uE_)f "Aͩ`r3 mKߊ:98lZ3\Mz0va#e Y߃9f!Bn&l$T_M˧4Wkl!̰W—J5LK' ŷoMb/W&pV22^+[CNqOr<$ZI ;q*#2TmwfS} ǩC|}2=u EpEؾ,i/B\b|1x6f S-.J#^/LQ;£u`otadF"ݚ>)*M@K蠬ˠ&t%R-R ܠVbٕpCES(".l%m(y!4` Q*4.) 2lѥpKzlfq Jߓa[+tGZ,TUK (*\}Rf4k/꩞яiAHYL/^q@DNK\/28f%TPB ؞W zز/Bt%p=6+!xψ41w' >% t1sy&m\v2_Pq?.XC-*8T򧘊hm,0hEX\myB0fI%E6WI[N&PņWrfO52pR؈NeAGrE C`D%]NG1,؆+N  g,`;2B\y M6$}"%`\0 [7kS1O*[K;`T^OܹiC 4>q!6tm`Jfd QbQms+ ^zp`-d(E7U0i3|pk麗UX^+mCJ5NSjrcλvV.r Z'lbIő#UOx@iNKKÌFwh[WBե?V:N\(RVLɤ?$(j< \`CN&8I7B8@6 MF:ckEŠT{{#j1HJRBrnWܙ"QpaYQA.?,Ŝ6=B D iUS-ȝzBie00yXM1m>TX,, hEMbϺ:J[  Gf]6sZSyͩ49*uFs ak1e., .%Ua^\DAĹm ˦Ya;;l?Չa ^w喛%x.ђfR#| CUdA1ϸޘ6fܪ5l6ٯQb|ty*Z,R h=$ Chwُ,ǿs]׸ l`i%kKG&"P$0U,7 f`ĵM23 40u:I.ljJ1ZL*]rU%SMaV@T0*|\GEZ-L219̙b(2 K';VE Os,7aޯlЊe;J֥=| jO0 .Rr/*4#.X)*٫Dzc* leM ]d*}-"uN QSI+%^~Qhfw\ `2'eu:(Xu47 81H$%ȑ<bU4 ˌf:r\E? M 7=ġ^"uᩉNEhrA.2ĠpĘNUSX&Ie)Bق"#L8XP*ILD`1HEcQ"`!Ύֵ*_24A׶1:Դ U𻕆&s|"E(D}YxnJ\.$O%2P@~,'+W Y"* ,{jJ^%l6 H`;) \25/Vm<&bģ2*#FsQqQ#Kqń4Ib%JrGEAYY,1UYoiY È%ӑUFuxFsR`9Ới12)qLwI*G@XZ8;u??Vpܬ^!i.|wV1^Fa$ hW_1L @'dJڋuK3\񘗻]ԺRRTJ-|{0MP~8|J@(¡ot! P|^k-Xg8}t NwC -Zw肚:>#3 wWq\kmp/B ac Y'KێD|KY%Tl a =s2X23Բ, q&0 G^F $Cez88YHHL: Ķ]YW Jzs1p2@Qf)P]Q,Q af-S54*xV}֎z "0wS4Fn 3L` Pr~t*t}+Ab#>ş2{1R> VE`hGNT]A4M;ʂܕxrUmB>s}BRoy j"A s5+pr0ưLv*tQ_!Ljϑ_ԼfJZp ٛ8E)RiN:ѝAҵb*_6TgxL%l|&UhT\4X'4c򚊈@0 /U 2'iN Y[nGS 1(%vQyP U4;cҢQȝ0F%)5Ҋ^LNYBH਷KW Y/?r.'BEދ\f ^^V]qMg?Ƞv2(4Ô"8lNV6}nՓ!B (. ^|7_j Jx*Pqw12bTo(rABbNYJu(%4Em=W:ATsLmZ՜Ľ9gBֈĄ'Y{E%6 S+TEl%n9r3C^0P2fbܻ$%8 QU1q)^څpqlPyֻjUI-Ǩ)N`r\` R%yn5"cf*(u8D 0lX&x0BV~!Z-a$L6Q-nn~b@]7M܌L_& @հh K"8A!rKxqV{JOw储2Y wdJODjUn&nZ]`i#rU$eE[ v^IL_HɅ"q8tʜpN<›KCn.DP80܄ *< P;ڊ7FboT@d G(U8@~%7Η,FPp_E2juP#1E;,Dq,j(EPusSY'}"bMA^ʫ,8@-ߥ!(1˟x1O5G~pK}CXV凫5iwx|T ,;MŮ$`z ΠVf:(jh7V\L*`l\pkE()R@'cª[t(Pķ[*b #`,O؅DE0(m6s8\C?)E3QW4Lכ-Ix.`'5ςd^PS=1A>N3tH x_/;85CmB)FŇyRXB3"aPf_@~МR%aƑ+ih>뛦 Na8G5,=:-1tw#DZ-掗L~ɭ52?f<+qw3Իs)?3>XӆQA8kZBEV{I~#JѦ]~tC?B䮠qxQLt_"t 1- ǩ R'@pw xT) P aoUa@$oE[Dyp\]ؗ𔵧`e[[ctN6ʸ"t9&aTRe>n%vƇ$I6eX! 5a)n\%xTEQd}͎lu0̢ee( xvϕ$Zr ,0z͆I~5iU\F7u|Dh` jAZUZTWh%i ^1`hcbS}Ui12rYUrpEfyg52sopPkP7mpa%k ^xZDneKi$n6.ǫ627b(ɗpeE.7s6BE\˽礴<)\XK0큃Gʩi˗D>ګup.@,ZUUJ䂵0S0y}\9NLxD-9Vlݯ v?w+ZoEUf8:^c[a="r@0 q@wls̡$tf } 5BctE8/o䕸s J2XrB>o 9"T5gJ\p *Tflm8.E_XBհaSԠq_Xp8gAyHPUlr(P #Xރ%l 3 ݅T^b q{X cm[kAC5YbLfg4x܅LC=wFEwCJ( K VIܸYeFg 5^`N&ѫP'J\Frj(1M9=BVn>y 5+RU,nfVTQ% Bjrw(ˮ'O`3傠hWc r6-U^` :qLg xT<52#ouUs7E@y`Z̢ 8kf*cUB nBt4T>hXp+9>ٟ eopGn`Knl?!ZB`^(Z0Jflfr?t Ĭ|34GxԱ%*LY:2yQ`fY(U 0,<5Bc԰bV)ky!-%\QGB-=7Z.˓& :#lG p3 Mƃ繩c֛\jGGȨZlf18ӓ`R*w5A{nu^WԩlK^\sQ`-܁!Y,0+9PNMWMo=DStpł˥FUX[ pW:V,,Q.Ms#be|H` xi'M :(!׸0-Aan6ViAoc3z!9,8b0_F5Pѳ&jvv)Eي{n0 MʱT1kw:X7˲2TmpZI”ju `b `L,%["aӲ.%P0JXrJV/yIg!.p=&X K‘xCzD5*,{⺗1 qס-1>~ ˖Z@grأyVzF<⻸bCH^,7̢SpM7JcAbNa}jS[ө*UsFp@Rk}뙙XQ1 2bԛ[NYAAX1핱.DS5Rd C^~j1QX(츇UE3hDRܦz4]B@ CtyXN#ġ;sCȷ8%!ry>"ψǠCg 񸟕b/.9H gp2)[a Gdh.eqB(IHqcrUb*0\k41ҋQ/㋡*eaZeiCdceޖ|Lp1}b'Iޚ\B{ f *bbq|ZU|;_R‚]]ˆ$[|LR5!, ]?SR ]xhUR2W! &<듹zqjTY&KhO~^$n0>UK2UBʢj3-!岬p巪v2ī q,uL:"pj('q#P(\-OW&22c¿@e\AAy׹DR]5cL^HvF(;s|2=(FOBX֣S7("f,NQ\J8Br*ǮRfZ M k@.栥6h먶%qP8ٹe:H-5EQmwqvM ԪS< jpU~s :X XM媏>&Q[.Pu̬EP<Q?Bi 0x1 R]'(%<*o)wdr[bQR\N*j8N_`"™d$?2K_15ԍ%oywNAOE])6MmG,٦sD %KIW"= Y>x͐AUTa-wDgs{w(`M~Gc &eUDpZb-UTvJ:](Kql Sj2~c!f_2_[{yť1R4*W9YJ ck3 ABƝ-JX j+nBhЂV8f KP>@.;rV/5)7-jn<][&N).le@۠l_A]UUI4_HqşP()reh 5/ gxjYӦ)1PeY6%@dՄ\BZ1K oKAQ<c8,-:s0 <&KƭÖ/qD@pk%uwcgF^`})7^29CQv nA@i,> GboK;\ t78~bވTb,Е1~`` ^!܇ WRX}1_J )cW؊i! B%e~\cGIBk()a"_`ti R"uIn6Hn$@5GP$ՐF1y`**h# EZ.Y*N^+an9``A=l^v!eYSDF_5XD>8j )[k{63%&tWpJN`ŵjcXlw1]ݒ Xxۅ d(jʥJ43͜68>PZcb膷h_ w ːU"-a-ϟ(2;p=._0&G2R*л;EBе")-%8c%wco@]`D4}HʳzdnA@$uǙJKAq`Ѷo?A=K+bQVĺT-xJ{')aSO=b2aTsw0v˴QSL?BklYDsC {.Tz73CnP8#V#RW[Y/|pƹ"_cg<Wl±GKg!HK:56Cp HX3!pb *X1m-Ap5\A :ޅ'dV(SFk@hwɼ 񻓹_{Ŀ-6yQq,h%s@ީPJ6oJ]u(*XB 2lCuĴX5[yQDu'?E&a u_1UX`T)@h 1sEWS2ѳn1ZV+c p)S|f EZPXC^pRXg(bzѨ&er6x_YTko+YEme;ZdrY ϸ/c-UuQ!/*|5,3ޅHqٵ5`F*Ef-^J*Ec$," Ktp1k mYr0Pnn-%~`%- cBq 03YB )k7<#| &jMf[ c?20?.F͒C˙t!0 EAp+" R9S[؞2Q@D1)=,o9!j ycyAUX*y~]XyE=@yu1 xi?!ɋqgCJsn(M?t+s=fr9NAAԽ%Xf wJ:D"D%z{JοļhpK4EAҍ?ۧ+G!B3˞0\XI̶K!!젍̎Ճ) c+?P,j߂+<"m& LeS^>RnUķ0c|F6qP1 "tl\fСS<]n,aSo1,hJZ=BQ=B>noDzP{Qtl"ԡS`xr^r!]7\hp^pi8sɘCG߈`#+|?![[Yfe^p9 HIT0p#H/ƛuG](l+ł1xD-L M"IYQȰl3@*1~&SoPo xYN.qT?aOUOL0Br,5M_jUIU@Kx-6̖h[ZKVڕ/ T@C)MVrjZPyÈ-+ WŒmyU!yXc|H/#d ]\֑7ȺF@/YU kf}rAF|eH2c.eM~&xG8Ϩq*`mQ 0"E wR*Q֊]!qĠOx /AF8`+rq<.Sfۮ_pE.;},aP|w'hȗ~ͱUlp`\$GTT%U+P@.()^١;cOQR+kWnQuf>@p~9)bSf(/0`oe+z .]A- C*t I u)](wGs ƭ =]K]iG(smF+ȅ~˘Q6 _NgT:7uv^mS}rM~m~1(x7i<R09 AJIx$bXo0ܬ֓5nU-9_H 5D +KgpLP=k,tT>Mׂ^0>S!Lne+)iIl1RSvP I~<51f杰Eؒs{r#gGjg8AWЅ˚>`;0NT#?u2qCTA2 2Tj2QVs p߈7C xѿ]!|,,waPUYZD ]Y%/u,*khNG (DeFUrR X'0uNAG NdD tˬ"Y7/e{ T[EL@f礝/1{ًo+~ Y,+ imzN<԰) U]g9ci%kw58tuPkpo (&1)} ?ˋbe'v>EGpp[{orCa(b)^kff),=2_PmLmflAa_p.!M8)jNpMKwRM5[Hm*8B֌A8V@ ^&Xh`TTEwq_b`2(*mp. =ʟt}`( ɤ5 h&V+0kBPLUA[mGqŚ&ցhl[lk F2Z\uc"2`*2`gKN:ASL, ẂYTj I _8|27TJQ-bQ+|vʢGAPx#A_9@Y|%0c?vbQe[Ԡy9 +Z!#6hqgEoX6U%Y]K)OÏԧJ8*4`T)J)p\61j K1pJ?|6R%aUp_&{Cc;D-5eL]ˡ@V$-*Tq5T5Sv9a0b$֯{"? q +A F32@D-/PdW#:LТpQn"tTEJpkvS@lD!>le []TKZW CYAJ^ěC2TWn= zQ:{m*^vO~ҩFς%lT:+ P UʻE1aOZ\3E]&}7kM VqLz\RTK)n!%y{޽J'3~g0_B[U{}O O >wK10D剗PVUܲ!#^%No6%k䈯#8ZS(\ 'U1ؤ)QWxH,HA(\B|ⶀrm|߻!M{G,8a_סо`cхcBHjáJhޒ Ċ Gjt' \D CkZ"gl-& R™DD؉E(o!ձك>c>KG(<4+ya6A՗q=T.&`!oP/VT&D#ܬ%Hm\%nYwc=\Ob<!q]7WȈ"1 @S%nX8!zpeݭaP%% c1dUM[CQOu/K<n}gXnHf*f_-jyXIEⵅَ؛|3w# ƨɘd~`OPR肥-u|!BB!uG!&\T́> p^0=KŧwԻZ&@J#_ Ԥ3`QOTWm JaVQ+%K)Y$HAn0F(TX࠹v%n8˘ ̬ ^{+!NOusYqAvQi NLEpXDDeF5A qB[,jz1OO8rV1Z G+Kc3.Ľf% 0ZT-]GbbVzXQ*UCpr ث$X_Ӹ&a1o_hg0n06WuDnX Qh.JmUD^ea[Zj'xiO$ 8 $6H6 |A?0\Jvb`B`p<ݥd[x`Kyj?^k0PJM1:.dU*^aR.!Q^É\9DA0sQ +<\n-Q\:Ua`w-H4n|DI/)xD.6}9n1i+AMJt9c@[pB:W/`Yiđڽb_ڨ$ig-֡Z]r1MafK (*Xl?<7x_9LQg{#x!k {!?(nsgɁ<)~cz F H]X0 ED8h$|P$l Kb>W6 '1V.%f*dy&F̡%\N"Dv l ƆbqV)9!4//,Ր $]5-pme|ź(P\;XZ v*t zX,Nv  &pCVdPRWVJ틈M1Ap ͢ I"UPBlp:fu~Z7?w&NP\ÁpN %v_ŕX.p-od7Ueo.gx#գS]R?i b$[Μ iu`U"cq);X q0)Q+W`V8 3}^la-Z Sfb?' )FDWNLįi2v1/L\qMuidmMU_T@_cbAʬTaabMzHܽv?PaEo;fn!1n, AchSӿ[qoV&^?m/u8p4n)V{RbȅS fJi=j[-̽.i 2~|Ce=L+#b Xq5lK_AEµ≏ԺP[ɋԨt[w6)3MkIwyH=(g-e>p$6`eEC+ #WX+kpu5%ܹ`]%`PPv0!b67,}B3ݫot[U *$YSY3,f7a(,Pbà0Y V`^ N2=K4 uRvFf Yo}:kGG&T FfW %P seljZUƮpXc$¡^ #G>Qjާc UDԣ!9 fn""LFǑwM:qlȡa E ?USOoZ]Ux,&]JɱJX`m< ԭ48nWS}|*H4McƀbۓW(H L}o2?U*_b%NKWþ.}0ZeQTWo45;t]A%T.e Vpi|U~Pn\2fZ-b3S㻲6:_dJV{j"쵧ȑ:\அ{Vk'@o[s~e4_:{yGV]AZv5c̨u"qh<6CE~"Y{)L,xcpm2cf3HO8  /q4YN\ߩ.Y Ni#D0NY2؎ru ;4EpZ7!]C0-V.| n9~463!~^qUvTXۙ b8ajqf!RSA.j+xt#Ȕʵim6q.ٝ])4s01+ɲ͡VGs|ēԾXr@)XJKx 9}L$2C%ip4P44ٌ?8|${z+ʠ)N:ԭLKo>= options(prompt = "R> ", continue = "+ ", useFancyQuotes = FALSE, width = 70) set.seed(7) invisible(.Call(grDevices:::C_palette, grDevices::hcl( h = c(0, 5, 125, 245, 195, 315, 65, 0), c = c(0, 100, 90, 85, 63, 105, 90, 0), l = c(0, 55, 75, 60, 82, 48, 80, 65) ))) library("partykit") library("Formula") library("latex2exp") library("lattice") library("MASS") library("colorspace") library("disttree") library("latex2exp") library("gamlss") library("crch") library("RainTyrol") library("ggplot2") theme_set(theme_bw(base_size = 18)) library(colorspace) ## HCL palette pal <- hcl(c(10, 128, 260, 290, 50), 100, 50) names(pal) <- c("forest", "tree", "gamlss", "gamboostLSS", "EMOS") pallight <- hcl(c(10, 128, 260, 290, 70), 100, 50, alpha = 0.25) names(pallight) <- c("forest", "tree", "gamlss", "gamboostLSS", "EMOS") transpgray <- rgb(0.190,0.190,0.190, alpha = 0.2) lightblue <- "#2297E6" lightorange <- "#FFA500" @ <>= ## Reg. Tree set.seed(7) nobs <- 200 kappa <- 12 x <- c(1:nobs)/nobs ytrue <- numeric(length = length(x)) for(i in 1:(nobs)) ytrue[i] <- if(x[i]<1/3) 0.5 else 1+(1-plogis(kappa*(2*(x[i]-0.2)-1))) y <- ytrue + rnorm(nobs,0,0.3) # more points for precise illustration of true function x100 <- c(1:(100*nobs))/(100*nobs) ytrue <- ytree <- ytree2 <- ytree3 <- ytree4 <- yforest <- numeric(length = length(x100)) for(i in 1:(nobs*100)) ytrue[i] <- if(x100[i]<1/3) 0.5 else 1+(1-plogis(kappa*(2*(x100[i]-0.2)-1))) for(i in 1:(nobs*100)) ytree[i] <- if(x100[i]<1/3) 0.5 else {if(x100[i]<2/3) 2 else 1} for(i in 1:(nobs*100)) ytree2[i] <- if(x100[i]<0.31) 0.47 else {if(x100[i]<0.69) 1.9 else 1.1} for(i in 1:(nobs*100)) ytree3[i] <- if(x100[i]<0.34) 0.52 else {if(x100[i]<0.54) 2.2 else {if(x100[i]<0.74) 1.74 else 0.9}} for(i in 1:(nobs*100)) ytree4[i] <- if(x100[i]<0.32) 0.51 else {if(x100[i]<0.63) 1.8 else 1.15} for(i in 1:(nobs*100)) yforest[i] <- if(x100[i]<=0.33) 0.52 else {if(x100[i]<=0.34) 1.5 else {if(x100[i]<=0.54) 2 else {if(x100[i]<=0.63) 1.9 else {if(x100[i]<=0.69) 1.6 else {if(x100[i]<=0.74) 1.3 else 1}}}}} @ \begin{document} \section{Random forests} \subsection{Motivation} \begin{frame}[fragile] \frametitle{Motivation} {\bf Idea:} \\ \begin{itemize} \item Combine an ensemble of trees. \item A single tree can capture non-linear and non-additive effects and select covariates and possible interactions automatically. \item Combining trees to a forest model allows for an approximation of smooth effects. \item A forest can regularize and stabilize the model. \end{itemize} %\bigskip \end{frame} \begin{frame} \frametitle{Motivation} \vspace{0.2cm} \begin{minipage}{0.4\textwidth} \only<1>{\textbf{Tree model:\\}}\only<2-12>{\textbf{Subsampling:\\}}\only<13->{\textbf{Forest model:\\}} \vspace{-0.4cm} %\vspace{-0.8cm} \begin{center} \only<1>{ %\vspace{0.2cm} \resizebox{0.63\textwidth}{!}{ \begin{tikzpicture} \node[ellipse, fill=HighlightBlue!70, align=center] (n0) at (2, 3) {}; \node[] (n00) at (1, 1.5) {}; \node[rectangle, fill=HighlightOrange!70, align=center] (n1) at (0, 0) {$\hat{Y}_1$}; \draw[-] (n0) -- (n00) node [midway, left] {\small $X \leq p_1$}; \draw[-] (n0) -- (n1); \node[ellipse, fill=HighlightBlue!70, align=center] (n2) at (3, 1.5) {}; \draw[-] (n0) -- (n2) node [midway, right] {\small $X > p_1$}; \node[rectangle, fill=HighlightOrange!70, align=center] (n3) at (2, 0) {$\hat{Y}_2$}; \draw[-] (n2) -- (n3) node [midway, left] {\small $X \leq p_2$}; \node[rectangle, fill=HighlightOrange!70, align=center] (n4) at (4, 0) {$\hat{Y}_3$}; \draw[-] (n2) -- (n4) node [midway, right] {\small $X > p_2$}; \end{tikzpicture}} \vspace{0.475cm} } \only<2->{ %\vspace{0.2cm} \resizebox{0.6\textwidth}{!}{ \begin{tikzpicture} %\draw[ellipse, draw=black, align=center, scale = 0.7, minimum width=170pt, minimum height = 35pt] (set) at (1, 3) {}; \draw[gray,rounded corners=10pt] (-1.05,4.35) -- (4.05,4.35) -- (4.05,2.7) -- (-2.05,2.7) -- (-2.05,4.35) -- (0.05,4.35); %\draw[gray] (1,3.5) ellipse (3 and 0.8); %\visible<4>{ \begin{scope} \clip (-1,4.3) -- (4,4.3) -- (4,2.7) -- (-2,2.7) -- (-2,4.3) -- (0,4.3); %\clip (1,3.5) ellipse (3 and 0.8); \pgfmathsetseed{7} \foreach \p in {1,...,200} {\fill[gray] (1+3*rand,3.5+0.8*rand) circle (0.04);} \end{scope} %} %%% color points %\visible<5-6>{ %\begin{scope} %\clip (-1,4.3) -- (4,4.3) -- (4,2.7) -- (-2,2.7) -- (-2,4.3) -- (0,4.3); %\pgfmathsetseed{7} %\foreach \p in {1,...,100} {\fill[treegreen] (1+3*rand,3.5+0.8*rand) circle (0.07);} %\end{scope} %} \visible<3->{ \node[ellipse, draw=treegreen, align=center, minimum width=80pt, minimum height = 40pt, line width = 3pt] (subset1) at (0.1, 3.5) {}; } %\visible<7-8>{ %\begin{scope} %\clip (-1,4.3) -- (4,4.3) -- (4,2.7) -- (-2,2.7) -- (-2,4.3) -- (0,4.3); %\pgfmathsetseed{7} %\foreach \p in {1,...,49} {\fill[gray] (1+3*rand,3.5+0.8*rand) circle (0.04);} %\foreach \p in {50,...,150} {\fill[lightblue] (1+3*rand,3.5+0.8*rand) circle (0.07);} %\end{scope} %} \visible<5->{ \node[ellipse, draw = lightblue, align=center, minimum width=100pt, minimum height = 30pt, line width = 3pt] (subset2) at (1.2, 3.6) {}; } %\visible<9-10>{ %\begin{scope} %\clip (-1,4.3) -- (4,4.3) -- (4,2.7) -- (-2,2.7) -- (-2,4.3) -- (0,4.3); %\pgfmathsetseed{7} %\foreach \p in {1,...,99} {\fill[gray] (1+3*rand,3.5+0.8*rand) circle (0.04);} %\foreach \p in {100,...,200} {\fill[lightorange] (1+3*rand,3.5+0.8*rand) circle (0.07);} %\end{scope} %} \visible<7->{ \node[ellipse, draw = lightorange, align=center, minimum width=120pt, minimum height = 25pt, line width = 3pt] (subset3) at (1.6, 3.3) {}; } \visible<4->{ \node[ellipse, fill=treegreen, align=center] (n00) at (-1, 2) {}; \node[ellipse, fill=treegreen, align=center] (n01) at (-1.25, 1.25) {}; \draw[-, line width=1pt] (n00) -- (n01); \node[rectangle, fill=treegreen, align=center] (n02) at (-1.5, 0.5) {}; \draw[-, line width=1pt] (n01) -- (n02); \node[rectangle, fill=treegreen, align=center] (n03) at (-1, 0.5) {}; \draw[-, line width=1pt] (n01) -- (n03); \node[rectangle, fill=treegreen, align=center] (n04) at (-0.5, 0.5) {}; \draw[-, line width=1pt] (n00) -- (n04); } \visible<6->{ \node[ellipse, fill=lightblue, align=center] (n10) at (1, 2) {}; \node[ellipse, fill=lightblue, align=center] (n11) at (0.5, 1.25) {}; \draw[-, line width=1pt] (n10) -- (n11); \node[rectangle, fill=lightblue, align=center] (n12) at (0.25, 0.5) {}; \draw[-, line width=1pt] (n11) -- (n12); \node[rectangle, fill=lightblue, align=center] (n13) at (0.75, 0.5) {}; \draw[-, line width=1pt] (n11) -- (n13); \node[ellipse, fill=lightblue, align=center] (n14) at (1.5, 1.25) {}; \draw[-, line width=1pt] (n10) -- (n14); \node[rectangle, fill=lightblue, align=center] (n15) at (1.75, 0.5) {}; \draw[-, line width=1pt] (n14) -- (n15); \node[rectangle, fill=lightblue, align=center] (n16) at (1.25, 0.5) {}; \draw[-, line width=1pt] (n14) -- (n16); } \visible<8->{ \node[ellipse, fill=lightorange, align=center] (n20) at (3, 2) {}; \node[rectangle, fill=lightorange, align=center] (n21) at (2.5, 0.5) {}; \draw[-, line width=1pt] (n20) -- (n21); \node[ellipse, fill=lightorange, align=center] (n22) at (3.25, 1.25) {}; \draw[-, line width=1pt] (n20) -- (n22); \node[rectangle, fill=lightorange, align=center] (n23) at (3, 0.5) {}; \draw[-, line width=1pt] (n22) -- (n23); \node[rectangle, fill=lightorange, align=center] (n24) at (3.5, 0.5) {}; \draw[-, line width=1pt] (n22) -- (n24); } \visible<10->{ \node[ellipse, draw = black, align=center, minimum width=15pt, minimum height = 15pt, line width = 2pt] (B1) at (-1.5, 0.5) {}; \node[ellipse, align=center, line width = 3pt, text=treegreen] (Y1) at (-1.5, -0.5) {\LARGE $\hat{y}_1$}; } \visible<11->{ \node[ellipse, draw = black, align=center, minimum width=15pt, minimum height = 15pt, line width = 2pt] (B2) at (1.25, 0.5) {}; \node[ellipse, align=center, line width = 3pt, text=lightblue] (Y2) at (1.25, -0.5) {\LARGE $\hat{y}_2$}; } \visible<12->{ \node[ellipse, draw = black, align=center, minimum width=15pt, minimum height = 15pt, line width = 2pt] (B2) at (3.5, 0.5) {}; \node[ellipse, align=center, line width = 3pt, text=lightorange] (Y3) at (3.5, -0.5) {\LARGE $\hat{y}_3$};(3.5, 0.5) } \end{tikzpicture} } } \end{center} \end{minipage} \hspace{0.7cm} \begin{minipage}{0.36\textwidth} %\begin{center} %\vspace{0.1cm} \only<1-2>{ %\vspace{0.01cm} <>= par(mar=c(3,3,2,0)) #par(mar=c(3,3,2,5.5)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) #lines(x = x, y = ytrue, col = "gray", lwd=5, main = "") lines(x = x100, y = ytree, col = pal["forest"], lwd=7) mtext(text = "X", side = 1, cex = 2.5, line = 2) mtext(text = "Y", side = 2, cex = 2.5, line = 1) @ } \only<3>{ %\vspace{0.01cm} %\hspace{-0.1cm} <>= par(mar=c(3,3,2,0)) #par(mar=c(3,3,2,5.5)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) mtext(text = "X", side = 1, cex = 2.5, line = 2) mtext(text = "Y", side = 2, cex = 2.5, line = 1) @ } \only<4-5>{ %\vspace{0.01cm} %\hspace{-0.1cm} <>= <> lines(x = x100, y = ytree2, col = pal["tree"], lwd=7) @ } \only<6-7>{ %\vspace{0.01cm} %\hspace{-0.1cm} <>= <> lines(x = x100, y = ytree3, col = lightblue, lwd=7) @ } \only<8>{ %\vspace{0.01cm} %\hspace{-0.1cm} <>= <> lines(x = x100, y = ytree4, col = lightorange, lwd=7) @ } \only<9-12>{ <>= par(mar=c(3,3,2,0)) #par(mar=c(3,3,2,5.5)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) lines(x = x100, y = ytree2, col = pal["tree"], lwd=7) lines(x = x100, y = ytree3, col = lightblue, lwd=7) lines(x = x100, y = ytree4, col = lightorange, lwd=7) lines(x = c(0.6,0.6), y = c(-1, 1.8), type = "l", lty = 2, lwd = 4) mtext(text = "Y", side = 2, cex = 2.5, line = 1) mtext(text = "x", side = 1, cex = 4, line = 2, at=0.6) @ } \only<13->{ <>= par(mar=c(3,3,2,0)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) lines(x = x100, y = yforest, col = pal["forest"], lwd=7) lines(x = c(0.6,0.6), y = c(-1, 1.8), type = "l", lty = 2, lwd = 4) mtext(text = "x", side = 1, cex = 4, line = 2, at=0.6) mtext(text = "Y", side = 2, cex = 2.5, line = 1) @ } \end{minipage} \vspace{0.5cm} \only<13->{ $\hat{y}= \frac{1}{3} (\hat{y}_1 + \hat{y}_2 + \hat{y}_3)$ } \vspace{0.3cm} \visible<14->{ for $\hat{y}_t$ being the average response value in the segment $\mathcal{B}^t_x$ which the observed covariate $x$ is assigned to in the $t$-th tree with learning data $\{(y_i,x_i)\}_{i=1,\ldots,n}$: \vspace{0.3cm} $\hat{y}_t= \frac{1}{|\mathcal{B}^t_x|} \sum_{i: x_i \in \mathcal{B}^t_x} y_i$ \visible<15->{ $\ =\ \sum_{i=1}^n \frac{I(x_i \in \mathcal{B}^t_x)}{|\mathcal{B}^t_x|} \cdot y_i$ } \visible<16->{ $\ =\ \sum_{i=1}^n w_i(x) \cdot y_i$ } } \end{frame} \subsection{Aggregation of trees\\ \&\\ random sampling} \begin{frame} \frametitle{Aggregation of trees} {\bf Simple tree model:} Obtain the predicted response $\hat{y}$ for an observed covariate~$x$ by averaging over observations in the terminal node~$\mathcal{B}_x$: $$ \hat{y}= \frac{1}{|\mathcal{B}_x|} \sum_{i: x_i \in \mathcal{B}_x} y_i \visible<2->{ \ =\ \sum_{i=1}^n w_i(x) \cdot y_i$$ } \visible<3->{ $$\ =\ \argmin_{\mu} \sum_{i=1}^n w_i(x) \cdot (y_i - \mu)^2$$ } \visible<4->{ {\bf Model-based tree:} Obtain the predicted model parameter(s) $\hat{\theta}$ for an observed covariate~$x$ by optimizing a loss function for all observations in the terminal node~$\mathcal{B}_x$: $$ \hat{\theta}= \argmin_{\theta} \sum_{i: x_i \in \mathcal{B}_x} loss(\theta; y_i) \ =\ \argmin_{\theta} \sum_{i=1}^n w_i(x) \cdot loss(\theta; y_i)$$ } % {\bf Note:} The model-based approach allows for fitting complex models but also includes the specific case of averaging over all observations which corresponds to minimizing the residual sum of squares $\sum (y_i - \theta)^2$. \end{frame} \begin{frame} \frametitle{Aggregation of trees} {\bf Strategy:} Combine T trees to a forest model by employing tree-based weights. The predicted model parameter (vector) $\hat{\theta}$ is the argument %of the parameter space $\Theta$ that minimizes the weighted sum of a loss function evaluated for learning data $\{(y_i,x_i)\}_{i=1,\ldots,n}$: \vspace{-0.2cm} \[ \hat{\theta}(x) = \argmin_{\theta} \sum_{i=1}^n w_i(x) \cdot loss(\theta; y_i) \] \medskip \only<2-4>{ \vspace{0.13cm} \textbf{Weights:} \vspace{-1.14cm} \begin{eqnarray*} w^{\text{base}}_i(x) & = & 1 \\[0.2cm] \visible<3-4>{ w^{\text{tree}}_i(x) & = & \frac{I(x_i \in \mathcal{B}_x)}{\left|\mathcal{B}_x\right|} \\[0.1cm] \visible<4>{ w^{\text{forest}}_i(x) & = & \frac{1}{T} \sum_{t=1}^T \frac{I(x_i \in \mathcal{B}^t_x)}{\left|\mathcal{B}^t_x\right|} \end{eqnarray*} }}} \end{frame} \begin{frame} \frametitle{Random sampling} {\bf Idea:} Build each tree on a different subset of the full data set. \medskip {\bf Sampling observations:} \begin{itemize} \item Bootstrapping: resampling with replacement, usually ``n out of n''. \item Subsampling: draw a subset without replacement (typically of the size of 63.2\% of the full data set; for large data sets a smaller fraction can be advantageous). \end{itemize} \bigskip {\bf Sampling covariates:}\\ \smallskip In order to reduce the correlation among trees random input variable sampling is employed, i.e., for each split only a subset of covariates is selected randomly and provided as possible split variables (typical sampling size: $\sqrt{\text{\#Var}}$). \end{frame} \begin{frame} \frametitle{Hyperparameter selection} Apart from the size and type of sampling two further control parameters have to be set for a forest model: \begin{itemize} \item {\bf Number of trees:} A high number of trees allows for a more stable model and for a better approximation of smooth effects, however, at the cost of higher computational effort. \item {\bf Size of the trees:} The size of each single tree can be controlled by setting stopping criteria such as a minimal number of observations in a node, maximum tree depth or a significance level if a statistical test is employed in the tree algorithm. However, in a forest model each tree is usually built as large as possible which can lead to overfitting for a single tree, but this is compensated by aggregating the trees to a forest model. \end{itemize} \end{frame} <>= data("CPS1985", package = "AER") @ \begin{frame}[fragile] \frametitle{Example: wages} \textbf{Data:} Random sample from the May 1985 US Current Population Survey. A data frame containing \Sexpr{nrow(CPS1985)} observations on \Sexpr{ncol(CPS1985)} variables. \bigskip \begin{tabular}{ll} \hline Variable & Description\\ \hline \code{wage} & Wage (in US dollars per hour). \\ \code{education} & Education (in years). \\ \code{experience} & Potential work experience (in years, \code{age - education - 6}). \\ \code{age} & Age (in years). \\ \code{ethnicity} & Factor: Caucasian, Hispanic, Other. \\ \code{gender} & Factor: Male, Female. \\ \code{union} & Factor. Does the individual work on a union job? \\ \hline \end{tabular} \bigskip \textbf{Model formula:} \code{log(wage) ~ education + experience + age + ethnicity + gender + union}. \end{frame} <>= set.seed(4) f <- log(wage) ~ education + experience + age + ethnicity + gender + union ct_cps <- ctree(f, data = CPS1985, alpha = 0.01) cf <- cforest(f, data = CPS1985, ntree = 5) #, control =ctree_control(maxdepth = 5)) vimp <- varimp(cf , risk = "loglik") @ \begin{frame}[fragile] \frametitle{Example: wages} Single tree model: \setkeys{Gin}{width=0.99\textwidth} <>= plot(ct_cps) @ \end{frame} \begin{frame}[fragile] \frametitle{Example: wages} Forest model - tree I: \setkeys{Gin}{width=0.99\textwidth} <>= #par(mfrow=c(2,2)) plot(party(cf[[1]][[1]], data = CPS1985[,c("wage", "education", "experience", "age", "ethnicity", "gender", "union")]), drop_terminal = TRUE) @ \end{frame} \begin{frame}[fragile] \frametitle{Example: wages} Forest model - tree II: \setkeys{Gin}{width=0.99\textwidth} <>= #par(mfrow=c(2,2)) plot(party(cf[[1]][[2]], data = CPS1985[,c("wage", "education", "experience", "age", "ethnicity", "gender", "union")]), drop_terminal = TRUE) @ \end{frame} \begin{frame}[fragile] \frametitle{Example: wages} Forest model - tree III: \setkeys{Gin}{width=0.99\textwidth} <>= #par(mfrow=c(2,2)) plot(party(cf[[1]][[3]], data = CPS1985[,c("wage", "education", "experience", "age", "ethnicity", "gender", "union")]), drop_terminal = TRUE) @ \end{frame} \begin{frame}[fragile] \frametitle{Example: wages} Forest model - tree IV: \setkeys{Gin}{width=0.99\textwidth} <>= #par(mfrow=c(2,2)) plot(party(cf[[1]][[4]], data = CPS1985[,c("wage", "education", "experience", "age", "ethnicity", "gender", "union")]), drop_terminal = TRUE) @ \end{frame} \begin{frame}[fragile] \frametitle{Example: wages} \vspace{-0.5cm} \setkeys{Gin}{width=0.94\textwidth} <>= nd <- data.frame(education = 13.02, #c(2:18), experience = 17.82, age = c((18:64)/1), #36.83, ethnicity = "cauc", region = "other", gender = "male", occupation = "worker", sector = "other", union = "no", married = "yes") { par(mfrow = c(2,2)) set.seed(74) cf <- cforest(f, data = CPS1985, ntree = 2) predwage <- cbind(c((18:64)/1), predict(cf, newdata = nd)) colnames(predwage) <- c("age", "predicted log(wage)") plot(x = predwage[,"age"], y = exp(predwage[,"predicted log(wage)"]), type = 'l', ylab = "predicted wage", xlab = "age", main = "Forest with 2 trees") cf <- cforest(f, data = CPS1985, ntree = 4) predwage <- cbind(c((18:64)/1), predict(cf, newdata = nd)) colnames(predwage) <- c("age", "predicted log(wage)") plot(x = predwage[,"age"], y = exp(predwage[,"predicted log(wage)"]), type = 'l', ylab = "predicted wage", xlab = "age", main = "Forest with 4 trees") lines(x = predwage[,"age"], y = exp(predwage[,"predicted log(wage)"]), type = 'l', col = "gray") cf <- cforest(f, data = CPS1985, ntree = 20) predwage <- cbind(c((18:64)/1), predict(cf, newdata = nd)) colnames(predwage) <- c("age", "predicted log(wage)") plot(x = predwage[,"age"], y = exp(predwage[,"predicted log(wage)"]), type = 'l', ylab = "predicted wage", xlab = "age", main = "Forest with 20 trees") cf <- cforest(f, data = CPS1985, ntree = 200) predwage <- cbind(c((18:64)/1), predict(cf, newdata = nd)) colnames(predwage) <- c("age", "predicted log(wage)") plot(x = predwage[,"age"], y = exp(predwage[,"predicted log(wage)"]), type = 'l', ylab = "predicted wage", xlab = "age", main = "Forest with 200 trees") } @ \end{frame} \begin{frame} \frametitle{Variable importance} {\bf Problem:} In a single tree model the effect of each covariate can easily be investigated based on a simple illustration of the tree structure. However, in a forest model this would require to investigate each tree on its own including its specific setting (induced by random sampling). \bigskip {\bf Idea:} Asses the influence of a covariate on the forest model by \begin{itemize} \item permuting the selected covariate and evaluating the resulting change in performance of the model (mean decrease in accuracy, measured for example based on the employed loss function) or \item calculating the total decrease in node impurities from splitting in the selected covariate (measured for example by the Gini index for classification trees or the RMSE for regression trees), \end{itemize} averaged over all trees. \bigskip %\bigskip % {\bf Implementations:} % \begin{itemize} % \item \fct{importance} in the R package randomForest. % \item \fct{importance.ranger} in the R package ranger. % \item \fct{varimp} in the R package partykit. % \end{itemize} % \only<2->{ % \setkeys{Gin}{width=0.5\textwidth} % <>= % par(mar = c(4,5.5,0,2)) % barplot(sort(vimp, decreasing = FALSE), % horiz = TRUE, las = 1, axes = FALSE, % xlab = "Variable importance: mean decrease in log-likelihood") % axis(1, at = seq(0,1,0.02), las = 1, mgp=c(0,1,0)) % @ % Depending on the fitted model the corresponding objective function can be employed as \emph{risk function} to measure accuracy by calculating importance scores (e.g., log-likelihood, number of misclassifications, \ldots).\\ % To measure impurity, for example, the Gini index can be employed for classification trees or the RMSE for regression trees. %} \end{frame} \begin{frame} \frametitle{Example: wages} Evaluation of variable importance in the fitted forest model: \bigskip \setkeys{Gin}{width=0.57\textwidth} <>= par(mar = c(4,5.4,1,2)) barplot(sort(vimp, decreasing = FALSE), horiz = TRUE, las = 1, axes = FALSE, xlab = "Variable importance: mean decrease in log-likelihood") axis(1, at = seq(0,1,0.02), las = 1, mgp=c(0,1,0)) @ \end{frame} \subsection{Implementations} \begin{frame}[fragile] \frametitle{R software for forest models} {\bf randomForest:} \begin{itemize} \item R package for classic random forests. \item Based on implementations of CART. \item First implementation of random forests in R. \end{itemize} % \medskip % % <>= % randomForest(formula, data=NULL, ..., subset, na.action=na.fail) % randomForest(x, y=NULL, ...) % @ % % \medskip % % Optional control arguments: % \begin{itemize} % \item \code{ntree}: nr. of trees, % \item \code{mtry}: nr. of randomly sampled split variable candidates, % \item \code{replace}: type of subsetting, % \item \code{sampsize}: size of drawn subsamples, % \item \code{nodesize}: minimum size of terminal nodes, % \item \code{maxnodes}: maximum number of terminal nodes, % \item \ldots % \end{itemize} \medskip {\bf ranger}: \begin{itemize} \item RANdom forest GEneRator. \item R package providing a fast implementation of classic random forests. \end{itemize} \medskip {\bf partykit:} \begin{itemize} \item R package offering a toolkit for unbiased recursive partitioning. \item Provides the forest-building function \fct{cforest}, based on conditional inference trees (CTree). \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{R software for forest models} {\bf ranger}: <>= library("ranger") rf <- ranger(log(wage) ~ education + experience + age + ethnicity + gender + union, data = CPS1985) @ Optional control arguments: \begin{itemize} \item \code{num.trees}: number of trees, \item \code{mtry}: number of randomly sampled split variable candidates, \item \code{replace}: sample with replacement, \item \code{sample.fraction}: fraction of observations to sample, \item \code{min.node.size}: minimal size of terminal nodes, \item \code{max.depth}: maximal tree depth, \item \code{splitrule}: splitting rule, \item \ldots \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{R software for forest models} {\bf ranger}: <>= newdata <- data.frame(education = 13, experience = 17, age = 36, ethnicity = "cauc", region = "other", gender = "male", occupation = "worker", sector = "other", union = "no", married = "yes") pred_rf <- predict(rf, data = newdata) pred_rf$predictions exp(pred_rf$predictions) rf <- ranger(log(wage) ~ education + experience + age + ethnicity + gender + union, data = CPS1985, importance = "impurity") importance(rf) @ \end{frame} \begin{frame}[fragile] \frametitle{R software for forest models} {\bf partykit:} <>= library("partykit") cf <- cforest(log(wage) ~ education + experience + age + ethnicity + gender + union, data = CPS1985) @ \only<1>{ Optional forest-specific control arguments: \begin{itemize} \item \code{ytrafo}: transformation function applied to the response, \item \code{ntree}: number of trees, \item \code{mtry}: number of randomly sampled split variable candidates, \item \code{perturb}: type and size of subsetting, \item \ldots \end{itemize} %\vspace{0.9cm} } \only<2->{ Optional tree-specific arguments handed over via \fct{ctree\_control}: \begin{itemize} \item \code{minsplit}: minimum number of observations to perform a split, \item \code{minbucket}: minimum number of observations in a node after splitting, \item \code{maxdepth}: maximum depth of the tree, \item \code{alpha}: significance level for split variable selection, \item \ldots \end{itemize} } % \only<3>{ % % <>= % cf <- cforest(log(wage) ~ education + experience + age + ethnicity + gender + union, % data = CPS1985, control = ctree_control(minsplit = 20)) % @ % } \end{frame} \begin{frame}[fragile] \frametitle{R software for forest models} {\bf partykit:} <>= library("partykit") cf <- cforest(log(wage) ~ education + experience + age + ethnicity + gender + union, data = CPS1985) @ Optional tree-specific arguments handed over via \fct{ctree\_control}: \begin{itemize} \item \code{minsplit}: minimum number of observations to perform a split, \item \code{minbucket}: minimum number of observations in a node after splitting, \item \code{maxdepth}: maximum depth of the tree, \item \code{alpha}: significance level for split variable selection, \item \ldots \end{itemize} <>= cf <- cforest(log(wage) ~ education + experience + age + ethnicity + gender + union, data = CPS1985, control = ctree_control(minsplit = 20)) @ \end{frame} \begin{frame}[fragile] \frametitle{R software for forest models} {\bf partykit:} <>= newdata <- data.frame(education = 13, experience = 17, age = 36, ethnicity = "cauc", region = "other", gender = "male", occupation = "worker", sector = "other", union = "no", married = "yes") pred_cf <- predict(cf, newdata = newdata) pred_cf exp(pred_cf) varimp(cf) @ \end{frame} \begin{frame} \frametitle{R software for forest models} \textbf{Further R packages:} % \begin{itemize} \item grf: generalized random forests, \item disttree: distributional forests, based on partykit, \item circtree: circular distributional forests, based on partykit, \item model4you: model-based random forests for personalized treatment effects, \item randomSurvivalForest: random forests for the analysis of right-censored survival data, \item \ldots \end{itemize} \end{frame} \subsection{Distributional forests} \begin{frame}%[fragile] \frametitle{Motivation} \vspace{-0.41cm} \begin{figure}[!htb] \minipage{0.285\textwidth} \begin{center} <>= nobs <- 200 ## GLM set.seed(7) x <- c(1:nobs)/nobs ytrue <- 1+x*1.5 y <- ytrue + rnorm(nobs,0,0.3) @ \visible<2->{ <>= par(mar=c(2,0,2,0)) plot(y=y , x=x, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) lines(x = x, y = ytrue, col = pal["forest"], lwd = 7, main = "") @ } \end{center} \endminipage \visible<3->{{\LARGE$\rightarrow$}} \minipage{0.285\textwidth} \begin{center} <>= ## GAM set.seed(7) x <- c(1:nobs)/nobs x <- 2*(x-0.5) ytrue <- x^3 y <- ytrue + rnorm(nobs,0,0.3) @ \visible<3->{ <>= par(mar=c(2,0,2,0)) plot(y=y , x=x, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) lines(x = x, y = ytrue, col = pal["forest"], lwd = 7, main = "") @ } \end{center} \endminipage \visible<4->{{\LARGE$\rightarrow$}} \minipage{0.285\textwidth} \begin{center} <>= ## GAMLSS set.seed(7) x <- c(1:nobs)/nobs x <- 2*(x-0.5) ytrue <- x^3 var <- exp(-(2*x)^2)/2 y <- ytrue + rnorm(nobs, 0, 0.1 + var) @ \visible<4->{ <>= par(mar=c(2,0,2,0)) plot(x, y, xaxt = "n", yaxt = "n", ann = FALSE, type = "n") polygon(c(x, rev(x)), c(ytrue + 0.1 + var, rev(ytrue - 0.1 - var)), col = pallight["forest"], border = "transparent") lines(x, ytrue, col = pal["forest"], lwd=7) points(x, y, col = "slategray", pch = 19) box(lwd = 5) @ } \end{center} \endminipage \vspace{0.5cm} \minipage{0.25\textwidth} \begin{center} \visible<2->{ LM, GLM\\ \vspace{0.5cm} \code{lm}\\ \code{glm}\\ \vspace{1.5cm}} \end{center} \endminipage \hspace{1.1cm} \minipage{0.25\textwidth} \begin{center} \visible<3->{ GAM\\ \vspace{0.5cm} \code{mgcv}\\ \code{VGAM}\\ \vspace{1.5cm}} \end{center} \endminipage \hspace{1.1cm} \minipage{0.25\textwidth} \begin{center} \visible<4->{ GAMLSS\\ \vspace{0.5cm} \code{gamlss}\\ \code{mgcv}\\ \code{VGAM}\\ \code{gamboostLSS}\\ \code{bamlss}} \end{center} \endminipage \end{figure} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \vspace{-0.41cm} \begin{figure}[!htb] \minipage{0.285\textwidth} \begin{center} <>= ## Reg. Tree set.seed(7) kappa <- 12 x <- c(1:nobs)/nobs ytrue <- ytree <- yforest <- numeric(length = length(x)) for(i in 1:nobs) ytrue[i] <- if(x[i]<1/3) 0.5 else 1+(1-plogis(kappa*(2*(x[i]-0.2)-1))) y <- ytrue + rnorm(nobs,0,0.3) for(i in 1:nobs) ytree[i] <- if(x[i]<1/3) 0.5 else {if(x[i]<2/3) 2 else 1} @ \visible<1->{ <>= par(mar=c(2,0,2,0)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) #lines(x = x, y = ytrue, col = "gray", lwd=5, main = "") lines(x = x, y = ytree, col = pal["forest"], lwd=7) @ } \end{center} \endminipage \visible<2->{{\LARGE$\rightarrow$}} \minipage{0.285\textwidth} \begin{center} <>= ## Random Forest for(i in 1:nobs) yforest[i] <- if(x[i]<0.27) 0.5 else { if(x[i]<0.39) 0.5 + 1.5*(plogis((x[i]-0.33)/6*700)) else 1+(1-plogis(kappa*(2*(x[i]-0.2)-1)))} @ \visible<2->{ <>= par(mar=c(2,0,2,0)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) box(lwd=5) #lines(x = x, y = ytrue, col = "gray", lwd=5, main = "") lines(x = x, y = yforest, col = pal["forest"], lwd=7, main = "") @ } \end{center} \endminipage \visible<3->{{\LARGE$\rightarrow$}} \minipage{0.285\textwidth} \begin{center} \visible<3->{ <>= par(mar=c(2,0,2,0)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, type = "n") box(lwd=5) text(x = mean(range(x)), y = mean(range(y)), "?", cex = 12) @ } \end{center} \endminipage \minipage{0.285\textwidth} \begin{center} \vspace{0.0cm} \visible<1->{ Regression tree\\ \vspace{0.3cm} \resizebox{0.2\textwidth}{!}{ \begin{tikzpicture} \node[ellipse, fill=HighlightBlue!70, align=center] (n0) at (1, 2) {}; \node[rectangle, fill=HighlightOrange!70, align=center] (n1) at (0.5, 1) {}; \draw[-, line width=1pt] (n0) -- (n1); \node[ellipse, fill=HighlightBlue!70, align=center] (n2) at (1.5, 1) {}; \draw[-, line width=1pt] (n0) -- (n2); \node[rectangle, fill=HighlightOrange!70, align=center] (n3) at (1, 0) {}; \draw[-, line width=1pt] (n2) -- (n3); \node[rectangle, fill=HighlightOrange!70, align=center] (n4) at (2, 0) {}; \draw[-, line width=1pt] (n2) -- (n4); \end{tikzpicture}} \vspace{0.2cm}\\ \code{rpart}\\ \code{party(kit)}\\ \vspace{1cm}} \end{center} \endminipage \hspace{0.65cm} \minipage{0.285\textwidth} \begin{center} \vspace{-0.4cm} \visible<2->{ Random forest\\ \vspace{0.4cm} \resizebox{0.6\textwidth}{!}{ \begin{tikzpicture} \node[ellipse, fill=HighlightBlue!70, align=center] (n00) at (1, 2) {}; \node[rectangle, fill=HighlightOrange!70, align=center] (n01) at (0.5, 1) {}; \draw[-, line width=1pt] (n00) -- (n01); \node[rectangle, fill=HighlightOrange!70, align=center] (n02) at (1.5, 1) {}; \draw[-, line width=1pt] (n00) -- (n02); \node[ellipse, fill=HighlightBlue!70, align=center] (n10) at (3, 2) {}; \node[ellipse, fill=HighlightBlue!70, align=center] (n11) at (2.5, 1) {}; \draw[-, line width=1pt] (n10) -- (n11); \node[ellipse, fill=HighlightBlue!70, align=center] (n12) at (3.5, 1) {}; \draw[-, line width=1pt] (n10) -- (n12); \node[rectangle, fill=HighlightOrange!70, align=center] (n13) at (2, 0) {}; \draw[-, line width=1pt] (n11) -- (n13); \node[rectangle, fill=HighlightOrange!70, align=center] (n14) at (2.8, 0) {}; \draw[-, line width=1pt] (n11) -- (n14); \node[rectangle, fill=HighlightOrange!70, align=center] (n15) at (3.2, 0) {}; \draw[-, line width=1pt] (n12) -- (n15); \node[rectangle, fill=HighlightOrange!70, align=center] (n16) at (4, 0) {}; \draw[-, line width=1pt] (n12) -- (n16); \node[ellipse, fill=HighlightBlue!70, align=center] (n20) at (5, 2) {}; \node[rectangle, fill=HighlightOrange!70, align=center] (n21) at (4.5, 1) {}; \draw[-, line width=1pt] (n20) -- (n21); \node[ellipse, fill=HighlightBlue!70, align=center] (n22) at (5.5, 1) {}; \draw[-, line width=1pt] (n20) -- (n22); \node[rectangle, fill=HighlightOrange!70, align=center] (n23) at (5, 0) {}; \draw[-, line width=1pt] (n22) -- (n23); \node[rectangle, fill=HighlightOrange!70, align=center] (n24) at (6, 0) {}; \draw[-, line width=1pt] (n22) -- (n24); \end{tikzpicture} } \vspace{0.3cm}\\ \code{randomForest}\\ \code{ranger}\\ \code{party(kit)}} \end{center} \endminipage \hspace{0.65cm} \minipage{0.285\textwidth} \begin{center} \vspace{0.15cm} \visible<3->{ Distributional trees and forests\\ \vspace{1.15cm} \code{disttree}\\ based on \code{partykit}\\ \vspace{1cm}} \end{center} \endminipage \end{figure} \end{frame} \begin{frame} \frametitle{Building blocks} %\vspace{0.5cm} \begin{minipage}{0.79\textwidth} \vspace{-0.5cm} \textbf{Distributional modeling:} \begin{itemize} \vspace{-0.05cm} \item Specify the complete probability distribution \\ \vspace{-0.05cm} (location, scale, shape, \dots). \end{itemize} \smallskip \textbf{Tree:} \begin{itemize} \vspace{-0.05cm} \item Capture non-linear and non-additive effects. \vspace{-0.1cm} \item Automatic selection of covariates and interactions. %detection of steps and abrupt changes. %(data driven) \end{itemize} \smallskip \textbf{Forest:} \begin{itemize} \vspace{-0.05cm} \item Smoother effects. \vspace{-0.1cm} \item Stabilization and regularization of the model. \end{itemize} \bigskip \bigskip $\Rightarrow$ \textbf{Synthesis:} Distributional Trees and Forests \end{minipage} <>= ## GAMLSS set.seed(7) nobs <- 200 x_g <- c(1:nobs)/nobs x_g <- 2*(x_g-0.5) ytrue_g <- x_g^3 var_g <- exp(-(1.74*x_g)^2)/2.5 y_g <- ytrue_g + rnorm(nobs, 0, 0.1 + var_g) @ <>= ## Reg. Tree set.seed(7) kappa <- 12 x <- c(1:nobs)/nobs ytrue <- ytree <- yforest <- var <- numeric(length = length(x)) for(i in 1:nobs) ytrue[i] <- if(x[i]<1/3) 0.5 else 1+(1-plogis(kappa*(2*(x[i]-0.2)-1))) for(i in 1:nobs) var[i] <- if(x[i]<1/3) 0.1 else 0.6 *(4/3 - x[i]) y <- ytrue + rnorm(nobs, 0, 0.1 + var) for(i in 1:nobs) ytree[i] <- if(x[i]<1/3) 0.5 else {if(x[i]<2/3) 2 else 1} @ <>= ## Random Forest for(i in 1:nobs) yforest[i] <- if(x[i]<0.27) 0.5 else { if(x[i]<0.39) 0.5 + 1.5*(plogis((x[i]-0.33)/6*700)) else 1+(1-plogis(kappa*(2*(x[i]-0.2)-1)))} @ \begin{minipage}{0.2\textwidth} \vspace{-0.05cm} <>= par(mar=c(1,0,1,0)) plot(x_g, y_g, xaxt = "n", yaxt = "n", ann = FALSE, type = "n") polygon(c(x_g, rev(x_g)), c(ytrue_g + 0.1 + var_g, rev(ytrue_g - 0.1 - var_g)), col = pallight["forest"], border = "transparent") lines(x_g, ytrue_g, col = pal["forest"], lwd=10) points(x_g, y_g, col = "slategray", pch = 19) box(lwd = 5) @ \vspace{0.15cm} <>= par(mar=c(1,0,1,0)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19, ylim = c(min(y), max(y))) #lines(x = x, y = ytrue, col = "gray", lwd=5, main = "") lines(x = x, y = ytree, col = pal["forest"], lwd=10) box(lwd=5) @ \vspace{0.15cm} <>= par(mar=c(1,0,1,0)) plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19, ylim = c(min(y), max(y))) #lines(x = x, y = ytrue, col = "gray", lwd=5, main = "") lines(x = x, y = yforest, col = pal["forest"], lwd=10, main = "") box(lwd=5) @ \vspace{0.15cm} <>= par(mar=c(1,0,1,0)) #plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19) #box(lwd=5) #lines(x = x, y = ytrue, col = "gray", lwd=5, main = "") #lines(x = x, y = yforest, col = pal["forest"], lwd=7, main = "") plot(x = x, y = y, xaxt="n", yaxt="n", ann=FALSE, col = "slategray", pch = 19, ylim = c(min(y), max(y))) polygon(c(x, rev(x)), c(yforest + 0.1 + var, rev(yforest - (0.1 + var))), # c(ytrue_g + 0.1 + var_g, rev(ytrue_g - 0.1 - var_g)) col = pallight["forest"], border = "transparent") box(lwd=5) lines(x = x, y = yforest, col = pal["forest"], lwd=10) @ \end{minipage} \end{frame} <>= set.seed(54) nobs <- 500 x <- runif(nobs, 0, 1) mu <- sigma <- ytrue <- numeric(length = nobs) for(i in 1:nobs) sigma[i] <- if(x[i]<=0.4) 1 else 3 for(i in 1:nobs) mu[i] <- if(x[i]<= 0.4|| x[i]>0.8) 4 else 12 y <- rnorm(nobs, mean = mu, sd = sigma) ytrue <- mu data <- data.frame(cbind(y,x, ytrue)) alldata <- cbind(data, mu, sigma) odata <- alldata[order(alldata["x"]),] @ <>= data <- data.frame(x = numeric(0), x = numeric(0), x = numeric(0)) names(data) <- c("x","x","x") fig <- party( partynode(1L, split = partysplit(2L, breaks = 0.4), kids = list( partynode(2L, info = c( "n = 200", " True parameters: ", expression(mu == '4'), expression(sigma == '1') )), partynode(3L, split = partysplit(3L, breaks = 0.8), kids = list( partynode(4L, info = c( "n = 200", " True parameters: ", expression(mu == '12'), expression(sigma == '3') )), partynode(5L, info = c( "n = 100", " True parameters: ", expression(mu == '4'), expression(sigma == '3') )))))), data ) node_inner_ext <- function (obj, id = TRUE, pval = TRUE, abbreviate = FALSE, fill = "white", gp = gpar()) { meta <- obj$data nam <- names(obj) extract_label <- function(node) { if (is.terminal(node)) return(rep.int("", 2L)) varlab <- character_split(split_node(node), meta)$name if (abbreviate > 0L) varlab <- abbreviate(varlab, as.integer(abbreviate)) if (pval) { nullna <- function(x) is.null(x) || is.na(x) pval <- suppressWarnings(try(!nullna(info_node(node)$p.value), silent = TRUE)) pval <- if (inherits(pval, "try-error")) FALSE else pval } if (pval) { pvalue <- node$info$p.value plab <- ifelse(pvalue < 10^(-3L), paste("p <", 10^(-3L)), paste("p =", round(pvalue, digits = 3L))) } else { plab <- "" } return(c(varlab, plab)) } maxstr <- function(node) { lab <- extract_label(node) klab <- if (is.terminal(node)) "" else unlist(lapply(kids_node(node), maxstr)) lab <- c(lab, klab) lab <- unlist(lapply(lab, function(x) strsplit(x, "\n"))) lab <- lab[which.max(nchar(lab))] if (length(lab) < 1L) lab <- "" return(lab) } nstr <- maxstr(node_party(obj)) if (nchar(nstr) < 6) nstr <- "aAAAAa" rval <- function(node) { node_vp <- viewport(x = unit(0.5, "npc"), y = unit(0.5, "npc"), width = unit(1, "strwidth", nstr) * 1.3, height = unit(3, "lines"), name = paste("node_inner", id_node(node), sep = ""), gp = gp) pushViewport(node_vp) xell <- c(seq(0, 0.2, by = 0.01), seq(0.2, 0.8, by = 0.05), seq(0.8, 1, by = 0.01)) yell <- sqrt(xell * (1 - xell)) xell <- xell*1.11 - 0.055 # to adapt size of the ellipse to the size with p-value lab <- extract_label(node) fill <- rep(fill, length.out = 2L) grid.polygon(x = unit(c(xell, rev(xell)), "npc"), y = unit(c(yell, -yell) + 0.5, "npc"), gp = gpar(fill = fill[1])) grid.text(lab[1L], y = unit(1.5 + 0.5, # to adapt position of x to its position with p-value "lines")) #grid.text(lab[1L], y = unit(1.5 + 0.5 * (lab[2L] != ""), # "lines")) grid.text(lab[2L], y = unit(1, "lines")) if (id) { nodeIDvp <- viewport(x = unit(0.5, "npc"), y = unit(1, "npc"), width = max(unit(1, "lines"), unit(1.3, "strwidth", nam[id_node(node)])), height = max(unit(1, "lines"), unit(1.3, "strheight", nam[id_node(node)]))) pushViewport(nodeIDvp) grid.rect(gp = gpar(fill = fill[2])) grid.text(nam[id_node(node)]) popViewport() } upViewport() } return(rval) } class(node_inner_ext) <- "grapcon_generator" @ \begin{frame}[fragile] \frametitle{Distributional trees} \vspace*{-0.12cm} \begin{center} DGP: $\; Y\ |\ X = x \; \sim \; \mathcal{N}(\mu(x), \sigma^2(x))$ \vspace*{-0.21cm} \setkeys{Gin}{width=0.58\linewidth} <>= par(mar=c(5.1,4.1,2.4,1.1)) plot(y=odata$y, x=odata$x, ylab = "y", xlab = "x", col = "gray") lines(x = odata$x, y = odata$mu, col = pal["forest"], lwd = 2.5, main = "") polygon(c(odata$x, rev(odata$x)), c(odata$mu + odata$sigma, rev(odata$mu - odata$sigma)), col = pallight["forest"], border = "transparent") legend("topleft", expression(mu %+-% sigma), bty = "n") @ \end{center} \end{frame} % \begin{frame} % \frametitle{Distributional trees} % \vspace*{-0.12cm} % \begin{center} % DGP: $\; Y\ |\ X = x \; \sim \; \mathcal{N}(\mu(x), \sigma^2(x))$ % % \vspace*{-0.21cm} % \setkeys{Gin}{width=0.5\linewidth} % <>= % paltrees <- rgb(c(0.97, 0.64, 1), c(0.70, 0.83, 1), c(0.30, 0.99, 1)) % plot(fig, inner_panel = node_inner_ext, % tp_args = list(FUN = identity, width = 18, fill = paltrees[c(1, 3)]), % ip_args = list(fill = paltrees[c(2, 3)]), % drop_terminal = TRUE, tnex = 1.7) % @ % \end{center} % \end{frame} <>= set.seed(7) nobs <- 500 x <- runif(nobs, 0, 1) mu <- sigma <- ytrue <- numeric(length = nobs) for(i in 1:nobs) sigma[i] <- if(x[i]<=0.4) 1 else 3 for(i in 1:nobs) mu[i] <- if(x[i]<= 0.4|| x[i]>0.8) 4 else 12 y <- rnorm(nobs, mean = mu, sd = sigma) #y <- rcnorm(nobs, mean = mu, sd = sigma, left = 0) ytrue <- mu data <- data.frame(cbind(y,x, ytrue)) tree <- disttree(y ~ x, data = data, family = NO(), type.tree = "mob") #tree <- disttree(y ~ x, data = data, family = dist_list_cens_normal) @ \begin{frame}[fragile] \frametitle{Distributional trees} \begin{center} \vspace*{-0.12cm} Model: \code{disttree(y ~ x)}\\ \vspace*{-0.2cm} \setkeys{Gin}{width=0.5\linewidth} <>= # function for output in terminal panels FUN <- function (x) { cf <- x$coefficients cf <- matrix(cf, ncol = 1, dimnames = list(names(cf), "")) c(sprintf("n = %s", x$nobs), "Estimated parameters:", parse(text = paste0("mu == '", format(round(cf[1], 2), nsmall = 2), "'")), parse(text = paste0("sigma == '", format(round(cf[2], 2), nsmall = 2), "'"))) } paltrees <- rgb(c(0.97, 0.64, 1), c(0.70, 0.83, 1), c(0.30, 0.99, 1)) ## plot version using FUN and tree of class 'disttree' plot(tree, drop = TRUE, tnex = 1.7, FUN = FUN, tp_args = list(fill = paltrees[c(1, 3)], width = 18), ip_args = list(fill = paltrees[c(2, 3)])) @ \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Distributional trees} \begin{center} \vspace*{-0.12cm} Model: \code{disttree(y ~ x)}\\ \vspace*{-0.2cm} \setkeys{Gin}{width=0.5\linewidth} <>= plot(as.constparty(tree), tnex = 1.7, drop = TRUE, tp_args = list(fill = paltrees[c(1, 3)], ylines = 1.5), ip_args = list(fill = paltrees[c(2, 3)])) @ \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Distributional trees} \begin{center} \vspace*{-0.12cm} Model: \code{disttree(y ~ x)}\\ \vspace*{-0.2cm} \setkeys{Gin}{width=0.5\linewidth} <>= node_density <- function (tree, xscale = NULL, yscale = NULL, horizontal = FALSE, main = "", xlab = "", ylab = "Density", id = TRUE, rug = TRUE, fill = paltrees[c(1, 3)], col = "black", lwd = 0.5, ...) { yobs <- tree$data[,as.character(tree$info$formula[[2]])] ylines <- 1.5 if (is.null(xscale)) xscale <- c(-5.1,22.5) if (is.null(yscale)) yscale <- c(-0.05,0.45) xr <- xscale yr <- yscale if (horizontal) { yyy <- xscale xscale <- yscale yscale <- yyy } rval <- function(node) { yrange <- seq(from = -20, to = 90)/4 ydens <- node$info$object$ddist(yrange) top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, widths = unit(c(ylines, 1, 1), c("lines", "null", "lines")), heights = unit(c(1, 1), c("lines", "null"))), width = unit(1, "npc"), height = unit(1, "npc") - unit(2, "lines"), name = paste("node_density",node$id, sep = "")) pushViewport(top_vp) grid.rect(gp = gpar(fill = "white", col = 0)) top <- viewport(layout.pos.col = 2, layout.pos.row = 1) pushViewport(top) mainlab <- paste(ifelse(id, paste("Node", node$id, "(n = "), "n = "), node$info$nobs, ifelse(id, ")", ""), sep = "") grid.text(mainlab) popViewport() plot <- viewport(layout.pos.col = 2, layout.pos.row = 2, xscale = xscale, yscale = yscale, name = paste("node_density", node$id, "plot", sep = "")) pushViewport(plot) yd <- ydens xd <- yrange if (horizontal) { yyy <- xd xd <- yd yd <- yyy yyy <- xr xr <- yr yr <- yyy rxd <- rep(0, length(xd)) ryd <- rev(yd) } else { rxd <- rev(xd) ryd <- rep(0, length(yd)) } if (rug) { nodeobs <- node$info$object$y if (horizontal) { grid.rect(x = xscale[1], y = nodeobs , height = 0, width = xscale[1], default.units = "native", just = c("right", "bottom"), gp = gpar(lwd = 2, col = gray(0, alpha = 0.18))) } else { grid.rect(x = nodeobs, y = yscale[1], width = 0, height = abs(yscale[1]), default.units = "native", just = c("center", "bottom"), gp = gpar(lwd = 2, col = gray(0, alpha = 0.18))) #grid.lines(x = xr, y = yr, gp = gpar(col = "lightgray"), # default.units = "native") #grid.lines(x = xr, y = yr, gp = gpar(col = "lightgray"), # default.units = "native") } } grid.polygon(x = c(xd, rxd), y = c(yd, ryd), default.units = "native", gp = gpar(col = "black", fill = fill, lwd = lwd)) #grid.lines(x = xd, y = yd, default.units = "native", # gp = gpar(col = col, lwd = lwd)) grid.xaxis() grid.yaxis() grid.rect(gp = gpar(fill = "transparent")) upViewport(2) } return(rval) } class(node_density) <- "grapcon_generator" plot(tree, tnex = 1.7, drop = TRUE, terminal_panel = node_density, tp_args = list(fill = paltrees[c(1, 3)]), ip_args = list(fill = paltrees[c(2, 3)])) @ \end{center} \end{frame} %\begin{frame} %\frametitle{Distributional trees} %\center %\vspace*{-1cm} %\setkeys{Gin}{width=0.8\linewidth} %\includegraphics{tree_box} %\end{frame} \begin{frame} \frametitle{Learning distributional trees and forests} \begin{minipage}{0.7\textwidth} {\bf Tree:} \begin{enumerate} \item<3-> Fit global distributional model $\mathcal{D}(Y; \theta)$: \\ % to the whole data set:\\ Estimate $\hat{\theta}$ via maximum likelihood \\ $\hat{\theta} = \argmax_{\theta \in \Theta} \sum_{i=1}^n \ell(\theta; y_i)$ \item<8-> Test for associations/instabilities of the \\ scores $\frac{\partial \ell}{\partial \theta}(\hat{\theta};y_i)$ and each possible split variable $X_j$. \end{enumerate} \end{minipage} \begin{minipage}{0.23\textwidth} %\vspace{-0.1cm} \begin{tikzpicture} \visible<2-3>{ \node[ellipse, fill=HighlightBlue!70, align=center, scale = 0.7, minimum width=60pt, minimum height = 30pt] (n0) at (0.8, 1.7) {$Y$}; } \visible<4>{ \node[ellipse, fill=HighlightBlue!70, align=center, scale = 0.7, minimum width=60pt, minimum height = 30pt] (n0) at (0.8, 1.7) {$\mathcal{D}(Y;\hat{\theta}$)}; } \visible<5>{ \node[inner sep=0pt] (density_all) at (0.8, 1.7) {\includegraphics[width=0.7\textwidth]{density_all}}; } \visible<6->{ \node[inner sep=0pt] (density_all) at (0.8, 1.7) {\includegraphics[width=0.7\textwidth]{density_all_hist}}; } \visible<7-9>{ \node[rectangle, fill=HighlightOrange!70, align=center, scale = 0.7, minimum width=50pt, minimum height = 20pt] (n1) at (0, 0.2) {?}; \node[rectangle, fill=HighlightOrange!70, align=center, scale = 0.7, minimum width=50pt, minimum height = 20pt] (n2) at (1.6, 0.2) {?}; \draw[-, gray, line width=0.5pt] (0.7, 1.16) -- (n1); \draw[-, gray, line width=0.5pt] (0.9, 1.16) -- (n2); } \visible<10-11>{ \node[rectangle, fill=HighlightOrange!70, align=center, scale = 0.7, minimum width=50pt, minimum height = 20pt] (n1) at (0, 0.2) {$Y_1$}; \node[rectangle, fill=HighlightOrange!70, align=center, scale = 0.7, minimum width=50pt, minimum height = 20pt] (n2) at (1.6, 0.2) {$Y_2$}; \draw[-, gray, line width=0.5pt] (0.7, 1.16) -- (n1) node [midway, left] {\scriptsize $X \leq p$}; \draw[-, gray, line width=0.5pt] (0.9, 1.16) -- (n2) node [midway, right] {\scriptsize $X > p$}; } \visible<12>{ \node[rectangle, fill=HighlightOrange!70, align=center, scale = 0.7, minimum width=50pt, minimum height = 20pt] (n1) at (0, 0.2) {$\mathcal{D}(Y_1;\hat{\theta}_1$)}; \node[rectangle, fill=HighlightOrange!70, align=center, scale = 0.7, minimum width=50pt, minimum height = 20pt] (n2) at (1.6, 0.2) {$\mathcal{D}(Y_2;\hat{\theta}_2$)}; } \visible<12->{ \draw[-, gray, line width=0.5pt] (0.7, 1.16) -- (n1) node [midway, left] {\scriptsize $X \leq p$}; \draw[-, gray, line width=0.5pt] (0.9, 1.16) -- (n2) node [midway, right] {\scriptsize $X > p$}; } \visible<13->{ \node[inner sep=0pt] (density_1_hist) at (-0.2,-0.04) {\includegraphics[width=0.6\textwidth]{density_2_hist}}; } \visible<13->{ \node[inner sep=0pt] (density_2_hist) at (1.8,-0.04) {\includegraphics[width=0.6\textwidth]{density_1_hist}}; } \end{tikzpicture} \end{minipage} \vspace{0.1cm} %\begin{adjustwidth}{-0.0em}{-1em} \begin{enumerate} \setcounter{enumi}{2} \item<9-> Split along the covariate $X$ with strongest association or instability \\ and at breakpoint $p$ with highest improvement in log-likelihood. \item<11-> Repeat steps 1--3 recursively until some stopping criterion \\ is met, yielding $B$ subgroups $\mathcal{B}_b$ with $b = 1, \dots, B$. \end{enumerate} %\end{adjustwidth} \vspace{0.4cm} \visible<14->{ {\bf Forest:} Ensemble of $T$ trees. \begin{itemize} \item Bootstrap or subsamples. \item Random input variable sampling. \end{itemize} } \end{frame} \begin{frame}[fragile] \frametitle{Weather forecasting} \textbf{Goal:} \medskip \begin{center} \begin{tikzpicture} \draw[->] (0.4,0)--(0.9,0); \draw[] (1,-0.4) rectangle (2.5,0.4); \node[font=\scriptsize] at (1.75,0) {nature}; \draw[->] (2.6,0)--(3.1,0); \visible<1>{% \node[] at (0.0,0) {X}; \node[] at (3.5,0) {Y};} \visible<2->{% \node[inner sep=0pt] (today) at (-2.3,-0.4) {\includegraphics[width=.365\textwidth]{airport_20200412.jpg}}; \node[font=\scriptsize] at (-2.3,-2.4) {2020-04-12}; \node[inner sep=0pt] (future) at (5.8,-0.4) {\includegraphics[width=.365\textwidth]{airport_20200413.jpg}}; \node[font=\scriptsize] at (5.8,-2.4) {2020-04-13};} \end{tikzpicture} \end{center} %% https://innsbruck-airport.panomax.com/ \only<1-2>{% \textbf{Data:} \begin{itemize} \item X: State of the atmosphere now (temperature, precipitation, wind, \dots). \item Y: State of the atmosphere in the future (hours, days, weeks, \dots). \end{itemize}}% \only<3->{% \textbf{Two stages:} \begin{itemize} \item Physical model: Numerical weather prediction (NWP). \item Statistical model: Model output statistics (MOS). \end{itemize}} \end{frame} % \begin{frame}[fragile] % \frametitle{Weather forecasting} % % \textbf{Numerical weather prediction (NWP):} % \begin{itemize} % \item Based on a physical model. % \item Massive numerical simulation of atmospheric processes. % \item Here: Global model on a $50\times 50 \text{ km}^2$ grid. % \end{itemize} % % \medskip % % \textbf{Problem:} Uncertain initial conditions, unresolved processes. % % \medskip % % \textbf{Solution:} Ensemble of simulation runs under perturbed conditions. % % \end{frame} % % % % <>= % library("zoo") % % Sys.setenv("TZ"="UTC") % % # ------------------------------------------------------------------- % # GFS ensemble forecast % # ------------------------------------------------------------------- % % GFS <- read.table("Data/GENS_00_innsbruck_20200412.dat", header = TRUE) % init <- min(as.POSIXct(GFS$timestamp-GFS$step*3600,origin="1970-01-01")) % title <- sprintf("%s\n%s", % "Global Forecast System (GFS) Ensemble Forecast for Innsbruck, Airport", % sprintf("Forecast initialized %s", strftime(init, "%Y-%m-%d %H:%M UTC"))) % % # observations % load("Data/STAGEobs_tawes_11121_defense.rda") % #load("Data/STAGEobs_tawes_11121.rda") % # "2018-03-14 00:00:00" in line 321 (first entry for temperature) % # "2018-03-13 06:00:00" in line 317 (first entry for rain -> aggregated to 24h sums) % # "2018-03-23 00:00:00" in line 357 % % getZoo <- function( x, variable ) { % x <- subset( x, varname == variable ) % if ( nrow(x) == 0 ) stop("Ups, variable seems not to exist at all!") % # Else create zoo % x <- zoo( subset(x,select=-c(varname,timestamp,step)), % as.POSIXct(x$timestamp,origin="1970-01-01") ) % x % } % GFS_t2m <- getZoo( GFS, "tmp2m" ) - 273.15 % # temperature bias: model simulates temperature for height 1675 (~1070 m higher than true height) % # => add 10.7 degrees to account for bias (approx. 1 degree / 100 m) % # Custom bias % GFS_t2m <- GFS_t2m + 6.5 % % # Subsetting obs % obs <- subset(obs, index(obs) %in% index(GFS_t2m)) % % GFS_t2m <- merge(GFS_t2m, obs = obs[, grep("tl", names(obs))]) % ###GFS_t2m$obs <- obs[,"obs$tl"] % # first value of rain is 18 hours later than temperature % #(both start at 6:00 but rain is cumulated over 24 hours) % # -> drop first 3 values of temperature % GFS_t2m <- GFS_t2m[-c(1:3),] % % GFS_rain <- getZoo( GFS, "apcpsfc" ) % GFS_rain$obs <- obs[,"rr6"] % # precipitaion sums over 24 hours (00:00 UTC - 00:00 UTC +1day) % GFS_rain24 <- GFS_rain[c((1:10)*4),] % for(i in 1:NROW(GFS_rain24)){ % GFS_rain24[i,] <- colSums(GFS_rain[c((4*i-3):(4*i)),]) % } % % % # Two POSIXct vectors for the axis % main <- seq(min(as.POSIXct(as.Date(index(GFS_t2m)))),max(index(GFS_t2m)),by=86400) % minor <- seq(min(index(GFS_t2m)),max(index(GFS_t2m)),by=3*3600) % % # GFS_t2m_mean <- rowMeans(GFS_t2m) % GFS_t2m_mean <- GFS_t2m % GFS_t2m_mean[,1] <- rowMeans(GFS_t2m[,-NCOL(GFS_t2m)]) % GFS_t2m_mean <- GFS_t2m_mean[,1] % % # GFS_rain_mean <- rowMeans(GFS_rain) % GFS_rain24_mean <- GFS_rain24 % GFS_rain24_mean[,1] <- rowMeans(GFS_rain24[,-NCOL(GFS_rain24)]) % GFS_rain24_mean <- GFS_rain24_mean[,1] % @ % % <>= % par(mar=c(0.4,0,0.2,0), oma=c(6,3.2,5,4)) % layout( matrix(1:2,ncol=1) ) % plot(GFS_t2m[,1], screen=1, xaxs="i", xaxt="n", ylim = range(GFS_t2m, na.rm = TRUE)*1.05, col = "slategray" ) % abline(v = main, lty = 2 ) % mtext(side = 3, line = 1, cex = 1.2, font = 2, title ) % mtext(side = 2, line = 2.3, cex = 1, font = 1, text = "Temperature [°C]" ) % @ % % <>= % plot(GFS_rain24[,1], screen=1, xaxs="i", xaxt="n", yaxs="i", ylim=range(GFS_rain24, na.rm = TRUE)*c(0,1.05), col = "slategray" ) % abline(v = main, lty = 2 ) % mtext(side = 2, line = 2.3, cex = 1, font = 1, text = "Rain [mm/6h]" ) % axis(side = 1, at = main + 42300, strftime(main,"%b %d"), % line = 0, col.ticks=NA, col.axis="gray30", col = NA ) % @ % % \begin{frame}[fragile] % \frametitle{Weather forecasting} % % \vspace{-0.6cm} % \setkeys{Gin}{width=0.95\linewidth} % \begin{center} % \only<1>{% % <>= % <> % <> % @ % }% % \only<2>{% % <>= % <> % lines(GFS_t2m[,3], col = "slategray") % <> % lines(GFS_rain24[,3], col = "slategray") % @ % }% % \only<3>{% % <>= % <> % lines(GFS_t2m[,2], col = "slategray") % lines(GFS_t2m[,3], col = "slategray") % <> % lines(GFS_rain24[,2], col = "slategray") % lines(GFS_rain24[,3], col = "slategray") % @ % }% % \only<4>{% % <>= % <> % for(j in 2:(NCOL(GFS_t2m) - 1)) lines(GFS_t2m[,j], col = "slategray") % <> % for(j in 2:(NCOL(GFS_rain24) - 1)) lines(GFS_rain24[,j], col = "slategray") % @ % }% % \only<5>{% % <>= % <> % for(j in 2:(NCOL(GFS_t2m) - 1)) lines(GFS_t2m[,j], col = "slategray") % lines(GFS_t2m[,"obs"], col = 2, lwd = 2.3) % <> % for(j in 2:(NCOL(GFS_rain24) - 1)) lines(GFS_rain24[,j], col = "slategray") % lines(GFS_rain24[,"obs"], col = 2, lwd = 2.3) % @ % }% % \end{center} % % \end{frame} \begin{frame}[fragile] \frametitle{Weather forecasting: precipitation} \textbf{Goal:} Predict daily precipitation amount in Tyrol. %complex terrain. \bigskip \pause \textbf{Observation data:} National Hydrographical Service. \begin{itemize} \item Daily 24h precipitation sums from July over 28 years (1985--2012). \item 95 observation stations in Tyrol. \end{itemize} \bigskip \pause \textbf{Numerical weather prediction:} Global Ensemble Forecast System. \begin{itemize} \item Model outputs: Precipitation, temperature, air pressure, convective available potential energy, downwards short wave radiation flux, \dots \item 80 covariates based on ensemble min/max/mean/standard deviation. \end{itemize} \bigskip \pause \textbf{Distribution assumption:} Power-transformed Gaussian, censored at 0. \[ (\text{precipitation})^\frac{1}{1.6} \sim \textit{c}\mathcal{N}(\mu,\sigma^2) \] \end{frame} %% \begin{frame} %% \frametitle{Weather forecasting: precipitation} %% %% \textbf{Base variables:} %% \begin{itemize} %% \item Total precipitation. %% \item Convective available potential energy. %% \item Downwards short wave radiation flux (``sunshine''). %% \item Mean sea level pressure. %% \item Preciptable water. %% \item 2m maximum temperature. %% \item Total column-integrated condensate. %% \item Temperature. %% \item Temperature differences in altitude. %% \end{itemize} %% %% \medskip %% %% \textbf{Variations:} 80 covariates based on ensemble min/max/mean/standard deviation. %% %% \end{frame} <>= if(file.exists("Data/Axams_pred.rda") & file.exists("Data/Axams_testdata.rda")){ load("Data/Axams_pred.rda") load("Data/Axams_testdata.rda") } else { ##### # load observations and covariates data("RainAxams") # tree and forest formula { dt.formula <- df.formula <- robs ~ tppow_mean + tppow_sprd + tppow_min + tppow_max + tppow_mean0612 + tppow_mean1218 + tppow_mean1824 + tppow_mean2430 + tppow_sprd0612 + tppow_sprd1218 + tppow_sprd1824 + tppow_sprd2430 + capepow_mean + capepow_sprd + capepow_min + capepow_max + capepow_mean0612 + capepow_mean1218 + capepow_mean1224 + capepow_mean1230 + capepow_sprd0612 + capepow_sprd1218 + capepow_sprd1224 + capepow_sprd1230 + dswrf_mean_mean + dswrf_mean_max + dswrf_sprd_mean + dswrf_sprd_max + msl_mean_mean + msl_mean_min + msl_mean_max + msl_sprd_mean + msl_sprd_min + msl_sprd_max + pwat_mean_mean + pwat_mean_min + pwat_mean_max + pwat_sprd_mean + pwat_sprd_min + pwat_sprd_max + tmax_mean_mean + tmax_mean_min + tmax_mean_max + tmax_sprd_mean + tmax_sprd_min + tmax_sprd_max + tcolc_mean_mean + tcolc_mean_min + tcolc_mean_max + tcolc_sprd_mean + tcolc_sprd_min + tcolc_sprd_max + t500_mean_mean + t500_mean_min + t500_mean_max + t700_mean_mean + t700_mean_min + t700_mean_max + t850_mean_mean + t850_mean_min + t850_mean_max + t500_sprd_mean + t500_sprd_min + t500_sprd_max + t700_sprd_mean + t700_sprd_min + t700_sprd_max + t850_sprd_mean + t850_sprd_min + t850_sprd_max + tdiff500850_mean + tdiff500850_min + tdiff500850_max + tdiff700850_mean + tdiff700850_min + tdiff700850_max + tdiff500700_mean + tdiff500700_min + tdiff500700_max + msl_diff } # learning data: 24 years (1985 - 2008, both inlcuded) # testing data: 4 successive years (2009, 2010, 2011, 2012) learndata <- RainAxams[RainAxams$year < 2009,] testdata <- RainAxams[RainAxams$year %in% c(2009, 2010, 2011, 2012),] save(file = "Data/Axams_testdata.rda", testdata) ############################################################## # fitting the models set.seed(7) df <- distforest(df.formula, data = learndata, family = dist_list_cens_normal, ntree = 100, censtype = "left", censpoint = 0, control = disttree_control(teststat = "quad", testtype = "Univ", type.tree = "ctree", intersplit = TRUE, mincriterion = 0, minsplit = 50, minbucket = 20), mtry = 27) #### prepare data for plot of estimated density functions # predictions for one day (in each of the four years) # (19th of July 2011 is missing) pday <- 24 # 2 (hohe Beobachtung zu niedrig geschaetzt), 4, 15, evtl. auch 7, 8, 23 (eine 0-Beobachtung und 2 sehr aehnliche), pdays <- if(pday<19) c(pday, pday + 31, pday + 62, pday + 92) else c(pday, pday + 31, pday + 61, pday + 92) pdf <- predict(df, newdata = testdata[pdays,], type = "parameter") pdf$pdays <- pdays save(file = "Data/Axams_pred.rda", pdf) } pdays <- pdf$pdays pday <- pdays[1] df_mu <- pdf$mu df_sigma <- pdf$sigma # plot predicted distributions together with observations set.seed(7) x <- c(0.01, sort(runif(500,0.01,8))) y1 <- crch::dcnorm(x, mean = df_mu[1], sd = df_sigma[1], left = 0) y2 <- crch::dcnorm(x, mean = df_mu[2], sd = df_sigma[2], left = 0) y3 <- crch::dcnorm(x, mean = df_mu[3], sd = df_sigma[3], left = 0) y4 <- crch::dcnorm(x, mean = df_mu[4], sd = df_sigma[4], left = 0) # switch x-axis back to untransformed scale # x <- x^(1.6) # point mass (slightly shifted) pm1 <- c(0.05, crch::dcnorm(-1, mean = df_mu[1], sd = df_sigma[1], left = 0)) # 0.15 pm2 <- c(0.01, crch::dcnorm(-1, mean = df_mu[2], sd = df_sigma[2], left = 0)) # 0.05 pm3 <- c(-0.03, crch::dcnorm(-1, mean = df_mu[3], sd = df_sigma[3], left = 0)) # -0.05 pm4 <- c(-0.07, crch::dcnorm(-1, mean = df_mu[4], sd = df_sigma[4], left = 0)) # -0.15 # predictions pred1 <- c(testdata[pdays,"robs"][1], # ^(1.6), crch::dcnorm(testdata[pdays,"robs"][1], mean = df_mu[1], sd = df_sigma[1], left = 0)) pred2 <- c(testdata[pdays,"robs"][2], # ^(1.6), crch::dcnorm(testdata[pdays,"robs"][2], mean = df_mu[2], sd = df_sigma[2], left = 0)) pred3 <- c(testdata[pdays,"robs"][3], # ^(1.6), crch::dcnorm(testdata[pdays,"robs"][3], mean = df_mu[3], sd = df_sigma[3], left = 0)) pred4 <- c(testdata[pdays,"robs"][4], # ^(1.6), crch::dcnorm(testdata[pdays,"robs"][4], mean = df_mu[4], sd = df_sigma[4], left = 0)) #legendheight lh1 <- crch::dcnorm(0.01, mean = df_mu[1], sd = df_sigma[1], left = 0) lh2 <- crch::dcnorm(0.01, mean = df_mu[2], sd = df_sigma[2], left = 0) lh3 <- crch::dcnorm(0.01, mean = df_mu[3], sd = df_sigma[3], left = 0) lh4 <- crch::dcnorm(0.01, mean = df_mu[4], sd = df_sigma[4], left = 0) @ \begin{frame}[fragile] \frametitle{Weather forecasting: precipitation} \textbf{Application for one station:} Axams. \begin{itemize} %\vspace{-0.05cm} \item Learn forest model on data from 24 years (1985--2008). %\vspace{-0.05cm} \item Evaluate on 4 years (2009--2012). Here: July \Sexpr{24}. \end{itemize} \vspace*{-0.4cm} \begin{center} \setkeys{Gin}{width=0.54\textwidth} <>= par(mar = c(4, 4, 1, 1)) plot(x = x, y = y1, type = "l", col = 2, ylab = "Density", lwd = 2, # xlab = expression(Total~precipitation~"["~mm~"/"~"24h"~"]"), xlab = expression(Total~precipitation~"["~mm^(1/1.6)~"/"~"24h"~"]"), ylim = c(0,max(y1, y2, y3, y4, pm1, pm2, pm3, pm4) + 0.01), xlim = c(-1.5,8)) # xlim = c(-2,28)) lines(x = x, y = y2, type = "l", lwd = 2, col = 4) lines(x = x, y = y3, type = "l", lwd = 2, col = 3) lines(x = x, y = y4, type = "l", lwd = 2, col = 6) legend('topright', c("Predicted distribution", "Point mass at censoring point", "Observation"), bty = "n", col = "black", lty = c(1, NA, NA), pch = c(NA, 19, 4), cex = 1) # plot point mass lines(x = c(pm1[1], pm1[1]), y = c(pm1[2], 0), col = 2, type = "l", lwd = 2) lines(x = c(pm2[1], pm2[1]), y = c(pm2[2], 0), col = 4, type = "l", lwd = 2) lines(x = c(pm3[1], pm3[1]), y = c(pm3[2], 0), col = 3, type = "l", lwd = 2) lines(x = c(pm4[1], pm4[1]), y = c(pm4[2], 0), col = 6, type = "l", lwd = 2) points(x = pm1[1], y = pm1[2], col = 2, pch = 19, cex = 1.4) points(x = pm2[1], y = pm2[2], col = 4, pch = 19, cex = 1.4) points(x = pm3[1], y = pm3[2], col = 3, pch = 19, cex = 1.4) points(x = pm4[1], y = pm4[2], col = 6, pch = 19, cex = 1.4) # plot predictions points(x = pred1[1], y = pred1[2], col = 2, pch = 4, cex = 1.4, lwd = 2) points(x = pred2[1], y = pred2[2], col = 4, pch = 4, cex = 1.4, lwd = 2) points(x = pred3[1], y = pred3[2], col = 3, pch = 4, cex = 1.4, lwd = 2) points(x = pred4[1], y = pred4[2], col = 6, pch = 4, cex = 1.4, lwd = 2) lines(x = c(pred1[1], pred1[1]), y = c(pred1[2], 0), col = "darkgray", type = "l", lty = 2, lwd = 2) lines(x = c(pred2[1], pred2[1]), y = c(pred2[2], 0), col = "darkgray", type = "l", lty = 2, lwd = 2) lines(x = c(pred3[1], pred3[1]), y = c(pred3[2], 0), col = "darkgray", type = "l", lty = 2, lwd = 2) lines(x = c(pred4[1], pred4[1]), y = c(pred4[2], 0), col = "darkgray", type = "l", lty = 2, lwd = 2) # add labels text(x = -0.8, y = lh1, labels = "2009", col = 2, cex = 1) # -1.7 text(x = -0.8, y = lh2, labels = "2010", col = 4, cex = 1) # -1.7 text(x = -0.8, y = lh3, labels = "2011", col = 3, cex = 1) # -1.7 text(x = -0.8, y = lh4, labels = "2012", col = 6, cex = 1) # -1.7 @ \end{center} \only<2>{ \vspace{-0.5cm} {\small Replication: \texttt{demo("RainAxams", package = "disttree")}} } \end{frame} % \begin{frame}[fragile] % \frametitle{Weather forecasting: precipitation} % % \textbf{Application for one station:} Axams. % \begin{itemize} % %\vspace{-0.05cm} % \item Learn forest model on data from 24 years. % %\vspace{-0.05cm} % \item Evaluate on 4 years. % %\vspace{-0.05cm} % \item 10 times 7-fold cross validation. % \end{itemize} % % \bigskip % % \textbf{Benchmark:} Against other heteroscedastic censored Gaussian models. % \begin{itemize} % \item \emph{Ensemble MOS:} Linear predictors using only total precipitation. % \item \emph{Prespecified GAMLSS:} Variable selection based on expert knowledge. % \item \emph{Boosted GAMLSS:} Automatic variable selection. % \end{itemize} % % \bigskip % % \textbf{Evaluation:} Continuous ranked probability skill score. % % %% \vspace{0.1cm} % %% \begin{table}[t!] % %% \footnotesize % %% % %% \hskip-0.4cm\begin{tabular}{ l l l } % %% \hline % %% Model & Type & Variable Selection \\ % %% \hline % %% \vspace{-0.15cm} % %% \textbf{Distributional forest} & recursive & automatic \\ % %% & partitioning & \\ % %% \vspace{-0.15cm} % %% \textbf{Prespecified GAMLSS} & spline & based on expert \\ % %% & in each & knowledge \\ % %% \vspace{-0.15cm} % %% \textbf{Boosted GAMLSS} & spline & automatic \\ % %% & in each & \\ % %% \vspace{-0.15cm} % %% \textbf{EMOS} & linear & total precipitation mean \\ % %% & & and standard deviation \\ % %% \hline % %% \end{tabular} % %% \end{table} % % \end{frame} % % % % % <>= % #### cross validation rain % if(file.exists("Data/crps_cross.rda")){ % load("Data/crps_cross.rda") % } else { % % nrep_cross <- 10 % seed <- 7 % % res_cross <- mclapply(1:nrep_cross, % function(i){ % % set.seed(seed*i) % % # randomly split data in 7 parts each including 4 years % years <- 1985:2012 % testyears <- list() % for(j in 1:7){ % testyears[[j]] <- sample(years, 4, replace = FALSE) % years <- years[!(years %in% testyears[[j]])] % } % % #crps <- matrix(nrow = 7, ncol = 7) % reslist <- list() % for(k in 1:7){ % test <- testyears[[k]] % train <- c(1985:2012)[!c(1985:2012) %in% test] % % res <- evalmodels(station = "Axams", % train = train, % test = test, % gamboost_cvr = TRUE) % % #crps[k,] <- res$crps % reslist[[k]] <- res % } % % #colnames(crps) <- names(res$crps) % return(reslist) % }, % mc.cores = detectCores() - 1 % ) % % # extract CRPS % crps_cross <- matrix(nrow = nrep_cross, ncol = 7) % # loop over all repetitions % for(i in 1:length(res_cross)){ % #loop over all 7 folds (for 7 methods) % crps_cross_int <- matrix(nrow = length(res_cross[[1]]), ncol = 7) % for(j in 1:length(res_cross[[1]])){ % crps_cross_int[j,] <- res_cross[[i]][[j]]$crps % } % crps_cross[i,] <- colMeans(crps_cross_int, na.rm = TRUE) % } % colnames(crps_cross) <- names(res_cross[[1]][[1]]$crps) % % save(crps_cross, file = "Data/crps_cross.rda") % } % @ % % % % % \begin{frame}[fragile] % \frametitle{Weather forecasting: precipitation} % \begin{center} % \vspace*{-0.2cm} % \setkeys{Gin}{width=0.65\textwidth} % <>= % #par(mar = c(2.5,2,1,2)) % boxplot(1 - crps_cross[,c(2,3,4)] / crps_cross[,6], ylim = c(-0.005, 0.065), % names = c("Distributional forest", "Prespecified GAMLSS", "Boosted GAMLSS"), % main = "Cross validation (with reference model EMOS)", % cex.main=1.4, % cex.lab=1.2, % ylab = "CRPS skill score", col = "lightgray") % abline(h = 0, col = pal["EMOS"], lwd = 2) % @ % \end{center} % \end{frame} % \begin{frame}[fragile] % \frametitle{Weather forecasting: precipitation} % %\vspace{0.2cm} % \textbf{Application for all 95 stations:} % \begin{itemize} % \item Learn forest model on data from 24 years (1985--2008). % \item Evaluate on 4 years (2009--2012). % \item Benchmark against other heteroscedastic censored Gaussian models. % \end{itemize} % % \end{frame} % % % <>= % #### prediction over all stations 24 - 4 % if(file.exists("Data/crps_24to4_all.rda")){ % load("Data/crps_24to4_all.rda") % } else { % % data("StationsTyrol") % stations <- StationsTyrol$name % test <- 2009:2012 % train <- 1985:2008 % % % res_24to4_all <- mclapply(1:length(stations), % function(i){ % % set.seed(7) % % res <- evalmodels(station = stations[i], % train = train, % test = test, % gamboost_cvr = TRUE) % % return(res) % }, % mc.cores = detectCores() - 1 % ) % % # extract crps % crps_24to4_all <- matrix(nrow = length(stations), ncol = 7) % # loop over all stations % for(i in 1:length(stations)){ % crps_24to4_all[i,] <- res_24to4_all[[i]]$crps % } % % colnames(crps_24to4_all) <- names(res_24to4_all[[1]]$crps) % rownames(crps_24to4_all) <- stations % % save(crps_24to4_all, file = "Data/crps_24to4_all.rda") % } % % % # skill score % s <- 1 - crps_24to4_all[, 2:4]/crps_24to4_all[,6] % colnames(s) <- c("Distributional forest", "Prespecified GAMLSS", "Boosted GAMLSS") % % % ## prepare data for map which shows where distforest performed better than gamlss or gamboostLSS based on the crps % % crps_map <- crps_24to4_all[,c("distforest", "gamlss", "gamboostLSS", "emos_log")] % % # best method % bst <- apply(crps_map, 1, which.min) % % # distance of forest to best other method % dst <- crps_map[,1] - crps_map[cbind(1:nrow(crps_map), apply(crps_map[, -1], 1, which.min) + 1)] % % # breaks/groups % brk <- c(-0.1, -0.05, -0.005, 0.005, 0.05, 0.1) % #brk <- c(-0.1, -0.05, -0.01, 0.01, 0.05, 0.1) % grp <- cut(dst, breaks = brk) % % # HCL colors (relatively flashy, essentially CARTO Tropic) % clr <- colorspace::diverging_hcl(5, h = c(130, 320), c = 70, l = c(50, 90), power = 1.3) % % % library("raster") # dem (digital elevation model) % library("sp") # gadm www.gadm.org/country % % data("StationsTyrol", package = "RainTyrol") % data("MapTyrol", package = "RainTyrol") % # data(MapTyrol_border, package = "RainTyrol") % # Create SpatialPointsDataFrame from station list % sp <- SpatialPointsDataFrame(subset(StationsTyrol, % select=c(lon,lat)), % data = subset(StationsTyrol, % select = -c(lon,lat)), % proj4string = crs(MapTyrol$RasterLayer)) % @ % % % \begin{frame}[fragile] % \frametitle{Weather forecasting: precipitation} % \begin{center} % \vspace*{-0.5cm} % % \setkeys{Gin}{width=0.84\textwidth} % <>= % % ## plot map of Tyrol with all 95 observations % layout(cbind(1, 2), width = c(9, 1)) % par(mar = c(5,4,4,0.1)) % raster::image(MapTyrol$RasterLayer, col = rev(gray.colors(100)), % main="Stations in Tyrol", ylab = "Latitude", xlab = "Longitude", % xlim = c(9.8,13.2), % ylim = c(46.6, 47.87)) % plot(MapTyrol$SpatialPolygons, add = TRUE) % points(sp[70,], pch = 19, col = "black", cex = 1.85) % points(sp, pch = c(21, 24, 25, 22)[bst], bg = clr[grp], col = "black", las = 1, cex = 1.5) % legend(x = 9.8, y = 47.815, pch = c(21, 24, 25, 22), legend = c("Distributional forest", "Prespecified GAMLSS", "Boosted GAMLSS", "EMOS"), cex = 1, bty = "n") % text(x = 10.3, y = 47.82, labels = "Models with lowest CRPS") % mtext("CRPS\ndifference", side=4, las = TRUE, at = c(x = 13.5, y = 47.76), line = 0.3) % par(mar = c(0.5,0.2,0.5,2.3)) % ## legend % plot(0, 0, type = "n", axes = FALSE, xlab = "", ylab = "", % xlim = c(0, 1), ylim = c(-0.2, 0.2), xaxs = "i", yaxs = "i") % rect(0, brk[-6], 0.5, brk[-1], col = rev(clr)) % axis(4, at = brk, las = 1, mgp=c(0,-0.5,-1)) % % % @ % \end{center} % \end{frame} % % % % \begin{frame}[fragile] % \frametitle{Weather forecasting: precipitation} % \begin{center} % \vspace*{-0.5cm} % % \setkeys{Gin}{width=0.47\textwidth} % <>= % % ## plot map of Tyrol with all 95 observations % layout(cbind(1, 2), width = c(9, 1)) % par(mar = c(5,4,4,0.1)) % raster::image(MapTyrol$RasterLayer, col = rev(gray.colors(100)), % main="Stations in Tyrol", ylab = "Latitude", xlab = "Longitude", % xlim = c(9.8,13.2), % ylim = c(46.6, 47.87)) % plot(MapTyrol$SpatialPolygons, add = TRUE) % points(sp[70,], pch = 19, col = "black", cex = 1.85) % points(sp, pch = c(21, 24, 25, 22)[bst], bg = clr[grp], col = "black", las = 1, cex = 1.5) % legend(x = 9.8, y = 47.815, pch = c(21, 24, 25, 22), legend = c("Distributional forest", "Prespecified GAMLSS", "Boosted GAMLSS", "EMOS"), cex = 1, bty = "n") % text(x = 10.3, y = 47.82, labels = "Models with lowest CRPS") % mtext("CRPS\ndifference", side=4, las = TRUE, at = c(x = 13.5, y = 47.76), line = 0.3) % par(mar = c(0.5,0.2,0.5,2.3)) % ## legend % plot(0, 0, type = "n", axes = FALSE, xlab = "", ylab = "", % xlim = c(0, 1), ylim = c(-0.2, 0.2), xaxs = "i", yaxs = "i") % rect(0, brk[-6], 0.5, brk[-1], col = rev(clr)) % axis(4, at = brk, las = 1, mgp=c(0,-0.5,-1)) % % % @ % \end{center} % \vspace{-0.2cm} % \textbf{Conclusions:} % \begin{itemize} % \item Distributional forests provide an easy-to-apply alternative to already existing methods. % \item Do not require expert knowledge for pre-specifications. % \item Competitive performance: mainly en par or even slightly better. % \end{itemize} % % \end{frame} \subsection{References} \begin{frame} \frametitle{References} \vspace{-0.2cm} \scriptsize Breiman L (2001). \dquote{Random {Forests}.} \emph{Machine Learning}, \textbf{45}(1), 5--32. \doi{10.1023/A:1010933404324} \medskip Breiman L, Cutler A (2004). \dquote{Random Forests.}, \url{https://www.stat.berkeley.edu/~breiman/RandomForests} (Accessed: 2018-02-22) \medskip %Hothorn T, Zeileis A (2017). % \dquote{Transformation Forests.} % \emph{arXiv 1701.02110}, arXiv.org E-Print Archive. % \url{http://arxiv.org/abs/1701.02110} % %\smallskip Hothorn T, Hornik K, Zeileis A (2006). \dquote{Unbiased Recursive Partitioning: A Conditional Inference Framework.} \emph{Journal of Computational and Graphical Statistics}, \textbf{15}(3), 651--674. \doi{10.1198/106186006X133933} \medskip Hothorn T, Zeileis A (2015). \dquote{{partykit}: A Modular Toolkit for Recursive Partytioning in \textsf{R}.} \emph{Journal of Machine Learning Research}, \textbf{16}, 3905--3909. \url{http://www.jmlr.org/papers/v16/hothorn15a.html} \medskip Liaw A, Wiener M (2002). \dquote{Classification and Regression by randomForest.} \emph{R News}, \textbf{2}(3), 18--22. \url{https://CRAN.R-project.org/doc/Rnews/} \medskip Wright M N, Ziegler A (2017). \dquote{{ranger}: A Fast Implementation of Random Forests for High Dimensional Data in {C++} and {R}.} \emph{Journal of Statistical Software}, \textbf{77}{1}, 1--17. \doi{10.18637/jss.v077.i01} \medskip % Zeileis A, Hothorn T, Hornik K (2008). % \dquote{Model-Based Recursive Partitioning.} % \emph{Journal of Computational and Graphical Statistics}, % \textbf{17}(2), 492--514. % \doi{10.1198/106186008X319331} % % \medskip Athey S, Tibshirani J, Wager S (2019). \dquote{Generalized Random Forests.} \emph{Annals of Statistics}, \textbf{47}{2}, 1148--1178. \doi{10.1214/18-AOS1709"} \medskip Schlosser L, Hothorn T, Stauffer R, Zeileis A (2019). \dquote{Distributional Regression Forests for Probabilistic Precipitation Forecasting in Complex Terrain.} \emph{The Annals of Applied Statistics}, \textbf{13}(3), 1564--1589. \doi{10.1214/19-AOAS1247} \end{frame} \end{document} partykit/inst/ULGcourse-2020/circtree_ibk.pdf0000644000176200001440000046402114172227777020476 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20191119111351) /ModDate (D:20191119111351) /Title (R Graphics Output) /Producer (R 3.6.1) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 153415 /Filter /FlateDecode >> stream xܽˮdu%8! B~ $TH*Ѐ"j*_,A?f{evNd5O&P~f2?_wxOsq_ך׿y>ǯƟ?| Tc\Ss}9 / d8yK\|}e"?||^+OƋ6x>n8~pky.̼mmehjos[||Q]\+_}6yds3~ʟ{|g//a.X/\6nk_-Zg>}Л_Akne77!nhnC\¦=Mmp>P6?on>OZ7yOs_]O %9b'}qfOoLsGXW/\]Ghvρ]whXC6 ݅XvCc5CzC|KpS n~/60>'ߓﺿ䁞OBm yH_􋯿CN7% e> IS/go?>ߣRX{nr "Ͽ/x|o߫ycpyy`%o7w};?4Em=;C/4 '?V`HX٧7r6raQTr0}e9p2'š()8C;iZ y )XrHSM&]!LFק`cq(!tqJ<ѧ)&vC@ǃ0?fQ)yƃ`$à ~AWO\S"./:1?SB!B.<ːy>T&~پ ŕRPϝܔϵC1؟wə]O F)R0Zm nOhqIXMCNgJx}oIiC]h_~f>S6ž7)iwʦ!Ԍ)bԾ6x^oYK ydS7 6nuOd&H>K{Ұj뙺={?R`R0 ; { qCd.2qҰ64V=a/S >! ֏d) Ǫo{>}ݟ`=zoc7)P^<[Ky֟p?ӵk)}P^/<_Ey`'Ţ_E7W⟻>1ܹiB.0 㰍MĚaa63I<l>O Pq0jgDO 2j"P0Lg]]I;MQ;Iu?0 S&GwCpɅArޛ7`w.8,b8I@<4?Ϡ8!>77AhC -M1qI/IbCХn8L5sSA;fXj`ӻa~(!bd}oH8E|F7~2Y`(0w6_$y<<2_ycKco\pn>:s@p' ôH}#}07}0֧\/a?x\^\M 6zo{X[u BkCS,!]E}j /T?-EZcxl" cG\'/mEFTua?e ~>ck'e=6zYLC^9KjcAga~'FTEhȋ&ۥ <O~HG~I)F .~؞?'g]_K$/”7z#OL+y}J_~OD7#~ao=1T?|? ?_}[@Y~FT ĹcWBj4դ!S|CD?;H0 )0P?F"mї'ڈ_A ~GzϏ0|;;/ <{ r=?_8۔|1OԏrpW߹7?kg_LAsmoWLpNw i;8UagIJ1ݯwLS7L go\h}7gn8~zZ ݯ&MS')pK1\>C5N\u w]?4&.ggn~idLtIS^Nf XNk`[x2\ G8eq-ћp1sΆ~ jω~aǹopc7}aDM\}жI8N}z(NX-j-ɰE ުEy+=yk4~3S;}s4gw4a|ڴYAEn{`ȠDZ8^{z񪯆dOw;.f#M{;qz)|'Ȫ"^u/11>Ϻ^E+zt ^EhAɈ~b4Ĕi:l CM \ρ!/gw`!aLb\$+0eyS֙Òuo^vK68es4 8e7d\`dE /eϛQ6ȪhxɢI/!nY4uM.l aˢdȢj8IM~ˢk~/YԹ z]-P!2ʪ+-L9q-<[[bh ^0Z[ z,gɋc'XKc).^{Uh=V=x!Y]{F3h'Νx%[ M?eKHԣ,;&MV51A+dD6 T s} ދS+:ƫ%3~)q&"Paobvpɻ)HրW6&`Yeڼ6_{V2Lٔ.K^\*⭩;dqǾ?k`~?oF%*tUi;\YX'FjYd5b_ s}4P'Z}bzg97%f<1i 1Y^;-lz7"[$˜٘L R,V`sO!6RȻ ܉!˳UUvt}q9sĠ*ٜO3_K`jt~)Vl*b޿ΐE6Tq& {g"8Bl+8nǘMXD% &8C IW{cZ#CeՍ O;0zoE 9=멻UEW٠$f57 'o)t&Z@9~9d [Qmסp&ND4zz>y=I r:mOp^My$쬈C̒m'6#.d\8\zM'B60~,^W K]ot*23Ĺ_SVȎ>_HS6:XUP ;+iK=͕Dl>Ac|#΋`Fϣp^J{}{o3 `~{vZ5x4@=h1;Qȶ{D=fvWIh\TB(e%cA>m.,5_d/u1}eu:iҝ vZVEF~AngJq=/[z?ѯL6KS'q&=B|&@6*&+l d6>ZVhpmqmC]l3r6p;8;+؜KH'쪥7 Ls@ l\zFÑWBa,z>?W&)\&U4iSX*֩>>kM*AFL=]U\J=00$`pG0 5YE SDxAy? ;G6TT!IH+a>*< ;Ӥ=W PS..6L0,іM׃ hI6=:l 3gqi\؍7>kNw{i}/*/Ik9UԓzkxjCW$"}H_?Im_>'FL.@|#vT) bznf)}_{a+\2~'ĭ_x#!v<֟=?Qv_D҅W=e|fdA EED ? 8ovЅ)I/@{I,䴳=tS,ɫ WPQNCqZ qkgF $w|6x6H:i 5HO;X[$^^$^ G!#'bMHyɤG|&){HK>KidU,M=bˇV OAٶhma"N> xS]p2qwk}Gƅ6_ nˎl#`{/;bBi^IٌT$DPf\Hk_N{,/x[xİ?rB0Dl]ů`kx)'V_w`t/FC}"zJ&& 3ҾkˀWfh\.?YZdqM+^X|.QG k\,zjvކ,sE9{:W$;  RGTv.!dː^[\E8w-]1p ]Eq(]ߑrNvM1]lB E8k]lj>ez^ʦ>8S.s S{}s" ;p7z^zy?DzDW}z] ;n`^/x(igVʾYN_><~7pZ>c^D>cD>蝁}Nb|;&p-{a'r^NZuҚ6@ClR>s]R8Lv4]9v: tP?[i`z:xf@ޔ6ߤSӵMs[ 5z].Lqg Κ0UWN2S򉗪mdBތ`L'wuFn8 J'@eȁ;#0fM5B=axӅB"Lj98}Nm-S4^gQp. &Rt^Iz^D\R[=ov z&v]\g\K{]}ٛm!H6pM!N e/,ju;4jiL>ڲJhӢYEjhcO!6 qwy46tGO {D0j4h(FBݣS*b5j_R/1{T"u"R5j}I j۩r!T6,6,h Xn0QTVau a< } e毈j k8ϛ=v߼vhv/W4UW+z[I ՞H_}]_؀`BgnvgnDX1#e/恛R!/+Ku0OKOhb!yEJ*"N7N :QQ!GFIϑSs/0?RM̊*hֆ.4vpVYaKhTVVRіsI{Um_flCM㺲%ح(QCo5^-\jna1!'^z+uԊ\ ة\DS#s-es[mQuIϦN hIEjUomZ@,8V֊p*ɢh" L.̣3M 3MYъ"(Gz9ĭ† ,t&bQ1N4Y١9<KfLWdm9؀ _fX$a[=` K,ufB5nB <ԠOt [Ҝ :^*et6!T^TZ9?3-*qEER1fs3*gH#45nҚQQaՊ,WkGEU&YėA!sO8G" 1#Ηːj2p0iIMĪY6k@J)BWvJ6k8KEߚfLh٭䗚0䇃a*j57fX /Sgjc²fئ5%SN1Rրr#44Aɚdf = s2!v%s(huYadVPwyUYtx#R]2h\m6|TVo0"31aZ3!eh>ϕD$n[TurTW[ f0V (;4nt6a{NWE{RUN≋eXE^3*t4BrJN#B*J64S*.ܚq-ƉV#X*#4-QcjԔ+s(d_̈́p\jԀ8=L%/4 o4]3䨼 +_am ̷I ٰy?ՆQ_Ƽ/= Bi~MIi|n|0bmdGn *1M7!rMRxQ_!(P1*W=P$|D|ԡZ,*'C.(LROL/7(B?9(q7 ei?:.s+ە0 WVaC R⫲߸i+A/7gnYff0-G\^o)3d Ou;UimK7hAD qt:REF| sNP"ȣ!!)͝kz&5c cZqu\gF 'N tQ tS+2&G &(;& B.aAcD(,G1qbbA1PٵBJz7b#XABF^*`3/@!-U<.Rm- ܫ0[01[cX-2aH׬DR`7ot&){۱ָcJc -y|3a 4.s [0gS"J3HFqbs<\αf]ݳA irxvRܙimẐa,77%M>vcC{hNjW,״Pg2m/ }{Yo;ߝ)bfkz :>^P)ch.o2"Ŋz;mbҤy%9X)ˬz@:KC E vinJZOƺ߹@;b1Fy:NJ eNX¡7|?Eu1zTR<6 N%z>]%:ҠykϧFݞ 139=C"6iA!pؙCT'0{Zw7Ÿ$,=![\ָFqXUwW҂M I`r7:,Պ _9d Z$0̥B6f !3dr+Y1&|khOBj̬%RI+yjLb_Lsd\%jfjcv`M(k< d?pՠ5(Pk nzm>;J33*EqqT̵ʀ}S5BnJCRG _S)5(\M]AZyXM!j˞,8l*JpSA|ەZaMr(;xU,7(UI7Uf7޶rNg9m^g2g2g]uo㳾ʑ}*E,RzLUN>;Վ(]3Yzj~L~M&~Mf~6xe^d,F!*)&W[ԃn,SĊ4)}?4hEnTk7GjySQZcYg⵳1ѓ啇m/dUzA+(Y<6F,6g˪Q۪Rwu;*d%bET~8U鋡=Y6МU9f*GNO~}Y+r޸ bDSW]ͫ7Հ웅Zɾw'jLfZ5Be%E5h-DVBS"X܍vFQ)z+2.Z(UeMc"~<[iNY&6xNEG+"EU+SV4H̆Kg,܇fTK au%{N5E$WUf7ָ<eeGA ޤ'@ TV3QtT_ܭYK6Fj =z"kW<IcyAakF=Dv4x7W(Aznf7VA|4ɯx4+{__1'=ٵvSd74XPdG/SP&\xҎPWG9έ򾈗jT'uumGj^b ~a)_SNUm`5W"ەXF֥4}`}=Fcߐ_ UHl_zJ: ުZk ײ?3:+:st:ʭHV^L0< nUm00_PkOOb&:T[hܸn;@!iUP%?a!*` MwjTILsO [H[bj%& UC5p ηUIfT5DÎj4NqbZ+IJ5hq5l9&=j&k3ԶA04bb0ᩬ d@T B_a鷩:WcBwM*0VشVZvTRJk(RI0Vg^zP;+-]czJ/d^*O͠9,vR PRGyJ춠kμ}\ B!K dg@Pl?|7ٛF.ä+LƜ+{ټ!s0c hObXw\1r \%e0r \ s-%0s> \35%U1s\ \<Ƹ%1 tz ]ѥE0tY.P왺ƓXk"/8khᕁ},U,ZI009Q$dAo! ֆBƥH"D^kq5O /DuxA&3`&ĥ/;X2ܡcG'\ntÙ˺he{c v̍^V=J/SG_M`50zy"ȼ^^ i/Ӷa?¬=mbV]+˫u.Z1) 38 ^`Du:j t:{uaA{Xt^yry))x' 89s,x\G8T}oٲ݂#?sVl'?/BTw\p:]A$:/ոŒ3ͫe` F.R#ELŒ0ㄦ~3wq 4 Ex؅F< CB`"OPm5{<2eȽd׮BU\ v­<DXO@-O/Q(˳O( EylJȤR.::,1ђfF*"N_4sHEP ΉT 4UOg5.] `GؗyY*!ᙯ5\R) wTyrǸ#RdzfNWa[s$R6՜k4@;7)Xe.Ye&@KOdh&<,;kl^Y.JXRkUU69S<`^<^<^<^U<^%妑Ҫ7eR݆rUnwWM6*f՛ ަpUo 9r}W-i 9Z]jy0 Wa%qճ`GX FI~u;y[!8[6>{%UCE(̎]4,II&ؔvٚȚbٌXx2ǭ)~,^< )B'*,2mfQ[V[(9;&lP*=`fL\Bj8T(\S#tRi(@ԍ*LOTήc>SL9H߭^"ƔTLUg&;Mc,etW×muhU捗Gfrt7q޸:8o\i750VcO]WכZl3W3ULoգc/gJ&>W/ iGu&nh^DFE7.F:G G;"HIeU\R?!s(gv/cbtefX휓?aDcW% &ْ LnB?g ir$hS:Oy/gF )T7a0=eo0YMK{e(>jdanJ؂"C&T٨lEw-L=1Ml\lMB^oC^ N)N DjX)s7a,5Q-u./,oz}I|I5]f$~~ea{gKɘ]`|\s 5Gx˞`G=Pp = 5{_HҰGA5)pK|cWf]>wX,<. 8e狹]'q~X7iBd=3S,"/\+P,s9V@j/gN_Nm+5 _b]b;ԕ-  ?]|bqIŦrutΡX&ХB1&.^N#>Nho&6c̑rc;V=q 6YK-wX1צ)`<=fWw\7&ݾtA=x ƗQbn^Rj)U8|?-o؈$o65ݎ7LgI7B.,6h0h'Z_,RqXC;`33jP2G "bnVj7fHY$XiW>Gؤf[;zZt;צ,Z8qVp0om9 KgxZ ZY_?\.vp\f,ޱY*%JTڐƙW_.C'T ݋<RBʼn{Qh훈+]Nxt. 5\gm: ("+Movl1ޘ^^ó=0,$SE.b%K(ɱLT#OA\#Kĩ8gPI}pU^)mLD"77SA05'a?$ҐlbqG@U2eYQCVmL ->@1[E3[[yl^bYgIq0=Xn Wz ;՜TZ[e!/i뤵7m[{}?OR5\ڊprE0@tr'{ͨ칶Gk(5(2'5,fu؈ 4 *E?SApXD-x!>BB8̬(P6::sТpLDZvB8?d73?ҒJ8،\u.n6Nf AY3YvGFrcjV涟 `,ZBG[,@ۥeYk oH27+<ޗguijXuW8(P툗">o(.o\C&_/z}ACՑS}Uc=q+4L/`kۻ?]:TҮdDG|O nMqߛ ]Ӈ)P+V,o܆eMBb)-Ajw g|d K$ӼB>iXm8y/OeO`qWpjzw u V[UN8;OuVQxվ"8Z Nt4V5l=ɗS#uOg/NW B8[dB^G^g v:I3=phHڽB~}7.iJ:`)|HHXCk KБXг⡥lw!ɋ7sV|f00}7i]H (W:DOOOCT Y˽o_nfI$㼴Gy>=nc8ͦwfy ;A˞r8b.Wd2q"uns`#_pgWG'O!c`Κ,cp6e?}& E%ե,%1ū=)k= Bo2uB]탚C:||zW*nwoP_f?qD;vM:.ϴ>909v4_1W-@:)xJˈ% wi{N̜*ef#{Ԏ/Y0;FTXlRpX83L$]pr7w`E!hcm %h|EJJڪ{em xVqۋGO)KGYZ\קgVmK |4<Ya*t!J򧻼;E*=ǽ)g.J|7ʒ Jݦ&./p %{g~!ОD:\z;ћ8>Bs ^\W1u.|;BW͇,"\rIvEx%B~L DM{eZLt~SZՋF)wH W5S1Vnj V!tسJ/~*ALP<}pXeWwvEձ hA"l0  y2Έ"ը4׹1Di/ I'?A @/lswK1=Cc)}Eyߟ>b w\YT[iɩXzQ7sͷaϟJa;U b# ,1Y J_H5Sr&L8^(wT-/eL*iw^ox?"S6liO-s*Btkl^.fjK1vvN՟L _=wW*Ou5b;d'}-{U֣sU9t}͢YkŹ:T[T]dGx9is>?EC}WnG{N`sj\_NG8EjNTx2҃cl(OCIN61NujP|~#:sǯ+Cs9 tC N{~P,O4WB͂GtPfB:ˏb^[˰ޯB}*Ozb(;MA;6g]sc%wiv;4ד0?ġN<rx!~z '!WjŲwjΉslC~{ /4N?5+"\r=94;$C3ՎS 9vއQr.;8dqzh<:8/TW*ߟE&%PI#_a}dQ.Wu)jW-zAyuv Y>0ژS1O;9OGގ@}0LCxNOˑWw\r,E4 Cko`x'~ɄX$w4rSֹ,7|By)P2\rw.@=V yeթ+S:Tp:ۼڟfN6,t34ߞ )a7cC,7 )/ټO jveo`5n瀯vjh r֗98:y'?<<0 ~.xcpN;WOdOov0FC"*nO5a/Wx*9&N=$r0#!tN~dfF:vv+BeԴ~/ ~my!=9s}w tq+1|H|灰?zi^Ѷ= $mXi?;G`7w hF BӡC:{9uĜcbWJs)t*{a{9҃s WEN#C^(?H?~61}{9oݪjbWvTJusϩC"CZw*=⣴Rީ}ґ1`ҋNQ3rͲMV/1W:_p s6w2ega2fmEJ^sGL?{a'e~~qH  SϝHmh{ػ{G~pR/OJC4I<9$QgT}^nK?;Mɻ]Q9yPN"1ꐑx4D :-@ۅ|>iqcؘZv|SATSrsBC1 ps1! MW_t=\"xq桍d{0^ϒ40pᅬ9وg:ZwG|%1RxhUkC}DCҳ :D)"@p#gɝb1f|tۈw8c9x`aْY{dilyo'BbP"E}疾r ԡ_tZ98#M邢: I{tj>v#]x @_cPK&f'czW߾7׿_};~_k~ǧ_iG/ W<9 ^_d}~mب?n/Vy1i \}-C^1SLס6S*0ocbO~fS%ލ[İp|!(a Sv*%~NNxmd*0V_jTm"q4%_'=B>սkj׃iU_2|~xy &o/{&?1?9蟵 ?pus=h.R79EQ7ƍm΋?΋_7"…?<lCI\À"<tқDE2M"z_R%4*Tm[hX▩ѻDH["i 외,[w?}OfC ưuI K ^4\Îf/%ّER5խ;&`[#VXíƠiy ݂coY3`A2mLM:Y\.ܗZ9Ksn¶ēgLɖ 2c۸9>l4hN 6`+LɺGp | ?]C4yTGǣ!'VaЬrz5)2Ot7\׌: {3mP٫XhA׷'y +J{ 5h>4}[TՃe Lޝ]ؾ?Wh#e=61FӬ,/;q`1,i[n]SSњ[GA0sb7ڎݪO3 Î3-JGte!dkYmuun 2vW%xt,-gBm#`[[/sUoEhHo 0n3A0} J{87xuwc5X{[VrS^g[.8Zy:[a 6ʚ̱(r5EϻbQ0 ŢYW6/8ZKy2pwb]:Mbzd%[\Cں 2%BD_=r.s$f2/J^̞&!Ind:2$E󖬑na]*FH[y+|&v_jR(lӝeBZyh5>%qn41,"Jh},&ˤZ4 ˦'Gj͉5M>ZU%KWXy0s1x]Vl e/6 kI,qS٨-pu- o-܁Zԍ.mo(%Ɋ~G%ڗz9̢xNӔQ-V&u\y} f!U 'ȷ<r#lrvڬ+s2}*1*0y**S6੤یR2OnsJ˰>NIt~*-cցT*[fmSpp&2n5O%e4>—y}@dގy@mS 2o;O> ?U6!SV'TE[9)Ol}Պ>U!6r,zڧM܎5~TEnmS.m%]Z\*k*m,SwE~DG99* zk|}HmSIr{oO6au=U%W69*9>J**R`V_T9B O)qkMa, ̓y N[sSEtRg=W "6iUçx}~s*Zt)}BŚ5UH}s0*u,\5{R1{s`*Bw\5ݧ=w hᅬ{ҪǙ"73^Oř֙_iO-n~jfrޢnf 1`x2h[@J`8lz<|(u;Xf-1nǔQiT1ܯ*ukؠ}yfM(vw*7 KALjoSuy<XOڝU ei$Vÿɪ6}zNUF3ɂ7m54A dk+[ϴCF9Lzl.9e,6&<;43,\:Rci_Hn`,4֭ 8GMɖݶ\ϡGuef K[G$K&sdmC欄iZ١ QSNMUE`iJKf6΂&UvRϸ^W5ftVKwzxVpR5U{VpaLjTW^p 6g{9JB0a*Er()PnrdMD k7Fxg˜q  MK SUbt[$~}^2Z%fsXLqYt~Rlc-,ߚ34rcԽV(`{KCVYb~JciXb*JA`PB4L!V4;ҹZ{||0K"???ro7>\ϣ{-̑_ ^?O7u1χX.ޘx)]>Gſ?o~'?4#LV 0``ss 'lnāw=_Q{k3Ue .J;le;/ï1Xaf#6q6u?;CT9V~Ǒ^33\8;6?[W|ƶ}6a06U ҋ3zAvag(L2%t,/6J%zt(9GaG]l*lYu=+Ub JLvILE0:#6jQ(V#ַ7LL(r!޵g52+zUb30aO6L>r☫J[&h%ٲ6̫f5~vvH^l -:Ձ Fzl.< D)jFQ{ iWO܀6sS4ף ElQA_$V̹$VW:bIFN׳$1Uu={(-:F3*5XYgj5h :'sS, &ۏLl] MٔaYq#I1qCI=6oiL\~sY:qƲQlA[elk6 @4oy~N߷ӶC!A l|bŌGC`gY/#p]?Ls=%ĤeD&h.6 F Ebm-L:d] 3+pdrtlϙ8 b-!28FN\/w4vMlFuvKl!T5ȱmt4 ޳#{|N1)|G,"1m?0 $k^ߘ$& Ij#`]Bk5F!Z¬Ki5YWļ+o8ȺPCM\2~֕, Xb("d|ieh( Ծ ls9 }j$Om=kIDGb` ĵvK>r45iPsVM)G- 3Gueb˻:_Ug^Og38Ea`޿_>[aF6TN!_]ۈ+z ֍, WJKO-d=DOfzsS9s̍£$d7m'g8|RXB.6~ X~ G(M[ D:<Ҙp:zdXU lRf d⑈S fb{_Y_%PMg⩝?`LMtJ*<”mߣ"c殶 /m}W莸c,GS0"/c,ır96[DpPdYAToBTB]MrSfP%^)yQw͂7ԬJa2L1{yUkNBQ*~8i:I֕, sTs;L3bdeĕӧ1KQ -Px( zL ޼ JlFm:yvL79-QNFL\y.19 Gh+\W=;fbqkUΜ%W3zz ̺͉3HiZQ;Ga qtGaNBdSIvOu$zU8՚bjc2KxM K`-y |P3VdI^5%HD  bbDj`JKgT<3QjS]lhCZ$53UwyHY.~͚V}Fo[7|3`Y 2څ+dhT+bv~M.Kz]tvqrՒ9h'O>lOztI'i|!+#rB.joąC21[~ӎ.H{"֐9CmFp?5xZ.(6t^~@u8f&:9CzWZS悆lܽˮmr֯M0|?v,jPl"e^[}a^c9OUWU[ܨC]sGfdcDD~@li A-ʤdJS_Ė֓5XE)@7enC tX EVTEN"IG.~/_ESڬNJZkKrBj1|pOxW#RyDb:R[]j0^ NbʖF8mȦp!`$RQV `QlElKc愘I0M626^ti^4pHa4C<61M tҴ~uaNi]Gy%]p?sZq?si}6 Ew_iW&L:~4Q2p|_cAvN]ON` N` G /NZ_Τ'boyr"bo\cYm/𾱊1xߠ+7v7Z8e!`=L:o Nt` 'b0YBgډ,JS[PL-?΄4Q,HLhT Rl SNhBNRdH7B҄%Z)3ڴ@& tEw22/HD\b-l@b(64c)qN@  8XNJklVB: F.NpK)"mNz[#iOcNbN$ ziccn7O<~դﯓ4j"i_ϯ_g;_*iHuyXd$"RSJH ˍ_"!غ$6:Ɲ.Ng!1Bߤ)Fp,G2.14.Fl[p|i%F*i7M157#{ GAl*XEl ;Pby b{!CdI~Q v6FvZّ|UK厮#CL "/' jF1zeuZH8c^$m[\DN71Nhf*mrlGub_b`4{܍El 5^B/:q\B/:OTc10y~rX5iNS]b.HEKH6u֭0dvHwѵK!Es)8C΋*^ti;v{ѱ k(TH}mk!EڶEY!ECA,+%>w .$hƁ%L9,:Xt ;ePwJ#5|V)ENDz1Ȕʢ)EKJfׁ 67c:^ ]6nn.ZS]SX}Ǽ~Ov5|r1n(@2,3p#1hU (H$'E8?sO&p=FLtYGs}^X~ܡ >(K>lr=ZB#XD(i Ms}$f,:kIs(PEKˢ; \(ѝE'^Igp"{?ZWr?}߾?,7 ,UOzpEp~/6d6[?s% ~*Wy9?MӲ{B>TΉ%Mw܏J[7vsMVq7ۥ-FP-JHP;!A-c5'"((3SJzDEdR5`BN\t-E|/b}~G qzoP 7Y)cZ0E?LaݍO1_&`e/RY^ΏhMOh6^;[Bl=nmF a#2$c'*#;EF!tw_<9uM̩otsC\8ēɥ9$4!_\ө,8<ש" 8S; wvE?׼Ɏ6c}l@1iY#L]𺝕ٴU&JMo  8D8JO黾&_VY7$ <>_] z|lZu!oč$+):'킼f0l}W-s$LOt6^#O&=wMcqkٜ9^#7m3p:ܶ)8=.f&TöLƋm6qz8cplZY&~UI*ނSjYO""# S5o+O!<నT"ӭTiϼC~kf  gu.5v5]6փknڱaSuy.ugK̨;[aFf;VXbFq02=Hq̠elhFtodab_k{\d15I4c*r)4#ZT u te?Ѐ%]ѧt_ٯI~U+:}Ε5xƕlv!Z+LW0=4klF&J/]rS}‚]?] 4u;@kQW' :bhL) !֤)vlۆ 쯱{{{Z|}~E"}O:&kqz6֪kC1lx=h6:cMj)ZʊAͪE*:9]%*Ͷ'vjFԡ9 jj3}gqtVКe?wS!M*ctBmEB|g rhxvKvqu9vuAH-㋌ƮXn.J107YID$- s?eq 5`=v12w.3Xᝡ=1,>[Bn7heЬ'bWt T7HkT"Mn퍓.6%́jJv- jt{+hnQWQjTۤ8ݐz^ߝlmp! tt+Kg]n`V/sU7!Y6[Wݪr"ݬƭnh@]%adzw:_ٺy6GޙlinOoMk޴$& -clWJ[j0r00<2e:]լl?.[bW),EWX,&LY2SU0]ـiݰlpBGA7i=bLN SuԀ`WyXHW0 "`]"JzbjXLV]pU6^3#%R`sl5y۲W]1?)iwؐ6D;;(E5t̊nwvHi! "1I8Ivg4$8fw&F!"F–H Qxz  IjY#LW+@)$F,;9 J3RѡaV&-%[<^%4>~nܫ|km$b3U_ sޔio[1p:V^w?k${ a|5ok[tBx` <5-N K56kXY@}躽j6sf=w{kaCn,H%G@G''@*Wl7r :WއgWr} b?S l.Tmq@# @rEP\ 0\HE(\/\8NE7\>\)U\-if| L z]iQ; Xlb kT#rTj UhN, 08S]i= үi3{@n>}BuX@lP >E} w5N <7`E_[Jup ]RȀ!nrX`WHvX0J|#&{- @U7ȁ.XZsuGX& ֝ ź Yw@3 `hJuם& KTwwY:ruGؾW0B8X&q~vX)QX-1XN12 U1 7a4 _M@a"0Tv,Gl0rLD0F ;D߇%uI&{[{ GsZʽ-+hA[ Z1Ɩ{r(k1Ö.arPq 3 AI z}nA=U: -o]uBYV *x^!G^J+I{:h!&%Wx _Y+xKv9 @_ PX49@g)P8S 8A=HP$9AvgPp9A}P؟#` e2FWwɷ%Y)FX"!Hr.RȤkv~ΠC_DG$@% ǁ!raa8J?䀃C8F?@-KMc׵u|U"8'N#}6B72/[^V>cjSVߘF6%U9G)WQBp +9;H^R"&`"%9H)f5RSP$%93ImTR@/m^R礄;=)aPJsVҗ%D?'M ϱ1^%cNR`83TZ*l-=ppl dngaVS(|8II+ﬤdfU% !i`M{hYp(gM`57`_ܕ3~ ̌ rtPqEX  *>Uk>LL M ACB8șa@΋UOFtpP"ϰrT8|Tb&6DڪSU!?B×¶OnШB8pT;|;NTG<%UGT'S+UȁW*Kr* 94S刜9~.mUة2HT$}@U`a*,QgrԨJ79TTJcut`vNN2#mْ$J82 GJO(91QC%Ճ"k82b;U]wM4;Cwͽ ;fpdThKӛV##V&+xҺ3{s0FHghSHBVi;ַkAЌh˽H*Z swV7I.ΆJcNtV;>0U6q*P4isش 9Z:sQQ#`McD)j1m5 p8[ =|!jpTp.8{\15kprZ98|q%>FW$BV 3~‘jNvpzrV+oȚnW5Gyy ΡaYG1N9PIR$M`-dk23۷LG&'??Y#pd;ا$I>5=r_fF("Q%XEJ0D`麕wLM6Z=X$1MΕ>!ջ7Qozc)m>7.&zC5jfSiꍐ69{$U(M!o4rx"WZwyTmN#7~mj5% ,Q9cZͪfoe5{ .kE&Y#КRֆSGo5{s03'2,lԠllHǀlY[m9uff۝e9z%lklH(qL"›DCd&lw*2Gv 6=91l|t #ck, atF aSӆTyAd:[!F -bSÆ1:ohFق^SvS>IFJVBVA!mSlk&1Sq XR m3 j 5o^d2+#[,̾X~6A&u&SF]LfA$)OJ&&44ŋ)*SsO,22zP4omsFNgP>#m ZGZLeQQr&P.Q20Ek1l-F2l.F2zl/F[t%QČ]7Jm7c]Is-zAQN'=/Ǎv[#94Qrɟ27 ~tq c4Pݪf]Lq`zu7[,/]6z5>\D@T3\p$A .A7]R Ho4t + }_t^t/:fJǭ]6fl2T]@(niE '{G߼[\@],R|/ƺʳ&# , {+0NC?>V C3lmc Tmܑ'ﱶ)K:vötS/"Eʄ;P3ňM2(Mj R:t.@FCϘ2f?)g (YN3k}g_m gۦd[bo|x`!f\>[8 >R(:poax~ + a`GaK]p= LS))ƾo뉁 =2krQ cmz8Yl1Nx"6}ʠobi}7[1U_P*(Y^^ߖB|ߢvֽkE#]3ALM~k9kGW7ϩ,&?][c #8hM,kwe41C;;X?9]JlZPs]1/hg$sLeDi7'WUv]< b^L7 ljĐl1,yrRxGvLva.\^<]E^{D菰0,~6RƓ͒&r/`bqwڠ&/ 0q]+ ~70UvŘljdm~}wP8|+Byf'݊d(%k\iG;hG3nm%99B4U+I=KHgsxH <͈iL#Vf3``"p憇. R^fjHE8!2Ͼws3=| z0tnuJl^@E>m D GO=^ͯyڟq%C&ںw ݼv'F3?HBW]+ nD|Y0_䳿ҨYݾ }_l M5rbػ~>W 7h_,@0|V 6ҾМ̮ }is8nriP"7? m`5FglF`NK0r0aghTO!):z}*u-V-( lAbV,VVUV<&Ya%hKxbe#+W9-ymrޢצ|c0_ه9Dx|&!"STҠ4/w;I F>Q1"wu}D柳_XJ?LŁ]<rg~=s/G`}'ɂ0VG:`ӘAum= mr=YǓtmT`wܬΓ9ZGK#9FmējPse|`{6X)ԭnf|GQ;7Α`+gW[.Si҄ @gm iuD=3i AGmyȘe%{_$p.3漞_!s%>w 1漣'{N<#P} '%tyDsqG@_2 39 y{cU$˜kDyυYW`b KwKoWuy% NB6&lA&d=$*3_ۇBAɓCl]RܯR'U_M mt_;?7u~aТOA!dhyZ5RLnG3OGCIə=Gzdbsp˚ڳ3>\zpRCG7hR> sRLl I'Zipj00‹ z,;8ܥ?K8xv\F=,qL،м wypӊsku;F'B0h;}zuk~(q8T^,B>9dź*}VJ[Z{9U^>O<A:SNfq/.iezE";7rbOW5Nd?|UP1Leגs=dxg_ 9' S͓DB:!'_1: Zr']w'\s ޜ#;RW0{=EnL?ϼ59 #[QXpa}ĈHp?' G=915l;f[pʣŒBr"gI:?Z+&9y&ԝډERq" v*\}9c2<Ҹ㾟VÞQ}?%l:L(_G)SΩ4PS59eAΓfzZQx$̛g.1'wZMZ'Q\`;;pǹ8Idi<#N;WS|Nns^S xl$6=BkW O^= 8M0zEM>@c%)+f;UceOҐ>;gew*<@Nsu ))zעC)NՈ<RG U#G_ϕG=4Ox_ ǹK5mvzMH=a@*GX-[|lVǦX+ w{{w Z}d6:M@R᥯s}9q>sj9Wz(}Jb%gC~A=9~ςw(?l2ؓ*#i?5ѣ;"3"Kꄛf:*ŎqyٌbdHaX~\͞#qRxqЙCh8CjGB,pTlke!>ǩRM~O3;Ewf]Et,=-%dyofZ|͜O~9wb h̏qC,2^9HC)=y>E v0>>{ @z &HʟAO~8M=Pܿ\@v6HxGSė44ϓsϹ$Ϙ\_bOiөq}O}8X9p6)OJ gωK$-;GvJo>[\,Ί>wtIW<)Oy8v`\c0UUӸFS|)?'kI)iXӰđV呲.ÿ>u}'z_3lֹI,ԖpY>3JU q'n?G$eCvs{3?՟WwzK}o_~Sӊ&cDJ/!L:Xi1Y@[?DHW'!LR 4-x:!ݩ@ }˖.{wIHoЋ%_?2@ t֟^oK^ijLA{˂Mc} ^43M` X /%x+EWe`=|olB"?tʗ>$oL^|Zt[~-:-V{[--FfvjniEc{u7;]'tJ~`/E/-eI,ڞGWGkѵob״c?]֯sU<;ϋnuEM ]/âsŢW]8}Zu~dpn?mzӢSբC}gxb-:mY{!+~\t۾$6۟+} EEǾuNjiϋa,w{ѶYw'iE/y(>eAs',9we!lm=Tl)oOe_'}3"f=awgBblq#lr\t?]?|}DhgE׼k1mA{w'en}]/E wLбa=~7}| C7xdѥʽ/tJ;>s/ҎL;v| -_#.}ǧ/+ÎoYe U{U72v|NY qY<mQE$RqL>:_.Iv|A꽉tY!{)~kɏ $ nt6N{6rN{lߪO.>,TC!^PtHk (n#6c26yMZl q,nv9?R?'vR~Ч\*\2L+w̫˕ _t-aRi6 Zp]-OX[F% ty=-n1#å,.TC#M@uihf5r-_ؕ 2u 8$].X;'\'v Uv/|1f HSMzO78Z*!p$`Ҡ%gɑ$ji4ܼ5s PZ/Y[o//j깗,UC A d'0#1%++]Apez'K %x$XCH\vC|ۜU-N/Y߮$%`,fB[٩G-KM2A1KЛzܗ.g U/>-!gYjfß:?;Ov\WONb<Iӯ}[z'I5X 0{f i*E/ZX|q؁eg7Dlh HsU`ʄ$0px[\`"8vܿsۂ% @˩[\%{+yD@⾴u2k˷®h9Z PK`6f=V:V,k\hf^*yivKv&Xbu(/1gg5e )@4奢>~Vk92͢+~1kB!Anܕ-pSi.J9@gWb_0). as⣼`aQ?v˰@nd2,ԗK^ Q!˰Xj^aeӛ(* -iʵ2M=Xe3i&jڢMn׷\z~,Shcܳ;CuWhu)LF~FFdU{w\jSޯm[_SmR0O[~msip-Ӣ%}Z?m*oj||_C˭o[!%+1qhK?- KՒ95'ulٲ$ο-[mwV߲Y|UiP<_@ƐyK_ߧ2`,iT}/^J,AzViߴ o4 MUx~~%T~( _ KO!J#~{V2*~,+?E :EB=Dsۢ}x<<~w>偿兿h}GJ'yKj$/_[CZ#y.I?/Ŀ'o·]~_ɯ?Flܬe9s*k.+"~R&z3`=E͛ /p!њ懯E"vYW.~wNs.?>51TMY/^_~r$q㷵_||}&%˿ e޲@ ܨWi%=_Еx 1d ^u҆>6`^h"@D= (}/N*<@$4JQ_y( }y܎P+8;4="6=AV Jٺ=?eQ߳ZS"+F+EYo n5 J0֍1{S4OZ-[=њ?4#b4̮9 >`V_&^YCh@`2ZUVP2QOFeOX?[/I?{䇦_O~F+ E_o`gVG#E<j 3N8NGoCc;]6$6[BlE 5}PwXht8!|_hp:۱Y!ۢyt,{nUaMtmM>c;F'ݏaU+~c_Q0`4~t!XX_[ +M "I&)Oy+ 1j*ܔ%M[VqvNc&t@E't\ZVh4Ҫ4miEW M:^m#1h눬TQZylYZ$N@HjE[Xp}Rb5*yLy?#yaD`3?<Fo[4 )j=ìr谜 ieNft+:(!=O ?+}~z,6ueOYMl @g[6mPu^YQ݈Y_b+8,IlY5%ƶS X^v8F!XdFߠbDct5D/Y,:8b!N^cp}^o.RDg?vE lY>l6-:ZXQI1QISlP 4bjdE3wD . 뢡֒Y7 1oYj f ϫz_"5YtĤ-Ev2+ LlFQ@{$ә& $' Ĩ}/A*X(l ,[a?oeD@SbӲS(fe[b%7;[~-mɶ ڱfԖMl^?0xy&@G/ +A`.`@?&~¬ [u,:h IgX U'N¶*M}O7'(M}OoBWQt^=ف'GL䴬|2k =NO_>ݖEZlc$+NCL*:X7+tcV"Ȣ;-__u-|E b/;XxFtP^i,;Z~Ju+F4i+"$Dt4w ~ (b5nǃSd&ŔY/xf#ϳh5^fԐXE}B b| o27󷉭+[~m'_icؐu *`~ 07Id 6'IlUhcʴViB;:Q ba9+'0IghǢgu(E \6Yb3C,{\p:suK#p}aɌ,H97ު'eKCUO #V*+#ؘLVC 1I͵aL-MjkBL5YmEg.vͬOK͆-YMT 1u}%죮{0KۈEkF[Vžit'S?SAv-E*( Bȡ*huF„*XYŽ*I2,AimbʖFMb( NГs'*bсh8K1Ht,2{W)ffIN:AsNVj|Hw^T F19,NGth%\mhwѕ赢35N":-X !RD{kySt^PiXF "Jq6.鲞׻n몠mUEtQi;2dA4? 3^M&d?RLFbeXoT[f}Rjdz@XGlR蒦ĤTAk#ZnuEO=ov.]4dR}lȂ9CYi=FeVXCfGzqY2P[1ugO+o$fy cFX,۪!s'8/KުXhA^-:`Y(h3shn)co펦 4ckJ)2ޢ3ABi{L҅-F(B/`3~b5% tU=h);A?B AL z-c3dz;YM'3k="H/jG !fAybO*hbâ bVZѺ_zz8*I؈xW #i3 $KC&in P>TCcj{TZtݾUl]txKAc2'an!s2l'ƃZV'J:Kc݁OTt~*9ޕ+'^0j&[x[F!RXe4𾺾etp\tO]ӝ:ATt.g|G9q6 cOPQ:s[*ͩ龅{5 't?Dp7q"~;<|qIP<֩ 8S B{^ xSlgz/8d⚧>=nl*Sa%x0jUR`C.f`iq[)! z*^G[Sn=k}q6M";B`r~Ț|Aƴ Iy6Mtd$1z 0}rسVC,!? ZpJT0"@Сg.fDFM2TlhxzKܩD['qU)NO$[(wxkZ<,N<^02PITsz8F{ETPY3]';n<m򓱍G3^3;w^3i=dY&K:L '1UT" ZgˇL.YʎŲfZL8 aBJQzsEW=,BW2ZvvjG0ۃ[c-:^hx!)%ڲ8@-;=.F F%Hi qȸ9T:w .aj$ɮN g)5X+4LE>0bhjj*dP+X zi hM吿+6z*\Jb7ĽHFc,Wt0߷|݋lJ#rȤ|32(s- +]'`xV4jF'J. 3 dwYe4v' j*XeWvcTUYxjY C]( UU{UExWQu}j=d֚Йn7马I;Y6)-Ffɒ]%mzI<.dvfWS &ujJq:ꕞhFӮZdad&GKe1{fRNLvjM]Y3N0T}-WvY'3$w+er `(ft3 ,<7Q4P7俢4pJAP Pw\]jq(!<kcIPx,aPo9"G9P5GRͲ~ R97A)*EڈPH:G鐅2UnkxQ~CqXԸޠvD=*dGT\ë+ʋrՋ  h'׀"\f'=j'=~,I^^f'݋4ߢ]9b/l B,HdM4Pvщ]Œ:غ  #Xޥw획"*0*25==ly>Taax0@1%"#z}V'.k= d/Iiٶ3p`9ԃ׾mNt9 bEP$Z(T@j"U} wٕmY+V +ߏ; PbC%tmY6a]9FȜ,rqjU9sfsĈ>՛)j;qԸt(C_svƓ>vJ?^V|]-]G6FHVkHd\%l9RC"#.HA NfDZpPR\jMwNbZ'NZ 4V'{y$bqOv݂RO뢍;|{=__؂_W*_a•Yfu<Ѣ3I/ݕT#A SlSβ\A߭2K! UJ*0OW:,;x|A§ خNAMïmvϮA,z1ljd ^ojӕngkBm]>ddpq=b۫:rQBSA}]{#U cspJw ⮜*;{ȎKL&V%w"}w>led&OkD7auWKEOv~v{w+Z~\;e߻(lVd}ûp6Cuz߯uµk0Wh4S+k+l±TغֺT_Jy iT a_~H;OeޫN{3'D[ )m޷ [jE^~8(aSW`[ԟvEoqkW.ʏbȄtFU.JoVNRUtt1qg*xs*2c]@iQyenWtVVY̞ե<)kj1Q:ꦶ3 ktC'CW[\fč$>L|c #{`&ќHZ4Ju! SuhJ7mYƣ-DіZ&8iMX>צ|HUSSq|g9Tѫ8ŭ[mꬩH-eY[ݸ)Wl]+{U'zd3פةա3 [ƒzOicP PEkTn貓uPՋԊsnBe,>]$"9HEPr B=m_6vzKzl)^8ɍ6}NR#dI]$+uw'Bji6u40U56ػ`KbÂirV3+)PkNCܐ!Jjnt47d0DC ]{B6lOH ڐj2q{XDn!i=bi1:{FqH1= $A|iBL{NЕؒy^{PLvI9Qh5ːU15hU60a7'} >@Y"L T@*LK#`bhP-*pDڭLqfYTbB){l25G~BQcH” e>߇c4\;Б\13Pd =QX澨Ց*CD#Q|27~$p'9S It%gox29<`Or'Q9S X, ➼HOrb'~9Cy` OOaه#Y+&xSٜnr48xc`<)1`Osƌ'9SP}?^U0,{mn12S{}rf._6G/+ippQnUzndB&\i}6řh(CO̝R|484SO,{Qk;rl],Ntu O"DAB sTDO,ƽ4iPd~%RqNM9F̋2%W!,gy#̼ g^4/s> "2y@/@s6ixn^7/|s.96΋*%uI;gy9#Xωv^;/s^8.Asv N$?.pП8a(Κ^jhpK>FK.?k~+j=K|Y՘ʈd5;f%BՄ#^--S7Zn!PFը|jVDFMoQF% 1HeU5Q7`lhm]՘*-+(Q*%k !P b"}-f8D906 ŪrKP*r?F8Ae3s@G:\`nq8farB :u\q@C8?ׁlQqX :hyRٽ8?#r9ء@Gv$;H!YK4v%';8y8e!א鉂Fh3FTZO3GQ%7-r|k=m}ZöWuY۫:V5jw۪!K6|.T3{_ucxGԇI}C~߯qd=/!}k$}rv}?6%}ތ v.gWj׎Ҩ+9Z*# w.I̶߮K\mX_J%1 ގ4yot`<;lCTϙpk?;\_nCIoPD0-[/CЧe0h7/a ES2t}VCMz65\L߽cԛ5&p1xī6 F$oz dLV'+9e+oquZ/UA}07K\hg=t_w"+`Ɉl8  C/4I@$KQ˦kXhJwM]v={~5:Yl%ł%Y%׿ u%n$& 5P G?djfZ.[6 L( ^M`iα~(|Vs Z0Ͻxc Bm Es2u/BwYv%{{VGd7B.q\I]MX.U̎ˮ?λyN̓4EJ5VkԵjm87*1w*魬ڇ qz,7o]b` qzmܿ5ז[V/`XkbWeZ8^bbOĆ0.lBw,p&#w3 |Gm55a-4Å_ K2a%.j%Kphx47H9._]C2{G8EA>,Ď*t!i},^bF0n +ƗĀO͓Mxl,l\%a#;m K|=Q.T2bu%Ns%Q=,1m"&bK (9bb%9MO0vWTۈڢEAb,'ͨı7?mƎ%ϰ=*، +<_trb dpFc3 ?I MS":4z%6gTnMd)to=tӲ0'02" La@"/~DP5p#$ "IH cYj~iJiȠ%MΠ5" oufe̸/HQMO>$r]D,cꉲTE RK}%&U|X_{=ؤNK^SDlR(}F-8ΜI MZUIV,GNznR,9IAt rޤ\&6I M 6iT rޤc&%\7iY9쐇_ol4srOzTm<)w$0Sr@қܤc#2+m=}!-L! ?A$9`pbh'+c$B o} JRF^$YW頔x|_qoMm^Wi~I;KR[ك #0=q= +~(>{WM̀Iρ(#6| ̼2qiUGͮB;5Lw|ZQ(~/;ݰl+/v0Mv8]$a:{OS,Ki^p0Gոv{Z>k_ueW_£ɹ\J5灪=b OM[L:#~A~V!ԛ;סH&w˄ U9Ӌ$vm_ 3A2C[u5HsL%a+`nDJvpW]I/=MLy]"{^lVwu~t0 MuB\O(Ld]m:u^ǾۙZ*s' :([cTu: araqQ>LNsvRU#vl&Ftֆ 6"&kYmq5"%l&xW75ܔs:s᝘&i .X} 0߫Qe,!l?aun݃zpv @=h+ra[d/: _t@Ä=r%c]˝sa5{c.{Kx"Г!}fg[>^B5hŞl75Rٰ(-)Cq'ըٓmfǻ۳a{WHfٛNdpbs"bx>p=&vG?S K}dр!ڸnӖ4%6pr:xݪ19/:_dhѼn`{HS_5#pZj1ǵ:D2X%s_G"PaxωpՓSm6)@}0w˞a>W 4:M* 5dNArcp< Տc&K7{U{*BPj.Nz<#_jݿX`Ԟh6>(+d>,Q ?($?hO`=_+0Z}twЪ;Q*6[qEխ@fOcP; sOPOjc Dݛ9+JXY#+M].|l|_$&b[۵V$ -K9E@Q__`oΙ\SkqKzMb_jj\_-JAj5h zv=Ay4meOqx|^ l܏c>a+xc>.1kT zw :\%b0QQnM, *hެB\_n@5me;Yu✷X7Gdǹb+w7or+̷<5#gK@l}|_#{}g|9 UL+u^M**;Lf]t7X[|/T{^(5JHyŷى9d'8V1 Kf[r䙼0<ѿ&nW EhkWzJuZ~JRb:н:7Mᆄ?qK?ڴhwy?}TzI {)=&X= O65+9E^#dPl8 (7FFxl7ͼ oXDև%h6Ϟg4``)Fhugǭ,}wa|UE3~}_tK^kkqy LÖESpp?0xPK2BCچ`͈Kרj/'c;:#?Pa7tp(o> I+ۑq .n@ 4'{Gy}0q@3էO7cϹz$>R!(Oz%6} I_}Wm\m~Fp-zZRJjiŵrDds[MHF#|߀.I*FHCppգ%#DH@{+g>t?^ IGƊu<-c%[ӽKg ;2U8s|#+.)Y-|?znR1X.<`}Ǻ7c]#[6ZCU>Aq1n+Y3|P9k[oac%a6iC .1nNCyC\Wkp1t-wK +:6zhKQLX5o>q+nWo~jW?'\Ķ<.)_Ut5sz)\rqW-ip)|U OPO7ג-9A6?\E Act!>ߊz$O~v^9WUo%כ=bzb 8˅ZN'Β?zwc^MoS4w!Q|Pai-!X3 S.{`{ݫJ݊vV-ЯǗ-|\Ӹ3<+/yܓ}׌ǟZt#:h;v$Yp^}O%Īْk;_r = FB t|mew:=lmWo::ݰn l =ߒIܙh'@R}&&>/gJdEGw':o⢭[=EBeO:o gW_;4Z/m G{/V;3 wΘ5qܼZʿV@+z2ZoCJ~o랹"kw%|Po:$uW ^&ڭkn\ /𚧺jWT [zN?;ȯZ\]M7OAOpv]a}e.4^ukxWk@Nqa=[S2M׆ZxnI;ŕ6+{d PiTTA;2W޳{0?@p f7.J)+-7{N H`x+_\p7v'˱$Lr3/-gxep ȾU-)f@p\Rh[) ~Ǣ₹v0^I>(ܸ"k9b]k͍OWn(Սc-O}t^ϭH_뉟M ҽ B>GfnU+i5:L.N*{?@. 2h/a']-vp{7O:;n}N ßLoAo__^I9/޻|_~VFܒWz~/O:{qBS^#;@ݲy͸]N^+>R޻Ni {7\Dw5;~y[ץ;f e^tn]gAbw:0x +e Vo߳] Jc8X6;~߼{cܛi_wu@qZ%X j2w=>*F~MJ^ >87ҽV%ɯu˹'j2o k% IEݧWFq''p޴;f8Xǎ%Gz52|_W*{o1'[}տ}_ox;z߷k~ _[m|_ 8?eb^_QOnƶ"&3绎OU(H3S.dئ"B7z;ӡodGSL̍frr&_xFU [2|>r^pc{7Dy6L^[\iKyM7X$|o ?`j&[lxf/w{!))zQwΌ\Xgٿ,&/{,Dy~ΌF9JΔߖ!S_=_r\(sd|1{|DGT`H9cs6Py$2q5%O,#jClTXnw 3yg[?ٮ^-v+yzK~%S_!r1 G;K&/\C):GmKz !csSiNyc;_޿ߟZ~V|}Z~52=bFk?~ɫ[Ndqﯖ޲[&ny>ZiA}~$>>$-~:o?j˩r;YxDn8 L?>Ud|Tm*m+Jj[?wpcPNtC;'jBc(;u?* [=smǐ;)y1}{x^Hcq6yC)zmxݿ'v#>xL_<@(q'j7/<#i~#:HWqȎNfZ}³O束x Pe&VPy{L<ί<['v~92GSDQi痞G'r2 ]DRyǞdUߙl0eNSe)_>&_|rz\w~Y܏dr'NO ag B&;*F? $̧)wW~wm?\?p}})[ҕc2+\hJ/ejULRgY/ez=Füc 92T=+AVW/eǖL$smSOjܗ2s=)vz)ו:i\"I.kŜbW|ᾔrh$K%*헲Kl&:\jOF&2+=Ml!|R/z)OtvϿ8j_ʝJ@ٗ23/ `䗲jsNKu'*zؓ-juZJ:г)*1kRɵI3R}5 rRm5ɭRe͵XR]59㥪kﳅk[z[aR5ӭ6R--݉{VlDɽTu|b^e?/U+84_?Gqb^^7rb_}'s6T9w/ Twwlj׉|Ib=\Z=Փy%{gK8 OK( k/a<3?/!Dܫ?n^—xDp Nhlz 2ƣ%\G@g3KNKNA-/<;dhv,"ϔ#>㎣R@; KccY?1E/So3e \aהI0h |S1qs`<uǣ1{ʜe bv~OtR.?]^_!7ejv+=t>~a\8d@ę6R+pHXEXBP.CnM$.P 4c"ʝZ^n ;q7ng.bu[Ere 7C49rs ' ˿º8q\~yd|"[.߿hxwP+FUAdB"UU etxu/GAvKCsE e ݰnF^W$}|ϿO_r-L+oǟ_ן?{+%AMU_ErX?_uUUw7Bf]"/2T!å9dG;d8b.42HP M$FXpVL:c*2T^%&CU2[Yc\64 2\5H&Q^&Ǝ.P7X*Z%k5}]4H4r&2MF7B۪~Uar2]%WB~YKyC$}A`ShL,Vک [iŨdyID5 bWʫ<+M߷z;dr1bGkp|_ +(g8֒m'[ۆB~M8aҥ7TNcrs-E߿Q[AMօ)P :۰J-$nS?F؏QbhW^c v{Y;M>Q-uzIɆЭQ2?on^^gy &u!LuGVK(!xM8~S~ i.d"[1do Ddm|ȏc mtBNz^MvUOu=܏$3yuG#vTeSCnI{2ҝKA}VpiƎy*p?(`='>$$AgY^\6:YA t+V#Ղ_U"Ȗ25XO[ƿ4ìg/R ̊ FV7[O)2kƯd*>L4+IoĈGzdU;,l@rR]`M䧩~S3W#VԯhǓ ylO:tNJd*Z1<ҎjEoYIdJשM~J"PUҧLmdiɅdǀm9cܖ\R/ܶ]rkd҉$Ij uAldreM V 6lNu'(˛2({3'8FmoYΠs}e;1{O:J5T*`15(aq^%onV:ʭ0sܿ f9$fon sw֗5eMmL}ځ_m{m?X@6m0h[raԖٻL jwC,9p1odcڤ5S褯0͋ Lڐ#??4ِKn}6F;ђK-'cc3,wֺ&m$%7Vd SSm 3yƔkZ/ɁO)lp%gq[&,Qz`_q~8jJ0ﳑצϿXяd\w? OږVoٶ-+ȒYyo92*Ek-2Vܚ-9}> @.AŝHFvl&"a5̞aeuȠR)R̛ZmLb790Y\^:u+ӹ%L&1K[6n׫&KRrOY\C2{xv={}ʓc^3]6$͢qbzvsgv]+~g}7~4ٸ;Gz7{eO︲X4;5$IOo2IPk _uǤKe^Y^<[gKy^v}Ru_Jm=[mRvm].)AJ98v ZlR#vl9aUjĎ}u52L&K4FɦFy:(iljj+Ejj_jxՒmvK%/2vmMVżBJ~7 %fc0+)2Kx7[)Zylj%–ޜ_Mzz2)IͤW+ QC.ǰZndu_jA3w!}}T/+~M6J3Wռ\rQITzo@akZxY#\xYQ t3yOe[0k&2unܖM8s7mc1cks5C1`&2 .ALj&bQJ0O#.kf(ŞZ՟'w4X#k?#mOMs ]op?N]O_xԭbeȠ\pQO(E&f%-#y_+oJHǶma$nሑW6S=6+wMtc1R>$pS[׬?p=K>ᜱjNWT I%Z:-wyS.:Xm=MNcַt۱\[SXdٱяI0jU$*[ORj-nj/mj1lj3yTA)NSV堔mgj=dyTA)g3 !* Y I/E=R8eZͬ.kV;+h qoj']D1v=hc~û= R#x6,2$#L>R@ƅf\XRdp<2FXְQ rI!cd4~hN9wޤs*уn@+ \<=NlRO.vq>B9i r}+gs&E;v5;s%dɺ 2+{eYjru998z mk\BF];ϾUCk58KE%7 qU](Ӯ |1 C5l@SDtSn{l[7v4v4s#9\7_ w?sToy(e3l;IY}v$'?317>cy`y ,İ3֎Y~;]O/=v=obw+vڽjǨy%VE@uܔQ:)D=Ӌ< A5IFwN?*%o'}#>k{ Tሳ\?!b ywݢ\gYj̝&Zw5 1A X {G[WeȉCW؞E p&L)0/poMXbf1 Jgf2<S H/M!=Ӄ?XXb"t>V0 -ZMm ^@ 1;qTg3fƣx>֏48J W;D/E'@qӋV5׌M%R|!s:8ۮr`W16V0ӌ IrzHrԈpK2)gv:rլ 1$CBBLD Oq]_#].~9~B3\|$|+׍PH$x6lz5 T~C$,7!o'½M@ ](Blr<Nj HÈ81^{gfOxXŒr36NBPx8S%v!\BVa@%ξEhzd$'xʇIJ'5ik)H lK|O;P'\tO8V KB!Ίd bLv] qt]P"}R-rjXi73e#xOJPD])Ѩ'Ѭe︫2 '-R4bЛ7I@GbO7';ֹh4,]WRkeLc`ڄY[Tل8e$_N]lOe쫩8 u7BF0LfA5,Ne r? rXX]F0  >IUX l_G˺X-Zz_n9uaԺJ ɳnc]zBj+SPM~[[u1( A`G8ICrSeM'TĊ]媤@AW'!UzNx.5HE'0 u#9xZ$biz2Ҭ,UmHi'GKHuPeRkgbƼ.1pz.ę<i}(f]% {;k˺jIlI`i7um$He$(8L[/,Qltw%|ȆГ @\#)^wbWD XC[ ɮ-siNQ)֧~eKg"|"@5>& ^qSVIAU"MQCA 5r߄d$67{:K:[M$$fhfA ػ&@oT(H06%o LIEcUY.zȠ ,Nie_ W>Qsn;ιi]6E(c2MDHq<,(zT1jCĝ\NcPkfC,:,Ʒc2,`gjX~Sleciy ccZ &.CW ;d]{L^%zs`{^#ɱh^z^f@{Yh^Rl/ZLz.R>xa Mpg*8#~ N C8 NpD7a[P*D(W}-8'*PU?RՍITmh"ҩ&mj0Wy[)F8jğHpQ3W+ ""R}P EbA g%`i44IAs8}Eо ؝#I8hQu~|Ro'"'YN-jdR5 -_p-CcsƩ:q&c8ip5Xy@ucp98L19ĎIFc{>Ir+ % 2qH!G49OVdӡ@GIrC(9,k:I_ΡNNҸ4f|]6͊K,[bBHU!j|26!L%B7ZV#ibE25?7'T} nqRŸjb6lCЫr)\& '-^* N}.<*Y4YW;*PJ`V"W%js1D99Б]z6t=': ϹXEs7p( pf7pp7 p 'p^7/p6pڤ7>pEpV7MpTpҥ7\pcpN7k|m M"-$ &')+.^qtZ"1u)Hk&D`&2TDfKdݸ]PȆ)=eDfA+ϊC+6OC+]טt;?1ak$%j7+ݓI9eK&&ttusA:}!rON"sGӿ6Rp)W4,='NPRG9W^*a>Nif7q@6T rސޮ$9ڛ(9[,980 V8MNNOPQNR3ĽƽYȽʽѕ~r7rrP7rr̺7r :ơpcB@N)R8w&CMp~*FoDvBӔawX&.kf +)+{X V}7WnDMw;֥VDEJyX M1SeI-Ov]'#1+:cdWthr*C\嚈DD?DDfo.4 ,f":k-b#M-w# NƉFIF2: = 0d8nI N3'Μb }gqz NCv 69:5]8c sZovn R):+MRv֎%ՃfI 2H!c+UddTރddL7`(2Ofva yY2l3 ʅ8&czv7 fQv6$Ч¿۠kOBŬO h&|nA>v+^0Mqj:&(%.L)4tn1MsYfpFuS) 4t/=AOL@lAS'b&8i }Fz>F&SNG>m]˦;A h1% Yvk G8Xe'c"db&YccK@%{ : &8[Ifם MBB2m<4Ns-r9OYUI2$fɼ^O9ϧi<{{\ {X{F{ZAWI=YT{{'(n*ܯOgw( ܣ0B0׺~ي~ے~nGT BLW"&'Ѕ~_јt@Wt@urk0!Cz YΊ[c-U_vW_o_>!/?^,kB=QY6% XK:"RX?1h+v8,"_ 8Kv S;( ]`f ]CZ/Dul^g3l>q C@9;cJQotkmsNZ>K~|=}`QBv^788d /'_`12ykHQ/;<Ʀ[5F%idjUݐOenh͟rn2shyKJx{q H:o!L=߭n#6NNGYtgJ~jjSGw@ihN;e[!Z7Cbw~Ѣ03]^o~DD4*Q$v@x{/ƭ&7dIu#XrXHnN75; feo|b֑s!< M&'؎oNcjq/Q}/z C6o)Z_,ͷyϚ#t"2wK0`+fMOcYQ(x 2iCsc6.inݯ<="~vnG$q ~;cotڊ2j Twn}8(g1xQkBQհ?noAtOD8x9sbz_S?5O7;m;/VzdvRNR߱Sxd#y]#N̑=⣨أ=H7אԼZC;t1^L6>Wܖ8D.FJ~hv+3e[kVH\qq=0 0LKTiTb0Φk'q^?ӽ{,yK#h!9bћ}OeX4'n C<eԊ$F`t.~:JfG`FjFz1Q#o Xk.' Dw'Ջ] TmK_Y<-sѠ #9q>ۛݡeu9kgun5u_KN,޵-A.XMA?SA{3טjoyn2Mטv&cFp^3~/:st][! XnU4;M*o%>DE3W_ಎ mKd{`U0G,ҡL~5P g/9QRD<}V^?̌_s}_A=4SGFnqD?`7keﮱpivZ|5;w V/wRpm n$=yUpOGU_v=bh[&_s6or+!һ;K&&,3z#;l K# 1c;^1}G\y}geM}Ԯ߿>B~"6Q3f3".9|+C0 QNE1z;yl6yAe LHQAda.[dAI/9oJTAܑx&~ó5咤zz773;)6z-~UoV?+Zeϙv'8cC*FAmTOT_#&qf-w,^rb7y3\nu{{yn8;F^+M\3tM+~EfrnUNigR<Uv7(DC>^k_3#.XySs-wt/Wb Q%AcƺGE~wnzfY.'᪱nӋӶ-Ļw?5n:"ovE*XL-$aSo[%+Y[rvCrEb 4We˻EUÿ9ݣzXV=_mז%{_I~yHP "tmZb[G]#Fd:+ڽՀ=YU#\g?U ʋ*g܆Ai߀ݵoĻzE3' Sƞ?T\n409%2Uй#E1/ pӒ31da^莣T '=kؔ!:%=B S|8y0fI\lRjaB0>JH :n9]K-2 Y2^JkqS> :sʾM͌^؃ U ~3C1};M/~B)~ vQסRkN:e SJexn˃,1}9=WTqﳸoqTYǀ21iD=&n6?78k(VE]H/9wcCP[ 2w$XfX.Rۀ0G{PdRHBN'WS/ri^U M)0"/i\wܔ/^Jމq<@+Z/)<}јX)GSߞ䜆w[{̱-/R^{:Pɳ~nDZ;#[X#[B'aɒ'/~2tй1ً\$קwSN=>F7-'e@3sZ%Їޮc_U\p4IZ;ssʩ3g9?迂@3bTDnI҃X/l#sH]L~$k/G̃| 'zR kne$ /u_erɩ±aMKh#gfjw2Yن[W>! .=ؙ8:ݳ:×O ,xӻ<= A„긙bztY:-n9n ~u2ޟ$=˧)D4ǧ$r<'ԇvx|`>+q}4:$\JE'ˢI܇$Cޟ)v9bE2=8X.ߑ a^y 缸i~P+K 5}nP> p!>e.ǿ_?_ogv}duo?yOV+|or>eiy RASLe )r7 reQSeC@V߽C2K|A^yU 3CZJy?Oe|vvZ(S5M.JM ' YKXDA!?` @y* 5FyAHC$Qh-<('d%.wr|Py;tz&g{Ty;z;1W\Q_L>NYd!5 u:\Wƍ@|_B%:Oj>a!Mx zx -E]g`Ha 1GDKMƀ,/'$lQtzYV/}p 9gGD+De]$DqvO-ZXT#+W%.Z4M\ȅ1$|Pֿݲ}S_%~BVd\9H-3~ѽwxMD'e9:q[C삼k0YBz;S/(T/%]q!}~ ʛ:/ }q^oY_%:EOhdz^ooyCC傱?x@H.9/yD]y,f#BnUTAuCθGΥd>I9`IT^{S奟9|yEe?2rBrTH*'^Uֳ>V!{ʻ2}I"ͧ1 C;lߟ _1ʞ91xK6ANX__=%rc>`]Y?>?P|zq>A-|qehNpp[,2G>XW^uC0})`}_z|;')ގ,b;Y|t_ ~@{gك`-EEa_@[v/1tnǟ+qQ&;~ g|G猯e**2񻦎-Wl/ǀ+ȱ%HDy;q˭Rpހ(ί<$<3M$DR\p `ԍ/#遅uz&ދ5A'ŊY|iظX4kuf/BҝT'b,IqkX6~"/V+8}Q(ڋkFNڷy2'bܼvnԉټX7싹X7T0į]x]D+yb/bS=‹8 OEy'"<!b^ٰw_b6NhmHl(^Xt"/r,z:;5.bz,:;M.",j;qD(Ӌh$nX&4O2‹H(ROB8*pϖ(,O.01O\EeNڸ5$(o8{M.,q\DY㜫}g"ϲ.gEelΩ%цy_Vd{ђM 7%-Y@^d׃2%T =-# ,jɺqv ljɾGe`UK>T.Z1`YsI)S.0>x)fhO7@P%U eDA!\-GOWUeXKe:3e nL{<òU7~iײ:o?~L,> ӄt}Go?,\ஷ\WI'_OcmίɎˤs,mssߟY!ns ໤㐽wjk),g Q؉?o]"핍*H՝貵ޓŖԼT1O-i)go:sYE(R1 T~;f-owuϓm^+03$QFJ:<ԛ)FmJD9^jňO c68uSBY5^bYn [\eׄ#,/ r2/6k> N韭ƩGDW~o̗*‚`+$XHVϳFvoM+`5Plhݠ5".= ՝; ֻk\ SBUuɫ#<6j+WR˄Q*m&7L`He7VW ~ae`[akQgцSϬaMhCə5 Td{2Yv`,8UM9EtWa,"\h9c`پbDRgYq o^(CnY5KE 5)>qT ⁛"KgɲceQe+R%S%dQTYhh^$`bY?͊7oEw1EUY?W,G jQk_L؟g CCwK}:lIogv&7Εϕ{}JT~ pwK?x ?퟉ܚyQC49ŢːϽǜw3pm24݊Q'2SV&-|2?T̬Hg|^%ǴףL[Y2&L]%KG׻neֱ_,hOe4noKC 5,cy+RV0Tcmɸ9Ϋgw}v/)W}dG?g~UW}hO[[Ƕ?T_Q}nK??^U{b[#+=  *$/~0?m W4w e9hM(IH @ /l_o?~n>[Ⱥ:D/c &zE/?7Ypˮ2-a<#e%-rdw )/i8!M(# { aC|vE{K伻DFڭy:`'!-< l/`~#~# B`鼾tSdt[-on wChA帻GFCwaZ𤲲Hs&_QoMth7J*UD@*ח4 ׯXxׯX7_|$9Y6tv&^d?[-i%GS.vٞrvF~->FM^vd[5nc%)R0Œ HWy=:y!r)zܦڄ5jp[Fl\j$3(Mqd!qTz"lpkS%Ʉj28AYENs7 &}1e>6P&F} iI+݂K*p)΃zI?Km=wE-4] M JԡTQЎe]TԎ׮P%+E qb뽍RuuQ;(V1+-ʩ۶{Ov~p:?8PlhJO_B0)N =ӛJ*):T jALU߃u҅AѕaSZ.tmP[v2S,(%!?EѠ-{X 1KH4{KKE3 VgzKjy09#^#VbDAPH3IMׇ?`&yXzz%tr`'FY͆E+j6,m2@7#+ITunRimI'i*3V <`"QoX_zKyHݖmDW׶sVI>2,T+}e~1m&~_!X8532dR*ZB\q,#(ͅϋ3LғR_cUMQ\lʒz<*̼1=5 Af͸ϓ6~1edq?:W0cf3+A6ծ6rVOiA(<+*ìN3נ:͠DOKN˝(&)jf)7)̂)5~.q)yϼg'YyI Hb*^쁉ݿ4k?MmJhj(,pGm5 4H)FXeP%k,0{ eP1-Ǩu)psWk\nժېrZ9#?>;$ 1\cRnuc)+2janܔ`Y+7t?1}KKno\ڡ63I/MyQ{~|(p?kwk긂U_~]q7al1d{Q23b ;ۗM?ؖEVk׹unc=Fps1BP:5\:ݖ%;ˑ^J8YB59@A) ^b.*`[zK9`*HZ l7uY W.]4uZm KYm[D&rT174xPK{je=8Vʽ>eNoc!˔CYaSt!~Q,t} +oiݲz&qI\1U\r2x')*RSb ٟ*W_G{a<\U֩ sU0 2WCiyTk:Մ \aLx>3s]՟N2P`Qҁ_/G׻p}C儱fܿ+)EBb1AMG<T=Oiot0+=p JK\rXN G( o}헠rUsjp:>Llj*wayKPDiVE,9BϠrM3 8uQUN1TVyW\^WyBt \q\7G'~kQqf\ 3 M5oT_~"-mc ,2 ]DlP_6#4f4$f/lc7Ȳ"oZ?*YlEmZ)۰TJnv0$,YzR&wy H]rB8~ K:c$N*/z AroKP7j3ZuԒ'd# 2V椲ܯ2~,9A :J]ET4idSHYwȕ?0'dci6GA+Dk9fxom=_r-Yj-~ ! |Ys}|-ZS֣Q9wTD%7DgOgjܖ!"jgDn471hSDXEA+"M"֣n%]D.և0"1b&9oncӈ|,6"M|#rnb&9lbmt1X籉{D.G䰉&9m Z \7ip\7Vy&yf@,tFY_N$2e咏D+IK "jJULM"]Ǯ#(Oʟ Ɛ0# A XrZhNZIyFsFgVユPdf&>O[lDC.|6 q4<͚-|LG8:#W:;Sξ3CZ"V0# 814Mu8`*j$RkTprNÆ&[Xd"&b4=M-YS:7 jWzd.[Ÿ}MClF^Qa5yΚ I0h5uW:Y h90W7 ` #xdfSAzI7Ϭ q20f&sM*퓩E " 6;g_n/W*?(吓rV@h{&bWyL$; ô/1笯)gČf$qXtZڹ\VJn|joÆskf}h,~m#P# 1a8]/ Pe'O XyBdu!,N 9ʿD/. tޅQ!ޯw].-bɤsN~ܕ\rue>QtI:q(eFзe`%;a琒)&Y!Ko{$>xU#1#Zk$wA e[NLP 6q֌CP~h#Hr0^lH?v9u A>= 5) L6!JA?r{l0XDEzX[ R:c7&GbX>/q(b5|u,_?a tI`4$ !E$Q1V°F#~atl+xaй_4 #؉aoVF+ư`Sj26ƨ 1+j@!6QR .[>rW 3u+lY"CI4tUu\#XZG{פb4Ye8Cz3/Kyj.1dpe1Ȝn *p,ie34qu& v,We hdU0VK j+]Thbɧ} vbP=] =$ >Aň|1GȈ0?-r}?vO؇9,p5%6P`-0T I4BL>`@`#ks#-hI)ɇg(&Z+Rs$FMqCs& luJt ABy`LABuAz[@+[ Dw֎@@o!;1aFyuy̔u3۶4j7U{&n5LMF腪[u/̜ Πb3=;U5+ B+nY@ )w+xxe+2YpM ά:3ΜE,E,(O0d^`g=̞J ߻ztS;H b_ß ǖNHDBu/ Ԯ1E bfFbu[gd'OT0Fd YM*Y޹T%+b*C>)j$"&z@Zu:9>StBީ-4# wBlrj).)Ʈ]=L{cbai[MlfdA=WF]Mm7֍`،մ^\u=Z{ms. {}cƉ؟MQMmm)κ;q.qj:e*ahE73YAGrwӻ7\&ۨ<׍@GO\_uN_1 ,ʍ CUHALriͶsڶΌCvÐY= ^Ye2FID=jBz; kts\bU'}N~?w j@ wjqtA&Z霠7um$Uv6@%Z$GsSJN$0f 2L-:ɂͭM6ʉ\_n d'yx⤤ٻ :s@SI %+ErUyH.?QG ;EH:/XH/&|0wN5)YlC$[EQx/Yc4$_q)ޯ 5I%xbo)VA3DN\[ӶA;ihV9I,iT8~5["7Rqpe܄Q֥ơ4I8ڠ#bSK!COب`#6"hmn~.Y%*am>8Ͻ=TYC,8&R݇R >SڶpI=@VٷZ)) pJ)t:!)+*):)Ip )X0 )g)v p$0,%1:﹈ʌoͦ!![-"uON;b#GfA5fhfɒl4jZVY@;O}EĺW`{o6 ),HFF,ck$H-֨aq5}8T;6v5DvcZ#m:SzN1vQ~QJ_)a%6Trrٛ{sAo>X- ط b[x~ ^@o XaM=`!(,=ck`X(d@p[ Bb"`'9Xp ) ]1 [ cԄ̘Da9E3[RJkDuZprW%bpZt҆׵\A/| t]tnk+'*|uPe/uɤQ* uyhgAHa omDA{ !X(g[|&W^Ҟ[~n})GW_WgikB쳕 L+f)홢BEIsX#{,>rq%$1V d&:1l4)FXDTb=%`A;eYImaC,Lƈ&K t :&u+:u :J҉ݶ%m)t ;^Yc,9YP-Kc斥AKmEB[XwH.C$!ZD{g&uM*' ׷\i~r'rb+83ڤ\ hy".Z"E\J=UUp\-J1\PnضC 0+tޤ0WUW'+D]%ވ 7ꦢb7x[3Q6C+b0\17 hZL]b.2Z3V&G+"cZ"qVƴI+^c1 eieqL9%ZIs21VǔM+c1 i0L4A `?tQ'`A0Ԁ ]jL6%G3Ke'aFRYE])gpbQ7L"?!I^]:x_C lf2\GԱD&u;::UbDA2rX U'dF uvn`F VY"6/vl5x^`#rL%!#SUe] AL L:372~ 3)`0*<< U1iV%)V\U6ڈwU {r%rMstS8[]G?@+@ؼ x r חLoM0H3zg#6Xi Dąo{q`K^c7/+ ;Xi4R1Ш̆ 1\4k֐Z95k#֬ D7kجDNk9ŚSxɀMߵ:.;38 Uܨ[KX&׊5IM+SvtTN4s߄ppT'AeDy@2uȐoBa@ITtTtEReYLEеMEIv&lNsIj&ydEj.3@Z.NbaC,]J`C˞N>/[&W:@bDb=7yK&=cp'gp}%4Ѥ;g)s}¬F_ 4ݨDnb&,U#UPM2OF 02٨@bi"DF"!ńUP;"n 1[٨-DF|!˗Cf֤7 f䐝7c1z2Əcyl٦q3\7#sFstWoY)ʛZʐ‹E IVO/^aFrWSEOiҘ̒6ALL24Σ إIc\!IM+ 6xWe'^9r+'ᐨr҅{Z:I_$v dPe,f}`Ȧ uf) 8dwʠv!$؜O\ %rٜQ")%ܜSl*yn+qsb|pf\7ZynN.1Lqsv7es~!3N0 E1N17'isrL9g!'9/s;8*{qLLxEؔ0fünSBϧcյ@8ϯ|`rH| ot?x Ҕߋ@S.POy1qd=B%,f=ngw՟7 ۏ_7RK%,xFo?|1N}[kH}]BvѬFϧ34-aN{AŲ+?\$\Xr.MQ]Ļ,gk@}i$|WCjEBĻ. > WAaTzqi-K$ Oka%u.IV UHūTfɄ)QK.^T|QBQ:\=׈I׍*t,3b(QFƲXU߲vH(ۖJ!FWN2]&XssD S~|T?! PuBaYkdS8vAg^fS_+RB m̰ p@a &qm`6Qvhzƥ^=P 7fO U|]*i喺~i|{n+ uadm1"":4\NJ%K?z ܰB=tU_KunEEϛgѕu|t']ߵT͏kL^%&(xpKTcgݩ~M8}خK`ўEw]+sS@ךJ=ХC18WV?%ʞoVսב;Nu> \m1' c{JM>gdF6g䵔+a)% $cp zY㺂8{VxDHCm>ƛ 򬽗y{ޯ^ v쓴GFy >|Q'3rnN h`UD궳_'8|SWt^oe~sr$Ƚ*)o^[9_jԜ/dqsJ'ʚ%nZ,1聵X:a_ kJqʤ2,>0H7zW~kN2 pe Ԑ#Y#?Sdr,c,~wMZϫ͹8|&\lˋ|Oɹ1+Ѧ_wեZG|>8f$ uȯے95}!>^ K3`Nk9.+;4N5CPTݒF0zX\GɈed bti+d:j_ߩR?%zIc wخJUy+✻4H8<8 1.MO 8IcpA^>{7}Xu"Nnc,%;vu0q8oҕ>ƒa&JߔOpꚂ`}/_| at\c#m B ~ה5'DE|;N)outަqVGhQK( YB `yݥRPx=??Anm]-ZY+|HH(Y}D*.ƠBۋN5#zu4N3C$9 a\kg_+GKlY* ?eڋVϹ ly e{Ÿ~MaAth Ui0NyY9ܷz,;gU|>q"o:ؿAD/k^Zl1^?W}"Zǀƈ:|zc#H^ˊ rC;O68^ xLg9Nγ 5ߒ,~ ^J >v/q7Y S:=Mw$ϳӕ{fkTޮ7{wd_Q@>t)xW("g֩y:;_w-Y.˭ʿl !y3b7̔,j7&g!s;ݦȢ}ڂe ڃc{P$'B65JqVK̼ oY=q.**T"FYi`h}OuC]h6 $w77ثxUғ:_?R^3Ltho߄u^h> )+k!( bԱnϧϧn4A'W|]!ޔt(+,31q^!i~t'q35/U7$NEqt nP>_ Xߵ::=MRu}DLU$L}j7^O_R:wiyoY^c5ɉ/ÞDUk.ɳxĩoS_m:8[ 9+Ԯ3_KAVlJdxi Q*5E I{4қV41`[*`.Ծxr⛵eA? S10̩sK`& }ȏ2 kK -dC()KĮK|h)2;Nҋ|8 XޕmPQ]/.వqJ.7'e(sA#+坩7 Rx<EFѕB\uK:Mqc_ѝF1kOŗMȗޝ[Q\ wMrsjNoxiǡ2>2o*_~;3܁~S~ᮼiqcEFZx^( ߝxBW j>/Ǣ'jҜGP #0$r'tRӁ^Ž K4A$ֹVo^rWK@|/q?Ww 0dCTIy-V;۰52eϭr& &1_7MT.ta Nbқ _^qޣ %ǢRRj' Ŀ[e{^*݋ rWU{|no/8~/xV Lc!Z3wpxs=E̤yQps ?|m/ޔݹQ6$k;ܐ>@ˢ1*ןZ=~WO£sY}1ݹ?gKLxs ]*oH,ךէz3 ?+@w d2н !K>/3IU F/#~p@'M:u:덺Gh&ǜ{5?^0ڥe{SaXoC>磯)cRRNؿ_?_ogv;rWW{oo#|?mvߞ;VWfd,܊ vGVe,4kL ʦ|QZSCe@o{*c%ގUFl0zY`gؙ)݁<x?n2w7ýQ9T^XO *U*< 28f&2vQS3Qy*.Qސ lP>%X9a }!+?9 \M]W|-SwDC^뙊CBFS>ʀl#wFZ;>~x!56BIbN 0G &s~Q3J~ K$Zӈ(CnLߟJI㯤rS^٤0TP nY%Ce Q坣u6Gfk!Q坋,WĨ}! e悤]bz9ݷK7o9Ǝ~tc9[F}S)S,Ol+' ,ʡxlk(eWLC7f+~R=K:0~DV;->!+¿7fm(m?ÄH4d: ^9?x4@./j oGk)r7G:Gm$f: rw9rd{g=:2|TA?qBocÿFq t}# t->xW]"uCe'ϔXw|D@^'m1~" !gϟ /xrBu sgK*d=N<|% g䕏c~Yӆw~P,;TKgaǞ^ /qr'OqB>*_|U;?6|7(K'TO >*}&ra痟" BOtܟY[*'`f}Yx@n D j?~q{yv~6K>0c[9_Ӗ(a\6AlG9{ۦ81ˡvY JQemiRPiYShyS6(._iJVC#SzN`VhJތff9*kf yE٬N#i21+Γ<Mg }pB*F [L'/%! @I1g-FܳK}h6Tgq,J|~DnEXHA-n;oPbQ2ֆd1-^,`{ctAXyrXܛ x`[C^-r 1w5@%ݲmUsq$Јg^ 3-qHt+dK:cgZzmLT<=3s_$/:CNn12#uO|WH`mvcKL*lj귝*oż^glII|$ Z+)v' Ōdg K뻘\bPњ8/fC{br1ړZu=^xx1 zt1 x1|@/f]#.Iz۞Wm /M"nw[$med.X2mvr_&</VLurOŪionGM4s~hVdX4s\f:$\;I/VRJ-faQ5*Y糅b ,|l^?xlozm櫠m uX97/uPw7>X7 E}P7h0 70d"V0o`Eu0OPc0/lh0l0^xg~-]DЫ_ė0"P E C$.b[//bi*ԉq">8.>F/?F\p1VnE1*4\ď1 >c6sLBۘgP8E3拨;f?܈b9y Acs/Ȍ}m83I,z& dӓH2$U ◁-"05,{r]d`P&eIsؔɾ'2*2H+2i`Ys v.q;wɣ&S磉«&tC-ߕMM: B255q=K} L.&alM_?m+l}7e}~w2?~ :ѷ???}_'I_a?⩉/nWɎd9'[OJdx??/RNnw?BkRߑ( m0o(>Rc0{9nK֚Q‰V 밷f)|&a Z[?eG%9裡a7 @y  Y HBMTm6zE|EsΟ]jӝQ_ȸ~qi*c#v7U(,y E4.#0UUs&zèٙP4cEla<jwSG*̶iKy-W2绨j2^ѥg[QHhHJ #iE.X1S"|`+-W۲ZJڒX]q\J?7 :i,׿LdzWԟKKrّTs ^o' ۞{^hiRLS'3LsڕܸHAF.&թXՉjrAV')II xwSvs ;s&r:!rO16^,En~"h.L׹\\H/ ͣ#-$Yl%ܭEkX?Ƅmʚ`hJ}x. br?C9 G.nlsj>.@bXcrnHRb61^6hy Cx F>MjQk1UB5QIsNpot?U%'RC8DJsWCEJ?&^}vϨ8 ZqD0nzdnjgV\_uT"u%^e<,"hp9-pf ڙ%l<"6{ O,3 "ta<#vEn˄S, ڢw! (|(|N)})>}](`}(}m)})Ɲ?(蝃x8p.q|9G:- <|ţ|M%?X: j[wϿz/CDD^8iUM?!zINS y?8\9zH_ZY={L3+O_Zۇ/y_Џ~/k㐢2WWڜ7c3~Z_?oȿqUyYЉՐ5Nt~ͨ&/__+vG e_m*;goHCl'v: +f-BN_AR0 ʀUA"Gc;LAHp1Ь\lkJqR#x$*P`?*\S*1)?*&S j9?\!$JD9(H _ {di1n T@q2%RԈR0}iX/ֱ _c--}kMl& (ET o:iR_ꯞ$KZ$+&bO8N$;!$/䫄b]~ I`='EkE |[Wu_.S aE]C6Ev7kDpYs.B*mq%Vq*yߴZ9ߴ)MUƸXנ*0\LG̺; PQ O_L&R+ԆTb)` MwK5M)lAˆz%VN~e $)&ㆳTS됶ZxHi%@KYh"S b8S:%Զ + X'W#g֡de&I]Fl2W*cu #VHllZv! GrMe{ ulל5 h-œ@@1o-vݭFALJ +KuCjqqjK$a-DF,ɞ+4Y ꠃD6SN|F3fr KLF':Є#qL4jV[Pټa l"36P^)sW*!!х1 El!vܴ Ŋ=*"MW}{l7f ߒ|T^mmȓUkulk[0Rmr[[9>oR ~K-N`' ,Ht(rG%Ӷ.R`Qڷ[,cEOˆ tcg}? 2hnp~𻱮?HJC8D!E0? <ݐ1_ )ceq 8Nb0P|GE[Ful  ӳ$mg}6B>AGlǧŬ:˄FH (VϣeIփqcvi 73`̴0$L]˲ O$3YzQLpHR¼NnO4B񌏎+V H&DiNBD/cAR|/y-wnrkpisE&} '4RW5 #4;AAV'U0̲{2LO11=?d$7uBbfN m˲ ʋ*P0 U00c sa"0ђ󘁬E'Cq$hc8H<6H9CRk$ZaX7PɷX1vMۀ&4WcB K:Ie0ɥÄk-7˄\FGygp;ŒpLŒOEe @L$HR$0߁{TnSmw =&2DT=2"DaEh*K"FtFsDDQ QC(b; ( ô3 dm58@pSeq0 f"! 88Ёig.$3Rl`xWo{?I:'3 sOnjb:f ǂlC"2tS[7.qsj4' Ma!9덯No|uuMn {WA/7n6;wgsLȶ8ɐFv%M{`jMNtҁ uU%:SR$E@b"wHŃw1r1ˑJ)`,3p=vSD-+m*$cMTehJIW\Ix 0! ueS 0 -%! '^NB{+=s' *Z 9} r# F '#""T[c 턁o>a| 97ie{I뾔} VKp8a"6LzS>"7Œ jΧ6998_l>J{ΐūJsFIΈgqhD@).ّP -p?ôi蕥0;YnFK\VS]f\vާa%ck08nqf2.mnsx#qke桌GYX ޯLyrҲae2rp`f屉 7%fGO N-㜖%.ؗ.㐖-?h˸ q]02uy$drÝ 4d7(Dƥ.D>Ţ/ˤeL`}Q4VDAU}m]2nqf:?mYn26Fz#q=SXơO]Dimٟ2q"n ĸL\対l`dϾhx1.!e8eԗq/gG^ݿsd[cg4&BC_ \_&v:nTy~8d|ss nF<>Wu`dlx板ֿg8bxw^|$L 0g.sX~DլD7CSxٸ:/a>h'(&ܜ #ۮ#4͛ ߫5-c1f"㌚K} Fꬳ8K[1;UO˔M,vs".3g`[7QL7FG:[PTxz |͸p> }L?Mo`_Go~\lv `>c3p ^?uNc/#|82w;v;e1T~5a~6aJucXfy" y tĤ"r QF6-Vi6kls汃6"b9zb(\6 /K^9O%TW֔c[iU2L$(x?rrfܦ_2ne)4" ڎLs_IJ s(8%'#2aˁS6@ЎtfxQd\*o@(d'uC d˂ A6J|^BRTY>ӛ',6zZniHܖ`Ӗds`K敓qAL5T>$2F]37[*3QhfǮ!Zc 1=4Y"} T cfJx`y1VyA ~Z1 m+zfc-DB[C2@fF5OkTC&ڹ_XWΖ1o 2y#ٺ-^OuV6gi7V:חq+_ieO xI iVQ:ӹou zUؠ*4ByN0Wq˪qXmU nT-hz+XMNQH.wU}N,Ζט5>n>.P}|[y6CK9#6m0yK o%FЂB I ub-%FE }OPXL nB,KZ3/G[ }pJ7 EN~q섴|MPy9Bc(3W؆!AZZ^<C>d~MM Lva/NVI:yqT0׈xqRzՊlnHj*h wW^k3;!Q4X"PcamaH DVϸ>344J\4\BX[G ֩6a:IA59^g哽oeSo55;|gf1AHjoJc֬ SzX4I&&`)NQ >Yυ׸fkRˇ>ݥFXKC^$EѤhhEzG7-\6G7_Ѷ;,mNf(i^7\nk 1͕T4a*9ʠd8D2ڰOo15ȫւ^}ć E'چjM=4#of᭢bvJ0ey!qZ6,i3r&/;njWx3 =ʤ8)wߜӝ#"G]Ȁðp@̽陹:3cݞz:g񙗫=tb=iT >սf6 UyqWfn8 eu{g 8Hi)Mj4cGcγ]C%SDR؈g6te mI?Nu\>hm /F΋TW ;](&Lgz 6i4d/Qۦ{d0/Pi-\nP{?V%A~U밀 q T5nO,4]4bU-7(͒ ĿVbVS)ìv'ѴKs6CiP\`{hF:S[gF˃,oʼ<8[H`'=*eY[<LM1XעȿVmzW9]|4]jw W}Kd^ 76Ѯ6Vouj>ݢH $3ڞ8K|.U~;T r4m]W&kýέ} V]X玦6,i<7lp팡6 ZHn u>LlS Z[0o{'ÀBՐJ5 &5Ma]L8zpx(Nj)ɵ^Z>ڽ⽛&2WAyAy B[Eʤ_x_gLy t n I/b75ҋ;47kSn6Z}^ѵsNN8%DYa BYZ=YΌtsr4}%jYDggmN'޷UA%llFk>=qձ?Ak;=yD xS{6}{&3 BQ۳I63?P5Nu)O-Т5 -C΄APxau6Zdn@@6Q?LϦMDL=t֎S5K"_ӛmPxP@bdx=$nN1!dȰचa"8֓kMw==hEFĒv֧aPʰ͍#jd:T/HO,te;.#~ ;m+qzgg̦wv\vg[lg겭j Ԙ#1uw:zVz6Euj⑩vOa.sG k6Vtzn`3_sw1͹Be0pJc,A⠃|OD* ,P8XH5$W&g0; *$c^ xB67Dmg#!z=Cd ƹ1bL"1p/8ㆭ9ŷtxqCǎ96[tXᷱϷS Vw: 03fPl4}{?s{[zp~67Z.Bo!WA z fTPQKh{7 ZO|~Jht~PHpA~_{BS D70QAWl6N lݱw66&8߶ASlۼ \;mv'K޷01m utmabI129ؙ&F(Ӽ%XZb TKjeX- %>ֱ(ulkk+Zкֱ8ulk)SQ" KG(ѣ|GwվTu,|tmf|O>/`t7lKؖ͛#7b[FG[wC,0,h͗ , ~P1TbÑ҇qi܏Stbo:W.q[c?ni[X\60eCőz-a+HWl E6"\m4YqT7UvfI*e_Hռ !҇!jҬٽs09iF Փ&e4OZpA|! a7 6p& G1y/>2uf4AʏJnJSv\obNov~w;,ꂑlnfbfڬCOuwڣCLUbFnwF2>np/1_|v8W/wK;6m?-]؈M,;6awتiQ\;iTǥ3U-U#+VdzV;ÕGeFkT;aoxdw"_c$x!4%eICݛƤh쿇w\:3xɼNv3)Փ߶QRJO$͉eLA#{G$t,t3t\;tܪGCc89U!="{UPbzwԤ.HJ1~87=U}};I4Dlه;0]:.=J:Ne;S6k;bRJf47X+v̥d֌uk׹k)x#D:|D'P<|6oX'l3L~v[~F4F Ϡ3tom}5Too@y= gӂ5ՠ{C= W̡hj1^Vt9HtR`ւ zT0!Z GDrWg((s/5`܈֊cx`GfL c/@C 6p L=)R$7~"]r<; t82<_9Xx>!>g;i{qͽOf\ iv,hnjG1?X-1G$_L^c\}aoBiZUܫAR`?qZv5̏ne*_ܥN`w:Nœ6st\g--7lg8W6cIL LFD֐"^|I:Nó-u\'cԱl썳 l8~~+@ dնFc}QL_6D Oa<Vc:+}Vizv-p1=ylCF7۾WC#{2d5wȺwzlrRSk#h26}_YϬzXl$X>Xl)|F&e v2]YL.LNu> 7+'՗- f_Ɏm~l0o9y_@c}Vjjvâ΂[~qRYE Z1Sƍ(ZB"Zw;PDkhw>]7UZ÷I|L 叅#$Z@Dk$ȪhY6qo-d~Y! fCd=M~[fO8V_n5JR=iJh]Y(-$눢tgRΓkvQ*jXl9<,ұlc^~A* ׆ѧnx 3{PP{l_CYo~?w¹|3~XjƯ26ho*_2v{}ߛX.߾CNEGZ"MV,C ş^οE.U(v~ _G_Qʽp u~V"MQA8G]:ZΖ^ĈEen6X&QO~ qs0utoAm;ݷU4!8%w1[('7AxnL@&\. MXւV;ETg𓣠ADܝ1d-%`j@ n`H7|u@kq}|ӕDo:O9tuv`DlSOHNgԹ/l T^S۬YSp'{r3 ^9`mnL<': 6o'7QW6i n*Ĭ.9ܾNyqabH繐ɰiAP};bpPIl;ԅB_lH6Fu7/8ƈ gnJCqێc}0Zڱ o l' 4 pBǪ jY'aЧU2O'NM\N dT:}NB/dk ֖ t: չ0m5tBϏck>ݏik\ U=;7%bѽ%P L@.aV? ~?jGDo @ ߔ|Eo/?߼}oqoQk3/ծ*9Lo\b+I7=PU.@gC+"UYJ0x>ZqՇ_iSTP o{/_\As*=r@ D {l|z4_K.P1)Æ۬wP\b|\W dRCvÇQz_oiXÙoq)>5L]gGr`8y|}kVx"p xMGq3\ yNg1358'4hƽj:C/4e j(8ƻx3ݸƀH\Em ~T,k-[7vJHi{T^6YEpj$ 7qTAAt@C=O(z95,QC-͏dР-jdo z-I% qQ}.i-6/|ʭ@(\}[O z:_o$hD4ghLoq=nYo(<8?~/#cEM|c̡π*FJ*9Ejr$!i"#:T}-)3h:xjT ݾ$VX~T'-z8kYgas:gwmxf4QTNŀ//@S5uКxZ76:xEN-ؗNNΩ0K1V?ԋ2*A'ha>T6hd0b>~P;삓WDTY}5Ç ޞ:qiw8#O!5-%S! ṁ C㬁_09Gk\;voЃ+<OW=-KN}{xpͺyR1xO+jب}  Mv%5Q'wᅧD6Ⱥ]MxƧ 0<x~ʙx"?/9(U/g:iBO˧mn6Kcx2[fu's'ě1$ٓzc'd'DIHZ OfmUS@,ϲ:':tg 병Gp`ߥɲ,f 5o]n=<+|sf:F6|]ӂ:,UVzOWtsmDmL;E»G"i1H+8~2zx0;edΣq'@P%4ËJJGO$*dK𴳨BCkONU czL`''f|E%߰Cyx}»ϔF e\T-s_~2iTwS$?Z8<lMu|ų* ܹ~K|ZhfR*ex<N|.)$E3Sصzz'__TdqOS͓Y,X KV ϹˬLvJ 8j+$=I#y=ON5ps{ڋO9:$*]rԘn'?')|f'LҮM~쉍\$gihX4 [k%jiϺGkwg+SC6rKZϖ>ѣK69aH|rKD5MNoZb><@טKNYO>dN`n')*] &0̭\x):׾KeJ2@ÒrXkz_ʧ@z~bWvɜ=yK^F oN:k\'ix4|: GYܳ[9+9|s#7K^8IΓq<_6&C|=ݳ[{2L4{9dy9*"+{XZ:1LKuκbk.z-zOxLSt똵w{rR{}td#+G#~)ptO"K_cF.Ш=<#9ϑ2] @ CO*gK%}~Dn׵d^tRϾsJēJEdY^PAiz8))A RK*BfdSzS]mR'He/':]֭oDeSPiTifTTklV 3Tz}}_gX'sdzr Lɗ%eg zy I>21P7~f>*9G_g@gYп'臓Aԡ|\~䌩9\ZyP< ? u')>戞E|Osj^g+-^Vsq4|PMqh:P8? uʁf/D7u^uP 8>{c>Ole9k'xL>gV^پdS'2;~d~;a|QpOO焒vyq[9l-ܪ彮x>ٯ'V<5Kx!ŭ\Ժ[ Yi}kIY sש91,csT3*!]QԋtϪJOz:A {%m~hgd) 2sW|4u(: (SOs_gOT ePԃp +ܸ#Bg% )Ӑ:O^SPxDл*!#e'%SzrbpQ'l=9jav"Î*z =zp&>_x~kf;81;zNA>TQM}ΔQ1L_U=t>0?弞 ayV Gz Kpװ>wYqxPrs6>\@Fig Ї{G9c,'JR8ɗ2(X{%nU(]Xlyo?&?{|vyQ{}oŷ7ѕ`q#o[CIUЇXMBE4B*E?V4p*v 9TFdLBKA^cqp#D\a9˔+9 P?nk{X2BT'x$ 猠ʿ}2B,j[B8 gIp ^hk!{6E"*+VoJ";&Ȫ{"lTE ;~`:Tc%Dz24Ҡ}cg= !\H+Qŀ! $*6B)J(N\kdm/p~\Brqo0l24k${4pie`y#{t -szm%]N`8yRJJё 1̏~h띅*F崃q^H)U%ek0`|*g@U6౑AΑ;Nmu9=#FP@㰭u&VOb#$L=B 1BERX!M#jQԊ1ABVg̍؟'Y7E-q27 lBh$,h4#% Ӄ.Bs>V8LECj/8AARE(Bh KౢoZ!EUaǚt0c =MJ$q#h)PB,7BU{J'0XojEOk|d5!`5f=aXk.BkQxsA( x, ƹu^/sNneunѽ fspnmml;%Pֆʻ׎}΋cZ2 \hȸ%Ud;”\2 .$du'I=-hml\x8%]%i%~ ,lO.xe%᭘ŏCDNkN~Sܘud2n}t2mGc\gxG^D2N}뼶X2.u Wt+tBy,ꮖKoXA|dRgH\k[ʕsXڗ֥I>M3uWd,BtQi-M\ɔi2a"5c-U]o50ҥeRe\`>ϺX#v7=>fSXPn܁1y5w3H^:q˶2bYgFX{ }wWne;{p{?_=ضOrǂ>Bk~%S-nL>PYDk}ϟ[PGH

A=$KmV֑pwbJMYnv*{;NqsiEJ).V#`GA =lo4lX-C[ؘ4N$4(N˽Ӱۻ<6$6tw$u`sI ^ PF/%qstn+xKy̙e[n;=5\UIyzgozg[_8G \P0#uhs'oəEXjV'NXOlyo9d6Z99LKA;._w'D\=ѓ bO =@/dw>ܔǔq~[NkT8pѭrĀ2՟8ocu^ð+}粿~:S:G}k|_ {BX!U +qſUR+XK5h w9݃p2 m}O{\!% Ɯ(3+5]a- ; uwMVh7J(J61 RCmܳwQGEJ%H*O7Zy1˳Zw8k-}ѱyڸ W+ao*w,񔲽~IjKQalTݧ&?{RӘa@-)c{S#*"J4*d)3-2c"emy6LzϬ8z6GO` ̣7{tV0 &@zB>HG Ga",P}XÝ4qIt0K QAAO?AסO7F?ѣ/6G[z"м Fa/}u(7heǨH^ͩCKiB6W5!xWv JM5LtAtPkR%P zV 7I3/iӣg6v?9%. ,@[xijqXna0 ˎnDPh1hXPјgU#< v0T TcHاm*PWîe(t[G~(yXevӦA8Xitj ꕼ ŕYqHfxsC (FSҸЄ)[f}R+%[HBnp&J93.NYP,{.>䌭ʭq=US*}j л7n ;Re6IeZMd;½<<(+ KJD("zI @5ȎcXW dUk,;MQNӲEЕ8j-Ţ5#%Sv#2"ZJ2Hλ"0 ! P Bg/8`KQX(@OQU -H6'ѓy֕ ꏍGdzOl@x 抛PF^dkFޘ-aA bU y=%!}=E+ lT+*z~KT}Ƭh)ZeB5/}VjT:{Ѫ~A<'1o:z3ϯ<@2NakdC&(O*JDa:e=e?S&89'e4-gNoA: 2W A%hAJLuIV7X&pU4@\؉x(gTq;k ǥn䯓~7n .l%?M,(". j ^2..>@(!#}v4Bh}C#BFr@q+c : 9-"4T %fBMHDVfH3Cg BB1O"HqAֹ0E["3@L  @F%O&@*NB@xǔ0@֭Y'ų% H=!.im]"MRFBp#!ptڍ-!p/e%_lIw`89:3]csqeg܎fg͓ǖ[ -[|6-7r@^|3`0C %%|w:]ڜ xnۮO $YB08+`y!ضVm`eP& &1L NawJ ~2e['CM ~E%!c"RÑLC ~EERC+# V+ /Vm] 䘓/J>n9q(xQz"!BN-G׮|m^8c/N $1X% {Xʏ3+?6I)49-M`}=_a<uܘ&Ɩ@Xt:eK4/M(p amaυaWaf$=F726PZ w{sqO2gX:,I~ =nB˛u$7I9n s8!VZlf`ҎAlV'ԼقB}fO !⌭?oZjB]+z$,ױu \=l6jݬx!BHm!Wݛ CeصHg!<7RBg$tzn}li})m"Sh?nזJ3V6KOtnz٬E]ٓre8umfjU]T6Wylnrn= arr,dL3حx!FmsB'@lݕs& BHqHBQ=#"B\~ЮY!gmB$F5} ֽB0jj3@*6iD*Bm!-R u3 s/m6_ͨ"Bc!-" j1"з,[sxB[Ho$!Śo"ūB[K {T,V휱b&`-Sjb$h#!;,8L;Sm.B8@$)✪ׅP2xHf/*??ΜRemI~pl3f@"' $%_ʀHRŎ!aw_ۂ_}\B5@odM|WFg{4@?|%ì l }_(v3Ӗ+l+QP}ʞY̊띐Y#,c:Dt`8Ϊַ,Hww[%tIlI3^tS!!Iim=Ewjoɐ~>VpXbC 3+"bUVzJTv;3% ~\.eKsɕLO=JaY{9e BkhT)S-xb˥`%aU ϒH`:@%,U RWD!Tc~'4nh8YD)I!R)r N(c?Q 4ļC![:aML4F !BvBQPVKgpBv λA[h[FX se 䘛OiB[+ֶ_%B{,c!=Y {ˬ=YiχVB2ۖSe] !-/[ y܎ 5sۮZ:)3ȕs!e+nJH[&,޼65ܳᕐjTpk+ ֙B:~$t Qh}ݣvc-Y bWT.+r'%Wc(HNDj3e'"!a f4-P5!{V]dϤR$S6 S|_l MQqdw$" wKIȖt둵 yoۮvyRU ˌ @؏%F@WV STP-} }abra]YmCtapdn-: A2L%S>@g?.θL3Xh^?J*hk=?.cH wB*t5nDtp | ``COۍ0iPY&{`F0 .u,7Z ѹ,XV.c3 +z,vcO N .ǖ3eGi xcDx#]xAq?F%FZxJojo:oRRSi:3 gYV>U`TVԿ4λ7{`aFX).FH݉g#{mb(ΦAhJK/1 VgC/q"BPڱz(CĐ26A y09kaK4ٽ8/BvNޟ`tmB> "\k'Bo%" vf~gM5v7@ڇDpk)Vض03bI1úkno5t]EM l*P`8-rX8of [E^n\m9ܯ2]9?W@g-6NhxzlYb6_Fuk櫨ӒTp8.o oO08 2"qs_Pl\AIz> O]=ji'vgI.;Uq+YIumQşetPp^T%zY 8E5q\HFANfPN<_l5Ap?k9E鉆QS956ʩY8F+m_NpWJ+2dݽw=yWwtwyJ @§9MX|kL}qԖ탢V[9FߐTᱡy^?<$Ж"<;>Y劂 ʡݠ^w%n=j[랣xǩ$a!~raK!.fTDrxXJrտGb,9^Twznr! s\ah5_ܸ- ; >NWdwN;(4t_jek(M]iEM˚7-O5 D45b_"G -+>l9gFeV* ׷ډ/w45=丕o!)B[7< * + {!yȪN1C/ݼ7ByHVhΨw'%RZě􃿏{҉ªYdB;?/@b6 w˦rEYl9M (uIU{Oߑ@܇. <ҳa~70%R`z[^_?lLDӜ:} rR46@.T,B5]g K3~釓eGjD_Նe{?%Ѯ[ 6 $oScj2 )g͵l{Pn2b󻬚oIbM%ލϖtW߷s=iͺ'T7@Lw*yw٣ цyNw6@e^"Nrm4DpRfyks-T̷{/S*J:ѪT=ЏY4ӻ2?غ\k~\'h/2QX;t>A8(J᧊yy;yա.MpB QPvW{"q^\W=q~NgWv&>^zrTѷN&G!cDϗ߬>GP7yэ2̓hsq7*V\ɲ-49:F?Q ׹ߘi6jjmrs>J R/ϹZP -"#s]l].j:,fE:tYZq>=d>D=6'.ȝ7 2uuO0 vP R`ݘh5'\X܁G>qy&9&Y F;Xֈ0&sn2wZ3uc>,Ld/jڈmb?(iKf4JDFK26q౷DŒxTCĦ1O ;DQ=d}ΝM"9Gz э?/߭l#bGoӲtYm*6z+OW[b.-;fASO ֱ kTt^Z*:OyZy2y5ZygI;@ qv{Zj_I#`񑴡cmIX_nn^qk>64ns]d8uATӞ>иpd.StՓWe=!gOvӓ^W(8x7ֆ)2^K/qҙiO huɗ^7u/XtzB2b^xN=&Ӧ:܅-;<_~u)O>}|J/n*Zqlk+;mW9b׽*GL. F792l=;C%y*GL库{Cqp%Wǡs\2{6`),>P1xD[zc$Szeja!qTꥁ7_zkss"쀽qZGV{A['Aɑ ܣ}R{af_wLơWw-{sjrN>TUȹJ9R*Lu*~Y&:C~=֛9EΙ\l*4>؛9[W=Ug|Z-׮|] #>ncv2#Cҏ;-?gGS5ˏ5Dh׺4|4+$qi<%ޠ~P};>gǎj~oCGxݻϦda 7a۟rM1uFW{8SFW9uEW/|_ t]~@ "藼Qu42ˏT9$@?t 3ԁH)-?w`rXr\8ǩ6i!Q>DGe҃bhYuq5omd Vwm 9Ɲh0.=9\s}]+=-\e\KT'kϸ}z ̵|>]^asKu+oHl5:W^dsM溥WVev>hoѤ: ײ?_ ~3 .Opѹ={ެy~˰kK7' EN?'/K轓cKs!~_q_$O}M}brqhD\ch\T66|C2?8wg\3/]G׶9}ᵱ>yyZm<'@]A@0oS 7ctAmX8 @I B(I qp,#.tO,\\Op=$.­fi{A\\5\ps=q.\\ױps8nw:}uI p68 ~a^?!VyL~K7σL~=p}kOx |{[j WpɼxFy0q9Lt͋z/ل4y5ց5։6֑6֙7֡蜷FG::%:5:F8.<)ltpttt xt"Z_.VCcNcccdNdk޴}۳JJKNK$K'(KG,>1KnG @ΑR8SZ`vs`::ߗk{ފk|pdl?Η_x>Sp4sKW:u^Z:0OtU)瀛rFgHI/v\5ݠFwK=(6k\b,_~'߰V߲V'.WGnWg벮WWز.XײnXX׎ K)|e1<~Z K',uAȬIɬQʬYc1iͬ qάycKW\'F'on]gN]R]V.^Zn^^^ct?!fdeX{4?{n&(ay ~>Oy4}~_(ݿ_ Os]y>rA#SG=,X$H <wYӋG;Pgo}Yt\>BCqq>Z3|]u\o}Nt2d6>)XGdeY}Z5a2}bpo\]3ׇkק&gcsX}p:O}љ\V3%F= \5v@ 40hf<tM@-$[],ї$AZYfJg߃gQieC_Itُmq^G tCZTK~TڰGkG/t?:;S{ !D0wH_ .{Jܢ;s7hfVTwkvj$ n5oɴV8WInn-X}:vl? ɵ#odwZsmL_@(5y`ϭoBql=kCfkP];A^_ZNBJٵ57uF.o 4^1K[ Z4NB}@H# KudhӐpʟE|Fj\#E]́`3ڎ!'W>#|~F{foU_ C\̏T;j7SϕЀ]E{NV-h6נ}V"9?`sVWmɶS^O#cjB=yg<]lW!]\('3xB>'(.S"NIzkM mt': $@i}GX}!q:VXmQEw9<4[;b! zYfGd߾w󎛕,dHbMFTӗyy"Q{֘2A%̰ ħ g=e@) `pqCz/V Fmoڅ;|\v*}aN2C?/[ۥ\_BDo-?ɇvkָy~t8#x|)?3d:C_=EndD%^<{ v Wjn }$pH%kgXm\r#ɈudwlooW+%́.ҵmJknd.dwuD[<A]~Èj򲭪2dxіwkV,:P _Nv5WD~)r_dQgL_ᅖh2{ߏqA:6յ[o ,6li/ŝD~J|t_dǃR[̻3EJfa6`cG|sJO>v{2b.)mSdN:+jTb\۱wPT4q77&sFv/?}>,VoV&vӖZzgDyoFx.j5'u$啪ܟQxXF[CH 2t.ƼNEwf_PrGءA.i`US~)⊰^$~W|H/i~3{Z9Ȩtr 5U>.$uKotʀLz)cvN|ȽgDr"6,k'A8#(g0lLukkQ.Ӭe$8){7f^9t QG9ه[hk[a_{] |4SF|_X"7{e W+R:Q/c+{W }XCy.hR?D^<9+1rY&2:\<*eQ]ki#^.ٹVmYW)/{K5/ݯOmXXe=\n$x˖&@ "ᐘEU~>||Vn5hRO)-t~>r&GP]$LNHG2 ]ٟv5WYD;#q:13Fp^Ľ5{5;G'"VUDElL&/Xs^F޽õK8s_/Mu5#6U |WDĿ<XE-0~䝶/ӀôX5>K%/щ$/,TȘdJAw{V /^q]#5*H p8RPtu𔶦dLtF"N`.ykI> 2`s M߽)1#;ov03# ׈fI@GI sh/%#ᵽ R1nWۭ[2@& d ؟ Hbc{pS?sT>껍(P&'K܋HmN$9BG;oi,bo,H]^ޫ=F";wo̘+BKEN*)=MX3ݛg)े %^S?ظҴ{i2h?>b t9fE{}i{!3]5s n݁Y\ECr4WH=s-U-;$DNE8;3Q"fY$=E ;Kp;RZԬ_Ӌ+VzF3H5@dC@g?̗^91?2Bj<#GwG#^|IbE׸ H}4lPKWd̸2yG+KDŽ[u=0zv-x&n MAtӳ)>-ۖj- ТH=blm@~0"#^.iHTͷM7oڳkwM2 JHnDBDb!W*"h/k*W#мw Zr0Ōx{]D'gsfHWG{swqZѡgAaU>S1 6u3>K\퓄6lq؝\XGew#We#eh]Qjm 2Ø*JQO`e(@>[lw6?'L E">u,:In-޽S$HȾ쭩;! 2T(طJPdo++V"*4k)n2!B-I?Kě m=;<~緼cQ B}gG4cؚKEr!~w}ӮP/^2o@G"}$R UyUOYjD*WuA uf"VP}Yl6R)ag$M9,р%]fqd?8#ItGLHeoړN]i)^3APK`H<(Lc5;y<ˇ5`"5ݜ`ܯ11? W#W"" m-ٟlhP' ҵ?PZLg&*&Ǯy<]Y nb SbP NafDw#/0Ô%ߧ.#C12:baGܓ,^1K#S3Ċ>{f+IgZC(ϩ_=d)Rd.(WIO ZD _~ Əteڿ܂i~}AiJ !+'ޝR̋.zE=,O6P+!TՌ)b[^sWj3Ka[{o0J_<]Lb\(B:T>@UnwHپverDܕW [ޑYYDtokoqt`ngkuxn%@_Ǹ;l1{G:b`FСnE:H@/ҙ|{C&!c74ܟ@$ Q7^.\c.OLĆ轢~N/θt#޳6ЂyV"46j_G筿{ftuN3{0ḫ':^$ tI Vlv?Jk^{oށQ G-5}~N"atR{C`ޜ)RjCDAF6^3~Jno?W/CEm/֔$DdO쐦_V^F.JąߊP3x`̝Qȋ5<$f3y4]n~W5r`sp-+.J_x[kXFq/J7R0&C´|Ϸo%!x׷x/z:ArK WOX8Z3\q_#0M5@ #dJrA*?$B֟Mp[ һj$&un#(T0h[#$l[Ys%'yryal2I)!4d!؏#C sM8IXf[$B($!Tr5)$هLqkMizL =IԋJPCUTZkD Y"W5BJf~tƐ쑞d,$g&dJ ɟ9wPB@#Y@Ig}#,l-zKu":!<г J$pON?Ѹ?9RAPwB2ʖ $@ رaQBk[N#y^JTI*.he!'T#KJPNB?0yA\' z_T$;d ~ D&dlW%Q7n0\/lt~ii;RJ֛`0]fُc3' رN@p: xjo+@Y_{J7P80O5AoM>4Qol`loٹbZ1ޥٞ>*MGVt?njӛpy`. @ 0a,7!W#L}X=-z' F&\i(!CgEYIh;$m:9 =GDGS; j-uA2\j)&aaJO2 \BFMᘺ=O&ᔟl_–'-!̻ A&•?0{ b9?֓*w)3߶ ;,~NJ0S>+"^;9Ty? rlwxlrs|:{5zw>oD=M7J=;נiܭ ,KfKU[T1ĖJ9tCJĖʱyH:dMHRi+򤔸N ڳbr}vS9l -/7 ͌Q餕&P!KW"{36KSFZΞ'fV 4lI(޺Pв?&@UgheLB.8,I0Ru)h)xt0  'asn>gtTg eNB>Na]x''79o$q] ,zJ-U,aFwFhB/0,=a/hp%)wQ j\BD/6#9o٘^ Wv߳ɵ^#K̯D;SA7E/9 R:$w|Ihy϶_J(y]$W̛& |D@%+f0 L\BU#2LP$2aэg4 ҒNC]tTQ]hUT'<$J=+\.<(!.r5E5J@ml36 pJ(E V%좁Ji/F#d|V(al>+lP>J@DaPB/3J~d 90?KF(.*nZ،N~pd"Oɓpf#ȯ'rm,Gn혂G֞ i$.p'w+xdsXL#f#X{w}~&F|[9{8:qMܒ ع%[fkbct /FsjѼƒgL:.{]G%gZrb\pQKΏaB.U"ikuH+K[ to_LpK9(a1Z:wR8@v!rK۸2D]7(7N؀5NS'5u}+k"et}x\#ְf#ٚ0]_f;/;, ֙$ tݰnM l_ïZZ^h;$O;St}lv} ]Ul|k顫ѣt݀*l\`"UQ^he^Gkùy,յj2fk8UPI)wuhYϳ}Ō >oCe꺣}?sN>6N,̶hwg")Lx%U@ScP"QyjElX[Mjzֈ5z%nӝqBxܿlO†Bsw_]_茾"F2ۼת/$ٲc6F$|($ڲYg1ֈ6F-uﯸrkG-3ct-&,k~}e^kW\>ל5nSֺe|H G u+TuM~᙮:I:_i_gwS?Y姈Z2>H-,oI3-<ԺZG2Y~AX#o6tۺ[wƺqݬu]|򭑰FVq7? RדN<\Ճ/u=Ϗ o̮R?}c~1C3m,sOߘe~44橩5MnWMSjIo>Є~.h1Ou@1q mi@J;AnAO}%ڗ  1 S~U [U c~V$ kV, s~W4{WD/P## dD(^2>Lo;Q'C eH/)Ĕ'Š2> UƯc(sY1NhCle `<2g_ pP4h1C>fP [M83i hG &svV06fY[mBjf#dNv?@oo |LS$WAᙤڼk}B+z@07((xp⩝{>k)w_Q螦y=,O%*۝i8叿rdd5?1[A'klDo %pm'_!B{'[r>Oҧ_\pVe ~ImO-?yY+*U 24]%yu R=N  }9*{݉ÜRr[5&ئ#iO 0j•t$j]}:] &5dʅPLbmivt|l4%)w0SkԢ$շ#&0"txkXZEd@S!s5M70IKm.WH2Snt$.(*K#RZ;vAU],6@E% b$R7aL39H [Sd5t4Ln. mAH=W(X!z]N`0et~BqSgv! LKhawL9%AuuDV$]5]aVvuIk*|.A^_<-w )/xb+ISsr/@P76ԘgLS>BPs?!m-98 cb@oqzendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 1296 720] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << /GS1 12 0 R /GS2 13 0 R /GS257 14 0 R >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj 11 0 obj << /Type /Font /Subtype /Type1 /Name /F6 /BaseFont /Symbol >> endobj 12 0 obj << /Type /ExtGState /CA 0.702 >> endobj 13 0 obj << /Type /ExtGState /CA 1.000 >> endobj 14 0 obj << /Type /ExtGState /ca 1.000 >> endobj xref 0 15 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000153781 00000 n 0000153865 00000 n 0000154026 00000 n 0000154059 00000 n 0000000212 00000 n 0000000292 00000 n 0000156754 00000 n 0000157011 00000 n 0000157108 00000 n 0000157186 00000 n 0000157235 00000 n 0000157284 00000 n trailer << /Size 15 /Info 1 0 R /Root 2 0 R >> startxref 157333 %%EOF partykit/inst/ULGcourse-2020/density_2.pdf0000644000176200001440000001632414172227777017750 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20200419202302) /ModDate (D:20200419202302) /Title (R Graphics Output) /Producer (R 3.6.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 3569 /Filter /FlateDecode >> stream xZˮ, W(zzlE xEq"4=}A>u-$V"Oy,ϟ>+e{ F}Qߏ??~GI9twϏ??Gy~~zLOyS6"~|ڴԾ9H|^v[#qQh˧֓WeQ,G5ͽd57K^W O6>Ι웓vx. 4'{sbJ7_喹g{K;apuWMIQ:OeInz+Rn}st48rꟖgKrɴyi)*8`Nb U2%xϗxq&zKƾ:5__z F4{]/RkEeKY@Z&Q^,4Y]EmpfW(z3POqYhLsT/ji_ p@#d][u*wY"xEЋBPB[/Tj'V"cz!gxq"ФAi^ ;6"GH/4x: É^%5N9a: Zc'KG+WM{XeU1oz&X7? Mm3 s6H[sĂydRdd !S<*SGAg.CFek ̈f̈̈O-2 :Y16mVx3&vŚI b.QgΌ-)܇=`3^AȟɈI8Dɳ \bԔ„e(EyuBVxY0FkZ>=i:=IPP³n E¦~_ F@ <8A. SٵU>EBA$0*{7X)2dbb"C"|-p`h(8 j>_ks  U Fl8`lfVCxkmU*01pÝۂ], ЍQsckV ` F^Z.\ RY$@қo[A<9 x\Kb/J67N{3dBB2-z dO1"t@Efe-C^Q{!$0L*%VcIQb;%N{sV\mrR@N6YqGgx`]I(o+ҞAQj̿("Ljo\TURD YjqldA#T8S$&?!-`M-^a!.M0G5;rVc\~_i?m[$ %LS!1` 5>4f{ R2x0~*ǧp:R 4HUP Q%OH2T;%)r~`[7#U(C>1!oVGhM ?sa3o0b1%I>BR{K)(.Wt)A>RFŸ)CIِT7 Uх XgCC|-.LȁՔ=>GDGʄa+s!\yД qbu ;XGE!)+YNXf!ʄk~Z"ie"*r#e"ǥaCm:E>RFZS<%i?4LdՆf"5 ,,5hoA.e*wT~!{Ϫ}e5Qē||Z'o{z`a/x%8bZP6_QZگ??#WyYpyh}-yu^ ~6(:WI>(!kV4П7 &}kПn'Ow 7CǺ!K㮄ȧ/6?c#'Nh}K5z}?c> Л;ъv1_-pbʰu1_8F:BO ;UϭT^L#_=׵hH̗K2tzI<[\;~!!<.>]08~$>#)G}A9X>!Пoצ3++ y=tQ~gKC;zQk{Z<ɍ "⮔~VaavYbTYjNuh`%.͌qa<4Q\=[K`KCl^uX% !fHԼ}tY;+qJ!]U`HM2Rѻ)Cb{2wEʽ"!+W1eXEc {UbR:+J]Nzjll E-VD pz琑(J}p*l8!4$B:iu>WXL5y UYɋC>bXZ<*| (ͶY;Qq6nUuqLoNu6[$g;tc70@jjJ[]շ Nt1w4qiN B7v'#`^X hh3*|AF5 g4J?/8NW#|oktF7Xn YޠF@?}jW;ڴt7X.a۴Я.?aZ49qɛV 6 [+V2YKYo}lZmx#Ѝfhڂ}}}:ގlz}ޚ}޺}ڃ=d./c4?2UW#[z*]_Z"0>?7endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 792 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj xref 0 10 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000003933 00000 n 0000004016 00000 n 0000004117 00000 n 0000004150 00000 n 0000000212 00000 n 0000000292 00000 n 0000006845 00000 n trailer << /Size 10 /Info 1 0 R /Root 2 0 R >> startxref 7102 %%EOF partykit/inst/ULGcourse-2020/code_tree.R0000644000176200001440000001137714172227777017434 0ustar liggesusers## ---- Data ------------------------------------------------------------------- ## Titanic survival data from base R data("Titanic", package = "datasets") ## turn four-way contingency table into long data frame ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" ## wage determinants data from "Applied Econometrics with R" data("CPS1985", package = "AER") ## ---- Motivational tree examples --------------------------------------------- ## Titanic survival: CTree library("partykit") ct_ttnc <- ctree(Survived ~ Gender + Age + Class, data = ttnc, alpha = 0.01) plot(ct_ttnc) ## Wage determinants: CTree ct_cps <- ctree(log(wage) ~ education + experience + age + ethnicity + gender + union, data = CPS1985, alpha = 0.01) plot(ct_cps) ## Wage determinants: MOB (based on lm) mob_cps <- lmtree(log(wage) ~ education | experience + age + ethnicity + gender + union, data = CPS1985) plot(mob_cps) ## ---- Determine first split using classical statistical inference ------------ ## Titanic survival ## - Gender plot(Survived ~ Gender, data = ttnc) tab <- xtabs(~ Survived + Gender, data = ttnc) chisq.test(tab) ## - Age plot(Survived ~ Age, data = ttnc) tab <- xtabs(~ Survived + Age, data = ttnc) chisq.test(tab) ## - Class plot(Survived ~ Class, data = ttnc) tab <- xtabs(~ Survived + Class, data = ttnc) chisq.test(tab) ## Wage determinants ## - education plot(log(wage) ~ education, data = CPS1985) cor.test(~ log(wage) + education, data = CPS1985) ## - gender plot(log(wage) ~ gender, data = CPS1985) t.test(log(wage) ~ gender, data = CPS1985) ## ---- Conditional inference trees -------------------------------------------- ## Refit CTree from motivation section library("partykit") ct_ttnc <- ctree(Survived ~ Gender + Age + Class, data = ttnc) plot(ct_ttnc) print(ct_ttnc) ## Predictions ndm <- data.frame(Gender = "Male", Age = "Adult", Class = c("1st", "2nd", "3rd")) predict(ct_ttnc, newdata = ndm, type = "node") predict(ct_ttnc, newdata = ndm, type = "response") predict(ct_ttnc, newdata = ndm, type = "prob") ## Women and children first? ndf <- data.frame(Gender = "Female", Age = "Adult", Class = c("1st", "2nd", "3rd")) ndc <- data.frame(Gender = "Male", Age = "Child", Class = c("1st", "2nd", "3rd")) cbind( Male = predict(ct_ttnc, newdata = ndm, type = "prob")[, 2], Female = predict(ct_ttnc, newdata = ndf, type = "prob")[, 2], Child = predict(ct_ttnc, newdata = ndc, type = "prob")[, 2] ) ## Refined tree (allowing small subgroups for children) ct_ttnc2 <- ctree(Survived ~ Gender + Age + Class, data = ttnc, alpha = 0.01, minbucket = 5, minsplit = 15, maxdepth = 4) plot(ct_ttnc2) ## New predictions predict(ct_ttnc2, newdata = ndc, type = "prob") ## Fitted class labels and nodes from the tree ttnc$Fit <- predict(ct_ttnc2, type = "response") ttnc$Group <- factor(predict(ct_ttnc2, type = "node")) ## Confusion matrix xtabs(~ Fit + Survived, data = ttnc) ## Group-specific survival proportions tab <- xtabs(~ Group + Survived, data = ttnc) prop.table(tab, 1) ## ROC analysis ## - Set up predictions library("ROCR") pred <- prediction(predict(ct_ttnc, type = "prob")[, 2], ttnc$Survived) ## - Accurcacies plot(performance(pred, "acc")) ## - ROC curve plot(performance(pred, "tpr", "fpr")) abline(0, 1, lty = 2) ## ---- Recursive partitioning ------------------------------------------------- ## Fit RPart/CART tree to Titanic survival data library("rpart") rp_ttnc <- rpart(Survived ~ Gender + Age + Class, data = ttnc) ## Display from rpart package plot(rp_ttnc) text(rp_ttnc) print(rp_ttnc) ## Leverage display from partykit package py_ttnc <- as.party(rp_ttnc) plot(py_ttnc) print(py_ttnc) ## Results from pruning and cross-validation rp_ttnc$cptable ## Prune tree (suboptimally here) prune(rp_ttnc, cp = 0.1) ## ---- Model-based recursive partitioning ------------------------------------- ## Add preferential treatment variable to data ttnc <- transform(ttnc, Treatment = factor(Gender == "Female" | Age == "Child", levels = c(FALSE, TRUE), labels = c("Male&Adult", "Female|Child") ) ) ## Fit and display model-based tree estimating heterogenous treatment effects mob_ttnc <- glmtree(Survived ~ Treatment | Class + Gender + Age, data = ttnc, family = binomial, alpha = 0.01) plot(mob_ttnc) print(mob_ttnc) ## ---- Evolutionary learning of globally optimal trees ------------------------ ## Package and random seed for reproducibility library("evtree") set.seed(1) ## Fit and display tree ev_ttnc <- evtree(Survived ~ Gender + Age + Class, data = ttnc) plot(ev_ttnc) ev_ttnc ## ---- ggplot2 visualizations ------------------------------------------------- ## Load package and set theme library("ggparty") theme_set(theme_minimal()) ## Trees from above autoplot(ct_ttnc2) autoplot(ct_cps) autoplot(py_ttnc) autoplot(ev_ttnc) partykit/inst/ULGcourse-2020/density_all.pdf0000644000176200001440000001463214172227777020357 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20200419202258) /ModDate (D:20200419202258) /Title (R Graphics Output) /Producer (R 3.6.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 2743 /Filter /FlateDecode >> stream xY% +ɪJ7p`8+}{g`/`9]EjG}\e{l?ugZ_=#Xb/P_~5ϫ d5>`n]W{t$CM~ HqsE$@\JHc+^)i`}߹ʹ+%]Mrm7?{jY޻'>H[ƼuXw87F7h7ЊBk'oAU`ġ0a7h'ܸ 8.tk:۸C޸E`  `Nv*&2[&qPv㦞ą< ~h\ hpc3qq݂nC_|r$;![G|l}oAw]ۤ.f U2$_㓧$NEEuB\8EB \"HIE{d(4`.aTߌ }ed"Ky5bNJJEfP*; ͙mSI85_y%fM&lu*HC5t!ԇ!Ps`n*ĥ32!26&BNHʬ. 3D(H mtpfɁ ՒP0gmUr=wMsAڬ~n^Q/OބẂ!P~S79L{? -|$ }Mő0tXmG0/ 5 wLc~R0^~? Z^P{cIGdx,)c )z?A<{%aH'pO[*{CFU!7ێ#Kf>(pH%AzY(l#|ӬjLlZڨ>'X'/YZJ/&ϑpMBk" o9^N OHT/C|~=n7NjF63_L ePx{pׁv˧c|qN t.h}~%{= ΢? ~HܼA(,w3_gK xȬ\8;zA ~W"淹%Eǻz<_͏?_*< xIT㫟"Ll&nzKL1 m{6N |6iF5>q* _͇a|q}xlK, 4cһ9;S7<a.;X{ *|`t~H;/ xԣ#0O4NŃX:8KDyGkֻ}fi?\KŦ ={z_=ƗƗ| £e*8b+oU12mxԙ-33=\G($/O'cuRdJl6&y!l7w=NU6ɰ G^GkrAzM.f40-n KlN 6uCi&V%] mFg-dZ-b˂gAl~1+j#.O,͝X[`HL}?Hm|?bE@endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 792 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj xref 0 10 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000003107 00000 n 0000003190 00000 n 0000003291 00000 n 0000003324 00000 n 0000000212 00000 n 0000000292 00000 n 0000006019 00000 n trailer << /Size 10 /Info 1 0 R /Root 2 0 R >> startxref 6276 %%EOF partykit/inst/ULGcourse-2020/Data/0000755000176200001440000000000014172227777016220 5ustar liggesuserspartykit/inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200411.dat0000644000176200001440000016114414172227777023003 0ustar liggesusers# ASCII output from GENSvis.py # Contains interpolated values from the # GFS ensemble on 1.000000 x 1.000000 degrees # The data in here are for station # 11120: INNSBRUCK # Station position: 11.3553 47.2589 # Used grid point 1: 12.0000 48.0000 # Used grid point 2: 12.0000 47.0000 # Used grid point 3: 11.0000 47.0000 # Used grid point 4: 11.0000 48.0000 varname timestamp step mem0 mem1 mem2 mem3 mem4 mem5 mem6 mem7 mem8 mem9 mem10 mem11 mem12 mem13 mem14 mem15 mem16 mem17 mem18 mem19 mem20 tmax2m 1586584800 6 275.542 275.703 275.528 275.561 275.705 275.578 275.598 275.359 275.260 275.534 275.607 275.574 275.587 275.629 275.563 275.577 275.452 275.409 275.500 275.594 275.653 tmax2m 1586606400 12 284.190 283.383 284.074 284.644 284.203 284.273 283.919 283.722 283.923 284.557 283.641 283.899 283.673 283.314 284.096 284.161 284.057 284.695 283.901 284.032 284.274 tmax2m 1586628000 18 284.059 283.532 284.217 284.378 283.167 284.139 283.993 283.877 284.115 284.657 283.531 283.851 283.615 283.312 284.043 284.195 284.160 284.588 284.451 284.470 283.450 tmax2m 1586649600 24 277.687 277.855 277.691 277.887 277.924 277.457 277.735 277.319 277.457 277.762 277.794 277.638 277.733 277.803 277.741 277.724 277.809 277.592 277.618 277.689 277.818 tmax2m 1586671200 30 276.835 276.880 276.956 276.825 276.872 276.868 276.925 276.764 276.903 276.790 276.921 276.760 276.794 276.824 276.886 276.830 276.982 276.912 276.947 276.947 276.899 tmax2m 1586692800 36 284.098 284.101 284.220 284.093 283.777 283.880 284.312 283.620 283.667 283.954 283.866 283.903 284.298 284.016 284.187 284.095 284.320 283.645 284.272 283.846 283.884 tmax2m 1586714400 42 284.260 284.363 284.461 284.434 283.920 283.923 284.479 283.880 283.793 284.180 284.050 284.227 284.566 284.182 284.433 284.406 284.616 283.867 284.480 284.147 284.123 tmax2m 1586736000 48 277.436 276.914 277.547 277.168 277.373 277.569 277.685 276.968 277.321 277.360 277.574 277.119 277.167 277.546 277.556 277.578 277.613 277.470 277.700 277.389 277.282 tmax2m 1586757600 54 275.733 275.977 275.771 275.714 275.598 275.597 275.570 275.722 275.806 275.495 275.768 275.759 275.558 275.584 275.585 275.728 275.726 275.671 275.850 275.963 275.589 tmax2m 1586779200 60 284.794 284.647 284.280 284.620 284.968 284.268 282.300 284.580 284.501 284.347 284.047 285.632 284.358 283.904 284.115 283.859 284.478 285.085 283.255 284.957 283.754 tmax2m 1586800800 66 284.597 284.231 284.013 284.122 284.768 283.889 282.392 284.236 284.315 284.422 284.132 285.502 284.155 283.887 284.172 283.728 284.552 284.983 282.912 284.896 283.722 tmax2m 1586822400 72 277.410 276.778 277.371 277.342 277.301 276.937 276.401 276.839 277.271 276.698 277.224 277.663 277.005 277.027 276.876 276.989 276.436 277.251 276.964 277.397 277.158 tmax2m 1586844000 78 275.176 273.079 275.265 274.138 275.626 273.970 274.995 274.031 274.729 275.256 275.035 275.447 275.207 275.035 275.163 274.555 275.067 274.442 274.823 274.463 274.953 tmax2m 1586865600 84 278.819 277.514 280.218 278.633 280.340 277.777 274.796 277.433 281.718 276.653 277.912 280.184 278.580 278.326 279.702 277.639 280.084 278.651 278.082 279.949 278.174 tmax2m 1586887200 90 279.368 278.310 280.971 280.407 280.696 278.460 274.811 278.025 282.262 277.010 278.416 280.768 279.361 279.456 280.086 278.245 280.859 279.121 278.717 280.834 278.688 tmax2m 1586908800 96 272.627 271.812 274.166 274.832 273.621 271.777 268.727 271.724 276.106 270.960 271.970 274.586 274.005 272.902 273.248 271.486 274.757 272.477 272.527 275.400 272.055 tmax2m 1586930400 102 275.045 273.821 275.223 274.640 275.032 274.573 270.192 273.709 275.205 273.330 273.470 275.506 275.598 274.533 274.668 274.157 274.860 275.441 273.543 275.290 273.494 tmax2m 1586952000 108 286.159 284.111 284.992 283.475 287.001 286.038 282.129 285.561 283.282 285.697 285.655 283.891 287.081 286.230 283.134 285.847 285.591 283.258 285.124 284.025 284.911 tmax2m 1586973600 114 285.024 284.430 283.842 283.380 287.498 286.465 283.363 285.931 282.911 285.943 285.817 283.661 287.141 286.613 282.695 284.985 284.913 282.817 285.344 284.241 285.394 tmax2m 1586995200 120 277.516 275.573 277.262 277.734 277.887 276.753 275.394 275.250 278.260 277.178 276.941 278.545 278.644 276.388 277.407 276.968 277.783 278.079 276.033 278.094 276.849 tmax2m 1587016800 126 276.979 276.972 277.579 275.738 277.916 277.631 274.471 276.625 276.062 276.724 276.493 277.131 278.282 277.725 276.297 275.889 276.493 276.500 276.609 276.468 276.339 tmax2m 1587038400 132 288.258 288.129 288.400 286.783 287.717 287.008 285.896 288.654 286.637 289.711 289.078 288.693 288.064 288.104 287.685 287.092 287.135 287.701 287.410 286.124 287.610 tmax2m 1587060000 138 288.115 287.895 288.154 286.422 287.564 286.506 285.623 288.762 286.599 290.074 289.564 288.001 288.686 288.140 287.702 287.479 287.738 288.271 287.501 285.715 287.627 tmax2m 1587081600 144 278.833 278.001 279.445 278.677 279.927 278.221 275.451 279.276 279.856 278.534 278.047 280.167 280.206 280.639 278.426 278.715 278.696 279.603 279.247 280.314 278.510 tmax2m 1587103200 150 279.037 278.652 279.026 279.256 280.220 279.412 278.247 278.864 279.424 280.273 279.908 279.764 279.161 278.450 278.667 278.602 279.033 280.016 278.749 278.968 278.972 tmax2m 1587124800 156 290.996 287.077 290.078 290.811 288.470 290.685 289.113 288.219 287.421 291.126 290.762 289.900 289.455 291.760 289.042 288.039 287.206 289.175 288.903 288.741 289.616 tmax2m 1587146400 162 291.047 287.100 289.930 291.180 288.669 290.345 289.361 287.879 287.011 291.304 290.765 290.126 290.315 291.555 287.471 288.193 286.767 288.939 287.700 288.789 290.076 tmax2m 1587168000 168 281.797 279.394 281.794 280.813 280.868 280.787 279.168 281.048 281.653 280.939 281.043 282.618 281.936 282.858 281.072 280.193 279.160 282.108 281.459 281.919 281.838 tmax2m 1587189600 174 280.601 278.613 280.820 280.014 280.636 279.893 280.313 279.204 279.598 281.353 280.063 280.325 281.493 280.900 279.637 279.153 279.346 280.463 279.592 279.958 280.810 tmax2m 1587211200 180 290.983 289.448 290.169 288.325 291.705 290.405 289.977 284.811 289.944 290.937 291.307 290.403 290.404 289.709 286.952 284.844 288.425 288.188 288.254 290.059 291.097 tmax2m 1587232800 186 289.936 289.829 290.237 288.450 291.779 290.671 288.255 284.238 289.524 291.041 291.142 290.570 290.495 288.379 285.546 284.360 287.675 286.703 287.759 289.720 290.874 tmax2m 1587254400 192 282.768 279.671 283.399 281.079 281.777 283.107 281.082 278.588 282.403 281.957 282.010 283.635 283.691 282.382 280.837 280.317 279.945 282.046 281.203 282.674 282.639 tmax2m 1587276000 198 282.312 280.204 281.546 278.971 281.720 281.162 280.292 277.193 280.584 281.572 281.000 281.745 281.951 281.110 280.185 279.775 278.799 281.585 280.841 282.125 282.002 tmax2m 1587297600 204 289.657 289.448 291.746 287.464 289.682 289.040 288.487 281.039 289.460 292.672 289.410 291.695 292.818 283.353 286.435 287.689 289.050 288.097 287.262 289.492 292.771 tmax2m 1587319200 210 289.513 289.665 291.280 287.429 289.365 289.284 288.551 281.760 289.333 292.929 289.442 291.470 291.475 284.134 285.829 287.594 288.637 287.959 286.938 289.573 292.000 tmax2m 1587340800 216 281.858 280.432 283.430 281.091 282.059 281.572 280.864 277.121 282.598 282.693 281.747 285.415 284.609 278.447 282.261 281.292 282.438 282.720 282.150 283.160 283.485 tmax2m 1587362400 222 280.159 279.579 282.212 278.048 281.845 277.511 277.788 275.112 280.298 280.818 277.373 282.744 282.640 275.812 279.887 279.894 279.687 281.865 279.879 280.486 282.950 tmax2m 1587384000 228 286.402 287.396 292.377 287.781 288.508 284.067 284.249 282.448 288.421 285.626 284.225 290.853 290.179 282.581 287.092 283.593 287.707 287.732 286.830 291.498 287.731 tmax2m 1587405600 234 286.363 287.391 291.704 288.737 288.565 284.098 283.392 282.025 288.043 284.963 283.458 289.839 289.829 282.521 287.095 283.650 287.144 287.718 286.749 291.868 286.958 tmax2m 1587427200 240 280.246 279.756 282.661 282.129 282.830 278.637 280.201 275.727 283.238 279.205 277.658 284.953 282.573 276.881 282.324 279.225 283.072 282.144 282.504 285.730 283.335 dd10m 1586584800 6 299.846 311.041 316.112 292.726 297.302 285.701 309.436 296.989 302.683 304.860 303.103 289.348 298.754 306.660 305.545 299.263 295.391 289.351 315.158 296.773 282.533 dd10m 1586606400 12 27.436 30.794 32.544 28.917 27.893 30.586 25.065 21.068 30.560 22.672 27.638 23.718 23.411 26.941 29.901 29.285 30.750 26.641 28.586 28.844 26.192 dd10m 1586628000 18 75.469 81.577 78.768 74.002 78.612 76.165 79.354 71.705 70.440 68.618 79.755 73.353 74.984 79.477 83.715 75.573 85.021 69.358 79.220 73.952 69.970 dd10m 1586649600 24 196.819 196.081 195.291 197.918 194.713 196.407 197.125 196.001 197.512 198.086 197.492 196.784 196.879 194.982 195.807 196.484 197.617 196.181 192.296 193.674 198.611 dd10m 1586671200 30 206.906 203.835 203.512 206.175 206.155 203.655 202.342 206.025 206.401 206.267 206.654 204.833 203.568 205.030 206.445 204.459 205.012 202.889 204.866 203.138 206.518 dd10m 1586692800 36 210.413 213.586 209.952 212.530 211.937 213.299 205.566 218.323 218.333 208.344 213.901 212.693 205.560 213.449 208.195 205.970 212.183 211.459 209.199 208.278 213.286 dd10m 1586714400 42 182.377 195.704 181.198 185.912 189.648 179.186 176.510 186.628 181.358 175.629 179.858 195.450 180.707 182.259 180.325 176.473 176.890 181.407 179.583 182.693 190.546 dd10m 1586736000 48 199.452 210.202 197.224 198.452 199.958 205.322 195.549 205.589 200.161 198.195 200.192 202.314 196.360 196.355 195.516 202.262 199.556 203.814 196.557 199.661 198.492 dd10m 1586757600 54 208.318 227.962 205.879 204.853 205.353 222.595 198.803 220.771 208.087 201.873 210.716 210.678 201.521 202.157 198.808 224.913 205.748 215.859 203.935 208.369 200.474 dd10m 1586779200 60 281.961 307.924 264.835 263.308 274.012 316.091 225.324 317.086 260.956 236.976 276.580 303.546 248.004 250.455 237.113 328.137 266.662 315.421 246.908 291.134 246.737 dd10m 1586800800 66 348.252 349.322 340.168 338.546 338.265 349.353 253.092 353.603 341.370 308.592 350.030 351.792 345.263 332.995 350.980 346.819 17.776 348.093 335.082 352.196 336.282 dd10m 1586822400 72 1.932 348.618 2.041 357.308 3.011 356.012 306.833 354.975 11.187 336.609 354.934 17.928 5.324 323.911 12.179 2.896 135.829 353.492 355.093 11.997 3.265 dd10m 1586844000 78 4.742 0.002 14.247 16.246 11.374 2.096 3.584 355.160 23.004 353.385 358.761 15.689 19.313 0.850 20.642 7.360 25.305 351.457 0.233 28.954 5.386 dd10m 1586865600 84 18.031 15.411 24.685 54.291 17.301 17.782 355.702 11.919 52.834 3.909 358.884 28.702 33.802 11.580 34.279 7.615 45.352 18.262 9.913 45.364 6.029 dd10m 1586887200 90 46.816 41.087 58.353 82.715 43.804 48.007 24.445 34.314 75.833 46.565 17.482 61.441 79.859 43.760 58.180 35.560 64.353 54.796 33.457 87.344 28.548 dd10m 1586908800 96 157.214 139.596 163.090 168.179 168.329 171.474 145.858 165.011 164.625 149.312 149.885 158.188 174.665 177.894 138.265 157.894 150.443 162.289 151.104 162.218 143.136 dd10m 1586930400 102 177.507 177.599 181.000 164.713 179.338 198.084 124.879 146.834 170.929 171.892 121.719 185.364 201.834 185.810 138.020 174.979 179.497 186.515 137.996 179.320 167.726 dd10m 1586952000 108 79.184 60.821 64.781 107.763 104.277 67.790 117.717 51.275 119.052 105.266 105.167 86.376 78.300 62.632 111.784 89.972 105.017 86.327 98.522 159.873 133.265 dd10m 1586973600 114 112.021 103.121 83.750 134.801 121.218 110.929 135.088 63.197 118.789 137.318 127.338 128.405 133.553 66.456 127.705 132.173 120.499 123.614 91.657 145.115 139.731 dd10m 1586995200 120 180.832 184.868 201.999 172.399 186.411 188.312 172.019 177.752 174.549 178.937 178.138 178.426 193.463 188.345 177.955 177.785 179.712 182.094 175.480 180.298 181.974 dd10m 1587016800 126 192.506 195.558 272.102 174.872 225.886 205.367 191.779 330.462 179.483 205.168 192.592 199.555 214.200 194.770 195.921 183.656 188.172 187.319 188.924 184.847 194.459 dd10m 1587038400 132 80.788 149.584 52.275 228.622 17.727 19.844 210.756 101.572 164.799 342.556 239.485 104.374 46.461 151.492 115.888 171.237 199.542 221.854 146.277 184.995 231.163 dd10m 1587060000 138 107.219 84.665 106.179 104.837 57.314 75.564 148.753 126.964 349.117 65.958 65.735 64.402 119.979 162.379 111.916 346.448 98.711 114.005 161.381 180.022 141.864 dd10m 1587081600 144 189.021 234.122 190.214 193.325 202.687 208.661 211.788 198.552 210.086 221.020 202.829 190.096 190.177 193.171 188.749 237.510 235.083 224.537 195.746 206.066 196.654 dd10m 1587103200 150 189.020 289.424 194.290 160.620 183.234 161.013 245.720 241.170 168.467 136.030 158.952 172.948 189.593 213.961 204.493 323.049 294.901 182.899 202.916 200.731 189.872 dd10m 1587124800 156 90.174 345.031 173.374 73.112 139.720 56.065 85.863 55.269 132.457 101.150 106.575 132.215 169.838 74.016 62.848 31.765 12.606 116.380 36.322 151.012 146.769 dd10m 1587146400 162 114.670 358.896 62.796 53.704 128.625 93.430 115.666 258.156 142.132 108.348 110.118 144.812 132.744 138.200 104.773 82.570 26.924 153.958 122.950 156.682 132.936 dd10m 1587168000 168 185.272 47.321 200.575 27.749 209.581 177.335 204.253 310.730 197.006 204.463 187.987 191.721 210.067 228.601 192.428 179.080 333.034 198.614 184.932 202.797 197.603 dd10m 1587189600 174 199.935 121.523 209.164 13.477 222.220 175.757 203.430 302.100 209.519 200.844 190.773 190.172 83.520 224.097 217.685 181.982 31.454 194.518 185.680 209.933 200.621 dd10m 1587211200 180 106.801 122.229 139.596 43.896 143.015 117.513 12.695 323.755 61.497 48.856 78.201 176.482 118.791 337.981 131.272 141.667 22.338 141.900 160.257 194.500 103.061 dd10m 1587232800 186 92.463 55.079 147.339 50.108 67.777 129.857 29.733 338.331 111.594 79.031 98.879 164.279 137.124 348.893 164.793 152.377 55.917 153.245 163.027 252.563 128.598 dd10m 1587254400 192 221.695 298.228 200.560 140.061 220.581 183.972 354.650 351.137 184.846 189.524 253.255 204.963 188.012 335.286 193.910 200.024 132.424 201.936 196.509 310.216 190.747 dd10m 1587276000 198 270.290 15.946 212.247 147.811 242.903 242.467 33.001 12.905 186.893 228.899 330.042 215.365 202.763 347.837 186.043 221.297 143.212 226.893 258.896 333.908 210.986 dd10m 1587297600 204 39.275 38.907 273.976 79.756 350.657 47.911 40.763 43.565 28.636 17.520 18.502 57.817 354.933 337.045 164.172 3.315 104.415 30.551 38.235 3.737 333.703 dd10m 1587319200 210 62.512 82.834 130.500 98.779 33.233 52.573 62.097 47.288 71.499 17.759 43.449 129.450 50.924 352.841 173.027 332.848 137.624 344.582 72.211 28.888 59.112 dd10m 1587340800 216 145.022 169.955 220.241 160.631 190.089 133.247 119.216 59.116 185.151 246.132 108.217 175.844 206.518 351.143 181.682 335.855 168.781 249.302 139.177 101.563 213.984 dd10m 1587362400 222 111.121 165.245 221.694 163.040 241.368 91.118 146.445 87.328 170.035 266.630 116.370 184.378 3.981 12.494 174.399 12.158 167.299 332.667 149.412 126.088 265.852 dd10m 1587384000 228 64.879 40.538 183.308 112.538 46.691 57.535 131.399 60.102 148.412 313.237 94.730 125.780 34.694 28.057 169.477 30.742 150.018 8.967 108.114 116.757 1.664 dd10m 1587405600 234 70.012 55.011 39.397 84.478 45.797 37.139 146.883 82.224 153.570 359.312 97.940 130.323 43.571 47.633 172.006 70.055 150.359 11.319 144.016 136.110 3.298 dd10m 1587427200 240 84.677 145.804 200.424 153.847 55.558 34.147 161.457 146.511 177.481 3.226 127.623 157.083 78.564 93.915 180.365 139.276 168.587 342.122 175.066 184.734 358.291 ff10m 1586584800 6 0.686 0.736 0.651 0.733 0.583 0.711 0.712 0.822 0.650 0.716 0.798 0.750 0.690 0.745 0.626 0.665 0.692 0.658 0.648 0.618 0.672 ff10m 1586606400 12 1.666 1.725 1.724 1.569 1.455 1.680 1.668 1.729 1.794 1.486 1.594 1.669 1.794 1.629 1.624 1.642 1.498 1.521 1.794 1.646 1.440 ff10m 1586628000 18 1.257 1.412 1.349 1.203 1.174 1.230 1.232 1.324 1.338 1.199 1.201 1.278 1.253 1.246 1.186 1.238 1.155 1.238 1.338 1.271 1.128 ff10m 1586649600 24 2.138 2.219 2.171 2.116 2.161 2.105 2.166 2.142 2.192 2.139 2.091 2.194 2.085 2.117 2.176 2.073 2.115 2.054 2.164 2.089 2.049 ff10m 1586671200 30 2.151 2.207 2.211 2.064 2.115 2.223 2.181 2.094 2.080 2.113 2.116 2.168 2.142 2.235 2.212 2.172 2.217 2.077 2.193 2.072 2.179 ff10m 1586692800 36 1.867 1.879 2.022 1.793 1.942 1.885 1.972 1.777 1.799 1.798 1.953 1.918 2.010 2.125 2.076 1.845 1.893 1.907 1.975 1.898 1.867 ff10m 1586714400 42 1.711 1.506 1.699 1.588 1.618 1.742 1.816 1.343 1.605 1.772 1.591 1.417 1.758 1.787 1.907 1.780 1.789 1.735 1.736 1.722 1.624 ff10m 1586736000 48 2.855 2.724 2.816 2.892 2.754 2.743 3.139 2.634 2.812 2.955 2.808 2.675 3.054 2.852 3.050 2.651 2.825 2.886 2.894 2.930 2.823 ff10m 1586757600 54 2.310 1.951 2.404 2.389 2.407 2.129 2.712 2.113 2.343 2.595 2.289 2.253 2.516 2.502 2.582 2.195 2.276 2.273 2.451 2.346 2.485 ff10m 1586779200 60 1.145 1.801 1.171 1.394 0.819 1.752 1.399 1.641 1.231 1.382 1.193 1.143 0.978 1.449 1.129 1.960 0.778 1.316 1.338 1.315 1.549 ff10m 1586800800 66 1.772 3.075 1.885 1.995 1.349 2.696 0.741 2.432 1.773 0.787 1.544 1.994 1.382 1.322 0.634 2.608 0.930 1.987 1.433 2.314 1.587 ff10m 1586822400 72 2.532 2.598 2.438 3.304 2.468 2.977 1.271 2.461 2.104 1.824 1.987 1.815 2.956 1.173 1.699 2.505 0.471 2.589 2.429 2.540 2.617 ff10m 1586844000 78 3.004 3.161 2.866 2.134 2.897 2.998 3.641 2.863 2.251 3.811 3.256 2.265 2.797 2.978 2.888 3.085 1.817 2.960 3.138 1.585 2.814 ff10m 1586865600 84 3.135 3.104 2.721 2.490 2.895 2.924 4.067 3.323 1.992 3.914 3.388 2.749 3.210 2.969 3.117 3.311 2.950 3.359 3.224 2.860 3.283 ff10m 1586887200 90 2.185 2.381 1.954 2.145 2.125 2.232 2.598 2.278 1.860 2.333 2.732 1.976 2.159 1.980 2.244 2.462 2.462 2.255 2.568 2.024 2.393 ff10m 1586908800 96 1.784 1.434 1.672 1.886 1.645 2.172 1.250 0.779 1.974 1.756 0.930 1.645 2.056 1.501 1.554 1.801 2.074 1.873 1.297 2.237 1.207 ff10m 1586930400 102 1.640 1.295 1.356 1.430 1.513 1.554 1.610 0.833 1.676 1.690 0.882 1.761 1.689 0.801 1.013 1.808 1.784 1.469 0.902 2.354 1.712 ff10m 1586952000 108 1.070 2.140 0.530 2.073 0.712 0.438 2.346 1.276 1.467 1.411 2.034 1.007 1.206 0.216 1.810 1.137 1.121 1.379 1.458 1.201 1.358 ff10m 1586973600 114 1.596 1.532 1.121 2.131 1.539 1.406 2.244 1.774 1.711 1.911 2.166 1.645 1.815 1.744 1.720 1.582 1.740 1.819 1.366 1.448 1.717 ff10m 1586995200 120 1.972 2.092 1.383 2.861 1.769 1.917 2.933 1.672 2.505 2.312 2.732 1.925 2.050 1.741 2.270 2.243 2.380 2.691 1.721 2.431 2.726 ff10m 1587016800 126 1.604 1.737 0.619 3.093 1.606 1.751 3.103 0.389 2.648 1.932 2.262 1.642 1.623 0.684 1.872 2.190 2.272 2.828 0.876 2.878 2.743 ff10m 1587038400 132 0.738 0.492 1.111 0.888 1.600 1.475 1.052 1.482 1.258 0.409 0.101 0.182 0.520 1.951 0.632 0.943 0.795 0.952 1.732 2.007 1.294 ff10m 1587060000 138 1.312 0.649 1.351 0.789 1.398 1.502 0.696 1.213 0.190 1.239 0.943 0.900 1.621 1.541 1.184 0.379 0.545 0.533 1.312 1.434 1.088 ff10m 1587081600 144 1.992 1.454 2.373 1.489 1.728 1.762 2.025 2.004 0.812 1.469 0.918 1.302 2.215 3.045 2.101 1.127 1.530 1.688 1.829 2.261 2.236 ff10m 1587103200 150 1.694 1.317 2.073 1.349 0.959 1.415 0.692 1.416 0.863 0.865 0.868 1.520 2.170 2.555 1.681 0.789 0.745 0.780 1.642 1.577 1.945 ff10m 1587124800 156 1.114 3.250 0.257 1.200 1.368 1.680 1.397 1.226 1.529 1.879 1.398 2.047 1.459 0.473 0.954 2.079 2.011 1.265 1.419 1.579 1.623 ff10m 1587146400 162 1.328 2.408 1.015 1.712 0.780 1.772 1.145 0.783 1.459 1.617 1.517 2.005 1.076 1.465 0.905 1.722 1.404 1.445 1.571 1.430 1.387 ff10m 1587168000 168 2.318 0.731 2.103 0.735 1.962 2.232 1.918 1.737 2.232 1.142 2.017 2.496 1.977 1.934 2.122 1.936 0.258 2.235 2.183 2.409 2.098 ff10m 1587189600 174 1.721 0.512 1.703 0.908 1.107 1.625 1.092 1.147 1.312 0.416 1.762 2.496 0.399 1.048 1.457 1.776 0.868 1.929 2.298 2.010 1.491 ff10m 1587211200 180 0.297 1.462 1.852 3.377 0.199 2.023 2.106 3.655 1.374 2.367 0.508 1.467 2.149 1.106 0.902 1.040 1.851 0.778 1.121 0.986 1.431 ff10m 1587232800 186 0.799 0.641 1.335 2.315 0.935 1.930 1.999 3.021 1.579 1.867 0.683 1.725 1.937 1.774 1.439 1.027 1.889 1.447 1.162 0.920 1.595 ff10m 1587254400 192 1.458 0.322 2.528 1.559 1.678 1.795 0.366 2.958 1.940 2.022 0.906 2.654 2.549 2.661 1.887 1.859 1.389 2.670 2.023 1.155 2.653 ff10m 1587276000 198 0.309 0.424 2.088 1.016 0.510 0.824 1.261 3.285 1.469 1.110 0.925 1.627 1.503 2.735 2.020 1.310 1.559 1.413 0.686 0.721 1.755 ff10m 1587297600 204 2.611 2.597 0.736 2.529 1.678 2.670 2.675 3.264 1.293 1.005 3.029 1.710 1.792 3.324 2.261 1.524 1.764 0.721 2.152 2.542 0.888 ff10m 1587319200 210 1.554 1.722 0.986 1.905 1.275 1.815 2.169 2.669 1.363 1.043 2.304 1.653 1.436 3.597 2.544 0.959 2.078 1.044 1.286 2.014 0.676 ff10m 1587340800 216 1.335 1.861 1.726 2.529 0.687 1.165 1.660 1.768 1.916 1.431 1.432 2.802 0.933 1.934 3.167 1.921 2.942 0.639 1.223 0.788 1.293 ff10m 1587362400 222 1.385 1.119 0.842 2.047 0.610 1.544 2.089 1.705 2.064 1.584 2.046 2.267 0.503 1.973 3.102 2.301 2.614 1.175 1.584 1.335 0.918 ff10m 1587384000 228 3.118 2.649 0.244 2.300 1.452 3.438 2.747 3.759 2.490 2.847 3.302 1.762 2.711 2.087 3.868 2.574 2.756 2.714 2.502 2.196 1.758 ff10m 1587405600 234 2.811 2.125 0.439 2.156 1.454 2.658 2.906 2.555 2.273 4.051 3.010 1.847 2.062 1.796 3.033 2.043 2.267 1.788 2.191 1.733 2.454 ff10m 1587427200 240 1.883 1.751 1.322 1.656 0.321 2.609 3.850 3.155 2.798 3.167 3.272 2.106 0.689 1.279 2.993 2.177 2.768 1.581 3.063 2.098 1.988 apcpsfc 1586584800 6 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1586606400 12 0.079 0.120 0.068 0.067 0.107 0.077 0.074 0.062 0.040 0.079 0.100 0.100 0.113 0.135 0.089 0.069 0.074 0.033 0.048 0.074 0.048 apcpsfc 1586628000 18 0.558 0.552 0.422 0.598 0.734 0.439 0.609 0.466 0.291 0.639 0.512 0.629 0.595 0.471 0.588 0.545 0.567 0.371 0.433 0.446 0.545 apcpsfc 1586649600 24 0.266 0.209 0.222 0.275 0.467 0.194 0.277 0.126 0.122 0.243 0.296 0.195 0.242 0.344 0.307 0.301 0.323 0.231 0.222 0.290 0.275 apcpsfc 1586671200 30 0.498 0.418 0.402 0.375 0.824 0.659 0.401 0.535 0.367 0.332 0.479 0.327 0.328 0.376 0.443 0.575 0.290 0.397 0.445 0.492 0.349 apcpsfc 1586692800 36 0.423 0.365 0.369 0.492 0.676 0.585 0.367 0.650 0.595 0.466 0.592 0.540 0.357 0.317 0.289 0.399 0.226 0.614 0.375 0.585 0.630 apcpsfc 1586714400 42 1.115 1.128 1.038 0.888 1.761 1.468 0.895 1.150 1.247 1.021 1.089 1.302 0.853 1.184 0.817 0.810 0.725 0.976 0.971 0.776 1.430 apcpsfc 1586736000 48 0.632 0.836 0.839 0.555 0.555 0.584 0.405 0.744 0.406 0.448 0.550 0.756 0.387 0.611 0.636 0.898 0.477 0.946 0.677 0.484 0.515 apcpsfc 1586757600 54 0.593 0.643 0.435 0.263 0.539 0.949 0.070 0.444 0.063 0.103 0.778 0.642 0.167 0.107 0.025 0.950 0.441 0.428 0.389 0.163 0.053 apcpsfc 1586779200 60 0.385 0.899 0.284 0.279 0.301 0.750 0.168 0.799 0.392 0.061 0.556 0.297 0.121 0.266 0.078 0.834 0.185 0.534 0.365 0.276 0.259 apcpsfc 1586800800 66 1.589 4.666 1.762 1.473 1.092 4.097 0.662 4.416 1.789 0.542 1.750 1.864 0.827 1.486 0.491 4.048 0.853 2.318 1.979 2.791 1.518 apcpsfc 1586822400 72 2.891 2.261 2.292 4.676 1.972 2.693 1.472 2.518 1.255 1.611 2.346 3.614 3.088 0.650 1.623 2.533 0.544 2.670 4.259 4.496 4.151 apcpsfc 1586844000 78 0.519 0.244 0.471 0.545 0.593 0.619 5.619 0.397 0.148 2.002 0.681 0.401 1.073 0.393 0.970 0.707 0.025 0.371 0.646 0.371 0.932 apcpsfc 1586865600 84 0.170 0.000 0.122 0.000 0.074 0.122 0.994 0.100 0.074 0.249 0.275 0.074 0.048 0.387 0.122 0.244 0.472 0.064 0.196 0.015 0.148 apcpsfc 1586887200 90 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.096 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.148 0.000 0.000 0.000 0.000 apcpsfc 1586908800 96 0.000 0.000 0.000 0.122 0.000 0.000 0.000 0.000 0.445 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.170 0.000 apcpsfc 1586930400 102 0.048 0.000 0.254 0.153 0.000 0.000 0.000 0.000 0.175 0.000 0.000 0.129 0.026 0.079 0.096 0.000 0.000 0.100 0.000 0.244 0.000 apcpsfc 1586952000 108 0.000 0.000 0.127 0.100 0.000 0.000 0.000 0.000 0.120 0.000 0.000 0.100 0.000 0.000 0.155 0.000 0.048 0.201 0.000 0.098 0.000 apcpsfc 1586973600 114 0.170 0.000 0.440 0.196 0.000 0.048 0.000 0.000 0.418 0.000 0.000 0.147 0.000 0.003 0.208 0.171 0.074 0.166 0.000 0.256 0.010 apcpsfc 1586995200 120 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.003 0.000 0.000 0.010 0.000 0.005 0.000 0.000 0.000 0.000 apcpsfc 1587016800 126 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.011 0.000 0.000 0.000 apcpsfc 1587038400 132 0.000 0.010 0.000 0.096 0.026 0.053 0.000 0.000 0.096 0.000 0.000 0.000 0.026 0.010 0.000 0.000 0.000 0.000 0.000 0.334 0.000 apcpsfc 1587060000 138 0.053 0.234 0.509 1.214 0.772 0.571 0.000 0.000 1.761 0.000 0.096 1.071 0.311 0.093 0.048 1.003 0.334 0.361 0.000 2.524 0.170 apcpsfc 1587081600 144 0.000 0.057 0.000 0.000 0.000 0.000 0.000 0.000 0.372 0.000 0.000 0.074 0.000 0.000 0.000 0.660 0.143 0.020 0.000 0.122 0.000 apcpsfc 1587103200 150 0.000 0.000 0.000 0.000 0.153 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1587124800 156 0.000 0.108 0.000 0.000 0.582 0.000 0.000 0.191 0.318 0.000 0.000 0.000 0.000 0.000 0.074 0.000 0.339 0.024 0.053 0.175 0.000 apcpsfc 1587146400 162 0.409 1.570 2.131 0.010 3.069 0.081 0.048 3.677 1.847 0.000 0.000 0.514 0.096 0.014 2.015 0.143 2.217 2.801 0.179 1.495 0.100 apcpsfc 1587168000 168 0.143 0.201 0.810 0.000 0.048 0.000 0.000 5.124 0.196 0.000 0.000 0.000 0.000 0.033 2.039 0.096 0.493 3.168 0.000 0.048 0.000 apcpsfc 1587189600 174 0.048 0.000 0.000 0.000 0.000 0.000 0.000 0.298 0.061 0.000 0.000 0.000 0.010 0.163 0.410 0.657 0.027 0.430 0.000 0.000 0.000 apcpsfc 1587211200 180 0.163 0.000 0.195 0.000 0.015 0.000 0.843 0.681 0.781 0.000 0.000 0.000 0.063 1.131 2.223 3.311 0.252 1.436 0.048 0.119 0.179 apcpsfc 1587232800 186 3.473 1.761 0.849 0.053 1.413 0.074 2.104 1.986 3.818 0.000 3.078 0.000 1.608 10.591 15.111 9.931 2.564 10.332 2.925 1.926 0.492 apcpsfc 1587254400 192 1.010 0.509 0.000 0.000 0.106 0.010 0.096 3.398 0.406 0.000 0.897 0.057 0.012 16.592 8.437 1.690 0.822 4.041 2.447 1.229 0.000 apcpsfc 1587276000 198 0.041 0.003 0.000 0.047 0.000 0.026 0.000 0.636 0.000 0.000 0.000 0.000 0.000 6.755 3.009 0.000 0.007 2.350 0.909 0.041 0.026 apcpsfc 1587297600 204 0.370 0.000 0.434 0.238 0.966 0.183 0.025 0.385 1.043 0.000 0.017 0.252 0.420 0.758 1.968 1.487 0.412 3.324 2.213 0.735 0.158 apcpsfc 1587319200 210 1.528 0.121 2.619 1.884 1.316 0.632 1.301 0.271 1.756 0.338 0.122 2.205 3.058 0.805 3.627 6.617 2.064 7.808 4.876 0.945 1.571 apcpsfc 1587340800 216 0.166 0.081 0.337 0.445 0.061 0.119 0.669 0.173 0.868 0.273 0.026 0.122 0.318 0.950 0.150 9.734 0.199 2.406 1.110 0.055 0.331 apcpsfc 1587362400 222 0.071 0.039 0.000 0.016 0.000 0.292 0.812 0.034 0.008 0.568 0.010 0.024 0.000 0.198 0.086 1.284 0.007 0.062 0.100 0.000 0.024 apcpsfc 1587384000 228 0.627 0.054 0.669 0.020 0.897 0.298 4.810 0.345 0.557 3.958 0.538 0.510 0.884 0.264 0.228 1.192 0.404 1.531 3.184 0.000 3.602 apcpsfc 1587405600 234 0.923 0.186 3.830 0.061 4.898 0.358 12.349 1.573 1.384 6.564 1.722 1.685 3.548 1.131 0.447 3.266 0.730 3.558 4.814 0.282 13.702 apcpsfc 1587427200 240 0.145 0.361 1.027 0.282 3.881 0.179 3.898 3.225 0.191 0.984 2.517 0.954 0.598 0.032 0.502 1.285 0.041 0.431 0.158 0.012 6.466 tmp2m 1586584800 6 275.542 275.703 275.528 275.561 275.696 275.578 275.598 275.359 275.260 275.534 275.607 275.565 275.577 275.620 275.554 275.577 275.452 275.409 275.500 275.594 275.653 tmp2m 1586606400 12 282.874 282.282 282.820 283.064 282.939 282.878 282.787 282.757 282.696 283.236 282.564 282.679 282.431 282.292 282.810 282.749 282.882 283.020 282.770 282.878 283.099 tmp2m 1586628000 18 277.768 277.792 277.758 277.880 277.865 277.749 277.786 277.650 277.513 277.851 277.778 277.789 277.702 277.737 277.761 277.810 277.759 277.668 277.733 277.840 277.943 tmp2m 1586649600 24 275.946 275.719 276.047 275.922 276.203 275.784 275.806 275.680 275.210 275.824 275.980 275.756 275.841 276.084 275.900 275.957 276.150 275.747 275.966 275.873 276.295 tmp2m 1586671200 30 276.787 276.832 276.956 276.825 276.824 276.868 276.925 276.764 276.903 276.790 276.873 276.760 276.746 276.729 276.838 276.735 276.887 276.912 276.899 276.947 276.899 tmp2m 1586692800 36 284.079 284.067 284.203 284.084 283.767 283.797 284.312 283.610 283.667 283.954 283.857 283.877 284.272 283.950 284.135 284.095 284.311 283.636 284.246 283.846 283.884 tmp2m 1586714400 42 277.394 276.787 277.480 277.076 277.275 277.630 277.664 276.804 277.388 277.458 277.611 277.066 277.267 277.411 277.545 277.521 277.597 277.502 277.601 277.556 277.272 tmp2m 1586736000 48 274.677 274.349 274.924 274.788 274.690 274.646 274.411 274.648 274.906 274.353 274.812 274.585 274.515 274.908 274.691 274.838 274.675 274.414 274.746 274.803 274.786 tmp2m 1586757600 54 275.472 275.722 275.415 275.539 275.319 275.233 275.324 275.396 275.570 275.140 275.524 275.437 275.286 275.310 275.372 275.422 275.369 275.375 275.563 275.735 275.345 tmp2m 1586779200 60 284.737 284.460 284.280 284.563 284.920 284.098 282.205 284.410 284.501 284.347 284.047 285.632 284.262 283.809 284.115 283.811 284.461 284.976 283.159 284.862 283.754 tmp2m 1586800800 66 277.592 276.920 277.497 277.260 277.417 276.989 276.873 276.955 277.497 276.407 277.431 277.788 277.004 277.140 276.690 277.107 276.883 277.328 277.164 277.471 277.384 tmp2m 1586822400 72 275.202 273.121 275.213 274.264 275.535 274.062 274.920 274.157 274.773 275.273 275.071 275.555 275.168 274.107 275.067 274.629 273.746 274.584 274.863 274.542 275.069 tmp2m 1586844000 78 273.322 270.537 273.436 271.360 273.759 271.777 272.858 272.328 273.562 273.454 273.708 274.089 272.188 274.432 273.950 272.280 274.964 272.605 273.071 272.280 272.779 tmp2m 1586865600 84 278.819 277.514 280.218 278.633 280.356 277.777 274.796 277.433 281.691 276.653 277.912 280.137 278.580 278.326 279.702 277.639 279.988 278.651 278.082 279.902 278.157 tmp2m 1586887200 90 272.941 272.112 274.082 273.044 273.886 271.986 269.149 272.019 275.798 271.213 272.339 274.656 272.819 273.210 273.617 271.816 275.088 272.698 272.783 274.002 272.365 tmp2m 1586908800 96 270.897 268.990 272.856 273.606 272.141 270.103 263.988 269.011 274.658 269.186 268.282 272.893 272.691 271.267 271.283 268.523 271.700 271.097 268.981 274.140 268.614 tmp2m 1586930400 102 275.045 273.795 275.223 274.640 275.032 274.573 270.139 273.630 275.205 273.330 273.417 275.506 275.598 274.533 274.668 274.157 274.860 275.441 273.543 275.290 273.494 tmp2m 1586952000 108 285.633 284.111 284.674 283.227 287.001 286.011 281.976 285.561 283.112 285.697 285.628 283.243 287.034 286.060 282.515 285.773 284.950 282.658 285.088 284.025 284.884 tmp2m 1586973600 114 277.318 275.207 277.671 277.977 278.067 276.449 275.453 275.712 278.651 277.267 276.892 278.460 278.877 276.486 277.400 277.289 277.331 278.204 276.475 278.473 276.943 tmp2m 1586995200 120 274.618 273.853 274.528 274.536 275.150 274.606 272.224 273.213 274.934 273.841 274.216 275.206 275.258 274.274 274.248 273.864 275.034 275.439 273.653 274.348 273.977 tmp2m 1587016800 126 277.027 276.972 277.552 275.747 277.898 277.614 274.471 276.625 276.062 276.724 276.493 277.105 278.273 277.699 276.297 275.889 276.493 276.325 276.609 276.495 276.339 tmp2m 1587038400 132 288.157 288.033 288.374 286.639 287.717 286.654 285.896 288.575 286.589 289.711 288.982 288.640 287.932 288.104 287.646 287.044 287.061 287.701 287.362 285.932 287.658 tmp2m 1587060000 138 279.455 278.755 279.681 279.097 280.294 278.847 275.784 279.286 280.011 279.216 278.878 280.635 280.511 280.685 278.953 278.664 279.597 280.227 279.482 280.336 279.091 tmp2m 1587081600 144 276.338 276.139 277.038 275.380 277.204 275.689 274.053 276.518 275.023 276.118 275.475 276.169 276.761 276.589 276.195 276.545 275.974 276.454 276.315 276.553 276.434 tmp2m 1587103200 150 279.037 278.652 279.026 279.256 280.220 279.386 278.247 278.864 279.367 280.225 279.882 279.764 279.161 278.450 278.667 278.602 279.033 279.942 278.749 278.968 278.972 tmp2m 1587124800 156 290.996 287.051 290.078 290.811 288.231 290.320 289.113 288.028 287.104 291.126 290.709 289.900 289.455 291.591 288.253 288.039 286.989 289.122 288.307 288.646 289.616 tmp2m 1587146400 162 282.276 279.936 282.001 281.491 281.394 281.009 279.799 281.126 281.699 281.559 281.323 282.708 282.510 282.904 281.139 280.531 280.037 282.117 281.701 282.227 282.176 tmp2m 1587168000 168 279.043 275.651 279.554 276.369 278.125 278.251 276.486 279.108 278.565 277.171 277.515 278.570 279.143 278.885 278.867 277.565 274.708 279.390 277.333 278.402 278.016 tmp2m 1587189600 174 280.566 278.577 280.820 280.014 280.636 279.893 280.287 278.190 279.553 281.327 280.063 280.325 281.493 280.900 279.637 279.118 279.310 280.463 279.592 279.958 280.793 tmp2m 1587211200 180 290.643 289.369 290.143 288.277 291.577 290.452 288.098 284.479 289.531 290.889 291.202 290.403 290.378 288.934 285.778 284.268 287.980 287.129 288.245 289.738 291.071 tmp2m 1587232800 186 282.962 280.351 283.582 281.435 282.413 283.275 281.409 278.720 282.633 282.338 282.429 283.824 283.890 282.482 280.825 280.454 280.030 282.268 281.283 282.843 283.013 tmp2m 1587254400 192 279.517 275.554 280.213 275.981 278.282 278.419 275.901 276.036 278.284 278.512 277.726 279.659 279.850 280.488 278.878 277.469 275.297 280.139 278.722 278.812 279.811 tmp2m 1587276000 198 282.217 280.177 281.546 278.955 281.598 281.153 280.218 275.922 280.584 281.572 280.991 281.695 281.951 279.990 279.975 279.766 278.799 281.532 280.841 282.125 282.002 tmp2m 1587297600 204 289.535 289.400 291.576 287.416 289.268 289.040 288.452 281.039 289.216 292.608 289.410 291.478 291.595 283.353 285.820 287.615 288.902 287.519 287.080 289.459 292.331 tmp2m 1587319200 210 282.585 281.027 283.899 281.297 282.942 282.001 281.222 277.625 282.924 283.479 282.359 285.593 284.926 278.794 282.448 281.503 282.649 282.980 282.418 283.633 284.115 tmp2m 1587340800 216 277.850 277.800 279.987 277.650 277.832 276.133 275.939 274.827 278.807 278.853 275.371 282.260 279.112 274.417 279.414 278.994 278.882 278.259 278.016 278.283 280.421 tmp2m 1587362400 222 280.159 279.579 282.212 277.826 281.845 277.485 277.755 274.956 280.298 280.679 277.356 282.505 282.592 275.594 279.751 279.198 279.630 281.806 279.863 280.381 282.859 tmp2m 1587384000 228 286.328 287.300 291.772 287.733 288.387 283.972 283.613 282.109 288.050 285.230 283.786 290.265 289.813 282.520 286.822 283.550 287.162 287.508 286.713 291.450 287.047 tmp2m 1587405600 234 280.720 280.289 283.732 282.527 283.016 278.967 280.469 276.026 283.450 279.323 277.974 285.203 283.186 277.168 282.594 279.486 283.298 282.556 282.580 285.881 283.487 tmp2m 1587427200 240 275.321 275.472 278.997 277.624 278.567 274.362 278.326 274.445 279.038 275.127 274.539 280.856 276.097 273.403 279.454 276.761 278.386 280.017 277.669 281.435 281.480 tcdcclm 1586584800 6 0.239 0.239 0.261 0.156 0.437 0.152 0.220 0.419 0.170 0.114 1.006 0.622 0.506 0.500 0.647 0.477 0.448 0.312 0.114 0.717 0.356 tcdcclm 1586606400 12 1.538 3.134 1.511 1.405 2.304 1.355 2.184 1.363 1.227 1.364 3.122 1.792 2.557 3.128 1.883 1.847 1.823 1.572 1.494 2.123 1.564 tcdcclm 1586628000 18 4.755 4.506 4.379 4.632 5.594 4.491 4.130 4.643 4.605 4.242 5.495 5.156 4.491 4.190 4.612 4.242 4.293 4.588 4.573 5.009 4.503 tcdcclm 1586649600 24 4.217 3.653 4.515 4.341 5.358 3.865 4.205 3.926 3.358 4.406 4.841 4.262 4.586 4.910 4.373 4.763 4.968 5.052 4.651 5.184 4.773 tcdcclm 1586671200 30 5.514 5.425 5.462 5.012 5.569 5.437 5.504 5.425 5.290 5.196 5.391 5.381 5.064 5.161 5.360 5.620 5.110 5.670 5.548 5.447 5.289 tcdcclm 1586692800 36 2.636 2.049 1.730 3.067 3.819 3.374 1.632 3.768 3.773 2.672 2.898 3.121 1.798 1.561 1.223 2.339 0.855 3.955 1.747 3.899 2.889 tcdcclm 1586714400 42 2.476 1.266 2.032 2.704 4.377 2.419 1.584 2.525 3.685 1.648 3.919 3.342 1.229 3.354 1.780 2.360 1.867 3.147 3.014 3.977 4.290 tcdcclm 1586736000 48 5.526 4.593 6.106 6.172 6.215 5.049 3.145 5.567 5.598 4.168 5.706 5.577 4.476 6.591 4.971 6.301 5.792 5.811 5.845 5.453 6.025 tcdcclm 1586757600 54 6.699 6.319 6.090 6.911 6.177 5.883 4.733 6.105 6.818 4.982 6.830 6.449 5.748 5.944 6.321 6.922 5.748 6.502 6.557 6.547 6.713 tcdcclm 1586779200 60 5.649 3.897 4.222 4.668 3.557 4.328 7.410 3.160 5.073 4.455 6.629 4.417 4.816 4.233 5.004 4.027 4.970 2.716 6.893 5.746 5.711 tcdcclm 1586800800 66 6.015 5.669 5.987 6.112 6.609 6.176 7.418 5.292 5.427 5.716 5.974 4.828 6.357 5.330 6.140 4.966 5.101 3.954 6.987 6.586 5.915 tcdcclm 1586822400 72 6.957 6.289 6.490 7.130 7.195 6.756 7.927 6.862 5.853 7.475 6.594 6.944 7.024 3.826 7.241 7.052 6.938 6.368 7.352 6.999 6.768 tcdcclm 1586844000 78 6.162 5.497 6.826 6.380 6.385 5.803 7.815 5.963 5.011 7.737 6.650 7.347 6.823 5.010 7.345 7.303 6.364 5.823 6.377 5.405 7.257 tcdcclm 1586865600 84 3.047 2.476 3.144 1.575 3.036 3.036 5.246 3.513 3.521 4.313 5.178 2.978 2.642 6.241 3.364 3.458 6.529 3.493 3.971 1.910 2.757 tcdcclm 1586887200 90 0.119 0.220 0.334 0.334 0.494 0.059 1.135 0.237 1.864 0.292 0.534 0.762 0.160 1.711 0.290 0.080 3.243 0.178 0.139 1.523 0.157 tcdcclm 1586908800 96 0.216 0.178 0.743 2.927 0.300 0.199 1.835 0.321 5.293 0.223 2.372 1.540 0.541 0.560 0.881 0.373 0.380 0.185 0.199 3.111 0.160 tcdcclm 1586930400 102 2.377 1.608 4.995 4.654 3.013 2.952 0.160 0.581 4.777 1.095 0.518 4.907 5.004 3.186 3.315 2.981 0.547 3.204 0.515 5.222 0.233 tcdcclm 1586952000 108 3.011 2.888 3.094 3.512 1.484 2.351 0.038 2.918 2.695 0.543 1.616 3.666 1.834 1.917 4.317 1.554 2.756 4.920 0.794 1.345 0.084 tcdcclm 1586973600 114 5.011 3.124 6.038 5.124 3.882 3.399 0.021 1.745 5.242 0.868 0.735 5.260 3.097 2.540 4.892 5.064 5.119 5.236 3.271 3.582 1.629 tcdcclm 1586995200 120 3.055 1.088 3.186 1.852 1.426 1.200 0.118 0.124 1.886 0.142 0.696 1.855 0.342 1.972 2.341 0.763 2.607 4.418 1.950 0.822 0.196 tcdcclm 1587016800 126 1.146 3.365 1.463 4.725 1.295 0.917 0.160 0.153 1.125 0.067 1.719 3.601 3.221 2.858 1.422 0.439 2.541 2.790 2.839 0.059 2.312 tcdcclm 1587038400 132 4.241 1.589 4.536 5.037 5.385 5.061 4.641 0.116 0.797 3.490 4.881 5.881 6.782 1.881 4.322 5.325 4.144 3.792 5.280 2.518 5.077 tcdcclm 1587060000 138 4.907 5.094 4.029 4.770 5.660 4.389 6.672 2.833 3.887 3.224 5.578 6.227 2.332 1.861 5.967 5.779 3.957 5.588 7.511 5.311 7.098 tcdcclm 1587081600 144 1.733 6.348 1.583 1.512 6.398 1.780 1.816 5.743 3.207 3.026 1.084 1.657 1.447 2.240 5.201 4.918 2.070 2.918 7.438 3.614 7.270 tcdcclm 1587103200 150 2.757 1.470 5.294 3.718 6.722 4.247 0.059 4.369 1.923 1.205 3.714 0.217 3.883 1.166 6.598 3.130 0.921 3.559 5.100 4.922 6.587 tcdcclm 1587124800 156 3.526 1.495 4.794 5.158 4.872 5.956 0.153 5.512 5.666 0.093 5.490 2.370 5.897 3.945 5.857 3.190 4.372 6.367 3.348 6.099 5.382 tcdcclm 1587146400 162 5.048 2.327 6.520 3.477 3.836 4.630 2.420 6.751 6.718 1.053 6.179 3.441 3.369 5.081 6.349 6.627 5.818 6.767 5.910 6.142 1.613 tcdcclm 1587168000 168 5.862 4.506 6.946 3.849 4.594 5.919 0.799 7.427 6.606 3.778 5.124 4.218 5.336 5.934 5.913 5.635 2.429 6.791 4.280 3.518 3.116 tcdcclm 1587189600 174 6.839 4.789 5.190 5.926 6.450 6.178 2.699 5.293 5.624 5.943 3.207 4.740 7.063 4.666 5.749 4.859 4.454 5.573 6.174 4.612 3.774 tcdcclm 1587211200 180 5.982 3.705 5.594 2.118 4.976 3.392 4.875 4.274 3.475 3.483 5.559 6.920 7.126 4.896 5.621 6.516 3.663 6.402 7.396 6.451 3.911 tcdcclm 1587232800 186 6.405 2.465 6.532 3.936 4.845 2.883 4.396 6.200 5.532 2.744 7.052 6.539 6.385 6.685 7.282 7.365 3.520 7.334 7.676 7.638 5.278 tcdcclm 1587254400 192 6.757 0.527 6.736 2.729 3.697 3.284 0.422 7.752 4.389 4.341 6.054 5.552 5.850 7.915 7.668 6.942 0.457 7.083 7.098 7.135 5.449 tcdcclm 1587276000 198 4.257 3.362 6.765 2.169 5.049 2.328 0.067 6.676 3.438 5.734 4.551 6.731 4.772 7.699 6.969 5.539 0.191 6.646 5.115 5.953 6.610 tcdcclm 1587297600 204 2.807 3.228 5.903 0.823 2.352 3.249 0.108 5.807 2.221 5.887 0.600 4.955 2.012 5.755 6.186 5.593 0.839 5.431 5.616 5.244 4.784 tcdcclm 1587319200 210 2.778 0.178 5.045 1.988 3.509 1.186 1.005 3.644 4.192 1.569 0.636 5.119 2.716 1.619 5.909 6.282 2.805 5.943 6.077 3.313 5.467 tcdcclm 1587340800 216 0.896 0.596 1.320 2.965 2.094 1.521 0.457 3.700 3.020 4.606 0.282 6.738 0.872 4.665 5.521 7.220 1.448 6.847 4.193 1.804 4.927 tcdcclm 1587362400 222 1.275 2.026 2.208 1.934 4.652 1.155 2.153 2.129 4.691 2.589 0.562 5.422 0.168 5.730 5.438 6.295 3.473 3.232 1.312 1.172 6.350 tcdcclm 1587384000 228 1.687 1.753 1.206 1.355 5.671 1.841 3.603 2.893 2.856 5.368 1.836 4.887 0.151 5.632 6.320 5.074 3.908 3.333 1.680 0.218 6.882 tcdcclm 1587405600 234 0.944 1.202 3.018 3.777 6.027 1.748 6.585 5.449 3.897 6.522 2.331 6.325 0.502 3.601 7.125 4.573 4.471 3.652 5.000 1.763 7.278 tcdcclm 1587427200 240 1.204 2.207 1.228 2.296 6.342 3.564 5.975 7.040 3.382 6.561 4.058 6.242 0.433 3.655 6.819 5.406 2.771 4.528 1.293 1.963 7.654 partykit/inst/ULGcourse-2020/Data/Axams_pred.rda0000644000176200001440000000035014172227777020771 0ustar liggesusers r0b```f`fbV 54Mׂ ad`a)(HI` |@ Kz%ۿ7vJz svclSq_o9 6O)V%: 0pnС: PĚZ dd-Ig&8)hp i?6%$l r$$y@/FPpartykit/inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200416.dat0000644000176200001440000016114414172227777023010 0ustar liggesusers# ASCII output from GENSvis.py # Contains interpolated values from the # GFS ensemble on 1.000000 x 1.000000 degrees # The data in here are for station # 11120: INNSBRUCK # Station position: 11.3553 47.2589 # Used grid point 1: 12.0000 48.0000 # Used grid point 2: 12.0000 47.0000 # Used grid point 3: 11.0000 47.0000 # Used grid point 4: 11.0000 48.0000 varname timestamp step mem0 mem1 mem2 mem3 mem4 mem5 mem6 mem7 mem8 mem9 mem10 mem11 mem12 mem13 mem14 mem15 mem16 mem17 mem18 mem19 mem20 tmax2m 1587016800 6 274.664 274.738 274.526 274.712 274.552 274.621 274.490 274.490 274.859 274.543 274.647 274.750 274.664 274.773 274.664 274.681 274.681 274.581 274.690 274.590 274.590 tmax2m 1587038400 12 283.811 283.413 283.548 283.500 283.557 283.546 283.492 283.592 283.929 283.748 283.564 283.581 283.711 283.662 283.334 283.454 283.671 283.767 283.527 284.028 283.689 tmax2m 1587060000 18 283.907 283.801 284.050 283.568 284.002 283.929 283.719 284.024 284.007 283.833 283.971 283.649 283.754 283.928 283.969 284.088 283.651 283.811 283.792 283.863 283.664 tmax2m 1587081600 24 272.914 273.703 273.071 272.628 273.828 272.528 273.642 272.867 272.611 272.791 272.902 273.240 272.640 273.100 272.505 272.825 273.111 273.323 272.952 273.952 272.435 tmax2m 1587103200 30 276.829 276.881 276.700 276.813 276.907 276.903 276.677 276.813 276.887 276.856 276.856 276.720 276.839 276.855 276.839 276.970 276.878 276.896 276.777 276.664 276.794 tmax2m 1587124800 36 286.091 286.672 285.659 286.115 285.905 286.666 286.140 286.730 286.592 285.826 286.072 285.753 286.110 286.720 286.254 286.234 285.490 285.931 286.327 285.869 286.142 tmax2m 1587146400 42 286.960 286.607 286.562 287.070 286.344 287.471 286.106 287.282 287.418 286.972 287.179 286.545 286.953 287.315 287.496 286.582 286.310 286.843 287.337 287.084 287.324 tmax2m 1587168000 48 277.760 277.455 276.515 277.678 277.043 277.610 276.495 277.224 276.663 277.928 277.607 276.845 277.157 277.810 277.467 277.382 276.899 277.237 277.928 276.294 277.481 tmax2m 1587189600 54 278.333 278.187 278.250 278.176 278.401 278.264 278.184 278.321 278.435 278.099 278.323 277.855 278.229 278.157 278.341 278.080 278.068 278.285 278.282 278.395 278.271 tmax2m 1587211200 60 287.358 286.765 287.047 287.438 288.086 287.993 287.139 287.797 286.944 287.862 287.862 287.155 286.440 287.081 288.056 287.218 287.902 287.167 286.642 286.037 286.330 tmax2m 1587232800 66 287.045 286.944 286.858 287.129 287.649 287.531 287.037 287.393 286.492 287.545 287.740 286.982 286.727 286.730 287.492 286.987 287.805 287.212 286.483 286.143 286.922 tmax2m 1587254400 72 277.746 277.256 277.440 277.806 278.834 278.809 277.359 277.944 277.723 278.680 278.852 278.068 277.221 277.463 278.332 276.817 279.073 277.319 278.066 278.211 276.962 tmax2m 1587276000 78 278.733 278.709 278.433 278.637 279.276 278.750 278.475 278.450 278.315 278.875 279.047 278.684 277.858 278.503 278.821 278.386 279.128 279.098 279.058 277.733 278.555 tmax2m 1587297600 84 286.063 285.430 285.382 285.503 286.740 284.829 286.599 285.433 284.595 285.109 286.194 286.343 285.520 285.629 286.056 285.501 285.838 286.785 285.808 285.112 285.410 tmax2m 1587319200 90 286.249 285.395 285.344 285.560 286.546 284.479 286.605 285.463 284.701 285.345 286.547 286.343 285.791 286.033 285.941 285.443 285.731 286.880 285.745 285.597 285.602 tmax2m 1587340800 96 279.894 279.458 279.485 279.820 280.452 280.063 279.279 279.999 279.317 280.113 279.904 279.662 279.062 279.450 279.860 279.515 279.786 279.778 280.384 277.677 279.498 tmax2m 1587362400 102 278.230 276.944 277.828 278.355 278.900 277.866 278.494 278.484 277.427 277.668 279.273 278.409 277.734 278.334 278.243 277.529 277.980 278.664 278.572 276.851 277.578 tmax2m 1587384000 108 283.891 281.789 284.158 283.096 285.864 280.571 284.936 284.329 285.606 280.348 285.889 284.531 284.156 283.560 283.719 279.789 284.213 285.735 282.287 284.437 284.223 tmax2m 1587405600 114 283.342 282.503 283.646 283.018 285.345 279.938 285.177 284.163 285.280 279.976 285.458 284.322 283.736 283.188 283.470 279.539 284.108 286.319 282.086 284.523 284.418 tmax2m 1587427200 120 278.621 277.056 279.137 278.565 280.370 277.162 279.376 279.523 277.022 275.616 280.403 275.910 278.238 278.351 279.685 276.402 279.149 279.297 278.694 275.741 276.603 tmax2m 1587448800 126 275.880 274.859 276.044 275.052 278.812 274.530 276.987 276.868 275.551 273.145 277.790 273.193 275.520 274.377 276.995 273.647 276.511 277.051 276.509 273.544 274.915 tmax2m 1587470400 132 282.983 282.402 283.849 280.727 285.872 278.246 280.099 282.315 285.173 279.329 283.550 280.363 284.425 281.777 285.795 275.967 284.042 286.364 279.820 280.225 285.510 tmax2m 1587492000 138 283.165 282.569 283.793 280.953 285.888 278.667 279.784 282.454 285.707 279.546 282.841 279.699 284.620 282.308 285.478 276.378 284.088 286.925 279.791 279.437 286.318 tmax2m 1587513600 144 276.080 275.330 275.935 275.051 280.985 275.332 275.646 278.533 277.550 275.156 276.536 274.354 276.238 274.501 279.126 274.522 276.587 279.763 276.787 274.209 278.447 tmax2m 1587535200 150 274.274 273.167 274.399 271.944 277.576 271.887 272.162 275.132 277.060 272.452 273.542 270.982 274.743 273.190 275.922 271.017 274.169 278.917 273.822 270.690 278.228 tmax2m 1587556800 156 284.182 282.949 283.273 279.119 284.592 280.145 276.353 286.517 285.990 281.686 284.821 278.961 284.148 282.546 282.241 278.240 281.888 286.803 284.657 279.811 287.951 tmax2m 1587578400 162 284.049 283.205 283.399 279.113 284.704 280.767 276.622 286.893 286.235 282.139 284.539 279.313 284.100 282.605 282.061 278.517 281.864 286.545 285.314 280.280 288.251 tmax2m 1587600000 168 276.678 274.827 274.825 273.408 279.158 274.867 273.253 276.475 277.784 274.017 275.418 274.173 275.770 274.251 276.343 275.787 274.465 280.415 277.626 274.139 280.540 tmax2m 1587621600 174 274.241 273.476 273.506 270.823 276.299 272.098 270.890 276.934 276.942 274.064 275.661 271.764 275.204 272.676 273.294 273.087 271.764 279.440 277.019 271.883 277.841 tmax2m 1587643200 180 281.219 282.865 281.355 278.854 283.677 280.568 279.205 286.868 287.259 283.913 287.078 279.947 283.713 281.489 281.566 278.946 280.623 285.786 286.938 280.858 284.901 tmax2m 1587664800 186 281.109 283.060 281.501 278.822 283.483 281.141 279.939 286.750 287.275 283.987 287.203 279.753 284.067 281.828 281.258 279.054 281.014 285.743 286.866 280.573 285.005 tmax2m 1587686400 192 274.745 274.848 275.003 272.880 277.454 273.897 273.782 278.730 278.834 276.226 278.081 273.812 276.401 274.384 276.069 275.881 273.279 280.434 278.370 273.626 277.441 tmax2m 1587708000 198 273.945 274.017 275.712 272.775 276.387 272.672 273.640 277.719 278.599 276.520 277.544 272.135 271.938 274.289 275.482 274.217 272.400 279.514 275.502 273.413 272.455 tmax2m 1587729600 204 281.934 281.247 284.878 280.613 284.377 279.429 282.446 285.521 283.587 282.934 279.902 279.612 279.194 282.645 283.925 280.534 277.479 285.507 276.813 278.532 282.353 tmax2m 1587751200 210 282.160 281.274 285.275 280.807 284.069 279.270 282.477 285.663 283.288 282.413 279.284 279.847 279.592 282.307 284.481 281.378 277.877 286.067 277.280 277.493 283.305 tmax2m 1587772800 216 275.998 274.525 276.992 274.008 277.935 273.338 275.707 279.636 279.360 277.359 275.928 272.849 274.140 275.796 275.556 275.051 271.093 280.426 272.327 274.548 275.225 tmax2m 1587794400 222 273.696 272.440 276.164 271.523 275.880 270.377 275.030 278.254 277.390 275.836 273.307 273.969 273.926 272.688 275.742 275.977 268.951 277.345 269.864 273.230 274.795 tmax2m 1587816000 228 282.633 281.853 287.765 274.516 281.378 277.880 284.859 282.581 276.118 284.337 272.069 276.887 285.554 275.298 284.387 280.927 278.090 277.922 276.598 277.041 285.594 tmax2m 1587837600 234 282.893 282.220 287.896 275.295 281.178 278.422 284.616 283.175 275.647 284.264 271.969 276.559 286.155 275.447 284.406 281.126 278.742 277.792 276.319 277.553 286.308 tmax2m 1587859200 240 274.456 275.570 279.125 273.399 277.562 272.343 277.895 279.252 273.258 279.616 270.248 273.510 274.853 271.028 276.798 277.594 271.715 275.735 269.684 275.568 275.550 dd10m 1587016800 6 211.762 214.307 212.972 211.435 211.170 212.379 211.771 213.217 209.670 212.988 211.109 209.254 210.224 210.383 210.126 214.886 210.825 212.643 209.969 211.656 211.411 dd10m 1587038400 12 279.912 290.752 288.060 273.107 288.359 282.840 284.445 295.846 274.795 272.124 275.580 279.375 283.318 273.961 277.625 284.500 282.299 277.412 273.616 275.026 281.223 dd10m 1587060000 18 4.773 0.718 1.306 2.555 4.369 2.698 357.305 8.648 14.453 1.038 3.559 6.441 6.079 6.619 8.193 9.779 0.888 3.534 3.259 353.959 359.900 dd10m 1587081600 24 229.680 257.859 235.856 222.294 231.010 234.859 274.056 216.458 214.276 239.287 242.370 230.958 218.322 239.804 214.045 214.001 240.642 225.825 227.634 261.187 248.875 dd10m 1587103200 30 224.612 232.707 236.147 219.220 244.917 207.849 240.729 203.981 212.170 231.970 227.760 245.427 218.074 210.498 217.927 225.149 238.831 227.871 208.117 242.871 221.850 dd10m 1587124800 36 340.079 341.846 340.443 326.144 336.750 338.630 345.991 337.922 326.167 349.544 344.274 351.504 334.661 1.659 348.894 333.121 332.976 334.973 352.784 335.073 348.873 dd10m 1587146400 42 30.143 28.126 28.381 17.483 27.709 30.876 34.711 26.550 33.271 31.149 26.883 17.407 24.032 31.705 37.787 17.632 25.166 31.044 17.485 21.616 26.445 dd10m 1587168000 48 229.691 227.477 215.549 229.146 206.290 225.142 213.070 241.113 220.670 235.379 231.016 247.648 225.090 236.260 213.786 252.693 219.016 223.452 236.531 224.834 237.153 dd10m 1587189600 54 255.664 273.245 254.688 221.824 223.377 243.862 254.775 262.546 271.975 264.023 276.718 268.473 264.224 269.999 225.037 273.135 232.565 252.863 272.747 276.737 272.900 dd10m 1587211200 60 337.549 335.649 329.474 331.778 333.277 279.381 335.737 314.153 321.770 325.749 12.113 5.184 317.692 339.288 339.882 320.145 347.319 320.888 343.639 339.554 325.501 dd10m 1587232800 66 37.902 11.383 25.027 38.156 56.515 1.053 27.986 10.708 356.287 54.993 58.251 61.775 357.396 16.387 55.617 8.329 76.014 32.911 54.604 2.885 11.728 dd10m 1587254400 72 224.421 219.254 238.866 239.916 209.090 215.807 244.073 239.983 253.614 204.408 203.692 197.301 271.199 245.356 218.350 246.030 219.970 223.375 211.797 276.802 233.297 dd10m 1587276000 78 318.844 313.487 309.682 321.987 247.088 322.454 332.829 303.982 318.728 261.489 341.464 35.531 330.689 348.885 298.223 304.195 313.340 344.272 285.517 343.014 326.424 dd10m 1587297600 84 19.737 12.672 24.204 15.225 8.576 18.487 22.696 7.560 11.038 7.137 38.488 55.079 23.993 39.317 355.993 349.681 6.595 40.369 53.973 33.851 23.095 dd10m 1587319200 90 52.270 45.745 59.933 58.478 64.996 48.531 71.950 72.167 51.436 36.349 83.312 89.699 59.368 80.076 50.623 38.205 49.516 69.464 79.750 60.707 52.191 dd10m 1587340800 96 133.636 105.190 130.739 140.430 151.877 109.042 154.687 139.844 105.434 86.267 155.045 147.231 120.549 147.762 128.785 103.863 128.948 139.492 151.689 107.539 109.111 dd10m 1587362400 102 135.553 85.901 137.024 147.999 165.049 114.721 82.473 149.712 122.776 89.159 164.132 100.323 119.159 150.135 143.284 110.727 131.430 149.012 144.197 77.759 94.204 dd10m 1587384000 108 80.912 75.076 89.488 85.984 156.101 79.094 87.307 113.524 56.999 57.835 76.970 49.408 77.180 73.654 108.205 76.846 91.851 80.350 105.747 46.860 54.874 dd10m 1587405600 114 83.132 76.369 96.696 73.584 187.128 79.416 88.422 110.444 77.637 54.190 83.483 61.161 79.850 68.605 117.863 61.162 93.248 90.648 93.040 75.701 65.294 dd10m 1587427200 120 103.674 105.981 123.888 82.918 159.821 99.179 129.883 149.332 130.032 95.579 117.746 107.976 128.059 68.081 150.107 89.687 118.648 144.039 115.648 110.190 129.396 dd10m 1587448800 126 73.513 92.477 83.105 81.969 137.689 98.432 118.939 104.792 91.785 105.288 86.864 87.685 104.580 58.687 141.976 103.007 89.316 150.317 103.201 106.154 137.298 dd10m 1587470400 132 78.876 85.862 63.760 79.586 131.526 91.251 82.908 99.620 94.046 101.334 86.741 96.846 73.421 67.587 116.612 100.969 71.225 140.671 101.394 109.288 114.477 dd10m 1587492000 138 99.064 88.123 72.617 82.722 140.063 99.218 88.688 118.366 100.142 105.929 100.936 106.188 61.312 74.626 107.275 104.306 78.996 152.464 127.575 127.497 119.088 dd10m 1587513600 144 155.069 133.662 111.576 128.312 162.558 128.064 118.562 157.451 174.479 153.887 155.175 144.990 160.494 113.378 162.108 133.673 140.237 201.284 162.682 151.295 188.349 dd10m 1587535200 150 153.885 113.413 90.153 75.824 151.322 118.880 96.337 162.374 292.859 140.402 168.054 146.217 31.178 120.165 76.649 140.761 60.643 280.681 171.659 155.057 267.270 dd10m 1587556800 156 57.093 56.878 68.843 62.290 137.295 82.698 86.606 111.474 28.431 91.622 38.468 95.671 39.493 57.967 72.752 113.050 48.801 1.341 146.991 127.571 345.061 dd10m 1587578400 162 67.385 51.741 70.134 67.427 146.200 80.148 87.864 68.986 33.103 87.524 36.158 98.563 46.416 61.311 80.811 121.564 37.449 34.597 157.440 132.400 352.226 dd10m 1587600000 168 200.959 144.864 151.034 98.316 169.580 151.057 127.239 316.469 27.179 183.797 237.038 161.677 181.956 145.115 141.439 164.557 55.970 170.300 202.112 175.959 343.141 dd10m 1587621600 174 359.333 5.876 93.143 43.415 170.337 50.353 113.234 339.883 322.289 254.151 270.798 159.327 355.997 34.834 149.927 175.103 35.833 318.663 223.724 175.111 342.565 dd10m 1587643200 180 32.824 15.057 63.295 35.081 108.424 40.899 93.019 2.455 9.964 14.242 302.625 78.181 19.648 44.782 112.023 113.670 25.942 38.403 275.201 74.216 348.472 dd10m 1587664800 186 34.658 1.763 62.289 15.810 135.675 27.398 80.392 358.564 123.496 83.762 250.962 58.154 28.594 23.285 103.893 93.833 23.222 103.384 287.971 39.123 0.134 dd10m 1587686400 192 49.667 316.259 173.468 312.043 185.373 298.829 185.904 311.226 191.011 193.200 214.688 250.113 25.516 314.014 203.323 211.730 325.645 197.347 337.601 237.480 346.405 dd10m 1587708000 198 56.005 336.413 328.600 292.755 212.132 313.797 36.461 327.750 191.617 198.250 212.653 302.720 20.437 306.004 352.566 277.356 348.833 209.213 345.023 238.155 13.359 dd10m 1587729600 204 38.442 2.612 7.164 317.103 18.808 332.569 46.073 359.386 182.241 193.329 230.639 323.131 33.118 330.369 22.318 327.938 17.882 193.654 341.834 62.501 25.756 dd10m 1587751200 210 34.329 20.536 22.444 357.876 204.991 356.273 53.225 359.424 202.087 223.682 339.634 3.689 61.372 344.964 11.331 350.072 40.836 251.129 338.360 357.927 28.761 dd10m 1587772800 216 58.789 25.374 168.223 26.981 207.486 0.157 167.673 293.242 230.089 210.925 347.709 189.142 152.267 339.567 346.998 194.810 71.812 277.445 287.059 287.278 175.543 dd10m 1587794400 222 40.062 328.395 164.323 21.416 205.349 348.722 191.791 292.107 317.047 199.265 6.494 226.726 182.737 339.100 353.965 190.334 45.638 28.351 294.866 117.850 210.051 dd10m 1587816000 228 40.185 346.398 113.403 53.599 128.028 340.416 137.983 328.488 338.265 126.096 13.895 331.315 40.505 332.322 0.609 175.885 35.284 10.814 325.257 84.268 294.984 dd10m 1587837600 234 53.673 350.615 156.762 39.456 92.747 348.234 174.750 348.390 327.512 135.226 15.780 347.913 18.457 333.677 33.728 173.598 41.830 337.504 2.533 72.917 329.012 dd10m 1587859200 240 187.766 332.514 195.327 42.336 168.148 312.260 194.234 301.270 297.183 183.345 10.640 12.079 260.548 340.264 189.886 177.765 155.253 329.567 324.102 129.655 237.479 ff10m 1587016800 6 2.422 2.405 2.432 2.405 2.455 2.430 2.376 2.435 2.453 2.439 2.426 2.387 2.393 2.455 2.437 2.383 2.421 2.447 2.390 2.454 2.439 ff10m 1587038400 12 1.288 1.323 1.288 1.290 1.255 1.271 1.215 1.395 1.260 1.225 1.345 1.380 1.258 1.279 1.403 1.193 1.456 1.253 1.208 1.275 1.330 ff10m 1587060000 18 1.122 1.030 1.216 1.047 1.210 0.996 1.073 1.094 1.084 0.882 1.195 1.122 1.011 1.115 1.066 1.144 1.063 1.136 0.991 1.334 0.977 ff10m 1587081600 24 0.580 0.408 0.647 0.739 0.698 0.575 0.488 0.412 0.868 0.576 0.497 0.635 0.603 0.642 0.709 0.888 0.790 0.716 0.658 0.433 0.527 ff10m 1587103200 30 0.998 0.974 1.033 0.979 1.000 1.318 0.889 1.199 1.241 1.001 0.923 0.768 1.213 0.881 1.058 1.131 1.015 1.028 0.924 0.849 0.837 ff10m 1587124800 36 0.883 1.234 1.176 0.701 1.289 0.636 1.177 0.479 0.555 1.015 1.000 1.122 1.089 0.629 0.849 1.039 1.142 0.964 0.569 1.127 0.829 ff10m 1587146400 42 1.176 1.211 1.347 1.239 1.164 1.088 1.163 1.034 1.008 1.236 1.209 1.283 1.173 0.941 1.069 1.183 1.309 1.143 1.043 1.211 1.150 ff10m 1587168000 48 1.145 1.267 1.007 1.154 1.130 1.463 1.533 1.022 1.434 1.157 0.391 0.761 1.186 1.355 1.292 0.969 1.132 1.383 1.463 0.849 1.256 ff10m 1587189600 54 0.761 1.005 0.796 1.055 0.868 1.010 0.824 0.760 1.034 0.823 0.357 0.510 0.956 0.930 0.676 0.910 0.640 0.801 0.975 0.973 0.889 ff10m 1587211200 60 1.219 1.635 1.408 0.971 0.592 0.593 1.332 0.875 1.258 1.014 0.858 1.309 1.731 1.253 0.835 1.263 0.806 1.452 1.314 2.082 1.789 ff10m 1587232800 66 1.153 1.348 1.188 0.917 1.150 0.533 1.324 0.924 1.358 1.148 1.200 1.462 1.481 1.415 1.184 0.959 0.914 1.344 0.947 1.756 1.433 ff10m 1587254400 72 1.883 1.689 1.753 1.570 2.163 1.540 1.541 1.792 1.270 1.996 1.835 1.546 1.646 1.437 2.138 1.459 1.981 1.449 1.922 1.454 1.710 ff10m 1587276000 78 1.552 1.228 1.370 1.410 1.356 1.131 1.237 1.408 1.701 1.130 0.901 0.953 1.740 1.444 1.543 1.461 1.286 1.199 1.095 1.944 1.255 ff10m 1587297600 84 3.642 3.201 3.150 3.358 2.513 2.923 2.881 2.561 3.408 3.699 3.445 3.040 3.356 3.000 3.424 3.283 3.557 3.417 1.933 3.479 3.306 ff10m 1587319200 90 2.677 2.465 2.531 2.577 1.986 2.287 2.016 2.311 2.461 2.445 2.419 2.363 2.631 2.341 2.228 2.189 2.215 2.696 2.068 2.319 2.583 ff10m 1587340800 96 1.849 1.733 2.107 1.979 2.153 1.787 1.437 2.540 1.637 1.784 2.306 1.637 1.847 1.671 2.016 1.775 1.852 1.979 2.208 1.809 1.680 ff10m 1587362400 102 1.794 2.227 2.011 1.811 2.754 1.817 1.116 2.368 1.668 1.860 1.832 0.751 1.854 1.018 2.289 1.740 2.003 1.753 2.038 1.824 1.720 ff10m 1587384000 108 2.932 3.650 2.666 2.259 2.171 3.083 2.931 2.181 3.539 3.481 2.247 4.368 2.810 2.952 2.452 2.794 2.813 2.981 1.904 3.560 4.389 ff10m 1587405600 114 2.866 3.134 2.251 2.416 1.022 2.808 2.393 2.350 2.703 3.961 2.559 3.847 2.520 2.842 2.322 3.333 2.485 2.176 2.341 2.919 3.623 ff10m 1587427200 120 2.136 2.383 1.993 2.330 1.318 2.492 2.146 1.780 1.989 3.053 2.048 2.465 2.293 2.646 2.412 2.940 1.872 1.912 2.214 2.844 2.820 ff10m 1587448800 126 2.791 2.475 2.232 3.225 1.883 2.836 1.369 1.321 1.733 3.201 2.580 2.367 1.771 2.919 2.188 3.198 1.940 2.099 2.350 2.831 2.459 ff10m 1587470400 132 3.614 3.444 4.176 4.182 3.005 3.839 3.286 2.788 2.937 3.706 3.540 3.554 3.125 4.256 2.365 3.775 3.276 2.362 3.591 3.931 2.727 ff10m 1587492000 138 2.835 3.281 3.432 3.366 2.358 3.382 3.048 2.812 1.998 2.822 3.211 3.404 2.596 3.403 1.361 3.466 2.803 1.481 3.205 3.867 1.934 ff10m 1587513600 144 2.630 2.181 2.090 2.319 2.511 2.708 2.831 2.622 1.782 2.523 3.127 3.073 1.015 2.365 1.474 2.939 1.585 2.078 3.274 3.396 1.896 ff10m 1587535200 150 0.915 1.548 1.877 2.303 2.398 2.498 3.347 2.282 0.457 1.620 1.593 2.156 1.726 1.539 1.178 2.247 1.304 1.122 2.769 2.959 1.099 ff10m 1587556800 156 2.539 3.460 3.199 4.369 3.018 3.176 4.351 1.822 3.014 2.457 2.036 3.168 3.720 3.307 3.477 2.725 3.462 2.044 2.086 3.224 2.757 ff10m 1587578400 162 1.535 2.583 2.243 3.024 2.839 2.663 3.092 1.245 1.939 1.834 1.633 2.413 2.089 3.006 3.279 2.400 3.153 1.461 1.402 2.176 2.900 ff10m 1587600000 168 0.531 0.591 1.440 1.062 3.036 1.599 2.166 1.175 0.358 1.819 0.661 1.930 0.394 2.177 2.500 2.347 1.291 0.291 2.240 2.604 2.112 ff10m 1587621600 174 1.092 1.920 0.705 2.067 1.818 1.399 2.142 1.293 0.282 0.577 0.995 1.720 1.062 0.884 2.481 1.750 1.785 0.624 1.836 1.486 2.317 ff10m 1587643200 180 3.234 3.503 3.846 3.646 1.667 3.481 3.177 1.930 1.390 1.678 1.345 1.964 3.446 4.360 2.599 1.089 3.763 1.345 2.120 1.615 3.639 ff10m 1587664800 186 3.320 2.835 2.275 3.131 1.639 2.574 2.504 1.820 1.021 0.775 1.008 1.667 3.087 2.951 1.530 0.723 2.508 1.161 1.219 0.896 3.340 ff10m 1587686400 192 1.202 1.854 0.935 1.846 2.265 1.519 1.085 1.509 2.697 2.519 2.938 0.919 1.977 1.713 0.754 0.917 1.845 2.153 3.672 1.615 2.374 ff10m 1587708000 198 1.127 2.209 0.977 1.893 1.404 2.077 1.102 1.131 2.514 2.235 2.755 1.271 2.976 1.981 1.221 0.877 2.715 1.647 3.036 0.991 2.043 ff10m 1587729600 204 2.501 4.667 3.156 2.606 0.939 4.370 2.745 2.103 2.831 2.525 1.397 1.986 4.340 4.072 2.892 0.982 4.153 1.375 2.988 0.997 2.907 ff10m 1587751200 210 2.334 3.372 1.993 1.786 0.063 3.608 2.269 1.559 2.090 1.311 1.546 1.159 2.863 3.258 1.865 0.272 3.349 1.958 2.858 0.572 2.046 ff10m 1587772800 216 0.783 0.485 1.075 1.800 1.243 2.240 1.922 1.148 1.537 1.797 1.413 2.124 1.818 2.517 1.282 1.938 1.362 0.825 2.052 0.272 0.499 ff10m 1587794400 222 1.083 0.922 1.430 1.999 0.578 1.953 1.706 1.280 1.179 0.783 2.197 1.370 1.583 3.015 1.185 2.443 1.775 0.433 2.768 0.437 1.603 ff10m 1587816000 228 2.457 3.439 1.427 2.574 0.552 3.229 0.509 2.398 2.057 1.899 2.658 0.718 2.063 4.071 2.164 2.601 3.613 1.181 3.483 1.257 2.012 ff10m 1587837600 234 1.586 2.737 1.086 2.435 1.158 3.832 0.944 1.979 2.286 1.678 2.037 1.714 0.966 3.429 1.684 2.318 2.576 1.655 3.010 1.693 1.025 ff10m 1587859200 240 1.872 1.850 2.211 1.607 2.444 1.680 2.761 0.960 1.662 2.942 1.777 1.886 0.677 3.234 0.827 3.371 1.400 0.484 1.187 1.658 1.828 apcpsfc 1587016800 6 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1587038400 12 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.010 0.000 0.000 0.010 0.000 0.010 0.010 0.000 0.010 0.000 0.000 0.000 0.000 apcpsfc 1587060000 18 0.003 0.000 0.003 0.003 0.005 0.003 0.003 0.000 0.003 0.000 0.000 0.011 0.005 0.000 0.003 0.005 0.005 0.003 0.005 0.003 0.003 apcpsfc 1587081600 24 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1587103200 30 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.002 0.000 0.000 0.000 0.000 apcpsfc 1587124800 36 0.032 0.036 0.108 0.008 0.189 0.003 0.058 0.003 0.003 0.026 0.000 0.060 0.026 0.008 0.008 0.145 0.157 0.098 0.000 0.000 0.008 apcpsfc 1587146400 42 0.609 0.673 0.991 0.324 1.020 0.200 0.613 0.261 0.201 0.622 0.520 0.848 0.848 0.503 0.220 1.366 1.197 0.699 0.279 0.680 0.299 apcpsfc 1587168000 48 0.171 0.063 0.078 0.444 0.038 0.138 0.014 0.197 0.142 0.253 0.028 0.406 0.475 0.153 0.043 0.284 0.141 0.176 0.155 0.046 0.204 apcpsfc 1587189600 54 0.066 0.048 0.073 0.014 0.012 0.057 0.000 0.057 0.162 0.018 0.020 0.023 0.077 0.064 0.010 0.027 0.001 0.068 0.106 0.039 0.151 apcpsfc 1587211200 60 0.273 0.299 0.471 0.221 0.183 0.194 0.233 0.352 0.560 0.206 0.243 0.144 0.609 0.441 0.370 0.450 0.153 0.330 0.385 0.524 0.521 apcpsfc 1587232800 66 1.591 1.551 1.855 1.616 1.712 2.635 1.387 2.136 2.377 1.219 1.763 1.475 1.534 2.366 1.736 1.855 1.511 1.084 1.866 1.761 1.308 apcpsfc 1587254400 72 0.187 0.018 0.319 0.265 0.171 0.372 0.097 0.989 0.313 0.206 0.059 0.036 0.399 0.578 0.071 0.467 0.233 0.037 0.357 0.779 0.192 apcpsfc 1587276000 78 0.028 0.214 0.046 0.255 0.136 0.364 0.081 0.156 0.065 0.613 0.000 0.038 0.337 0.018 0.114 0.334 0.438 0.018 0.057 0.334 0.077 apcpsfc 1587297600 84 0.252 0.654 0.774 0.758 0.767 1.028 0.200 0.974 0.954 1.233 0.196 0.143 0.153 0.172 0.824 1.002 0.988 0.079 0.708 0.217 0.378 apcpsfc 1587319200 90 0.604 1.485 1.821 1.227 1.917 1.964 1.293 1.957 0.870 1.251 0.175 0.349 0.148 0.901 1.709 1.770 0.949 0.236 6.680 0.080 1.033 apcpsfc 1587340800 96 0.000 0.123 0.026 0.026 0.122 0.104 0.053 0.026 0.074 0.159 0.023 0.122 0.000 0.079 0.074 0.053 0.000 0.026 3.611 0.000 0.074 apcpsfc 1587362400 102 0.128 0.284 0.922 0.252 0.060 0.932 0.206 0.249 0.000 0.074 0.125 0.195 0.219 0.492 0.244 1.247 0.039 0.127 0.557 0.048 0.128 apcpsfc 1587384000 108 1.506 0.381 1.011 2.581 0.455 7.786 0.296 0.323 0.105 0.915 0.532 0.100 0.609 1.384 1.833 8.734 0.344 0.222 4.083 0.038 0.124 apcpsfc 1587405600 114 1.350 0.170 1.637 4.744 4.790 9.639 0.631 2.096 0.118 1.547 1.364 0.000 0.596 1.300 6.664 10.911 0.602 0.122 9.499 0.000 0.000 apcpsfc 1587427200 120 0.270 0.122 0.147 0.785 2.064 2.809 0.703 0.170 0.048 0.505 0.319 0.017 0.213 0.244 0.196 6.442 0.176 0.000 4.487 0.000 0.000 apcpsfc 1587448800 126 0.096 0.096 0.014 0.265 0.516 1.520 1.274 0.258 0.096 0.250 0.233 0.045 0.053 0.000 0.000 5.554 0.092 0.048 1.840 0.014 0.062 apcpsfc 1587470400 132 0.010 0.096 0.010 0.074 0.319 1.214 1.671 0.333 0.000 0.478 0.064 0.107 0.010 0.000 0.067 4.284 0.024 0.000 1.182 0.343 0.000 apcpsfc 1587492000 138 0.000 0.244 0.000 0.100 1.008 1.870 2.766 0.435 0.000 1.129 0.249 1.202 0.000 0.000 0.679 2.696 0.071 0.000 2.423 1.807 0.000 apcpsfc 1587513600 144 0.074 0.000 0.008 0.222 0.076 0.581 1.161 0.048 0.000 0.172 0.196 1.217 0.000 0.000 0.573 0.526 0.053 0.000 0.334 0.474 0.000 apcpsfc 1587535200 150 0.010 0.000 0.031 0.010 0.057 0.096 1.738 0.000 0.000 0.010 0.048 0.000 0.000 0.010 0.382 0.000 0.057 0.000 0.000 0.014 0.000 apcpsfc 1587556800 156 0.000 0.000 0.000 0.094 0.397 0.048 1.549 0.000 0.000 0.081 0.000 0.192 0.000 0.000 0.364 0.323 0.003 0.100 0.000 0.000 0.000 apcpsfc 1587578400 162 0.296 0.000 0.000 0.571 0.717 0.287 1.331 0.000 0.000 0.191 0.100 0.868 0.000 0.100 1.028 2.255 0.080 1.594 0.000 0.048 0.947 apcpsfc 1587600000 168 0.026 0.000 0.088 0.397 0.191 0.180 0.170 0.000 0.000 0.000 0.000 0.628 0.000 0.459 0.497 1.602 0.000 2.017 0.000 0.000 0.413 apcpsfc 1587621600 174 0.026 0.000 0.326 0.017 0.334 0.000 0.000 0.000 0.000 0.000 0.000 0.085 0.000 0.000 0.067 0.344 0.000 0.170 0.000 0.000 0.037 apcpsfc 1587643200 180 0.324 0.000 0.087 0.025 0.320 0.000 0.000 0.000 0.000 0.057 0.003 0.956 0.000 0.000 0.073 1.457 0.000 0.463 0.122 0.167 0.000 apcpsfc 1587664800 186 1.131 0.000 0.100 0.106 0.635 0.005 0.061 0.798 0.117 1.231 2.520 2.887 0.000 0.000 0.566 6.947 0.000 1.283 4.323 1.556 0.000 apcpsfc 1587686400 192 0.185 0.000 0.000 0.207 0.010 0.000 0.003 0.095 0.241 0.462 6.235 0.555 0.000 0.000 0.048 4.789 0.000 0.430 11.486 1.158 0.000 apcpsfc 1587708000 198 0.069 0.001 0.000 0.022 0.053 0.000 0.000 0.030 1.917 0.818 5.644 0.053 0.000 0.000 0.000 0.181 0.600 0.743 2.411 0.357 0.026 apcpsfc 1587729600 204 0.043 0.176 0.000 0.522 1.127 0.760 0.012 0.426 4.261 1.327 6.124 0.150 0.000 0.033 0.000 0.299 0.581 2.008 0.316 3.834 0.000 apcpsfc 1587751200 210 0.199 0.152 0.000 2.943 5.153 1.653 0.102 0.782 6.805 2.779 8.460 0.607 0.000 0.519 0.000 0.973 0.189 5.009 0.231 9.990 0.000 apcpsfc 1587772800 216 0.000 0.005 0.000 7.248 3.001 0.849 0.018 0.073 11.278 1.789 6.857 0.102 0.000 1.174 0.000 0.567 0.139 5.110 0.003 7.228 0.000 apcpsfc 1587794400 222 0.000 0.000 0.000 7.282 0.917 0.171 0.018 0.140 9.986 0.067 9.454 1.533 0.000 2.091 0.000 1.653 0.012 3.132 0.008 0.673 0.000 apcpsfc 1587816000 228 0.026 0.000 0.000 4.577 1.813 0.029 0.158 2.104 8.623 0.328 7.199 5.471 0.000 1.428 0.004 2.389 0.000 7.880 0.519 0.964 0.003 apcpsfc 1587837600 234 0.122 0.018 1.697 3.385 6.126 0.139 0.978 3.532 8.508 1.262 6.704 10.060 0.005 1.556 0.209 1.953 0.000 13.346 1.668 2.581 0.128 apcpsfc 1587859200 240 0.003 0.335 0.051 3.038 5.990 0.083 0.785 0.673 5.914 0.031 3.234 8.924 0.000 1.468 0.225 0.460 0.000 8.404 0.238 0.726 0.023 tmp2m 1587016800 6 274.464 274.595 274.373 274.521 274.399 274.373 274.347 274.347 274.659 274.399 274.495 274.607 274.521 274.621 274.521 274.538 274.528 274.485 274.547 274.399 274.447 tmp2m 1587038400 12 282.248 282.379 282.366 282.169 282.370 282.227 282.331 282.401 282.181 282.112 282.134 282.012 282.344 282.152 282.188 282.504 282.183 282.379 282.082 282.169 282.175 tmp2m 1587060000 18 274.101 274.492 274.035 274.429 274.746 273.528 274.759 273.763 273.986 274.288 273.943 274.453 273.710 274.254 273.571 273.972 274.280 274.582 274.282 275.192 273.767 tmp2m 1587081600 24 271.229 271.772 271.104 270.871 271.581 271.230 271.719 271.283 271.141 271.288 271.145 271.395 271.184 271.264 271.083 271.530 271.285 271.289 271.293 271.103 271.032 tmp2m 1587103200 30 276.829 276.881 276.700 276.813 276.907 276.903 276.629 276.813 276.839 276.856 276.856 276.767 276.839 276.855 276.839 276.922 276.878 276.896 276.777 276.664 276.746 tmp2m 1587124800 36 286.091 285.833 285.633 286.067 285.539 286.619 285.566 286.683 286.544 285.778 286.072 285.753 286.110 286.672 286.206 286.208 285.437 285.904 286.327 285.869 286.095 tmp2m 1587146400 42 278.193 277.457 277.199 277.740 277.714 278.244 277.376 278.067 277.858 278.291 278.228 277.270 277.914 278.209 278.119 278.162 277.299 277.995 278.114 277.078 278.009 tmp2m 1587168000 48 274.484 275.464 274.177 274.597 274.540 275.298 274.830 274.371 274.802 274.879 274.143 274.176 274.717 274.696 275.056 274.584 274.435 275.240 275.185 274.547 275.532 tmp2m 1587189600 54 278.333 278.187 278.250 278.140 278.401 278.264 278.181 278.321 278.435 278.073 278.314 277.855 278.229 278.157 278.341 278.064 278.068 278.285 278.282 278.395 278.271 tmp2m 1587211200 60 287.184 286.765 286.574 287.237 287.921 287.931 286.970 287.618 286.685 287.693 287.735 286.919 286.313 287.028 287.681 287.070 287.776 286.940 286.642 286.037 286.330 tmp2m 1587232800 66 277.835 277.939 278.057 278.588 278.387 278.845 278.231 278.531 278.661 278.200 278.360 279.044 277.876 278.409 278.482 277.230 279.195 278.178 278.404 278.645 277.738 tmp2m 1587254400 72 276.448 275.665 275.934 276.243 277.275 276.653 275.658 276.176 275.455 277.513 277.207 276.424 275.708 275.974 276.996 275.825 276.886 275.741 276.552 275.617 275.708 tmp2m 1587276000 78 278.733 278.709 278.433 278.637 279.276 278.750 278.466 278.441 278.315 278.875 279.038 278.684 277.858 278.503 278.848 278.386 279.128 279.089 279.058 277.706 278.538 tmp2m 1587297600 84 286.053 285.368 285.356 285.503 286.582 284.710 286.456 285.203 284.548 285.100 286.194 286.200 285.520 285.612 285.971 285.474 285.630 286.785 285.639 285.112 285.401 tmp2m 1587319200 90 280.093 279.562 279.563 279.837 280.567 280.112 278.946 280.055 279.416 280.144 279.682 279.287 279.218 279.044 279.899 279.428 279.916 279.973 280.404 278.189 279.554 tmp2m 1587340800 96 276.397 276.408 276.271 277.040 278.430 277.153 277.610 277.466 274.346 276.730 278.032 277.723 275.559 277.493 276.979 275.977 275.604 277.061 278.488 273.981 276.291 tmp2m 1587362400 102 277.926 276.437 277.692 278.177 278.808 277.322 278.155 278.195 277.140 277.231 279.231 278.231 277.565 278.191 277.973 277.007 277.736 278.452 278.018 276.708 277.291 tmp2m 1587384000 108 283.298 281.789 283.797 283.001 285.587 279.978 284.936 284.202 285.267 279.989 285.767 284.409 283.759 283.486 283.401 279.635 283.825 285.396 282.029 284.437 284.223 tmp2m 1587405600 114 278.763 277.303 279.353 278.770 280.405 277.315 279.612 279.553 277.502 275.816 280.614 276.279 278.607 278.529 279.827 276.570 279.239 279.671 278.893 276.093 277.011 tmp2m 1587427200 120 275.744 274.353 275.809 275.022 278.203 274.490 276.896 276.622 274.192 272.957 277.914 272.390 275.407 274.613 276.565 273.466 276.436 276.545 276.461 272.254 273.365 tmp2m 1587448800 126 274.351 274.509 275.784 273.430 278.635 273.618 276.242 276.740 275.526 272.823 276.393 272.965 275.055 272.204 276.934 272.758 276.056 276.611 275.469 273.272 274.881 tmp2m 1587470400 132 282.983 282.376 283.849 280.727 285.824 278.246 280.046 282.315 285.173 279.329 283.248 280.046 284.442 281.729 285.699 275.967 284.016 286.364 279.767 279.546 285.510 tmp2m 1587492000 138 276.392 276.072 276.410 275.499 281.233 275.501 275.972 278.723 277.919 275.509 276.862 274.480 276.756 274.954 279.601 274.805 277.061 280.027 277.040 274.509 279.380 tmp2m 1587513600 144 272.834 270.667 272.590 271.495 276.219 271.295 272.288 273.570 273.388 270.798 272.492 270.133 271.345 270.430 274.925 270.314 272.823 274.859 272.488 269.985 273.811 tmp2m 1587535200 150 274.248 273.091 274.289 271.835 277.454 271.609 271.336 275.047 277.060 272.351 273.533 270.792 274.743 273.106 275.865 270.827 274.100 278.917 273.779 270.564 278.228 tmp2m 1587556800 156 284.182 282.949 283.273 279.119 284.592 280.145 276.353 286.517 285.990 281.686 284.615 278.913 284.148 282.546 282.241 278.240 281.766 286.459 284.631 279.811 287.951 tmp2m 1587578400 162 277.310 275.418 275.246 273.770 279.320 275.093 273.580 277.450 278.267 274.608 276.243 274.421 276.249 274.634 276.670 276.051 274.927 280.807 277.942 274.494 280.710 tmp2m 1587600000 168 271.930 269.723 272.189 269.211 274.749 269.731 268.615 273.148 272.444 270.141 271.065 269.793 270.774 270.318 273.064 272.414 269.022 278.193 273.447 269.110 276.759 tmp2m 1587621600 174 274.241 273.479 273.506 270.775 276.230 272.098 270.650 276.934 276.932 274.064 275.661 271.764 275.204 272.676 273.050 273.087 271.764 279.440 277.019 271.883 276.263 tmp2m 1587643200 180 281.219 282.697 281.355 278.802 283.582 280.568 278.871 286.851 287.255 283.913 287.061 279.938 283.591 281.489 281.566 278.680 280.596 285.776 286.707 280.810 284.853 tmp2m 1587664800 186 275.175 275.320 275.421 273.258 277.792 274.517 274.431 279.075 279.209 276.701 278.103 274.205 276.697 274.728 276.443 275.989 273.827 281.036 278.544 274.067 277.872 tmp2m 1587686400 192 270.075 270.912 270.238 270.294 271.840 269.816 269.036 275.980 277.220 274.306 276.603 267.706 269.956 271.053 270.349 271.403 269.707 276.950 274.972 269.946 270.793 tmp2m 1587708000 198 273.945 274.006 275.712 272.775 276.387 272.683 273.640 277.719 278.577 276.473 277.274 272.135 271.938 274.289 275.482 274.193 272.390 279.466 272.560 273.413 272.328 tmp2m 1587729600 204 281.934 281.220 284.830 280.513 284.129 279.348 282.446 285.495 282.990 282.389 279.419 279.574 279.194 282.645 283.925 280.477 277.479 285.433 276.813 277.390 282.353 tmp2m 1587751200 210 276.512 275.289 277.523 275.000 278.320 273.510 276.448 280.269 279.560 277.550 276.176 273.878 274.614 276.115 276.694 275.494 271.669 280.717 272.848 274.771 276.356 tmp2m 1587772800 216 269.278 268.153 271.290 271.131 274.057 269.188 271.465 275.069 277.458 273.119 273.273 270.263 269.226 272.526 269.941 272.096 267.320 277.242 267.550 271.373 269.624 tmp2m 1587794400 222 273.622 272.436 276.164 270.385 275.854 269.605 275.030 278.195 275.201 275.836 270.817 273.934 273.926 271.715 275.694 275.977 268.951 276.548 269.864 273.230 274.795 tmp2m 1587816000 228 282.585 281.725 287.765 274.516 281.330 277.806 284.345 282.481 275.600 284.167 271.968 276.623 285.554 275.298 284.335 280.712 278.090 277.604 276.245 277.014 285.594 tmp2m 1587837600 234 275.827 276.144 279.525 273.612 277.780 272.913 278.357 279.599 273.441 279.820 270.628 273.675 276.100 271.259 277.655 277.942 272.492 275.734 270.750 275.830 277.216 tmp2m 1587859200 240 271.366 270.564 274.151 271.061 275.232 268.002 274.511 275.676 270.614 275.850 268.037 270.525 269.359 268.706 272.227 275.515 266.599 274.295 266.830 272.990 272.372 tcdcclm 1587016800 6 2.014 0.825 2.544 2.709 3.373 3.132 3.689 2.123 3.527 2.175 1.902 1.220 2.589 2.301 2.185 3.506 2.178 1.012 1.763 2.975 2.930 tcdcclm 1587038400 12 2.790 3.395 2.871 4.129 2.462 2.805 2.948 3.019 2.784 2.520 2.847 2.518 2.780 2.506 3.370 2.204 2.609 2.665 3.323 2.653 2.704 tcdcclm 1587060000 18 5.362 5.562 5.208 6.658 5.700 3.513 6.175 3.881 5.362 5.786 4.749 5.196 4.912 5.132 4.490 4.490 5.941 6.164 5.301 6.115 5.723 tcdcclm 1587081600 24 3.690 6.167 0.952 1.816 5.301 1.994 6.420 3.339 2.448 5.054 2.162 5.599 2.812 3.655 2.210 1.331 3.400 3.977 4.867 2.941 2.234 tcdcclm 1587103200 30 2.306 1.775 2.199 3.630 3.285 2.877 4.319 3.002 2.077 2.905 1.976 3.895 3.093 1.721 2.133 2.371 2.421 3.644 3.238 1.394 3.157 tcdcclm 1587124800 36 2.621 2.271 2.432 2.414 1.465 3.068 1.150 3.787 2.988 2.708 2.399 0.721 1.957 2.646 2.693 2.422 3.498 1.419 2.331 2.118 2.225 tcdcclm 1587146400 42 3.182 2.523 2.403 3.847 1.436 4.468 2.088 4.794 4.595 3.631 4.460 1.811 2.969 3.735 3.701 3.425 3.249 3.022 3.270 2.443 4.405 tcdcclm 1587168000 48 3.141 5.587 2.731 3.635 4.012 4.626 2.621 3.431 3.829 4.638 3.220 2.845 3.965 3.490 5.170 2.676 2.046 4.304 4.462 4.473 5.693 tcdcclm 1587189600 54 4.997 6.145 5.565 4.550 4.824 5.588 4.945 5.894 6.132 3.667 4.519 3.675 5.636 4.084 5.853 3.067 3.128 5.989 5.766 5.504 6.433 tcdcclm 1587211200 60 4.129 3.254 5.500 5.076 5.209 4.258 5.172 4.706 5.662 2.903 5.042 4.298 4.851 4.252 4.538 3.564 3.769 4.093 3.552 5.657 4.656 tcdcclm 1587232800 66 4.919 4.755 4.934 5.909 5.613 6.098 4.527 6.166 5.994 4.955 5.237 4.202 4.126 6.069 5.834 5.223 5.768 4.750 5.548 4.388 4.049 tcdcclm 1587254400 72 5.791 3.941 6.166 6.373 7.268 7.478 3.859 4.566 5.345 7.786 7.530 4.584 3.798 7.392 6.836 7.149 5.789 4.924 5.010 2.326 5.428 tcdcclm 1587276000 78 4.411 6.202 4.600 4.244 6.795 7.097 3.670 3.531 3.847 7.206 6.798 5.615 0.919 5.866 7.197 5.936 6.937 2.692 4.325 1.933 5.438 tcdcclm 1587297600 84 1.613 6.700 1.577 1.180 4.906 5.642 1.091 3.151 1.986 5.641 4.517 3.319 1.774 4.240 4.511 2.470 3.339 2.123 3.169 3.488 3.971 tcdcclm 1587319200 90 3.711 4.257 4.603 5.611 6.307 7.049 1.875 6.745 2.584 6.683 1.699 2.620 3.877 4.840 5.814 4.487 2.180 3.146 7.220 2.305 3.531 tcdcclm 1587340800 96 6.215 5.149 5.021 7.123 7.743 7.655 6.488 6.919 4.371 7.257 4.264 3.901 6.085 4.990 7.508 5.763 4.557 6.127 7.262 4.998 5.067 tcdcclm 1587362400 102 5.843 5.338 4.952 7.071 6.862 7.097 7.804 7.768 3.011 6.160 7.303 5.612 5.593 5.381 7.074 5.967 3.835 6.164 7.077 4.917 5.061 tcdcclm 1587384000 108 6.234 5.719 5.029 6.616 7.511 7.328 6.598 7.864 3.327 5.606 7.325 2.755 4.987 5.658 6.805 6.681 6.334 5.530 7.029 1.802 2.771 tcdcclm 1587405600 114 5.665 4.966 5.044 6.663 7.899 7.679 5.210 7.667 0.520 5.474 7.353 0.552 5.696 6.064 7.168 6.127 6.380 2.956 7.355 0.351 0.303 tcdcclm 1587427200 120 5.195 4.956 5.837 6.037 7.057 7.615 5.885 7.760 2.883 5.510 6.613 2.042 6.160 6.281 6.341 6.201 5.888 3.374 7.139 1.210 1.009 tcdcclm 1587448800 126 4.116 3.764 3.651 5.201 6.523 5.833 5.842 6.541 3.611 4.903 5.319 4.738 3.779 3.078 6.158 6.305 3.963 3.325 5.829 3.142 3.282 tcdcclm 1587470400 132 0.997 2.406 1.210 2.797 6.805 5.478 5.767 5.880 0.455 3.557 2.721 2.896 1.175 0.118 4.310 6.593 1.812 0.378 5.656 2.768 0.340 tcdcclm 1587492000 138 0.545 3.584 0.181 3.603 6.356 5.597 5.743 5.676 0.191 5.094 4.873 5.706 0.577 0.126 5.036 6.184 3.117 0.149 5.788 5.649 0.875 tcdcclm 1587513600 144 3.371 1.114 1.239 3.947 4.882 4.048 5.576 5.609 0.218 3.384 4.426 4.927 0.174 0.181 4.035 5.172 3.675 0.388 2.716 4.698 1.374 tcdcclm 1587535200 150 1.363 0.174 4.120 2.001 5.879 3.117 5.666 2.693 0.212 0.684 2.275 0.751 0.149 2.645 4.217 2.655 4.822 0.694 0.692 1.231 3.426 tcdcclm 1587556800 156 0.983 0.098 0.403 1.886 6.754 1.143 5.595 1.164 0.111 1.334 2.803 2.262 0.098 3.643 5.197 4.570 5.677 3.717 0.090 0.136 5.247 tcdcclm 1587578400 162 3.942 0.059 3.086 4.108 7.233 3.676 5.890 0.378 2.273 3.585 1.548 5.253 0.059 6.043 5.956 5.784 5.637 5.916 0.187 0.869 6.610 tcdcclm 1587600000 168 2.556 0.111 5.556 4.811 7.676 3.658 5.408 0.111 0.639 0.589 0.577 4.026 0.119 4.717 5.276 5.784 1.273 6.494 1.444 0.313 5.889 tcdcclm 1587621600 174 1.827 0.160 6.361 2.015 7.621 0.657 3.838 0.342 2.477 0.761 0.453 3.300 3.464 0.793 4.476 4.483 0.164 6.598 3.433 0.983 4.447 tcdcclm 1587643200 180 2.281 1.200 4.687 0.499 6.850 0.178 5.171 0.132 4.208 1.393 1.811 2.732 5.950 0.046 2.392 5.317 2.167 5.874 4.393 4.254 3.726 tcdcclm 1587664800 186 4.736 0.377 2.377 1.426 5.263 0.602 5.431 2.833 5.447 3.170 7.399 5.635 5.129 2.496 5.251 6.489 3.541 5.618 7.654 5.748 4.544 tcdcclm 1587686400 192 2.870 0.613 0.080 3.334 4.614 0.979 2.014 5.132 4.476 5.115 7.870 3.342 4.045 4.663 1.713 6.283 4.583 5.280 7.913 5.109 5.425 tcdcclm 1587708000 198 1.813 0.344 0.706 5.682 4.056 0.310 0.770 3.277 5.368 5.488 7.620 1.467 1.850 1.871 0.337 2.384 3.278 4.613 7.028 3.503 3.991 tcdcclm 1587729600 204 1.015 0.822 4.827 3.971 5.285 2.921 0.527 1.918 6.234 3.884 7.794 1.264 0.328 5.375 0.913 2.481 5.200 4.872 5.333 4.979 0.279 tcdcclm 1587751200 210 3.019 1.712 0.816 5.580 5.119 4.949 2.822 5.732 7.053 4.346 7.736 2.855 0.321 4.982 0.712 2.360 4.474 5.860 3.775 6.766 3.945 tcdcclm 1587772800 216 0.763 2.573 0.066 6.254 6.244 6.235 1.368 4.314 7.668 2.983 7.475 2.744 1.356 6.668 1.035 3.691 5.364 6.960 1.418 7.432 1.773 tcdcclm 1587794400 222 0.411 5.068 0.080 7.867 5.267 4.356 2.700 5.936 7.827 2.182 7.863 5.085 2.841 7.679 2.085 5.593 2.074 7.177 2.229 6.105 0.305 tcdcclm 1587816000 228 0.262 3.364 0.130 7.786 4.417 1.471 4.497 7.030 7.681 2.939 7.818 6.731 1.413 6.923 1.021 5.716 0.550 7.397 3.200 6.598 0.606 tcdcclm 1587837600 234 0.552 6.198 1.348 7.631 6.192 2.476 5.200 6.223 7.778 5.419 7.932 7.512 1.328 5.750 1.828 5.674 0.430 7.843 6.656 7.368 2.258 tcdcclm 1587859200 240 0.193 5.932 0.805 7.620 6.761 2.857 5.387 5.490 7.905 5.823 7.646 7.860 0.887 6.696 2.207 5.257 0.623 7.901 4.229 7.198 1.997 partykit/inst/ULGcourse-2020/Data/GENS_00_innsbruck-flughafen.txt0000644000176200001440000016115614172227777024041 0ustar liggesusers# ASCII output from GENSvis.py # Contains interpolated values from the # GFS ensemble on 1.000000 x 1.000000 degrees # The data in here are for station # 11120: INNSBRUCK-FLUGHAFEN # Station position: 11.3553 47.2589 # Used grid point 1: 12.0000 48.0000 # Used grid point 2: 12.0000 47.0000 # Used grid point 3: 11.0000 47.0000 # Used grid point 4: 11.0000 48.0000 varname timestamp step mem0 mem1 mem2 mem3 mem4 mem5 mem6 mem7 mem8 mem9 mem10 mem11 mem12 mem13 mem14 mem15 mem16 mem17 mem18 mem19 mem20 tmax2m 1520920800 6 -2.996 -2.210 -2.945 -3.348 -2.930 -3.836 -2.478 -3.191 -2.966 -3.307 -3.746 -2.532 -2.507 -2.817 -4.753 -2.387 -3.917 -3.683 -3.149 -3.485 -2.983 tmax2m 1520942400 12 1.124 1.509 1.090 1.278 0.584 1.353 0.488 1.199 0.960 1.202 1.168 1.447 0.719 0.869 1.435 1.743 1.085 0.977 1.447 1.364 0.998 tmax2m 1520964000 18 1.342 1.602 1.256 1.544 0.924 1.413 0.687 1.514 1.200 1.328 1.377 1.482 1.002 1.280 1.453 1.770 1.334 1.104 1.530 1.566 1.299 tmax2m 1520985600 24 -2.741 -3.259 -2.764 -3.112 -2.748 -2.219 -2.686 -2.838 -2.403 -2.595 -2.572 -2.559 -2.708 -2.891 -2.828 -2.734 -2.637 -2.680 -2.188 -3.070 -2.694 tmax2m 1521007200 30 -5.489 -8.782 -5.415 -6.627 -5.155 -8.470 -4.776 -6.570 -6.689 -5.006 -7.354 -5.983 -4.814 -6.675 -4.145 -4.686 -4.420 -4.286 -4.151 -4.643 -6.681 tmax2m 1521028800 36 0.988 0.770 0.798 1.004 1.246 1.086 1.129 1.257 0.950 1.181 1.012 0.929 1.169 1.052 0.771 1.133 0.850 0.879 1.280 0.965 0.982 tmax2m 1521050400 42 1.336 1.203 1.121 1.370 1.370 1.487 1.618 1.405 1.381 1.443 1.407 1.314 1.462 1.556 1.147 1.446 1.146 1.249 1.537 1.344 1.489 tmax2m 1521072000 48 -3.042 -3.087 -2.733 -3.141 -2.871 -2.656 -2.315 -3.265 -2.983 -2.638 -2.986 -2.755 -2.558 -2.964 -2.484 -2.690 -2.578 -2.789 -2.239 -2.993 -2.866 tmax2m 1521093600 54 -3.844 -5.125 -4.033 -3.901 -3.631 -3.875 -3.485 -3.944 -4.384 -3.710 -3.566 -3.604 -3.654 -3.732 -4.462 -3.479 -4.035 -3.701 -3.343 -3.879 -3.665 tmax2m 1521115200 60 1.503 2.050 1.731 2.023 2.393 1.734 2.040 1.742 1.815 1.774 1.410 2.150 1.875 1.924 1.816 1.613 2.136 1.470 2.488 1.784 2.268 tmax2m 1521136800 66 1.971 2.212 2.041 2.167 2.413 1.988 2.393 2.183 1.857 2.317 1.823 2.180 2.276 2.249 1.680 2.160 2.160 1.831 2.566 2.052 2.500 tmax2m 1521158400 72 -0.654 -0.646 -0.729 -0.223 -0.325 -1.111 0.003 -1.018 -0.926 -0.644 -0.814 -0.170 -0.642 -0.681 -0.919 -0.446 -0.833 -0.731 -0.318 -0.853 -0.098 tmax2m 1521180000 78 -1.411 -1.044 -2.312 -0.962 -0.724 -2.092 -0.772 -2.345 -1.848 -2.173 -1.566 -0.847 -1.821 -1.917 -1.539 -0.193 -1.480 -1.588 -1.240 -2.102 -0.632 tmax2m 1521201600 84 1.466 1.259 1.507 1.992 2.459 1.669 1.650 0.866 2.082 2.434 1.027 0.346 1.858 1.428 0.913 2.267 1.471 2.293 1.209 2.361 1.898 tmax2m 1521223200 90 1.836 1.912 1.706 2.150 2.669 1.745 1.641 1.172 2.245 2.501 1.732 0.449 2.220 1.524 1.119 1.657 1.805 2.480 1.603 2.575 1.980 tmax2m 1521244800 96 -0.910 -1.480 -0.695 -1.109 -0.263 -1.228 -1.349 -2.081 -0.454 -0.147 -1.340 -1.866 -1.023 -1.370 -1.056 -1.271 -0.074 -1.087 -3.014 -0.860 -0.453 tmax2m 1521266400 102 -2.484 -2.726 -1.921 -2.750 -1.662 -2.815 -2.232 -3.411 -1.811 -1.803 -2.390 -3.805 -2.522 -2.412 -2.340 -3.998 -1.267 -2.071 -4.041 -2.442 -1.601 tmax2m 1521288000 108 -1.623 -2.472 -2.300 -0.321 -0.130 -0.961 1.074 0.104 -2.043 -1.619 -2.292 -1.585 -0.619 -2.034 -1.180 -0.845 0.412 0.107 0.036 -1.156 -1.250 tmax2m 1521309600 114 -1.784 -2.335 -3.332 -0.203 -0.203 -0.908 0.679 0.457 -3.018 -2.117 -2.174 -1.584 -0.659 -2.077 -1.198 -1.340 0.321 0.023 0.087 -1.222 -0.893 tmax2m 1521331200 120 -4.474 -4.033 -9.186 -2.714 -3.240 -3.164 -3.178 -3.931 -8.424 -5.216 -4.462 -4.203 -2.974 -4.783 -4.453 -4.303 -2.331 -2.577 -2.454 -3.326 -2.790 tmax2m 1521352800 126 -6.722 -4.539 -12.887 -4.831 -5.664 -5.168 -5.671 -5.703 -11.009 -6.977 -6.400 -6.284 -4.411 -7.133 -7.435 -6.209 -5.993 -4.440 -4.273 -5.033 -5.771 tmax2m 1521374400 132 -1.752 -2.176 -10.340 -1.917 -0.741 -2.891 0.501 -1.461 -5.011 -4.019 -4.709 -1.864 0.483 -2.613 -3.029 -0.417 -5.119 -0.683 -1.983 -3.058 -0.774 tmax2m 1521396000 138 -1.662 -2.080 -9.858 -2.083 -0.682 -2.806 0.834 -1.532 -4.364 -3.955 -5.064 -1.512 0.592 -2.455 -2.681 -0.086 -5.045 -0.021 -1.745 -3.038 -0.692 tmax2m 1521417600 144 -5.175 -5.540 -14.227 -5.385 -4.374 -5.139 -3.174 -4.094 -6.763 -7.049 -8.547 -6.344 -2.772 -5.206 -5.279 -3.134 -9.074 -3.993 -4.175 -6.356 -3.521 tmax2m 1521439200 150 -6.718 -6.595 -15.154 -6.253 -14.554 -5.930 -4.176 -6.379 -8.318 -14.936 -11.012 -7.788 -4.563 -7.100 -6.649 -4.836 -13.886 -4.813 -4.936 -8.700 -6.548 tmax2m 1521460800 156 -1.976 0.205 -7.522 -0.944 0.024 -0.234 -3.082 -4.532 -1.821 -4.197 -1.784 -2.939 0.183 0.014 0.166 0.917 -5.655 -0.215 -0.487 -3.437 -1.379 tmax2m 1521482400 162 -1.923 0.552 -6.887 -0.478 0.551 -0.636 -3.220 -4.297 -1.923 -4.019 -1.676 -2.904 0.201 0.555 0.641 1.393 -5.363 -0.259 1.444 -3.412 -1.154 tmax2m 1521504000 168 -4.706 -2.441 -10.614 -4.290 -4.705 -5.155 -7.024 -9.303 -5.065 -9.564 -4.558 -6.747 -2.870 -2.641 -3.184 -2.776 -10.494 -2.991 -1.307 -6.183 -3.730 tmax2m 1521525600 174 -7.362 -5.236 -14.634 -4.050 -5.125 -12.398 -9.326 -10.406 -7.523 -12.339 -7.639 -10.069 -5.458 -4.775 -5.066 -3.630 -17.744 -4.234 -4.000 -9.544 -9.101 tmax2m 1521547200 180 -4.846 -1.187 -3.214 0.707 -0.770 0.265 -6.901 -8.096 -2.416 -8.405 -0.058 -7.039 1.054 0.829 -1.989 2.724 -4.343 0.535 1.803 -3.422 -0.212 tmax2m 1521568800 186 -4.884 -1.285 -2.598 1.016 -1.031 0.608 -6.850 -7.880 -2.617 -7.857 0.076 -6.983 1.066 0.961 -1.954 3.190 -3.813 0.609 1.931 -3.509 -0.198 tmax2m 1521590400 192 -8.370 -3.322 -7.041 -1.802 -3.662 -2.670 -10.453 -10.034 -7.365 -12.544 -3.736 -9.332 -2.565 -3.621 -9.146 1.024 -8.199 -2.431 -0.779 -6.154 -4.466 tmax2m 1521612000 198 -10.714 -3.778 -19.649 -3.804 -6.600 -1.400 -15.868 -11.642 -10.160 -15.689 -7.015 -10.217 -3.531 -6.822 -19.072 1.676 -11.849 -7.382 -1.650 -7.462 -8.683 tmax2m 1521633600 204 -6.139 -0.753 -0.644 -2.285 -7.405 1.347 -6.055 -8.455 -8.454 0.582 -7.944 -5.518 0.371 -3.704 -2.700 4.691 -0.322 2.495 1.287 -1.620 -4.350 tmax2m 1521655200 210 -5.932 -0.700 -0.112 -2.166 -7.625 1.140 -6.099 -7.609 -8.084 0.924 -8.042 -5.404 0.350 -3.688 -2.444 4.874 -0.315 3.031 1.413 -1.567 -4.246 tmax2m 1521676800 216 -10.617 -3.911 -3.622 -5.495 -11.835 -0.959 -10.400 -15.081 -11.873 -2.642 -12.486 -8.945 -2.742 -10.823 -10.455 1.959 -4.473 -0.238 -1.619 -5.583 -11.188 tmax2m 1521698400 222 -17.233 -6.092 -11.664 -8.469 -15.354 -3.269 -12.761 -16.871 -13.229 -4.115 -16.722 -9.884 -5.239 -22.184 -15.440 0.432 -5.633 -1.938 -4.241 -6.627 -19.935 tmax2m 1521720000 228 -7.211 -4.095 -0.536 -5.908 -7.813 -5.953 -7.867 -2.676 -8.378 1.201 -8.829 -6.033 -3.658 -3.697 -3.119 2.313 -1.673 3.178 -1.800 -0.192 -3.619 tmax2m 1521741600 234 -6.833 -3.642 -0.238 -5.489 -7.508 -7.026 -7.837 -1.943 -8.132 1.041 -8.568 -5.889 -3.439 -3.270 -3.084 2.651 -1.059 3.076 -1.504 0.034 -2.315 tmax2m 1521763200 240 -12.328 -6.635 -6.141 -10.812 -10.989 -9.434 -13.044 -4.921 -11.679 -2.733 -14.420 -9.333 -6.130 -13.520 -7.465 0.371 -4.136 -0.473 -5.786 -4.472 -10.702 dd10m 1520920800 6 292.263 275.547 273.523 280.913 310.628 291.603 307.343 265.279 286.688 289.693 277.434 280.640 308.079 299.734 275.461 279.258 291.207 294.851 279.295 279.466 302.878 dd10m 1520942400 12 293.026 287.216 290.139 282.562 304.419 288.697 313.111 291.623 295.605 286.579 290.038 290.641 307.077 295.387 282.544 286.968 286.598 294.494 292.120 285.126 288.142 dd10m 1520964000 18 295.564 290.622 294.684 290.080 300.960 300.163 306.249 299.181 295.444 300.756 297.220 294.579 299.964 297.139 292.091 289.732 297.175 293.987 302.375 291.620 300.666 dd10m 1520985600 24 275.670 262.057 278.981 271.627 276.225 262.824 270.502 275.363 270.486 279.752 266.383 276.002 279.422 270.395 283.478 282.451 283.634 282.821 282.642 278.388 271.083 dd10m 1521007200 30 287.831 282.194 288.722 280.760 287.839 266.216 284.572 270.029 276.619 272.451 283.744 292.888 287.103 281.992 305.508 294.692 300.711 298.310 298.530 294.441 269.924 dd10m 1521028800 36 272.156 318.516 178.587 309.755 209.977 307.171 207.542 228.472 278.030 217.892 266.772 295.556 216.732 237.663 343.128 260.105 322.806 257.962 100.461 304.019 260.259 dd10m 1521050400 42 151.523 141.485 156.185 141.461 152.206 146.025 160.648 150.782 150.734 153.826 153.934 151.957 157.948 154.673 137.119 154.701 148.342 155.007 156.451 144.098 157.160 dd10m 1521072000 48 176.546 175.259 176.242 177.323 177.664 177.492 178.223 175.798 177.611 177.712 175.409 177.219 175.834 175.521 176.858 177.879 178.193 174.474 178.955 175.713 178.095 dd10m 1521093600 54 173.891 175.198 172.058 175.838 176.106 174.965 173.811 172.637 173.882 172.283 172.158 174.883 172.772 172.248 173.101 174.569 177.625 173.124 180.166 174.302 176.203 dd10m 1521115200 60 169.170 169.362 164.789 169.509 167.415 165.956 168.469 160.606 164.096 164.588 166.493 170.440 167.107 165.522 168.436 170.608 171.520 169.487 170.644 168.972 171.469 dd10m 1521136800 66 161.897 160.824 169.022 162.290 170.573 161.974 161.454 176.041 161.762 171.030 176.371 166.512 165.097 166.128 164.482 169.218 170.371 162.139 157.659 167.578 166.412 dd10m 1521158400 72 176.754 167.119 201.690 166.456 184.008 183.253 176.279 222.745 185.674 192.884 195.051 174.126 188.818 198.108 166.042 170.692 180.936 175.150 179.682 200.246 177.465 dd10m 1521180000 78 213.139 250.197 288.001 201.892 207.311 254.199 271.043 285.623 276.941 171.267 313.452 249.948 231.920 233.376 195.925 160.382 224.810 237.878 286.147 201.246 206.787 dd10m 1521201600 84 290.541 301.347 14.328 270.467 196.744 307.256 288.839 322.289 296.681 144.760 321.580 302.528 234.628 262.759 249.492 224.281 189.115 299.952 306.394 156.697 204.808 dd10m 1521223200 90 13.697 42.786 96.487 343.993 160.605 17.549 71.855 123.868 122.345 162.020 123.873 349.418 133.732 61.681 299.888 289.109 159.607 39.348 26.160 151.200 157.073 dd10m 1521244800 96 108.414 57.685 133.214 177.774 172.878 127.262 176.721 244.106 138.093 224.524 157.562 8.240 171.422 25.784 359.941 279.028 164.094 148.955 174.378 159.654 313.525 dd10m 1521266400 102 35.747 352.671 99.689 116.392 220.426 101.034 152.344 323.337 100.573 321.323 126.798 20.724 205.923 14.087 357.276 291.618 116.836 41.981 143.640 14.790 350.552 dd10m 1521288000 108 1.637 355.402 51.217 47.285 299.634 22.867 34.930 359.548 44.270 349.247 354.650 21.088 349.150 23.577 348.866 327.188 350.263 13.253 54.945 336.217 354.755 dd10m 1521309600 114 355.347 352.339 15.752 13.842 335.969 14.997 24.311 39.743 11.739 0.783 8.095 22.362 352.997 30.342 359.345 352.491 327.738 359.158 18.134 318.055 0.678 dd10m 1521331200 120 354.280 359.197 1.629 16.018 292.950 16.226 20.164 100.697 357.059 5.067 8.248 10.200 333.992 40.872 6.475 332.907 331.129 10.639 23.935 308.235 6.289 dd10m 1521352800 126 0.855 1.619 7.813 24.279 282.530 9.939 45.907 43.176 0.585 6.306 359.642 0.830 318.618 53.875 16.504 21.068 330.196 29.956 7.780 320.102 115.717 dd10m 1521374400 132 62.972 21.640 21.625 65.818 289.604 34.388 133.825 38.968 23.197 14.057 352.922 1.949 321.280 90.247 47.869 152.619 332.659 60.990 349.651 331.292 79.224 dd10m 1521396000 138 101.737 82.533 30.672 60.187 325.109 57.625 132.495 16.593 100.053 41.141 348.347 63.608 17.166 107.925 87.146 141.030 349.583 92.877 13.408 351.055 119.099 dd10m 1521417600 144 157.158 163.282 16.364 165.390 252.629 169.958 143.984 14.305 168.398 267.078 288.979 154.632 134.949 148.423 154.337 177.948 356.807 250.541 174.984 280.897 161.077 dd10m 1521439200 150 138.888 153.895 35.415 159.262 256.625 173.083 30.281 348.859 170.477 5.826 188.511 70.858 113.015 146.732 159.027 159.206 12.835 335.189 159.391 286.699 183.726 dd10m 1521460800 156 84.334 134.348 77.226 159.379 226.569 6.860 353.084 329.932 101.687 1.186 170.293 56.381 141.824 126.440 142.955 160.771 27.915 116.099 169.193 27.492 30.818 dd10m 1521482400 162 45.134 24.531 49.094 151.705 49.014 3.131 350.720 327.136 110.346 347.487 155.089 23.963 145.253 104.831 107.899 165.420 21.233 167.379 157.742 25.453 29.138 dd10m 1521504000 168 58.877 333.834 54.465 157.866 173.934 266.965 341.699 320.402 151.539 326.704 174.301 14.479 165.308 126.810 19.015 181.228 21.748 182.727 181.121 44.743 64.471 dd10m 1521525600 174 54.724 357.952 48.920 98.638 158.333 207.936 341.111 316.140 131.878 324.428 178.581 13.506 165.128 82.389 14.352 167.836 13.208 197.950 140.578 56.161 17.416 dd10m 1521547200 180 44.338 125.483 59.830 100.019 134.900 184.919 340.774 310.028 70.851 344.003 323.444 28.039 142.190 45.993 10.983 171.484 55.170 147.747 83.951 49.407 24.033 dd10m 1521568800 186 37.590 132.696 72.939 28.575 9.020 167.906 348.429 327.584 50.904 345.398 357.228 14.529 128.272 18.490 3.660 163.970 29.353 39.967 98.299 42.373 7.975 dd10m 1521590400 192 54.211 145.786 109.746 14.243 322.264 177.563 4.304 331.391 358.864 258.148 349.807 4.675 168.170 9.854 328.485 166.293 180.401 297.035 125.242 61.779 5.650 dd10m 1521612000 198 27.464 355.063 112.410 350.741 334.844 180.728 18.940 326.761 327.382 209.876 349.747 359.944 20.424 357.966 313.184 168.457 205.443 246.264 76.154 65.142 27.143 dd10m 1521633600 204 24.071 18.990 82.428 15.312 343.673 210.753 18.630 324.436 340.029 209.608 353.964 14.436 27.404 8.215 357.349 158.545 207.048 202.033 30.318 69.912 42.380 dd10m 1521655200 210 5.676 7.375 86.335 18.406 350.655 264.158 10.683 357.826 321.731 179.777 347.051 0.659 17.230 14.715 0.956 159.879 266.546 173.590 11.195 66.487 36.272 dd10m 1521676800 216 333.661 338.562 7.105 6.934 320.880 329.614 7.567 204.722 256.430 200.168 306.216 3.295 10.267 23.250 262.639 225.226 275.926 191.694 7.289 165.004 57.953 dd10m 1521698400 222 332.428 319.663 24.509 355.012 305.413 350.674 358.263 203.192 314.397 195.072 296.843 2.635 6.457 47.515 302.173 329.837 341.399 190.198 5.841 171.368 51.028 dd10m 1521720000 228 0.259 351.798 31.747 6.944 5.471 353.578 11.240 234.133 324.032 217.343 322.548 4.658 9.343 32.926 352.674 328.642 21.001 224.440 10.393 112.530 57.253 dd10m 1521741600 234 354.069 356.361 43.680 4.459 45.195 350.960 3.059 156.316 331.457 188.758 294.622 351.486 3.665 45.438 356.940 338.176 105.369 263.710 7.368 15.891 47.740 dd10m 1521763200 240 301.310 317.950 61.050 19.008 200.872 338.646 17.278 184.074 264.188 171.338 212.583 329.534 357.432 198.632 248.407 338.675 180.458 337.356 7.617 275.606 158.778 ff10m 1520920800 6 1.203 0.927 1.242 1.150 1.259 1.555 1.430 0.959 0.892 1.357 1.041 1.337 0.994 1.090 1.341 1.459 1.375 1.474 1.111 1.448 1.290 ff10m 1520942400 12 1.515 1.638 1.705 1.804 1.504 1.528 1.652 1.656 1.327 1.431 1.603 1.603 1.416 1.195 2.016 1.677 1.801 2.091 1.550 1.989 1.461 ff10m 1520964000 18 1.785 1.874 1.846 1.790 1.651 1.604 1.555 1.876 1.759 1.739 1.660 1.856 1.801 1.755 1.917 1.914 1.814 1.843 1.847 1.901 1.735 ff10m 1520985600 24 2.218 2.409 2.232 2.426 1.943 2.204 2.080 2.009 2.171 1.920 2.431 2.318 2.029 2.365 2.243 2.287 2.116 2.130 1.998 2.300 2.051 ff10m 1521007200 30 1.546 1.855 1.503 1.650 1.329 1.660 1.322 1.340 1.606 1.431 1.881 1.756 1.497 1.587 1.801 1.780 1.473 1.665 1.413 1.748 1.629 ff10m 1521028800 36 0.337 0.750 0.634 0.573 0.668 0.661 0.952 0.363 0.373 0.304 0.602 0.559 0.850 0.139 0.806 0.385 0.421 0.429 0.224 0.578 0.574 ff10m 1521050400 42 1.542 1.154 1.738 1.535 1.649 1.363 1.987 1.629 1.324 1.774 1.669 1.615 1.821 1.663 1.339 1.855 1.671 1.796 1.970 1.567 1.601 ff10m 1521072000 48 3.242 2.584 3.252 3.087 3.422 3.358 3.309 3.286 3.059 3.318 3.468 3.264 3.506 3.341 3.050 3.468 3.212 3.348 3.514 2.949 3.509 ff10m 1521093600 54 4.040 3.777 4.076 4.057 3.981 3.902 4.290 3.988 3.921 3.973 4.291 4.132 4.234 4.064 3.833 4.231 3.926 4.175 4.088 4.106 4.107 ff10m 1521115200 60 4.851 4.617 4.852 4.606 4.738 4.456 4.920 5.042 4.644 4.841 5.041 4.884 5.103 4.720 4.786 5.138 4.816 5.210 4.629 4.823 4.820 ff10m 1521136800 66 4.280 4.708 3.683 4.903 4.044 3.835 4.660 4.091 3.948 3.625 3.711 4.596 4.252 3.774 4.425 3.942 4.539 4.684 4.473 4.078 3.965 ff10m 1521158400 72 3.281 4.600 1.823 4.463 2.649 2.466 3.448 1.607 2.382 2.194 1.652 3.090 3.091 2.257 3.799 2.953 3.058 3.949 3.226 2.382 2.964 ff10m 1521180000 78 2.159 2.433 0.879 3.076 1.973 1.879 2.687 1.089 2.098 2.046 1.024 1.473 1.904 1.484 1.967 3.292 1.098 2.129 2.726 1.540 1.994 ff10m 1521201600 84 1.836 1.855 0.530 2.420 1.987 2.018 1.580 0.720 0.748 1.923 1.175 2.726 1.062 0.403 2.196 3.267 0.712 1.608 2.314 1.521 2.044 ff10m 1521223200 90 1.178 1.204 1.142 0.310 2.601 1.549 0.453 0.731 1.639 1.245 1.288 1.763 1.115 0.922 0.462 2.699 2.545 1.083 0.651 1.960 1.353 ff10m 1521244800 96 0.613 0.150 1.597 1.513 3.168 1.495 2.157 0.207 2.163 1.135 2.022 0.951 2.094 1.874 0.802 1.645 2.199 1.316 2.223 2.133 1.774 ff10m 1521266400 102 0.978 1.870 1.319 0.798 1.515 0.709 0.328 1.031 1.533 1.656 0.268 2.021 0.571 3.197 1.397 1.772 0.686 1.738 1.457 1.841 2.420 ff10m 1521288000 108 3.135 3.081 1.430 0.782 2.075 2.124 3.137 1.859 2.487 2.982 2.951 3.295 2.685 2.943 2.657 1.986 0.541 3.994 1.606 2.284 1.866 ff10m 1521309600 114 3.600 3.032 3.330 1.732 2.792 3.539 3.683 1.422 3.545 3.037 2.630 3.089 3.303 2.402 3.260 2.417 2.722 4.073 2.594 2.525 2.024 ff10m 1521331200 120 2.581 2.672 2.336 1.125 1.834 3.020 2.043 0.805 2.696 2.299 2.159 2.192 1.876 1.396 2.044 1.385 3.962 2.857 1.960 2.017 0.139 ff10m 1521352800 126 1.642 2.429 2.659 1.394 2.099 2.804 1.510 1.691 2.326 2.082 2.551 2.242 0.794 2.148 1.923 0.448 3.707 1.768 1.178 2.778 0.412 ff10m 1521374400 132 1.066 2.375 3.335 1.372 2.345 2.291 2.279 2.504 2.050 2.712 3.063 1.961 1.255 2.510 1.854 1.650 3.678 0.763 1.296 2.605 0.797 ff10m 1521396000 138 1.743 2.021 2.595 1.488 1.620 1.583 2.647 2.981 1.706 2.095 1.781 1.646 1.179 2.361 1.755 1.124 2.596 1.503 1.337 1.667 1.499 ff10m 1521417600 144 1.813 2.495 2.104 1.784 1.584 1.463 2.416 2.227 2.144 0.120 1.082 1.361 0.395 2.589 1.892 0.889 1.590 0.579 2.611 0.971 1.795 ff10m 1521439200 150 1.211 2.645 2.612 2.843 1.272 0.897 0.880 2.699 1.608 1.374 1.914 1.879 1.071 2.477 2.257 2.264 1.793 1.138 3.480 1.066 0.950 ff10m 1521460800 156 2.242 3.112 2.766 3.319 1.060 1.762 2.699 4.055 1.275 3.079 1.800 3.310 1.649 2.545 2.089 3.135 3.024 0.789 3.003 1.605 2.125 ff10m 1521482400 162 2.150 0.797 2.492 2.690 1.275 1.828 3.111 3.471 1.741 3.330 2.205 3.626 1.930 2.352 1.310 3.032 2.514 1.973 1.636 2.350 2.162 ff10m 1521504000 168 1.884 2.109 1.732 2.926 2.048 1.249 2.042 3.427 1.672 2.974 2.641 2.859 2.941 2.044 1.398 2.515 1.310 3.853 1.683 1.318 1.186 ff10m 1521525600 174 1.951 1.098 1.983 1.759 2.905 2.038 2.308 3.768 1.454 3.342 2.056 2.433 2.923 1.922 2.761 2.973 1.196 2.580 1.102 1.376 1.316 ff10m 1521547200 180 3.100 1.331 2.934 2.517 3.116 3.091 4.130 5.499 2.544 4.459 0.355 3.151 2.371 3.380 3.608 4.185 1.774 0.286 1.852 2.325 2.097 ff10m 1521568800 186 2.621 1.605 2.146 3.632 3.632 3.552 2.208 6.106 2.262 2.528 2.427 2.753 1.984 4.088 2.451 4.125 1.612 0.760 1.765 2.297 2.925 ff10m 1521590400 192 1.945 1.392 1.322 2.405 5.485 4.832 1.700 4.825 2.634 0.936 3.782 1.887 0.857 3.674 1.881 4.967 1.156 1.551 1.676 1.461 2.046 ff10m 1521612000 198 2.191 1.423 1.105 2.301 2.937 3.239 1.561 2.417 2.878 1.555 4.259 2.420 1.972 2.903 1.482 4.459 1.734 1.272 1.099 1.153 2.132 ff10m 1521633600 204 3.794 2.445 1.433 2.757 3.757 1.670 3.907 2.538 4.299 1.349 5.481 4.237 2.550 4.295 2.597 3.128 1.714 1.582 2.702 1.470 4.349 ff10m 1521655200 210 3.003 2.022 1.020 2.812 2.916 0.744 3.278 1.558 2.067 1.844 4.244 3.544 2.686 3.048 1.883 1.898 0.313 1.817 3.134 1.004 3.351 ff10m 1521676800 216 1.382 1.924 0.208 2.298 1.598 1.824 3.091 1.636 2.013 2.693 1.817 3.226 2.470 1.660 0.765 0.858 0.873 2.979 3.003 1.196 2.185 ff10m 1521698400 222 1.432 2.001 0.510 2.077 1.186 2.530 2.930 2.072 2.395 2.963 2.589 3.287 2.473 0.824 1.252 2.207 2.042 2.323 2.950 1.373 1.874 ff10m 1521720000 228 3.648 3.069 2.307 3.191 1.672 4.159 4.040 0.407 3.632 1.865 3.985 3.530 3.144 2.400 2.642 2.639 1.277 1.767 3.697 0.882 3.088 ff10m 1521741600 234 1.669 2.853 1.547 2.602 0.877 5.370 2.991 1.415 2.242 1.010 1.722 2.399 3.193 1.169 2.258 2.615 1.038 0.599 2.493 0.792 2.231 ff10m 1521763200 240 1.147 2.481 0.706 0.997 0.714 3.910 2.146 2.415 1.667 1.824 3.146 1.760 2.495 2.139 0.519 2.252 2.245 2.789 0.698 1.031 1.728 apcpsfc 1520920800 6 1.087 1.937 0.721 0.674 1.656 0.497 1.478 0.951 1.348 0.879 0.738 2.124 3.012 1.666 0.293 1.180 0.634 0.674 1.092 0.646 1.549 apcpsfc 1520942400 12 2.310 1.928 2.193 1.982 3.025 1.502 2.587 2.595 3.326 1.846 2.284 1.827 3.659 3.109 1.110 1.256 1.825 1.978 2.009 1.459 2.178 apcpsfc 1520964000 18 1.311 1.182 1.266 1.089 1.554 1.826 2.032 1.208 1.790 1.689 1.564 1.528 1.584 1.226 1.216 1.071 1.350 1.245 1.804 0.943 1.314 apcpsfc 1520985600 24 0.430 0.316 0.411 0.512 0.331 0.335 0.339 0.291 0.305 0.414 0.354 0.441 0.373 0.380 0.721 0.669 0.608 0.495 0.604 0.726 0.339 apcpsfc 1521007200 30 0.409 0.403 0.260 0.451 0.443 0.175 0.452 0.183 0.150 0.248 0.488 0.607 0.443 0.313 0.844 0.661 0.577 0.696 0.518 0.588 0.309 apcpsfc 1521028800 36 0.597 0.587 0.454 0.445 0.423 0.572 0.573 0.336 0.489 0.338 0.367 0.608 0.428 0.571 0.876 0.547 0.735 0.676 0.616 0.456 0.589 apcpsfc 1521050400 42 0.555 0.556 0.500 0.523 0.571 0.710 0.632 0.447 0.543 0.726 0.506 0.448 0.440 0.514 0.845 0.497 0.768 0.575 0.458 0.409 0.561 apcpsfc 1521072000 48 0.048 0.015 0.045 0.000 0.051 0.074 0.023 0.012 0.074 0.042 0.037 0.035 0.048 0.000 0.096 0.037 0.122 0.033 0.026 0.000 0.048 apcpsfc 1521093600 54 0.048 0.000 0.029 0.000 0.074 0.122 0.057 0.000 0.048 0.048 0.066 0.048 0.096 0.048 0.000 0.048 0.067 0.048 0.074 0.074 0.074 apcpsfc 1521115200 60 0.722 0.143 0.730 0.674 0.578 0.456 0.965 0.557 0.504 0.896 0.947 0.504 0.711 0.774 0.361 1.018 0.224 0.578 0.361 0.409 0.796 apcpsfc 1521136800 66 0.705 0.918 1.342 1.028 1.420 0.891 0.630 1.101 0.951 1.134 1.645 0.853 0.690 0.879 0.954 1.125 1.357 0.609 1.384 0.695 1.443 apcpsfc 1521158400 72 1.362 0.483 2.578 1.428 2.344 1.440 2.083 3.674 1.984 1.475 2.621 2.212 1.371 1.749 1.056 2.661 1.790 1.330 2.609 1.732 2.520 apcpsfc 1521180000 78 3.937 3.643 3.752 2.149 4.322 5.428 5.406 4.888 4.893 1.091 5.715 8.005 4.121 4.753 3.153 3.289 5.514 3.462 6.095 2.345 4.612 apcpsfc 1521201600 84 5.010 5.011 3.008 5.211 1.923 4.583 3.284 4.116 1.106 2.483 4.919 6.277 4.117 3.859 5.428 1.997 4.987 2.780 2.786 1.077 4.160 apcpsfc 1521223200 90 4.323 3.014 5.021 4.208 0.552 3.577 2.431 3.259 3.446 5.408 2.812 3.406 3.873 5.592 5.511 6.077 2.612 3.059 0.841 1.263 4.323 apcpsfc 1521244800 96 4.044 4.235 2.587 2.161 0.394 2.937 1.196 2.282 2.379 6.344 1.787 2.984 1.744 5.341 5.674 3.142 1.927 3.072 0.170 0.306 9.847 apcpsfc 1521266400 102 4.234 6.090 3.908 3.372 2.020 3.685 0.250 1.380 2.756 5.789 2.424 3.706 1.034 4.209 5.584 1.824 3.946 1.838 1.199 3.845 5.350 apcpsfc 1521288000 108 4.629 5.753 5.728 4.533 2.670 3.925 0.922 1.050 3.643 4.784 5.398 3.364 4.666 2.850 3.249 2.401 5.914 3.853 3.790 8.093 3.913 apcpsfc 1521309600 114 4.030 4.090 5.721 6.531 2.516 5.524 2.930 1.191 4.464 3.868 3.667 1.928 3.953 2.932 4.114 3.243 6.513 4.422 5.894 4.985 4.148 apcpsfc 1521331200 120 1.508 2.974 1.632 6.680 1.581 3.327 0.545 0.303 1.847 1.202 2.125 0.597 0.847 0.775 1.492 0.687 4.896 1.590 4.096 3.954 1.009 apcpsfc 1521352800 126 1.078 1.822 1.310 2.754 1.079 1.655 0.184 0.545 0.989 1.209 2.163 0.763 0.784 1.034 1.729 0.325 3.396 0.884 3.433 3.096 1.181 apcpsfc 1521374400 132 0.494 0.991 1.266 1.043 0.898 1.695 0.075 2.189 0.486 1.332 1.958 0.566 0.898 1.869 1.624 0.248 1.941 0.339 2.819 2.684 3.941 apcpsfc 1521396000 138 1.092 1.082 1.562 2.084 1.779 2.885 1.150 3.918 0.595 1.333 1.923 0.552 5.387 2.725 1.439 3.587 1.138 0.621 3.866 2.486 3.962 apcpsfc 1521417600 144 0.939 0.191 1.934 0.715 0.844 3.024 0.992 1.796 0.308 0.117 0.263 0.468 5.730 0.318 0.397 4.425 0.144 0.913 0.634 0.977 1.015 apcpsfc 1521439200 150 0.459 0.045 3.110 0.223 0.000 2.387 1.560 0.989 0.096 0.043 0.000 0.409 3.678 0.053 0.027 1.142 0.086 0.886 0.435 1.142 0.330 apcpsfc 1521460800 156 0.595 0.822 1.590 0.148 0.000 0.912 4.105 0.723 0.430 0.368 0.139 1.076 3.029 0.222 0.157 0.416 0.308 1.460 4.934 2.054 1.481 apcpsfc 1521482400 162 2.724 5.914 1.371 0.287 1.886 1.330 4.293 0.889 2.657 1.184 1.178 2.737 4.352 1.652 1.093 0.905 0.499 4.085 1.678 3.504 2.704 apcpsfc 1521504000 168 1.372 4.392 0.148 0.222 2.197 0.282 3.061 1.654 0.908 0.244 0.191 1.836 0.509 0.175 0.371 1.825 0.109 0.741 1.386 1.657 1.665 apcpsfc 1521525600 174 1.532 0.918 0.000 2.749 0.407 0.000 2.212 1.606 0.112 0.187 0.096 0.939 0.948 0.218 0.270 0.389 0.000 1.222 0.860 0.674 0.201 apcpsfc 1521547200 180 2.603 2.080 0.033 3.134 0.366 0.048 1.498 2.046 0.631 0.544 0.648 2.383 0.822 0.614 0.222 0.639 0.008 2.443 0.552 0.853 0.492 apcpsfc 1521568800 186 3.040 3.578 0.217 3.481 4.647 1.385 0.999 3.489 3.813 0.418 2.530 2.539 2.096 1.241 0.170 0.658 0.360 3.261 2.299 2.251 0.980 apcpsfc 1521590400 192 1.382 2.172 0.000 4.467 6.830 0.368 0.307 2.075 3.552 0.074 1.883 1.262 0.717 0.619 0.143 0.965 0.139 0.837 1.530 1.450 0.318 apcpsfc 1521612000 198 0.916 0.806 0.000 3.535 0.788 4.836 0.126 0.805 3.345 0.000 1.363 0.814 0.499 0.165 0.000 0.262 0.000 0.026 1.681 1.233 0.122 apcpsfc 1521633600 204 0.753 0.839 0.000 2.863 1.388 9.222 0.458 0.355 1.049 0.000 1.262 0.887 1.087 0.000 0.000 0.684 0.121 0.033 0.970 0.870 0.040 apcpsfc 1521655200 210 0.932 3.934 0.297 3.922 1.642 9.206 0.703 0.243 0.771 0.641 0.910 0.825 2.036 0.026 0.122 2.172 2.488 0.371 1.874 2.938 0.038 apcpsfc 1521676800 216 0.153 4.907 0.180 3.096 0.821 7.811 0.474 0.000 0.075 0.808 0.191 1.056 2.273 0.026 0.000 2.336 2.682 0.960 1.631 1.903 0.026 apcpsfc 1521698400 222 0.026 3.258 0.023 2.093 0.464 7.280 0.416 0.000 0.621 0.351 0.293 1.182 2.597 0.000 0.043 3.281 1.668 1.572 1.426 0.560 0.016 apcpsfc 1521720000 228 0.100 2.924 0.000 1.968 0.412 6.287 0.498 0.143 1.309 1.344 1.078 0.726 2.819 0.000 0.798 2.531 0.554 0.679 1.373 0.465 0.000 apcpsfc 1521741600 234 0.249 3.724 0.074 1.805 1.776 3.461 0.454 1.646 1.151 5.959 0.424 0.757 3.238 0.000 0.934 1.994 0.662 3.978 1.063 2.365 0.025 apcpsfc 1521763200 240 0.000 2.582 0.026 0.894 2.095 1.938 0.238 0.682 0.187 4.141 0.017 0.410 1.969 0.000 0.127 1.842 0.624 8.801 0.127 0.916 0.000 tmp2m 1520920800 6 -4.168 -3.406 -5.327 -5.956 -3.309 -4.404 -3.582 -5.908 -4.154 -4.831 -7.271 -3.265 -2.992 -3.455 -7.605 -4.071 -5.724 -4.711 -4.971 -6.015 -3.694 tmp2m 1520942400 12 1.076 1.509 1.090 1.278 0.536 1.353 0.488 1.199 0.960 1.154 1.111 1.447 0.719 0.869 1.409 1.743 1.085 0.950 1.390 1.364 0.998 tmp2m 1520964000 18 -2.681 -3.295 -2.748 -2.978 -2.849 -2.095 -2.652 -2.812 -2.360 -2.573 -2.663 -2.507 -2.686 -2.858 -2.838 -2.722 -2.558 -2.711 -2.193 -3.049 -2.634 tmp2m 1520985600 24 -7.363 -9.517 -7.489 -7.924 -8.812 -9.229 -7.458 -9.173 -8.540 -7.888 -9.273 -7.311 -7.502 -7.925 -4.662 -5.066 -6.116 -5.952 -5.414 -5.019 -8.246 tmp2m 1521007200 30 -5.859 -10.518 -5.988 -9.042 -5.446 -10.421 -5.037 -7.783 -8.158 -5.550 -7.989 -6.685 -5.197 -8.890 -4.452 -5.037 -4.688 -4.614 -4.417 -4.959 -7.847 tmp2m 1521028800 36 0.988 0.770 0.734 1.004 1.246 1.086 1.103 1.257 0.950 1.181 1.012 0.929 1.121 1.052 0.771 1.133 0.850 0.879 1.233 0.965 0.982 tmp2m 1521050400 42 -3.897 -4.904 -2.982 -4.972 -3.180 -3.116 -2.342 -3.886 -3.818 -2.902 -3.366 -3.578 -2.807 -3.546 -2.549 -2.961 -3.470 -3.058 -2.615 -5.162 -3.521 tmp2m 1521072000 48 -4.644 -6.052 -5.089 -5.205 -4.353 -4.353 -5.344 -5.310 -4.760 -4.379 -4.812 -4.677 -4.789 -4.825 -4.805 -4.179 -4.536 -4.772 -4.160 -5.267 -4.917 tmp2m 1521093600 54 -4.201 -5.330 -4.298 -4.098 -3.902 -4.122 -3.788 -4.131 -4.607 -4.077 -3.743 -3.907 -3.859 -3.971 -4.850 -3.676 -4.440 -3.967 -3.744 -4.109 -3.786 tmp2m 1521115200 60 1.503 2.024 1.705 2.023 2.393 1.708 2.040 1.742 1.768 1.774 1.410 2.075 1.875 1.924 1.694 1.586 2.110 1.470 2.440 1.758 2.220 tmp2m 1521136800 66 -0.706 -0.802 -0.715 -0.455 -0.454 -1.123 -0.236 -0.983 -0.943 -0.671 -0.790 -0.433 -0.675 -0.672 -1.071 -0.560 -0.819 -0.814 -0.498 -0.808 -0.385 tmp2m 1521158400 72 -1.642 -1.098 -2.546 -0.957 -1.084 -2.204 -0.845 -2.609 -2.286 -2.531 -1.801 -0.968 -1.920 -2.416 -1.628 -1.049 -1.554 -1.656 -1.338 -2.322 -1.064 tmp2m 1521180000 78 -1.594 -1.640 -2.709 -1.455 -1.241 -2.268 -1.511 -2.874 -1.994 -2.769 -2.006 -1.222 -2.235 -2.127 -2.513 -0.469 -1.790 -2.091 -1.749 -3.253 -0.942 tmp2m 1521201600 84 1.466 1.233 1.507 1.966 2.385 1.669 1.640 0.866 2.082 2.434 1.000 0.241 1.858 1.428 0.913 1.819 1.471 2.293 1.209 2.361 1.898 tmp2m 1521223200 90 -0.891 -1.618 -0.903 -1.159 -0.270 -1.186 -1.541 -2.520 -0.470 -0.117 -1.349 -1.778 -1.092 -1.372 -1.226 -1.240 -0.163 -1.081 -4.331 -0.795 -0.457 tmp2m 1521244800 96 -2.923 -2.838 -1.993 -2.789 -1.771 -3.108 -2.310 -5.730 -1.838 -1.713 -2.309 -4.329 -2.612 -2.548 -2.516 -3.988 -1.300 -2.512 -5.240 -2.744 -1.692 tmp2m 1521266400 102 -3.423 -4.007 -3.195 -3.976 -3.111 -3.691 -8.833 -5.086 -3.922 -3.032 -3.928 -4.377 -4.984 -3.901 -3.456 -5.630 -2.555 -2.916 -4.351 -2.698 -3.105 tmp2m 1521288000 108 -1.693 -2.472 -3.167 -0.338 -0.178 -1.044 0.794 0.104 -2.854 -1.977 -2.488 -1.619 -0.645 -2.115 -1.211 -1.255 0.338 -0.034 0.036 -1.256 -1.250 tmp2m 1521309600 114 -4.422 -3.973 -9.112 -2.688 -3.238 -3.046 -3.100 -3.879 -8.076 -4.886 -4.545 -4.067 -2.823 -4.665 -4.231 -4.254 -2.214 -2.515 -2.380 -3.226 -2.986 tmp2m 1521331200 120 -6.629 -4.529 -12.756 -4.845 -6.015 -5.052 -5.645 -12.894 -11.032 -7.018 -6.563 -6.494 -4.885 -7.676 -7.323 -6.431 -5.993 -4.279 -4.299 -4.950 -6.021 tmp2m 1521352800 126 -7.999 -5.730 -14.970 -6.956 -6.421 -6.630 -8.133 -5.881 -12.067 -8.185 -7.771 -7.105 -5.256 -7.641 -8.099 -9.206 -8.508 -6.253 -5.573 -5.729 -6.284 tmp2m 1521374400 132 -1.752 -2.176 -10.340 -1.943 -0.722 -2.891 0.501 -1.496 -5.011 -4.019 -4.709 -1.864 0.387 -2.687 -3.029 -0.417 -5.119 -0.683 -1.983 -3.094 -0.800 tmp2m 1521396000 138 -6.847 -6.405 -14.124 -5.350 -4.310 -5.101 -3.333 -3.863 -9.558 -6.875 -9.141 -8.200 -2.720 -5.121 -6.229 -3.377 -8.935 -6.264 -4.005 -6.285 -3.360 tmp2m 1521417600 144 -6.778 -6.976 -16.751 -6.734 -13.549 -6.094 -4.298 -6.426 -8.157 -18.031 -11.767 -8.582 -4.606 -7.118 -7.044 -4.950 -15.412 -5.663 -7.352 -12.184 -6.527 tmp2m 1521439200 150 -8.919 -7.685 -15.154 -6.335 -16.095 -6.395 -5.695 -8.183 -9.963 -15.771 -14.506 -8.300 -4.832 -7.857 -6.802 -6.561 -14.065 -6.357 -4.988 -9.025 -8.121 tmp2m 1521460800 156 -1.949 0.205 -7.522 -0.957 -0.030 -0.726 -3.311 -4.532 -1.848 -4.197 -1.800 -2.939 0.183 0.014 0.166 0.917 -5.655 -0.442 -0.487 -3.550 -1.453 tmp2m 1521482400 162 -4.702 -2.448 -10.793 -4.405 -4.975 -5.850 -6.871 -9.032 -4.986 -9.201 -4.597 -6.616 -2.734 -2.481 -3.141 -2.727 -10.858 -2.979 -1.377 -6.109 -3.739 tmp2m 1521504000 168 -7.445 -5.162 -17.629 -5.527 -5.341 -13.808 -9.369 -10.319 -7.654 -12.938 -8.229 -9.850 -5.985 -4.979 -9.784 -3.628 -19.421 -4.953 -3.801 -9.609 -8.601 tmp2m 1521525600 174 -8.401 -7.222 -15.258 -4.100 -6.566 -13.245 -10.592 -11.041 -9.945 -15.186 -8.159 -11.394 -5.623 -6.053 -6.519 -4.672 -19.196 -4.562 -5.853 -10.918 -11.471 tmp2m 1521547200 180 -4.941 -1.213 -3.214 0.707 -0.770 0.265 -6.901 -8.093 -2.416 -8.405 -0.074 -7.039 1.027 0.803 -1.989 2.724 -4.343 0.509 1.803 -3.422 -0.260 tmp2m 1521568800 186 -8.270 -3.222 -6.668 -1.733 -3.698 -3.267 -10.501 -9.910 -7.118 -13.310 -3.662 -9.446 -2.499 -3.360 -9.152 0.066 -8.620 -2.518 -0.886 -6.035 -4.430 tmp2m 1521590400 192 -10.994 -5.085 -22.521 -4.032 -7.361 -3.195 -13.631 -12.315 -10.145 -21.993 -7.638 -11.534 -8.631 -7.135 -12.535 0.488 -17.277 -5.954 -3.125 -8.783 -9.771 tmp2m 1521612000 198 -11.907 -6.930 -19.967 -5.436 -10.032 -1.448 -16.301 -14.406 -12.409 -16.038 -10.475 -10.745 -3.581 -10.678 -19.280 1.398 -12.943 -12.344 -3.171 -9.190 -12.718 tmp2m 1521633600 204 -6.139 -0.753 -0.628 -2.320 -7.579 1.329 -6.055 -8.477 -8.454 0.566 -7.939 -5.565 0.332 -3.704 -2.748 4.569 -0.322 2.460 1.261 -1.668 -4.350 tmp2m 1521655200 210 -10.643 -4.249 -3.875 -5.486 -11.860 -0.825 -10.228 -14.974 -11.671 -3.527 -12.328 -9.050 -2.736 -10.809 -10.738 2.068 -4.246 -0.495 -1.705 -5.245 -10.854 tmp2m 1521676800 216 -17.189 -5.998 -13.423 -8.576 -15.370 -3.368 -12.844 -22.132 -20.910 -4.483 -18.506 -10.141 -5.124 -23.073 -21.660 -0.136 -6.728 -2.002 -4.250 -6.793 -21.646 tmp2m 1521698400 222 -18.369 -7.380 -14.446 -10.369 -20.354 -6.617 -14.379 -17.706 -13.407 -5.656 -17.262 -11.026 -6.986 -25.030 -15.493 0.118 -7.406 -2.893 -5.799 -8.322 -21.774 tmp2m 1521720000 228 -7.211 -4.095 -0.536 -5.908 -7.813 -7.153 -7.867 -2.708 -8.405 1.144 -8.829 -5.985 -3.658 -3.697 -3.119 2.265 -1.673 3.062 -1.800 -0.192 -3.619 tmp2m 1521741600 234 -12.685 -6.631 -6.821 -10.355 -12.105 -9.301 -13.703 -5.562 -11.705 -3.230 -14.160 -9.508 -6.074 -17.536 -7.587 0.520 -5.132 -0.468 -5.469 -4.265 -11.009 tmp2m 1521763200 240 -23.396 -9.969 -18.727 -13.869 -14.306 -12.414 -15.749 -7.307 -22.976 -3.821 -16.608 -10.838 -8.251 -14.853 -20.775 -1.598 -4.910 -2.609 -17.594 -10.824 -14.842 tcdcclm 1520920800 6 7.344 7.047 6.963 7.112 7.520 7.287 7.522 7.050 7.022 7.215 7.164 7.627 7.451 7.156 6.731 7.212 7.250 7.341 7.820 7.457 7.628 tcdcclm 1520942400 12 6.883 6.834 7.142 6.949 7.198 6.925 6.777 6.894 7.385 6.862 6.677 6.943 7.284 7.275 6.439 6.839 6.722 6.559 7.046 6.872 6.582 tcdcclm 1520964000 18 7.313 6.977 7.351 7.197 7.003 7.545 7.173 7.012 7.498 7.202 7.072 7.539 7.312 7.344 7.157 7.261 7.297 7.332 7.322 7.198 7.244 tcdcclm 1520985600 24 6.408 5.030 6.175 6.564 5.420 5.467 7.136 5.290 6.463 5.823 5.604 7.142 6.524 5.890 7.293 7.566 6.883 7.074 7.093 7.115 6.651 tcdcclm 1521007200 30 6.807 3.033 6.044 6.841 6.116 5.209 6.798 5.450 5.555 5.895 6.257 7.197 6.707 6.255 7.777 7.447 7.341 7.204 7.401 7.238 6.171 tcdcclm 1521028800 36 7.389 6.173 7.099 6.757 6.675 6.474 7.130 6.698 7.214 6.255 6.887 7.225 7.061 7.179 7.380 7.276 7.432 7.155 7.378 7.333 7.292 tcdcclm 1521050400 42 4.761 5.886 5.256 5.518 5.360 5.493 4.831 5.009 5.242 5.428 5.163 5.202 5.046 4.711 6.002 5.128 5.870 5.050 5.232 5.155 4.628 tcdcclm 1521072000 48 3.923 2.347 4.208 3.426 4.097 4.259 3.583 3.183 4.075 4.030 3.460 4.044 3.971 3.745 4.226 3.950 4.111 4.067 4.155 2.671 4.028 tcdcclm 1521093600 54 4.979 2.715 4.513 4.819 5.919 5.451 4.690 4.730 4.563 4.770 5.543 4.722 4.995 5.695 4.040 5.464 5.098 5.399 5.283 3.775 6.026 tcdcclm 1521115200 60 6.834 6.479 7.364 7.321 7.260 7.088 7.464 6.900 6.773 7.229 7.311 6.867 6.998 7.214 5.890 7.203 6.472 7.324 6.635 6.508 6.958 tcdcclm 1521136800 66 7.629 7.259 7.862 7.615 7.825 7.389 7.591 7.823 7.797 7.777 7.862 7.776 7.823 7.664 7.874 7.615 7.729 7.690 7.639 7.755 7.825 tcdcclm 1521158400 72 7.333 7.766 7.323 7.938 7.367 7.487 7.826 7.631 7.573 7.117 7.829 7.305 7.208 7.487 7.549 7.238 7.795 7.067 7.853 7.512 6.811 tcdcclm 1521180000 78 7.193 7.391 7.112 6.553 7.434 7.774 7.299 7.848 7.717 6.689 7.905 7.944 7.134 7.443 7.815 7.840 7.807 6.784 7.635 6.884 7.636 tcdcclm 1521201600 84 7.554 7.673 7.427 7.626 6.680 7.671 7.376 7.812 7.293 7.296 7.861 7.851 7.469 7.878 7.811 7.115 7.908 6.762 7.501 5.770 7.793 tcdcclm 1521223200 90 7.460 7.306 7.765 6.735 6.442 7.638 7.046 7.166 7.571 7.908 6.568 7.734 6.914 7.629 7.762 7.813 7.660 6.387 5.452 6.782 7.596 tcdcclm 1521244800 96 7.786 7.936 7.768 6.448 7.513 7.545 7.909 7.375 7.941 7.844 7.504 7.777 7.208 7.750 7.638 7.747 7.849 7.316 4.864 7.655 7.951 tcdcclm 1521266400 102 7.886 7.886 7.842 7.439 7.771 7.920 7.194 6.711 7.821 7.920 7.858 7.873 6.926 7.894 7.829 7.710 7.913 7.899 6.884 7.765 7.919 tcdcclm 1521288000 108 7.885 7.898 7.892 7.783 7.657 7.912 6.319 7.534 7.753 7.867 7.819 7.899 7.753 7.809 7.874 7.401 7.892 7.732 7.816 7.871 7.920 tcdcclm 1521309600 114 7.846 7.847 7.885 7.727 7.354 7.912 7.901 6.797 7.845 7.913 7.737 7.843 7.920 7.879 7.811 7.686 7.847 7.884 7.920 7.855 7.933 tcdcclm 1521331200 120 7.951 7.899 7.802 7.843 6.392 7.941 7.987 6.189 7.941 7.892 7.818 7.205 7.893 7.884 7.807 7.776 7.895 7.887 7.948 7.899 7.531 tcdcclm 1521352800 126 7.719 7.905 7.883 7.858 7.330 7.907 7.250 6.277 7.962 7.877 7.850 7.557 7.446 7.704 7.868 7.109 7.920 7.800 7.848 7.852 7.191 tcdcclm 1521374400 132 7.167 7.468 7.352 7.581 6.710 7.805 2.927 7.515 7.794 7.845 7.821 6.910 6.948 7.297 7.914 5.487 7.822 7.110 7.713 7.762 7.814 tcdcclm 1521396000 138 7.006 6.911 7.385 7.754 6.655 7.891 5.435 7.719 6.605 7.871 7.701 6.293 7.480 7.233 7.475 6.966 7.659 5.131 7.679 7.586 7.147 tcdcclm 1521417600 144 6.824 5.514 7.626 5.622 4.242 7.436 7.794 7.797 6.823 6.503 6.660 6.349 7.770 7.259 6.526 7.650 7.228 6.998 5.353 6.846 6.596 tcdcclm 1521439200 150 7.007 6.352 7.789 5.898 0.615 7.306 7.920 7.688 5.957 5.658 2.376 6.524 7.619 7.238 7.052 5.849 7.096 7.248 6.043 7.603 6.542 tcdcclm 1521460800 156 7.550 6.059 7.735 7.433 3.291 6.072 7.920 7.028 6.319 6.808 3.559 7.292 6.873 7.373 7.161 5.892 7.068 7.475 7.938 7.783 7.086 tcdcclm 1521482400 162 7.744 7.936 7.218 6.697 6.186 6.018 7.827 6.984 7.283 7.222 6.395 7.966 7.021 7.428 6.044 7.218 7.209 6.983 6.605 7.692 7.472 tcdcclm 1521504000 168 7.781 7.920 6.851 6.923 6.695 4.695 7.862 7.693 7.029 5.353 5.361 7.864 6.696 6.889 4.719 7.899 6.947 6.356 5.750 7.256 6.684 tcdcclm 1521525600 174 7.773 7.628 7.065 7.885 6.645 4.281 7.843 7.785 6.679 4.208 6.672 7.772 7.208 7.739 5.393 6.276 5.550 7.742 6.753 6.144 5.534 tcdcclm 1521547200 180 7.762 7.626 6.433 7.920 7.782 2.681 7.892 7.837 7.285 6.263 6.502 7.892 6.324 7.255 4.562 6.989 3.989 7.905 7.344 6.406 5.323 tcdcclm 1521568800 186 7.821 7.728 7.385 7.941 7.958 6.674 7.618 7.719 7.730 5.708 7.881 7.832 6.211 7.078 3.336 7.649 7.099 7.765 7.912 7.333 5.713 tcdcclm 1521590400 192 7.435 7.457 2.260 7.912 7.920 6.352 6.928 7.821 7.859 3.036 7.783 7.744 6.044 7.003 4.746 7.938 6.757 7.825 7.680 7.626 5.397 tcdcclm 1521612000 198 7.499 6.467 0.189 8.000 7.280 7.513 5.143 7.147 7.985 1.445 7.541 7.860 7.008 4.285 0.173 7.728 4.784 3.939 7.775 7.345 4.828 tcdcclm 1521633600 204 7.706 6.789 0.227 8.000 7.506 7.857 6.566 4.524 7.727 2.517 7.926 7.112 7.841 0.844 0.604 7.715 4.787 1.557 7.484 6.941 2.367 tcdcclm 1521655200 210 7.082 7.641 3.826 8.000 7.446 7.907 6.997 4.480 7.381 6.414 7.415 7.545 7.771 2.133 2.600 7.731 7.777 6.607 7.872 6.886 0.971 tcdcclm 1521676800 216 6.258 7.701 4.827 7.993 6.492 7.808 6.734 2.443 2.785 6.763 4.871 7.713 7.734 2.696 0.822 7.767 7.666 7.458 7.928 6.013 1.670 tcdcclm 1521698400 222 5.572 7.839 2.820 7.893 6.873 7.793 6.453 0.647 3.968 6.407 4.390 7.790 7.666 0.636 3.294 7.839 7.345 6.747 7.933 5.559 1.492 tcdcclm 1521720000 228 3.313 7.726 1.200 7.725 4.927 7.893 6.274 2.819 7.595 6.308 6.981 7.602 7.784 1.380 6.518 7.728 6.031 5.175 7.788 4.973 0.561 tcdcclm 1521741600 234 4.973 7.777 2.520 6.979 6.676 7.817 5.830 6.640 6.950 7.430 5.329 7.819 7.686 3.257 6.268 7.541 6.346 7.103 7.697 6.481 0.826 tcdcclm 1521763200 240 1.386 7.893 2.884 6.743 6.829 7.908 5.403 6.569 4.823 6.869 3.758 7.634 7.709 4.501 2.807 7.519 6.549 7.865 5.480 6.101 0.457 partykit/inst/ULGcourse-2020/Data/GENS_00_innsbruck_20200414.dat0000644000176200001440000016114414172227777023006 0ustar liggesusers# ASCII output from GENSvis.py # Contains interpolated values from the # GFS ensemble on 1.000000 x 1.000000 degrees # The data in here are for station # 11120: INNSBRUCK # Station position: 11.3553 47.2589 # Used grid point 1: 12.0000 48.0000 # Used grid point 2: 12.0000 47.0000 # Used grid point 3: 11.0000 47.0000 # Used grid point 4: 11.0000 48.0000 varname timestamp step mem0 mem1 mem2 mem3 mem4 mem5 mem6 mem7 mem8 mem9 mem10 mem11 mem12 mem13 mem14 mem15 mem16 mem17 mem18 mem19 mem20 tmax2m 1586844000 6 273.273 273.141 273.196 273.094 272.980 273.326 273.318 273.136 273.335 272.944 273.389 273.461 273.508 272.992 273.133 273.395 273.455 273.576 273.381 273.609 273.441 tmax2m 1586865600 12 273.300 273.389 273.198 273.092 273.444 272.758 272.570 273.619 273.787 272.935 273.414 273.206 273.626 274.144 272.608 273.545 273.205 273.273 273.109 273.161 273.787 tmax2m 1586887200 18 273.633 273.637 273.594 273.459 273.858 273.153 272.927 273.876 273.989 273.310 273.672 273.520 273.993 274.432 273.114 273.950 273.507 273.740 273.375 273.554 274.089 tmax2m 1586908800 24 267.711 267.994 267.913 267.585 268.116 267.564 267.589 267.904 268.018 267.263 268.113 268.262 268.052 268.329 267.757 268.097 268.170 267.816 267.748 267.935 268.169 tmax2m 1586930400 30 270.247 270.046 270.264 270.349 270.377 270.085 269.502 270.118 270.629 270.129 270.159 270.005 270.587 270.941 270.081 270.386 270.071 270.587 269.943 270.075 270.725 tmax2m 1586952000 36 283.536 282.595 280.881 282.802 283.440 283.205 281.532 282.371 283.747 284.037 282.390 282.183 281.154 282.724 282.080 282.794 282.421 284.124 282.557 283.302 283.049 tmax2m 1586973600 42 284.433 283.495 284.696 283.195 284.618 284.101 282.360 282.747 284.634 284.830 283.502 282.867 285.055 285.773 283.034 283.454 283.143 284.987 283.741 283.637 284.993 tmax2m 1586995200 48 274.371 274.529 274.338 274.628 274.487 274.398 273.387 274.192 274.525 274.044 274.068 274.312 274.621 274.795 274.006 274.372 274.303 274.587 274.110 274.441 274.652 tmax2m 1587016800 54 275.898 275.915 275.916 275.771 275.917 275.645 275.448 275.821 276.082 275.921 275.767 275.780 275.960 276.132 275.791 275.916 275.693 276.030 275.847 275.980 275.936 tmax2m 1587038400 60 286.242 286.636 285.841 286.513 285.972 286.375 285.872 285.879 286.525 286.369 286.343 286.241 286.181 286.718 285.812 286.072 286.208 286.447 286.331 286.744 286.376 tmax2m 1587060000 66 286.096 286.514 285.422 286.693 286.500 286.750 285.351 284.951 286.497 286.417 286.190 285.748 286.084 286.798 284.786 286.266 285.386 286.383 285.492 286.627 286.526 tmax2m 1587081600 72 277.289 276.929 277.011 276.976 277.486 276.616 276.807 276.781 277.164 276.884 276.585 277.414 276.927 277.593 277.717 277.609 277.460 277.379 277.270 277.599 276.344 tmax2m 1587103200 78 278.144 278.280 277.853 278.242 277.909 278.268 277.696 277.806 278.367 278.363 278.428 277.894 278.026 278.265 277.649 278.328 278.128 278.057 278.152 278.194 278.334 tmax2m 1587124800 84 288.522 289.047 286.259 288.597 286.135 288.292 285.631 287.987 288.684 288.895 288.336 288.139 288.417 288.098 288.517 288.457 288.683 287.316 287.956 288.744 288.954 tmax2m 1587146400 90 288.056 289.118 286.219 287.897 286.139 287.719 285.364 287.775 288.362 288.412 288.031 288.075 287.662 287.608 288.426 288.044 288.249 287.279 287.292 288.679 288.813 tmax2m 1587168000 96 278.658 278.527 278.189 278.275 277.177 279.375 277.076 279.290 279.866 278.467 280.231 280.116 279.341 279.804 279.574 278.372 278.678 278.098 278.641 278.739 279.639 tmax2m 1587189600 102 279.659 279.567 279.279 279.418 278.789 278.648 278.880 278.872 278.925 279.206 278.686 278.672 279.145 279.028 279.315 279.675 279.449 279.540 278.752 279.715 278.753 tmax2m 1587211200 108 286.500 288.360 285.963 287.605 288.185 283.917 286.865 285.134 286.371 287.975 287.074 283.097 285.155 285.468 287.592 288.250 287.688 289.120 285.930 287.117 284.544 tmax2m 1587232800 114 286.047 287.502 285.828 287.382 287.855 283.679 285.186 284.298 285.293 287.016 285.702 282.809 284.824 284.716 286.214 287.925 286.327 287.760 285.916 286.019 284.186 tmax2m 1587254400 120 280.561 280.126 280.759 280.983 281.574 279.532 280.352 279.020 280.195 280.466 280.489 278.963 279.678 280.047 280.357 282.104 280.229 281.375 279.046 280.551 280.044 tmax2m 1587276000 126 279.142 279.326 279.439 279.446 279.926 278.427 278.528 279.281 278.838 279.822 279.016 278.732 279.114 279.184 279.686 279.732 279.406 279.971 279.555 279.680 278.675 tmax2m 1587297600 132 282.932 283.332 284.718 284.999 282.428 282.605 284.777 284.876 284.142 284.429 285.611 284.384 284.581 283.669 285.248 287.331 284.341 281.400 285.305 282.949 282.108 tmax2m 1587319200 138 283.391 283.901 283.911 284.956 283.302 282.777 284.784 284.323 283.866 284.732 284.393 284.285 284.228 284.215 284.582 285.825 284.236 282.090 284.322 283.265 282.151 tmax2m 1587340800 144 280.930 280.297 280.455 281.400 280.359 279.633 281.088 281.304 280.414 281.206 280.130 279.935 280.817 281.238 281.049 282.475 281.455 280.418 280.340 280.441 280.016 tmax2m 1587362400 150 279.295 278.571 278.989 279.805 279.599 277.546 279.304 279.817 278.753 279.703 278.433 279.026 279.321 279.663 279.398 280.719 279.390 278.989 279.089 278.493 278.506 tmax2m 1587384000 156 285.314 280.542 281.192 281.200 287.213 280.008 281.754 282.623 287.911 282.030 281.473 285.175 286.215 285.248 287.222 287.183 283.482 281.849 287.211 282.505 285.187 tmax2m 1587405600 162 285.191 280.997 281.372 281.039 287.036 279.807 281.114 282.088 287.581 282.867 281.792 284.773 285.918 285.196 286.699 286.092 284.010 281.473 287.432 283.390 284.963 tmax2m 1587427200 168 280.137 278.848 278.862 279.327 281.651 277.808 277.936 278.572 281.622 279.597 278.793 279.582 279.947 280.848 281.278 281.737 280.773 278.684 281.048 279.566 279.860 tmax2m 1587448800 174 278.207 277.680 276.509 276.776 278.916 275.869 275.182 276.248 278.201 277.723 276.860 276.646 278.008 277.876 278.424 277.854 278.891 276.890 279.312 277.905 277.713 tmax2m 1587470400 180 279.936 278.415 279.261 276.937 286.707 278.860 275.906 279.942 284.397 278.352 280.286 278.904 283.542 283.265 282.282 284.671 285.643 282.906 286.066 281.645 281.573 tmax2m 1587492000 186 280.095 278.860 279.034 277.285 285.865 278.605 276.592 280.345 284.565 277.556 281.015 279.140 283.122 281.556 282.350 282.073 285.704 282.196 286.534 281.327 280.726 tmax2m 1587513600 192 278.841 276.110 276.742 273.982 281.010 276.485 275.615 277.636 280.831 275.358 277.766 276.437 279.352 277.864 279.217 276.952 281.336 278.290 281.705 278.735 278.248 tmax2m 1587535200 198 278.351 276.953 275.797 272.793 279.321 276.574 276.272 276.348 278.476 274.398 276.173 275.868 278.039 276.218 278.000 276.822 280.262 277.068 279.596 277.058 276.898 tmax2m 1587556800 204 281.556 283.906 279.255 280.183 285.697 280.925 280.954 279.761 287.883 275.648 281.176 280.794 277.168 275.631 280.459 280.551 286.576 278.396 286.972 279.329 281.879 tmax2m 1587578400 210 281.707 284.243 278.394 280.161 286.170 280.957 280.230 279.862 287.816 275.474 281.422 281.047 276.594 275.385 280.906 280.368 286.318 278.132 286.551 279.036 282.008 tmax2m 1587600000 216 277.344 280.049 274.423 275.767 282.515 278.473 277.721 276.358 281.629 273.821 277.114 277.569 274.482 272.969 277.664 277.092 280.718 275.324 281.389 275.221 277.649 tmax2m 1587621600 222 275.660 277.905 271.518 273.405 280.731 277.682 275.735 273.129 279.141 272.427 274.032 276.034 272.505 270.627 273.761 276.443 278.860 272.491 279.993 271.096 272.530 tmax2m 1587643200 228 281.262 282.130 272.391 278.355 287.371 285.036 278.557 279.066 282.484 275.092 281.740 280.702 275.960 272.600 278.548 279.560 279.055 272.675 286.577 274.907 282.445 tmax2m 1587664800 234 280.534 281.812 272.694 279.121 286.041 284.060 278.110 279.042 283.063 275.382 281.815 280.545 276.107 272.590 278.625 279.672 278.953 272.790 286.259 275.370 283.070 tmax2m 1587686400 240 276.065 277.906 267.418 276.229 280.049 280.224 274.980 274.552 280.359 272.958 276.619 277.685 273.506 269.778 272.081 276.438 276.697 268.768 281.503 272.722 275.647 dd10m 1586844000 6 341.513 341.768 339.977 339.296 338.712 339.978 343.593 343.961 341.857 341.564 338.846 344.699 340.985 343.998 339.656 340.886 341.043 338.721 343.686 338.942 345.688 dd10m 1586865600 12 352.351 352.681 351.885 352.884 351.327 355.012 356.357 351.715 352.328 354.285 348.788 354.494 351.990 349.750 355.895 352.283 351.859 354.518 352.643 353.293 351.467 dd10m 1586887200 18 20.608 20.742 18.299 22.781 16.734 28.157 23.625 16.460 17.850 24.576 16.250 24.239 15.797 16.190 22.750 22.238 18.142 21.825 22.287 24.216 20.571 dd10m 1586908800 24 186.484 185.449 178.676 192.697 175.264 180.806 214.862 188.590 177.465 183.396 182.744 180.710 180.771 183.367 203.099 178.471 177.829 182.824 204.049 184.527 175.994 dd10m 1586930400 30 195.517 190.191 193.794 195.673 202.481 177.656 163.759 223.987 214.944 203.477 198.424 209.938 196.585 194.813 165.430 190.760 211.722 201.484 190.410 162.259 193.546 dd10m 1586952000 36 35.652 38.966 43.684 31.611 54.321 57.088 33.119 18.487 33.087 33.384 34.526 32.949 32.024 36.858 28.087 38.834 40.634 33.512 38.839 38.625 52.640 dd10m 1586973600 42 80.387 84.372 99.479 86.288 90.022 101.004 62.321 67.096 87.401 68.843 76.737 77.275 80.248 90.004 69.611 84.316 83.127 70.602 78.496 82.453 88.684 dd10m 1586995200 48 185.541 184.695 192.972 180.806 190.328 184.257 184.424 185.723 187.897 186.607 183.376 183.751 187.591 190.517 184.715 185.464 182.926 185.897 187.742 185.286 184.103 dd10m 1587016800 54 205.548 204.114 217.224 198.707 209.525 204.503 207.133 208.118 207.658 201.278 201.568 201.249 203.968 206.284 206.383 208.031 206.671 208.857 208.175 204.634 203.406 dd10m 1587038400 60 273.993 276.944 302.471 246.527 254.768 293.352 272.181 308.278 285.220 259.541 274.767 274.560 279.163 290.952 287.450 251.135 293.998 275.069 300.240 279.352 266.882 dd10m 1587060000 66 4.901 10.273 3.836 341.424 9.366 6.611 26.356 7.246 18.535 356.017 19.194 348.269 23.655 35.028 347.429 6.141 359.765 27.160 11.642 3.223 17.722 dd10m 1587081600 72 230.278 237.619 235.634 227.341 214.724 227.723 242.009 208.420 225.051 231.009 228.468 235.389 218.817 221.136 231.548 229.098 218.164 224.214 226.470 256.748 217.617 dd10m 1587103200 78 234.629 239.653 248.272 221.075 258.989 206.473 252.235 212.047 226.220 244.724 207.360 219.487 216.841 218.679 246.755 221.285 225.907 258.368 220.296 243.790 224.377 dd10m 1587124800 84 297.629 324.236 321.866 304.607 326.544 222.483 317.577 321.112 276.299 282.767 251.763 264.148 306.987 240.078 295.997 296.850 310.224 325.339 281.177 332.230 272.227 dd10m 1587146400 90 80.105 73.444 22.990 61.159 21.515 139.921 11.758 111.365 111.913 21.413 150.388 148.619 94.906 176.364 144.819 51.243 88.481 21.838 37.186 101.808 105.656 dd10m 1587168000 96 201.765 203.114 198.165 200.182 206.412 207.141 210.521 209.237 232.376 222.725 208.157 216.916 200.834 220.044 203.180 204.347 213.087 204.774 210.526 210.310 192.419 dd10m 1587189600 102 212.117 241.534 205.319 200.588 193.623 235.055 203.821 265.542 243.708 263.970 264.687 256.881 215.427 277.348 241.340 206.643 222.787 207.040 268.194 252.821 212.046 dd10m 1587211200 108 237.893 232.385 226.578 197.518 249.671 286.870 193.188 303.531 278.751 288.702 273.716 270.058 244.337 287.783 241.961 192.353 227.677 158.848 308.276 285.819 258.311 dd10m 1587232800 114 209.039 20.407 198.152 186.014 139.107 310.393 206.849 36.945 336.804 17.003 331.895 308.471 338.977 18.709 273.795 178.859 194.503 154.360 15.438 354.310 262.679 dd10m 1587254400 120 197.680 183.323 226.080 198.593 183.134 210.216 213.509 176.994 355.974 184.877 207.506 245.753 157.459 169.875 222.736 201.592 197.818 199.352 184.848 192.610 197.598 dd10m 1587276000 126 175.233 189.259 262.823 220.855 176.724 248.899 217.550 172.462 163.855 181.848 235.573 199.925 160.511 175.152 267.568 229.607 199.712 182.610 187.013 184.153 163.157 dd10m 1587297600 132 168.243 176.189 222.975 237.993 191.222 267.729 247.709 171.800 153.973 179.985 301.852 201.717 170.746 155.174 67.662 229.099 293.541 243.122 150.293 145.767 162.081 dd10m 1587319200 138 150.606 189.200 163.709 157.566 196.192 16.456 162.494 163.346 153.825 161.665 30.717 115.539 159.505 151.169 122.588 162.600 150.449 27.048 155.796 85.174 151.248 dd10m 1587340800 144 163.566 188.979 250.045 165.962 186.022 72.372 173.692 182.166 174.458 177.187 132.208 187.709 172.009 170.308 170.087 173.704 164.882 109.304 178.456 162.971 168.395 dd10m 1587362400 150 174.499 177.404 354.542 171.859 165.665 79.455 163.924 228.594 182.766 174.825 97.498 167.883 175.663 164.191 175.180 185.494 162.487 92.268 180.851 148.489 159.042 dd10m 1587384000 156 177.583 172.701 44.739 152.675 156.587 87.774 133.515 331.043 126.943 158.112 93.696 144.423 173.445 153.163 143.587 167.687 143.286 94.393 162.494 146.504 109.943 dd10m 1587405600 162 144.465 221.804 70.517 158.458 162.580 100.051 22.131 26.752 143.594 139.623 98.714 120.450 173.043 138.178 147.703 148.175 125.486 96.218 165.775 104.875 110.798 dd10m 1587427200 168 152.235 303.714 99.363 285.028 180.347 127.745 31.131 47.414 161.600 150.505 105.663 127.223 182.955 160.611 165.572 167.783 149.555 134.029 179.257 144.970 143.119 dd10m 1587448800 174 137.332 331.491 107.215 314.241 188.303 126.527 46.600 78.049 142.871 114.419 114.164 86.461 197.261 126.454 92.372 187.576 158.019 156.118 171.616 155.562 144.872 dd10m 1587470400 180 148.712 352.170 108.967 334.164 164.265 118.126 84.885 90.726 115.687 36.635 112.672 66.157 143.814 35.711 94.801 40.768 157.857 91.672 154.584 88.399 78.240 dd10m 1587492000 186 158.470 34.842 173.243 8.237 176.753 35.838 113.696 95.586 126.664 19.827 95.597 60.167 186.392 14.128 91.911 33.131 171.838 129.098 142.685 51.996 41.541 dd10m 1587513600 192 178.083 163.535 193.733 53.385 182.479 163.045 142.124 145.170 150.488 57.178 115.358 67.321 198.358 36.577 127.722 113.370 203.636 220.478 173.657 32.001 46.698 dd10m 1587535200 198 201.633 162.382 234.637 53.053 200.137 67.710 133.362 26.494 161.732 12.036 93.450 60.350 269.873 25.578 50.192 132.711 248.909 259.414 186.161 26.384 43.320 dd10m 1587556800 204 216.560 166.771 312.236 44.361 232.254 85.144 79.289 22.630 130.998 41.708 49.927 49.991 323.700 22.279 43.727 157.137 296.590 1.187 185.415 43.911 52.051 dd10m 1587578400 210 225.158 163.368 340.613 32.638 171.767 86.711 68.288 11.746 165.455 37.374 43.808 48.829 345.607 30.231 32.722 131.923 313.842 16.907 244.574 44.937 43.976 dd10m 1587600000 216 208.341 181.064 349.810 30.972 178.131 142.554 93.621 16.331 195.154 32.928 92.988 101.494 340.791 30.346 24.390 174.835 9.303 27.975 177.797 56.565 49.651 dd10m 1587621600 222 294.676 188.274 11.208 41.204 170.656 146.376 18.049 19.402 214.235 15.757 108.353 71.012 355.185 25.817 0.733 188.457 44.068 27.318 178.165 54.317 49.505 dd10m 1587643200 228 356.272 222.736 10.049 58.873 176.980 81.621 19.004 24.091 223.478 29.371 80.948 62.245 8.931 24.854 357.339 46.739 53.631 32.904 151.464 55.747 48.956 dd10m 1587664800 234 359.393 289.897 5.356 53.430 225.473 62.571 5.528 14.797 226.100 23.979 65.301 68.576 9.252 17.141 1.268 16.872 46.372 29.877 173.443 44.262 62.832 dd10m 1587686400 240 6.776 297.258 293.154 56.988 213.145 17.123 337.941 6.645 216.902 19.458 143.159 139.251 3.272 13.635 7.361 348.658 97.075 33.255 212.133 81.063 169.340 ff10m 1586844000 6 3.644 3.497 3.500 3.597 3.523 3.790 3.818 3.475 3.572 3.663 3.696 3.820 3.703 3.402 3.883 3.651 3.717 3.728 3.737 3.659 3.665 ff10m 1586865600 12 3.832 3.959 3.822 3.891 3.779 3.837 3.915 3.920 3.899 3.823 3.915 3.972 3.738 3.924 3.715 3.768 3.877 3.690 3.850 3.748 3.794 ff10m 1586887200 18 2.265 2.448 2.383 2.227 2.330 2.247 2.249 2.328 2.251 2.157 2.366 2.446 2.259 2.310 2.284 2.309 2.336 2.228 2.254 2.337 2.308 ff10m 1586908800 24 0.772 0.790 0.799 0.813 0.895 0.881 0.252 0.727 0.586 0.816 0.565 0.522 0.901 1.063 0.717 0.969 0.511 1.074 0.758 0.718 0.932 ff10m 1586930400 30 0.593 0.351 0.854 0.471 0.781 0.883 0.319 0.550 0.733 0.853 0.833 0.329 0.853 0.781 0.226 0.664 0.318 0.747 0.416 0.440 0.694 ff10m 1586952000 36 1.941 2.275 1.598 2.344 1.729 1.892 2.206 2.140 1.937 1.742 2.157 2.237 1.515 1.631 2.075 2.127 2.133 1.772 2.054 2.162 1.778 ff10m 1586973600 42 1.481 1.541 1.231 1.665 1.111 1.527 1.740 1.582 1.362 1.381 1.641 1.561 1.301 1.349 1.463 1.541 1.559 1.285 1.380 1.560 1.449 ff10m 1586995200 48 2.389 2.459 2.389 2.580 2.354 2.426 2.302 2.343 2.408 2.312 2.370 2.423 2.421 2.441 2.353 2.399 2.433 2.418 2.367 2.417 2.433 ff10m 1587016800 54 2.199 2.269 2.002 2.480 2.122 2.218 2.084 2.139 2.188 2.242 2.322 2.419 2.329 2.280 2.246 2.083 2.366 2.075 2.171 2.140 2.216 ff10m 1587038400 60 1.115 1.043 1.499 1.473 1.029 0.995 0.624 1.570 1.356 0.991 1.013 1.032 1.409 1.206 1.227 1.091 1.335 1.023 1.185 0.915 1.114 ff10m 1587060000 66 0.806 0.733 1.080 0.483 0.963 0.425 0.448 1.090 0.961 0.304 0.343 0.889 0.658 0.554 1.129 0.918 1.067 0.785 1.049 0.807 0.382 ff10m 1587081600 72 1.371 1.207 1.832 1.898 1.792 1.028 1.215 1.713 1.668 1.302 1.332 1.031 2.009 1.736 1.564 1.617 1.355 1.430 1.091 0.543 1.526 ff10m 1587103200 78 1.466 1.277 1.416 1.660 1.346 1.687 1.287 2.068 1.426 1.412 1.630 1.656 1.898 1.931 1.396 1.355 1.421 1.038 1.571 1.286 1.606 ff10m 1587124800 84 1.189 0.835 2.171 1.445 1.695 0.639 2.108 0.654 0.878 0.844 0.587 0.810 0.845 0.826 0.810 1.358 0.840 1.659 0.431 0.786 0.994 ff10m 1587146400 90 0.608 0.813 1.232 0.785 1.151 0.956 1.115 0.619 0.564 0.344 1.322 1.027 0.633 0.466 0.740 0.757 0.685 1.226 0.448 0.416 0.675 ff10m 1587168000 96 2.269 2.344 2.360 2.205 1.400 2.571 2.149 2.506 1.712 2.048 2.171 2.394 2.582 2.466 2.181 2.250 2.243 2.004 2.324 2.233 2.170 ff10m 1587189600 102 1.969 1.627 2.373 2.234 1.648 2.023 2.085 1.558 1.609 1.385 1.783 1.220 2.206 1.802 1.488 2.005 1.828 1.547 1.871 1.541 1.839 ff10m 1587211200 108 1.109 1.304 1.835 1.999 0.535 1.735 1.094 2.144 2.232 1.255 1.972 1.341 2.177 2.174 0.331 1.452 0.789 0.393 2.401 1.392 0.950 ff10m 1587232800 114 0.814 0.375 1.550 2.422 1.640 0.493 1.701 1.037 1.559 0.763 1.797 0.647 0.818 1.338 0.067 1.278 0.746 1.034 1.519 0.785 0.660 ff10m 1587254400 120 1.840 2.567 1.660 2.703 3.502 1.167 2.295 1.888 0.325 2.521 0.820 1.583 0.458 2.304 1.490 2.101 1.793 2.577 2.381 1.702 1.773 ff10m 1587276000 126 1.424 2.467 1.242 2.413 3.068 0.662 1.940 1.832 1.678 2.726 1.278 1.472 1.092 1.644 1.010 1.693 1.649 2.210 2.331 1.016 2.105 ff10m 1587297600 132 1.127 3.229 0.482 1.094 2.940 0.244 0.983 1.696 2.163 2.316 0.655 1.441 1.622 1.566 1.324 0.767 0.264 1.325 1.715 1.326 2.356 ff10m 1587319200 138 2.294 1.563 1.656 2.011 1.384 0.787 1.417 2.512 2.529 1.680 1.262 0.306 2.480 2.037 1.807 1.962 1.885 1.787 1.998 1.284 2.268 ff10m 1587340800 144 3.302 2.903 0.808 2.365 2.371 1.164 2.367 3.161 2.815 2.855 1.324 1.920 3.300 3.057 2.482 3.153 2.891 1.512 2.643 2.369 2.473 ff10m 1587362400 150 2.908 2.320 1.786 1.866 2.939 2.263 1.533 2.205 2.389 2.224 1.889 2.440 3.961 3.170 2.285 2.918 2.082 2.345 3.142 2.913 2.117 ff10m 1587384000 156 2.661 1.967 2.760 1.861 4.283 2.832 0.996 1.799 1.836 2.678 3.082 2.677 3.721 3.521 0.616 2.732 1.802 3.223 2.882 3.258 2.340 ff10m 1587405600 162 1.677 0.369 3.415 1.832 3.353 2.623 1.417 3.040 2.702 2.378 2.863 2.351 3.064 3.054 1.983 2.589 2.281 2.785 3.292 2.514 2.822 ff10m 1587427200 168 1.607 1.544 2.911 3.112 3.571 2.359 2.653 3.133 2.605 2.177 3.073 2.407 3.008 2.582 1.962 2.605 2.538 2.616 3.685 2.621 2.559 ff10m 1587448800 174 1.087 1.841 3.009 2.961 2.712 2.101 2.789 3.016 1.894 0.964 3.115 2.407 1.988 0.615 1.511 0.472 2.873 1.918 2.919 1.521 1.785 ff10m 1587470400 180 0.865 1.788 3.210 3.196 2.244 1.235 2.968 3.471 3.356 1.459 3.515 3.726 1.205 2.417 2.779 2.110 2.646 0.688 2.709 1.753 1.687 ff10m 1587492000 186 1.940 1.529 3.553 2.645 2.493 1.500 2.068 2.679 3.231 2.531 2.955 3.582 0.621 1.907 2.186 2.569 1.262 0.529 2.181 1.761 1.829 ff10m 1587513600 192 3.433 1.586 3.668 1.477 3.755 0.261 2.213 1.899 2.835 1.888 2.181 2.476 1.288 2.412 1.759 1.533 2.290 0.636 2.756 1.074 1.537 ff10m 1587535200 198 3.084 1.883 2.273 1.577 3.343 1.375 1.462 1.332 2.113 1.844 1.478 2.171 1.321 1.719 0.684 1.445 1.346 0.204 1.966 2.526 2.303 ff10m 1587556800 204 1.930 2.378 2.715 3.753 1.991 1.826 2.026 2.702 1.647 2.079 3.016 2.985 2.526 2.560 2.719 1.853 2.155 1.711 1.207 3.139 3.239 ff10m 1587578400 210 0.875 1.667 3.048 3.753 1.681 1.532 1.623 3.180 1.709 1.938 3.077 2.365 3.309 3.067 2.743 0.388 1.423 2.975 0.471 3.328 3.376 ff10m 1587600000 216 1.255 3.179 3.077 3.155 3.381 1.500 0.833 2.412 2.755 0.929 1.526 1.031 2.461 2.714 1.863 1.325 1.203 3.505 1.334 2.042 2.045 ff10m 1587621600 222 0.663 3.237 4.554 2.484 4.055 1.692 2.800 2.179 1.906 1.778 1.570 1.048 2.704 3.342 2.815 1.137 2.748 4.306 1.959 2.517 1.516 ff10m 1587643200 228 1.943 1.838 4.267 2.950 4.453 2.136 3.101 3.367 1.775 2.634 2.521 2.730 3.029 4.738 4.866 0.962 2.924 4.892 1.671 3.049 3.250 ff10m 1587664800 234 1.971 1.560 2.587 2.448 2.627 1.630 2.685 3.261 1.071 2.748 1.873 2.168 2.848 3.573 4.467 1.926 2.976 4.404 1.716 2.895 2.139 ff10m 1587686400 240 1.805 2.763 0.913 1.553 1.652 2.118 1.359 3.210 1.175 2.792 0.701 1.540 1.576 2.732 3.122 2.083 1.565 2.630 2.152 1.151 2.175 apcpsfc 1586844000 6 2.153 1.530 2.192 1.504 1.843 1.751 2.311 2.173 2.101 1.901 2.171 2.251 2.245 1.843 2.139 2.059 2.306 2.223 1.990 2.150 2.249 apcpsfc 1586865600 12 0.119 0.100 0.110 0.110 0.100 0.209 0.191 0.036 0.093 0.119 0.171 0.219 0.062 0.074 0.219 0.110 0.219 0.110 0.171 0.145 0.119 apcpsfc 1586887200 18 0.038 0.000 0.023 0.033 0.023 0.074 0.122 0.023 0.023 0.055 0.066 0.103 0.023 0.016 0.096 0.048 0.061 0.032 0.077 0.041 0.029 apcpsfc 1586908800 24 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.003 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1586930400 30 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1586952000 36 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1586973600 42 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1586995200 48 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1587016800 54 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1587038400 60 0.015 0.010 0.017 0.000 0.000 0.000 0.000 0.048 0.015 0.010 0.012 0.022 0.015 0.015 0.048 0.003 0.000 0.015 0.020 0.010 0.000 apcpsfc 1587060000 66 0.810 0.462 0.642 0.048 0.366 0.095 1.002 0.614 0.701 0.327 0.407 0.909 0.729 0.461 1.934 0.791 0.831 0.774 0.801 0.530 0.201 apcpsfc 1587081600 72 0.000 0.019 0.000 0.000 0.048 0.010 0.731 0.000 0.012 0.048 0.000 0.100 0.005 0.000 0.258 0.100 0.023 0.024 0.027 0.144 0.000 apcpsfc 1587103200 78 0.000 0.000 0.000 0.000 0.017 0.000 0.041 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 apcpsfc 1587124800 84 0.073 0.016 0.497 0.067 0.960 0.078 0.883 0.000 0.048 0.077 0.040 0.170 0.143 0.122 0.069 0.026 0.048 0.282 0.041 0.026 0.031 apcpsfc 1587146400 90 0.803 0.481 1.403 0.775 1.791 1.172 1.612 1.433 1.711 0.593 0.653 1.728 1.540 1.659 0.532 1.309 1.281 0.813 2.166 0.553 0.296 apcpsfc 1587168000 96 0.002 0.000 0.062 0.000 0.000 0.143 0.000 0.535 1.632 0.162 0.163 1.856 0.239 0.678 0.128 0.000 0.386 0.009 1.078 0.478 0.000 apcpsfc 1587189600 102 0.096 0.048 0.143 0.010 0.063 0.913 0.000 1.044 0.810 0.101 0.048 3.247 0.526 0.602 0.143 0.000 0.000 0.048 2.388 0.944 1.013 apcpsfc 1587211200 108 1.374 0.896 1.692 0.441 0.821 2.761 1.726 3.130 2.081 1.202 1.209 4.760 2.631 2.352 0.614 0.361 0.917 0.318 1.798 2.189 2.356 apcpsfc 1587232800 114 5.557 6.318 4.502 2.796 2.326 9.351 10.931 3.890 10.702 6.581 5.470 6.943 7.498 6.425 6.694 1.756 7.619 3.657 1.643 6.969 2.317 apcpsfc 1587254400 120 4.436 2.708 6.658 2.074 0.504 9.105 4.744 0.662 6.875 3.629 1.459 2.022 9.980 1.290 10.132 5.120 5.334 1.292 0.000 7.283 0.566 apcpsfc 1587276000 126 7.483 0.262 3.716 2.181 1.809 4.883 4.404 0.674 0.223 2.813 0.122 0.026 6.103 3.649 3.083 6.854 6.538 3.856 0.074 3.341 1.756 apcpsfc 1587297600 132 5.728 1.699 2.202 1.540 4.468 5.208 3.477 2.615 0.875 2.589 1.616 2.211 2.447 4.789 1.326 1.452 1.776 8.712 1.983 5.633 5.736 apcpsfc 1587319200 138 3.581 2.296 9.972 5.338 0.903 11.934 3.165 5.147 2.524 1.216 9.630 5.303 5.539 4.164 3.337 5.171 4.810 4.908 11.594 3.942 4.977 apcpsfc 1587340800 144 1.412 1.353 13.959 8.898 0.129 11.344 3.186 3.807 1.567 4.793 5.477 1.661 4.822 4.331 10.164 3.113 2.428 1.199 5.238 0.431 2.018 apcpsfc 1587362400 150 3.883 7.894 7.243 8.585 0.000 3.882 3.548 7.893 0.048 4.516 7.044 0.048 1.264 1.802 1.652 0.741 4.435 0.547 0.383 0.578 0.342 apcpsfc 1587384000 156 1.567 10.323 3.228 5.491 0.048 7.008 3.824 4.799 0.096 4.717 6.035 0.218 0.390 0.605 0.352 0.504 4.754 2.438 0.096 3.727 0.669 apcpsfc 1587405600 162 4.474 6.702 5.339 7.208 0.262 8.288 9.838 6.910 1.457 1.575 8.445 4.356 1.858 1.497 3.981 1.899 6.013 4.785 1.574 0.456 3.288 apcpsfc 1587427200 168 2.800 7.246 9.571 7.223 0.061 2.633 6.846 6.623 0.139 0.445 3.297 2.612 0.178 0.136 1.829 0.069 3.138 1.061 2.055 0.331 2.595 apcpsfc 1587448800 174 5.216 3.233 5.310 3.211 0.000 1.639 6.432 4.288 0.961 2.789 1.841 1.841 0.382 0.449 0.489 0.052 0.956 0.122 0.461 0.502 0.312 apcpsfc 1587470400 180 8.487 4.100 3.041 2.888 0.679 5.542 4.716 1.632 1.110 10.150 0.937 2.470 2.829 2.009 1.186 1.243 0.671 2.143 0.292 3.779 3.877 apcpsfc 1587492000 186 7.318 5.249 5.038 0.707 1.520 6.602 3.659 2.861 1.331 8.893 2.144 2.127 10.657 8.462 4.310 8.556 1.167 8.293 0.597 4.913 7.727 apcpsfc 1587513600 192 0.341 3.344 0.693 0.244 0.656 0.609 1.059 1.805 0.061 3.636 2.863 0.545 9.500 8.157 3.783 2.489 0.328 4.623 0.215 3.562 3.560 apcpsfc 1587535200 198 0.097 0.061 0.670 0.000 0.039 0.528 1.149 2.312 0.026 6.673 1.662 0.385 11.799 9.541 4.749 4.646 0.340 3.633 0.158 1.530 0.753 apcpsfc 1587556800 204 2.306 0.548 1.999 0.158 0.679 2.066 3.177 2.150 0.683 5.612 0.878 0.898 8.257 6.986 3.919 1.945 1.650 8.283 0.719 1.566 0.371 apcpsfc 1587578400 210 3.985 1.321 4.928 2.585 0.628 7.373 5.412 4.154 6.125 6.247 0.820 4.510 4.248 6.933 1.100 6.120 6.169 5.364 6.657 4.011 0.296 apcpsfc 1587600000 216 2.269 0.190 1.416 1.489 0.135 0.877 2.221 1.958 7.589 4.270 0.074 3.044 1.294 6.746 0.256 4.261 5.560 6.120 5.381 6.592 0.100 apcpsfc 1587621600 222 0.380 0.894 1.698 1.391 0.025 0.057 1.972 0.344 6.518 3.357 0.096 1.430 1.206 3.724 0.083 2.192 7.108 5.938 0.552 8.394 0.000 apcpsfc 1587643200 228 1.771 2.179 0.797 2.915 0.459 1.122 2.161 0.074 6.214 2.619 0.430 3.216 2.367 1.984 0.048 5.285 7.120 3.581 0.619 6.161 0.000 apcpsfc 1587664800 234 7.619 6.978 0.200 2.284 3.014 5.944 4.143 0.218 7.073 5.542 1.568 4.751 2.884 1.439 0.552 6.888 8.178 2.529 3.428 3.569 0.000 apcpsfc 1587686400 240 6.163 7.591 0.000 1.478 1.804 2.025 2.888 0.822 6.090 6.527 0.249 0.922 1.329 1.023 0.476 3.075 4.570 2.384 4.903 0.792 0.005 tmp2m 1586844000 6 268.607 268.923 268.292 268.556 268.238 268.348 267.995 268.499 268.938 267.741 268.899 268.970 268.971 269.001 268.372 268.623 269.055 268.635 268.387 268.821 268.985 tmp2m 1586865600 12 273.300 273.389 273.198 273.101 273.444 272.758 272.570 273.619 273.787 272.935 273.414 273.206 273.626 274.144 272.608 273.545 273.205 273.300 273.109 273.161 273.787 tmp2m 1586887200 18 268.073 268.326 268.230 267.960 268.443 268.030 267.972 268.197 268.390 267.778 268.453 268.672 268.397 268.679 268.084 268.424 268.549 268.157 268.101 268.283 268.448 tmp2m 1586908800 24 259.523 259.464 259.573 259.921 260.301 259.225 257.768 259.834 259.905 259.173 259.515 258.337 260.257 261.653 258.789 260.180 258.706 260.291 259.071 259.030 260.524 tmp2m 1586930400 30 270.247 270.046 270.217 270.297 270.302 270.085 269.449 269.970 270.555 270.082 270.028 270.005 270.539 270.819 270.007 270.291 270.018 270.465 269.864 270.013 270.668 tmp2m 1586952000 36 280.242 280.116 280.539 280.407 280.908 280.577 280.672 280.083 280.739 280.533 280.029 279.927 280.852 281.179 279.818 280.279 280.012 280.598 280.021 280.187 280.842 tmp2m 1586973600 42 273.383 273.580 273.202 273.870 273.399 273.656 273.434 273.505 273.362 273.136 273.524 273.595 273.311 273.585 273.197 273.440 273.449 273.263 273.065 273.566 273.619 tmp2m 1586995200 48 272.973 272.951 272.999 273.072 273.112 272.858 272.034 272.720 273.196 272.693 272.682 272.792 273.221 273.364 272.651 272.897 272.818 273.173 272.747 272.930 273.252 tmp2m 1587016800 54 275.898 275.915 275.916 275.762 275.917 275.645 275.448 275.821 276.073 275.904 275.767 275.780 275.960 276.132 275.791 275.906 275.677 276.030 275.847 275.980 275.936 tmp2m 1587038400 60 286.242 286.504 285.814 286.174 285.972 286.375 285.759 285.614 286.525 286.211 286.211 285.929 286.181 286.718 285.525 286.072 286.208 286.399 286.283 286.691 286.139 tmp2m 1587060000 66 277.590 277.739 277.387 277.351 277.821 277.521 276.954 277.309 277.919 276.957 277.275 277.769 277.317 277.758 277.752 277.772 277.773 277.693 277.764 277.793 277.572 tmp2m 1587081600 72 274.241 274.205 274.613 274.592 274.559 273.770 274.507 274.458 274.549 274.350 274.100 273.718 275.027 274.714 274.151 274.451 274.069 274.475 273.814 274.280 274.397 tmp2m 1587103200 78 278.144 278.254 277.853 278.215 277.909 278.268 277.696 277.806 278.367 278.363 278.402 277.894 278.026 278.265 277.623 278.302 278.102 278.057 278.152 278.194 278.298 tmp2m 1587124800 84 288.395 289.047 286.037 288.401 286.056 287.826 285.255 288.013 288.657 288.895 288.283 287.800 287.308 287.907 288.517 288.430 288.683 287.290 287.956 288.744 288.674 tmp2m 1587146400 90 278.521 278.810 277.995 278.497 278.205 279.411 277.483 279.048 279.949 279.451 280.361 280.272 279.105 280.013 279.782 278.531 279.197 278.498 278.983 279.171 279.864 tmp2m 1587168000 96 277.352 277.286 277.040 277.206 275.343 277.035 276.111 277.814 278.210 276.843 277.140 278.106 277.724 277.696 277.576 277.267 276.826 276.946 277.511 277.858 277.738 tmp2m 1587189600 102 279.659 279.567 279.279 279.418 278.789 278.648 278.880 278.872 278.875 279.206 278.686 278.624 279.145 279.019 279.306 279.675 279.449 279.540 278.752 279.715 278.657 tmp2m 1587211200 108 286.165 287.210 285.963 287.509 287.872 283.658 285.613 284.695 285.354 287.593 286.310 282.892 284.859 285.236 286.428 287.884 286.739 288.346 285.842 286.417 284.342 tmp2m 1587232800 114 280.794 280.548 280.918 281.169 281.721 279.650 280.311 279.390 280.279 280.806 280.710 279.323 279.807 280.356 280.594 282.094 280.371 281.491 279.475 280.713 280.262 tmp2m 1587254400 120 278.397 278.378 278.808 278.873 279.657 277.679 278.219 277.850 278.303 278.855 277.661 277.613 278.381 278.205 279.404 279.235 278.620 279.487 276.821 278.705 277.228 tmp2m 1587276000 126 278.877 279.221 279.389 279.446 279.609 278.262 278.441 279.281 278.707 279.679 278.894 278.732 279.114 279.053 279.686 279.732 279.111 279.594 279.555 279.454 278.675 tmp2m 1587297600 132 282.856 283.306 284.252 284.803 282.360 282.552 284.734 284.293 283.872 284.403 284.700 284.215 284.354 283.669 285.045 286.167 283.842 281.248 284.653 282.923 282.099 tmp2m 1587319200 138 281.008 280.533 280.490 281.517 280.511 279.754 281.131 281.435 280.564 281.405 280.326 279.975 280.861 281.316 281.184 282.527 281.428 280.406 280.536 280.528 280.099 tmp2m 1587340800 144 279.005 278.212 278.963 279.740 277.528 277.433 279.212 279.257 278.375 279.382 278.370 278.193 278.796 279.154 279.228 280.342 279.343 278.950 278.176 278.389 277.937 tmp2m 1587362400 150 279.269 278.354 278.632 279.011 279.599 277.226 278.909 279.626 278.727 279.703 277.931 278.665 279.103 279.615 279.042 280.654 278.924 277.834 279.115 277.889 278.147 tmp2m 1587384000 156 285.012 280.542 281.135 281.056 287.160 279.955 281.440 281.968 287.806 281.609 281.378 285.127 286.093 285.095 287.222 286.605 283.464 281.605 287.211 282.488 284.982 tmp2m 1587405600 162 280.327 278.934 279.091 279.401 281.857 277.754 278.101 278.707 281.844 279.987 278.904 279.691 280.234 280.938 281.355 281.800 280.934 278.719 281.265 279.675 280.085 tmp2m 1587427200 168 278.210 277.676 276.447 276.924 278.430 275.823 275.300 276.226 277.614 277.750 276.938 276.627 278.004 277.636 278.147 277.441 278.920 276.566 278.809 276.950 277.179 tmp2m 1587448800 174 277.734 276.476 275.513 274.875 278.724 275.513 273.396 275.002 278.154 277.014 275.797 275.710 277.960 277.707 277.640 277.321 278.492 276.752 279.321 277.750 277.661 tmp2m 1587470400 180 279.831 278.388 278.262 276.744 285.686 278.511 275.906 279.915 284.291 277.718 280.238 278.856 282.980 281.964 282.208 283.000 285.643 282.196 286.066 280.991 280.783 tmp2m 1587492000 186 278.935 276.160 276.677 274.520 281.393 276.629 275.625 277.831 281.027 275.311 278.023 276.577 279.278 278.030 279.343 277.119 281.626 278.512 281.935 278.883 278.374 tmp2m 1587513600 192 277.324 275.263 273.864 271.441 277.291 275.267 274.356 275.006 276.049 273.875 274.998 275.002 277.226 275.717 277.335 275.068 278.524 276.041 277.273 276.912 276.612 tmp2m 1587535200 198 277.271 276.953 275.274 272.793 279.262 276.548 276.193 275.924 278.380 273.589 275.982 275.851 276.312 274.470 277.134 276.688 279.652 276.326 279.548 275.969 276.411 tmp2m 1587556800 204 281.420 283.784 278.737 280.120 285.331 280.490 280.897 279.470 287.613 275.556 281.128 280.715 277.028 275.100 280.459 280.047 286.421 278.195 286.671 279.301 281.832 tmp2m 1587578400 210 277.901 280.100 274.677 275.990 282.667 278.714 277.911 276.756 281.935 273.987 277.481 277.795 274.418 273.301 277.750 277.306 280.936 275.518 281.646 275.476 278.117 tmp2m 1587600000 216 274.256 277.525 271.425 273.276 279.711 276.521 275.400 271.807 278.708 272.334 271.243 275.279 272.154 270.736 273.250 276.253 278.874 272.665 279.703 271.253 272.415 tmp2m 1587621600 222 275.581 277.730 269.734 273.020 280.727 277.630 275.294 272.426 278.744 272.132 273.999 276.017 272.368 269.449 271.807 276.390 277.521 270.591 279.776 270.983 272.038 tmp2m 1587643200 228 280.957 281.819 272.386 278.328 286.628 284.166 278.383 279.063 282.484 275.092 281.740 280.303 275.960 272.600 278.548 279.417 278.814 272.675 286.329 274.859 282.445 tmp2m 1587664800 234 276.267 278.092 267.708 276.520 280.075 280.476 275.600 274.897 280.588 273.284 277.212 278.028 273.895 269.882 272.546 277.067 277.015 269.094 281.630 273.031 276.274 tmp2m 1587686400 240 274.072 276.602 262.793 272.196 276.996 277.029 272.578 271.699 278.809 270.703 271.558 274.912 270.501 267.779 267.507 274.641 274.731 265.405 278.632 266.969 272.437 tcdcclm 1586844000 6 5.958 5.952 5.762 5.856 5.479 5.908 6.474 5.905 6.277 5.665 6.226 6.216 6.071 5.670 5.759 6.129 6.033 6.292 6.286 5.698 6.216 tcdcclm 1586865600 12 3.756 3.054 3.328 3.702 3.449 4.385 4.190 3.376 3.707 3.999 4.442 4.475 3.005 2.909 4.691 3.200 4.734 3.486 4.120 4.101 3.852 tcdcclm 1586887200 18 1.047 1.882 0.986 1.189 0.500 2.681 3.422 0.566 0.710 1.950 2.053 2.381 0.635 0.346 2.772 0.745 1.984 0.815 2.521 1.224 0.863 tcdcclm 1586908800 24 0.308 0.329 0.294 0.308 0.186 0.482 0.813 0.350 0.316 0.206 0.791 1.097 0.291 0.245 0.648 0.346 0.753 0.224 0.639 0.350 0.388 tcdcclm 1586930400 30 0.098 0.052 0.105 0.143 0.098 0.084 0.038 0.105 0.098 0.105 0.112 0.046 0.105 0.143 0.136 0.241 0.105 0.098 0.076 0.084 0.156 tcdcclm 1586952000 36 0.028 0.271 0.103 0.897 1.073 0.374 0.387 0.126 0.305 0.245 0.780 0.021 0.169 0.094 0.541 0.118 0.216 0.013 0.296 0.063 0.063 tcdcclm 1586973600 42 0.788 1.474 1.494 0.968 3.637 0.468 0.890 1.216 1.176 1.067 0.704 1.016 2.279 1.153 0.959 0.911 0.771 0.940 0.803 0.442 1.658 tcdcclm 1586995200 48 3.331 2.443 2.629 3.594 3.284 1.849 2.279 3.025 2.367 2.794 2.804 4.512 4.948 4.135 3.079 2.912 3.052 4.144 2.839 3.162 5.285 tcdcclm 1587016800 54 4.162 3.521 3.111 4.655 3.902 3.778 3.568 3.761 3.743 3.719 3.931 5.249 4.342 4.263 3.621 3.958 3.816 4.186 3.462 3.844 4.507 tcdcclm 1587038400 60 2.065 1.923 1.566 2.967 1.329 2.694 3.733 2.385 1.732 3.519 1.760 2.939 2.106 1.735 3.594 2.861 1.441 1.474 3.286 2.316 1.582 tcdcclm 1587060000 66 6.938 6.822 6.960 6.674 5.276 4.405 6.203 6.188 6.680 6.286 6.673 6.752 7.165 6.259 7.097 6.540 6.889 6.992 6.788 5.952 6.924 tcdcclm 1587081600 72 2.464 2.621 1.822 2.766 2.839 2.275 6.455 1.615 1.483 3.162 1.917 3.399 2.369 2.573 4.487 2.671 2.220 2.904 2.353 5.981 2.458 tcdcclm 1587103200 78 2.314 2.657 3.813 3.821 2.013 2.988 3.440 3.930 3.470 0.881 0.937 2.611 4.297 3.139 3.683 2.996 2.766 4.575 4.334 2.066 3.094 tcdcclm 1587124800 84 1.182 0.348 2.012 2.723 0.999 3.431 2.005 6.127 4.434 1.516 3.743 1.994 3.200 3.561 1.722 3.886 4.360 2.126 5.816 2.402 3.016 tcdcclm 1587146400 90 3.612 4.063 2.796 5.533 3.406 4.954 2.891 5.899 6.748 5.765 7.811 5.606 5.823 5.184 5.786 5.380 6.132 3.598 6.070 4.513 4.862 tcdcclm 1587168000 96 4.836 5.498 5.391 5.334 3.286 5.111 3.104 6.561 7.474 6.319 6.945 7.230 6.158 6.326 6.877 4.907 2.003 5.321 6.064 6.723 7.719 tcdcclm 1587189600 102 5.958 5.803 6.450 5.664 6.548 6.487 4.439 6.697 4.430 3.938 4.508 7.521 6.673 6.882 6.454 6.189 3.929 6.824 7.129 7.003 7.787 tcdcclm 1587211200 108 6.507 4.207 6.690 6.977 4.660 6.406 6.180 6.406 5.587 5.642 5.388 7.422 6.646 6.662 5.743 6.206 5.607 6.344 4.372 6.651 7.070 tcdcclm 1587232800 114 6.800 7.186 7.839 7.720 6.279 7.287 7.436 6.991 7.406 7.386 6.254 7.076 7.281 6.706 7.030 6.630 7.072 6.306 5.481 6.965 6.925 tcdcclm 1587254400 120 7.127 6.540 7.913 7.497 7.642 7.088 7.406 6.322 7.625 6.721 5.905 7.202 7.423 6.579 7.716 7.748 7.866 7.560 5.123 7.528 6.740 tcdcclm 1587276000 126 7.730 6.850 7.313 7.249 7.499 6.441 7.417 7.322 5.263 7.806 5.920 7.656 7.515 7.542 7.295 7.866 7.469 7.805 6.642 7.210 7.214 tcdcclm 1587297600 132 7.684 7.923 7.708 7.679 7.958 7.069 6.755 5.468 7.337 7.216 6.466 6.000 7.116 7.437 6.986 7.028 6.773 7.937 7.110 7.800 7.890 tcdcclm 1587319200 138 7.209 7.622 7.958 7.767 6.666 7.408 6.606 7.915 7.958 7.137 7.613 7.056 7.574 7.637 7.248 7.684 7.760 7.343 7.804 7.313 7.898 tcdcclm 1587340800 144 7.734 7.358 7.958 7.734 6.166 7.862 7.741 7.951 7.632 7.909 7.568 7.357 7.853 7.917 7.653 7.589 7.452 7.835 7.479 7.796 7.887 tcdcclm 1587362400 150 7.714 7.839 7.883 7.930 6.668 7.808 7.393 7.834 5.534 7.827 7.669 6.632 7.423 7.713 6.492 7.004 7.655 7.625 6.169 7.283 6.765 tcdcclm 1587384000 156 7.131 7.979 7.742 7.979 6.828 7.958 7.722 7.644 4.652 7.979 7.551 7.631 6.959 7.265 3.569 7.108 7.267 6.936 6.821 7.930 6.756 tcdcclm 1587405600 162 7.663 7.741 7.738 7.979 6.814 7.945 7.791 7.972 6.597 7.074 6.429 7.892 7.485 7.581 5.627 7.487 7.718 6.806 7.739 6.854 7.905 tcdcclm 1587427200 168 7.829 7.972 7.944 7.867 5.223 7.667 7.865 7.993 7.498 6.721 7.105 7.714 6.614 5.575 6.815 5.804 7.706 6.247 7.868 5.098 7.905 tcdcclm 1587448800 174 7.853 7.401 7.927 7.356 4.172 7.046 7.906 7.822 7.285 6.976 7.692 7.833 5.173 4.521 7.787 2.345 7.583 5.990 7.667 4.127 7.411 tcdcclm 1587470400 180 7.805 7.666 7.731 7.522 4.809 7.852 7.623 7.091 7.616 7.837 7.430 7.432 5.452 4.876 7.921 3.541 7.276 6.997 7.103 7.056 7.668 tcdcclm 1587492000 186 7.923 6.788 7.564 6.845 6.297 7.771 7.777 7.135 7.287 7.913 7.300 7.640 7.247 7.572 7.729 7.807 7.257 6.272 6.416 7.471 7.822 tcdcclm 1587513600 192 7.635 6.709 7.907 6.040 7.230 7.307 7.225 7.379 3.205 7.822 6.353 6.818 7.954 7.945 7.549 7.633 6.744 5.945 6.015 7.626 7.597 tcdcclm 1587535200 198 3.480 3.764 7.902 6.096 2.262 6.719 6.820 7.322 1.871 7.525 5.310 5.512 7.868 7.951 6.225 7.252 3.087 6.466 5.339 6.887 5.706 tcdcclm 1587556800 204 6.262 5.144 7.009 6.530 3.600 6.972 6.447 6.889 2.134 7.517 5.178 5.747 7.707 7.657 5.814 6.844 4.951 7.371 6.165 5.906 5.060 tcdcclm 1587578400 210 6.497 5.940 7.452 7.610 5.302 7.604 7.521 7.062 5.030 7.875 4.590 5.826 7.802 7.681 5.088 7.485 6.577 7.134 6.977 6.346 4.771 tcdcclm 1587600000 216 4.553 6.682 7.252 7.352 5.366 6.071 6.835 6.712 5.826 7.500 2.432 6.421 7.556 7.794 4.868 7.437 6.879 7.718 7.786 7.280 4.352 tcdcclm 1587621600 222 2.817 5.786 7.277 6.679 5.691 4.693 7.111 6.549 6.582 7.700 1.091 6.084 7.134 7.888 4.696 7.039 7.595 7.972 7.784 7.567 1.489 tcdcclm 1587643200 228 3.682 7.286 5.967 6.278 5.505 4.654 6.880 4.806 7.145 7.707 2.674 5.784 7.431 7.864 1.613 7.706 7.716 7.805 7.534 6.043 0.267 tcdcclm 1587664800 234 6.703 7.667 3.436 6.916 7.496 5.608 7.623 6.461 7.083 7.421 4.454 6.044 7.218 7.673 3.863 7.758 7.587 7.506 6.568 5.966 1.026 tcdcclm 1587686400 240 6.964 7.822 0.922 6.597 5.840 5.605 6.807 6.770 7.442 7.670 3.186 4.913 6.204 7.423 6.016 7.455 7.315 7.401 7.027 4.840 1.961 partykit/inst/ULGcourse-2020/Data/crps_24to4_all.rda0000644000176200001440000001402314172227777021443 0ustar liggesuserseXy@OBŒ"K%.L50df"Ke+%)(uPf{Y)fs{s><3shVSSSWڭzWUC뢦E>{bnjp-fda/KfPw޺a Jߠ(2>Q)>pct̄hInL(o2!  eĠu wT\x_>x A/ zto1G\@OPSj󇥺BZ9oqaOW̎Jigz ɶq#k!ׯM΅$Ac7$N}BgPDvf8˹uoLCtB"+!>_}[ $R/i( _nI8*΍F7+ҾB20~O\X/}ԋ !ǃAV6rOBq´my&/zulm2Κ EywwP?P P׻OGCI>o@_;)3KCz{MH6G@<ؠi;2@Gƚݖ X En>O U$^QO݀\d0dx(3Fۿj$V!~NFdA0j;VVWN9+= F}/\x 4-c\Or,+6Aa@h[a3Y!W:!rug(8Bֱu} qsY  Z; :~vg?ǎf@sˑY\iŴ߽9iWzBx!;h2 ^:@}41 n$8Al^?XbH¬n}_ IånQ.35 G4A[ZcN@$KRD]#3v[&C;]Y|B[+1N_L='t0լwU_x Y8_z4wZK1C}Ҷ'ه\Ӷp8~Gلw_ @M9D/zw+y^ZL\PgNꚅ bV}aBp{R7]m:Y-tNf*25ڥ*K6p!sSrz%moOĔ:{x-t4T{M;v#g1KCPVzT;GUDaެ :}H:lr'z%!Y) sp$-4|%:e; Kepw_![2&bNz-hoL͟o 2t%au8u<-D>lu4d76*%8Md\u=QiXL1e4%>4wF kkNFj;߻҆0gԭA3?+oK'u]pOG(w=7~P 힭QQҩu8?,*}@}9:}pkÍmMȻzb3>X=&ڥC93d?/\W I}Tc>F'oXbl$ 5x g8qє(̛/OB*l D.6 ?"J_$מ{AҠ2t](ZgnqKz}MH/ӂ&Ld8=sf#8~idoBq!]>ꕣn]Uf0}5ͧ|O򥱍sِ45@YؔNҪ;PNp9?l䓧cIvJ(ץ]w&?EXqcF>{m! qחTMim"(j[jA6ܘ F2c^<axAQP%{3(}SKˏ7@Ԛ?tTA]HseRw/g!o8Rw<ֹ!:)v!Dǜ厇h~KW.5!o_:A' 5dgIvMʨeݙ\|P (:?6_k%WmRO_'z°D(Jcǂ'_a n}@=}ܒ~(Ye@,>s:ʠڻ U]t*!~]6fqC?tJwL"]wmYzup&!`kh|k^em[N@a`?H:D G>bVnPE|.v (hD| UEnA"۽߻%w. !u0iVh0y'Ze,}?r:as5'Y3Da(?_lYs; +9V G7-, L]Xu,vە;6"šo/h_ILFK8qa2藥5d(<&1O04K7s"(KFc澍&diW'O/2 Lۄ?$ Q}A/_ڻW@;ctj-?/l [iMq %+nΨ^k&4cK!}J+5лV~kI_j!Dݯwܳ3CN[@{O#N((R7{:z/@DG~rڗ0B}#zPXbV^$>$Blo,l) j;rH7Z6ݴ4Aaj G{e]/!<kOBaϛG-=dJ&(Y,Ր Yg^oIVa~m}@jϕIzՃ_§ߊ]!cxiǐD>/y}Qi~Ay𬾭Hazw蝵#|!~޽)m`r^ĥ~D9.]?XjV^oCc|y5'*""*(x$޻8Y'uOlGtC7!v=\HN %}ȿ%nݦP~ )kWݯ^_kqz[ _s@$ uP|.o8 EcoAymJj(Vο 7sSgK/TdrӚ Hsc[1-6 28؟,{Y'Лk|RTsOGv~n8[OہzIۤ>ۃ k̷3 nN֍/SBVW`Kͮ; 1eP Dg\))x:R|?2׊o8=z-dH6Zh`mO d}yӝOnp"P&W>-C+NL,HO%V=$0oΘ~ 9ԻJ/Td[hfB?'8Hm/ý zɑP<ޗ#qEӉ r8L׾ݷA%JjV SlŐg%)GM͸6d6|EADvMk:N.'zҷҁBv^}iBM OTBn˩-$>&;|M6EACd'xr;0qw~;x?:Rϕ䇓I3X@:? #! 7%.G"2pա:n,&;͏H "vD\Tܮ39uZ;@aaaR;Go?6]oٿCp؎v1`_ q0 Hf>ucT$pyLvRxM E0};72؝Dfs,MB٫]EܰeVȪ=:.A\Yu$9CuS(\ɌT<Nipartykit/inst/ULGcourse-2020/Data/STAGEobs_tawes_11121_defense.rda0000644000176200001440000000502014172227777023675 0ustar liggesusersyU >,305kd&CAZe8w^2MKlnY&IY;!0{ተys{>g W]8sUۿʶʫ?yҥ-ҭ=úMm>n6,YxÊ%KtYiqb:}8Pt\W㱕W`I _!/7v_ .N~WIBO7HK}-ע%;K;^rZ^3Ie)wxn&m *ngo9i^OJ$a%0IH;ޖIk?}%В%j ,(NEbA0BQ0PǷo0DW<>sg.n]bxFI(/ԭ0tIZQ-n9$[+r/|>"J}:j>D)?V?nyOǫEa'c<Z.=:NymtHڿdɧV~=#$-q-/RNA:?IQsǢq#Q=5>ne`zj>ylTKV>X?]/_sk9ݿJ珎s_Y:uL_<*qp)QEsKڧ$ 'Iwk{}DQ/qة߆!ܟ(uϥdy>JbTם'Cis/sA曹&~wA懹'F4u}u\ui\׋Dv )W]<-TJI6O&{Ǖ[裸[Syϧ#=UU!wtW%2CAT i#b|mɾe/$<)}@Oj==?EO-Y_:f{KT}hY ?]JzW7FWɧFMS]S^/C/47׭/Gr-_'vD˟xq;YzZq|o_5Oi3N2$/_ŸnwH,Rݖe5+>yǟk:>bjpÆY%TZ|O@E+s*݄~O;~G,~W9m `9lix`/Q.Ip???tgn݋?П?x4a?t?2d.'G|$?] ??~7h9O,ş؄?ь?Ÿb3'{OOğr1Fɭq'wO>?yj8TS6O݊?aOWOş?}5oO߅?>g*gLƟ9j37gğ)˧b˧S )xJ1ɱ>]1partykit/inst/ULGcourse-2020/Data/Axams_testdata.rda0000644000176200001440000022454114172227777021662 0ustar liggesusersuTW7 ҂"Ht#Ț4Ht`#aJ) -HH %- ]"w\w8_xck5׌g_@_T̔ k؏8F88x.)v'wwa؝_Śm "wNj~OXg/ ~!5pqsu3Qk2Mw/ \!<5?&VuPT.g/_O;ۃT*ڶ.бp#DS9^N$[G J+:^GjC[OOgGMG+jm8&?;m1`%mq ?u;K#󂳗ل$wqtZ.~:Ǩi?N0v-{%zA`rA-G/O̎?j8b c9z;n|鄽~ѵw`Qfb``uu01 j*K_ H՘^:/i;x^LAk?09lD/#Qsr2-[,<~UX+z:/ݰe1mLIk{ߠ%wHbbW@@L{9^$~Ǘ畿mK?y Y{ìӟ`S:`308#&7  _\/_ 5qԈJIA7lN?Qp۱4jvzc.].$, L+qEl_ۿ$T;Q:AP-g\z@8 \:< !fퟸ:#c + ]0k'D $a J$ATw^n"B{`r~K֮k{yǮ?X+Z>ak%X+Z>ckXUak5XZրF5a+֚ւoXkZڱց;?s:{?_,4߿-͎muI> ^f ~yA-`ę#| D ӏy 'xfL}_>Go`([vѫx?q<ΐ@1׿ۏ~(+ȥd@.!}>k!@K@C4@{מEcKѓ!2lU)IG٬%c_SG g'7<W[ * Fŋ+.O6,2Ò:ZYK :#_(7 -5e>~?% nϞ:>cFD)U1_BcPGˊiˡt^'Gշ]UѲБro-=^8<"o  G_b q^y1a&f a59Qhg~+z  Di;*Mjjؙp/=$CM^y17,돢ckmgU YTkeywҹюhچorQݔ6m'T櫹ݻTԖ2W [Tvu}x앏"O A]e41Tol{.9nl}A#[8j-o[wzp_l"6 P{L o; P ~Cf2'y?{pǐ(UK9-TT#'ﲖ䆪ΛiMV[[Wtf^XIeȫ ^D狄#IQˇNh, 9\`L&)⤯ >zN_\ J1!}rhޣUҴ*+7esZr7BsUب;!J4\<9RԊ8>)LrӚxĒ!>%",Nv>eQ^sX\hcZ9ϻ+?ۺ[&@!;Lb~ba|,U@hp)HJ#/MEԴ~h. LJ1a9d]og F243]C][bʗz%auv<._] 1DQhO ^pQJq_7nRXբyrC^HBxNţeCZc@:l8Wpo2rt*8Dm{wL.i_4C[ ŭѤ\Ƣ/{Ko*.q-$LZzaI;u];4߬,ZaKi.NJy`>yUM/ ̐>HE]<K?lԓ2n 3SZ)b$M>u+AYޞf8](\|؇>›ceZS㱦G7 /S1|RGqL;V'5_BxȸDb ,-27qU+ (n'isD (cᮈ%$SS@rIh,+E}|9\>d $W8G+9XY3sHUׂCtҟ\ #`+׎vڗ]9~P\zNj&O&;ސ+kը%'\@b(N3]8m;9ʑ՟aM)8+;4on^JPwv<2tLe~pdaGZ(Xy ;]2X]F xhČѶ@J3bwvhNsE@+xgHa? =$cΥҵQH<ܘdݳ VDh eo\8G^XjG LQ.W0 wqjd} 1oWe89t |3֌Be|HUCV4yKC~E<I4Cy? ~w1}pQ"YEgH{7.Vȹ,'\c 8#~K _j7,⧳󆨁2 P&Цzʹ-2~3Ct1>]s6逬E;Bm k ߾ f&ǀ Bܔc TqoE kp0@{\j?qp,\8٢)3S>ם! pKrb`.I)Qo ͒x ltLbVoO*?P$۠|טGm 1IYJǞdfdUi/{Q@{?]2Ok;$8dDpJ*|'1(hLjs[ {&#RZMרWPJJf+Pޓ:uDNڂoS6}U { ʒػShߴ' hn1.L@k` {}EM7`{A}d?%|hu ьl[<[\=^M$"&.J#GՈ"iܒGKhemr4%->Z9H_90t8~vq8Mpet: 5~抦nz8-|?+˨{urd.dᨚF>1x82!`խʫ;_+z/~ɱw7Pکfu/8]Ш9~~D4>K[8i Z~8&7-J姴B9JzhG ۠}FCca d1!}gbT_uhXgV{ OgO@3 vNy%1GcTϭޢmX'"!Uʰz.PǑbZi(t۔-S<儦uo@kLITx?j_hP;bӼN\F'KvZxC hf~RS/,LB*'/#Ոo09„t?'DhG"64$ 4TQH14.70Eݔ~Zސ̟j A"nE iha9v7 uZwGӤbPQy?Ȣ//3Akgfnr /62Oۢ'Cd"ʅIeq~d>m=?v j-Oq ixJM?x9 5GrU:82 h-W6`FM>f`=ؿ >7)|<U< 8:o/ly .BQ]h'bP h gСua9o>Mw m6m/€:|9{8T~ewߞ{= $u@8*FE/O3Va1hzy 5Qv]64*4s ]vPwof߱{{7hS{}4}u 9> 2Ql34h8-FxGQ_@3ooE?pVP@#g -?8񒵰M|_?_[}-HY4Y앎 ar361JHr+[@O`вY&C]xoT@h=WTuxM {\S,~o~m֩1c9t5C+@'}, klJ_X &w跭/(tZizd{eвGh)1"V*3|wKKA;B^MDf¹7Xz3G-Ez7|1mh@;t@ƃ@ im'dE;ѹ;ܩ^E<2|ni֥c@xc{ۗc.O>a;!yc4ʦ&[W#OS^ZwHyҦ H͔S_#-h61w862  ?HvjV_?*θ xW6萶3## 5}K m3ߝvyV'JT7.V&̭ʁ:W" Q gߓhl?U%>㒀TunsBC1zY㴀~^xva֮ݎ_<ؿ+rৠTu ="4FMIWӽJP_}|cAY XuZ0fN*"_s0>Ep-̦QFxZ"ɨoPfi{:2.YϪJDUQn1*Pڅ(FAK?﷜YʛCv=fEJ,B[|?^FC_vL2|UTH|Y`|E#>7r Fj2hWQv)W߾+ы&N^c3@TQW{3^jXIz /գ_t;e8@zK)m}nyG+Ck higc/3PTT<;VĎ6?ytȨdj~^Pw j.;C.] FOW[UgwB]yNFӁ^%ͬ~#F㻩η/2Д+l'ZO,"D%Qv/ z{EԇJ@eU$1~.Ũw h+*X~N I;\.6y_,RRQm֤ uы7 C?C- s(\9ю: nn#[ Gk-3:u-絢b4k4$  ͆\؋3jҫ;fIo◐*WO~}{>-ދ>z7GՁh260w4)w[YVsAGHKМpt'> XC3kn3Txڢn(넡@t'Ψ}y$⠺~mgkgGdrsm77PG0~jc<‡_R#.8SE&PVϾ<T:z IrdF|UFg4@U5j9zˬ2aX##B\ *;JYo&k@jP;O?T;oSGDkw*KJK&fqn]=9tȜ-Z$=7=Z$q md2ZFb_]`g7dupV>m^ _zl }H"s7-s 3w9 Z$~Qz@^B9gيcfܖ!:-j  D[| {Ly^EK]PThɮmuIYX!Hy.{QJ/ոQ);Mi*je~éP ͟bUDK9{;GK;޵!=ԯ_?K \ϠZkGu1?:آV=,ҔEYa}XYp[K؁g!pW0_XO v Cզ"<P'GSDh<Y$jw!ug7hSsP&)(< \ mG9'D/)kٽQ+Ԛ/*l6Gޡ7#عa%|Tϰ(A-_Um7$wPw3q%CM]Hm[u70beT|zu'&9&[~έS1>C}Id%w5!)WM CUzT(4F0#+ʣ8jj@Irjગ,_b/4\HoW6T@D U|D=m{SQHYryD(U\x$Zv3sXn+%cET7f${ e":q~ET73x-9zpE/45.~W=?*N T6PAWw`m3%eNYmzsY?11e'*"b,N8ĭŅ6mQ-P(V2@pjyeh O?dhH=+ѻ Stا$B:D ݪdPۏwb!C [at6Ey߶<ٯb"o 2 `+k}JӳE~a&DY{|r9|/\=~ e[i_ {} }>L{{=?=PCy VLQyAf )x8ٍRo_.ߒ]},⨾ODZ UCYղ]]JD>F'[ŏc}bl2lĎ!^k MA1l.*ytY,1ʞϺvF&ʦ:v_^=>=" Uʒ(pª )^TP$+Us8"'Tԯ<kgŹɃn3_}R͌J-d<{K(5P =ON 4A{N^ݘ)ZS4ss5r ω^8>RiWrчÑ(iͪ&*_խuGRQ'P(\ vG9O>N}Gy݋8ч\(fh'wv[v˄99718;k>?E :{P?ݼQu1я*kq(U[{P5o%NGPC2,$v q:yosCV}2RE-BLs9OW*"`IH{TʕQ Dķp@GO,*kքNOOCtEQm}&Q"vW?=Ё2g:ٜ q'zyksIkeFڡO.5* OB~→3CGcsЀcy5eT}Q }&&\x4wF,P_IGJsmqU6KJ x\QmJT9~wX0_mĀ*dPBvF>A\vB-l[N.b P$9*P­Uc/EOk>E-eIL/ޡT7rQm.ۚ;rwҩ@Ji,ov:օSZOu>@[s=AlT}I7(\zJX6C~ͧД)޼7cיP_[L1E㫯2*Tq OM.:%7q g^غނl;eI:uD&J#.} *m~&K EM1 P),*mǿer"MQCb!_ f?7*뼱k1iJTgeދJ3~wuңd94ʳ"iMBh4KuJb`2Eq7>5po[?r*~ue=: ~/fW TT}7lKyݕ/}}Uz1|ۨ/D_ r{x_shȑT'eʶz{;3M˨DىZu}t'F#ן'KP|!ۇWҧM~DUx NU֤OKd9jlz̈́O?0F5tP #M#I 'Z0.@3]F:w*x/!49f]*÷~Tj| Fb;yd(gugd,p0]Y2ZƬu{j\6?""4,h;ED_cTT,TP;}A%w8b0*/x#Kb+ 'A_βgj?cdjZc}b'ܱ?9j.C]i/c*Зeo6VD_ˏ u&Yn~"NӢ>_jsؕ%>~Ȫ EnH"LO'VZ~Dzqn(J>b1nFV'.uS(m֒vM&Yw * jnRϫ>=׌twE'M>M,_jRFX^xJS*xTbouT)SZEٛ:+9~̍#p`W<Ꙟܪr ml/w.;# |Fk_ejɹ&QxQ1تbQmhdR=zQ!Ty'Sףw,mYC:h3"ѨUU>'J" in/4Pgg@w.<{nwEL@b#2tZE? "vQ AC<(X5/蝉Z[Irz}KjҝLXPaF=jUj?: @MRGwM?C`QbY͵囨}F뻄(jf/khf+&oDl7K;Y7;CT9QkS>J*E= nZG ؈TN9l+y\ЫG}㓒hlF9ց$',}qVBc4j'(Q]Ef THXzKܺ(2^e$Uw}u]TnkCi!p_cZUz98(_tO1nzQ,d>};|?v>-Wk3Y&5N=V]Tؕ1`=tm2D^t!HvC2/o} b-Iّهp0ب3 ;ITUһGYYr&~#ZfER](y0l6hA.`w:J\gh]vC:H8{5{Fhz/v~(1o n[k\ˁϐ4@M~7kxa\_W~n}fиE8zu'8=/`+ F-?D !6X~-I"ey#Q`tP<˼ -N*TeaZR>v!4-3*%=ǎo #bsLF^ϵAaz r2>X&p*ވ3/?Z`B? '@u[PїƗfz| +D%dޢAa.HVB:~1Ku$zdfT9cɮĂsG._S+0;CtJS| "}Q;?&29\w΃6 U0!M&ߟP}xeбԍ 'dsAdU vҺwqJ-D \ tobցLa^5gJ9(V)|9 πCt 88\5t 4ꞏ@ 8^Z9HfNAkW3+ȡegԨ+wؕzD Гo2GX",oqh,%s{i׬Z==mC=Kzo<ZqOa;G9pҎEJKZ灪+gLfZEpAj iH;C׽}5C@ܢ)2vafQq@3yK >]tl\X{|)&0fU\1 >}뾮P@Aڇ=u'|V K^eYh{E>2w! ȗؾlj<ows5 [@oy0zފ{n@R 1X! {`)}xVW(}I3]s7@?lwfr]g Ul54s-[BSzpJE)GhdPfTw%z&C"Zͱۺ4xگϹ0pm{߆;~ݖ@Cf$^ <%4 ˏum^뵙b`5f oNt!@dFVjdkx>qIb`8JT(DRh* SC W oz3hG܅+pZc"  PWچɽܰo@F SıQty^,NNwsg gQř~NoI`yױh" *M~*1{t1x%@٨#en^e{]7igK;S[Uya o9Q[Bovjx℅0&UdL2ĝ:kW@^0UEHgK\c]n4:6@-co$-EmI\~hl+1<#!`OaHf'y(IΑڱ/|d'U*A=˛p"82>}H/X?NV"U`γlU=VVjP>>Bٖ~@t>}GMenՕO#ƉFݛv+4 D> ( g G0)UpnoX<8Qc`x!;Lc`+ {[>`V CU·8@9*_̼g6ëA/hHde3u4_{˧TR2!yd^#h>YwoMã$o@S5hu-ڏwfAEv3h1L,@XS&SdO@ʗ6] 5: bs+D(dr#Mz .yOQpn5kO9 [5vӝșGT:͆N>#uI2pr"-]zNQxMh70az,VsMpv6[.v.if&ՖoBr5[ c!N릗3@LU F*- ^$?8HfM=t\3 M}4vZ GiA0E(N$;)\s_Aj}8Bȸ0 ɷ=KROPY7ӦIM^ךЩ`f}Rq\~ GMO<v3;n4"~9OzeeAa8-g2Gd{S&g OƝKrDk^kYzAKp~昚H-nj)s;:xmx;ϛ7X0}LyR *mNQR9Nug~/ONv zv9okb!8Ku@^S[.p}/o km9"Ҫ%uߝB̞ẁWzމˠL2;_wSVuh.hx~`:*G*+#RqC%g4%rW@ݢj@ 4E%wK^Gnj,& oN&Sg-8ˠRq>@Az< K0~f|dYФ"w48'"kw(IJ̤+*jݦM3AQχׁeV0~7Ӡş] 1nATkkkv䁑yy}CTv^rûDsm_ Ȗfw< ڄ'n2KH< ipx)O8L[ tj32x2e68辮ZMr_Z4yo3 QÇB;z_#|U1lE([^dx wCwe>,KB0 \s45ZC( Vזri{, lfcTk OQ+̗_@,l S9 2gQ-F$$EO ff́^{W30?et3-@sUĸ ȖgejvKvI0`:B>~U{[?yn'hϿkRYūb#RIs>Ciuo۴A`FD )S}~E:B&EVdqmA*zm2Ͷ) bǠ% VZq`t>_j?.S){ S20J}f 1?n A`ry8a}zn)HWxցٶޟztM>{<fao @B}/r<(_9J>*ԑAy3X`|X͘LDAd--Sj!(ᩰGTs/&75{P>!-M&~yg]Gw Vۇߑ5>@yv8|3@uUE\#W  )q<D}T3xdU:(Ȥ(Rij<)ܑ\ }C@c ўhK:; @oa͹zTk@v>X:1voɔ/5?AoC>8*Ĝ>1n% `~Eh*-GiQޅ/4vSC] yfni5/+#iROCu_zgI1 |SSrSCcy_f\j`6L @vҦpƑU(ZPDD-X_d O^z@+vP¾<4KÆh܏~X3Br+|=]@pdXN_Sb/ARLE?SWGAof.^Nko{|4as ; CџAî*.V^3=פ%vy05<;Ll:}Pa|م:; 3-k[T>kpTk|r0%}3b Gx7/?r;ܤƵ"^hNqN$%>K+@z ?|8|Q0\F Z%u Av">YH=pYqqoȕCǘN'{ leWnd3V`a-Oq{.>E'-?+qDo/Xp&d) /Ϛ)72kCyU7$OX>Dsoհ#Z(sԒg8ً{+u@x;;bլz[  {I! =(<ׁs2%p6G7*g~AK:|v?wAsu?h! wLSC8U:qW0(hV*dKz?ߏ1Y%xs qI@T%@Ln&([uΜ Hu TSϵ/@I,&BmHQFa<17-)ah׎|F)TG2Q%\= ˎ;S}q3C?Jo7pMrLF4h߈Y"Fs tj'*;_8>|@;e$^`67y '2WQ|cH. _IF۫'Ԥ@>cfs-) f*pMl͋Q "_d.4@%)7Ѧh-g=!*.;.תk \mhduF qsIrp3Kf9Cf{h򐕏qQyLqU]8,2;-q2 N'O&O^  322sNɵ- Yoα=h]!B}=w f|+ɯOY8tOՎ|:4ɘ'ОI^ԣv,%Z*yti2Z\>e>H}cYC@1hw ED=+:߸d@Y .͘}ʁ꾱:ovu%k% IdY& zQW-4#=|7mKQvlX(B?@Y%JXG;ЮGh;5.p-(iQN!jjTW J t=4C Jy^= 4GD~A?r(8&мdh=ֿ0#lm%#nдaES[ƃ *Q}~ n@;Zr :z9<&]xWk-1o0 J#^^6#Qn}5@-lLb(jI~kTO1y85##@s V~͚NZVΡjZGG3`d8rЏ#[33P߽>7@dQ]i~3Z|jǼ]m3z{Arao4@(P XRB~[f 4|ayẆP"h3 vHn;+Nw/D3v H`oN-niIGOh&RQE;9@bTvt;|<= `~ϯ.}-)|Jl_HdS45u?XgMBOQsݖgJvȋyD4!aWs95R0Zsi6?Bhv@B~%`;ГpWhbc%Z)>psqvzD7utţK(n;k\>~?>*zR53Zyu4rOjT1zh>wVy;FT{Ec($IBkmh>s';-gPCKǞYK-P,[te~f? 9/Yʣj:su}jF J_ޡeߨQWp#sԱqFkkDk,A}33vŁ.õ'2lOkjI[o[z*Drȝb5߭imSI:ǒ|;eߡ@?zR~:0wqWԏ5cɨ Wx/x0Ԙ?ڤw߱lof˓z4Î#>5ʜz w߿ +/ Fli E1͙!OC@GY?ѳeov#<~q^V]ZCoER.q0?W+yi=v=b5L~ÄYj>6F /΄\|oq/zDt }걷^Ϣz<8 M3_Rʚj~kL<1eS^?E6:7RR ^wĉ\W,<8ʝ8 <rˀ직1 _6^wg0?yW*SFˣ=li 5q,8j{/"#!u*;x9m;b9[ԙwѺ"J#m_ wAqOyY@a> ~3a=5[j>OcNB%Hi.nQ25z%&O^~3GM1}>/c&_x po.c$kS68z^vs@lK;=T/ngf_`'SB 6o{;*<+PHIp59z~GyyY'6mztNx+2ID*pwgWS$\{w3XlV 6^AVy D㲺a)P2eB~w_dk |; ; BrߒChQ$źaW;tRO \lp4uV=,89/M9W},^BSs܎S,_GJbrTsJ(81Ou",w#NJ +CDGFϜ$NK}~_<+rhԆ Cƒ+u!gBt-ͺ"# ;p}.*lv?c9஁/XEvHYܨǙ?u"& _b\0| n PP!)W+|U7RaNWxKȄ Lr^gcЋAɳxE]=V0< a M?ۺ!,![[*y}CgvZeo.Jw/0Lۏp/N0U _\Qo)!9iR'kou/Qbpc/gS0%cj07FX߆O.zUazS DϮfLx*2It{MCJ \ԲD@ӷ..ce*c|[`> @c16\)7㫌7 "CФ 2=/@ 78.sFЫO1K-pPu"26dz@~V8hU#s=@pgH`> 1W}R'J a0{6S[op// hy _۪TŪh8HeMX>qDpn*q)hX4NC6>yh;`jv3Z^pʍǁNM`tme|Iv%n;vTl^<#rcz _u54NF۩. ꘗLrDx8OR80e%-evnv͒VnMpsY$4-2$9 xs_eI3md43IVY>2\IZ{XBHZy% M{=1;8$e\ڀ6[??R}k@ uo*R rP BN27ݱ8b)S 8sU]֫L.n8'J$sp`iD<: WŽbg+@$cC+ˉ1M&qcb9v,L 5uC4=Q<:uZb>4]gbe5/zԇI[WiL>bjhUyKO3"ͦ@>k/ tc/}Mk%QXg6c$?F `~٠Oh1Sze H7גiP-y[^o˛ E*81_zro\g'P:#]d*qfo@yNx(K̀m28+>hrk"%T|2}R.z( dXjН^zB`Я/3L TFG8}_l hL{?ʿާw?N >-Zw 7%.^9 hRY}s .._u.-=2p_%1hu6:g;2aP>l.uWzF'a#W>6ldGKkFmY!Zfʆ|[/%Y'ViaGl,E=A5wGWj[3$/c>*}f&S^?Jb4p6_Mbr0H*r>l3M]+Vr15&c  ٢/ XAhaL3Y`cEn~tv'2Fɡz䡁Xgojsrz:IPبL?Wlu)arE{Hm&mfKeL/_71#G'l԰[/YFӷ|IhNss?~c"iǏZ) `O Ch l|d ltfƏzހ*AMLg'azt3F5mbVnlsF0~ oz[L2gL~>giOg8  `??gC 䰑B'2ݣ5a~L>5OÒnbH7`r{HO1:ŞNg:wu8`xl9̋#Tӈ{ _*,iF}%"5s̏$YܒQG4Ϙ=EޟℍFڝvL[/=cG$l_ *~|oJMJ+K>U3dO!w>̿{b8*~v? 6&?3c:Fq`cGٞ1 6znݜFv {V#wQR m{sXCCl}UͿn\SǦ6Q gY%Zx4,P:uyIW>o+%z%&?ϯre{31^?@R l{$X>~a -o[R_ a-KrNя1<*,M\rŽ|OR^)͢Vqs0\_\71uz$bi{^s,?a=:43A[X[*;=zl\??f#WO& rبhڎ񹀅qiH':bM_bśkXx5w?ӫ,G5I OÕb}Y=O YWg(<4/>'>ߋg0=ǯ_->ٗ4A /JjFwHU`w2 , >to{5bQൠ#EF0{&kczXKuc|nHۀM߰|S˃K>r(4v'>}= ~$mcz%cvFb86i>(c;3z 6IcTN9%G}{I=dœ&RVgSyvF,Il_6A_cV$gƋo[X>IG'!1Qk3; {\X=y=+>`o}SmˠDmԉ[#i9 ۧ?| ȵ6i( GS|aiQlU҉bk}{V6j1<$2.`b?!,LZԒḍ:ljKcryK21/P>3xQrߟdg*riQG8y&<RuFS_afP1h+Vob~E {iX H۱~O' AZmP?6vNIJjb^Y3cﵺweI/.hV 0=WP1+uD}b &4ɘx - 6]+ ?"1rxdN5S͂c; PZs5D#/fJ zB;~*o&2;,Dw0h*'G+Hub Vq&hks\\sWU/˭N"i3NW87:c6I|dV ZIK*ژAu6 hD}ܠ2pΦ ag6e^k*g߀uQrG="r qv;w'9njq COs*Zi|#Yfg}Tr>7Km \õrP7*5<Ġ3Y8dS℞|- r8]ˏ3p$aIPA6=dA)MшyQMܢ*'}A&\d31 1R=JZެ< )TM:A^s"* ZZto}M龊Al!x4voމ;!#Ag2ކ4IAIP^(+w]"pu*21T=>6 ޸0K3 c#-ױը["ΫO}9 /AщG h3D_(Snbi:y$o5GfҩߪPIo5U? O޼HiCm: QRM2v7@DhHy:1xPT;Iͧ q^fW-D< 2M7iڶn|厚 ;n鸸NWyTކ3pʻW$*m -N䲟 #pr,L/]@,dsA$U\9]w@d!֞ZRrXy5H~ \8րl < r9}8j9$<šs_ǣ !9+O, 6 2&1+^ :o@"${<"ӿŁȇM;mz98YFč;AtMH~0!O!3|nU^y @UNoqc` Į% (g,RHy !hXjb>AOqJ)nуЊ* 8wfΉH)]YZ?ụG<RZN3 L{J (>0 zL0囚䃆2Kӄp^ ldkZ7D_|okW-R9R #A(D/)⛃TN[*>yZwY8,^M >a RtKk;.=<֗ wL *kDo1win]-3bQ܇̀S# ;/IHzXA[3FauA#Jq ڣiH&!{qQ]!9HDّ$2"{イ*~Wzq_W29 ֋l C?!iՀyJ$N9sQU4z0IGAIn#-'ِDV%H$c-5b;!Uz=Ha޺mp $5}vh8QeIE"^ _HXl:$N^ L2ԙO; >!FETOI'#yPgNק$@Sk{o?]3-fk/H/ؑ@(MEIhGwZ<9p>␻vpm97Ez'Z ITX@l52 Hԯ)B'Wa׶b-C Px=$(;YXX8};9$7 ;4Fb%T1H=V.y\DܛU}ifUSq[:w Ht" ڔ[^H< &熥K$PQJ]hDdȍ2$ vǼFIl "K57;֐tpM/^#eϟ:y5 $N)a^ib /8@J,Vt!SZo"/gkq ![Ѷt!qGM#6XNpb'v_8g$W#ڈ8_S\Tn6$FVu_W✜G宽C8x m[i_{.>N$F֛E?( db=nt.]ψ;mػ-Bu+[)Kb2~x9d=jyqМGܹs8#N/T zCg bY74|oUF|4m^.Tn|GZ-!F$r"v\ Er\;*--2E@_?#8;?p($0D<#e2w["~cYCά"2b?.G#`aH4B j:D pVQ_ZFBAC嗐h#})F$Azs4dCbo"i7q$h7T\ȵ3HԽ VIW5[ϗ _Y_C\DG:-Nu{)JGc*R>Q-y/%CY~ \Eu.[Ol!-8zkN?Ď=~2DRN(jQQPw"Qj6ӏz/0_k7}TK $[2$`:[N#sE$$E(hЏwhrZfA'y)}aܾsIZlyzn ,ahtKe]u{3▀N_̛.EJ/sҲIytN$[q\=FA17^zd/Dr dsH$-#$*2 _`ZiXl!rV37$nԄN?֫\$x07ۘհCr7ʼn?ɑ 1$`g6i G:? aS: ;ܿHT鵱(` jl708މlCGZ ykw$Ysn`Nu5D"3Ǒ_wI]uB|"MBzJrCLI}|{cϽ]瑔]Ƒ}ٟï@FуN$1~<eX^ECvY 1m]; jvq>#U*@bF2S!1Vv$}x|f:Qg ~2#E0qx521 }iP# D?c}~C{醝lSu5!3{ <bF̄eCO60c=U}n{aaٛ0&rⅪ5PoO侈06JTF= >3a޺0M)T!StPdr3YZi?6|hx~zpRGϸ+5bT*Qvs7x_p(tEԯdHG;Lњ JYn0cYo#s0I> Sq9dS\DL_}X}9x3??L9R=K*0:riU-֙}hZg30yzpL8 O1:C'[j;_$U=jʷ/BD:͋\i3O.0J{zR zJ] sL =tM;aa =r'` Qx3}Q~h~>86B?ˍ$aG]-q_ 3{V\ cA\PxD0^)3#ے|0X5( &>Qg'0xƷvkœLrjMoX!o`F'Ꚗ-(hqqgE`c ߨUZw{{0 &Zh:a4C>7ֵ.S yIzr%uU@\pz+0Bm5?~9 ݛ-X6&+fnhnE- UgRU!WYohM _sSHQ-֛5`H_h-zݟEJV.$2[C<ݗh-5ǐ wd\S #k'ASKK(Ijq\Qd *via^x o-͆ZA]]*KE,B>Bex|sYI304sM 3e:ІϒS0W(wV<=cWmF`iN[b7(kfa܃gM>ǘ.8݉"yLP4ZIiV^MXN^|e{8 U700@EX3/zOf5YP Ն]B_aG֮_5am5qQvOg $ٱ؛GEax̜߾s11i᫾ 0~ Ư,`{lgī3ǦayK_F1|ao0u%gs/ t`8=՝SDwa<V-Ba> 槸ރC#UX=7gwfs r`[/0)n 39j` -$ _8[v :] ]?yWÚE̻<5TQp#ބ{BgcUwygwU;{PQKƘB~gaOyD &e{,>qPހ .rd}&˻1ZusyMg' Px)#?yCf ~Üx)+dG_{sBcw!kҚ楝FT'*ahT{cX&2 \4X twtW7Mh/WYR Ұ6Wƙu̍G0,p 컯uk+8- 4wan? j:÷KY\WC78w~nV9ӗr%?}8Oh0Su%UYӖBCWsGn?/̄ wg̙4,bcXpJMcТ_fJoP=ϓçزQx-Fw|J-;"ao/AͥcI s:/x \̀> oܦWҍ>4',oC #/yq2tU B6ֻ!m:8]IUd6d_VNxpmL.hwРC~Ҵl r/1=k箠L'c{ ٫g*uBxv!Ѫe Jxa?]f.)d;Iqu׷+`BvVL4:y"!C!Jq1\jxqYYq&po*S}s* J̺NNJ|u:z{|t^.qU^H JYңYB?Ns<|(IL=g[ ^G ޡl}Od34㷣 fzAiP#ex??=tߔPxb7Ov/KgIIXWּ˪gʆ` Х.DP~5NߩT|diB{A Sr#$x~>\zA Zy^ZA[)d^ӸsAegÁtb.:|gD\8Tz|$υx RфBMj/6' (j@硟5!D|oY(ˠeC]iI 'r~J _w7%$S} #:R^td |o1AKؔPI'g.1 bDqAN9W^xw^yn$+B/1t6׺ nO~relg7n8o?OîMR 1~ F1epsy~Ȗ2*v PWlo<֌qC3bc<BtPaM[G,gW㍠[ޛk !  WIV E7AOpmc #8 a} 6|^^i2J&|,G9܃⪨,闓8kl/] 6GUI倸碗gf+EG<(;.D.P=#9i#;Qސ mS[xH'r[c~.3h9d/AneȲCn߆sTs-?#NOh&Fze4^ dE  T ̯Gw#,kO~Եy?E$ @ c`nVF7Cc`uX'%u_=[p0["q8C{W%7@?n0 ;*WEt!kةDJ,x Cl;rKr2*?D[H\9 T_ T Kn $psxsp}R: eS4h [? Z,O# X:efxt`*Zw;~^C|5M`ʺDxl!m<e܂iu0]6]p[8 9v~06,΅z2YcPwܟF5w!lt?UK]|J# Zj8Wӻ>{,a^px<(@]tKP~Fw1(A/)+ ;PBUr77_=aJ?Au9 vY50hO>~f 3ՇB@풁I뫡)|l2N~|N𽆄4! RG|P'+rwlpι N|C>DWW@5ի`7{]GpfFG)x1S"$X\ ANX?@;/1o3FB♡^apd[1j7_'OnBI4$1י#v!wEGڊsSk)&vFNA.|e> ⯲²Kl+C&bn<_ o ]f6R.b/DKHĆ#X=F~h`ݜ"O OA}Z[y~PMxr6K, 3@Cq^*"y匼L} ] ^ HYyNSi f o`|yyS#<>Xf 1\e)_gVo6 )=Ͼ; /~G{JQ \ .ij2TxCvT77wY,M-FGG+Dn}QpQ˽8/y0boDŽޟE9󋊠8R9CUsֶA<9/n][]S𘯋NFy0>};Xo)yg k1f=ÃME%M< ~42-엸/.!a0\{-6C >Hi)uۈӌ`:`wרֽwu6z~8Ϥ_z L -'ٯBpCڛ\V8`q#o)XwY8r;`c`xUw~<1 v|B\XtP4ľX^YG ǴAvnw#0g{f+F: z"@gF [ zHN=*!G??}ڙ 빬]{r3vCEv&G%5+gRGBqZG <s+ʍp.mXX>e')~nCՍs\9x6w} k_+|~Dt<ޯ䝶1J6.w%jp`u=j~|$ֳ5E{X@#[t{3}4sJ( X=l̺\8r>;_^/ـ֪ܪmG72Yo`OEx." [{G*6<\YkI=~';-NX^yT%#ѻ,t ƀOVq0(%|dV_K{E1؛o}e@UQx- qr&XJ{P>jùPd-0;B MdVysjo2ޱ:Xq^D*r %PjF{m3zH$K| %B_m톔$XpK7*}n|nW9Ibgwn(f2m;˯݂AoVԵ% Zq64;?% >Nm}g!Ţ#VrH/']d?< j y:wC:Y<$LyUɯ#d2xmLF9EVנ˝M loCzG^4dsr@D|GhJ|AZ~lz4e\ TVuWZo2ڨз}{:T8={Np  > o"k`BzPޫm/XK[U2>Hp=i9I9GMh(kڥg1-+?AFm郒ڷO.4&'׷I,JB[K'}|>-ZdOm}Lb N4sBs*đȃJ] qӧ՞jՅO=l3@.q~N>}r*:߫R2pp{x7Zoxӛ/j Xps).&*/C̴8.,/Cqt0Ȇw*䓡vE)I)߄'~UBDrBe><aH Px.j@9^l}lKEUF7 p퓅FEx=}7ivO-ƑIƧKpIӗj}ʮg Yb֐_4r=X^')5\J?DbVWH4=,KcD#ۋS Nov!b{݈ MY12W"-A/?gbcKYD:uIAx~MG$N;F#"dDw3n@cfaDKrJGa%)"ob 08HǷX} "tF}@>#O\Þ}=.MHDB^ax?}~{_DdӘ18Óy"J(""}L}J]|l!j t3"5I^c*RHǑzd-"WNmO݅HgCI4#,"&?(| S-ۯ"qAVi %MxݏyRA{"bn[yW"qEķ u`+\AdEO~ bݤNq mgR^ʛ}}HKh`(A]O~r8՗}~` KqhcE臔BGK"6\dÌ?lfYc~ңBĮ -rD/uhD}L&~D\՟ b`c/DY*[fԨ74ǥ;wDyRNaַx|7cĨ vڈXNxx+=ESMD.rpcEDk?"._l`D_8Fufsa@9&cxE|k|p?:^z UEDҝwxW.-"4!b4fDl;%((xZǤ^R blUsϽW@n\#+=N<XFB Q"b9\>\j> gEjo < }7k+~ct>[Sb?:1¶S>Fjt9x^}qx\qXVsN==O}~p@DNNn?bgRPZD~#׀ }S/64I@Dѣf/#Vָow 9\MB' ,r!ZDD.%S76ttuq=ԋFDaRQKѷZWAD|FL< =;plk p^y8>-nGOCƱL>쿊ǭ./nٳw. 룖IDL^p]~dN!q(?"\7Oޔ;ny_nIicO8jBGBD! |Ii<59ֻ-7|jØO$[Ie<\1܏b/8Q'׻4RX>tEc<¯itcf yWY˳=x1 _yqU3|1:7hf}H[%aEm^:5Aͅ-t%I"#ǥ?z]79؆S!"Ixb=w׃lpݮk-Hg~E$}m#K8TJwa_b<|X~JDda#olۥ1.h0oa}Hƒd|r~'Wx)}ӱ48/=:ӿ \8 D#IACD,hHʞEQMDJ F, )۲$N$ˆJnc9>zGoX}`? -?{!~%7>qqVD2>uuDzL"R"RzJQ3"E2sQA2 ΠNDƶ9H^ғqߜt*#uì Db}RSB_s~X]|bU0pw3wD|1q)9ƌ#DY3kp=dOe`mV>~n/5kaxB$ %Qnώ8P+7z\ s8_d*}`?':^҇H!VKNy|bN aP><.%'&hraa폿Oa\gF%`^|p fh󅻲QkwT#ґv'^.Ŏ]º:@>ב1G="~Ŵ-q Gp>]ya/odx?Rw0n}/,yk[EDRWpJӾ(}*P*Սr@S̾TдzaUTqS7m)B64^S0̓kgmZlք#&T^&G =::yΕ6UӦ_L kC{5X ԰ ݅88(@÷-6hȹcZ'yn\'Un4I̩Y@M8(=H =Aq yh%_zX=:&k, hhӖ~ (Lh`a=ir".C~, b7!OKf83>o @Xv.X VpklfӐ@Ed`_Dю n”It5;&uA׬PcC\zc/xA_Ǡ%bم2>{<;Yg *?: =X^Qye K?n33 >߅*R-P夣C}*kfr^7^4 O8Bf87{E9f)ciF`h],<:v#t{Rwlw 4һyJ"#.OȰ!$/}>1[Y|%T(F*LRYj(?v!@95lIP"xh<Qě1-ňN?q {mNPw=C2[ D³F('v -ĝB5Sw-Edr\h d&qsWa(i#=g5?bK<˛Y0n^A зTu%4Oxn<֢g;P#Gdm)lw4Oa?e:Ӊ>j`@Su|nrt?`ڛDF~/ ˬۋу4%?ȆeӋ0]ec.X\usX W⅁u`v!o={i_ё-u-X (0)0(fzV}4M2sd>TzFtUTv20wm|2UZB_ߘp*u1)XmqZ$ TivaݻH0+ f܏qm"aj&Ky:&YB>ukV0B |sԺBrn}ӻukyvC>ׄ0al2`}l&49'~p|㋬M[ǥ Ч䕵R:į|e(!xn_)%B l5sДt4 meyݲ<­O(>ǚ[?qU6 +"@/ܐ77!exw"PH:CXPLo\tp"" 7־ qv;^?WCLn}8;v:#ۆQUjo5Aq\~>N#O%RT/ Έ/"fைVB CCǬ_K!9|"XsI:j','~n .4kcy?~g9jU^[;9$ܿ,4VxBJ;[s٦;l12"ێͷőmgV]ȶfNò ]K˂ 6q.ޅ惧J5&}q_~=lFC%~Ǩ8:a0Дh鞍㡚\lF?+ }=I9uT.格S<68Qswlv!#;O~3: Α1w]pN/g k1 ]0R=ż'3+Y@ňޣkOdl`]zŠ~<5qPB~^ХuDxg* [#z כ]:R~w;PVn銈E4=foUAY5dKar/N0TCia~ D{>۶.HazK(¡z/ㄇ<^uHZk<֧Ÿ0EXpʻI0k S>~i{gY p-Kjve+_=qi=-[kA:wIO^}3aj?se?P?pϿuFJ֗{>)_I3/ޮxxNQԸ~^椾U> u?p?T#21Ezu1crs3c] eaH ۺՏJK6b*Eqd8vd aKl=/u),k@_fbIY'!)og1n͏\ =A;9c ='!SX7\= >9jȊuhp b]žuK>͕cE ͘o}茼_?<\;Ms퓣UW.s9'} .~%7L_s5x=Vw` 0u|i:O0] .czf1\gSx<Ϧܥwnr"~X xipI>+̓}|RAP`I} ZWqGMoQ: Ƕbݹ;HyyƵ_1nn.c=qck׃~C/a 8yV>u`T\ws1omϯRO)fZY> "~y ?w^3$%+=-Գ;#W^X7E^`au2ø(҅S%>7!ʦX^.yy<}{m7W-O/" Nטoo|4}I7~u 8dcr3 u38Sd.xW~.}`7 e\fNoO~F[#QOcDxbj;N![BoCݻ?lsƒ[ǻqM&UDא5%r>!g'b7:k0NFD ⣫I+(,Q,Ŵe 嗄'v9 eg(bnKyBDk q]-Dh-,3)߭9yץN98ʟ-:㸎$B {pv6}zm]g7\L D>`lA+80( jn^;x AnS"M2$aձw^>=ǯ]Ouk~FDae0ny7 };W:hDoYvIBDM|ܧ"y/w+S>]b:v<Rvx,-W?":<ONցW#ݎAD+YD$4ȳV;?T"`Ol|qOY=ʣX[=+NoQ:rO` ]~vԎX ^,|=,!u&o"r߰h|h mD<p۫6kag8i7_H{9vZ#L >}0`9Zƒu}A”N$7 "mK"2ƒ8ys_-#^&>%_/N0jzD`~aX7n|JQHMgW/?O&+SQMfa Va~$@Ջ?A}3CgXOE#(R6U nڬED~R3L[n`"wZ}|'!q7` 7j Š_@_qpգ`lo]>a>(._ci }x0j.E =1g?3@'+Uy\IڸOo13Y'ZlxЬx^#^j(knSLF<h{|e}5y+P Fl1"ܻo׾a~X\uUrJI6TN< mCpc\ i2mWO޾%87or:EtGeD^fuXLTB TbSWsc⺸>.Bvb̂NWxc7/&nbHU_D,}a0ƻDZ6n<>\cC w}4+#tcVsGmX9yQǭ§p}ZBXG S<YiL"Yb/ĨTZ}93S_`6WRIKoGGEShJ_hU=‹뮩&R ;.XHk #96R#5Hˊ;n]yާXwľNv+)ֻ*#1^8a0iI?TV $x.s7":,H~qCL_u3eƓxƟfQkZ9Nl?qc}%4K%ar!E0ѡd%x-]lp }KQ}tv:OZ;ipOwum#`\+R|Oa!1xgi؅s]PxƉ*;+(Duȸ0Ra"^ K-]kܻxN~}ۂp`; S +\b*I8g˫}Bߜ=6W-^1mD|=|9i#0M<ӵMx_'}} 7SX5i;]#bp-k7_>žy!{+a9)ǛW+%8;(VTu_ՀſoW@$],kİH4XV~b>YYf7lN<3[D$QI0"ޓ{p~#΁s !Լ"~Of j-FG"NԒ]oK8M\_!D94urz'h9g[\(72"e2E$ȽI&N"}*g6Wv'%D9!D"Z\>}g#cq("1kG$C_B$zpDlK:}0%0?=مu:e^wP>"mO9u$fޏ8?9Ʃd皯/.=H,[xd'>Dxy*"QQ\چ+:~JN=" ,U+]\ס9v=Ǐ N2 cQx2o-8=T>?iTK< 2ќNv84AE?Dc)ʷ!Z\P(RTD2n5D06Nj\xH{Twh\ӟq.[5;7qH1^hq},ݷ_suys׿7.M/Hv%Ƴ% ;Aⰿ- ^:sORu!Erp"1<#$шHGe ~A$RCaWFp^~ۺ CX7T8y}a>a=kt׽>jp5m_Q=ϥl9X)a1Lb穋5װtϊCZʫ8BǦb^kN+#y:7>+Wمm1>2e\;.^fL,oOz«T c߼?9saoX'Tr(dqaf/݃?f9vB,X,sZ@Www>4Sibe,HTh #>Q>OAĭø ?vL-Wz b+Qy[KHO)S$49"gy@1>G>'&c[>y0Íyq^+OX [Ŏ~*[GWϥUns)ӐwapzPu?f#>d{?}R8"?C?(}_;y\LX=D9_s:C:Λ{]q?^ݡ*;әf?}Cu]Kۯ$edP w蟳v,F[G;Ti<1%( X1Ȫ?U4?̿`QX/co=P7[eED컿72gDݶH+8_:7U"ba86~i}slVD$+/Qy0b ̉6O7b^{^y}}{5_T~dO+/y0(ء'·~ i8;}^OD֍]80(m~O_"~$׾΍TbQ }\pU E~@$dnD:u!u%X_ha|]ߏיrV `WShVb~m)Ocn@Pg:3^b[(zۅ}tr˝b<5\9?8wWG$7RLnY}mG7ؗmF`+,tFc"Yj@$Z摇ױOʴH޾c5u? Dk"+~ DD7"ys ÈA9h{sUlnª?*O"}uxs}թ'7D}_I濼avQJ"X!Cx|9vJ߿Nqu-|HB܂/RB$udZ8v̓>x7 = ֫{.x|:('ڤƸ8?ipc<~yPӍbW!lװ OPùa;uoDA@`׻7W@WjQ?tE]ɠ#3"9τdsGQիX/+XiWgJc.Ȯ4ǹ=l1ub쟣mؗZc~fmb\i (]x_[(>y)9| ,OJ!Q8"X zn :_?x:5#cP`%_Dh+|Z"l )sNaNonukCsV8LܜVLļWqm@sg4T,8Ŀ)$K~Gy=<ߩ?{\ώa _jpƯIi2DnDjcD{᜿"C!JHE;7T,NA(:S-JDߛFwPX`:Rb>#c/C ϫv UvtH6(=_0@/}*P.G@<צ  g B[M0 l- h9iIPus<ti1yC̏Чl=6Psה>t:l 7׋ aISPsT ɋB9˃kd0v=4 N1h?:mIzv@҆Ln$ >/ԯ*}O9FKч! &Y$hA+O9ূKέ:2 ^0}y]cPp/:?C g5a1o ]~o@Vm0AN/`Hnj݌,b[NJI:lȆ4B~(_g6JE 9G!S&]+Tq?wKB<|GCn`z" MH\W:HzD+$19F4ӂ0n(۟| >uo5I7Uq#I0'킏­Sʿr^TB)˿4CzߓAAW׬ Yg5>#NJܫ}Vɠ`X9 eO-ΰTEhcbcgiG:jebCr⡞EZs֔Rn586E SV)2|?( SШcY ՛wC3G`SVp e_{ޥ[Y3BݩiPA9d_9G^|kgj^|3 եvPjBOd5-LIPwԒ:ik>uشd|!] &ʒdD94CA^W.,V2_rKPP; y)ϖG JƼߍ ɢ3>TQ`g"=s/{ ~CUzFQTNH,\긥?AQWP|>w8fu cC"-*{4LJ"\J \] ~UPIrw< VPUȚ$GuN 9'PtRը*j2_B*:Pk#JUށW{OM9hyK[FB3O.Sq:b Z>野%y5U\sP5o9 o> S34zވ3=:m }'|`o%0sR$ b|j"dȧ@`ꤣe=«FݓƴܿWȢEjx몠܄bBTl~uF@ʪ L\l6ck=Pa+ԦT^Ku\) JP~nivg3?+zGҞx9,]a0\| ѧ໑0*lqs=$T.;0)Pe>~Nϑ|I0r2.p_hj1? AIaW0[Cf;]X]CS>p߷TUx GRiP1pjK=(UqǞMb4j\Z n[Ch4=ni.N@UhR-T8V2@5|PVFh@Z8 mݐ[.ܘUn/ +x M^R|*Y\.Ae :~VKsGVxG ro(/@z7[ԇͻ%C3.= QV([M1_~C[G6ԎסQɒ3(zSN3q*-ÝPۯ1sZ} ! ZTZszT9`} R/we@E+9Py?4ٷzꏇ;ݽWl?߀3=NVP\sЖЗ (/8g B.j~(Q\zǽh-Γ:@u.W/_NTy}Ǘ f*kzT)C~k2#k~, n;[ۧݲ؇/5jZAEX`E;4\P,lʓIPK}a--/0 Qf!Ej Y/@aѝ: 'hb GtU@M(*;Â.C9 5Rl_9_ Pþ`wg\N]k-l|J'y4U\ 'Se#KSyq|P770)d21/T#@,M8m!"' /6k2騮LDzA Ij|8|m5Hg,dAʦI k]xU-KTZBQ_4ຐޤ_5PCskM \M U?ѮCgdųrBB.(ISUp+P7|t ~6bz` 9^] VsA!{>Pn1o G+2+Ge7o>3fdEl9>6|%{ Cia0yuooTq܂Ρr̟fҤϒ},8EG-jJ,%t+n MB7@}Y;g`"mgN]0 /B$i ϻ#ߚ@g/l۽;֎>3 h. YPZR&+)Vae M9+aAR}C*|aif(Xy+)*i ;% iu OWpgoNmc;"L4v@]Esd^`rٸhPY^{+:;挡sξ +Y}Mh'?+7*ɔqtxXME XC`2#x,<(|u/cZՖu`I&蛫:~FN=|m5>:?ׄwוنY؁Unq^{bAVz ]t' j.PzRUwEV7:]UMt(ks@}h~=v-V\Z(Hͣеn߰E⟈I_WĬ.o{O9a>Jh@pߖ,T;%1aSə:fI.sw+⳶ ?n CTn[* lWc@ɘK5SP^fOlhA~nЖlwh}hAIsu/j|6h "ܡyЏvCǭ1C[ޔiBv#=v;zݪlPt'42ГV,!)p654yIPAi襷;'ts-?65o5`hjh>Ye3oXݲFch,V^}ʋSnS'@]U';f̠ ZU/P):n'! u;;/B$?N?s2UAqf:Q߫G9I0irZ/bnIAPq94׮{}*NjOWۼܢl?m^FII_nto*>1f e;uObړ 5`5/Sz+Ʊ0C=ϾO1 XBWE,ˣ8&9 f{a>"q%f OݼQН|x_ lײAyRCY,fBфPh͠ϱs ehT Et,"Aݬ~ߋ7 Q@#r?qޏCMlb?C1[P&\j! ߚ>YUFBMUdK&YsڋuPvf !yHPB#Ѱj(Qu[G8G}zm:9{Jg÷g&BiҡpKO]7TH&'AO0o?ǞSCȑ4Pgn ˽^~9}߇Y'PdJT%7< ܏ A1o=b}kY ݁Ъ\b0A`:;t(j nݻ= Ֆ :iȷ8t(- 3wStUSP_|"샂Lo?@zJy_%// =a|P"{1uez, * ^ADZ-_'463b[1,&-,_щ3u9tyn|b &~;؊8ZtV c=e}J,O٥,FZ./D Kksg~0~<?#; 3äp|vq#̒i^vZSc0xȡð F0NO5-o nB5zO e@ɢ݇%^'JA "5i09]٤2ŬUxq2d2/GMb/0;#3l0!7Yg ]wɦvOC$Wwޖz 'հT`JGXOenS /sb(y[kuD7pn)h-*{`Qх~]=_ Ce\n`42̖~ zux5e|'Xa[;Q'9YYt-1-gCF&~reTT*%'K~Y ~O{XteU:HCӿ0V2+1 U#c%LN)bQ@?~t?1Z=e`ו2gW07'}{4aot碇)Lz;5Fyh[>Qsif9XA&'j,Wmc.*-n06Н<"[a|>XƵ펟鳞ԍlw`rgO`?`\X$<9À,%'Oi_Yha!0"]zfLi(dtǹ`p;QNsEmMJ۽ff1 +.\K:0;ry[l10D.z;r 3ƕ|*5d8ToV*/S8|Eܾ\#➓Erdu7.˛u}y@oFMi1543553mJIѢRSJ IR$PrH=Z"$?.VqƳcaB`NϨ P.U7&eA0] G/sU`2f(Mڝ *՘ Q;06hu Dž$SЇ;\wmug]ӐAcZ5fSoEHy>&2%F= >| %WN%pJk5Y5fNoS{W?oxå1˷ 8_F?MEW㽣L]ל8ʷXi)cX7Z!+-;>@m߷Cc.vG.nfFG]QrY?0~\!j UJY;w#T*hV~0vB{)8ޞwfPkت;G"%̀؅xof.e6 yM`CV̷i`avM7sZ>6pm?*0#n fBtוmi1o~m]8w]f{g'+|0vΌ 7_-\:`8sX>`r.pa0V՘vu߫f-o;\XsY`><XoTnLV|9K[lyg=s-Mxy-բN%/ y߉!o R/EYP9+ HrnvȄbOB6D70#=!8#xng6`~^НqẠ&O̼XXY/+HF1!VO6HzGV؁~5`nNƐyMZ@qμ㏹`)Ex ^8.۟"evNN*߫R;+ҫ'3eB>Jw.S1*,x*/tۊַ#ff˼t0~XI{^k@͝`]=9k'Xm /:վuB#6ၥ+-;:,B c&ȞgVHm,_,h5jVoM/`|Pꫤ$X.o7 G6m:[/lUoˌCmn#yuXwkn"r-"Gdrޜ%NsGx`\pޠ$=*݆Zm+L/F[2'cd2ˆ/gσY]BeG7,Z0UN1nEJ\(|vl) Ce|nQ:G*'z¬#{<'?U[`E(ݲkV"yi7MQu`{#xy+8Z^ꜙV/Z$nŝU!|4s&iR[*1Oc.XԀ0MX%WK6՟2U+L>t+F:sy`b| JꨄϺ)>c3$>g*ֳ3ކr`Sn8f/ދQ:;mue4.+')0]lZgK/}HihH'ꏫ^( }t-ۭLNJ$ɞomN,¼[TgM;P7GK `E\|ar}8Ԏ5`4`JlףG؄zv,Ҋ  5;Hmך!lw-l:_{.Mo(936>sxr{eWHyt03/ xF54lj^v;bqF~SDݾInh9)]=M@\GDHE8RZ!̄d.h,"(6Ag͒A^c^yZ]@YtdJPl~`M3PK y+ZbKܐ뿂mwk,-J@Yͣ8gƪ3kc@j@|p.)PmR(gr @-q+&Ԕ{>j~R*+DSr/-\=;~sn~;W1׽иcuФ(ߍQ*aaTqP[3Ggd"|(8J (ؿc9]4%;oֶzOcxY/P6UNQe .˸ E'm@$9Y ԴEt:AxNPFx&66#Zzy;nt }kA5&3ssS6b/E:y+eo (Cob\J՚mra Nuq|@- Q8kzXO8<0iVR.]T(3(.Q' l3tA>; Uc@YjO1q\<=A#KgC%hd'~+"#"imY7/Y"`ޟR6+_)#N[r P>< Ji!Y,\:M6>.F/aFJB@HTG%f[K)މ#F@׸@^s>\ (]V,(F>P"@UnB!@xsT} V1aRd_z8\\hB'vA0.{A1MGo|5J|A:(@W`Q܈.7} + J n9jM]*A>.h)rA}L~O2ndOSI:/ȑA'ς:=gJonN'hyt$IuBxEtd߳vc?FY}8 R^ra:f>5 U1f+W^}I Gs0,Elȴ'_`rx /.s\G{}@e-jjvaқcM8 洋f#_4F{'hcfdg,Z ?%@nq> .97@UR ṝGv#yx? rWyqA!7 Q EK(oiS$3IXl.BrYTdDԍȤ5a@IMUa/ d$HdVOj$ByQ<JN/\$tu]N 0t<gx+~#M=nxϚԚрq۵KTxO0sx,xM0pzR+;-ObAQ.hwG^DOLZ}*zH:j3ݎGuOm*K̓Yi^jl =Nw&=<1 3?ּ%3L)z3'x Sv∵3 ?O~oL7{ !Su*\f$!:J4jva4i}lhdPr^dq[A`6% qƖc.9TxYx0Sy(!ƫs0|[n`i!k2!|)Ě2179ەWti듾,Tڌວz'oM0}7xהPϰtpC# $rFVQB RZ)YEnهpRT+Oz ~18nX}T[`nrRCd /:}qk'(կ{]|}tiqH->R#HkIg>)9tg-Vب0߳aU-:5TץiVsAZ)X:Kؠ|EuJ0id.)g|%2j6ap|ZN !5l[OC`ۛ:2kN kR 0((W u21[u2+9P]Cglå+é@K:Y!n9xn9f >@3ZW@ݔ@oEO`#. N]=\%)s:'ڒg -tuQ+Y\ 2CN/cp=/_I*}op\!֒YW.?wo?J)y!.p`o^W ʆ֯qʭU~N`b*΅}UF09 uM :],ތjZsoC@Km\\^#@缛D @뮏^9'_[VZ.9cœ\ɞ zճv/D==WÂ[\[JB)JA6=`x#09u:\ckn9,@;_hS }A>^ 9]4Q0ЖStCc`]e@/'ZЙGQw[Gr>]s"=;+8zuOr @7lܭ4Tշ@ؗX4dϗm@[|@& O.,20[ ]d? ux8l"']up17UHV5B'04 Zt0 *~ x+Ӓ n}ter2[~ ."\3 jF.{j_偑գ  x>Wud~y”D>OLШDl\I sDw=+;e!O)VIwpHaV@T{Mz2=3ҀvL3 cȁR`}㠻N3; @g}WF~m:l;f* b ?L"u`s_q+{k# Ws_ҹ8^#+wү(w 8`Q>aOQ3%ז-&rF96U`;Ɇh52|v#*fq%Ik[B>XAlhخ1rKʾRR<}] mt{>C@{Gy_w+ dȒ7!_{F`m9scevO'FrB OUG==w>zG]~\+-h`<'x_ʳsMxm3/vI z9M_h_΃#oR,p٣Ο;\gSIW\ XjMȯн髌>;Wp{7k:}._V[~=%H`ݷ{8(}?1ؙ˴{M7n|9q_s G/e&E ^o$0/\9$l+1PWi?~x3Qi܂Osw1?'n{ 12\Ƞih%8mW^lr{V:<f WB6``aԕ9@>Hú^{E-cVAfc&ܷv 4m$<4Iיצ(g$OO~&dqA+z2G qM5nֻa=xN\΄uz-ZyI0u_p  GK9NzJJiM}~ޓGY.&uCxP;]^kX"l4pP$iļmS g¸*X?`ᩝO6Ɠds\9Kqƫwjuk8/Īq}._d F&>Vd0Lۣ^Z:(Ǚa u&O.:q-~{t}Fm˰ Oe) 4Rq3k_Ӣ{zk{xϟL~\/Z# o>V542 qEм'{L:7wW{szDH . $a>EMm!9ˤW$l-\"ʪA" &L"wwIO3ID^hі$bv+Idza H}\چ~&6d. ;ROp#IDAm#Ֆg~MԔƤIDV/;`pKl:[~[̛%[&g cg9 _m@MWsYpZO*^!Ҟ/ID|+^'4-A(ۧ2yU﬐=i(4~ E@c6=8ީ40dkF,|9vƹYʈ܁ۺHDbrwHՆe'+(~o2듰?jHKDV1n>Fq~.+{~9d:H˙%H%v.488q2wNi#|h(zpZjFލ},|c1 [Řg's|,Q C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?PL7Bx).O6>aQ;'2n4rUL>*ey=Ґ;vjOH D_FGZ%zUz޵(c9ʿ;J\9随W[dz*g{Un*Xv5Qw֦Փ VYR$@^o5"6&Il.}(]Xmi.;($TfEZ2*9I8PTXnIi>ЬP,鎵bXM0z]ݳJbar1RnnޡfE<6hE9~}(w=Z\L@Ҟ1is@㞢SY#&,w +6Y2sTP`d9fMiV|Z5E''כ^qjwW,< rg4ƻR1*599W _ic=P/@Hb[U$Ny8 SP KPI6@q@]rH$X8X֣ir Kfq=/0}*&|]H R=cY_iV8 8jwU ''֔?=Zp;U啈hǭ&Ac@v+mU;:&'ƂMjEPT(p3PiQU|q֦{`wH'h "wc빸yʟnm9LIVl -qVrI=<*-wH4Չ|RH(\ -Jͷ֔4x䃚Vr<;Q1()Zo*6 {S`t敉A`.Fsc)'jMYd>O=XAO@=sJqxjtaȤoZ^zePe(;tϮjj1)sHǏz$1ӽ74$@FrGJTR=*du@qH0*¸e#zTJwPY254RZqHV9ž ` 'A]|Tg4lIjӰi$7>ܜAnx=*hu\\kM%X ,N7$Mi5 IT~ъoS@0yyxVrӚCwf/ dM4uǵi=O(Tr64~:mpG5U9 fnj6"OZCqlcLRy#H.$CT܃ޫ .{HeHuyS_I:- NhG4,I[ MMC[~E&y 櫬in2(ažu\ poր,ԑ>V6^g 5$$穪R@r Hy֤FO=;ӕ<櫫 h S TYn&.@j'sֳG[Ɣֺ M4Ɯz:~!4.q/Gbl䊝e atz%O@qj4 />!'Ɨ]1ޒIv㚦&zNʷ<'Oqڐc9Si.2sU\ց2wz{-8(a: }9n iBCDO5#@ExaoZ\jc+ۊp :n@eӖPVVXy_ZIE*0{5+ɀ}*0bs82''hW$8 P⓾qjtZj΀,/җ4:7$=iW?v{2}%zsKz!p5Ap{=íFU)uZLc~nNj&<0^:;nix5q'|S 3֩jZM_pP4I(=J[#ځ4`IFi5YGR ,+(bN W-֬D>QWmsjxcGҬ$'&TbqYEwQD6 CVciz @UWx\VSPsP(U3Ke6OD@cɪ~zӼN4V ZM3jAdLv 2qңi23;֘p\4ȲdzcL=jAqbI#_8Ih1zS Qgڇ@#M-P=g?*E'PO=^EBd簧y i8 wy@Y/=O6Tj AOS.L[uژ,>QN9#qB4sR{ D:TI6GpÅ)L2?*{ yFG,Uު\]1sy5@]JF'ZlYZFGҀgRE!~Q''' 1Cހ4EqSx5&RǴ{PDF\ M@P9ۜjlk>c@ g84#f2sG@*sҼMҀ"*:x1g )t+(4QZq@ osB"Qޘd*=b֚J͓0ɚ#t qkg9Z92Flapx*6/2Fs4~j0KzzX ✓nd.xU^FOSp&$Мu7Jes - 6Ҭ UQ 'OjORKUenz ZE'Y*ITɞ*g*r wfSp4GOYy~:a&ՕXtu4űF}jRr*jg9!$RFACC?ZF;Pz`&z9:N18@28&gڐIۊ{9ɤ,|MA!8MF0ό㊙Wh8,ae F{nJ%vPq2)lO֗q5}94*.t+cVN3Rn/QT>о򦛑uKP4`zLw~lڶgV֩RJ@8 -@[и߃GYyjC)ZvPyTo̤Ui:qJY33g Ui^ aq*ES#ہLUxnFѰ V3Q6J"IsVzzE'4܀Pp+1n֓\NZ!GTO9Is~5QAnNR@ʾ4橙E1pi*h[4l&,z Jgتi~)`hF/(ѸPDݮ0$ n&>Y\^*H5HQ8U|⑥J'.`sL7 *n&=zi`޳}QG @iO|ԫ~}xi.=MfEqD9 i$.Cj):jh |9ͩc?0Mi:6z˶sԌy JkG^k{{)&,z7sҮt<5ɫo5FD;p;)Bu*z01?7ˀwJG5]B7 }zRǯyM-@$B+YV'ՁQfВ=!zG^kRp 5A ? @tͨ3j'vskV6P;5'UC.7 %;#G(zS'  gpHܿi.5'=pɫr[yO"cG-ęϩ!ÿ8jωNˁ"gZڴjk}y ʂ3>=f;\ƨu}jo} W u*pAƸ-&\kP"M n-qy&f˂>gǥ%y?_scfMv|bq׭rR܀8Rï֋ T1o­&ass\\ 4Qy#tOx1֫Ix3ְUjDy@5V]H.~aXo'5PQW`:uL)W'{9leVNӰOު2k$\Q& ai291WZ6KqtK{5YQ@cE꿵7_֬Cfݎ6AsM(|I?1JvLw:-CđeF,u^Մڱi:+IelP^VHK,ޯ[Q\|tT\*0OyAE:Ba$g 2=w'vGU"NE-H#nc-I53N5'vULb{?h~u է˯OoZˇ"6ԓsВQq5mT0$'gh);8'5^[Y(9^yZ8[h+W5x[)ڲM_*фȿwz&li4LO-Ĉsš%"$ҹ-O5a@ƻYS]IjƩ+_rysk*sO[[HKp;sSu$*) BڃfYuY$ F=jq]! &+Pb \Ӱ]jA;TY3W3 jdӰ]PU ZPܹRz%p] r8g)tnJGRqjt! CgPU#8ϧ@ߝ#Q7[IЦ)Y)OǨM0ʀFzZ|wԙG;\M!O}+͋"nRF][ʼnH$wo¥;|Ce]X#cjom~vYc9;6FIP Py"b}I'>luG\iS=sA'Uv1\Ү[ƍnV@șXqaۓM%7\ue(ReG֔ϟ<A⧛ YpJ8,Q`40w3'қa@I)P GpF 5)x})@sT@QQOMG̻A@ؙ}ͪ8#vO9*H +a\늣-rk8U'Cq۲c,>^pVeݖw !5s#׊ּwyW.S8Xޔz|@LX/CiܛJr T&(QF1Uekh[h#C _BMF(͍)F3^muO,O\bsێ1gŮ(9+zJܱ/&(yݾLaMq4[ܖ >Onbh^x٥YQ̌9^O\gWcҴ5퉳өw׿j~X#?LHvc?x`$aF<`u TapL}G< NT(yVXc@m(O҆Q1|S&%*G J!x'On2iY޿C֝T>mq;%5Rwg{loXؖLUiWnIS@p:ugqϷ~ЩygkH0`XmYWJ CT~=Y"ʹqRvd`>p1 BK2.˼R"n?jE+j X!ڮIݩJ==i2-PE8ln,fbE9㷵FeIzE)v4g})q/JVe#@0RCt5$3.{SZ@<7oQOֈ$!maѽj҆P嶕#JT.v:pQ&'smacCc٦]H2rOjjGTU7*ɪIH=i!|rOSH$zOӟ\\l8'R3֓8֚r}6AcSEf3ya῝3{ܟ?h'ޘKSMby$N&Jlj~CuD"o ֤ pm,~B xvPon#f $=NjH!zҍgaǘ1Tb 7zKch?QF۹!arO~q-R$eU_rMx>%7rHl$1s9=}r'n\dZ̻Փ۽|uE;ܒZ__B!-g˷V/hz$xfe>L{^xQԯeᦸ;cs$sy$3kMn4(YNG-Zk<)KޠyV;犈Hh K3mLbF} ;ќE@J7>71AO]Կ|wr⋁4(OVU动͗d;B%H^hMX2t#")4V2:~7ە-xpA |\⣝ F }Ԇw9a8xpp;XLNN9w$Q LӦ9O8R)K1@/>أ++S )@o [FUfi@@ /V_ޔo,H9^J2NJ.8<) OZ1 /@(=G6 ҚNx6HdF FqHi䑷<'֫}ip8}=(cye3pKdQ@=LJ`¸ TpXۖNM:yd)=UGJZ58_Ԣ&c)1ҥG-8Nb c,kR(p j):~T`7zU*7gQ䒱āǯV m>rs})J\`SJ#@ΠbUGarO 䜂p0)z*JP AQڟ0QŎ;~$2ݎQ$P0CJ҂##/1I =?:>ϵT!dZCzzRrjg٪9)F'鵬Z6AfSS31o iYy@6%Qn1B ֮ZeKÊ#j"Lr{ quZ]%sQ;̸ۀ޳㻓rfazђ^yfM.Ik(H &=@3ϝdQ4\Y RWn mP\MQQb4q6 *rGݨ<yCR%ԌReK^y<+'= G5j٣m2rG@j?gqoBT{~0=;o3՛|I? {]LyVVIP`z2=Ghb^>X"#@Y^1ڝ4&WJ!7f) Y?@,Iqt%FF3CVi@㧥TU,_]c7 go#ګ]FbcR^Itz>c3=NYBXclKpY6n>s bL`Ƀ1Uc' nRj2d攣֘T]H'$cLXcLSBXրܻd %z?ZsQT~ =OH3wNLp ߕ$|i:>\+ nޕ~^4ReE/F)1qCJxژ% &T@2FIȨrA@M1vP@ qO$ BTDvާ5,DoL@ޕGx ~4nctϥ0j[ yZhb1\ӾY;NҕP'NNUsڤSV9_ nzeQxssR|AiVBy+9b2h H'8dE4)*$=*^-* \N܏,H)QȍDaOi<Œ00rC= h'_M6&8#Ӵ)Cl;  G$;TLޣx5%x<㹦9XPidH`BcnxfY s+eU1 f?'_pcqQFʲ)c9fc@w4T~yhn=酇A߽9i#(8Gz]Ln2]##7Lf#d"rLTaO\ǔi{P 0:9?Z}`cX˿8I+dq&I@A ʂ \ }j6TM$W(1+4?P)C`R%XRyf$BH">2xdڡc,=)\@?wҀ2no qRCh'!@:ڝ7g=On1ɹGߚroR4ohHSZH7t%ӨWXvde3Z>~Wps߆NJs Aẗ 2bo?z}`&§`y׳d?OZPM:ZOxBt-ޤ9O@ǥxd1v 8OJ,D>G0{VwF?.Ex[Y҂ (?Ai.pUG<:yJC[Ƣz2{=:Y;`Ỉ֠ȏm4s ɍǰ^ɡ˦C1Ig%FV$VӍ۞isמu(\PG/"0ʲy|H l<:4ED Vwt#u2#m'SW1\~~Z$0یP*QC]tEexVC=㿉^1:ʠJk\}k(t?Qn46<Èw n5bWd7WpۏӅ1DsS1p<NqYS b['#Z/YP^v yteCt^ܱf豓(r@SPFCH @sVlS=5J(%Мp=ӐHd%9SMiLARPqڡɴNi,žlMDh9' 䐿ZS^f#ln{ m06FrqHN@<\i7sM\cB(y),,}q֚"ܨYA R@cD4g1Q5$~jnRÐ)ْ=$T9ԏc鏭Gn:F0 Ǫ?*tmiBWۊ,D|+dCs,:c#> _MRrOZ8i 8ӎեWA# ?3(V e!qwwxW9#J\犀QBq# AdޠHќJW8@y20 T BBXzP*JJ<i eF@ t(%Mぜ\$9 0 9(K|•eʁ9C$DwI0ep!`pLS(;J3z➠HN{LPs c* eq۽ mr{# )\m.۶Ң iWbX{H8jy4wfFێ?q䞜Vϑ0%$@8?bKi,,@F*$ӌSB0Rzb 1L N0q֕㎙VB j$NH# ㊞}alNOj$ʹ8Zr#22aNv¢vH*HmZdvQ`HKnv`+*em@ >b sJ3 :zSU$}<S6e NOALwi׶Gzh\dv?PUQo9ܾqLLķBGJChFwr0ZMbr49P5¼)TJ$xm3zG!EQ=jVoQss4+'&܍߅,[ܫm%wcjCz31{zyۊFj 7Q^'4ibmܑh92hW#ev8U&QcC69#Bb=O8¤xLr}j'E["㌎ejcs$p6cPwyovv)wYTӀZhHopz|Y;(]*78a2;`qĸWR$-1HrR99=:o_េ4ܘĎ-/9={ 傌neB4x'Lb!a!'Ep~5vv"GSZ>ަB%Qs}kмeBmsdLð\y=*ȉOЊ[" H7t(3 #h$TYM7Lt?9Z쓙*eGYvi1`ՋK / 2jkM. BtI |i?QbR(`$vV0K,DDSB Aۂy` #XpQu|2ɒ{Sydh+vgiYV?ݵ! ѬZu u'4c*#N[)|Z+IjgtM4JvP?_Z4oi@)+qp8ϨF󕴹[y >,:EZA~xԒ5X0DX~0ܟN1^IP2ݶQ[*(ǦGm%p9#L inyVhPǯǭTpxL'Io{ D,f뎋קQoPmJ ̛؁fПIumJoD|nК Gq,e6O'Oqw-ܳ2Mm3=瞙r"kBRb4%وG*tWPVֹ_j( s{ܴtZGvx2wJ KZ|yWͷr9Ejx+K#X;2'q&RAy骳xQF A=zZ n4N!ȨB36鑚<7Ji:]Cm)d2^k5"gN~tǥ2[A+lp&p?¡B.Wtv8ZԮ+2CzC[KB o|q%8}UddU|#= +8=jRQ RruEma!;FT) >fMi,qte%UXOI-, '(dyP'͂2Fj'[\P#bL]] ie܎ #=*tN9 ҭ[O`s$ .I_-fUxre@ h>xgu%Ɨk|.;⧗X-ȑuu,p_ns.GNOZVY3 9;>]f3ʔc#;A9Wc\Z]>O0DIG w#vNOAo7v@8ю檌ڹǹvI<"n '+kd@ Jp:eƝ00S"-Ԑ*H6NGOZ];?Z4gxt+֩a-w0T{YC( 2ب NZYw 7xJЗqGmTHcYJ"S5)czUuuFy+ë Ǟ1~԰C-]r9؊Z0D͕LVYH'|?5Un6YX!Iڧ9<֭QA +5^ E8uOn)%+FBc'8lxٞT۰3~&w }JqG<\gkb4S$uI%;tf7-]!-.V! yܓ%}8Z´U^m=r;~_λ4Md%= ǿz4XU~3<[ơ/C)ǗckV"-4wrc+Ocʪ'KpFx2 Okz]{*8Xl@qYp|\N))+4bΐM c@X/d  `2Muh:tЉ71[6 5E_M_0iNnM[34!N@Uҭ$!"F8\J/ut4fUT C n ^!u:/^֥ҴqZ{mtĤH08umKkqn_7e/8ch>Z8Tk)\IȤ $ڪI|..rblcz\.>ҲjrV]a\α i}cl"w'8I#Yƛvo'[Uŭȏxe-⩡涹H]6r} _fVעדkotOV?;<*闺ՓK ;v s qH/%Za 9,Ksֺ${$儌:~4I˛Hq x MJTxt b+r9&CylZKv3KnAoZMhGP˶ !i}%{nT4f?![_0ct{aψuٴlcGTG;2$$L袟.q]V-W]992jsWHc1,B?'뚹%+ne<R}$rDq|Gxɓh zFVB>'QŤIwL8wm#98{أc E94ݾJf0ʯ2rBׅg󉄣Cֹ$ݞB׌P&#~(3Os}t.q{mU\p?Zkxfk[u;$u[9UwST}v8(ԑ>~K'S{u[QscU}o|#1nK?QDI:kpyPغ k[",vڄ}o.yRX(c 8 2MR8U*R23W"Zf9 [9EK.lHV!;9מ ~4F5ci9N^Ub\n6a3&9X k1ޠ*m&D}>lwJbn>W$Zyqve_(KV,F9W_}k 6lXp7"бP }%}3MF Ab=]I䦟քXꍲLK|=Mh`;y NAPJaenpWQsMپ5y+ ud 2s wr-de0-A븐Zl-ԑ磩geFːm̏l _oī,H˴l$UO*1`7\>L[)Vx <2ptsQ%<S@JmmB巷 f%pBrO^<4FZKH#yY`EnjD'YW54>CdۃBirsr?zqX NCƎ`5`{xKžc;qjRԅN)Cg& pJs4bGS<3namd֥bu"Cⶹ$,1D)=Oyf!pO}kz%DBMI&mP># ґ#nG⠶iX3K$dJ<2''?\|;da䑮n#9=0A_ [Fy Uo,8'Dvz~4j]nj[{RIBЫ(<9U_Eb:ʡXңǽt& gGieb4[74mrw͜~u;lp7g ZڋM:dWl<b ˡ:fZ9CjK]Ig-qu-ʫrNΦP"i"Ignz"_A|ۜ4ǟ|/VhbAЁϥ\q0L;t8KʱQO?}jw@:K/-fA4s9i^=G:ۻbW'̒`8Jpj헃|9pN.%h1xmO| U>87 1qҤؑx.#[C{l\L%brH \G BϯCDn JƛQb 63؞*8u|Xg8^@"+_djW{pv&eRAYzliGOssn^֕r56Yweq'#iO?%<2ѝo܊ڏ6q3G'frdass9yhUEqu(g`[wWKo8G]C̺I2 ~Fzjl&RJWvsUx1[u>q-JWB,nK iӮ,/]ZMgg c&I<v ZoJmuBضX@>TUK_m}l/%6L|!f1A'*@㌊(/s${Vиl0x 󊺞K8Ȇu烴qWjڿwۆMďldayN9鵽ͮ!H'"`UCzrGֲ榟5u1ėedVgŪig1 ֍ey m|;# u`}kᾰHFtP V[/UZ)- #~>!֯рk>z70 8L]3贉4sҵ,dGxQҲa@^q]_|VܻZ^[E `vGkҵXtwӴ^P.{w7'$bSӚ{x[L噶4Kk#1ъ{jNՐs9 Fb^?`AU9 #exQKGsJKm_)9ui$Tl3fmb. lJ_Cήt]ՙ%ȿy}熼%WK flgζݤq=VH:Ǜ6OoƳzDU댍 m׆'~>CH.</]N ӿf֟$"%YgB35is.wTn8qלS|O6jjpAbuMѶ팀pOg|O,&)]@AjgH,*O1xK{KHAc,  *)@0/t_Ŗ SZ =cY_6{MMc_4p>U/ei&9M}W%F7-|?^\rρlQ ?%XDTv~0|}Mlo|!k83h_ݥm t*s uepJ^EpL#RI#!Hq׷wBJR]Q|[ MBA qe\nRG'ߟ44w"1-cW]i*̩ -2YOgk|{ \,3*gIINyp^Y>ӻ2犢 xe1Y6|WkzUx 3S i{*-:r?[5Hqʒx;^R d²[BVm>^s趲-4YOsaRQP6e)10z5@jHڌFy,&Xx+7d*5 TdX4UP?xJLJA,OYAo}&s.0Ɇϩyf_Pn猁w_VFF0=ǞOga7G5E9܌K;}?Zwu,}Xۄ -ޕoʃG=@dϮU+DIo~sTZ:4hYOG7&i^Lg"*_59{r-$`ݏ*C)d܉1P9G)s,Lٻm){jQ6?f7|VŒ>Mah̘s2m;"3’myS‹PiQap?NU\9?)ƴ8K5$m9%y~Dk#A>v%Pm6y?Su(,VmAl0BOrjU ?S5PQ͹4l=K^LUl#Taы.ƨ {m?J/QbK-$[J֔Z鍀k}]wN8G_Kߡ~Km5\uuS~`ۿl8sj 麓J/PкzwDny wۂs1sG_ӼҫlD*OMJԇ+0{?xhE?PzG6`n5*x4SX_ʃv4Xq Of4 tMseېYN1M3'EW_ʇλFm$*@Ȟ?\T s9y񓂪{u|뱪tf9B>c@ڀ,F[ i2WhPsAKYv?K9W=XAS9w?AOv"Qj?ǻ?εeHDJ#= m vpr_X{FU[A*#'㷑uv!?)SgS\T*2c3z+֮syO414#nG.,S^I"%p}埥YVU׿~{octz1] xJY7{}͗+qj %$?Ny꫎ߎ+o]'r$N'"_ R>Qϥ`<[ݼjF0)W0z as˜=9"hH !6xOb={R,.J@ՁLU oM+<=NIP{xzV}kRI-̑Iܣ=ůū_ỳ4G ԇS؟Zߋ¿ſ$OoEQ]PT. #v/}+ . :cdُo猭q]LAdEpbcW,iAlbo_‘Ng+Ro24x ]3Oi1>|.H9( Z,d`wHxK\äF?8\3K݂9h`]bWɷ*m~)iD1DUԋ1:H[c, <ۇo۩BWcִ!8cpOmc=u{EYsm۩WJC*$r};KUy*??"Ք >،UIG%RA$ 9U!E-אPD灁qSH7)OW'R}Y2srspHN剶xwgŨTta>;go^#COiҞBd@Mx^81r/#p>vP&yt҂ÒH[!961E{ GixYpcB*] щGg+&y$ìXO}ۿ/>rSd3돁*E/{IX?#Y&j!'FkF?x7b(w3sY,HO*om&qsT>IеPy/*٭&C|)yfǸ=4m y֗{ʄ1UGHoY}XҠBk7} xuџ+sm!(^+#mY|=d?J̹mۦ%5kcA?V'HQo!sǿ O.}^gPkhV6߳^6d?i}YBtfa88a/qI_c?~ek>Nj_#8?^@*eAUӚhդrI+o>*, nBCT}KHDU?u kdg_X}MT70SdR6G& ځUIfeHNxIPR,j%r@$ui몖u>U@)$M>zqⓦi|Tu(vI Rzq֗2UO 6qS&۠fzxcNb*zk3>sg' 81IAvl A,R`uو8Eޣ"/#`5>6~ю=M)JeYPp0)Ҍp0{ҏf8fnXbGB8OM df898C=zF~GR.1beиcO1QA+%';9^TsOIY]ri:|&ކE*>HeT\psURr> -Ss8k%cTJܩJe,@^2a#Ƴ,瞣J2pEn"W8nub=Hertz.HvY39bGZ<1c.@5c3ޜeڠPOul*OךT&BqHG>`'p7,wzb7[CMF@Xsƾ̈́qcaʜzqS*nɑUd]ѣG%ʀC)83z$ifKi>y$às@q3#ЫO$N;\lkE c}1\01 %»ϴ<֥YGct_GnYf$ #:J۳g[wv {TyW,chI>ߺa۽52Bm2 .#82}}Edܥ&{3ߘ)MOn [ivۄdn`Nq^x6-5mOR~i'1ƪ~ߑq x\zS0RTc2$K 7+F+!~T3W>.O罛F]#[+?1]g̏~%+>GO+\1gWT~=d  M u#qζ5ByhÌqp2ɝˁӤ)9dU^ D@$ z (B-\f?ʦMB!) PB8?֑a~JHTQ@0A)׎3gۘzNA@ϿJ` m(> g)\)HWRO5Y.`:\-ԑL@!A}Jg'1$$L4vb|~4 2Nwuɦ @&l[ܲ&nGLʪNe?.0겷 @Xv`zUG9Æ84|ޕ*<.08d aA*Pԫ 睬MاbzfǤHeێ,r0vW sM ;`fp#$*}W@p_ixuUHj4 2Ms9 H`0hP]ci<_od2"B(U "qPmS[0+ǽd O*sgX&{(#*x`~~V4Ƶ<`#VZP2" w."/}mqҘ4Qj d1H/ncQd {@JV?&>X3 Q Mp2߂@vjHЃKk[TuJ RisHЃ9'۷ 7?K&'=v1VD>qBRP] o2萐(#ګϤh׋F(xȃĪ4IT,ǁ|#,adՖ1j8&Ii͢?ݷOqB89VTP G">g-U?Hgd8B"r=(t"yo@,S=ERk%g? 0z8?/[]>ٺPa!Qߠ".HuG\~S6m ]Nb0r=Zǻ,;z6$ع<4c*$0 ۷Z_ق׭[>x&5>kf'gD8_9pj~rCe ,33\om2rև= 01hX{8v<]}N*k#T GH;k|K!;;uھn92JUd,ϰ >:q菝H>Ug]7uHPMsy\Ҿcn,F8?H60uϻIa``yϗdMiq9'¯ R?.r7waeZA{Zы>V^"M.q4c6k}gȿ?:.'aĻb{"o3'I\zDiWZ͍WBiz< nc01q<Ο[<`~8 YO":ʐxާcG5_^dv#>ko(>˜-Q__WGCڷ_{oqCh:pM[ISЧD{?$WG? *BR*+jnȐ+4m%L(S16IB;r*ɞ&AB?’+I_(Ƞ >twm&w#>`)ogI!Y09$8&ԭ.\4@0e枖ZK!-Rx}wvLP2~鶷9u#+({yժ]<"<yݬgźj(ɝBy0 \eܤ&s#Eq--+|O׭'XgWumѰ*c%Vo\!mYm^hc(mE& 茤${տZ\mxչ֓*=oҰ*ۖ&Jz#Dk^c+`)jaF┡#' .9 CaG>`$y xшe/1Pa@R$eW8 ;AJ< @sXGgPt}*5չ!8p[C6}p(N1 zp܄ tH#P;BܘU`B\f0F1Yw'Q,` 㺙?O{T|BdiNr2=x% K199֙%ݴe˞J 8ٸqZ7̫郺YYQ+#rGًAt\1?Jje!wɧeNJU9G|Tk43o=p)F  pO`!P*O 8)Pv)>4q3R%)uFѼ0O4@d!LқBgC:9mܚ;:T|1C 'dnʨQ}&G0zP]ٷ_’i!c~z Qj'@xB1A]B%p zX 82#DS. CiUQ`=ZMJO@YWx=pi>Qk2aY7 \~W*W9.fNU'SPVҲ~2^Os\F6}FdSPu0,Hòrk^AG N#~J0"qR 1Q\1eofS̹T<~+\YVՇ1s H5]Dgh@vpL͎MG?NFjv8b;Nn e#yw& fUnKSži_ґ~#6VS3RePEd\JvL RݤOYo.-=%^*n?Zv@tA#4Gcf+Y?UTZlwg` ׂ$' ~Б8`l~uvBukhչ-|}eɩ‬3?SnoD')MX簮|{ߊdqJ/n&TFB=Ns }V'Y?:hw}R <\܆G4 n~=;8*1%<Ϙ 1-pi$S$6LBm}Z.;fxHgAT1qqjqM2##CޯImY+t$lҩ$e$d]3ĩ[? 3@v*6ט^kpn,%#㊂m\݃ҋHھkfeP6`zP㦥}|L3Zj0G@k9Dȝ>˞Nmo"Y9#?Ą7_=jז~%d-/n,nFRˣ*d+t|KǙm 0{k}kOQsT`GSIp+tO-"r. Gqd{8 +߈vXctN#,%D@FA$0<` jTgh\eU]5?U {֣S[|XnF#z9l |p-Ն#6ց,xbFvN%vtԮ"U:p8iL튄BV(Sk9mЭPPOLbjl9dcs*"=E55HR8]JñBc ͻ2ݡ',O|qN3p ?v`w& _:%z@3߭1G:;(V|c~^ixTg_k&K@b " *1jΨ(=YK!|Rʟ%JJpԃMk[icӎ]9iPI?MH!VfszU2#9 ?1)O5gh@+d=I/MoO95HO2t?Zw#p jr vH8v3ojw#m))Y2N?8Y9Tp0Uw{TreF1ԑҀ,g>*lTTN*Hϵ[2@Wa"W MS'HQ5 ʱ8 0D;JGTZy7bi,' 幥E*psjt6@\LTm$0FMrk1fm\ع0E_VLxZҡ!cƉB:=( (Ա$>Y$%sI%1>7|5 IT8gCc=x4!P@{/*89ZC%Wzw*TIK݇WW(`?ZL~lK(xtmH [ Qv th- 4W9<PW&b>]Mô/֪PUZY'Pgq֚ ʾp*+pV#I2G/p3S<`?$oMP G)^Y=ݘtf%5RlCI2 *N®h}rGUH6>$eza~{sQtķ0v",HjE.ylMƞ=y=TzF {I4Uߊ;.vTl!di@s$HjĞ`QUsw۞M 7/jRj̖^V c#(}X<]E3ɂHHV;VAULrӚ|IvҠ  Jִo! Tp08;;ץ^#{wmTӀ~YlqVsy6n: U+,%an$WZuHb `ԭaVb nA"[v`3`pr\0g&|Kx~;$1ݪ$ -,ȫ M2?Z=8YHi8|^cֳR-Y|N]G`sӯA 6PHc@ccNy!tu<j.D|bݴVJ:@ mgBH ̐[hO. L6@1P}4`')UA&+(v?3@̻0 eq QO bA8R䝥:wi~Uehis<]I>j}p~:SZ"w~10̄Ҟ)$O#HʷG29?J |8鶏11 4mk4Æ9 [*^,ї4ڻ~1J) g%n?\n,tA K<+0U4CĊu8MZ@%șTu #8Lj$,0H'fl "D'PL4Z"Yu緷pq &?2][b\J*11M+Dq@.&mǴ282akܖE<5J&@$g֜/MU aܑ<2$폙隤eJpvO-_7*5,H۴*1UY$r62(ʸZ2GˀZ/ЉG(WDam/*&]qZ$`l݋꧟ϵ9'.zNhXG]AMĸq*w"@=Uyn&8P\zM۴=3L5QGmp#R$z@Egt1H Q3mzzT.[+/$2`"[)Q,B0F99uw 2 rw[S4ų *Z*.%i KsFsJm:}J-GLA#I{%8$VL $g#r.0pnO8ZH?hA=_iI`^hw+U;J~d*r+x$}#⥅T[>B1n9:T4[wK5ӕ=TԩlH+cZ.3Go3ˈ#Omʻw VN)j$;mLw[2Ο'˩<uZn9#h8n=öLpo!*W< :esZKuoII\sV#d5Rh)8<ۥ!qd{לi~%?OԖK<LXٗ9++mXѷ$gn\j2EtlnV9 ` ilE%$Q˪D#8#;TV|Ԡl?Ji\ (}u2UW#5Ia @ dW*QCkm)7nȭt*s2|zq]gG+wn{4֐ e=ˎjWQY^Yl۽8(%bOcT#[eϦHF109gHᐞ5]c@3@E'nNw.q*_$sRGJw/I9B>; zqΤ[w_r0^['SR2BO1SԮAWs@XF>B4K0do1ga}Z FR=Hg&B^1R!i fک d1 Aí&HH#h\z f8ne׾zs3Bb9P[dq!O*q?)ts5B7-&A$>k GLAe82}4$sS!N* YvUe\i8ASW"1 P:ԱͳyMϷSRp^ll*W? rDA:x!d,y>#h#o^c6iP6+{@$қp"m^ԉ>ܮ;`J?#dd*bǸTttlwBӦOҚ\0EFtGxցg<MКẁG҆,\i>&xZz>FF?A6cx'T7FZ`,8䚑K;w*eFTHI9c襷v)cN* 9{W_x/OT3]J?yO/'~_;0)n0}.-p6)0 c4amQf0\2|zVh~&=!- QH$dx^)V ʫqjZR 87O۽&&Fs+?$,l g;J#ךI #Q;+=? uTvI?201Y4 5^SlFbiOZ6> vQR81yBU"%5F>?)fxb(0wLg|O`wPS6u5_RҡDJΏpe9nj0$0$F[pM_\hwh.˕>b1ZE݈gt[iAm*1l r+|+urqu:g=ž$y3FwVNkw˧l,~`br̸cPw0C],ĕR3ӐߧRӱYxI&l81ӿ g⑂ذw'U{,`EV%f)4#eJO9SI !'󦙕sE_cgVv?yxNxj҉%E9e4D@6}<O֭}UL@)J$b.s@(wt8ڧvfҲbFG'rG)vs;`*dUwU}:>Zy@?ƱLG^ OCW N'O[}aXq?J9 ٧u gg͏ͫ6MY§=SoWB$Qmi`q[,sڴLA.q*i0px/.#`*c.roXwZ̳m<+oCT=zV}J(I!>0b*c|[544> /s=yIS@;K׶R\iO0YXmm؇sg9ϥd~bydȾp >Ap:@;>_2vQS?n*3yknZdnq=jy@ɰ/4e]O׿ҽ&+d񝘎EZZ#ˮ2=IRGyas9̷b /hwb..7SHsM>TMo|Pe]oGpvG@g+)#lgYK.+ˍKxW}#Lg?|/뫻L歴/ox,r22\z94YpA8jBs]wxy )6p#,՞}r 9R3Ik:)֕2IzzTWcޥYNyz5Ұ NF㴃O=Rmt#8?Q#*K{+H7ybե(@( 퓊MC_>p /ͷrx݆쵋qp$@!SbU~jb[;}A<BSf-Fk>Nz39+. N1h p{UXhIc.)eW⁨%ͳgc1kB /-Ksvu֦:7{ ͸(9n߃ Yhzws]ٮ«|X:ɽ lWC,e 6jKLtŵuG#[buµ,g*2~QM:y?.$c=jjLy]?ҡO'mA$ :wwzp总IN KBIWLЯ_?Ҧ0SƄpTz@Fb)-? #PQ#ųW隐+)I 1JA{@05^CR?+@XpzJC'⥍#`2ç A`nVw_p)dr7:U!A ˹zE CE^GOSA.MB˺7Y4sv)43B 畧EKX ԏT'=@j18`22EDH+TW<„y5|vv qQD zm^2}Ryd`)ϳ$0v=O v\(#=3r3Q$IAQo*G>®wrqg6*<Jc:(e*C PY7u)Bdtcb_o^O*0` dPƏ(n>{o*A!V`7`CJ(<\,̓'?΢i%v<iYR@ϥ*´#U4y9cȊ8-ҭL_XH&pn<Zt _63"MIݥO2n )]x1ڽN] XVCopYecRkgn?i wq=HTξX& gDĀnjiBlJ ];d Eb[EhEc$zըV8 vFMXD>38#qk%3AmiRnRvQ ߭06_be(ç?Ιqwswn^V<&yGq`F}1dSNyȠSx. W'kM@./XxWU;r?AwOϗ('P*%7ɃMrC!@SzS 0Q@D>wh!;S-V;v>W Fk?Y]&PTđn ZLC(u\:N]CMC 2rh$&0A#U*ml$$櫛s*Uv&C(<֘>TKfx]1#5?LM [9v?Z& zf 71<2R}ހ2ϯ91GQ0?^j .1#߈J[A+Iot D  ۹X[2!Ǩ?ҧ?|F8 𤤖^Oq@-˫ ʐGUͪ.|F9T~ՀZKXrwQRt]G\zR-ҵk[ ugus* ꧀vzVȭۏ/me1Ս}*Ĩ?3w ?#qާf,Z7SX}K%.LݐO`s953E4R7 |pćI_­[|E"O>;ݒqƕK[k{hPeFRp$c擊Ϟã^\YO+4 =6 :fj6"y6?R-ZNKI6Ҩ!BnH.ŭױ[>V_T4<dtj6r[NSv 21tGWb.;]GpN|?J˽׉|3gV RhnrWcb>)"ԴE[2R$㘜#8fcERG @ 9\ܞH湫ܶ7mb YOAYwnAeٜZw;ct2wi # kErP;X#b:,@-RpySOwT1 :fwlm~y# bi2:Qf^8ȍ P(+*tQ~t=hTy6랔ی@ $ʿFDO+8*D` ۭKr֜= o'P=vƞ71'cq\?͉n)8UjMث?`1'Vi9eHʀ<*ثH/M ~w#[>0bxUmu{wr[ǿiQ18>cnS> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 3484 /Filter /FlateDecode >> stream xZˮ߯8_ h[{a@8" &離< Yx<5ҡج~Td^WY^-h镛5__/׿}|/?~yXočv×?ƿ:_O;|lގt,qfOs;,=]x~tatÞL`LIVS?ғؑLI<]t󓝩Gz4e#=QO?ғƑL9\ꑟ̵}~,r';hG~2e%!,ُr7Ŏabb=Z=n'byգmqjGfg?\vlQ%Q^Scn/ͺ/'~uOך;r~ZN y6KnVY̅VnE~7*=͋y^O<#ß"χG{ȖBEV '3~?)# y%\ub+0?#\ E$ar!`?7bye(Btm[&p|%M/U"bЯT-86f>V̯[R~^>ChWj"LWA۞Q|۳+! }vh;)~'׀y76[aؗ*̑m `sW%)f>oKuJ!H)7셈^Fowraj#a_j&7)Ǜ7) Ҽ H &O ')oR{cIG~rRZ+ Iߤ7諔 l-s2 BdKe hT=BOP0)r}ƞs9ݩcSLsK=R"H)c{aB:gd\0#Uy{ 1Z2$OnS6HHzPhh=Q SϨG}Y [, H =BҙY:!Q: zYY]E=Es<P }X)?,"% aKb=6@1B_ u,V#@7 }# =DX(A r˼9H4!g/dylx. F z(aRFm  ÕA AXaB_ Gi s2Mű7®>j*,8u!7obǘxpe3ǐtΈfʺdsV>R!}A? ?oѐ=C~Xq~{*ei"r4I\WYPP |Q9ĨUpQd@X#" zp!DYBuUg$_t1ҏ3:16fp3ohn‘ |pN 1a 6Z;G!zjΛgapb;ub _G"l~8'_ق?XRmSU-`}UԤ<_b~#WǴu.$.S+չ?b_ug`$FI Ԓ41*Ajm=,T Xn|T>΅Q i-JcjqPfJ  ~*>%JЀOf8%eCb8zN>z(_9gbWU$/Ybboƒ(ۘ]hٹi}9vc9D+ɮ#+zb&Վ~]IӚ#xtryHYi8Pa8(v ~x '&_~e٣Q)(7BE SY(9#rC"4!_\'FϬO֏@%N>yy5㱇E|E|zR!1@4;٫AW'" iԿZc8ņVǢ|(4o. Co:*8 *"Q8P|9֘8x\q=Qsj7*J6UāI?4puSo`[CGʖO8Cg3GNĝUR\oWm-nL(/-3AF(_H{.m8OeH@I8Srco xS|%*1x~Q_CE2i?G?;/h&,Iߺ/,Gs#Mϫt<+w ި1qT](sFSģ'c nt^z6]Ot\o7Eo /II7Ǜ1!0zL02` ڵr˄ȋw̨1qAx ZtyaF!1ؑ(Ftr\fG}/:ŅsNڔy {t*SYtj^Baنª-fi`y%1Ih6I06kl{Lh78qVm2bAJjα`Zc8  α`Yc8HyQ`_cGXc R~-5ޤ9!V}D75 /կ7ӄoR&e66h;qt}pA [`^/כ_v}C@د/OǾqo7iv} #8XFJ)}_^ }X nf }t'%5tPGEOz>|?gLݾ庿ll~}}>:qPkn xQr?$yPendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 792 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << /GS1 10 0 R /GS2 11 0 R /GS257 12 0 R >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /ExtGState /CA 0.200 >> endobj 11 0 obj << /Type /ExtGState /CA 1.000 >> endobj 12 0 obj << /Type /ExtGState /ca 0.200 >> endobj xref 0 13 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000003848 00000 n 0000003931 00000 n 0000004070 00000 n 0000004103 00000 n 0000000212 00000 n 0000000292 00000 n 0000006798 00000 n 0000007055 00000 n 0000007104 00000 n 0000007153 00000 n trailer << /Size 13 /Info 1 0 R /Root 2 0 R >> startxref 7202 %%EOF partykit/inst/ULGcourse-2020/density_2_hist.pdf0000644000176200001440000001673614172227777021006 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20200419202302) /ModDate (D:20200419202302) /Title (R Graphics Output) /Producer (R 3.6.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 3590 /Filter /FlateDecode >> stream xZˎ$WP|dq؀ dÀ0+@ރ6|jbX,)__<}lђ\Ө6JϿ{/?|?>ȩ|ۯz\;}3?(_oS?=[w4I7{6jwq=,3wr[It S>[N}pƻpA Ffo+(b|Q/9x@>yvDJd Z'r#RM*ہ@DCj:/4R Cčh R%j:Q?!4vD+DГԓEtlB}~cq,*6MGs Һm!wզiKpnX=oA]J A!`TcScH? ?0ReY u-pߌܔ1SK ikVM.L ]1gR,3KԙŲ3tE:@O巄&̽WPg2rh,50v%xjG>hĢ^V ڟ:hzDZNibT5Hi+:O0NGv-|}P"pF/u L V `yC)@+p"5_0ZN}ZjshE#B0[=g"Z[ LL'p pά5+o\Uċp# ~-PXd,ʍt M7- N …L^4f{ R2x0~Jǧp:R 4HUPMQ%OH2 ]Hw/JR7(ZBo@GP;|bC>cZ[d*~ 5'@>ιAм{TH%T&Iɲ-ĺdQTӕd$H  'eCR2YOF.c >R66n eB;1e"^S&$%")*|5pAS&ėƉa׍&c|LBLnd;c(ahފT{oAN>=HQhhMXN0NT&M8oDF0гâͧiS8B0p엩Gܵ^Sx>=ָFOQi}П}|~-.rN>jBa~DEkib\BN_e FLյПF{5 ${\%'XHSXCBR ,8hAß?_!4#ܬ#=!|[/͏~ b?s?T| uۏܟ|c:->|]! 3͡x? *kǓD|YH_-DI=T%¦ȴ܅u" Kx*>BW -ߠ?bg†a|(3{{Š?pxu~ģ*^M0*x1x,281O3>?bԦx/7*P"4JK1"6 )7~$伈)1$"UUc`)'A0_0lOz0>Rvc>&}4,1GsOlB - :_|Q!qc1k#p*_ܺJ%=Uw]{|D)SOw(dϳq1ϣtǼ G֏ć|}@;(/< 'dS}CMyT`}ea8ޠ;lqx4^r#+%t_="-CXX/*u^nUbgU ,R*e|PPn]\fw]θ0V˨f.j%{R sJ$j^uC>6nQ_*pu HDʁAƪETMT!0oj!{gxS6w2*u4{b,*3-3!,Nln0]JeHhw=X7g@ST.vʐ=]r+pU̼vVء&JCLU'v%VwICQU!$CQsHc>TN8*l8!4$C:iu}ݯj 5#|D+hŰLy,| (ͶY;Qq6p:qL/Ўl}6I2Uvn`h"?kJ[]lGbG& tcw2Vg5͌&EP ͮtc؎??hGO#jm˭? ЏFi6(֫K66Oد$<_ZM o /[_KK 쬥x>66uٙ}i q qk vF{14nm>n}>n>nh/G6o>o>o>o2~[˽ދxGLp_!◿xC1?hѓ%?endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 792 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << /GS1 10 0 R /GS2 11 0 R /GS257 12 0 R >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /ExtGState /CA 0.200 >> endobj 11 0 obj << /Type /ExtGState /CA 1.000 >> endobj 12 0 obj << /Type /ExtGState /ca 0.200 >> endobj xref 0 13 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000003954 00000 n 0000004037 00000 n 0000004176 00000 n 0000004209 00000 n 0000000212 00000 n 0000000292 00000 n 0000006904 00000 n 0000007161 00000 n 0000007210 00000 n 0000007259 00000 n trailer << /Size 13 /Info 1 0 R /Root 2 0 R >> startxref 7308 %%EOF partykit/inst/ULGcourse-2020/Makefile0000644000176200001440000000301614415225047016773 0ustar liggesusers# --------------------------------------------------------------------------- # List of Files to be processed RNW_SOURCES=slides_tree slides_forest # --------------------------------------------------------------------------- .PHONY: clean distclean all: slides slides: $(RNW_SOURCES:=.pdf) clean scripts: $(RNW_SOURCES:=.R) handouts: $(RNW_SOURCES:=_1x1.pdf) clean # --------------------------------------------------------------------------- # Generic rules for creating files %.tex: %.Rnw echo "Sweave('$<')" | R --no-save --no-restore --no-site-file %.pdf: %.tex pdflatex $< pdflatex $< %.R: %.Rnw echo "Stangle('$<')" | R --no-save --no-restore --no-site-file --no-init-file %_1x1.tex: %.tex echo "x <- readLines('$<'); x[1] <- gsub(',t,', ',t,handout,', x[1], fixed = TRUE); writeLines(x, '$@')" | R --no-save --no-restore --no-site-file --no-init-file %_1x1.pdf: %_1x1.tex pdflatex $< pdflatex $< %_2x2.pdf: %_1x1.pdf pdfjam --nup 2x2 --landscape --scale 0.95 --outfile $@ $< # --------------------------------------------------------------------------- # Clear working space clean: rm -f *.aux *.log *.nav *.out *.snm *.toc *.vrb rm -f *~ rm -f Rplots.ps rm -f Rplots.pdf rm -f *.eps rm -f $(RNW_SOURCES:=.tex) rm -f $(RNW_SOURCES:=-*.pdf) rm -f $(RNW_SOURCES:=-*.png) distclean: clean rm -f $(RNW_SOURCES:=.pdf) rm -f $(RNW_SOURCES:=.R) rm -f $(RNW_SOURCES:=_1x1.pdf) rm -f $(RNW_SOURCES:=_2x2.pdf) rm -f *.rda rm -f *.rds # --------------------------------------------------------------------------- partykit/inst/ULGcourse-2020/exercises/0000755000176200001440000000000014172227777017341 5ustar liggesuserspartykit/inst/ULGcourse-2020/exercises/exercise_german_credit.Rmd0000644000176200001440000001627714172227777024514 0ustar liggesusers--- title: "Exercise: South German Credit" output: html_document --- ```{r, include = FALSE} file <- "data/german.rds" stopifnot(file.exists(file)) data <- readRDS(file) head(data) ``` In this exercise we will use the 'South German Credit' data set. It contains a classification of the credit risk of 1000 individuals into 'good' and 'bad' together with 20 additional attributes. Simply download the file `r xfun::embed_file(file, text = "german.rds")` by clicking or download it from the corresponding homepage which also provides more detailed information on the data set. We can import/read this file using `data <- readRDS(...)`. The file contains the following information: * `status`: status of the debtor's checking account with the bank (factor). * `duration`: credit duration in months (integer). * `credit_history`: history of compliance with previous or concurrent credit contracts (factor). * `purpose`: purpose for which the credit is needed (factor). * `amount`: credit amount in DM (integer). * `savings`: debtor's savings (factor). * `employment_duration`: duration of debtor's employment with current employer (factor; discretized quantitative). * `installment_rate`: credit installments as a percentage of debtor's disposable income (ordered factor; discretized quantitative). * `personal_status_sex`: combined information on sex and marital status (factor; sex cannot be recovered from the variable, because male singles and female non-singles are coded with the same code (2); female widows cannot be easily classified, because the code table does not list them in any of the female categories). * `other_debtors`: Is there another debtor or a guarantor for the credit? (factor). * `present_residence`: length of time (in years) the debtor lives in the present residence (ordered factor; discretized quantitative). * `property`: the debtor's most valuable property, i.e. the highest possible code is used. Code 2 is used, if codes 3 or 4 are not applicable and there is a car or any other relevant property that does not fall under variable `savings` (factor). * `age`: age in years (integer). * `other_installment_plans`: installment plans from providers other than the credit-giving bank (factor). * `housing`: type of housing the debtor lives in (factor) * `number_credits`: number of credits including the current one the debtor has (or had) at this bank (ordered factor, discretized quantitative). * `job`: quality of debtor's job (ordinal) * `people_liable`: number of persons who financially depend on the debtor (i.e., are entitled to maintenance) (factor, discretized quantitative). * `telephone`: Is there a telephone landline registered on the debtor's name? (factor; remember that the data are from the 1970s) * `foreign_worker`: Is the debtor a foreign worker? (factor) * `credit_risk`: Has the credit contract been complied with (good) or not (bad)? (factor) # The Tasks We would like to find out how the credit risk of a person depends on the provided additional attributes of the person and the considered credit itself. By employing a tree model we are looking for a separation into homogeneous subgroups based on the additional information. Our response in this case is the binary variable `credit_risk`, as covariates we have 20 additional variables (17 categorical, 3 numeric). Apply the CTree algorithm to build the tree models described in the following steps: * Load the data set `"german.rds"`. * Build a tree using pre-pruning with a significance level of 0.04, with a maximum depth of 4 levels and the segment size of terminal nodes not being smaller than 15. * Evaluate the performance on the learning data by calculating the corresponding confusion matrix. How large is the misclassification rate? * Predict the credit risk of a new client who doesn't have a checking account, has never taken a credit before, is a 35-year-old married male who is a skilled employee working in a business in his home town for already 5 years now, and who plans to take one credit of 4000 DM for repairs in his own house where he moved in 2 years ago. The credit duration is 24 months, the installment rate is 30 %. There is no information provided on his savings and no registered telephone number on the client's name. There are no other installment plans or other debtors and there is no other person depending financially on the client. Does it have an impact on the prediction if the duration is reduced to only 12 months? * Separate the data set into a learning set (2/3 of the full data) and a testing set (1/3 of the full data). Build a tree on the learning data set and predict the credit risk on the testing data set. Evaluate the performance based on the number of misclassifications. How do parameters such as a minimal segment size or the significance level applied for pre-pruning influence the performance? ```{r, include = FALSE} # data <- readRDS("data/german.rds") formula <- credit_risk ~ status + duration + credit_history + purpose + amount + savings + employment_duration + installment_rate + personal_status_sex + other_debtors + present_residence + property + age + other_installment_plans + housing + number_credits + job + people_liable + telephone + foreign_worker library("partykit") ct <- ctree(formula, data = data) ct <- ctree(formula, data = data, control = ctree_control(alpha = 0.04, minbucket = 15, maxdepth = 4)) library("caret") caret::confusionMatrix(data$credit_risk, predict(ct, newdata = data)) newclient <- data.frame(status = "no checking account", duration = 24, credit_history = "no credits taken/all credits paid back duly", purpose = "repairs", amount = 4000, savings = "unknown/no savings account", employment_duration = "4 <= ... < 7 yrs", installment_rate = "25 <= ... < 35", personal_status_sex = "male : married/widowed", other_debtors = "none", present_residence = "1 <= ... < 4 yrs", property = "real estate", age = 35, other_installment_plans = "none", housing = "own", number_credits = "1", job = "skilled employee/official", people_liable = "0 to 2", telephone = "no", foreign_worker = "no" ) predict(ct, newdata = newclient) newclient2 <- newclient newclient2$duration <- 12 predict(ct, newdata = newclient2) ``` ```{r, include = FALSE, echo = FALSE, out.width = "100%", fig.width = 10, fig.height = 5} plot(ct) ``` ```{r, include = FALSE} set.seed(4) trainid <- sample(1:NROW(data), size = 667, replace = FALSE) train <- data[trainid,] test <- data[-trainid,] ctrain <- ctree(formula, data = train) predtest <- predict(ctrain, newdata = test) library("caret") caret::confusionMatrix(test$credit_risk, predtest) ctrain <- ctree(formula, data = train, control = ctree_control(alpha = 0.01)) plot(ctrain) predtest <- predict(ctrain, newdata = test) caret::confusionMatrix(test$credit_risk, predtest) ``` partykit/inst/ULGcourse-2020/exercises/data/0000755000176200001440000000000014172227777020252 5ustar liggesuserspartykit/inst/ULGcourse-2020/exercises/data/CPS1985.rds0000644000176200001440000001365414172227777021751 0ustar liggesusers=pyǏP$~JH )(wIOH}ѶI&)` HXlA.3n$Eg2ܸQ)$]fܤq&)$E&=JIF9ﻻkwGV{k֞?/Xxld5uO~~_t_fg}_r~pAsls>kmi87c;v:7dqX;{uCN/v=`ק냌7?@_7?}k͟v{~[;c;85Hy>츀fϳ_9>dNo_q]78 ?y ?jq!u7}짮fͿ64Mr so7_5<,JtY'𢭿c'@>;1#֫_O\{Cݜx6ubǿ;zﹿ~Nշ8ڰsA&{߰y+/襧'X'n>J#y1q|}:g]ƂO%> z޸~6n>8i-|@wA.OOX{g5mygߡ.Nlaef}7{A]giwaěPẇqޭ%G7=J4qmݰޘ=by>3}bq_s/f5v.Y\&/V\O[܎kwⴭ+t8%6&6?猭m_?b=grh m#p(y̟[Y3‡>/Z}^cܳyGϺys`Ge39e/ęxty3#֏XWG,Sv9,C}^}E[:|[Hs&ه?s־`urn<޵?Y -?W3ukiI{]c_Əy}3n\]\/K8++ϙϯuƑ )>۴>)1Wk0ixyuq-僺[~]suc,a(ЖqIǯ?x9wS )%]JysKQ_ݥ>|^r\^|ܪ8ocR^偖.MVg_^o:~TwgҼmiwr>}qnK\;NۇKϥt7c7~}ORc:]? Ϲ\y|?oWiz?/~|ߒniyי矗/ٟJ~RtJqsK罒kplEe;tAUw}]?[{څA{î?kםZ{8ײ3 }6>6nWgtKN+|ߑ۾}qZ]{785wZ'>^̸kE_ZvmuzfWsߟ9cZ󦛗C㮩@{օܠBZ'sox;;ơK䉺¯ yikGߍc%q:{Gz;ƽa-0죎:zRܵMr<@}n>te-Ψ_'衏7\|w[qqiy |b'o =ts~9v3ϧ5_"oCxzx}2x1/﫮;5^>gXNg>> qt_s&\o8}؟#8Pԏo _g-oC\0]{_<}z5 ?^|f:!Ի?'`~`y,:?y~2gZO[ oc vu{~s/ ?G<3~}o?ǹ_wuܵȜk;ob}M;\_q}:=f^o/b~oN`>zy3ZhYKݗ~O}NnMk ~V]ZxǺ>67!<~Z]>:~~?;5׏uOGwzˍ?yt79e_C?Dž]?.;ח|ezݧzogܛ߫>xŵq7.v,ka[O> ?xyWbwA1 G_k~r>kx2ns짎;~؅qҮ g߮37/7]c^}w׆3_wk~bGq[5 ؛:^C{~Ekxd5\/|3__/׆.{a<9>}s]Y~}qk~1ߟX׬s?~ß3gֆa_P?Џ`'-qÁ{7Wsyͺz_.-)Ϸkm]fߥzA}g9q~}y/1v^6<9gf]s4u|mj~b{7S];I¸Il5n}wj|uw">u'Y(ݦ݉ؕjbҜ6a䝹InGxSqnIZ$M곩$nfFk$4aV]O=Ư.$q sq߭ dc;}22EfgڝU7׸:l:Զq}F嬤;ޤ1jnFiLiG~[qi&>Xil븴,nL)OugNa+{^Rb4겉u뵎3MMɏIj SJDk|\ v(7NNJڪ-۟&zN><\+}< NtuS|Tc;aX?8_||{ݺ_F~?߼gz>U׸J>՝k7dvӜz'r)·t~_G$~.]_WuӨaTx'μMy\5O]JMhR%ߴi&mt殫I[S%&AιxMdMԭqqm¾I&9h:{i~9I|曬cݫn6; H+7=ŏ/-nf>[^ڽ߶n1ʫkޏW>̿tsサNu&_8nq3&&M7]x3Os]; ]R~WwF!kF!kF1kĬF1kĬF1kĬF)kF)kFU֨F5Qe*kTYU֨F'ktF'ktF'ktF'ktF'ktF7ktF7ktF7ktF7ktF7ktF/kF/kF/kF/kF/k|֘Yc>kg15|֘Gc۶zێvRkK-RkK-RkK- (((((((((($$$$$$$$$$Jj*URVIZ%Jj:RH#:RH#:RH+ԺRJ+ԺRJ+zRI'zRI'zRIm^jRڼ6/yKm^jbIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ $%A, bIKXĒ D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXŒ(D$%Q,bIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$$$%I,IbIKXĒ$TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbI%TbIΒpVo/_zpartykit/inst/ULGcourse-2020/exercises/data/german.rds0000644000176200001440000003142314172227777022240 0ustar liggesusers}y|\Yv֭WU*-lٲee[2eef TKer$u Yߏ-5$$/ KKؗu:t}JR{{z*_tU\KWhY38%K882]י/zh;Sgr] /X̒3^}fwfrAHvk9\ce?+g+s˞3||KB+kV蜅|B2-B<`|l08^V}i+o 6ۯι1keD](WZrȜkep~X'_x}c %aVg6>aQSVXp|^1θe?P X} ۭ{.'͵W9fYUVkΪw'^6q^ϼi񧶕c.y1[ Ւ ~,}ʻ1!l0Vc+ʝ+xmqf47/wok=Ϫ9Z',0ʍUkP][XL8KN'r\B8>F ӖV<8w^Ċ9)ښε[ݭm\{gpD^f^G͛7o_h_9‹55~={E?ؾluwvglov;2YzTpȻ5ӹB8V9_g?E\^fmxǼ?cJΟm5-6-+JkxW,Nʑ:"u>SJ44=^yu=ϩކ~lAk쑵+J ~\b35?o[k9ւؠ})ksjݔ+ *w $BS^v/n]sWcdeCe4~h,ed*f [smњϱ̝s{kIpT6 5,{2.%o|Zv'\c)oǚۋ̍DkSjQd3ʯ?/(Ygɕך+tnz|8N9VD>3\!sW#z~΍1?WU<wוiUjF8bQ-7‘"W}{1}n/xS WR R;9Gm^Q"{M]25eIzÖ^Ꚋ\k.ܮcͽFr"~-+E֯yvAsI~TsfŎ&o UuO׳jΜZqNtf3*ɽdYXVrĿ5e`}^˜::8)ئyY^ןt{ 7QG.9YjG)k*=F*x\n1jZ#[=GcTΚW㪒kBO*{ܨE)k5̫wݧ^Aר_$yTrx'%\[m[KɖFbƥ|97¹9cņcsƄEoK~ypMIɸnCJ}齪phFjE%SjJ5/=yW@NOx-*93Jاkyuxa揘ʓ! ^v.cae9VYBzN-{u~C18![7jOVCUdӐ]nll[ݷ1o_.v:ov{:[[Ft67گwlon=Omn&;?%vv`6fd8^ͯ?CShJֶhƪL>GHsS%CMQ!9MJŀƞ+vkg\5Ե"B_1kku* <&鳰ĸ:Ö:/pjZG0n?>xYŃyj8Rzqh%Vmq_c,h86zgg< FSKKknĹڏ_Zk~}[)9ml#8:%|{²[57Z'uCwZnj ޣp-i 1'-ۯעODcZi.bgٚõg:g:G5zfNc Fuڤ 8'ܓm>l[ཐ݌ecun2g^!`~e>{&ɐ=,c{EZ+rZO,f|5X]1t4ޏVO彭Ŀiv3#}uCxK=gߘtQf9V4 s5Cw/gw{wg=0ZUĶkw@;m|p7 :[;ݭ[ۛ,nl;lmvz]QXtt6G띝ҩ:{ΠݓnooCߊȾ޹/cs ˯!*'[Z?;wks!)hi|ʹ _yr~&L\yF Ν#xй9Ok-lX$2Þy\2_qUps0>uf81;C6yչǠX5;{߇0T=Ɨ gç~ }klw:x il~EVr=?χ/W@윽+ν!r/aƖ*d5³/t7 G0?%}qcGD<);{9rö)-COq:wq`˧1g{o<YF\k+d!w3y 9>n¾WNAOo R?k8#&g0o mMȁsQ6ȇ) <g_]!c|(r{y5#`T؅ ~@`r=:dCy0\c݈!rWb{zwˆ6U1~ϫ2,; :gf9._żnqC?oCS]S5^s!ugg08k_g8ˀ陷qFM/ P Y|qNXcfP_/~ |Xc=N!w~ 9Gqڟ"fg[gas2*w10>a.]5Z,jl-؎L#-o==sb@TP '%0y"?U1\Oan]rKQi`C[V{o 0/.~'-vG an\YAmQSJ u[NMC/g=8!jK=c5{7:j{ U !^frK5]'?<ߛdž5\ pVqm¯fxB=6QKs,po <s7q_[[C8\4a<5 _}^nࡓlfX3XϢ.*ry>3Erڿ(.\T> ~3!nU!W]ϖy .+Sƫ92pK ['\XƼOqAp Fs? ,-{̯GZ { \RE ՁQF/*ⶄ׿9@f~-仆5`j ܣ'Th9=XLð/<وu6 !R~;:bq }2,|A(9U^?Mkx*}p_2|}XpTyνqħ ^"?U|XG]@}8:isRu8dCm.WY"3蓳1`*0=7l-|0P-`hGNp"zo\aԂ,} u2m><Ǜ !'Tuep\ 9h={̀z>N}1_:LSbϏͼ!W3ؑgY,= a|E`e 1F> lr8.#ַ/lߟǕ2_dž{w5!we~O=c [g!W׭BwMCnmQgk 5~ 6\ޢeg?2aM sk ^FSK5Xf!0}uҚ8FGmc=-|~i?6T+_?w[{ķګ ħr\uߊ(~g~ǯo9|TH^h_39u Zq$bUl#"CLL/3| Þ9gVc~—eg؇ҘaKX+cM0˾X,dXBya ״P>C~Xb8]ZYvXd/-l[<ĸXʜmoF8cXe.-19|ž7P91ӹ\b]C]gE,[ zNs|,GĞY}`d \!eU[PEu2t-{Ǭ#~k?;5\;٢ZXGJOpۻъW煢^)3KG%'צs7F˰>0bUc㼷NNNJX-[JsbQI<7+n^ޭ^ykwoD! D~$>|J?֡?jֲoOBj@k8,'Skk۪uXX~h^˱Zvf,X=䒑[rcqϜ'c=n/sOǗC9`bYwŸxʾlGtZvvܹ-۠eg$jF,m:z`^8Y5gRZ9 U(g>]gm/YW%]o:txƥaXǘ9,' t,ZEA}ۦupF˙Eb}ZX Wbɲ[,:\V1x_r\qp?lb %z^dh1֭XkZ~sռ} _XJzu.g]7,>jCϳƙ?BcC>,lWIme{όZ1`f9\! |z41B{+\{ƍ"j-l:n֋b|u??n 0wnϵj+󫾷Q"KSFl_1Sklլ7Y6 !+BоKH٫:1>X5mudǟ2N 9OO3z8 ǛsB>3c5XxZ| "zpZGCvlaZϬOPWcgo^hl`qa?k][e>\ǽ2?V^Qc5PĽ1 ɎYO>A!Y0g7ď1l-‚`Pęrl"N+dEO~]t[ z2궟oolw7nmwtGWv^ٻ~)?x3lBۛI{$/QHQSfh>*۷"߻9?5fE#Gw1=֤\`M1.&!c݇Lw#G{Ū0(wk*)*eawS)&-q5` >)xT8z1 )x7b2I-8l^KFC_i!z1;-zd`ƯOGmK5[8.heZկٷr[Hy2 Ī ̟_V8 MΓ'sB5eAnƙg-1Xv1Z v&vS[1ad2֬5PѾ[mՃ[-KV`L3zL+,72ɷqN9>^ks[=y8^V2.CCc>˟F- VjN+6V-S Xhj`硓to"wʛnnml7G-ýMڼmow޺|35vNү$8yApƱ)Ep~^}8.Xr>c8㸄e?cs8.z9蟟]ruOu~sS^/&'p\q+'Sޮ[ʶ'%?{ϓyo%k}]V>In.+}Kي&2_V1ϗd+/}j圏u^xXg?ȟ*Nϋ>S^^w˟}ǫ^E{ɯ_W%Ob73^aD~L䏧|LOyO~./Q  生{Ӎprcx6>x9w_;~eF}.'سֳ>_>m^m?GΧ|x[.xּ%71ɽpm?v_j-=.*7܈$NMWܨfN{ ɵy}b#.x9n g7_¿9Ozݷbyn+;xYp#\sk^e/E5G/(/mKna/mq`J8kۙ%9F$KnT+g}얼},xUy݈^+1/ߊݧ>>Ǽ^o. ?FtϿ}%71ow#|ōpIۋ{>'ݨny>I_nU7Rӹwܨockn%ӂKpx57݈Ks}'|>nqugOW-mzv۱_{;~/Ox! ˿]P^H-F~(2S7Xe7ʳp%7 ^uFl{̍e&O{h(&1byƯq%}dqU%5EbqZWjyō!~v_K~%w?{%?d?&u-9}sps$=.dY󢏋pwNt#ޖ=Wh$&}^Qe?ېs%7o\7ݨg~Hlnĕ7\ghǫ~ r˲Xϟ:՜nG>n vel/m}Yonc.&{UeO{;ogW>^s|L}Vg z&x/ 9Ћ/dl{._Ȧqc53eA^j(up'%7K~}I4NSkxr ׭~nOq;.L+$ՇKIrkAD-xRgQ<Ӄ[')ӯ"_&Ik{Ҽb? [=Ʊ'6'dAV?xgw~R'P\rS$zP|uLcXTJ]wXsCO)?}?*0 _L647XsmlKA5z/q=EH^)M51[b8H/dk%pkZ85ʽiS7N R͊oŅ>X,,ri@E-X.򖢿hnQ/I/i% E\PTV-ܤpQlq}`>53Se!IJƭUKqtրr )8qNJ=7CuWL&3d͸</WȆ=ST\yƬZHC6`(7Eg~3?Ow]~6>۽_^JcP[sCc!ݬJD굥??r %(6!)/Ah~Ћ 057<ƊHvflZȺXd닰(::ƕT/kh)kRbW&/%ס|>rx ٘qlż(aS?1Ll׎~cy3 9b?wf8|Oa( V'<=O'"|IK\fHM+ևՃ~{}<w+X\C2 \u??nmh{꠻1I'^XVΖp~׹n]gzc[۟lm޽hkh)^M"cY&6/,EIu#pm ŇEq$c51 ]σr4>wIl1 OERxq|)Ԟ׃0s~\=I-wT{{77ׇ &MwH)=A|$v~%ԋ݇ 5畃|7p?hjRJT(R Ò3/):R %oȾ+ZXQΊdTМPb+&DJNs oħH8˸r➂]k$c):첞+:ʍMNQr8)b"Ű0-"{Bbܕ$┒:Ū(WEq+gQY{_Qˏ^ܟ?ޙXa+D"C[qm$1K}?h[475&{OX$NUѺX.w$tuPj:jα(%5#TXMV&8:bv8z#)v)^(T*Xvbcܔ51^,$5;bS@ME5v<3.&ʵ8Rme.Ɖ}jBrqǕ“>b/_BS"ĸ`{띍YY=_ ܣ+}Awcs76?[{"v^#6{P3<y't^g뵡mmw?w^sD;2Ia]M=!kGtɣCAڂ[݆1} Tb׃nV[>x#!Aw^ﵷ7?1lnIk oߔXrb ͍N~Xk Upartykit/inst/ULGcourse-2020/exercises/data/titanic.rds0000644000176200001440000011445514172227777022431 0ustar liggesusers xq <$JA@\QR6Eɒlٲ, Hqhvh'8g;qa%;gǎc+>ǐsI8;s#]]Η_U]];9~TWWWUWWzy-^^H/wǍ/U QiduAVT$YեE``r\^ 7_9fAS~nҏ7r'?i R ~`xS@m~;UJ7MV˂R/oṻwOVKO' -gb 9?LuR\l >_(&~5+MQPN_abLJsSA\fY}ՙH엖sS[UDQHL x J1zo1x/8 Pu8/(l>&@g+0Vj>*.R& A[SpaٟJD .c&CcP3VlEB(47~X Ɩ_8 U 0P G0@TW CeAky%?~·@3G33z$[ a?&L΄Kk0tS _6'8x2~, j^üo oT.TL"D㵀1Bm".W45Х`%70艥SӖ;<y.zR>xˍ' ~n G/NmpX7<pt2 S$L:K ;@Q>*Z@()Taai9ITZ*#EXHJ AI $_]-B`b-RT߭P`O @@Yt??ax:W%-؀Q2+Bb0QuhC?PhZv⩙ 'Utd)AD`t)7$H 8܅|hcx[\yeBr"Ši+Q"zDb,P+RK岿h4K)a-* q^ mV}';/DD+ )2b>4b iP}g&r@ҙFFWI9y?VJ|6*i>W'}el&Y Qu>7KQeRa\7?f?E1X.bA,0ABJJ "W/4&NbP*| e.b ~PHm؀ @#N=Yi2b`#HY Uai> 1S>/. BydQA/7|⤴s9m>\X[!rKb;r!? ݘ Ha-w* KJ9+dˈťcɑ{ `vA$K]/gs00hlC@@t?c"Xf%D@ `VP2Z =RcUZ~|E7Ow` KL q7 R 2y U[_,k8t%L6r04R21[=.t$ni.s0.-g]\ATH:ā4٪BlfPI8fbƤƢuh`i"Erd.4w3]nt%gהtpE#J@z &z棐'Z<@:D`i.De2] o\Ҽ9΁\  KJ;CSsy;picY" 1S_J rL%X\dTae{5+c%X-s |bmSZfn%*D[0;E$qȏy*٬v6v DJo(V $DbnZ%Zmx9`q9Lxؾ6y*D&ùC~V R5k$+cR; i]P2֡ȴNaJn(aОAz$^FVo[^Ԓ8V+Fh%*$Nn-"`RX @kJ[˶ h L4\*u!J[lׇN@BT}ht9 fODzD5\7YXf|1"#{kт 5%Z'*_:.'_Gn#(IK`D9 2O Pθd}b (Vӟ J m6p7^A$Qs0Ŕ2N*$Vz"p\$@J+!s*/e~K>' dӇ Bb內Jd vYRq*OKV)q~6]>2 ٢"JaRf'%eOþUA,=\93 }92FKBϫb ?r 9N1A@iLG6egZT[d4)| 9 "Yˠ6C06k3Ehkb{=Tn=KElMiEXя!@<* x/Y6KWze 551]6L0/48 G(dn=٠e7gBf>L:Zrs9b90b_pv0.2@+1.1hvʹ hIo~n #ܡ᪶ H QnTF.1)"zղ HF߆0HLcgɝ=:_DuTT\[5pBJYSKqEn8䣨d !%֑Ǡ4;iT0LRxQ B@'[ @Alyx0P `hxiI~mIlج-cCE#%ub@z&@*ighqB˙!h+,Fb *h] n{&j(\ s^e_>0HM0o#;5 XѣsM0F-: Lt>S`:Y HJGU2fX5,Y` F3V@"ČqI{8wؠ")v<gJWZRk"Xec'6Gt( `ngT CEH ciQM'H>Pڐ,zf9K0."*@RF,ZY]CY/,qdYxvRL$dPN/8S%IZmDX&/ $yK6*lN6p#XKe, >!+p0:nj6Acng׈/a5 hP/Hf?<Kق]ۺŐrQu@TwZ&5H(2&H!j\djhٓ._D|mtm0jgm߉ƍca' ;tb.-~E󈣲W+lMx3;IZPQ&sw@jWjY>m9>;.U"U>V[Z)cdĸIg4\PMq!Gq%Nj4ik.rĐOSE{Cƨ֫?YE䯉;|c ) hl>Z:&%z @aħP1.|->P65B3Mb&K.*jrRxMTAu$6bbygH)M^MWky4j':4i1yH+c2K6^-YɣK˴( u P;jU!)WCEU{(i,ɞNؠn # ~|Udp7@H> DF˝Cz!gdAe\6ՙQEbO]v1\y s$L@+;hu9$6=NN Us p)4MTwR?|!gBEH9STK!e rΔ@FPʓ 8]ޡj\d&BHSb}fѴ|ò? f[)|C;}\ >ԅbhry%X*]Rnc<VE1*>te{xTE[ҡaǯ<ɔUڨ<$ڌ#tf_f}:j70j,7\zwch&a3K:pD^maw_?aI]'ji}YS0 /lK ¬' lݑL8bKi;hiGGdqqkn6B8JUN@qqīhUZZ+J] |lUd]́4~cK%y| i.ðj uxSB+W"8+ v;X#"Ol@7Ӌaf?orHΝy`$"k+ W?E8tQD*]Hdv`U]ԔdiqY}o9ba6X@]v+.0O.jTK0&K2J6dF+$nHb%2q\ dYEgɷ]r16IsghK^а'n;4J%l˵0p`W]H'gEd h=G  -eB]+t G6 !z4leu@!.b@e% N*!7,f}2VJo)XpnP A-91L:gt:E>nw0J(p{y5 kREhu V!SV b(9h_H đ~4JQ: C|bC%믮u;J~YG'G^Cص1ygv4 /LCSݸymEcϬl>S|Ɣ`&0 R{yS~AfWWP3Ӟs Vr2݌9NW1PX=gP{5ij T$d og!{bL煹_{>aAhLqTLdE ,@ŔN18㋽M@'uE & yZbbTde2,Erbhyf;[jK95@,32x5WQ-js_"9c"}X3XlWLnSvocҲ_rBXase>m#w.%*wvD(}TWB;뾵NRc$l Y"ڨH5i0u ajl|I ˖SPd %B$EvN:aZrUkljbl ,2^o?;T 3~aeXV^xj1ܰqΪm:BY5"Z . п՚-2n; `S$RCԷdŠ&5{,F u-3U%Y9[^] @\+6$߈qf=CGc6͝9h`$D+nG@ &3vƥfEMB+T`Yg'@/6gWڮj#zAF鴫G0}Q_!1T% )Tu oBnv2"' χElڝ+OWRDת h]͜ݥ'0$G_βC-LQ\TUu ̣;]rNi-@q*sdG9R1ČeW$Ei5[z\$><1AZڳJHጧ`( 9qɱ1(21X4"<W{tv8:ET~櫊A3a\z 1$-Eu{gjmF}aRP+7w CyWCD@ 2˴.eP39q)`:kH.UI{,eъɜ(YqdKI-B8AVY3u,jKrD*̌a-]3ƌu=#^9J3$#PC;B {ÞDu:b}”)6{j}lKQ%G6>l$TgO᠓<4 X*4/•ywNDBH"m T987"`⚃NNBǖrBhtNA=7ɑ Xb2`٨|I9)Mt>7,_0F5LBP ''JTn1LbmTXhPi"&cNPN38potYe!TDYI)jckiT0cȶrBVu" zpsT:,,?\|tv60MR>&Hm0Z<_yD7C~j0YYH>kIp H8QV\@vPAN03o`Tֈ"CHXXnHv^h#jkjNDf@jbNDaG%MG1窝4AGb$\h"Rpm#("=HP/yUTu,9M} GSV8l6 %'t$*Qt%$݄CVSX f ODT>w|yi} рjgUZ#r+`T|*f.KaT A:C(U|. x_GӠ aF rҔN)#'jss_=-X7wz9&<.[&,یaREeH)ƘmVX'>m>c꣊]C{.b:#WUtnꌗC:-ٛ.?Ƀ;@Ն 1;糸*ZbSdR-\W1JV/erZqc6 bq{h88Ve+{@#QF!eɅAq1^"r3c*t2Uм%^UtS& c<`1ؘs5 wYTY/k@M0(ۺI۴\^&~raTU8Jf_ъ;oU:Xq"eDƭk'h72Xxr\8 P- 與!/3M[!'yնK8quYd ttY"&q΀SI]4;x8̀ #mKU}sWE? 70Ic2*UִD[ɣ$J"k(@1V~7BwW&> P1XDJ•@Ab_ M2ϮuI9Є˘\s狻3 +֝eZqHbPQ"Rn361zPǟTZAc;0b!ꅝF _xN0DRa^x:=2Y VW&darpB-(3 $Zt2:l!ਛMlQ'h>H$RG|u!ONnTPt^}R9ƽQRJbT`up>7tÁ yΔFEڗS9!豆6rl^*6@Nyke;͍sX>BzΝ/?&O[˸ Z)lXg2jcbF7Xt./[([XVՀ.Ivwl`8a·`2,Vk :·Y8ڋeN Z/Vў c#ׂYHz:N!ο}^X%lqㅧK̺0t[zfς`*H)^˛ϐ~JE\# 4݉K9(*J㡊R)PA5#w =7ԡ8G};0]ޕT~$,w2Mr>s=. bڑe'U*2qGd7޴{t\89!8 ̷bP䟱}yw 3֣?Î EL}|v 3&qʬt_k `& @ήB1pQs39upsH(etc͚]0k9u%Fq/2W8cO\7.A}&M#5N <;6Mt v7B_g+,ZfRIN!`@RjfQsIEr%Ո̎Bv~xҒ.ϖ|Ki4A8,Ra.<lbv̙]S~>NS"oě )?, [ؔ_,n>]΅GT\V]޺y-Nt_IaR}jb}ChʒmnjS~]PQ+:0g#Hs+pSXJy<.Dl:gNYM@*PeJ K *)^9 jf)`&)} Q&0plSIt)&qX0 2Ebt1x֊vz"; hKBR"9OTt=ѱ]tYv{'}! S>(r']a>]{2Nۡ zQMF/娤? UU(N>:"o KUx/-{d.~rkf1gCA3[h!L{ږK1ғ0;G`M8dhdS&=u SԸ ZOXlL5j.m( Ŭ`-(5$$QDj,h%:eiЉJl$|)X~ 3YaK *`ojE'^byX{pޮlmpf]KqUUGݲ FR  hv`D#b,FSM&ϢDX1kOUwL)hQ)P&buugbHyEJpLAMaRs;u2ONE(Mxʝ親E{5U9Nm8N6}Өǐ*(UU-@V;jNa4AzǍtw?P|Y+U(Ƈ|:lۦbVr!Pz8:l8enpXYJBiC 4x`PnT`ǧSW \01wBqv7oX>0"' ,OUH1)qqΦ gMD kNCh:Z¹ؼ|9*ER* 4 aXתQL ڝX5ȡJ$|ǡi-|k Y!HV}qva~s*u ba_67IۛYk0VW3:\͝R`ˉ1Xo({Z6T@Uʝnm$7s9?4!R6{̅(]T;- y xh*:VBDNuDs%ۣ|E q B:s&K/lU@ A>M2nNifl¸j/䜙T\m{mVJ,΢yלUwa|cs<`TvLby`d|i3]ۋE1i@C߾173>Yn b@& c?.藬0+M(қ7EnQ{{;MjEzmnj/6J8yѺɬ6V ɮ3>lM\?y(%|H$pH SZ-g1wofFбVrHb TY6_:djejzs&:bźsXY~f6Y vvYbע@;59[(;#Hg?z}!s|",-DŒoz'B\|Ӕd B:y9GJ7y7x[ML8%Ta-"J*]{P\77k%P^QwBT1Lu_>+C+Xrd6.T]~ctYvrE3A~ib~>F=4cbҍ X2n 3 ؀.A1sM/k䌥>_I h`e׳3a6tR-1n+: +~Θu O:v]s#j͎jÞ8PAb=-ϛ 9z&,c $7 JyB* _Uv h8ط,Y=?k3, fjo)9WiwzD̝n1;ge  CFQ؉vȌ*p-b7DAɊ:"T2"4C'hpǸ8\s=2%8};Z?r-Y6(2B6Ԇ'udƽ"'^ k]` :|KbK@ШܱB.`wR)K`ڣ6X3h!Z3:)o2ѕU:b)UTTkgVԮG&}[vqǑ41(6dZ$L~#m(3,'Gʆm""79ت)mJh:B %=T G67+xfㅨX!bܳXfIjD(pghV@"vK:|9%E낿l 1f3$h6hQW-\R;N.GfVM$OT6)]'`[4 ^yLλذn6븉]Flle#Zu?Qn QdX7xEy998|=Q)Pհ $lvvq"aN\o*-[#hgD{4K# ˕+xpAَۅrI6& Z VDl9ba1{PU 8,:4bL3>0d5w3\., -f`&ķ0b*(~﯊ZϷπxT]gHvrp5xFNTQ b{݅бk~z8ѣgE0# t0U,ns̜_>(as I$#0@+Djr6+v.`L?EE8xGy~!=GHO++!ݳ0?Z-`+.C77%m !bfKY:S4Ad gi.@t&o1HGݫz Yy8 ٚݝm,bSr8ge hiUh\&'A+ꞍVhPM0÷d+(v4,)F"hYЬxr&P^i=Q%hDlLUWThsr2Z" LNO0U[jua.{ {U=^JHAAԖm@ K*#ub;xcv@In2!TU:MLJ; j\*/]&5q;0ꊘb4b[qOna ` M*3%`N|zr/Ս2958zWRJ+DJs HP֚eo"pCt)ʼn:j+(&l٤4oI.@ҫ[>n87KUagޡε8Q JhV=ID_5kg"AI RqQEgbnU&w\ DfG_'vKh::|݅ۈIvr2⺩Wq`\d.^c1A,`! {J0tc_~.51$$*$IOj%6r39;,:TP~ķJ'zh7@9~/eGs?[޹B11z.cv S1UVV#W8eYa} qT LXW@/aE{kGKrJSbD~´k.#Qy=XT^WE84Gw|grr1+7b4@5I84wcNs7#aVs"J.#2@2i@+iv΅ VF -T~TTfLgSdTg..[(SQ53%f2 UnS9ub:It`ripH+xO↪ݤ'$q20']Qz:&< ex{uεJ<$"oOT1*XwhFӱ6?nN頛Da|%p㓡X8V@[:At ʳK]xg6hFZj嘉M>fB&"m>m5~^ǒĴ__Ƭ sgvu!;w>TG]qH,T`3I(ciH ӎp5kUc]}cp_< |7V)>Mn ZjI??O5/Cj3Jy8?pIK/?Fb){m49Ɏ+2%UT∨"E7;lcNz @9ZŮk 爥cʨBMeTC:p4u9nDcV3rO'9 ?ƞg9*&B&QźIRuoE\8gc%hLT rq?|2mr̀XNǝuv)Kg}]Z ͔x|;n p}dz A8( Oɉ]$]x]8,PgQ/rEi@> =n,:n$iXzШTb Ac~;@w Y E%\n8%#::Bdb4T-'+P<4\ĠoD ԑ.Ry"( ] YUUgrbͥzL+$ 0M;9㑩XCh}'bЀ܃j7 ܆F0 uΖZ}er$?\Ӽ5{@P5WJs4;:`!Y0`$8|Qu KKe*AÖD(Tf{ɒ( -,p5򆢣Eu&thw? .x,Zg; f`6YexM (+c.RQ3kò=@>z]ځ =GR,G"!P . e$qA΁h yFSU:b#y` Joqv2^VRWlr]I" vS:цekRIkfh2m0ŋS:~D ~dnQl?9xIbeZ*F8N}@i63;mx!Z%,3yxd)ff(Sx6cy@QwK$4J*-XmU Q1E0#<'`=~ur+<3ͲSnlh(TXfz#܂J0_UuVveInց* !bMr1PUJCy^nǸj$EX*acF},)e V䡁:c *$C]67 Dr׳AX͛(Z3ΑAil"PоA+ iqзjA %ثbso3w!)u6SP[\$W٥At2tKi*Rv5}5™""oR*`!dnHnx;,R^ɍWdU*m0nǏ. tdB%죳 %k1c\:5 x>;9L ZS,`Rړ\]g\NbPHiYzk's7 Fvѳ `h0M@=@ptЇW0ŵ=3}PIi>wFuӠss ;!DuX+A ^yMF*b.# \4TY`A1ķ)/'!m"z9JY۠wU#}Vv;dzeƀVĜuIm]OiUc 8<x1pw]$ѶT,6[CsF>ctmq]j5*K[,乄0-!P:0;# =Q BV>Apc0cN ?K"~Uk9q f9w5sĖ͍r9/ptXJ[0eal$䕔ŋSr}˔Kj<|*il|Tv!z$ƻę aQQ!BNDUꌻ:$QD]Ѝ)${ * ntq8?r?fLʏ6GBRZ4 Ah[Sj `ɢb#aj +}Vj5P::3zX1QQ׋Aw5E J[:k4W)]$vn@@Aft q3G"k5"V)ʋ& pU؃[-yZtp[YU+::G Ĩ3C˫06D%&QuQf棁{4pAՇQ"3DTC`~PsvBݣQ^:$}/@8g'FE:1; G DiKBY-S$3mLD?m6 2HmI,;P<X_bed2\|HpKWrÛa8X:=pN|oUé9n:V g,DdKK)֢1E&%shsED ӷ}ra 11er )Fkn|zVBJ:J )!w)Gy)ݫ|7ȑBUn6ۅvlv';% tC؅ՄH2m(i~n(0W#.]'ng ~L.2-amRݶ3 5vo}9(]֜58QqhgϝcA}| !eP`-# iX]MŽ+"Xg8ԅ h690 lVxd,)`=Dncc!r 3 RZ([;gϘZ$UwGsTTXȢ;aنgJ5'U-lh"vo9(~[FPLg7G,@;͐ ͵)١"=H,DQqbhuLӑ>՟!RVÒY5C<:l~q7Ƣ2kQzYIM njnqxDbcA=]g2!1"tY-'1d7]ݐ8`6hfF(pYh ppF|W]v[X;G.]t& #qYa1 B=&uwrA9Kj|Ǭ  YPok9REדfwN. cԪ#mAtJɑTג d?`Ec6W3g䔟oYPA)+gKdw]Ufe#a8|_O6*>Qw}e.Ft@7#sr$)8S1ew76'}P{ЋT@(3 oTK. #O%^paTmD*dr;zX^Bb& S{ON*ir;2] wGx#ZNTv-N2*w{:L*"5s1_d1H4ɳ'rt$^x/vIzyj wJ. ]0LD$dz ivdt tCZjuPU5',`;hAlLY]P0q@VĠ!*8mo+W+A:/nw{n \,юuijA7A1r$$%NyB'Pdk7prB-͛œl]W;@M\S|^([ Raۅ2џorR&d2,nLY+ Evȇ]C՚dò ~|ʧð3C]\5P8. B"57:&{:@r-3FVȓXA#$NÔ J;K0a3d pmXۋN(UnRv@ݔE>$^Zf0 `(43id4.FJ@aKN6qu=..y#x9r,QA犱‚6r_ٯ$)AtE-_aG)}ybЮ6R&W GlNl Tq:\ȱ+kmbXsaN΀TQpkAQ~Y;%iwsŞ &rmQb˴t\iFv9.Y#~T7o={_GvfA{QI0) @YAX3 6BgyYNst _-љ4C.?>]-ݭiYq( J\8aeK]ůDv(HYhl}qf}EnR I`.H"Qx]K:>Sj:xg+M@ιHZŕu|g&Nx:\Յg2:f¤J-1+Cq`#{},s#iÌc;/}4"P _HHTۊ]k8jPW=n\Pޓs KA MRڗ=_7~,fM|PEհҬ4=rD۞ ?S}}rJĦ%#EMed=Ub۠ut"Ye0_LGcϹynPF _HyR Crp6$T9-q/tȶٛ>㥅Wu:z6rL%¸3%[TUx/d'a$*3aIR8Ġ\ |ʶ1@g~䪣&p`l/XMgg &<ݾ}/Σ6/#Ȩj $o8J# 5s`wڲ<켕 fxVޙY.lQ/x+e2!3@`mǝAUڕE@c$gml!Iϣ^;4- .aD99fIR~Q fa]YNXՀR}b4,rSDYmlT. KXѰRDt[f&ZQsՔuϪ ˜E+_lt9~llc1O@NW+r-75q8 ] J7j݀w톍wy/F7\Q:%yʓt82jasҔuDvX^o<iR7 Y}ҟږ+Z$΅6C{s΋P'rK2;J"tt'} d (X6U}|ysNDlv1%9 KPK!L*}7'&V{0fߧmv-kݙUq#{7a4BQM{Yr{hP  i`¿mj S54xlL~껖9:ج#'+{^/iSG炐gG9~2Ӌ룢(+/v(Y\^8c|e\"3v`Kd,?qD&r1Xzh>P EhIi]b.[3V: b/*1f^U`fbY0ۨ]AJ2FXi[u** F99Ida,OaHs/zhgl-lW gQR Üxv;%]A'K:o$VmCE؂ΏlOBei9ک^'w;39U9Tf2GT]\2o{, CrߐVs;F<mnp1lXxΙ&CZ匂&3r]n.)0Yy}nWFU~V};Yimp(/F}>\ s2%L=|gmfWhfQYiF8hو6phzchCwy-~|Un{Ϗ?k}ų7jm}yby8xD;;,H~yJl?8/uV؎469Eta.KE|Bo/X,LBaWX8Xۅt =XoׇS1 *=Ŵ/g~#~a?q#v#~{lcWa.=ۏタqx?~w@xGKh@'9g8r'z K~ڷ'@8-IC)_I~t|h?-S%8n8DNs7l5'څIGrxK8.{3O/r^#ߥy/Epr<~la"]*?mW;g< 8??`Fzr B(3q!ca^7|=GF>tARq"%7Y| z)ߤo8?q~%wq|H~r]|S$=K="=;}/hcp#ߢvoX7Ky $xI7op< O./#KF~#q #EM/~,ۃxA:Bc?>`ے'/Z'pدy⼑ۅxqF<#rc\Er\d;a<~D<o>둎Y;ﴙYzi\|Zo]r~Orp8?%ڇǫēDS_>ghByM4 ~p\+S8JA~t|y@~'/ r_> 0ǭ> We٣P^A~tߵr]J꽏fIvf?$/Ѭ'[us-~/9oq8~W!^Oyn=r!ߑ,{o췔f]8H)g)u/gZ/rm'D8.=ٹ!\p^;X/1NO|P drfJѾȧMܟEyL'G{_~Ԏ{% fsXπɗr~K '5F'D>g)c#8^r_-]@EK{ܗKClWo3iG+ob@<=fuKE< |] >\__ΈX.C^7}$;h"Iu8:';!쏖'C^ꓒKK{'{WX.mH鏇G3re?~Oa|)o*i_#9[r\RNJ}v98=$Hr^n~K8R)Sڷ/ˤbR|$ʓ+ɯI{nI;%C"GK },c'-E]J''{WD=nO(弐z3ɟKć}둌r5W}=8ROz`{HN0H۔6>(*{@Z|irH9M6Ky\3Dg9pm7+EQ$H$?yQw*%z%+!Cy)j)IEm3M9Үv83~;InQ[W{ 5Fѥ܄oO%𴮛c9X/qYW(8HJ}Z=y>N=_Nri|E}*-4r7GC.Rn뫴fVǓ~:[]ڕ!N'T|#k_뾜OHV%k =RnRO~үd˕I ?+.! %>n $?B+\W-9}R^)Jq]qr$<:""z)e9RD:|R>Q7z;)I$ {/|JGһ18}-//Ec$)χreWܧ9]XC>#/ r\Y)(&/zŭ_KIF鷉BoK|UWRR@D`;}ACivH~Ox$9JoiDS_Xu7E vA/9Y/5('K{;ʇ5uWos)}(iv>쪟ۤ]S\ dٍڞ֞]qw]Y?7uEHl|/* avԗ^6#>4C=dIko-d1 [F]o!E9545+mlh2Y 5vKvbICYIFs:k-Ț{i<{+sپfaTo6Ci<+GqjӒllw|"iuԛzx53Y33uV_46Xڒ'9+sk\#IYHcژy,5KYmZozchlF)q]G4zx\fi$.!V0kLksZ}pni863پ&ȿʹ*6mˢ~FY^5g4,ՑE'_4F3syL'_f~)i\ez4k4u:/5[ߘw⹇u=,? VßiM;̴w{lCVOٿowkʻ=1 >khRzc&Cq,l4Y(Nh%-/kNgCuն1 ^p7edKOkKZ~fSrϢ4Z#Jy=JxH/Y8hT!Jl=_ϔxGk)' GYAM|~HJǽ,ɱEity/$icڷimKKXUv[O%l$7J\eѓls_ϢzcUn 6KFYäg6 N\'^Wz'oM3Y7gW䖞-=-/)WJy!,,`ݼh JKa)ⰴ伏rů~?ZP"ƖD2{2ױ`EYw_zvLFY8- ʼL++:#-^9E¤ٴZё_x7WK ͎v("l3r j`+l^֓gzZ^V>f>_[ռZvoԾ,z*oc*4fP̝o$Vt-ekMKi_+@'O⤞<'٨,CJƨdz2U=:N[hd!m,pVΚgiߦ)u%~֠zchnnF4yOI=`+tl_fX6‰lk5l;xz''+] nc}bik\Z{|hhLJ*}3tԨ| 'nzQEߛ_BYײ]i+Ϭn?gYش.LZeN[g%yjvյC3[sUV{FxnԦv4CV]͎o=euulfnۭYfhr+of5fiz;cݨM=5gkݧx![YG|oe\jt .]RvhZkF,}ml]Klе,Jۑ}CK6,_fx?o+-YIݦS&<1b9ߩnfubMi)C}%DٻLⰻyʴ }Li?{;ZY:wy5u"[!X!Ow>V1iŹ,k?;̒}w?crOlwH)0+[FNa7n&0Y8 Saߜ`0q2=;?;^M|ylr$v7q5SY|r9ҙd%5_mScpg.u\7Hg"nLy'xIN)ΟFy} mxpڸΫn9_;I+wy`I\]S'Wmh1NRp ]q3^3m,2}?fxK\`X^}F ɇnf i Vǜ>x\YqɓV:Zzyj~NxxyBk(CkLrU e3`cʿiZ3Yx;ۼt],iݳt,e0ONzv=Bzvc4M-'͘L!`R4+pyjApŲPSWqS>\BO7fմc:Tn~-DzQ2Vo*MO,>{SN6YvG-No&]_4~\tVj4(S&YehS_7[5U;iOƷקnVx~켕\v-/㥠T K>+_ u9 z De^?P-.x_k`/bleg,*-?h0 f~NMF .eSۆҊ/KҒ%sH q̱j gKyqJm=[x_KX_YM~)p!2n<T A1v>ջRέo/_=SA\ŜMWe;h3 Q }C3h_hC 4U+\b.֙U?ͬ8V.'=# F臽ve:yw/$]=o?7I7ۡawVzN޾Knqx>yOm ;ÐI|?:o_ ;`0z{HҍK} voo'ywN- Ї=0 !~(sKO{:NП<{;uxCОS^ӀKt~~zu=뾐/؇}#g.{砮g9 :ywOw_y}Gx>]OˏL{/|2N:a~Ko1ywc^{,h^Hc~3Id'25o>z;9h_xA߻ޱ@{?~_-?x7%Ӯ[ZyHz~f_ yy v%Kz~?tg:{?|  ft';:yZ<Ϗ|iJ|~Ŧ,wvt:h<N{_ IZ. \t_\ϸa ~!I=}Atz d_u8Do;ޞ.B}' E%_%H״] tj d!~2PߩILG{蔖[V? Pku!.3ZSUZպO*E 7LL~ `_QW< }< d\G Oy5gW@>}1 }1YcVzfko(΂ܼЯ̾s֋Ye' !X|j6=a&8^IoH+_!j]](yC||!6t>e Ǘ>/Cʴs* hG= ;r^+{(oߢMwLRjv= '013;{D뎻*%}@ o>MF{`S֯|/N<|GAhǀLO7?%еЖ7Ae^Khil=c0&)IOa {-GAh%iJ#J|#dI 4K0OX %a]S߱mcd|3SAW&iȠo6ZN:kwXg[IRvwQj03=ip~ w='yO|?'}HS4vAyͰf<_\<ȋ2!c[>U5n;i'vNI;i''O}=?{^D7gϛ}x3=_|LqOb_}=}ęomP3|C^ -C3T񾞻~z`WK_վu}/=s{>~5Ojǻ^G3 ';Mo7ϙ7YB{gGnԿy%yw{o|EZ<~=;]?_ߴz_+{_`2~_9]=쑁|xbo'/ ̓?@n_x3owxc#~+>ZzfZwN*g^/}LO9>ӟy~g7;̦[/j_|/DžScL1q#P-?WخЅm=?ɼ~\Yqǧ?sƌ>W}^7W=ҕcYӯ7c{:Ss~?+wo9=zyenqO[4xyæ[Cwj'J롛W){i^|3jBpw{C|"ޑtoQIO?zzO d9S?>_$ʣ~O?_߫)"C_ѳ_s0-/"Ԛ'CIo.َbM=߽wVD!?d~ȧk);|f| fg깡hG?|-:?#ٔڬ|ρI^~;.鑄~|-?УuOl+|jE"Dz4OCsť s{>=}>l‰?~ vZo񷔗ͳfBO' =0g$>ރq'G9}sϜzy{>'׆>;s.8yt1_S=rD}Josf<-!G^j3.XT_Ro^.\'GOy z%W7P#vR> }+ҳ,5ȭo잧"I }u֔#t9^ߦQƧ__z=cQ'獜G a~Ek1KW}Noħ헛O4|+쯘/ӥ' = ߇:_C~/wo$>?i=z]jO|cH qɒzQb%N y'tR޷W^fO3oίSմ?w "^.jl %z4]ljGX'O)ҟRęoX~g`V/^q$G=O!u%?(_Ss4S=8y9Pͱہ9h|x"z|׭##Po|扯SDrt#|zM;.A'h{O?KV5OSy4r|"՛ޤ>C8ag5.}YWIvg}}l?GOkavWҟ5;{/,<D||iAﲿ/C/ev {}OH.6'[g<]K'I|?{KO,Ub_ 5χnNa(bH'|}ZO̽D x5|3I\ka;+orZ]m,nTf+^Mly?}ocz.e?ёk78>>"ϼt7xgM?UcF}z"K/NwX}ʴei z~O7Ԯ#B.A~򧴓HO~-7cnwk'H{®Sc}BpoOl}%؞7x2+r|C܏fQO~`c]jonhOC﬑gK֗7BPb =?-~7cv͟fF*un+J>O<+ 'n3OwLA3|}q6GP?${G=|\'_y&K6Pt})r^-Yc'x|~%;S~B;5vGWXωi_mи>>o |֬cS+js zp~g~97ϚzpC>ݤbޣF?~'jg4w/~? r/co2 .i>a<׳ Si ^iHcE?^̏i3̓~f">ez&Ip+D ٝD9~ FNOd? >h-Dȟ..} ;"_(u󃊬^-Gv;ϝsy_xfVViu;VyVD^jyV͒_$s-dnWivp,63c-ܨowNI;i'vNI;i'O>5G:{mg׽K/??^T+m2|ysPb fU[l[Vs ^A=ҵ,{7KY)۱ԃunegi{`F}ZVMz\+O4;eg|VxWnձzw3;\E#>9f]gRZ+wto 4/g3N$T^3kUG]\^eY:ǫM5CS5OZȞ5U,_ _qVFjc|j|vmf6^-_Nŋ\v=mO#=΋y"JجϤfqe_fu5|avm7HڝZ+XO:In,kYY1۝vNI;i'vNIwbZ:݌)dx6_O oTWzVի' iO+fpp7Ͷ}+4l}YƢ=I<43noԟf}X4w3΁fBX73~^4ӗFt 53{sm[_VƫY*6fh+Y which also provides more detailed information on the data set. We can import/read this file using `data <- readRDS(...)`. The file contains the following information: * `name`: passenger's name (character). * `gender.`: 'male' or 'female' (factor) . * `age`: age in years (numeric). * `class`: passenger class or the type of service aboard for crew members (factor). * `embarked`: place of embarkment (factor; C = Cherbourg, Q = Queenstown, S = Southampthon). * `country`: home country (factor). * `ticketno`: ticket number (integer; NA for crew members). * `fare`: ticket price (numeric; NA for crew members, musicians and employees of the shipyard company). * `sibsp`: number if siblings/spouses aboard (ordered factor). * `parch`: number of parents/children aboard (ordered factor). * `survived`: Did the passenger survive? (factor). # The Tasks We would like to find out how the survival status of a passenger on the Titanic depends on the provided additional attributes. By employing a tree model we are looking for a separation into homogeneous subgroups based on the additional information. Our response in this case is the binary variable `survived`, as covariates we use the additional variables `gender`, `age`, `class`, `embarked`, `fare`, `sibsp` and `parch`. Apply the CTree algorithm to build the tree models described in the following steps: * Load the data set `"titanic.rds"`. * Build a tree using pre-pruning with a significance level of 0.01, with a maximum depth of 5 levels and the segment size of terminal nodes not being smaller than 20. * Evaluate the performance on the learning data by calculating the corresponding confusion matrix. How large is the misclassification rate? * Predict the survival status of a 30-years-old female passenger, travelling with her husband and her two parents who all embarked in Southampton and paid 25 Pounds each for a 2nd class ticket. Does the prediction change if she had a ticket for the 3rd class? * Separate the data set into a learning set (2/3 of the full data) and a testing set (1/3 of the full data). Note that for observations in the test data which include NAs predictions can not be made. Build a tree on the learning data set and predict the survival status on the testing data set. Evaluate the performance based on the number of misclassifications. How do parameters such as a minimal segment size or the significance level applied for pre-pruning influence the performance? ```{r, include = FALSE} formula <- survived ~ gender + age + class + embarked + fare + sibsp + parch library("partykit") ct <- ctree(formula, data = data) ct <- ctree(formula, data = data, control = ctree_control(alpha = 0.01, minbucket = 20, maxdepth = 5)) library("caret") caret::confusionMatrix(data$survived, predict(ct, newdata = data)) newpassenger <- data.frame(gender = "female", age = 30, class = "2nd", embarked = "S", fare = 25, sibsp = "1", parch = "2") predict(ct, newdata = newpassenger) newpassenger2 <- newpassenger newpassenger2$class <- "3rd" predict(ct, newdata = newpassenger2) ``` ```{r, include = FALSE, echo = FALSE, out.width = "100%", fig.width = 10, fig.height = 5} plot(ct) ``` ```{r, include = FALSE} set.seed(4) trainid <- sample(1:NROW(data), size = 1471, replace = FALSE) train <- data[trainid,] test <- data[-trainid,] test <- na.omit(test) ctrain <- ctree(formula, data = train) predtest <- predict(ctrain, newdata = test) library("caret") caret::confusionMatrix(test$survived, predtest) ctrain <- ctree(formula, data = train, control = ctree_control(alpha = 0.01)) plot(ctrain) predtest <- predict(ctrain, newdata = test) caret::confusionMatrix(test$survived, predtest) ``` partykit/inst/ULGcourse-2020/exercises/exercise_forest_german_credit.Rmd0000644000176200001440000001602214172227777026062 0ustar liggesusers--- title: "Exercise: South German Credit" output: html_document --- ```{r, include = FALSE} file <- "data/german.rds" stopifnot(file.exists(file)) data <- readRDS(file) head(data) ``` In this exercise we will use the 'South German Credit' data set. It contains a classification of the credit risk of 1000 individuals into 'good' and 'bad' together with 20 additional attributes. Simply download the file `r xfun::embed_file(file, text = "german.rds")` by clicking or download it from the corresponding homepage which also provides more detailed information on the data set. We can import/read this file using `data <- readRDS(...)`. The file contains the following information: * `status`: status of the debtor's checking account with the bank (factor). * `duration`: credit duration in months (integer). * `credit_history`: history of compliance with previous or concurrent credit contracts (factor). * `purpose`: purpose for which the credit is needed (factor). * `amount`: credit amount in DM (integer). * `savings`: debtor's savings (factor). * `employment_duration`: duration of debtor's employment with current employer (factor; discretized quantitative). * `installment_rate`: credit installments as a percentage of debtor's disposable income (ordered factor; discretized quantitative). * `personal_status_sex`: combined information on sex and marital status (factor; sex cannot be recovered from the variable, because male singles and female non-singles are coded with the same code (2); female widows cannot be easily classified, because the code table does not list them in any of the female categories). * `other_debtors`: Is there another debtor or a guarantor for the credit? (factor). * `present_residence`: length of time (in years) the debtor lives in the present residence (ordered factor; discretized quantitative). * `property`: the debtor's most valuable property, i.e. the highest possible code is used. Code 2 is used, if codes 3 or 4 are not applicable and there is a car or any other relevant property that does not fall under variable `savings` (factor). * `age`: age in years (integer). * `other_installment_plans`: installment plans from providers other than the credit-giving bank (factor). * `housing`: type of housing the debtor lives in (factor) * `number_credits`: number of credits including the current one the debtor has (or had) at this bank (ordered factor, discretized quantitative). * `job`: quality of debtor's job (ordinal) * `people_liable`: number of persons who financially depend on the debtor (i.e., are entitled to maintenance) (factor, discretized quantitative). * `telephone`: Is there a telephone landline registered on the debtor's name? (factor; remember that the data are from the 1970s) * `foreign_worker`: Is the debtor a foreign worker? (factor) * `credit_risk`: Has the credit contract been complied with (good) or not (bad)? (factor) # The Tasks We would like to find out how the credit risk of a person depends on the provided additional attributes of the person and the considered credit itself. Therefore, our response in this case is the binary variable `credit_risk`, as covariates we have 20 additional variables (17 categorical, 3 numeric). Apply the forest-building function `cforest` to build a forest model as described in the following points: * Load the data set `"german.rds"`. * Build a forest model with 50 trees. * Predict the credit risk of a new client who doesn't have a checking account, has never taken a credit before, is a 40-year-old married male who is a skilled employee working in a business in his home town for already 6 years now, and who plans to take one credit of 5000 DM for repairs in his own house where he moved in 3 years ago. The credit duration is one year, the installment rate is 15 %. There is no information provided on his savings and no registered telephone number on the client's name. There are no other installment plans or other debtors and there is no other person depending financially on the client. Does it have an impact on the prediction if he plans to spend the money on furniture? * Which covariates have the highest influence on the model? * Separate the data set into a learning set (2/3 of the full data) and a testing set (1/3 of the full data). Build a forest on the learning data set and predict the credit risk on the testing data set. Assess the performance by evaluating the number of misclassifications on the testing data. How do parameters such as the number of trees influence the performance? * Apply the function `ranger` to build a forest model using the same parameters and compare it to the cforest model, e.g., based on predictions, the number of misclassifications on the testing data or variable importance. ```{r, include = FALSE} # data <- readRDS("data/german.rds") f <- credit_risk ~ status + duration + credit_history + purpose + amount + savings + employment_duration + installment_rate + personal_status_sex + other_debtors + present_residence + property + age + other_installment_plans + housing + number_credits + job + people_liable + telephone + foreign_worker library("partykit") cf <- cforest(formula = f, data = data, ntree = 50) newclient <- data.frame(status = "no checking account", duration = 12, credit_history = "no credits taken/all credits paid back duly", purpose = "repairs", amount = 5000, savings = "unknown/no savings account", employment_duration = "4 <= ... < 7 yrs", installment_rate = "< 20", personal_status_sex = "male : married/widowed", other_debtors = "none", present_residence = "1 <= ... < 4 yrs", property = "real estate", age = 40, other_installment_plans = "none", housing = "own", number_credits = "1", job = "skilled employee/official", people_liable = "0 to 2", telephone = "no", foreign_worker = "no" ) newclient2 <- newclient newclient2$purpose <- "furniture/equipment" predict(cf, newdata = newclient) predict(cf, newdata = newclient2) ``` ```{r, include = FALSE} set.seed(4) trainid <- sample(1:NROW(data), size = 667, replace = FALSE) train <- data[trainid,] test <- data[-trainid,] ``` ```{r, include = FALSE} library("ranger") library("caret") rf <- ranger(formula = f, data = train, num.trees = 50) rf$confusion.matrix rf <- ranger(formula = f, data = train, num.trees = 500) rf$confusion.matrix rf <- ranger(formula = f, data = train, num.trees = 50) pred_cf <- predict(cf, newdata = test) confusionMatrix(pred_cf, test$credit_risk) pred_rf <- predict(rf, data = test)$prediction confusionMatrix(pred_rf, test$credit_risk) varimp(cf) rf <- ranger(f, data = train, num.trees = 50, importance = "impurity") importance(rf) ```partykit/inst/ULGcourse-2020/exercises/exercise_forest_wage.Rmd0000644000176200001440000000702214172227777024202 0ustar liggesusers--- title: "Exercise: Wage" output: html_document --- ```{r, include = FALSE} file <- "data/CPS1985.rds" stopifnot(file.exists(file)) data <- readRDS(file) head(data) ``` In this exercise we will use the CPS1985 data set, a random sample from the May 1985 US Current Population Survey. The data set provides information on the hourly wage in US dollars of 534 individuals together with 10 additional variables such as education, age and experience. Simply download the file `r xfun::embed_file(file, text = "CPS1985.rds")` by clicking or download it from the source which also provides more detailed information on the data set. We can import/read this file using `data <- readRDS(...)`. The file contains the following information: * `wage`: wage in US dollars per hour (numeric). * `education`: education in years (numeric). * `experience`: potential work experience in years; age - education - 6 (numeric). * `age`: age in years (numeric). * `ethnicity`: Caucasian, Hispanic, other (factor). * `gender`: male or female (factor). * `union`: Does the individual work on a union job? (factor). # The Tasks We would like to find out how wage depends on the provided additional attributes. Our response variable is the logarithm of the numeric variable `wage`. As covariates we use the additional variables `education`, `experience`, `age`, `ethnicity`, `gender` and `union`. Apply the forest-building function `cforest` to build a forest model as described in the following points: * Load the data set `"CPS1985.rds"`. * Build a forest model with 50 trees. * Predict the hourly log(wage) for a 37-year old hispanic female with 10 years of experience and 17 years of education who is not working on a union job. Does the prediction change if she was working on a union job? * Which covariates have the highest influence on the model? * Separate the data set into a learning set (2/3 of the full data) and a testing set (1/3 of the full data). Build a forest on the learning data set and predict the log(wage) on the testing data set. Evaluate the performance by calculating the root-mean-squared error (RMSE) on the testing data. How do parameters such as the number of trees influence the performance? * Apply the function `ranger` to build a forest model using the same parameters and compare it to the cforest model, e.g., based on predictions, the RMSE on the testing data or variable importance. ```{r, include = FALSE} f <- log(wage) ~ education + experience + age + ethnicity + gender + union library("partykit") set.seed(4) cf <- cforest(formula = f, data = data, ntree = 50) newworker <- data.frame(education = 17, experience = 10, age = 37, ethnicity = "hispanic", gender = "female", union = "no") predict(cf, newdata = newworker) newworker2 <- newworker newworker2$union <- "yes" predict(cf, newdata = newworker2) ``` ```{r, include = FALSE} set.seed(4) trainid <- sample(1:NROW(data), size = 356, replace = FALSE) train <- data[trainid,] test <- data[-trainid,] ``` ```{r, include = FALSE} set.seed(4) library("ranger") rf <- ranger(f, data = train, num.trees = 50) cf <- cforest(f, data = train, ntree = 50) pred_cf <- predict(cf, newdata = test) rmse_cf <- sqrt(sum((log(test$wage) - pred_cf)^2)) pred_rf <- predict(rf, data = test)$prediction rmse_rf <- sqrt(sum((log(test$wage) - pred_rf)^2)) varimp(cf) rf <- ranger(f, data = train, num.trees = 50, importance = "impurity") importance(rf) ```partykit/inst/ULGcourse-2020/airport_20200412.jpg0000644000176200001440000022217714172227777020516 0ustar liggesusersJFIFhExifII*12iBShotwell 0.28.4   http://ns.adobe.com/xap/1.0/ C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?M>ߝJ~>(sK IFNz5*m)B)؛=TJ~XM!͓K֤?tQ`NS}iJ2qJWuHc*ES?zP!vHg4=1rGH"0C[z6iD 6qS$hY` ݚ0nߕ;*msNb7 nnaȫK*iBJWѯ6!#nIb+6)N9ݬQ_ȃn㟭^ԋ7}kG9 JTFnIlT,?5Oj1SYJj5AsP;׷rckf [( 5TSl@ 85m|t9|+Ε;=Nȴ@%2HhIP5|\S1U$VӍڲѡi,pnؑY Pͣ4m3pir@{q7Pg&7QbLboYɏ̌uj$\ Uar5( %Rřg`jaR$Bߥ[w v)@z{dPjB=irGI EQ%uO}19*P^Ry@@`sN]J7=b3Dqw@3`'vJ@>Ҥ6P'ӂ*mލހ"ؾ=*b()0\ƛɠH(/"cXlcG\qzmco p0O~tb2w֥h;UjL4%$ʊIV>lw|Nܗ6\[ ;F'h', $j~RԚ{$cUF7z R"/%9qf| "զe %aQ:.]Gm Tb2GJc*Fz)dA OSmځ WdS pp^: F_4ڭ#Pbh[=9y}hdՃ-4s0+~9)ޕce#FIA<.=*_,ZU@޵sڞw1D``! O9m۩{柷&8iOi@sT9.*ǖEQ>ߝOl4R;Txqϭ8!Jo4 :TIPh'S=*h27]]9$YH{ ӊ!~C*R t)y91p3W]bCrb) )jGL@UW=hcޔ N@qRRw)faN Ϳ|R~ =(̈00iq@^;Fi"ÿ =KwWN 9ҁhgGHcO Z :QH"Tj4:ŊrHtTcHO@>PƮpN[Ly#t9e%ˌ[3OzCs+^O {qګ[#^U"ѧ#OSKInCt,pES:ꢴ" -p9kͨ97"VdR*I:#F'P5N=A6~u' oGvd8!RNTsbeR{HvKd^$բf3XM1㎕+»^Zkyڕy#]XK*@^:R#j臾(i]B:ΗyEQDC<+=܂w@*clQp*yB( ai(VmR бq@ A DO';f8P_ҕP>޵caV0 ԈCJ@ )ڟ! #⬬ ~1PVxxVqܬԒxP;8ȭ{kVD+سn4/{uF= b)\hKQߚ]R"~40=:Fx摔ߕJnҤ ATr1*OҚW%4\.Þ؏R9ϠA#ٞ <&:~֓;fG>}?*,d<E&V jEpi,zռhי0EUd8-=_K09}3X8J扨ĪGϐ8T+R/}FzB @O'B~jVpq2?JG2ăM0c6H⦦Z.})Jrch=:6zt *z!{t40 H6<n0œ*UA<-9`{TNy*@(` c@=F);x9M8.=)r߅Lpi ;S2$(No-c]'=z^R9jbF2@/JKqv4n5W杝N`dsLPVHr}G,Χ }>7z)Yz⩥c8/v\#dl.؏9#9jkY[+FIEQY3W$ZnslHd`V]ԕyZ*,85"\ڝ1G2)"Þ*EjqjF ffRW(z֐4JR+3ž{PmڴL#ҕ-RÕQM0Vޤi)0f_٤{ckM*'Z&SC 35CzI ;S0GJaG5~-tۇ[G?Au! dP J%TdҽV%j7.aW:a};kU*me;*ːrw`qOeEq\E;GE`#\j.beTҼx坤_#=k|G(ٮt侻xd6+u3W4Z]y;f˞# lA;O ua5ϭԧCTp+lRƻs1٭C|.WQ=WC∵ Kv "E(A#z㞕}z7+9oV3AѴWYU 4R3@qĺ ^ 꺖*=*azկESS2˖'HH9`hzxLR5M4bΗ(%PKn+@,IM&i` [Tkh]llwěF*aBIy|`K[}'Dڳu\G30Xn n59nu-]VVfh )GeF>@8r{5RR}OQb|# NQ=*,RPl&=srq@Y ;Uh=90܊qq@EH*P03@rpI!'ҦHrE8OP(Xe8Ȧ*s" 7u)M=Ȁ=qqSyx4A@vzsNy;a<bi6h ~ڗ#@])ҜJn)B#gn*O(iQINQO ?#N<`#nTO(h1609=+tzW6tI\FpS>g9#2 Ĝ2c.W-N`M]#K05 כ|a;\ie!`'ӑ]MIW#3J:Ge-G,5ZkFZrFߓN:Wsg:ԍaq@1U$ymB O,q`ņ$B% qU9wFwl =ZV\F{ڵ$JHɂb[cGa*[ -ܫ*aeOCW+!R>`q-Rp8Px$xD]X,JZH9|(<[=rm o䎠v"[*A}HR] 8AJ6E2oisqGk eVT-S {SD[+oK˻&.bT́aΞv嶟$_rE,؜;caFDpe5=6RI[ M Hu8Yr#Uʲ0T7 + yėZl^v<15 J'ſx}5y,rz#} l`]oI|3Nkg\khfOG22~lVmIrgO $bYXnƻp9[R9_UDn6傞H3*bzp][tG;qo+ Ў סk:N7vyV<ȃ HRzҜltˣ*;KmTJHbaFz #u^u \[hbڼOE3W aV-89倬v`Ҧ9m/;SmC"_0G02W>ɦ^A.;,nv~L[>`¼J؅9hzt{G#j֗WZhmY#^qtCai>hcpH$Ym|v=wonS򒲺Ya5eǎIt+"IZ)#`'o#m=G]w.m/L/V+mB9[21H`3d䜀9sKKSԴKDu'AjX^NwpW1c8~)hogAq[c|+/*:]PN2vDomJi'dS;k_knkUЉ bJ\*9J5kgţо;Yq|5l8.y„$9lY񞽮iv\q/VbF\^OL ׂ:uykifŧ!;X@'_Va'n}F.&w_J\d -˔ pJ^|^hbԒI!28";|O$78JVlɏ*mmj)~l 7๵-RQil.h^=Xb6T'+GTxSZ\Jnh8h .0y5MKCR=Axf_$g8#gs\|ysڡ $1tDv&2 s {Ag-l쬥y8ܢ8 A vPH( J>*ϗ1fT?? 稥=*ϕԢN@bacLT.C8%Zp*yyBEVT(v/("y4_Uay>ec$qO8(6qJcՒ= /҅{IhT)Kz:O(@XI{Q5ĩmF>@V1/U&DhOQJ#T3JHdHw♩C_=s5Ԓ{uRͻn _cំ-h0-\f 8!e]dqN`Kʪ4FLٷϫ<6{0+"##p_pOL㹤ͦ4lאʤh%să׃`|#>/|Imӭ7Ja݆۹lqy<^iX=&8aKI,oEp`7# G|\Js٧AC嘭GxlZL$6R1c'oSu̚=\_r=Pۛ}OQqW?j6 J˟Eà5%uiĎ-g`+2m ,Jn`ܲ+iW"K?%B?x) : Ð4GBChĐy|2%]Ccgopzώ"_ڥeͼ9eU;B9Рʳ;?`=h3*H#f#JpB+7>zTL@X @ `Ҳc,(K~58rEe$v/%g%.N5zJty.ne h] (i7Gc=/\/5q#jS#4XZm,|vސ9m/3x9_̌(2탐@knӬu]>-v壌[ Lqfg/fxL =GLyYnbWaeT'bW >fNv[]> \cqQ + ~.-&|IOGOJطה}aj.lxfKRI| cwj'R+0J}}Z~qiatĬ$1bQA^IQCt-բi+q d.۷3AWk:Ɲ RAXLq $cA|A[C#giQK@;IA?@JRRtmO|IDSQծhm4}:1IފJR\/&fZEiQtG呐b1#$ž Ҵ &-C]e(L(\pMgZZ[C< w>p\8n 8 M.gE]I{f-^'00Hf'i O$`qX2UJgO.}5/Č<x5kn;o Xٴ>efr=׎"[claAfNwbAہNJ"USN> ^KW%ҼU 55HjDH s葉|:>ݬO klӕ4t1IgR]SRrW53SK{!!/%\ rPOuᯈQᶸ˿SLᶂA@ nȭ/ȌU޶4ԞQ>a,IH!0BG'#WWZ&g2Qƭf+,|"1 CNψ/6mM2O*]=;dI}J~lF^_uM2)[yXJdGe~dΈꑝVkq\8mA]@mj-ORLWB򥍑ق)@N㌝.N+ő-u8K4TDF̨gxSO敵%% 21FOn*=ZmZ%黆$mC&9Q1cA=@|O?ícSlEl"ʁ#2Y'!0 O95O ZV]5K$Kˀ @gE[ ]xSK!ZOftX[5@cY0 TJFjO>5.}_u Y%Q nH`B+g5j/ aLڭI 'tgEd'd|CXx¶GIdUM6O\ ʤʥuaFv`ago@ckOg&V:Fq=> ӖNX[ԍ&Gv=3BE- 'G|mIyk{`Vñ$IGÀNFQ_ 5 WR*JqA=G>N+ʪd֑hmgK]KSsl 3{`?/+h,,s/~( !qCE?u&[; H8 W{YE d6l<)bz3 X֧̖3Z0u٪ 3]鱤v9؈ V;G<7z/2LNLx|ך Zx.HmB<< ?{9+#|>Tɨ}+MHX $)%ymOjQks-WrDC#)A` 89Ju$I'X21^OJЭ/u+%/#H_֭F_D""?cJYNzWi{jV ȣU)D@t;V1Ҟ"ESz_#5sV1w0欕 ho14KdP0\PFj!s)X`qV1 +P-3AZ(_aT-(ytO6`A)VDdRl?RbFjO.KW*jw YXiDxHcR8VD@۸WБ޽rtA4 a++Zڕ*]XvEcd`8:ӼGZ8%mmpbܟ2qyyvk(croz>wp?:(b;~-c,CuȖضYH#DgҾaR*Qg.#rx$ RDJ#E,xI&s:uӶ܎9,㞭sNjC w^f}un^k FB8cdr(EiIi=C-6Iݍhb.in-Dq#pX5NA |ۋ+wi}xZS:It0ghƒr+1xyJ˲>†1׹VW{t^XJ.1 Z=v nGU῅i{ĸFis@XPOAHڣ-,E;cߟ`0 pqO4? xcJ!8ڭc00s^t)v"Y ŕeO,vy8lZֺjIyܐF 0#td$xHGCGH& =rpz _7:ڇB +ȋ(HrXg---Q1,Um3Ar_Զ84E*bҏSGLVyua]XмIc Ud`;JmkZ:gu+8$<sM(^ 4-o1ѧ.oq0\X,sy=sfj2]PD.wf\OPQ_9VEJs3cijӮ(h;c= 9(A{y_\ؿѴByÉÕR[^j2"\\t 9NO*LJNH9Lq|VlK4tN7EEtSqs˙?xwQެ,@PsVԮnu eWwTn}CST]W$[Ʋ$?R$rd[]; /n@ebQNQqWR5zs:8*p+Qӷp'ٷy_<%.--RW\g?FҼ1m"%gkg~#U\rz|>uK{)ؕ7HhK9 3[<:gx[K,8]KK\§lXrIMǚS_+Dzl5Y"{aUqe$I;݌MTyno!w1P,F ž;8ywsX]:,ӭ6&D.V`O2a۩cyǷj1L 6 GWQJt%mozQ$YU:疬q?r(+k/Xioe!h6:;z?y'Xb1 6k>cW6Bx} ÞѢɞn6?)lwewvO,ďo,sƋ:g斚Z/ri촨b8~^|F#bCc nlw5iquyL'pπ$303]#:fiySs8ʫR*\pvg!q[}FH8Fٸpl}#95%b ѕب)󁍠g-j?xGLZS#)HZuXˁž@ sigؼsv# R3]vijeB耒 XayP=yWW^@J63ex#ulym Rlj.HddWX` ~] zgi'iĮҤdQ`~V\se[+;6X9$Iq@ Pp=2sV~jɫyQ$V7K活ē9=\eM4s61S"[}V$P:吥M`xq] mٗTpzܚ3zC%N~SۊȞ}ejdOK3óIYsFT|8!F>bOg[4b `#_ob' r켓5m4἖)&yQU mʌQmsNQANF1E/<`[Ap.<ǸѠoZɊԖQ%,D;vߊ4L,Hbqy Pp?N)=KHuu"(;CvQ/5cppH>4QchF{棐 #o)Boƚv*a8%GcV<)-D)9@?c#tw,Fp{gfifeyai#4p!8R}Or];WXH-ld"zMƩy= ?8FpgО9Yē*aN:Bb̟x ~$F{ vϬO/SyT_Ȩ+SlbSO GLM\Տ&f(*+ ZXR_4\9QT&41dJqJʊ.sڟd QNʈ✱gLSy#ɮOBƯ+{ibZ%m _w'%D<󓟼+g]5"cE|:꺥Ɇ{%L@`v3I#ہR"$l["nyy_ϡcBItXG88#9!Jx쥱3:4hsxSsp|CDo.v\/Fsԃ=j\'ڭK,2e9# F|5[<2οhdmq8 3/&5a q r8 b^ծu}N;A'F "v۹UF:铎kC=ޭ3(UwA_~s 3?AR').>FQg,8$s9G_13dZVm!fcHUJ̲m. (Tx9j/im;QHi+: lv @:!1wc$7RQNvm]:h=ZFO.isir/';H#jK]Ft$ +\ee$Ƥ|6rNԛ3ma:%rQ)iA;u W'.F4q Q_/AXMuQoţst?vEjzUڰ ;~\zPK'LGOՆg " ԻKظz\Ň=O _AnGg+uʰ$s~cՒZ"BZͯGsn(y'v1d _NҔ^j,|'̠??9AM:]>C)<<.P39I _̑K%LGR{y(SrF]T\j:]5HP AO|[|9w(X̓1\,2IyJn.n7 1\YOxKgR~&+q iwqАǠ'ϙfIWSu O4bAb?1Jf$QAebw:9-TyܧEYGNOZoiڪ@k"4dq @q:]1QI3)rnIgqnwM5d#fd` 91P#VטaWeq\xdL3 #1,8<zxăt2(ܭ9~)Ma9FeZF3F,#'zPiz؀U<-ngQgp9$s$tjב"ͫ1S^{8鞼\1j摞rZ,m 7˞pi&UXDj3*^p6Ѣ47u?{"x5# @2[qҩISPo28D2Ioz}*̱DLyUpCl gZ-ġnY-{/sWV?hhc`g]1zt'ִݐ5eqfH%qfݹT@Cj.85<)梉G㞇SE6ą"L'#Vp?MHLIdc Iq=M$(ZFw{1bfgYrpF:Tk"_w I=Gg8#U%x3 @p2:)iZr0*_R?J%7Ͱ!r?ÏU ť0{ҧ.%_;cǗb=)!Z{S ~56҈W2 0O9N1dz$6w0[=4M![JJ+ՈNUqT IO@P0:T0G&NE.zmvcA 1`b2!#ަzq$4W0vI>tE3ߥyxVvR;1[7nRiELe7h=҈md 0iXֲsn"M 0u>} ]˾I39P~Ig?[Լ9u*Ylܤ 5G5v/j7iڵv/HכйD MrJ͵y܊r-r[Xiia:zsh:EO 4r}Z >PF=p\R#)Ɨ]w6 V l4 i d$܃dO ._>`TX7!-sxdkn5ym.dݤY7ez]j e ?7$ϭxU]g+:J V:-{/1iYGwjʷ sk>]G~%[xFk˻ffl7T `r8=6%.Py 8q1F~bۏ: 7LM9Q`72ރ#?S\U9\l:थw&,ҥڢŲH[ dpC9SOH57x",eX$  r[M8C50+Iەa<#k<i]T$=XV7K[wt WG-; ;9)%w 32EyVtd 0I_{w%W0|M Mqm$ 1C1y"FDŽx݀G c>”W"&MHƶm-b8ͳCd\lp{3u{ankSssw3O7N; n=$y;v}e$pʎ$].7,ePs/rMjڹ7)4c˲D<?(~3 }tdms \4yROS<=kdRap@`z1Z֬u fikswn, ԞVjJBH3b 45Da&"XJg`:ՕK  @0Yʐˏ9%U [Vh"WX V}*x`HTԦڴSg+!&#ʈjF#q]%@5x¶6pD"C!49C7[zTz`,88d;~:]U`Q4N˫e?t'xtcvt^.񅟂ne8iہ39'J1j0܃#>‡ }\m䍣JƱ+mcob m I d95q\iweyQIG)U02 Td ֜y5a'v+]n;XT$:[)my1|0vopF-Oo\QdkF o{"bxc'sI9n@8"o XWF g=H C3CsקSpvuk K,J!b * FpɫqgkcO϶zȻжEq="@~+мqkC ;&#sߛ7~i5;<)iV 2bƤ0ۍm)=jc;29s/55յ⛻K9` zAa[>y-cfI\4q&zd}3Wj$ok9?adJ˵LGG9 `t;g85QZm"xLwYa?++ub0pF:<,Y2D'H0x5zAĦ9ZIc~e E?bY~_3$[K +ÑO9^fVÐǖFtC >@T\ $A\`c F}ҸMq-mok/3!cʆw?\zԋ[5L?rz<՛%(^#p\[~{;ɵ%Ot B9#׊2*)qXQ#=Mus mdKqK 'Vl2#CLsNHXVDq"9OJȫ{LFmbpK`}. EH<wbIcߩn/ _xzS+dGxsO$@'[b,Ak8ͶgFF4)Vͻ}=ԩp˝NG3=Ө*<8OQCyT?SSe$:ئ r+g8}EWZO,;-}aUYd #8sާ0۝y1Ϡ\ꌕ͕ԎgG,B;SLI3KnϧNzd*d]vP>^%o3w[dqީE"Sf& Uϣsޭ[_Zp *ʒb%e'0s*{$<H LM? 8V5F !UVWVF3%?8ɕ6ݵNx9Rjn9p;z#U[9sƠ#'&gq(cn: ϥH@ZD|)65 4mZ.mG+捿4iDd0d{hSO!|Ȅ{Xa d e؄Qf`MrWBVEFea؅$~5|/ ~PTCkRfU\Mu:iiM,|$x:'G{OMOPcvO62d-$f@H`?0੉*Ee:2'XXNѕ=<' Ӛۯh^ʿ,jWs?9?.s]ŧۄ/WL-gi$mKZڞ)E4ΛsN{F1b@ҽ/ψ-'tvĎR(!6*O5hVk2[-bc6%qGWxc'sŚUΪg8Bc9'u <f͸[!c!H@xls9gP =Ĥm@$׌W] 6IA'͓xk+oIbF@ƷO @O{{{w7->+˴}y^G ̌1 P#$E&sN']X],m°S5(l\㌂OS5M/^}Jm~ᝎru޽Eo ~KIgщ?Wڲuɵc+,X9PN9683ӋwWq"7iڷo,<6q@m۷&$Ns5W7wD3xa8^GpזWחRo>u'5% *Ibӥ>D%#/5io%hv$ߒۃگxVV4oI-Jj׾*[SdQdpw0F BOOS0Nx8z{ڍߔ'[)cd0 ']liޭ=+RJ ;F9 j4ٯ^U1Į;`d[mQꌦI'`[}*n.gw~N96m-=_Q/m!p!9aÒ /bbiX7m+ia3]]Y ,I6FWvq!I Wj6w.0I;`+zRm]w$Kol$`<IY R'!˒g2c=95ֳ"yfL>s;#U(w;RCږR+O:c؀ dwڒ͌et rϳwr%?ѶnxқjK7?>H;hIz\^,\Gt`и}?p7m3(13Kq|dV4U{93P;OOcJ"GRȷwČg*X.BEqihB'}PFp> o0Ir98ZZ)(Xk ,XR\\G0 n=N U,^Erx8S֭ I;Ai'Uhf{{Ź$G.I@-XG0W dabH{ԖVih;FcÚH-eEI",3΄*I̻c;*jr9ĭeT*IqJKXRB(?5+SHoc-ND˨^AgPӸ\a7;XlCTQnAs˕eRF AFu( =ͳY*1UyλWNܕza[8@C'3:UN][$tk$$K#iot!xEa;!/cmc95^KHb6/|F㯵]RfY$y`u?1{ɣA-Q\ߴBW$ X'gv-O$C cw gsq:Vi H#5;f(m5.v6Ie"~a:%΅%|[>Y5FF[ʻz, '>ԞaF*bK!bI=cC05jZj-5H< I9]B CETDnxˁ>cbFj΋ĺg#^Kc%/'^9xI8ڠuQ@9.WQf8ש/ۘM_[ں!MFu%}{1L$O%` +䓷zs^MjEmmbWGl4BV&0' WxJ 5In_E;l]$q^wA<D ّ&x,GYM9SH5YZC{}bȸs֧px|7G )q̱$$?ԑ[ H%DCOy73Z$Q;+ӿ(v:M)u&ԣ0|ye3{1yMt+/Tn2"WB@kKht庂+HpI1֒ 6giCt6h$+1sqM׭g,]P$q[zwlTډ}'x5«ŽJ  ;>T\Ps n!#20*@#y㠪7!*f- ~Xoj6pxz fGBBЂ+\srӴA, YBWmqb/]!B֮[\6!#F rL nvrW{]MKZӬ?B,^a c=}MT0R*-}v~27lLWMyͣ2l;E"@ǐF1QY$-L<~aWN39riw-kutW+ ㏭beɵzy<{}Knʔo^G#Iw|ǒà{8,5Dz6GN©'=GPua8%գG1+[SҞ1-2FnPCSNU}:UD+XJ׵Jz\Ima-ɑ7p T)di Xؒp1_noqyl0@Ftm6 )%y+ȥκjf;@do,32jd:B1&㴿z隒5ٕZB^1{Ɍ̄yj9*zhsO#ff\y~H2,d7ӥ[Kyl6f#p'v .DD#[y,32JJd#nI'WFUǩZE2HƅӾ M)]Ctj)G$s@'iC &Fxj&1MςŞH8e$8Z1gyhݔ0[=V&q) ǽajkkԅxJJƳ`ɬ!yX"2GJY s tokmneJF1VV?-9j$B:M M," ؃@$\[MiW+(rT5sQm{dy\LL@ҥՖD4gޫmZ)(ZP+mvH'.-y2o}69p`u W[p#5?;KӓQgFCmruUv;#k Զ ece f(Wp!v O;xԆAqj5t:U!+ih{y\n3А3!S<OZ´ޓW(1gp6+*[;+4Xh3=Ūսfp{r1^*qF 0ޕFkm )$RY@@V bݬ|T-G?-y|l`VAG1i^~߭rzTs-w|6'Wyzxk63٫'7̋W)ybAWKP%1"RYG_m=+3hZֱsپ[pvqB'd`b4ͩPsz(k($!v`펵Y!iÂXo޻郜{]'i[ȌыrnU11z]rDz̅-:-?8bNp~graE@>ҵp#ʝ9O[^\\孪ŗpF{30K5=/O^S${"lzV_tiJLZe 8`sW*n;#N'xW0\F L`}ֱ.c;fbIoȮV¬)!c¡6Os2۹INz#U ݑ(Z-ٙ"F|㨪D7#qc B.A'|qBq\Gyh@Hϙle8)ppF9h@!,F3⩂m Wv =ihB׭Pj6#UY  5sBxt㿞6PqQveXZ< <F:N%ޯsoG򳝪8lc\K*-&%v2<8  |ww%yPIv$jYHʷM)HmחF_,0)kkqsg>Ղ폩܌nnAzcҺ&7 $#>)AXs#h `rpNN~cQ=OhXh]f8?>f=wsmP ݂ן¯i:h 8"Gb6ALˍG-["Ѹ@c(/kmn`m#I<-cW\ԥvF6jʕc0_~*Q ,n$;[O)]fxv9?)>E{0҈pN;A}@lŷ4 Xh$eG>Vo1ڜߚ̖`ŲG LVq' 支ب.y]ÍrV|W|JC\ ơp̧ӐBBOjY]/Pyl]Z)45 iXguV^=>nA!H~)cԟi('crNAY96%k(d\CV) "3PF )*<#ʜ폩Gr7ulvⴻ>A#iiY•RgfӸК-F8P#mE >:+JHܬ0ֲtt(UVuYE!`ZS^ V4H$h3VL`\V9MRb̄6p\үŧ=ьFEIU FSk{]NId*3MPLHR$U_V&Yqj:X$k'c*If L7w9wb7$^U[eeJ !0zJ҂;;x:5\GiT8=sK*`$r 2zZš;i~)ӥ7[BX0H=0vAR4I" F H#oZb=ҥV#YN9V4n.gh]m6I8c]Ek L`9ݕ#iWcIVуЊ$QWh5M8e%fw4egoc77C\8qS[fX {Ҕe v&7;:=!Bln>L5|Gygs h5Kz%yk:tQ'U^[@Z@wz+גYo.SxBZs9^V1N>G$"ZIDikp,DXv=7Y#ʑ`#*7|ۼj4)?$vGҹC4W"[0gqI#:f_ӴvEr[`1fQq힚Rxl=26$9*;arGy5Ϥr+F%ǖ2y"w I\ij6zqX)XK]nkM6(Vg\q%&Ic>نƜI9q+eGrX19>Pzz Yv)nqZw=>cWWR5Oy02O_¨Ǫʊx7̹ol{b㡓i=͔OEX, О|[z l)GcČYnH2 @ Onjliҁ,0TmӌV;]k3hJʥASpAP[̉pѹ<Z֋2@wc۟J5#X$c0HHf֪3"j+5yJSZAO^k}FTSu#zVn.&hU2ɿ )J!#\-&5c[WN%#6,?,1YwrN|gHa̲3LJif;FWbd;~iw:NFG1Y;hr:&>͝@̌@@ t$oJO$U4ZD@K|q'ÃW@f"L߆zkgZqtVG+g vl&"4W1ӱLwdV І+de7'dFUgNqd t*mv% _S2[ʊNp[:@v*U_t*Dq, p2v*)¹BjU-7KgUD`,qG'u$[Z\Kb2N9F+n+ 3d۩S<`o~i).Ɯŏ-OqQ]yʁ#p3dV"24r uy,O^!3 >P }w"Q*:b_XWy0)Vf@;(۔hS+zX6&PqI@Pb%scnڰEH(g X@둟L~[xfKKW2Ȫ;1 UJUmHf;e'70 ^k(3p9{rf&~i+b6d@uWΐ3Yso$Ƨv0GQ OpoΌ,:BL9t/1+`QIc h C9=:nn'e_yV8c㎜fk o4$/Ȫ,}:sSQ1SPkX7gLUETJ7qPC,|$(h@=?CLxܘZC26F1T o8?G•#LI85Br|$ԥf6dYbݸ g};^Ep%r (npĞ+QV,g?WnnOiToc }rZ/s"%_RvE ETz\^=kRuoA«G[DGz9OG/aZl0H, *}9Z9ԸF8}kB+#lW=keSK3D}"'+6yaH YGi*l}MJpGvr@0EX]p^E_2%C; |K $+Lm5n1=>!h˜3`-F^% nIո&w[ˏlTgzң\B2zcU@M)T`Ԍ8®PoZ7֑4qvc'9Y6v1b8:ho#y`X[|U`oEhfrD[g%'۞[F⋂Չ!PX}~$l8t2Oߦa*IypUP ;6rj%VQ3e{pJ;G5^4e+.Ooj]ZNsVKRJ |sڛZA[\Hɓp^9=x 90mC*ohj~+\O%垛+ vs)@(6vu[Uu+/5%ƬFN;އ#ætf 䍙n# oqzrFsYjwcz+j;3$nP6rsxpyM+};T-Ai)!v.AX nb-7eq>}:#oۺSjr"ebO{O|g>oo[c7佞eWdB2 jsϓ7\][Q_6rHe$9|qO=Zz־Q1e, TZbmboKH;9.bc6ѷsj14IlIs$L[*bI#o|n8Mӭ4P.]ou?g+`zUT-o ?FV}Z;j/#cBdV_/4Ɨ &ka8@y zcH&o/5}GlZ7Lr'i c88xvͥ70F . s.0Iݓk:ɯ,?6hoe..Y#b#geKse{/I!$>[Ǩ)#nrWu=BTv?E&- m<95~+ 6hϺs gVEc96zUJgy5>w^(F[CI5(ͰqԸ`2MxtG-_2ͬ S6,0-UO/H ?_nh y9.ͻjۜxPT%.kM¿Z>ܸPC I%~}!a/GoWt-I'$|Ĝ㩧Zek@w$2W9,T)#eՙ:wE>{O FF޽ "i<4\H"@t䑞=jKJdKZDqJ])khiI]JN t>eD `V9=s[Z`ݣiDkvdT,cZtO.H`1ۖf9mtRbʲٺ%_;(k3~GNN͂hfxsS.=5ZѮ>I[D oV^ [)rpϧ:7;y>ƨhb>}Kx%T8uTX t_\xnJhc b<0$2y_~Oj=J'”{Y.tJ#XǨhQ3WxVR3cF*J֧ *s]=vT-ռ%P\V{7 iGPsұ5_ 7r\&UQ>e%3ӅvgO˧iE׳=eEgw(zg#\5Ƕ"mTQ[a#X\ "-Cƍb#?fT;p$YxERmݤFą@$-pQp r tiGGryG'k$pRuRz\ cSڪ,HxFphdOW4O[R}"a Y 砪vWd𖣨ڽeŴ A*c+ hu&F/vaqts^$M4r$d@1'r3f<Z QeP;$̈́,7arF1ќ-φ=ެַ[Ɩo?3Qv55k{ $?M299kk=bI;\<9e[qܵwV֦iKH PI'6W2fmHÉgfڜsEmtIm*Axqo\uxmtt7Oknľ"6{K8r]파)' P0x_>9Se`x?7}޼4KO[)֞@Z3s;'N=.w8 pwɷz0=b_ O g[0NU# m*oِr=0 CivGmcCUo*>]#+]B##?~Q`* D%GNkWNm&y"MB'c8IxǡWX3=smw:gzZ_]>d9HHF2 smio.S=Į8O> WS7guoN ==SQР(RꬡIbFH囿ae9+;O#%<߷kIC2CF;F+~R8|Dx[M:kk[ r ꚧğk1582.]`!7d>Zyeklj4B4&F9B8.fyEZ'kѸc@靿ҳS&IXF65/H%/c>Ïʲ~ iD7uG!ܸ_Ckaيӹ#)ۏ-283yֹdn `==GӽuC,fucyc`sq]&mkZ}5DVTVp##X1d[cϮWyxž*P5 oZk\y.9$OtW]Ny&[td d#XXljUùk"=kv>bܱcJRNZ2vڵpe:+U:T&Eֽo –eu9]}Eja~;B*S7`?Jӵ)m<Ү0]8qܓE^#$]u֚rWtfZ={Kw5GS'F1~ڢJ2WsX=ݕ؞Mi&(՘Ԑy䚍bXԠ!4Ԣǩ#\[I@q$(v28aR#05'"zcȺyyUv%A<ʺ:R1{dI\Sg'>lsۿ?8ϩBoq(`h"0\<'9xKDp0OUjϨ\Ӡktir9 @MwxbI3ÅW@1*ϜH i3N/k-g uO]`6O5Q/CX ߷ Wݺ~ G3~[izc'uZa=K&h'ӬP V@.m d;Si|2{6WdCt̙r8e)ԁsT-5I,K]5*l[v2ZjzeM6䒟{~5 KtN6>KOOo4K@BMnfJ :c>z_d& wqC%:gp*yS[^'79^^?k8;wZ^1_8 k5OUb2G4XDa\ܣ\0Eel/SWh.JGQ]F?Zլ/F{Kfdռ;~Trijbܛ? Z er,,ģ60(a럭o a'ĝ#SGQ]Ѫ0^^{x/YVi伒aq@H! R9dW_J~ [[7f:ԌR+SuRK}%]M Yo0yc,c*@N@Uڻqڨx{Y{e-$M.GnqR7EVэa rwX:qa؊/\kФkY$1}.;F[#85#y-NyɹsXj ݼ\:}9泮>k6̯ehK"rvb'+,9v 뇊X+)tury|`Pj$9z _Z[=/QK?:Ki> y:@lAA[O%ilQn ֗Dg9ΰI?yhK(<9'x dH NGEFwC~5Z~!2E=; 'zW'|8j߉ndCK!\W<(bz Gozns}qo/]k* ҵlX  -(=It3 V$k}cp%s2b$H^qqeQTkT 35%9Țqzӷ@uKZ{g5 |Ymwʼnk|Qx#4!U %ڱ/1~!B=,Ѹ1Y}^dIt5IF4 {+^zR{;8;CtSm8S/vxRОZ\ F[mF+Km01K$ ~RqjjU\uZ'k^\L6q,F?*082Ƴ<}B<ZxHy?ٙ0jBI#,9^&!&~ğUcNg D(Asa5ƈlt d8GԐm-vGjn[92˥/9t/k{>? )?d厪f8y Cʌ?LQuH9]d-1-,hZxEYbQ=4ɛAGkˌw'a`}7Q+=wgx?Q1W_=Y-/W(v#F0Gj ROH5p֓O .&Mq,n&c 94Fd8"YnK]$Z8Դ0L_\fV8dnU/lTu7g 8!f/W?ޱU/a&1Oҏ%:ꎆ-` ?V#ouuǡhn:Sv`б0ߕ:t-uK6j)x avo8+V3iZ򯽅Sl}ɡcSf RHT=>Ǽ1d*=y#LBW/4{\ uHbz CQL[zRW4,(G)?-7"C& {xkH(~BJ?Sʿ,w.q,l~RW(,mG94،9o,g<_3bˣ =LYG\kFAt+M+ ~?{jpeրK.?jףZ kfI &Wc0JM*_1u^ڗgޟy*ɶc}~1_RG=D4=H]6{Sqf`@y<.ф&PHt^d>Q!H8xHqOph̓H).OBY#̡_z3 ? M*ߌ}:JJt4\0t͙<8cQos"ug]|-mY; zwcsʩ;Ήx* .X g!p|`U(IȯZ@UPf۾@j)b|w;遢q'UIx2xcR\xnkPBˮ=A~@{XfKºգ:Kں$bfe'3GB+ո`E>yRIMìsdQm%|H!fw OeB H^O}=Mׇn8i-a׆77~r?ۨX /`!'?ʠoH*r~Ꮑ.[2`B="XU:uga x{ϗẘ 'DEVBǭ}E7O]Gn[^0q6h/-M}<mB?j3=-1 GqR ArW^f[''.P&&guR%D{ɔc3Y<UCHqLHx뻨Xos6ƫHs3+"ٻIYYܨ?)>QYuD3];ڐ1;VAB}s]|ylSsI?:{ƖDXFdOB9.9&z5\ jj^ 'nhLr蚬NNGg)`q܀*ϟ/5cuEC,zѷ'xU~"OM&21dd 8gzHV>d!K?\Tsm|[zC^L_#1TskidRqnH Q}Y[8ݜ>G-7580&:`IN]$fGc6dq^`MDZ6E/&f=M4][G6]l9(T >>d6pqƘ@TwPwdJnj%F/ct?{ m\A-' RgrdcϽg 1$ʏ:eE.2<}i{/05ϖfb1Mi)YO\ڥTOaqO73(?~M~X; l G\VA&GFsyM􈁾p#إW7Y@>A D`*ˏPv,7'ﵾmƮݑ`?Znc_!z+=6W+9 걃ԓzIEEƚΓ>CSߥHpGf3H6HwF)3ל.9jX$MpA_I!UQ:ƙ0;Nʟ&iRgsOd}nSߞ\SĒ9ۖ S4K#99'WLbqF+! y9FfGUYBo^4pKk+V pl0pxwuSۿCO3H `+>"aF3u ٠M-ǐ:ϧ_2:4\FS'G =*UPkMQa0j}Fw ļ<`g#%zpj{t&~<@'@GpCIj)Yd p0A?qcמm"$dO˜uV=7I$qr0?JދSB7Wyaz)9=ϕi$ϗw,@>[=oz223CMVh(WxdKE_ި qpsq]Zt/\I$.I"G1+2!l**W7jG?bp oپM8#Pq|Rs ć=,fBXg_؏𮵭)?#ً71ڟ 8% pjfH5#89RH=*DeGLvlҝƃ;833ઁVG 0Im̸O/LG?*z>)M󨙢@ `o ~ xLp S? ?@0b1Lr>G3 {5]ۨ RsNunT;ZM*ˀ}?֫$x`rz)@,2csR>U{H?xMiq֚ {\LXFx۫J(yߥUy'4ϷGs֋HTbVe$kEsOZueS1p w""\,$J ֡i?P*sz=jId$4\,1&+YT4X O)?͆GTvj.P2SҤ"U9xaBLFbx| >c8WeuW+ ``oB2eN12b3g1Za[bң B 2`iM 8kJ}PM,M)RGwqT:\\'G.FcTG$,:dT<\zc`,rqبΐ %Se8w> RfC1Eiz8R > q%N5SƦOiTEz"5,w:|@+s RCQdX WAֵG٧TcԚR.Lε+Y"nt =wYIqZ[#rj_)H8{4:Q}准u+<F alS.|KIkP0pcϽuf< `Ls䵛ò'= 7V8f_ V/ùo{z(Ã#K =7:jv펿jB%0>FqM$LuT_G\zGiv$4=_ݮOc8P~Vx[0zcD̸BbdMòdt=>ljp\< F6nH7_Dz #x08ziSuW|Ӥ96ʟcFLZ/;A֨0C(M99/Bgu}n/֣ifsv͎?*~T:'0Ik;"OG/e':dÕr>9)v_j _3/d9AtI U z?,`}Eu*?ҙ:,p6v_A?yvl6* '}٘HK 0l+p:AΑiAl9(:~[I$ 4,`cʏn+[X#uO?^*>DLVDD }IvD{`H_l9_2(l>ueXgTtume&aDNJs@Y> hF?c8RLjC WҥvKYJW=g6Z9N|ZoJ{ S12G(<9 OInY: E[f:xy|sۊ; RR~KH4*"p68z@I.zwtRv s@㜓ֳ̬"?}m3˧@HwF}}2L?vPU}=z},O@@/U7d۹7HkN7W)@ـ\t# |akП0+g ޅZr]z9#S*s%o{!KyHrɕqZd#Xs8'8IRqJ"eONt` eZ]njF E72Foě3oyGνsHJTq- >psӜ1TqREsqබNXňbx(KC)`8?O4ℱq:`R$0H8hac 2`ULg}1N r} p_ӧ08&R}f6Y1|fНX2L2|Oc)BG-Ni0<.ˊ@sL50%zHmp< FjavːXښȼHy4 SCE'XIeE(D/V\3׵駤@"Mk,˵G yM{ sIOVU*s42.TX~d _L?iߒUa2deG`#I$ +z)R,¼1aV20*gf?JoQ0 A8#{TMu(&LC"G/R _BlsBX"yC\gJuXq(AШ$R99_>},8꺀Nf_1IPv?۶R~ѭAVVEUV̡ qS|IG HLڌ-&pNc#>V+g'ȁY8UԤovՏE8G],iHMc8V ︁OA3?>XL:|[sǻVR[H}6s(/Jh>r6)b\}qY/)Sӂ -p{TX #M}98=4ȇ¯$G?pe W#4h$k7dVp%4ίb3QK,TdoHⲗVrf|Y5P 'w6L'+V#k&^<ǷZMnv?J|.kQ2{ʛ?ҳqxT7G-`,ˌsInA q܌RD$Á(ۆs]ͱt(hw5K1$(YzshY(.c3֕qэJ\Ԟ 랞bS-寙K Yd^jZū)k(Xpz&?x~\"^8pHj~Q vJ s*gc,tVnO#kmM@(R;H:0+/Pf_9I I9.~تǐY\{twc֩W au3Mn @w  0k6 & ʲJ*r 8Z:eF af+2돭s~ >ߩʯ)Ewm {($1nN]Gx!8]3_7QL%ʑ=Ϭ5W`#wP@oszɞ9_ql;TP1Dإ[hWKJ0s4jzf3[bJ]cU;9ʜ⣏Z}My#q@yrrOMF1ҰobE]^8-fjLA2sϟ xW"(Ip3'Y^y_nghmN:G2{UzֺKKQdEx*vJnOpk7UFj3Ǧ*Qpiȼ:zbhQ5v'TFX+xTKatѿ}pis1<Uʀ0 bg%2F{sT.N L2#~d]dMBB0ma'"d@USҹn;BiZEqU CIYX`;>)[9erij=.Œl*HM8d$P~i\e\0Lb|@JJu+900U %F9phF1|^M8"S i0pb ) 1>*ONOC*hD 1E NoqLk*p=h@M!1挌?U|wݛ{)`3',:F\s`gWJ+bI 6rju@.d`S\ f➶6r®ʶ?E"~P%x4Ӹ h0KGߩ S]UXiV܏9JUIRQ41FvFc>WLN|G}W|nC0818z>֒1hd)ivVGQH+);ṠǚLGZ%8 c&0>RQp_BnXcrfjqH!Lu@(2VHaNO0/LkADPYոXK{wlێ)=7) VtEh`8G8R}%.$cU$S@Z9Ǧ) {I 7dgr|P37#<|R*NA&|?ZΕdip=i`. H#]Dae3<GF%|Ԫ $Pj[)i\S\7\*4~40#~J?ZkrGP?ZI@ QC<cC9sK Ǔ5qqg$Tmy6sGz>SC T2jX .cCHa}JLSZ4aj |= 8)A&0rݰzW[;TW5Yl$oJFk,۴R̀|ў eC\ ,aԔflAp:{8L[6v =~~=\ czkuLg2c_E9]E>.ݲ(x#XXG&sFRE;z*_Wx}-ȴxݷ` ̼`X~-\yvaFb29t 36 }*@K8%5Y>TG$`edk)mXU!]bc-1 t#5wÚ>]9B96#crCSÞ Ig:ϢA8ՍrcoƩEZIsYkIb[7 stT]+KsnVIIBY2y,I^E.+)R5+*fV(#Ӓ]6 o+g;)g@%Oz0bV)ԼP7FG֗L1Nk4A-D?e+[w.S#ӆ=+\2Z ^ HܜzK7C *e< VfrJ#Ƴ-[R@pzgh,g!CHknb1I?1?)9\ Wœ6ҕ~p=h` 7. Hƣ. ܌ҿsT +.$cr_)HŚ8=iʅ{dwq5ԔЯ| bPFͷB8nq̃0o=֜?)x˂QHT@Xrwc-\dG 붛琟/l@r?:sS$wbhʑ$\cQIZƸ_`U&9SJd 89ik2ؐl櫃q6҅'POZ Yl71+&z+<,II#O7gUURjU@zDϱ<~5H Bfzm֬%7 ב`.؃֙|P^#>B#J/~bYs1YeN0p}R#v+d(HJ@8_-z{05XlE?zʆ?!֥_ ?Fcv=MR.xiY2s)eD)z;A))j슃U> #85 Ϩn(I mj-Cjm TpcC q@ssi-d+u+r 3{=g!`Uũ]j95['i'4v˓qN5mHo},QA*Obsɪ1?y"}d zdfKUCMTXk AWY*,hm~>H _iM!~3H,Br{ӣ ޥg&Dp@q$r}0hŵArs<0j3 8T:DZJ#̌(#,֦UG<! $0>I>/HD̃˜ |CA= 8R_9=3sZBgqI}A_E2+E>C޽|E/e=>4 {i`ь;6;KbAyS:Z<#)UNI][i~T  Z=݂?ҧet$ bbDe`8:gDP#F|B=!;hR[šv݆|Fah`"Cձ¬d•l̹W@#'vTT)YaZ ȠKpqTm-˹XL1 8:sZ0Ehkvx7g0Uê˷kWq㹬#wKQ5^TDR# DžJ3;/ҕVE33ھAOx{PZic8GdwfR2d'', ^P~jZ݄N4ɣƛ.-@V-30d'i/3IdZ}-h1?@"<{cg62+fI!q{jžk79gP5xaPVKF@l?2AԱ.k\_3zŭJ#r&7uή'_=GQN\Rz?!*yd3Lm\|vt> UzTH+7Un#T: vLS ;}\'ba,>p #Tӕso"]BG)GJ~Fk>8e?*$_]/nq$(OlOxr]iW1:xQHDYC(#v95>$23 7[+BHY%RAi KmSO qe%.AN2Wo.bTPOK)$.Fc*k8leX[=q@9|?m<28CK6 {s*ZOpLKOAk32Gd }=kh̬m׉5hr;mF@/o-A2CoM%$[#"FUG#%cӏ6qX}9a9O+dUD-,Mm;( Qֵ %}Rb[Hh)#0JtBK>zVm\T G3VViȻ-NhQGiw,@!˴sQ!F?t(K{(7/שEqVhPr;u΀4HnV|ETRr*8k<`Nz JAۃRwlL?+̀Znޘ D{ȩe$ҍ+:O8'sٛjD. Zۥ$E-!Px!L!d.ysH#nԁ~6-K.Aܬ nr )>oprJArv24Ԍ7aG.Hf?ae|ӕyS|ݤ=( bvt9XN?mRiKJp%lOBhuS "Llz4&Y#4$`=ABΑܨYT%=y e%ӳ$g~u./BnEgGw9hʌGP Y(w wxc\}Ozφvhq~ty|;jTj $.Vaa*}y5f)c+}M0&@ڸo NXރw`BJWxz`#w+ +S~4(W9ĒjL@kybRF%?HI81\ ZcB 뼆hSFcPx9{| 8ɻcAaŘҗv1>Ee-ץ $b֘#ڪ?I"<2ƚW۟j2kǎ2.0(N8:dd8O|s)\ @xNM! {/¿.}v-wlcҼ1QCkOIfod< 5骑SϩRc$;H'AZ|ϮhsZk+.;cK B 'fz6ђRJP8*0B66x'`ط[IE#k+mGR8m'إr ?JZu46&reMUnuxdc 6Xnb4.q߻t5Ķ;?-x8c+a7˹֚n5r[pd?:/H5hۋ9eHcI|2s4dv=f=wKG嬒u? Ս H`UB=x|_5<˫8ʱrLҺὝn ƠNOY΍;nR=2,}v!ى,XgIz۬ve̊.2Գ6'ԒSQŧ\Y`p(ڭ$o9-ɫi]MX]9 r{(9]#NVܡ-X XC*m;WV[\!ԃ`Ӧ)KD62ΥOta&{/!g?_f9ob\7-, 7}F})ǩYQYDw5S!c5I9@M |(oxru5)?{ {\3#6%(F}eђ"3'k})yo=Csb'.qp5s, "%p@ skB9 wEddy1w霅A56rr0\=Ώ=ľk*#q@sh+؅\8IoAn?+1n_H8feqmfaTO/AdE0 ,b:FG֖OG5ݛa";h W:{O%3jf$tV_y {GzQ/%vp ly3Sq&BP2y^+>n +H.,[ɽ#$dy]f툿5gn IbF-1A2+tKw6ܒ vcӶ(ϝWh_i؈I纜5KCK͜]x~5UHBA |9 A5cb2Yn?b035"2Q}ob*Gtl F(ˣjyIl.#AÖ_bxϥg(&R=N^~cUf 's=k_(IT.FOWCC#ju# 0O.L=Znk8G-ݲ[l\g9Y#X:fz)M:iwNy?JTO7c]H>j&4- TG3¤PRBumQʠ̣3Ӛ`06P ͬĠc>F)T^#aY%Z68^.r$a\y#~KcyDqk<瑟ʦGt;n81`LSe2y$qӣ=TڡH``-Is}iK\3d~e;ALF xb&aE9'9Tp̡: .I5v+03GE -Rd;UTq"N?72\tG)ZdI4 AP8W'k1>̧)\;F1jGp8Ui 20 :ۖ蠏gL ^-Il5,2 0 A< <5/IӸ-ڦy'֣2~FGFA~%~E%K3-A*caU.F-t~*=z MU[GmKH E_ҮvjW-<`n8*@Hexlz?[Ze\])-ϡgI5VHY$9\??iOkXm= o,wfGpVn Ϯ8mq-JH 'b{fQ-,Vس3Cq!#B[J_i*s˧+b,!=B tWQrO')֥&nd,;~:MC@VS<H:JĞǭDj_@Cs yf_.#_yr-X^ki{ArEͲ4+w0U ?xSܻYnoOa be 985^Fm$qX> ,O,rDt tW ڛ6,׬&nKǨBjI g?*G$Nkku?h$,Mu%.ZR~6vNQe[}4q7(>lΰo V+]nW!L")9ʷ*y VTG-!m&N`5r{V2 pyjվqou~H09_k+b)x-Ϟ W5oK.tmu {bPHhȺg%#e!?PECFA\cgΒIloskB64-]` *nbi|a`}=? V,Z8C+A.*:0UV PYN =7FcLksh5̻B."%=A?J.`myϱgLTR8ǪY6K*HuKKS~{XI`auRhni+yFE9,f )>=An+fesno2Nk!70GD~YGZ>l{6E$Zn-Susi8Yn~hc-Cѡ,!c 7r *:֎j^ͫj"y0u= c!Oy֙s I0f9+ 3.GSL%Bޢu- )0, Uƥ1 LdA@= a<%onS#:9ኙ2ot@P:iꁇ5*'ITV-ϨG;|4`% ;Ң،s3)ssT -Iz~b%4N7۱Z%M Tpp>eX33 ܟvo=T.G*7g#*(FSq3m:7hCȊ;3x5$*aʀ.Cw,9@SVWQryAp:RŸnhRMWbG1oMS'sLӝ:;$ 7z|Êd HK;dY!Q۱G z 41x_T p3;1ڢ9 ZXDFdl"NM*TQPxL.^[l:Svs75HAޫS`5*ҡ{Ic`MDeG7Gm_aϞ.5ː=ixk7V9n% `$?ۚG̊AqnS=@F?jeef%7o0K4iu:& A7H:Krتg Y;5\HOY#r ]-*{Fz-K6Ys{۪=`drAzUw3)-r;;Pݍ 럖gwa["덃*B0FnCqah&WM0\aӺe ݓiUH$$boa?O\nc469J:٣j ch sT.hs'\ցX >]6QЎNi2#>䍑4H , W9j],6qp+'\ƨK*CRhV.t>/1-)*aÏD2Ty{ѥ)f"`ѳPZZ\euIд3ǒD$La)n/$fB129IIW,wOGҢ䴂xkyдrGz@#A-ʋS"x$E?}(Zݤ[9U/0C$m >(_=ﵝ#dLT}j֤E:,KH?H>ɛTH;ԐGVQ^ 80V*4-V*Lg#vV'iF*-o:si!W^%r? 31=bto^賛2Ki ?iXWg}=5̖`?\+0VV1Am&_=j],Yͬk >`xzܲAaiЏyi%h/qRp'Hxe'T, +Zi?/S#"ĪObZ>TkฎqX0QIR^*ʵT:m*$.>"d([<9aaKhvL \0~ڣrI/,K sɫ3K1?{ HؐqFZk ^WIA,@YO@p) @ಌ"߯&k4%@'i(G>URR~ Y)ǻPdyI>T p1h~d"Io ҀN苏A@ڿ~2ڜp3悥csJ #7 "OzR*)oPzb$ydѫgg.=V;ǂDPs 8ˈۀGuN9Idd4cw>G+eT2[wfTC9qXWW!(9#-!*p?`ds퓚;!9p`pV]qOIm$`"{6/Ў~u~% ѳ\,N1Zv7o lӒk#=Ppwn8>G {irF, ucp*yT>hc7gp ?op֢ildRVR͏CUn.mclm8\HS|<`ê`+yLu`3*? lI@f,H ;!*J~ihF5iNQrڣn 8QiAg.q(partykit/inst/ULGcourse-2020/slides_tree.Rnw0000644000176200001440000010730414172227777020346 0ustar liggesusers\documentclass[11pt,t,usepdftitle=false,aspectratio=169]{beamer} \usetheme[nototalframenumber,license]{uibk} \title{Classification and Regression Trees and Beyond} \subtitle{Supervised Learning: Algorithmic Modeling} \author{Lisa Schlosser, Achim Zeileis} %% forest header image \renewcommand{\headerimage}[1]{% \IfStrEqCase{#1}{% {1}{% \gdef\myheaderimageid{#1}% \gdef\myheaderimageposition{nw}% \gdef\myheaderimage{forest.jpg}% }}[% \gdef\myheaderimageid{1}% \gdef\myheaderimageposition{nw}% \gdef\myheaderimage{forest.jpg}% ]% } \headerimage{1} %% custom subsection slides \setbeamercolor*{subsectionfade}{use={normal text},parent={normal text},fg=structure.fg!30!normal text.bg} \AtBeginSubsection[]{% \begin{frame}[c] \begin{center} \usebeamercolor[fg]{subsectionfade} \Large \insertsection \\[2ex] \usebeamercolor[fg]{structure} \huge\bfseries\insertsubsection \end{center} \end{frame} } %% for \usepackage{Sweave} <>= transparent_png <- function(name, width, height, ...) { grDevices::png(filename = paste(name, "png", sep = "."), width = width, height = height, res = 100, units = "in", type = "quartz", bg = "transparent") } @ \SweaveOpts{engine=R, eps=FALSE, echo=FALSE, results=hide, keep.source=TRUE} <>= options(prompt = "R> ", continue = "+ ", useFancyQuotes = FALSE, width = 70) library("rpart") library("partykit") library("coin") set.seed(7) @ <>= data("CPS1985", package = "AER") data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" @ \begin{document} \section{Classification and regression trees and beyond} \subsection{Motivation} %\subsectionpage \begin{frame}[fragile] \frametitle{Motivation} \smallskip \textbf{Idea:} ``Divide and conquer.'' \begin{itemize} \item \emph{Goal:} Split the data into small(er) and (rather) homogenous subgroups. \item \emph{Inputs:} Explanatory variables (or covariates/regressors) used for splitting. \item \emph{Output:} Prediction for dependent (or target) variable(s). \end{itemize} \bigskip \pause \textbf{Formally:} \begin{itemize} \item Dependent variable $Y$ (possibly multivariate). \item Based on explanatory variables $X_1, \dots, X_m$. \item ``Learn'' subgroups of data by combining splits in $X_1, \dots, X_m$. \item Predict $Y$ with (simple) model in the subgroups, often simply the mean. \end{itemize} \bigskip \pause \textbf{Key features:} \begin{itemize} \item Predictive power in nonlinear regression relationships. \item Interpretability (enhanced by tree visualization), i.e., no ``black box''. \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Example:} Survival (yes/no) on the Titanic. Women and children first? \begin{center} \setkeys{Gin}{width=0.9\textwidth} <>= ct_ttnc <- ctree(Survived ~ Gender + Age + Class, data = ttnc, alpha = 0.01) plot(ct_ttnc) @ \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Model formula:} \code{Survived ~ Gender + Age + Class}. \bigskip \textbf{Data:} Information on the survival of 2201~passengers on board the ill-fated maiden voyage of the RMS~Titanic in 1912. A data frame containing \Sexpr{nrow(ttnc)} observations on \Sexpr{ncol(ttnc)} variables. \bigskip \begin{tabular}{ll} \hline Variable & Description\\ \hline \code{Class} & Factor: 1st, 2nd, 3rd, or Crew.\\ \code{Gender} & Factor: Male, Female.\\ \code{Age} & Factor: Child, Adult.\\ \code{Survived} & Factor: No, Yes.\\ \hline \end{tabular} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Example:} Determinants of wages and returns to education. \begin{center} \setkeys{Gin}{width=0.99\textwidth} <>= ct_cps <- ctree(log(wage) ~ education + experience + age + ethnicity + gender + union, data = CPS1985, alpha = 0.01) plot(ct_cps) @ \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Model formula:} \code{log(wage) ~ education + experience + age + ethnicity + gender + union}. \bigskip \textbf{Data:} Random sample from the May 1985 US Current Population Survey. A data frame containing \Sexpr{nrow(CPS1985)} observations on \Sexpr{ncol(CPS1985)} variables. \bigskip \begin{tabular}{ll} \hline Variable & Description\\ \hline \code{wage} & Wage (in US dollars per hour). \\ \code{education} & Education (in years). \\ \code{experience} & Potential work experience (in years, \code{age - education - 6}). \\ \code{age} & Age (in years). \\ \code{ethnicity} & Factor: Caucasian, Hispanic, Other. \\ \code{gender} & Factor: Male, Female. \\ \code{union} & Factor. Does the individual work on a union job? \\ \hline \end{tabular} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Alternatively:} Linear regression tree. \begin{center} \setkeys{Gin}{width=0.9\textwidth} <>= mob_cps <- lmtree(log(wage) ~ education | experience + age + ethnicity + gender + union, data = CPS1985) plot(mob_cps) @ \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Model formula:} \code{log(wage) ~ education | experience + age + ethnicity + gender + union}. \bigskip \textbf{Model fit:} \begin{itemize} \item Not just a group-specific mean. \item But group-specific intercept and slope (i.e., returns to education). \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Example:} Nowcasting (1--3 hours ahead) of wind direction at Innsbruck Airport. \setkeys{Gin}{width=0.87\linewidth} \begin{center} \includegraphics{circtree_ibk.pdf} \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Data:} 41,979 data points for various weather observations. \begin{itemize} \item Dependent variable: Wind direction 1--3 hours ahead. \item Explanatory variables: Current weather observations including wind direction, wind speed, temperature, (reduced) air pressure, relative humidity. \item Circular response in $[0^{\circ}, 360^{\circ})$ with $0^{\circ} = 360^{\circ}$. \end{itemize} \bigskip \textbf{Model fit:} Circular distribution (von Mises), fitted by maximum likelihood. \end{frame} % \begin{frame}[fragile] % \frametitle{Motivation} % {\small Wage data: \quad $log(wage) \; \sim \; education + experience + ethnicity + region + parttime$} % \begin{center} % \setkeys{Gin}{width=0.99\textwidth} % <>= % data("CPS1988", package = "AER") % ## ctree % plot(ctree(log(wage)~education+experience+ethnicity+region+parttime,data=CPS1988, % control = ctree_control(alpha = 0.01, minsplit = 7000))) % @ % \end{center} % \end{frame} % \begin{frame}[fragile] % \frametitle{Motivation} % {\small Boston housing: \quad $medv \; \sim \; lstat + crim + rm + age + black$} % \begin{center} % \setkeys{Gin}{width=0.99\textwidth} % <>= % data("Boston") % plot(ctree(medv~lstat + crim + rm + age + black, % data = Boston, control = ctree_control(alpha = 0.01, minsplit = 150))) % @ % \end{center} % \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \textbf{Original idea:} Trees are purely algorithmic models without assumptions. \begin{itemize} \item Data-driven ``learning'' of homogenous subgroups. \item Simple constant fit in each group, e.g., an average or proportion. \end{itemize} \bigskip \pause \textbf{Subsequently:} Trees are well-suited for combination with classical models. \begin{itemize} \item Group-wise models, e.g., fitted by least squares or maximum likelihood. \item Model-based learning accounts for model differences across subgroups. \end{itemize} \bigskip \pause \textbf{Trade-off:} \begin{itemize} \item Assume simple model and learn larger tree \emph{vs.} \item More complex model and potentially smaller tree. \end{itemize} \end{frame} \subsection{Tree algorithm} \begin{frame}[fragile] \frametitle{Tree algorithm} \textbf{Base algorithm:} \begin{enumerate} \item Fit a model to the response $Y$. \item Assess association of $Y$ (or a corresponding transformation/goodness-of-fit measure) and each possible split variable $X_j$. \item Split sample along the $X_{j^{\ast}}$ with strongest association: Choose split point with highest improvement of the model fit. \item Repeat steps 1--3 recursively in the subsamples until some stopping criterion is met. \item \emph{Optionally:} Reduce size of the tree by pruning branches of splits that do not improve the model fit sufficiently. \end{enumerate} \end{frame} \begin{frame}[fragile] \frametitle{Tree algorithm} \textbf{Specific algorithms:} Many (albeit not all) can be derived from the base algorithm by combining suitable building blocks. \bigskip \pause \textbf{Models for $Y$:} Simple constant fits vs.\ more complex statistical models. \bigskip \pause \textbf{Goodness of fit:} Suitable measure depends on type of response variable(s) $Y$ and the corresponding model. \end{frame} \begin{frame}[fragile] \frametitle{Tree algorithm} \textbf{Goodness of fit:} \begin{itemize} \item Numeric response: \begin{itemize} \item $Y$ or ranks of $Y$. \item (Absolute) deviations $Y - \bar Y$. \item Residual sum of squares $\sum (Y - \hat{Y})^2$. \end{itemize} \pause \item Categorical response: \begin{itemize} \item Dummy variables for categories. \item Number of misclassifications. \item Gini impurity. \end{itemize} \pause \item Survival response: \begin{itemize} \item Log-rank scores. \end{itemize} \pause \item Parametric model: \begin{itemize} \item Residuals. \item Model scores (gradient contributions). \end{itemize} \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Tree algorithm} \textbf{Split variable selection:} Optimize some criterion over all $X_j$ ($j = 1, \dots, m$). \begin{itemize} \item Objective function (residual sum of squares, log-likelihood, misclassification rate, impurity, \dots). \item Test statistic or corresponding $p$-value. \end{itemize} \bigskip \pause \textbf{Split point selection:} Optimize some criterion over all (binary) splits in $X_{j^*}$. \begin{itemize} \item Objective function. \item Two-sample test statistic or corresponding $p$-value. \end{itemize} \bigskip \pause \textbf{Stopping criteria:} \begin{itemize} \item Constraints: Number of observations per node, tree depth, \dots \item Lack of improvement: Significance, information criteria, \dots \end{itemize} \end{frame} \subsection{Split variable selection} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Idea:} \begin{itemize} \item Select variable $X_j$ ($j = 1, \dots, m$) most associated with heterogeneity in $Y$. \item Heterogeneity captured by goodness-of-fit measure. \item \emph{Often:} Maximum association over all possible binary splits. \item \emph{Alternatively:} Overall association. \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Potential bias:} Variables with many potential splits may yield greater association ``by chance'', e.g., continuous $X_j$ or categorical with many levels. \bigskip \pause \textbf{Unbiased recursive partitioning:} Accounts for potential random variation by employing $p$-values from appropriate statistical tests. \bigskip \pause \textbf{Possible tests:} Depend on scales of $Y$, $X_j$, and the adopted model. \begin{itemize} \item $\chi^2$ test, Pearson correlation test, two-sample t-test, ANOVA. \item Maximally-selected two-sample tests. \item Parameter instability tests. \item \dots \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Examples:} \begin{itemize} \item Titanic survival and wage determinants data. \item Selection of first split variable in root node. \item Employ classical statistical tests. \item Does not exactly match a particular tree algorithm but similar to CTree. \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Assess pairwise associations:} \code{Survived ~ Gender} (Titanic). \begin{minipage}[t]{0.43\linewidth} <>= plot(Survived ~ Gender, data = ttnc) @ \vspace{-0.7cm} <>= <> @ \end{minipage} \hfill \pause \begin{minipage}[t]{0.5\linewidth} <>= xtabs(~ Survived + Gender, data = ttnc) @ \end{minipage} \pause <>= chisq.test(xtabs(~ Survived + Gender, data = ttnc)) @ \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Assess pairwise associations:} \code{Survived ~ Age} (Titanic). \begin{minipage}[t]{0.43\linewidth} <>= plot(Survived ~ Age, data = ttnc) @ \vspace{-0.7cm} <>= <> @ \end{minipage} \hfill \pause \begin{minipage}[t]{0.5\linewidth} <>= xtabs(~ Survived + Age, data = ttnc) @ \end{minipage} <>= chisq.test(xtabs(~ Survived + Age, data = ttnc)) @ \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Assess pairwise associations:} \code{Survived ~ Class} (Titanic). \begin{minipage}[t]{0.43\linewidth} <>= plot(Survived ~ Class, data = ttnc) @ \vspace{-0.7cm} <>= <> @ \end{minipage} \hfill \pause \begin{minipage}[t]{0.5\linewidth} <>= xtabs(~ Survived + Class, data = ttnc) @ \end{minipage} <>= chisq.test(xtabs(~ Survived + Class, data = ttnc)) @ \end{frame} % % \begin{frame}[fragile] % \frametitle{Split variable selection} % \textbf{Compare pairwise associations} (Titanic): % Based on independence tests, e.g., $\chi^2$-test for categorical variables. % \vspace{0.4cm} % <>= % chisq_test(Survived ~ Gender, data = ttnc) % @ % % \vspace{0.2cm} % % <>= % chisq_test(Survived ~ Age, data = ttnc) % @ % % \vspace{0.7cm} % % $\Rightarrow$ Select the split variable showing the lowest $p$-value. % % \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \begin{center} \setkeys{Gin}{width=0.95\textwidth} <>= <> @ \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Assess pairwise associations:} \code{log(wage) ~ education} (Wages). \begin{minipage}[t]{0.39\linewidth} <>= plot(log(wage) ~ education, data = CPS1985) @ \vspace{-0.7cm} \setkeys{Gin}{width=\textwidth} <>= <> @ \end{minipage} \hfill \pause \begin{minipage}[t]{0.59\linewidth} <>= cor.test(~ log(wage) + education, data = CPS1985) @ <>= out <- capture.output(cor.test(~ log(wage) + education, data = CPS1985)) out <- gsub("alternative hypothesis: ", "alternative hypothesis:\n", out, fixed = TRUE) writeLines(out) @ \end{minipage} \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \textbf{Assess pairwise associations:} \code{log(wage) ~ gender} (Wages). \begin{minipage}[t]{0.39\linewidth} <>= plot(log(wage) ~ gender, data = CPS1985) @ \vspace{-0.7cm} \setkeys{Gin}{width=\textwidth} <>= <> @ \end{minipage} \hfill \pause \begin{minipage}[t]{0.59\linewidth} <>= t.test(log(wage) ~ gender, data = CPS1985) @ <>= out <- capture.output(t.test(log(wage) ~ gender, data = CPS1985)) out <- gsub("alternative hypothesis: ", "alternative hypothesis:\n", out, fixed = TRUE) writeLines(out) @ \end{minipage} \end{frame} \begin{frame}[fragile] \frametitle{Split variable selection} \begin{center} \setkeys{Gin}{width=0.99\textwidth} <>= <> @ \end{center} \end{frame} \subsection{Split point selection \& pruning} \begin{frame}[fragile] \frametitle{Split point selection} \textbf{Idea:} \begin{itemize} \item Split $Y$ into most homogenous subgroups with respect to selected $X_{j^*}$. \item Homogeneity captured by goodness-of-fit measure. \item \emph{Often:} Consider only binary splits. \item Trivial for binary $X_{j^*}$. \item Otherwise typically exhaustive search over all binary splits. \item Possibly already done in split variable selection. \end{itemize} \bigskip \pause \textbf{Goodness-of-fit measure:} Depends on scale of $Y$ and the adopted model. \begin{itemize} \item Objective function (residual sum of squares, log-likelihood, misclassification rate, impurity, \dots). \item Two-sample test statistic or corresponding $p$-value. \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Split point selection} \textbf{Example:} \begin{itemize} \item Wage determinants data. \item Selection of best split point in education in root node. \item Residual sum of squares vs.\ normal log-likelihood. \item Two-sample ANOVA-type $\chi^2$ test and corresponding $p$-value. \end{itemize} \end{frame} <>= evalsplit <- function(sp) { m <- lm(log(wage) ~ factor(education <= sp), data = CPS1985) s <- independence_test(log(wage) ~ factor(education <= sp), data = CPS1985, teststat = "quadratic") c( rss = deviance(m), loglik = logLik(m), logpval = pchisq(statistic(s), df = 1, log = TRUE, lower.tail = FALSE), teststatistic = statistic(s) ) } sp <- head(sort(unique(CPS1985$education)), -1) eval <- sapply(sp, evalsplit) @ \begin{frame}[fragile] \frametitle{Split point selection} <>= par(mar = c(5, 3, 1, 3)) plot(sp, eval["loglik",], type = "n", xlab = "education", ylab = "", axes = FALSE) abline(v = 13, lty = 2, lwd = 1.5) lines(sp, eval["loglik", ], type = "o", col = 2, lwd = 1.5) axis(2, col.ticks = 2, col.axis = 2) par(new = TRUE) plot(sp, eval["teststatistic",], type = "o", col = 4, lwd = 1.5, xlab = "", ylab = "", axes = FALSE) axis(4, col.ticks = 4, col.axis = 4) axis(1) axis(1, at = 13) box() legend("topleft", c("Log-likelihood", "Test statistic"), col = c(2, 4), lwd = 1.5, pch = 1, bty = "n") @ \end{frame} \begin{frame}[fragile] \frametitle{Split point selection} <>= par(mar = c(5, 3, 1, 3)) plot(sp, eval["rss",], type = "n", xlab = "education", ylab = "", axes = FALSE) abline(v = 13, lty = 2, lwd = 1.5) lines(sp, eval["rss", ], type = "o", col = 2, lwd = 1.5) axis(2, col.ticks = 2, col.axis = 2) par(new = TRUE) plot(sp, eval["logpval",], type = "o", col = 4, lwd = 1.5, xlab = "", ylab = "", axes = FALSE) axis(4, col.ticks = 4, col.axis = 4) axis(1) axis(1, at = 13) box() legend("bottomleft", c("Residual sum of squares", "Log-p-value"), col = c(2, 4), lwd = 1.5, pch = 1, bty = "n") @ \end{frame} \begin{frame}[fragile] \frametitle{Split point selection} \begin{center} \setkeys{Gin}{width=0.99\textwidth} <>= <> @ \end{center} \end{frame} \begin{frame}[fragile] \frametitle{Pruning} \textbf{Goal:} Avoid overfitting. \medskip \textbf{Pre-pruning:} Internal stopping criterium. Stop splitting when there is no significant association to any of the possible split variables $X_j$. \medskip \textbf{Post-pruning:} Grow large tree and prune splits that do not improve the model fit (e.g., via cross-validation or information criteria). \end{frame} \begin{frame}[fragile] \frametitle{Pruning} \textbf{Pre-pruning:} \begin{itemize} \item[+] Does not require additional calculations as only already provided information from statistical test is used. \item[+] Computationally less expensive as trees are prevented from getting too large. \item[--] Performance depends on the power of the selected statistical test. \end{itemize} \vspace{0.4cm} \textbf{Post-pruning:} \begin{itemize} \item[+] Stable method to avoid overfitting, regardless of the power of the employed statistical test. \item[+] Can employ information criteria such as AIC or BIC for model-based partitioning. \item[--] Computationally more expensive as very large trees are grown and additional (out-of-bag) evaluations are required. \end{itemize} \end{frame} \subsection{Conditional inference trees} \begin{frame} \frametitle{Conditional inference trees} \textbf{CTree:} \begin{itemize} \item Employs general conditional inference (or permutation test) framework for association of $h(Y)$ vs.\ $g(X_j)$. \item Broadly applicable by choosing suitable transformations $h(\cdot)$ and $g(\cdot)$. \item \emph{Examples:} Univariate $Y$ of arbitrary scale, multivariate, model-based, etc. \item \emph{Default:} Pre-pruning based on direct asymptotic tests for split variable selection. Maximally-selected two-sample statistics for split point selection. \item \emph{Software:} R package \emph{partykit} (and previously: \emph{party}). \item \emph{Reference:} Hothorn, Hornik, Zeileis (2006). \end{itemize} \bigskip \textbf{Note:} CTree used in previous illustrations of classification and regression trees. \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{Illustration:} Titanic survival data. \bigskip \textbf{Data:} Preprocessing from four-way contingency table \code{Titanic} in base R. <>= data("Titanic", package = "datasets") ttnc <- as.data.frame(Titanic) ttnc <- ttnc[rep(1:nrow(ttnc), ttnc$Freq), 1:4] names(ttnc)[2] <- "Gender" @ \bigskip \textbf{CTree:} With default arguments. <>= library("partykit") ct_ttnc <- ctree(Survived ~ Gender + Age + Class, data = ttnc) plot(ct_ttnc) print(ct_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \setkeys{Gin}{width=0.9\linewidth} <>= plot(ct_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} <>= print(ct_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{Predictions:} Different types. <>= ndm <- data.frame(Gender = "Male", Age = "Adult", Class = c("1st", "2nd", "3rd")) predict(ct_ttnc, newdata = ndm, type = "node") predict(ct_ttnc, newdata = ndm, type = "response") predict(ct_ttnc, newdata = ndm, type = "prob") @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{Predictions:} Women and children first? <>= ndf <- data.frame(Gender = "Female", Age = "Adult", Class = c("1st", "2nd", "3rd")) ndc <- data.frame(Gender = "Male", Age = "Child", Class = c("1st", "2nd", "3rd")) cbind( Male = predict(ct_ttnc, newdata = ndm, type = "prob")[, 2], Female = predict(ct_ttnc, newdata = ndf, type = "prob")[, 2], Child = predict(ct_ttnc, newdata = ndc, type = "prob")[, 2] ) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{Hyperparameters:} See \code{?ctree_control}. \begin{itemize} \item \code{alpha}: Significance level for pre-pruning in split variable selection. \item \code{minsplit}: Minimum number of observations in a node for splitting. \item \code{minbucket}: Minimum number of observations in a terminal node. \item \code{maxdepth}: Maximum depth of the tree. \item \code{multiway}: Use multiway splits for unordered factors with $> 2$ levels? \item \dots \end{itemize} \bigskip \pause \textbf{Example:} <>= ct_ttnc2 <- ctree(Survived ~ Gender + Age + Class, data = ttnc, alpha = 0.01, minbucket = 5, minsplit = 15, maxdepth = 4) plot(ct_ttnc2) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \setkeys{Gin}{width=\linewidth} <>= plot(ct_ttnc2) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{Predictions:} Male children in 1st and 2nd class are now in their own terminal nodes. <>= predict(ct_ttnc2, newdata = ndc, type = "prob") @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{Evaluations:} ``As usual.'' \begin{itemize} \item In-sample vs. out-of-sample. \item Scoring rules (e.g., misclassification rates or other loss functions). \item Confusion matrix. \item Receiver operator characteristic (ROC) curve. \item \dots \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{In-sample:} Augment learning data. <>= ttnc$Fit <- predict(ct_ttnc2, type = "response") ttnc$Group <- factor(predict(ct_ttnc2, type = "node")) @ \bigskip \textbf{Confusion matrix:} <>= xtabs(~ Fit + Survived, data = ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{Terminal nodes:} Recompute empirical survival rates. <>= tab <- xtabs(~ Group + Survived, data = ttnc) prop.table(tab, 1) @ \end{frame} \begin{frame}[fragile] \frametitle{Conditional inference trees} \textbf{More graphics:} \emph{ggplot2} support via \code{autoplot()} method from \emph{ggparty}. \setkeys{Gin}{width=0.9\linewidth} <>= library("ggparty") theme_set(theme_minimal()) autoplot(ct_ttnc2) @ \end{frame} \subsection{Recursive partitioning} \begin{frame} \frametitle{Recursive partitioning} \textbf{RPart:} \begin{itemize} \item Implements classic CART algorithm (classification and regression trees). \item Split variable and split point selection via exhaustive search based on objective functions. \item Hence biased towards split variables with many possible splits. \item Cross-validation-based post-pruning and no pre-pruning. \item \emph{Default:} Gini impurity for classification, residual sum of squares for regression. \item \emph{Software:} R package \emph{rpart}. Similar implementations in other languages (e.g., \emph{scikit-learn}). \item \emph{Reference:} Algorithm by Breiman \emph{et al.} (1984), open-source implementation by Therneau \& Atkinson (1997). \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \textbf{R package:} Part of every standard R installation. \bigskip \textbf{Hyperparameters:} \code{?rpart.control}. \bigskip \textbf{RPart:} With default arguments. <>= library("rpart") rp_ttnc <- rpart(Survived ~ Gender + Age + Class, data = ttnc) plot(rp_ttnc) text(rp_ttnc) print(rp_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \setkeys{Gin}{width=0.9\linewidth} <>= plot(rp_ttnc) text(rp_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \setkeys{Gin}{width=0.9\linewidth} <>= print(rp_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \textbf{Coercion:} \begin{itemize} \item \code{as.party()} method to coerce \code{rpart} objects to \code{constparty} objects. \item Based on generic infrastructure for recursive partitioning in \emph{partykit}. \item Enables unified interface (print, plot, predict, \dots). \end{itemize} \medskip <>= py_ttnc <- as.party(rp_ttnc) plot(py_ttnc) print(py_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \setkeys{Gin}{width=0.9\linewidth} <>= plot(py_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \setkeys{Gin}{width=0.9\linewidth} <>= print(py_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \textbf{Post-pruning:} \begin{itemize} \item Cost-complexity pruning, similar to using information criteria. \item Complexity parameter \code{cp} controls trade-off between reduction of objective function and tree size. \item Carried out automatically during fitting. \item Additionally, ten-fold cross-validation carried out as well. \item Results in \code{rpart} object as \code{cptable}. \end{itemize} \bigskip \pause \textbf{Here:} Fitted object also has optimal cross-validation error (\code{xerror}). \medskip <>= rp_ttnc$cptable @ \end{frame} \begin{frame}[fragile] \frametitle{Recursive partitioning} \textbf{Example:} Employ complexity parameter \code{cp = 0.1} for illustration. \medskip <>= prune(rp_ttnc, cp = 0.1) @ \end{frame} \subsection{Model-based recursive partitioning} \begin{frame} \frametitle{Model-based recursive partitioning} \textbf{MOB:} \begin{itemize} \item Parametric model in subgroups (maximum likelihood, least squares, \dots). \item Split variable selection based on asymptotic parameter instability tests. \item Split point selection via exhaustive search based on objective function. \item Significance-based pre-pruning (default) and optionally post-pruning based on information criteria (AIC, BIC, \dots). \item \emph{Examples:} (Generalized) linear model tree, distributional trees, \dots \item \emph{Software:} R package \emph{partykit} (and previously: \emph{party}), various ``mobsters'' in extension packages. \item \emph{Hyperparameters:} \code{?mob\_control}. \item \emph{Reference:} Zeileis, Hothorn, Hornik (2008). \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Model-based recursive partitioning} \textbf{Example:} Investigate treatment heterogeneity for ``women and children first.'' \medskip <>= ttnc <- transform(ttnc, Treatment = factor(Gender == "Female" | Age == "Child", levels = c(FALSE, TRUE), labels = c("Male&Adult", "Female|Child") ) ) @ \bigskip \pause \textbf{Model:} Tree based on binary logit GLM for survival. \medskip <>= mob_ttnc <- glmtree(Survived ~ Treatment | Class + Gender + Age, data = ttnc, family = binomial, alpha = 0.01) plot(mob_ttnc) print(mob_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Model-based recursive partitioning} \setkeys{Gin}{width=0.83\textwidth} <>= plot(mob_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Model-based recursive partitioning} \vspace{-0.4cm} \small <>= mob_ttnc @ \end{frame} \subsection{Evolutionary learning of globally optimal trees} \begin{frame} \frametitle{Evolutionary learning of globally optimal trees} \textbf{EvTree:} \begin{itemize} \item \emph{Goal:} Globally optimal partition rather than locally optimal split in each step. \item NP-hard optimization problem, attempt solution via evolutionary learning. \item Based on so-called ``fitness'' function. \item Essentially a penalized objective function, similar to information criteria or cost-complexity. \item Thus, no additional pruning step. \item \emph{Software:} R package \emph{evtree} (leverages \emph{partykit}). \item \emph{Hyperparameters:} \code{?evtree\_control}. \item \emph{Reference:} Grubinger, Zeileis, Pfeiffer (2014). \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Evolutionary learning of globally optimal trees} \textbf{EvTree:} With default parameters. \medskip <>= library("evtree") set.seed(1) ev_ttnc <- evtree(Survived ~ Gender + Age + class, data = ttnc) plot(ev_ttnc) print(ev_ttnc) @ <>= library("evtree") if(file.exists("ev_ttnc.rds")) { ev_ttnc <- readRDS("ev_ttnc.rds") } else { set.seed(1) ev_ttnc <- evtree(Survived ~ Gender + Age + Class, data = ttnc) saveRDS(ev_ttnc, file = "ev_ttnc.rds") } @ \end{frame} \begin{frame}[fragile] \frametitle{Evolutionary learning of globally optimal trees} \setkeys{Gin}{width=0.72\textwidth} <>= plot(ev_ttnc) @ \end{frame} \begin{frame}[fragile] \frametitle{Evolutionary learning of globally optimal trees} <>= ev_ttnc @ \end{frame} \subsection{Other algorithms} \begin{frame} \frametitle{Other algorithms} \textbf{Furthermore:} Based on \emph{partykit}. \begin{itemize} \item \emph{model4you:} Model-based trees/forests with personalised treatment effects. \item \emph{disttree:} Distributional modeling with regression trees and random forests. \item \emph{circtree:} Circular distributional trees and forests. \item \emph{glmertree:} Generalized linear mixed-effects model trees. \item \emph{psychotree:} Psychometric model trees (Rasch, Bradley-Terry, \dots). \item \emph{stablelearner:} Stability assessment of trees (and other learners). \item \ldots \end{itemize} \end{frame} \begin{frame} \frametitle{Other algorithms} \textbf{Other R packages:} \begin{itemize} \item \emph{RWeka:} Interface to \emph{Weka} machine learning library, provided open-source implementations of C4.5 (J.48) and M5 (M5'), and LMT. \item \emph{C50:} C5.0 (successor to C4.5) decision trees and rule-based models. \item Many more: \emph{mvpart}, \emph{quint}, \emph{stima}, \dots. \end{itemize} \end{frame} \begin{frame} \frametitle{Other algorithms} \textbf{Beyond R:} \begin{itemize} \item Unbiased recursive partitioning software (standalone) by Loh and co-workers: \emph{QUEST}, \emph{GUIDE}, \dots \item In Python: \emph{scikit-learn} implements classical machine learning algorithms, very limited availability of statistical inference-based algorithms. \item \dots \end{itemize} \end{frame} \subsection{References} \begin{frame} \frametitle{References} \small Breiman L, Friedman JH, Olshen RA, Stone CJ (1984). \dquote{Classification and Regression Trees.} \emph{Wadsworth, California.}, \medskip Therneau T, Atkinson B (1997). \dquote{An Introduction to Recursive Partitioning Using the {rpart} Routine.} Technical Report~61, Section of Biostatistics, Mayo Clinic, Rochester. \url{http://www.mayo.edu/hsr/techrpt/61.pdf} \medskip % Breiman L (2001). % \dquote{Random {Forests}.} % \emph{Machine Learning}, % \textbf{45}(1), 5--32. % \doi{10.1023/A:1010933404324} % % \medskip Hothorn T, Hornik K, Zeileis A (2006). \dquote{Unbiased Recursive Partitioning: A Conditional Inference Framework.} \emph{Journal of Computational and Graphical Statistics}, \textbf{15}(3), 651--674. \doi{10.1198/106186006X133933} \medskip Zeileis A, Hothorn T, Hornik K (2008). \dquote{Model-Based Recursive Partitioning.} \emph{Journal of Computational and Graphical Statistics}, \textbf{17}(2), 492--514. \doi{10.1198/106186008X319331} \medskip Hothorn T, Zeileis A (2015). \dquote{{partykit}: A Modular Toolkit for Recursive Partytioning in \textsf{R}.} \emph{Journal of Machine Learning Research}, \textbf{16}, 3905--3909. \url{http://www.jmlr.org/papers/v16/hothorn15a.html} % medskip % % Schlosser L, Hothorn T, Stauffer R, Zeileis A (2019). % \dquote{Distributional Regression Forests for Probabilistic Precipitation Forecasting in Complex Terrain.} % \emph{The Annals of Applied Statistics}, \textbf{13}(3), 1564--1589. % \doi{10.1214/19-AOAS1247} % \medskip % Breiman L (2001). % \dquote{Statistical Modeling: The Two Cultures.} % \emph{Statistical Science}, % \textbf{16}(3), 199--231. % \doi{10.1214/ss/1009213726} \end{frame} \end{document} partykit/inst/ULGcourse-2020/density_all_hist.pdf0000644000176200001440000001524214172227777021404 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20200419202259) /ModDate (D:20200419202259) /Title (R Graphics Output) /Producer (R 3.6.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 2762 /Filter /FlateDecode >> stream xYˎ% W/(zP^0,r؀3~C5=,1l֩CJ_?ƾJvu,f\>}:_޾\۟_~փO?߷Q|O[ǟָ|yvxȁ|U _D\er~EryE}rƵ8^!]1^!g^k_}" 񼕊m몷;x{\y7\~x,6r Ews DV;6jϛZ+!u_qMGdc]C@ F-4{i_C"سmw?rLފW-޾c9#^b\{׺LnW+;xSʢQ'牟g;+pOhѮDL˥MTGzYEٙ[{c]jφ|ɯޯ|㻈$Ȓs+_ iv+%͝?vβJIgUc'CVa;+񳅛*a ߓ_ad[Ƹv˜w7F ZڴZڂoj5n\5o},qɤ}\ m\סu~Zm\-_@ "Ɏ%[F=A޸'ROK~Ui\ ht%c&&w uQ`Y  -kTq[!"`5KV rG#*[qM׹N(q+fHD)R@%Ԟ%:u[&LB ia 1^S.XE2k7Ŏ@fPonX8eSIq^%6NM*l8TAIwr@k ];!(t+>6X49E%KJqi`bLg!E'\eS| N :'hR4Xr HX H  Mj2\N7Sh.r54`fp3Ay![=Џ"<0@ۭOxlgwj4iNTiT7'GgxaN+BߎcXJ<(?~N,FH'2IQm+&͏2~bQ:Ž6)Y݅>*:E?öTL$xٯ:}!SBvRI ٘)4xM ijh~O8Kg)<$a?I<²=TQAz)AgX0)qHOЖW-~ՖWb[cO??]c*HZe@EU zo^opߝ^/3v +: 9ֹʞv>3YrmCVz,dNw ?+ݣS ѷ?]c`X=m5HN,xm-i۴?ă6=J,}V)ƒҋ$5/FՠPk/'_!>NM?M qe`#c /  eGWxׁwӧm|q t.pǾb^3?шy?$A/Vw 񫚯# xȬ͘8;zA ~`,[XyQ.[ -8ll/P/xl<0SO%?Ed_s̢SG3oyu 9N_y 33ķiN1?ij[4uv^fpqҟWa}MU3vI0c-mKrhx;1Dbo'^VONSc# bz~$ ơxS(5o̪`CYuO&Ji L.l=on{CaB|9J{;y+o[8@$ O.gP)oJ6q* ,h!^_/pKֶYVlUc5L/fb[|c3ydE޴2"Ŀ~ow}?%<~z2_endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 792 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << /GS1 10 0 R /GS2 11 0 R /GS257 12 0 R >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /ExtGState /CA 0.200 >> endobj 11 0 obj << /Type /ExtGState /CA 1.000 >> endobj 12 0 obj << /Type /ExtGState /ca 0.200 >> endobj xref 0 13 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000003126 00000 n 0000003209 00000 n 0000003348 00000 n 0000003381 00000 n 0000000212 00000 n 0000000292 00000 n 0000006076 00000 n 0000006333 00000 n 0000006382 00000 n 0000006431 00000 n trailer << /Size 13 /Info 1 0 R /Root 2 0 R >> startxref 6480 %%EOF partykit/cleanup0000755000176200001440000000150114415225047013477 0ustar liggesusers#!/bin/sh for f in ./src/*.*o; do rm -f $f done for f in ./src/*~; do rm -f $f done for f in ./R/*~; do rm -f $f done for f in ./man/*~; do rm -f $f done for f in *~; do rm -f $f done for f in .*~; do rm -f $f done for f in ./tests/*~; do rm -f $f done for f in ./tests/*.ps; do rm -f $f done for f in ./vignettes/*~; do rm -f $f done for f in ./vignettes/*.log; do rm -f $f done for f in ./vignettes/*.out; do rm -f $f done for f in ./vignettes/*.bbl; do rm -f $f done for f in ./vignettes/*.blg; do rm -f $f done for f in ./vignettes/*.brf; do rm -f $f done for f in ./vignettes/*.aux; do rm -f $f done for f in ./vignettes/*.tpt; do rm -f $f done for f in ./vignettes/Rplots*; do rm -f $f done find . -name "DEADJOE" -exec rm -f {} \; exit 0