47
47
update = FALSE, drop = TRUE, ...)
50
lpart <- 1:length(attr(x, "lhs"))
51
rpart <- 1:length(attr(x, "rhs"))
50
lpart <- 1L:length(attr(x, "lhs"))
51
rpart <- 1L:length(attr(x, "rhs"))
53
53
## default: keep all parts
54
54
lhs <- if(is.null(lhs)) lpart else lpart[lhs]
55
55
rhs <- if(is.null(rhs)) rpart else rpart[rhs]
56
56
if(any(is.na(lhs))) {
57
57
lhs <- as.vector(na.omit(lhs))
58
if(length(lhs) < 1) lhs <- 0
58
if(length(lhs) < 1L) lhs <- 0L
59
59
warning("subscript out of bounds, not all 'lhs' available")
61
61
if(any(is.na(rhs))) {
62
62
rhs <- as.vector(na.omit(rhs))
63
if(length(rhs) < 1) rhs <- 0
63
if(length(rhs) < 1L) rhs <- 0L
64
64
warning("subscript out of bounds, not all 'rhs' available")
68
68
collapse <- rep(as.logical(collapse), length.out = 2)
70
70
rval <- paste_formula(attr(x, "lhs")[lhs], attr(x, "rhs")[rhs],
71
lsep = ifelse(collapse[1], "+", "|"),
72
rsep = ifelse(collapse[2], "+", "|"))
71
lsep = ifelse(collapse[1L], "+", "|"),
72
rsep = ifelse(collapse[2L], "+", "|"))
74
74
## omit potentially redundant terms
75
75
if(all(collapse) & update) rval <- update(rval, if(length(rval) > 2) . ~ . else ~ .)
86
terms.Formula <- function(x, ..., lhs = NULL, rhs = NULL) {
86
terms.Formula <- function(x, ..., lhs = NULL, rhs = NULL, dot = "separate") {
88
88
## simplify a Formula to a formula that can be processed with
89
89
## terms/model.frame etc.
96
96
## convenience functions for checking extended features
97
97
is_lhs_extended <- function(Formula) {
98
98
## check for multiple parts
99
if(length(attr(Formula, "lhs")) > 1) {
99
if(length(attr(Formula, "lhs")) > 1L) {
102
102
## and multiple responses
103
if(length(attr(Formula, "lhs")) < 1) return(FALSE)
103
if(length(attr(Formula, "lhs")) < 1L) return(FALSE)
104
104
return(length(attr(terms(paste_formula(NULL,
105
attr(Formula, "lhs"), rsep = "+")), "term.labels")) > 1)
105
attr(Formula, "lhs"), rsep = "+")), "term.labels")) > 1L)
109
109
is_rhs_extended <- function(Formula) {
110
110
## check for muliple parts
111
length(attr(Formula, "rhs")) > 1
111
length(attr(Formula, "rhs")) > 1L
114
114
## simplify (if necessary)
115
115
ext_lhs <- is_lhs_extended(Form)
116
116
if(ext_lhs | is_rhs_extended(Form)) {
117
117
form <- if(ext_lhs) {
118
if(length(attr(Form, "rhs")) == 1 & identical(attr(Form, "rhs")[[1]], 0)) {
118
if(length(attr(Form, "rhs")) == 1L & identical(attr(Form, "rhs")[[1L]], 0)) {
119
119
paste_formula(NULL, attr(Form, "lhs"), rsep = "+")
121
121
paste_formula(NULL, c(attr(Form, "lhs"), attr(Form, "rhs")), rsep = "+")
133
## simplify and then call traditional terms()
133
## check whether formula has a dot
134
has_dot <- function(formula) inherits(try(terms(formula), silent = TRUE), "try-error")
136
## simplify to standard formula
134
137
form <- simplify_to_formula(x, lhs = lhs, rhs = rhs)
139
## if necessary try to expand/update/simplify formula parts with dot
141
dot <- match.arg(dot, c("separate", "sequential"))
142
ll <- formula(x, rhs = 0L, collapse = TRUE)[[2L]]
144
for(i in seq_along(rr)) {
145
if(dot == "sequential" && i > 1L) ll <- c_formula(ll, rr[[i - 1L]], sep = "+")
146
fi <- paste_formula(NULL, c_formula(rr[[i]], ll, sep = "-"))
147
attr(x, "rhs")[[i]] <- update(formula(terms(fi, ...)), . ~ .)[[3L]]
149
form <- simplify_to_formula(x, lhs = lhs, rhs = rhs)
152
## call traditional terms()
138
model.frame.Formula <- function(formula, data = NULL, ..., lhs = NULL, rhs = NULL)
156
model.frame.Formula <- function(formula, data = NULL, ..., lhs = NULL, rhs = NULL, dot = "separate")
140
model.frame(terms(formula, lhs = lhs, rhs = rhs, data = data), data = data, ...)
158
model.frame(terms(formula, lhs = lhs, rhs = rhs, data = data, dot = dot), data = data, ...)
143
model.matrix.Formula <- function(object, data = environment(object), ..., lhs = NULL, rhs = 1)
161
model.matrix.Formula <- function(object, data = environment(object), ..., lhs = NULL, rhs = 1, dot = "separate")
145
163
form <- formula(object, lhs = lhs, rhs = rhs, collapse = c(FALSE, TRUE))
146
mt <- delete.response(terms(form, data = data))
164
mt <- delete.response(terms(form, data = data, dot = dot))
147
165
model.matrix(mt, data = data, ...)
159
model.part.Formula <- function(object, data, lhs = 0, rhs = 0, drop = FALSE, terms = FALSE, ...) {
177
model.part.Formula <- function(object, data, lhs = 0, rhs = 0, drop = FALSE, terms = FALSE, dot = "separate", ...) {
161
179
## *hs = NULL: keep all parts
162
if(is.null(lhs)) lhs <- 1:length(attr(object, "lhs"))
163
if(is.null(rhs)) rhs <- 1:length(attr(object, "rhs"))
180
if(is.null(lhs)) lhs <- 1L:length(attr(object, "lhs"))
181
if(is.null(rhs)) rhs <- 1L:length(attr(object, "rhs"))
165
183
if(isTRUE(all.equal(as.numeric(lhs), rep(0, length(lhs)))) &
166
184
isTRUE(all.equal(as.numeric(rhs), rep(0, length(rhs)))))
167
185
stop("Either some 'lhs' or 'rhs' has to be selected.")
169
187
## construct auxiliary terms object
170
mt <- terms(object, lhs = lhs, rhs = rhs, data = data)
188
mt <- terms(object, lhs = lhs, rhs = rhs, dot = dot, data = data)
172
190
## subset model frame
173
ix <- attr(mt, "variables")[-1]
191
ix <- attr(mt, "variables")[-1L]
174
192
if(is.null(ix)) {
202
220
## convenience function for updating components
203
221
update_components <- function(x, y) {
210
if(length(lhs) > 0) for(i in 1:length(lhs)) {
228
if(length(lhs) > 0L) for(i in 1L:length(lhs)) {
211
229
lhs[[i]] <- if(length(o_lhs) < i) n_lhs[[i]]
212
230
else if(length(n_lhs) < i) o_lhs[[i]]
213
231
else update_components(o_lhs[[i]], n_lhs[[i]])
216
if(length(rhs) > 0) for(i in 1:length(rhs)) {
234
if(length(rhs) > 0L) for(i in 1L:length(rhs)) {
217
235
rhs[[i]] <- if(length(o_rhs) < i) n_rhs[[i]]
218
236
else if(length(n_rhs) < i) o_rhs[[i]]
219
237
else update_components(o_rhs[[i]], n_rhs[[i]])
249
267
all.equal.Formula <- function(target, current, ...) {
252
if(length(target)[1] != length(current)[1]) {
270
if(length(target)[1L] != length(current)[1L]) {
253
271
rval <- c(rval, paste("Length mismatch: target, current differ in number of LHS parts: ",
254
length(target)[1], ", ", length(current)[1], sep = ""))
272
length(target)[1L], ", ", length(current)[1L], sep = ""))
255
273
} else if(!isTRUE(all.equal(attr(target, "lhs"), attr(current, "lhs")))) {
256
274
rval <- c(rval, "Formula mismatch: LHS formulas differ in contents")
259
if(length(target)[2] != length(current)[2]) {
277
if(length(target)[2L] != length(current)[2L]) {
260
278
rval <- c(rval, paste("Length mismatch: target, current differ in number of RHS parts: ",
261
length(target)[2], ", ", length(current)[2], sep = ""))
279
length(target)[2L], ", ", length(current)[2L], sep = ""))
262
280
} else if(!isTRUE(all.equal(attr(target, "rhs"), attr(current, "rhs")))) {
263
281
rval <- c(rval, "Formula mismatch: RHS formulas differ in contents")
284
302
stopifnot(inherits(f, "formula"))
286
rhs <- if(length(f) > 2) f[[3]] else f[[2]]
287
lhs <- if(length(f) > 2) f[[2]] else NULL
304
rhs <- if(length(f) > 2) f[[3L]] else f[[2L]]
305
lhs <- if(length(f) > 2) f[[2L]] else NULL
289
307
extract_parts <- function(x, sep = "|") {
290
308
if(is.null(x)) return(NULL)
293
if(length(x) > 1 && x[[1]] == sep) {
294
while(length(x) > 1 && x[[1]] == sep) {
295
rval <- c(x[[3]], rval)
311
if(length(x) > 1L && x[[1L]] == sep) {
312
while(length(x) > 1L && x[[1L]] == sep) {
313
rval <- c(x[[3L]], rval)
299
317
return(c(x, rval))
302
320
list(lhs = extract_parts(lhs), rhs = extract_parts(rhs))
323
## combine (parts of) formulas
324
c_formula <- function(f1, f2, sep = "~") {
326
stopifnot(length(sep) == 1L, nchar(sep) == 1L,
327
sep %in% c("~", "+", "-", "|", "&"))
334
rval <- as.formula(paste(". ~ .", sep, "."))
335
rval[[3L]][[3L]] <- f2
336
rval[[3L]][[2L]] <- f1
305
343
## reassemble formulas
306
344
paste_formula <- function(lhs, rhs, lsep = "|", rsep = "|") {
308
## combine (parts of) formulas
309
c_formula <- function(f1, f2, sep = "~") {
311
stopifnot(length(sep) == 1, nchar(sep) == 1,
312
sep %in% c("~", "+", "|", "&"))
319
rval <- as.formula(paste(". ~ .", sep, "."))
328
stopifnot(all(nchar(lsep) == 1), all(lsep %in% c("+", "|", "&")))
329
stopifnot(all(nchar(rsep) == 1), all(rsep %in% c("+", "|", "&")))
331
if(length(lhs) > 1) lsep <- rep(lsep, length.out = length(lhs) - 1)
332
if(length(rhs) > 1) rsep <- rep(rsep, length.out = length(rhs) - 1)
346
stopifnot(all(nchar(lsep) == 1L), all(lsep %in% c("+", "|", "&")))
347
stopifnot(all(nchar(rsep) == 1L), all(rsep %in% c("+", "|", "&")))
349
if(length(lhs) > 1L) lsep <- rep(lsep, length.out = length(lhs) - 1L)
350
if(length(rhs) > 1L) rsep <- rep(rsep, length.out = length(rhs) - 1L)
334
352
if(is.null(lhs)) lhs <- list()
335
353
if(is.null(rhs)) rhs <- list()
337
355
if(!is.list(lhs)) lhs <- list(lhs)
338
356
if(!is.list(rhs)) rhs <- list(rhs)
340
lval <- if(length(lhs) > 0) lhs[[1]] else NULL
341
if(length(lhs) > 1) {
342
for(i in 2:length(lhs)) lval <- c_formula(lval, lhs[[i]], sep = lsep[[i-1]])
358
lval <- if(length(lhs) > 0L) lhs[[1L]] else NULL
359
if(length(lhs) > 1L) {
360
for(i in 2L:length(lhs)) lval <- c_formula(lval, lhs[[i]], sep = lsep[[i - 1L]])
344
rval <- if(length(rhs) > 0) rhs[[1]] else 0 ## FIXME: Is there something better?
345
if(length(rhs) > 1) {
346
for(i in 2:length(rhs)) rval <- c_formula(rval, rhs[[i]], sep = rsep[[i-1]])
362
rval <- if(length(rhs) > 0L) rhs[[1L]] else 0 ## FIXME: Is there something better?
363
if(length(rhs) > 1L) {
364
for(i in 2L:length(rhs)) rval <- c_formula(rval, rhs[[i]], sep = rsep[[i - 1L]])
349
367
c_formula(lval, rval, sep = "~")