38
38
# ' selected edges. If `"none"`, no edges are returned. If `"sum"`, the sum of
39
39
# ' selected edges across folds is returned. If `"all"`, the selected edges for
40
40
# ' each fold is returned, which is a 3D array and memory-consuming.
41
+ # ' @param na_action A character string indicating the action when missing values
42
+ # ' are found in `behav`. If `"fail"`, an error will be thrown. If `"omit"`,
43
+ # ' missing values will be omitted. If `"exclude"`, missing values will be
44
+ # ' excluded from the analysis and added back to the output. Note `conmat` must
45
+ # ' not contain any missing values, and `confounds` must not contain missing
46
+ # ' values for complete cases of `behav`.
41
47
# ' @return A list with the following components:
42
48
# '
43
49
# ' \item{folds}{The corresponding fold for each observation when used as test
@@ -90,11 +96,13 @@ cpm <- function(conmat, behav, ...,
90
96
thresh_level = 0.01 ,
91
97
kfolds = NULL ,
92
98
bias_correct = TRUE ,
93
- return_edges = c(" sum" , " none" , " all" )) {
99
+ return_edges = c(" sum" , " none" , " all" ),
100
+ na_action = c(" fail" , " omit" , " exclude" )) {
94
101
call <- match.call()
95
102
thresh_method <- match.arg(thresh_method )
96
103
return_edges <- match.arg(return_edges )
97
- # ensure `behav` is a vector
104
+ na_action <- match.arg(na_action )
105
+ # ensure `behav` is a vector, name and length match
98
106
behav <- drop(behav )
99
107
if (! is.vector(behav ) || ! is.numeric(behav )) {
100
108
stop(" Behavior data must be a numeric vector." )
@@ -109,38 +117,58 @@ cpm <- function(conmat, behav, ...,
109
117
stop(" Case numbers of `confounds` and `behav` must match." )
110
118
}
111
119
check_names(confounds , behav )
112
- conmat <- regress_counfounds(conmat , confounds )
113
- behav <- regress_counfounds(behav , confounds )
120
+ }
121
+ # `conmat` cannot contain any missing values
122
+ stopifnot(" Missing values are not allowed in `conmat`." = ! anyNA(conmat ))
123
+ # handle missing values in `behav`
124
+ include_cases <- switch (na_action ,
125
+ fail = {
126
+ stopifnot(" Missing values found in `behav`." = ! anyNA(behav ))
127
+ rep(TRUE , length(behav ))
128
+ },
129
+ omit = ,
130
+ exclude = ! is.na(behav )
131
+ )
132
+ conmat_use <- conmat [include_cases , , drop = FALSE ]
133
+ behav_use <- behav [include_cases ]
134
+ if (! is.null(confounds )) {
135
+ confounds_use <- confounds [include_cases , , drop = FALSE ]
136
+ stopifnot(
137
+ " Missing values found for used cases in `confounds`." =
138
+ ! anyNA(confounds_use )
139
+ )
140
+ conmat_use <- regress_counfounds(conmat_use , confounds_use )
141
+ behav_use <- regress_counfounds(behav_use , confounds_use )
114
142
}
115
143
# default to leave-one-subject-out
116
- if (is.null(kfolds )) kfolds <- length(behav )
117
- folds <- crossv_kfold(length(behav ), kfolds )
144
+ if (is.null(kfolds )) kfolds <- length(behav_use )
145
+ folds <- crossv_kfold(length(behav_use ), kfolds )
118
146
# pre-allocation
119
147
edges <- switch (return_edges ,
120
148
all = array (
121
- dim = c(dim(conmat )[2 ], length(networks ), kfolds ),
149
+ dim = c(dim(conmat_use )[2 ], length(networks ), kfolds ),
122
150
dimnames = list (NULL , networks , NULL )
123
151
),
124
152
sum = array (
125
153
0 ,
126
- dim = c(dim(conmat )[2 ], length(networks )),
154
+ dim = c(dim(conmat_use )[2 ], length(networks )),
127
155
dimnames = list (NULL , networks )
128
156
)
129
157
)
130
158
pred <- matrix (
131
- nrow = length(behav ),
159
+ nrow = length(behav_use ),
132
160
ncol = length(includes ),
133
- dimnames = list (names(behav ), includes )
161
+ dimnames = list (names(behav_use ), includes )
134
162
)
135
163
for (fold in seq_len(kfolds )) {
136
164
rows_train <- folds != fold
137
- conmat_train <- conmat [rows_train , , drop = FALSE ]
138
- behav_train <- behav [rows_train ]
165
+ conmat_train <- conmat_use [rows_train , , drop = FALSE ]
166
+ behav_train <- behav_use [rows_train ]
139
167
cur_edges <- select_edges(
140
168
conmat_train , behav_train ,
141
169
thresh_method , thresh_level
142
170
)
143
- conmat_test <- conmat [! rows_train , , drop = FALSE ]
171
+ conmat_test <- conmat_use [! rows_train , , drop = FALSE ]
144
172
cur_pred <- predict_cpm(
145
173
conmat_train , behav_train , conmat_test ,
146
174
cur_edges , bias_correct
@@ -152,10 +180,21 @@ cpm <- function(conmat, behav, ...,
152
180
edges <- edges + cur_edges
153
181
}
154
182
}
183
+ # add back missing values when `na_action` is "exclude"
184
+ if (na_action == " exclude" ) {
185
+ behav_use <- behav
186
+ pred_all <- matrix (
187
+ nrow = length(behav ),
188
+ ncol = length(includes ),
189
+ dimnames = list (names(behav ), includes )
190
+ )
191
+ pred_all [include_cases , ] <- pred
192
+ pred <- pred_all
193
+ }
155
194
structure(
156
195
list (
157
196
folds = folds ,
158
- real = behav ,
197
+ real = behav_use ,
159
198
pred = pred ,
160
199
edges = edges ,
161
200
call = call ,
0 commit comments