Skip to content

Commit 83a3642

Browse files
committed
work on test suite
1 parent 0d70bb8 commit 83a3642

File tree

7 files changed

+179
-79
lines changed

7 files changed

+179
-79
lines changed

R/branch.R

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,44 @@
4545
#' @seealso \code{\link{mergeNA}}
4646
#' @importFrom stats model.matrix
4747
#' @export
48-
branch <- function(x, f, .fill = 0){
48+
branch <- function(x, f = x, .fill = 0){
49+
if (length(.fill) > 1L) {
50+
stop("'.fill' must be a length-1 vector")
51+
}
52+
if (is.numeric(x) && (!is.numeric(.fill) & !is.na(.fill))) {
53+
warning("'.fill' must be a length-1 numeric vector; coercion attempted")
54+
.fill <- as.numeric(.fill)
55+
}
4956
if (is.list(f)) {
5057
f <- interaction(f)
51-
} else if (!is.factor(f)) {
58+
}
59+
if (!is.factor(f)) {
5260
f <- as.factor(f)
5361
}
54-
out <- x * model.matrix(~ 0 + f)
62+
if (!is.numeric(x)) {
63+
x1 <- as.factor(x)
64+
x <- as.integer(x1)
65+
out <- x * model.matrix(~ 0 + f)
66+
out[] <- c(.fill,levels(x1))[out+1L]
67+
} else {
68+
out <- x * model.matrix(~ 0 + f)
69+
}
5570
attr(out,'assign') <- NULL
5671
attr(out,'contrasts') <- NULL
57-
if (!is.na(.fill) && .fill == 0) {
58-
return(out)
59-
} else if(is.na(.fill)) {
60-
out[out == 0] <- NA
61-
return(out)
62-
} else {
63-
out[out == 0] <- .fill
64-
return(out)
72+
if (is.na(.fill)) {
73+
if (is.character(out)) {
74+
out[out == "0"] <- NA_character_
75+
} else {
76+
out[out == 0] <- NA_real_
77+
}
78+
} else if (.fill == 0) {
79+
if (is.character(out)) {
80+
out[out == "0"] <- .fill
81+
} else {
82+
out[out == 0] <- .fill
83+
}
6584
}
85+
return(out)
6686
}
6787

6888
#' @rdname branch
@@ -71,6 +91,9 @@ branch <- function(x, f, .fill = 0){
7191
#' @param \dots Two or more vectors of equal length, which are to be combined into one new vector. If any two vectors have values at the same index that are not specified in \code{.ignore}, the function will report an error. It is also possible to pass one or more data frames and/or matrices (which will be coerced to a list of column vectors).
7292
#' @export
7393
unbranch <- function(..., .ignore = 0, .fill = 0, .factors = c("character", "numeric")){
94+
if (length(.fill) > 1L) {
95+
stop("'.fill' must be a length-1 vector")
96+
}
7497
vars <- list(...)
7598
ismat <- sapply(vars, is.matrix)
7699
for (i in which(ismat)) {
@@ -96,7 +119,7 @@ unbranch <- function(..., .ignore = 0, .fill = 0, .factors = c("character", "num
96119
vars[classes] <- lapply(vars[classes], as.numeric)
97120
}
98121
}
99-
lengths <- sapply(vars, length)
122+
lengths <- lengths(vars)
100123
if (any(lengths > lengths[1] | lengths < lengths[1])) {
101124
stop("Vectors specified have different lengths")
102125
}

R/mcode.R

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
#' @seealso \code{\link{mergeNA}}
5757
#' @importFrom stats median
5858
#' @export
59-
mcode <- function(..., recodes, .fill = NA, .result = c("numeric", "character", "factor"), .factors = c("character", "numeric")){
59+
mcode <- function(..., recodes, .fill = NA, .result, .factors = c("character", "numeric")){
6060

6161
# process variables
6262
vars <- list(...)
@@ -70,6 +70,7 @@ mcode <- function(..., recodes, .fill = NA, .result = c("numeric", "character",
7070
vars[classes] <- lapply(vars[classes], as.numeric)
7171
}
7272
}
73+
7374
## check variable lengths
7475
lengths <- sapply(vars, FUN = length)
7576
if (any(lengths > lengths[1L] | lengths < lengths[1L])) {
@@ -83,7 +84,18 @@ mcode <- function(..., recodes, .fill = NA, .result = c("numeric", "character",
8384
parsed <- parse_recodes(recodes = recodes, vars = vars)
8485

8586
# create new variable to return
86-
.result <- match.arg(.result)
87+
classes <- sapply(vars, FUN = class)
88+
if (missing(.result)) {
89+
if (all(classes == "integer")) {
90+
.result <- "integer"
91+
} else if (all(classes == "numeric")) {
92+
.result <- "numeric"
93+
} else if (all(classes == "logical")) {
94+
.result <- "logical"
95+
} else {
96+
.result <- "character"
97+
}
98+
}
8799
newvar <- vector(mode = .result, length = nrow(oldvar))
88100

89101
# function to check values
@@ -148,14 +160,29 @@ parse_recodes.list <- function(recodes, vars, ...) {
148160
}
149161

150162
parse_recodes.character <- function(recodes, vars, ...) {
151-
152163
# car::recode()-style argument
153164

154-
splitrecodes <- strsplit(gsub("\n|\t", "", recodes), split = ";")[[1]]
155-
x <- t(sapply(splitrecodes, function(x) strsplit(x, split = "=")[[1]]))
156-
outval <- unname(x[,2])
157-
inval1 <- gsub("[c()]", "", unname(x[,1])) # ignore bracketing
158-
inval <- unname(sapply(inval1, strsplit, split = ","))
165+
splitrecodes <- strsplit(gsub("\n|\t", "", recodes), split = "[[:space:]]*;[[:space:]]*")[[1]]
166+
167+
cleanup_recodes <- function(x) {
168+
if (any(grepl("^c*(\\()", x))) {
169+
x <- gsub("\\)*$", "", gsub("^c*\\(*", "", x))
170+
}
171+
if (any(grepl("^['\\\"]", x))) {
172+
x <- gsub("^['\\\"]", "", x)
173+
}
174+
if (any(grepl("['\\\"]$", x))) {
175+
x <- gsub("['\\\"]$", "", x)
176+
}
177+
x
178+
}
179+
180+
x <- t(sapply(splitrecodes, function(x) strsplit(x, split = "[[:space:]]*=[[:space:]]*")[[1]]))
181+
# generate `inval`, ignoring bracketing
182+
inval <- cleanup_recodes(unname(x[,1]))
183+
inval <- unname(sapply(inval, strsplit, split = ","))
184+
# generate `outval`
185+
outval <- cleanup_recodes(unname(x[,2]))
159186

160187
# check recode lengths
161188
rlengths <- sapply(inval, length)
@@ -173,45 +200,25 @@ parse_recodes.character <- function(recodes, vars, ...) {
173200
}
174201

175202
return(list(inval = inval, outval = outval))
176-
177-
203+
}
204+
205+
parse_specials <- function(x, specials) {
206+
178207
# parse special symbols
179-
parse_specials <- function(specials, var) {
180-
## * - wildcard
181-
specials[specials == "*"] <- "*"
182-
## NA - NA value
183-
specials[specials == "NA"] <- NA
184-
## min - minimum of that variable
185-
specials[specials == "min"] <- min(var, na.rm = TRUE)
186-
## max - maximum of that variable
187-
specials[specials == "max"] <- max(var, na.rm = TRUE)
188-
## mean - mean of that variable
189-
specials[specials == "mean"] <- mean(var, na.rm = TRUE)
190-
## median - median of that variable
191-
specials[specials == "median"] <- median(var, na.rm = TRUE)
192-
## : - range of values
193-
194-
return(specials)
195-
}
208+
209+
## * - wildcard
210+
specials[specials == "*"] <- "*"
211+
## NA - NA value
212+
specials[specials == "NA"] <- NA
213+
## min - minimum of that variable
214+
specials[specials == "min"] <- min(x, na.rm = TRUE)
215+
## max - maximum of that variable
216+
specials[specials == "max"] <- max(x, na.rm = TRUE)
217+
## mean - mean of that variable
218+
specials[specials == "mean"] <- mean(x, na.rm = TRUE)
219+
## median - median of that variable
220+
specials[specials == "median"] <- median(x, na.rm = TRUE)
221+
## : - range of values
196222

197-
if (FALSE) {
198-
invalmat <- matrix(character(), nrow = length(inval), ncol = rlengths[1])
199-
for(i in 1:ncol(invalmat)) {
200-
invalmat[,i] <- parse_specials(sapply(inval, `[`, i), vars[[i]])
201-
}
202-
203-
204-
sapply(seq_along(newvar), function(x) {
205-
v <- sapply(vars, `[`, x)
206-
207-
208-
#ranged <- grepl(":", , fixed = TRUE)
209-
return(x)
210-
})
211-
212-
213-
apply(oldvar, 1, function(x) {
214-
215-
})
216-
}
223+
return(specials)
217224
}

man/branch.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/mcode.Rd

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/tests-branch.R

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,70 @@
1-
context("Test branch")
1+
context("Test branch()")
22

3-
test_that("Output as expected from branch", {
4-
set.seed(1)
3+
test_that("Output as expected from numeric branch()", {
54
a <- c(5L, 2L, 3L, 2L, 4L)
65
b1 <- c(1L, 1L, 2L, 1L, 2L)
76
b2 <- c(1L, 2L, 1L, 1L, 1L)
8-
expect_equivalent(branch(a, b1), matrix(c(5, 2, 0, 2, 0, 0, 0, 3, 0, 4), nrow = 5))
9-
expect_equivalent(branch(a, list(b1, b2)), matrix(c(5, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0), nrow = 5))
7+
expect_equivalent(branch(a), matrix(c(0,2,0,2,0, 0,0,3,0,0, 0,0,0,0,4, 5,0,0,0,0), nrow = 5))
8+
expect_equivalent(branch(a, b1), matrix(c(5,2,0,2,0, 0,0,3,0,4), nrow = 5))
9+
expect_equivalent(branch(a, list(b1, b2)), matrix(c(5,0,0,2,0, 0,0,3,0,4, 0,2,0,0,0, 0,0,0,0,0), nrow = 5))
1010
})
1111

12-
context("Test unbranch")
12+
test_that("Output as expected from character branch()", {
13+
a <- letters[1:5]
14+
b1 <- c(1L, 1L, 2L, 1L, 2L)
15+
b2 <- c(1L, 2L, 1L, 1L, 1L)
16+
expect_equivalent(branch(a), matrix(c("a",0,0,0,0, 0,"b",0,0,0, 0,0,"c",0,0, 0,0,0,"d",0, 0,0,0,0,"e"), nrow = 5))
17+
expect_equivalent(branch(a, b1), matrix(c("a","b",0,"d",0, 0,0,"c",0,"e"), nrow = 5))
18+
expect_equivalent(branch(a, list(b1, b2)), matrix(c("a",0,0,"d",0, 0,0,"c",0,"e", 0,"b",0,0,0, 0,0,0,0,0), nrow = 5))
19+
})
20+
21+
test_that("Errors as expected from branch()", {
22+
expect_error(branch(1:5, .fill = c(1,2)))
23+
expect_error(branch(1:5, .fill = "foo"))
24+
})
25+
26+
context("Test unbranch()")
1327

14-
test_that("Output as expected from unbranch", {
15-
x <- c(NA,2,3,NA,NA,6,NA,NA,NA,10)
28+
test_that("Output as expected from unbranch()", {
29+
x <- c(NA, 2, 3,NA,NA, 6,NA,NA,NA,10)
1630
y <- c(NA,NA,NA,14,NA,NA,17,18,19,NA)
1731
z <- c(NA,NA,NA,NA,25,NA,NA,NA,NA,NA)
18-
expect_equal(unbranch(x,y, .ignore = NA, .fill = NA), c(NA, 2, 3, 14, NA, 6, 17, 18, 19, 10))
32+
33+
expect_equal(unbranch(x), x)
1934
expect_equal(unbranch(x,y, .ignore = NA, .fill = NA), mergeNA(x,y))
20-
expect_equal(unbranch(x,z, .ignore = NA, .fill = NA), c(NA, 2, 3, NA, 25, 6, NA, NA, NA, 10))
21-
expect_equal(unbranch(x,z, .ignore = NA, .fill = NA), mergeNA(x,z))
35+
expect_equal(unbranch(x,y, .ignore = NA, .fill = NA), c(NA, 2, 3, 14, NA, 6, 17, 18, 19, 10))
36+
expect_equal(unbranch(x,y, .ignore = NA, .fill = 99), c(99, 2, 3, 14, 99, 6, 17, 18, 19, 10))
37+
expect_equal(unbranch(cbind(x,y), .ignore = NA, .fill = NA), c(NA, 2, 3, 14, NA, 6, 17, 18, 19, 10))
38+
expect_equal(unbranch(cbind.data.frame(x,y), .ignore = NA, .fill = NA), c(NA, 2, 3, 14, NA, 6, 17, 18, 19, 10))
39+
2240
expect_equal(unbranch(x,y,z, .ignore = NA, .fill = NA), c(NA, 2, 3, 14, 25, 6, 17, 18, 19, 10))
2341
expect_equal(unbranch(x,y,z, .ignore = NA, .fill = NA), mergeNA(x,y,z))
2442
})
2543

26-
test_that("Non-mutually exclusive ignore values errors unbranch", {
44+
test_that("Errors as expected from branch()", {
45+
expect_error(unbranch(1:5, .fill = c(99,100)))
46+
})
47+
48+
test_that("Non-mutually exclusive ignore values errors unbranch()", {
2749
x <- c(NA,1,2,NA,NA,2,NA,NA,NA,1)
2850
w <- c(NA,3,3,NA,1,NA,NA,NA,NA,NA)
2951
expect_error(unbranch(x,w, .ignore = NA))
3052
expect_equal(unbranch(x,w, .ignore = c(3,NA)), c(0, 1, 2, 0, 1, 2, 0, 0, 0, 1))
3153
})
3254

33-
test_that("Factors coerced correctly in unbranch", {
55+
test_that("Test branch(unbranch())", {
56+
a <- c(5L, 2L, 3L, 2L, 4L)
57+
expect_equivalent(unbranch(branch(a, .fill = NA), .ignore = NA, .fill = NA), a)
58+
expect_equivalent(unbranch(branch(a, .fill = 0), .ignore = 0, .fill = 0), a)
59+
})
60+
61+
test_that("Test unbranch(branch())", {
62+
x <- c(NA, 2, 3,NA,NA, 6,NA,NA,NA,10)
63+
y <- c(NA,NA,NA,14,NA,NA,17,18,19,NA)
64+
#branch(unbranch(x,y, .ignore = NA), list(is.na(x), is.na(y)), .fill = NA)
65+
})
66+
67+
test_that("Factors coerced correctly in unbranch()", {
3468
# need to write this
3569
})
3670

tests/testthat/tests-mcode.R

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,42 @@
11
context("Test mcode")
22

3-
test_that("Output as expected from mcode", {
3+
test_that("Output as expected from univariate numeric mcode()", {
4+
x <- c(1,3,5,4,2)
5+
expect_equivalent(mcode(x, recodes = "5=1;4=2;3=3;2=4;1=5"), c(5,3,1,2,4))
6+
expect_equivalent(mcode(x, recodes = "(5)=1;(4)=2;(3)=3;(2)=4;(1)=5"), c(5,3,1,2,4))
7+
expect_equivalent(mcode(x, recodes = "c(5)=1;c(4)=2;c(3)=3;c(2)=4;c(1)=5"), c(5,3,1,2,4))
8+
expect_equivalent(mcode(x, recodes = "5=1;4=2;3=3;2= 4;1=5"), c(5,3,1,2,4))
9+
expect_equivalent(mcode(x, recodes = "5=1;4=2;3=3; 2=4;1=5"), c(5,3,1,2,4))
10+
expect_equivalent(mcode(x, recodes = "5=1;4=2;3=3;2 =4;1=5"), c(5,3,1,2,4))
11+
expect_equivalent(mcode(x, recodes = "5=1;4=2;3=3;2 = 4;1=5"), c(5,3,1,2,4))
12+
})
13+
14+
test_that("Output as expected from univariate character mcode()", {
15+
x <- letters[1:5]
16+
expect_equivalent(mcode(x, recodes = "a=d;b=e;c=a;d=x;e=y"), c("d","e","a","x","y"))
17+
expect_equivalent(mcode(x, recodes = "'a'='d';'b'='e';'c'='a';'d'='x';'e'='y'"), c("d","e","a","x","y"))
18+
expect_equivalent(mcode(x, recodes = '"a"="d";"b"="e";"c"="a";"d"="x";"e"="y"'), c("d","e","a","x","y"))
19+
expect_equivalent(mcode(x, recodes = "c('a')='d';c('b')='e';c('c')='a';c('d')='x';c('e')='y'"), c("d","e","a","x","y"))
20+
21+
expect_equivalent(mcode(x, recodes = '"a" ="d";"b"="e";"c"="a";"d"="x";"e"="y"'), c("d","e","a","x","y"))
22+
expect_equivalent(mcode(x, recodes = '"a"= "d";"b"="e";"c"="a";"d"="x";"e"="y"'), c("d","e","a","x","y"))
23+
expect_equivalent(mcode(x, recodes = '"a"="d" ;"b"="e";"c"="a";"d"="x";"e"="y"'), c("d","e","a","x","y"))
24+
expect_equivalent(mcode(x, recodes = '"a"="d"; "b"="e";"c"="a";"d"="x";"e"="y"'), c("d","e","a","x","y"))
25+
expect_equivalent(mcode(x, recodes = '"a"=" d";"b"="e";"c"="a";"d"="x";"e"="y"'), c(" d","e","a","x","y"))
26+
})
27+
28+
test_that("Output as expected from multivariate numeric mcode()", {
29+
x <- c(1,3,5,4,2)
30+
y <- c(1,1,1,0,0)
31+
R <- "(5,0)=1;(4,0)=2;(3,0)=3;(2,0)=4;(1,0)=5;(5,1)=95;(4,1)=96;(3,1)=97;(2,1)=98;(1,1)=99"
32+
expect_equivalent(mcode(x, y, recodes = R), c(99,97,95,2,4))
33+
})
34+
35+
test_that("Output as expected from multivariate character mcode()", {
36+
37+
})
38+
39+
test_that("Output as expected from mixed multivariate mcode()", {
440

541
})
642

tests/testthat/tests-mergeNA.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
context("Test mergeNA")
22

3-
test_that("Output as expected from mergeNA", {
3+
test_that("Output as expected from mergeNA()", {
44
x <- c(NA,2,3,NA,NA,6,NA,NA,NA,10)
55
y <- c(NA,NA,NA,14,NA,NA,17,18,19,NA)
66
z <- c(NA,NA,NA,NA,25,NA,NA,NA,NA,NA)
@@ -9,13 +9,13 @@ test_that("Output as expected from mergeNA", {
99
expect_equal(mergeNA(x,y,z), c(NA, 2, 3, 14, 25, 6, 17, 18, 19, 10))
1010
})
1111

12-
test_that("Non-mutually exclusive missingness errors mergeNA", {
12+
test_that("Non-mutually exclusive missingness errors mergeNA()", {
1313
x <- c(NA,2,3,NA,NA,6,NA,NA,NA,10)
1414
w <- c(NA,42,43,NA,25,NA,NA,NA,NA,NA)
1515
expect_error(mergeNA(x,w))
1616
})
1717

18-
test_that("Factors coerced correctly in mergeNA", {
18+
test_that("Factors coerced correctly in mergeNA()", {
1919
expect_equal(mergeNA(c(1,NA,NA,NA), factor(c(NA,'a','b',NA))), c("1", "a", "b", NA))
2020
expect_equal(mergeNA(c(1,NA,NA,NA), factor(c(NA,'a','b',NA)), .factors = "character"), c("1", "a", "b", NA))
2121
expect_equal(mergeNA(c(1,NA,NA,NA), factor(c(NA,'a','b',NA)), .factors = "numeric"), c(1, 1, 2, NA))

0 commit comments

Comments
 (0)