File: Diff.R

package info (click to toggle)
r-cran-bradleyterry2 1.1-2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 1,208 kB
  • sloc: sh: 13; makefile: 5
file content (138 lines) | stat: -rwxr-xr-x 6,092 bytes parent folder | download
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
#' @importFrom stats is.empty.model model.frame model.matrix model.offset na.omit na.pass reformulate relevel terms
Diff <- function(player1, player2, formula = NULL, id = "..", data = NULL,
                 separate.ability = NULL, refcat = NULL, contrasts = NULL,
                 subset = NULL) {
    player.one <- player1[[id]]
    player.two <- player2[[id]]

    if (!is.factor(player.one) || !is.factor(player.two) ||
        !identical(levels(player.one), levels(player.two)))
        stop("'player1$", id, "' and 'player2$", id,
             "' must be factors with the same levels")
    if (!identical(attr(player.one, "contrasts"),
                   attr(player.two, "contrasts")))
        stop("'player1$", id, "' and 'player2$", id,
             "' must have the same contrasts attribute")
    if(is.null(formula)) formula <- reformulate(id)

    players <- levels(player.one)
    nplayers <- nlevels(player.one)
    ncontests <- length(player.one)
    D <- matrix(nrow = ncontests, ncol = nplayers)
    D <- col(D) == as.numeric(player.one)
    D <- D - (col(D) == as.numeric(player.two))
    colnames(D) <- paste(id, players, sep = "")

    fixed <- nobars(formula)
    X <- offset <- missing <- term.labels <- NULL
    saturated <- FALSE
    sep <- list()
    empty <- is.null(fixed) || is.empty.model(mt <- terms(fixed))
    if (!empty) {
        factors <- attr(mt, "factors")
        term.labels <- as.character(colnames(factors))
        vars <- rownames(factors)
        indexed <- grep("[[][^],]+[],]", vars)
        if (length(indexed)) { #set NAs to zero
            indices <- gsub("[^[]*[[]([^],]+)[],].*", "\\1", vars[indexed])
            vars <-  gsub("[[][^]]*[]]", "", vars[indexed])
            ## assumes no overlap, e.g. no age[..]:judge.gender[judge]
            grp <- split(vars, indices)
            for (ind in names(grp)) {
                vars <- model.frame(terms(reformulate(grp[[ind]])),
                                    data = data, na.action = na.pass)
                lev <- levels(eval(as.name(ind), c(player1, data)))
                as.sep <- rowSums(is.na(vars)) | lev %in% separate.ability
                if (any(as.sep)) {
                    sep[[ind]] <- as.sep
                    vars[sep[[ind]], ] <- lapply(vars, function(x)
                                                 max(levels(x)[1], 0))
                    colnames(vars) <- gsub(".*[$[],? ?\"?([^]\"]*).*", "\\1",
                                           grp[[ind]])
                    labels <- gsub("([^[$]*)[[$].*", "\\1", grp[[ind]])
                    for (lab in intersect(labels, grp[[ind]]))
                        data[lab] <- vars[lab]
                    for (lab in setdiff(labels, grp[[ind]]))
                        data[[lab]] <- vars[, labels == lab, drop = FALSE]
                }
            }
            if (length(sep)) {
                fixed <- reformulate(c(names(sep), attr(mt, "term.labels"),
                                       rownames(attr(mt, "factors"))[
                                           attr(mt, "offset")]))
                mt <- terms(fixed)
            }
        }

        idterm <- id %in% rownames(attr(mt, "factors"))
        mf1 <- model.frame(mt, data = c(player1, data), na.action = na.pass)
        if (nrow(mf1) != ncontests)
            stop("Predictor variables are not of the correct length --",
                 "they probably need indexing in 'formula'.")
        mf2 <- model.frame(mt, data = c(player2, data), na.action = na.pass)
        if (idterm){
            if (!is.null(refcat)) {
                mf1[[id]] <- relevel(mf1[[id]], refcat)
                mf2[[id]] <- relevel(mf2[[id]], refcat)
                if (!is.null(contrasts)) contrasts[[id]] <- "contr.treatment"
            } else {
                ## 'else' defined by contrasts arg/contrasts attr of id factor
                ## leave refcat NULL
                if (is.null(contrasts) & 
                    !is.null(attr(player.one, "contrasts"))){
                    contrasts <- list()
                    contrasts[[id]] <- attr(player.one, "contrasts")
                }
            }
        }
        offset <- model.offset(mf1)
        if (!is.null(offset)) offset <- offset - model.offset(mf2)

        if (length(sep)){ #create separate effect factor
            recode <- function(x, keep){
                lev <- levels(x)
                ext <- make.unique(c(lev[keep], "nosep"))[sum(keep) + 1]
                levels(x)[!keep]  <- ext
                relevel(x, ref = ext)
            }
            for (ind in names(grp)) {
                mf1[ind] <- recode(mf1[[ind]], sep[[ind]])
                mf2[ind] <- recode(mf2[[ind]], sep[[ind]])
            }
        }

        X1 <- model.matrix(fixed, mf1, contrasts = contrasts)
        X2 <- model.matrix(fixed, mf2, contrasts = contrasts)
        X <- X1 - X2
        ## will need to check for saturation in each set of indexed var
        ## - however as only allowing (1|..) just consider player id for now

        saturated <- 
            qr(na.omit(X))$rank == qr(na.omit(cbind(D, X)))$rank && !idterm
        if (all(X[,1] == 0)) X <- X[, -1, drop = FALSE]
        attr(X, "assign") <- attr(X1, "assign")[-1]
    }

    random <- findbars(formula[[2]])
    if (!is.null(random)) {
        if (!is.list(random)) random <- list(random)
        if (length(random) > 1 ||
            random[[1]] != parse(text = paste("1|", id, sep = ""))[[1]])
            stop("Currently '(1 | ", id, ")' is the only random effects",
                 "structure allowed.")
        random <- D
    }
    else if (!empty && (!idterm & !saturated))
        warning("Ability modelled by predictors but no random effects",
                call. = FALSE)

    if (length(sep)) {
        attr(X, "assign") <- attr(X, "assign") - 1
        if (!is.null(random))
            random <- D[,!sep[[id]], drop = FALSE]
    }
    list(X = X, random = random, offset = offset,
         term.labels = term.labels, refcat = refcat, contrasts = contrasts,
         saturated = saturated)
}