Skip to content

Commit 7a8d758

Browse files
authored
Merge pull request #2 from michaelzehetleitner/fix/fitMetaDprime-wrapper
Fix fitMetaDprime dispatcher for non-numeric participant IDs
2 parents e6b931b + 501e0a2 commit 7a8d758

File tree

2 files changed

+39
-11
lines changed

2 files changed

+39
-11
lines changed

R/fitMetaDprime.R

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ fitMetaDprime <- function(data, model="ML", nInits = 5, nRestart = 3,
121121
## ToDo: Namen anpassen
122122
outnames <- c("model", "participant", "dprime", "c", "metaD", "Ratio")
123123
# This function will be called for every combination of participant and model
124-
call_fitfct <- function(X) {
125-
cur_model <- model[X[1]]
126-
cur_sbj <- X[2]
124+
call_fitfct <- function(model_idx, participant_id) {
125+
cur_model <- model[as.integer(model_idx)]
126+
if (is.na(cur_model)) stop("Internal error: model index could not be resolved.")
127+
cur_sbj <- participant_id
127128
participant <- NULL # to omit a note in R checks because of an unbound variable
128129
data_part <- subset(data, participant==cur_sbj)
129130
res <- int_fitMetaDprime(ratings=data_part$rating,
@@ -140,13 +141,11 @@ fitMetaDprime <- function(data, model="ML", nInits = 5, nRestart = 3,
140141

141142
# generate a list of fitting jobs to do and setup parallelization
142143
subjects <- unique(data$participant)
143-
nJobs <- length(model)*length(subjects)
144-
jobs <- expand.grid(model=1:length(model), sbj=subjects)
144+
if (is.factor(subjects)) subjects <- as.character(subjects)
145+
jobs <- expand.grid(model = seq_along(model), sbj = subjects, stringsAsFactors = FALSE)
146+
nJobs <- nrow(jobs)
145147
if (.parallel) {
146-
listjobs <- list()
147-
for (i in 1:nrow(jobs)) {
148-
listjobs[[i]] <- c(model = jobs[["model"]][i], sbj = jobs[["sbj"]][i])
149-
}
148+
listjobs <- split(jobs, seq_len(nJobs))
150149
if (is.null(n.cores)) n.cores <- min(nJobs, detectCores() - 1)
151150

152151
cl <- makeCluster(type="SOCK", n.cores)
@@ -155,10 +154,12 @@ fitMetaDprime <- function(data, model="ML", nInits = 5, nRestart = 3,
155154
# Following line ensures that the cluster is stopped even in cases of user
156155
# interrupt or errors
157156
on.exit(try(stopCluster(cl), silent = TRUE))
158-
res <- clusterApplyLB(cl, listjobs, fun=call_fitfct)
157+
res <- clusterApplyLB(cl, listjobs,
158+
fun=function(job) call_fitfct(job[["model"]], job[["sbj"]]))
159159
stopCluster(cl)
160160
} else {
161-
res <- apply(X=jobs, 1, FUN=call_fitfct)
161+
res <- lapply(seq_len(nJobs),
162+
function(i) call_fitfct(jobs$model[i], jobs$sbj[i]))
162163
}
163164
# bind list-outout together into data.frame
164165
res <- do.call(rbind, res)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
test_that("fitMetaDprime handles non-numeric participant IDs", {
2+
dummy_data <- data.frame(
3+
rating = factor(c("low", "high", "low", "high")),
4+
stimulus = factor(c("S1", "S1", "S2", "S2")),
5+
correct = c(1, 0, 1, 0),
6+
participant = factor(c("p1", "p1", "p2", "p2"))
7+
)
8+
9+
mocked_int_fit <- function(...) {
10+
data.frame(
11+
dprime = 1,
12+
c = 0,
13+
metaD = 1,
14+
Ratio = 1
15+
)
16+
}
17+
18+
res <- with_mocked_bindings(
19+
fitMetaDprime(dummy_data, model = "ML", nInits = 1, nRestart = 1, .parallel = FALSE),
20+
int_fitMetaDprime = mocked_int_fit
21+
)
22+
23+
expect_s3_class(res, "data.frame")
24+
expect_equal(unique(res$model), "ML")
25+
expect_equal(nrow(res), 2L)
26+
expect_equal(sort(unique(res$participant)), c("p1", "p2"))
27+
})

0 commit comments

Comments
 (0)