File: grid.func.R

package info (click to toggle)
r-cran-plotmo 3.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,400 kB
  • sloc: sh: 13; makefile: 2
file content (192 lines) | stat: -rw-r--r-- 8,644 bytes parent folder | download | duplicates (3)
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
# grid.func:  apply grid.levels or grid.func to x (a column from the input x mat)
#             to get a scalar value for the given background variable

get.fixed.gridval <- function(x, pred.name, grid.func, grid.levels)
{
    gridval.method <- "grid.levels" # used only in warning messages
    gridval <- get.fixed.gridval.from.grid.levels.arg(x, pred.name, grid.levels)
    if(is.na(gridval)) { # pred.name is not in grid.levels?
        gridval.method <- "grid.func"
        if(is.null(grid.func)) {
            grid.func <- default.grid.func
            gridval.method <- "default.grid.func"
        }
        check.grid.func(grid.func)
        if(length(x) == 0) # paranoia
            stop0("length(", pred.name, ") is zero")
        x <- x[!is.na(x)]
        if(length(x) == 0) # paranoia
            stop0("all values of ", pred.name, " are NA")
        gridval <- try(grid.func(x, na.rm=TRUE), silent=TRUE)
    }
    check.fixed.gridval(gridval, gridval.method, x, pred.name) # returns gridval
}
default.grid.func <- function(x, ...)
{
    if(inherits(x, "integer"))      # return median rounded to integer
        return(as.integer(round(median(x))))
    if(inherits(x, "logical"))      # return most common value
        return(median(x) > .5)
    if(inherits(x, "factor")) {     # return most common value
        lev.names <- levels(x)
        ilev <- which.max(table(x))
        if(is.ordered(x))
            return(ordered(lev.names, levels=lev.names)[ilev])
        return(factor(lev.names, levels=lev.names)[ilev])
    }
    median(x)                       # default to median
}
# Check grid.levels arg passed in by the user.  This checks that the names
# of the list elements are indeed predictor names.  The actual levels will
# be checked later in get.fixed.gridval.from.grid.levels.arg.

check.grid.levels.arg <- function(x, grid.levels, pred.names)
{
    if(!is.null(grid.levels)) { # null is the default value
        if(!is.list(grid.levels))
            stop0("grid.levels must be a list.  ",
                  "Example: grid.levels=list(sex=\"male\")")
        for(name in names(grid.levels)) {
            if(nchar(name) == 0)
                stop0(
"All elements of grid.levels must be named\n       You have grid.levels=",
                      as.char(grid.levels))
            if(!pmatch(name, pred.names, 0))
                stop0("illegal variable name '", name, "' in grid.levels")
        }
    }
}
# this returns NA if pred.name is not in grid.levels

get.fixed.gridval.from.grid.levels.arg <-function(x, pred.name, grid.levels)
{
    if(is.null(grid.levels))
        return(NA)
    gridval <- NA
    names.grid.levels <- names(grid.levels)
    # look for pred.name in the grid.levels list, if found use its value
    iname <- which(pmatch(names.grid.levels, pred.name, duplicates.ok=TRUE) == 1)
    if(length(iname) == 0) # no match?
        return(NA)
    if(length(iname) > 1) # more than one match?
        stop0("illegal grid.levels argument (\"",
              names.grid.levels[iname[1]], "\" and \"",
              names.grid.levels[iname[2]], "\" both match \"",
              pred.name, "\")")
    # a name in grid.levels matches pred.name
    stopifnot(length(iname) == 1)
    gridval <- grid.levels[[iname]]
    if(length(gridval) > 1)
        stop0("length(", pred.name, ") in grid.levels is not 1")
    if(is.na(gridval))
        stop0(pred.name, " in grid.levels is NA")
    if(is.numeric(gridval) && !all(is.finite(gridval)))
        stop0(pred.name, " in grid.levels is infinite")
    if(is.factor(x)) {
        lev.name <- grid.levels[[iname]]
        if(!is.character(lev.name) || length(lev.name) != 1 || !nzchar(lev.name))
            stop0("illegal level for \"", pred.name, "\" in grid.levels ",
                  "(specify factor levels with a string)")
        lev.names <- levels(x)
        ilev <- pmatch(lev.name, lev.names, 0)
        if(ilev == 0)
            stop0("illegal level \"", lev.name, "\" for \"",
                  pred.name, "\" in grid.levels (allowed levels are ",
                  quotify(lev.names), ")")
        gridval <- if(is.ordered(x))
                        ordered(lev.names, levels=lev.names)[ilev]
                   else
                        factor(lev.names, levels=lev.names)[ilev]
    }
    # do type conversions for some common types
    # (e.g. allow 3 instead of 3L for integer variables)
    class.gridval <- class(gridval)[1]
    class.x <- class(x)[1]
    if(class.gridval != class.x) {
        if(class.gridval == "numeric" && class.x == "integer")
            gridval <- as.integer(round(gridval))
        else if(class.gridval == "integer" && class.x == "numeric")
            gridval <- as.numeric(gridval)
        else if(class.x == "logical") {
            if(!is.logical(gridval) && !is.numeric(gridval))
                stop0("expected a logical value in grid.levels for ", pred.name)
            gridval <- gridval > .5
        }
    }
    return(gridval)
}
check.grid.func <- function(grid.func)
{
    if(!is.function(grid.func))
        stop0("'grid.func' is not a function");
    formals <- names(formals(grid.func))
    # check grid.func signature, we allow argname "na.rm" for mean and median
    if(length(formals) < 2 || formals[1] != "x" ||
            (!any(formals == "na.rm") && formals[2] != "..."))
        stop0("The formal arguments of 'grid.func' should be 'x' and '...'\n",
              "       Your 'grid.func' has ",
              if(length(formals) == 0)      "no formal arguments"
              else if(length(formals) == 1) "a single formal argument "
              else                          "formal arguments ",
              if(length(formals) > 0) paste0("'", formals, "'", collapse=" ")
              else "")
}
check.fixed.gridval <- function(gridval, gridval.method, x, pred.name)
{
    if(is.try.err(gridval)) {
        if(inherits(x, "logical") || inherits(x, "factor"))
            warning0(gridval.method, " failed for ", pred.name,
                     ", so will use the most common value of ", pred.name)
        else
            warning0(gridval.method, " failed for ", pred.name,
                     ", so will use the default grid.func for ", pred.name)
       gridval <- default.grid.func(x)
    }
    if(length(gridval) != 1) {
        warning0(gridval.method, " returned multiple values for ", pred.name,
                 ", so will use the default grid.func for ", pred.name)
        gridval <- default.grid.func(x) # revert to default.grid.func
    }
    if(is.na(gridval)) {
        warning0(gridval.method, " returned NA for ", pred.name,
                 ", so will use the default grid.func for ", pred.name)
        gridval <- default.grid.func(x) # revert to default.grid.func
    }
    # possibly type convert gridval
    class.gridval <- class(gridval)[1]
    if(class.gridval != class(x)[1]) {
        if(inherits(x, "integer"))        # silently fix so e.g. grid.func=mean works
            gridval <- as.integer(round(median(gridval)))
        else if(inherits(x, "logical")) { # silently fix if possible
            if(!is.logical(gridval) && !is.numeric(gridval))
                stop0("expected a logical value in grid.levels for ", pred.name)
            gridval <- gridval > .5
        }
        else if(inherits(x, "factor")) {
            warning0(gridval.method, " returned class \"", class.gridval,
                     "\" for ", pred.name,
                     ", so will use the most common value of ", pred.name)
            gridval <- default.grid.func(x)
        } else {
            warning0(gridval.method, " returned class \"", class.gridval,
                     "\" for ", pred.name,
                     ", so will use the default grid.func for ", pred.name)
            gridval <- default.grid.func(x)
        }
    }
    gridval
}
# this retunrs NA if pred.name is not in grid.levels

get.fixed.gridval.for.partdep <- function(x, ipred, pred.name, grid.levels)
{
    gridval <- get.fixed.gridval.from.grid.levels.arg(x, pred.name, grid.levels)
    # common type conversions were already done in get.fixed.gridval.from.grid.levels.arg
    # check here if that wasn't possible
    if(!is.na(gridval)[1] && class(gridval)[1] != class(x)[1])
        stop0("the class \"", class(gridval)[1], "\" of \"", pred.name,
              "\" in grid.levels does not match its class \"",
              class(x)[1],
              "\" in the input data")
    gridval
}