Сопоставление функции каждому участнику исследования

Я пытался применить функцию к этому набору данных, который состоит из данных из отдельных исследований, разработанных AB. Он состоит из 6 переменных: a. Уровень (количество циклов AB в этом конкретном наборе данных всегда равно 1, поскольку все исследования разработаны AB); б. ID (идентификационный код участника), c. Шкала (тип шкалы, по которой оценивается участник), d. Время (случай рейтинга), т.е. Фаза (A = исходный уровень, B = вмешательство), f. Score (счет участника).

library(purrr)
library(dplyr)

Tier <- rep(c(1), 36)
ID <- c("C1", "C1", "C1", "C1", "C1", "C1", "C1", "C1", "C1", "C1", "C1", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C1", "C1", "C1", "C1", "C1", "C1", "C1", "C1", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2")
Scale <- rep(c(1, 2), each = 18)
Time <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Phase <- c("A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "A", "A", "A", "A", "B", "B", "B", "B", "A", "A", "A", "A", "B", "B", "B", "B", "A", "A", "A", "A", "B", "B", "B", "B", "B")
Score <- c(4, 8, 10, 12, 15, 7, 7, 9, 14, 15, 16, 4, 3, 2, 2, 7, 7, 9, 14, 2, 3, 6, 6, 7, 5, 9, 11, 5, 6, 3, 4, 8, 7, 9, 3, 3)
db <- data.frame(Scale, ID, Time, Phase, Score, Tier)

Это две функции, разработанные Manolov and Rochat (2015). Они отлично работают до тех пор, пока не дойдет до расчета более одного участника за один раз. Поэтому я попытался изменить некоторые детали второго (MPD_meta), чтобы сделать это.

MPD <- function(a, b) { #Manolov & Rochat, 2015

# Obtain phase length
n_a <- length(a[!is.na(a)])
n_b <- length(b[!is.na(b)])
meanA <- mean(a[!is.na(a)]) 

# Estimate baseline trend
base_diff <- rep(0,(n_a - 1))

for (i in 1:(n_a - 1)) base_diff[i] <- a[!is.na(a)][i + 1] - a[!is.na(a)][i]

trendA <- mean(base_diff)

# Predict baseline data
baseline_pred <- rep(0, n_a)

midX <- median(c(1:n_a))
midY <- median(a[!is.na(a)])

is.wholenumber <- function(x, tol = .Machine$double.eps ^ 0.5)  abs(x - round(x)) < tol

if (is.wholenumber(midX)) {
baseline_pred[midX] <- midY
for (i in (midX - 1): 1) baseline_pred[i] <- baseline_pred[i + 1] - trendA
for (i in (midX + 1): n_a) baseline_pred[i] <- baseline_pred[i - 1] + trendA
}

#baseline_pred

if (!is.wholenumber(midX)) {
baseline_pred[midX - 0.5] <- midY - (0.5 * trendA)
baseline_pred[midX + 0.5] <- midY + (0.5 * trendA)
for (i in (midX - 1.5) : 1) baseline_pred[i] <- baseline_pred[i + 1] - trendA
for (i in (midX + 1.5) : n_a) baseline_pred[i] <- baseline_pred[i - 1] + trendA
}


# Project baseline trend to the treatment phase
treatment_pred <- rep(0, n_b)
treatment_pred[1] <- baseline_pred[n_a] + trendA

for (i in 2:n_b) 
    treatment_pred[i] <- treatment_pred[i - 1] + trendA

diff_absolute <- rep(0, n_b)
diff_relative <- rep(0, n_b)

for (i in 1:n_b) {
diff_absolute[i] <- b[!is.na(b)][i] - treatment_pred[i]

if (treatment_pred[i]!=0) diff_relative[i] <- ((b[!is.na(b)][i] - treatment_pred[i]) / abs(treatment_pred[i])) * 100
    }

mpd_value <- mean(diff_absolute)
mpd_relative <- mean(diff_relative)
mpd_relsd <- mpd_value/sd(a[!is.na(a)])

# Compute the residual (MSE): difference between actual and predicted baseline data
residual <- 0

for (i in 1:n_a)

  residual <- residual + (a[!is.na(a)][i] - baseline_pred[i]) * (a[!is.na(a)][i] - baseline_pred[i])
  residual_mse <- residual/n_a

list(MPD_raw = mpd_value, Residual_MSE = residual_mse, MPD_sd = mpd_relsd) #, MPD_percent = mpd_relative, Baseline_pred = baseline_pred

}

MPD_meta <- function(DBR, n) {

MBD <- db %>%
  dplyr::filter(Scale == DBR, ID == n)

# Create the objects necessary for the calculations and the graphs
# Dimensions of the data set
tiers <- max(MBD$Tier)
max.length <- max(MBD$Time)
max.score <- max(MBD$Score)
min.score <- min(MBD$Score)

# Vectors for keeping the main results
# Series lengths per tier
obs <- rep(0,tiers)
# Raw MPD effect sizes per tier
results <- rep(0,tiers)
# Weights per tier
tier.weights <- rep(0,tiers)
# Standardized MPD results per tier
stdresults <- rep(0,tiers)

# Obtain the values calling the MPD function
for (i in 1:tiers) {

  tempo <- subset(MBD, Tier == i)
  # Number of observations for the tier
  obs[i] <- max(tempo$Time)

  # Data corresponding to phase A
  Atemp <- subset(tempo, Phase == "A")
  Aphase <- Atemp$Score
  # Data corresponding to phase B
  Btemp <- subset(tempo, Phase == "B")
  Bphase <- Btemp$Score

  # Obtain the MPD
  results[i] <- MPD(Aphase, Bphase)[[1]]
  # Obtain the weight for the MPD
  tier.weights[i] <-  obs[i]
  # Obtain the standardized-version of the MPD
  stdresults[i] <- MPD(Aphase, Bphase)[[2]]
}  

# Obtain the weighted average: single effect size per study
one_ES_num <- 0

for (i in 1:tiers)
  one_ES_num <- one_ES_num + results[i]*tier.weights[i]
one_ES_den <- sum(tier.weights)
one_ES <- one_ES_num / one_ES_den

# Obtain the weight of the single effect size - it's a weight for the meta-analysis
# Weight 1: series length
weight <- sum(obs)
variation <- 0
if (tiers == 1) weight2 = 1
if (tiers != 1) {
  for (i in 1:tiers)
    variation <- variation + (stdresults[i]-one_stdES)*(stdresults[i]-one_stdES)
  # Weight two: variability of the outcomes
  coefvar <- (sqrt(variation/tiers))/abs(one_stdES)
  weight2 <- 1/coefvar
}
# Weight
weight_std <- weight + weight2

# Obtain the standardized-version of the MPD values for each tier

# Obtain the standardized-version of the weighted average
one_stdES_num <- 0
one_stdES_den <- 0
for (i in 1:tiers)

  if (abs(stdresults[i])!=Inf) 
  { 
     one_stdES_num <-  one_stdES_num + stdresults[i]*tier.weights[i]
     one_stdES_den <- one_stdES_den + tier.weights[i] 
  }

one_stdES <- one_stdES_num / one_stdES_den

data.frame(Id = n, ES = one_ES, stdES = one_stdES, weight = weight_std)

}

Как видите, когда я применяю функцию к одному участнику, она работает без проблем. MPD_meta требует два аргумента, т. е. номер весов и идентификатор участника. При применении дает нужный мне результат.

MPD_meta(1, "C1")
#  Id        ES stdES weight
#1 C1 -13.79167 0.325      7 

Однако, когда я попытался сопоставить эту функцию каждому участнику для одной конкретной шкалы, я не получил желаемого результата. Это дает мне одну и ту же строку, повторяющуюся n раз для каждого участника. Обратите внимание, что результаты по-прежнему верны. Очевидно, я мог бы сказать %>% unique(), и он выбрал бы только один, но это занимает много времени, когда я работаю с большим набором данных.

map2_df(.x = db$Scale, .y = db$ID, ~ MPD_meta(.x, .y))
#   Id         ES     stdES weight
#1  C1 -13.791667 0.3250000      7
#2  C1 -13.791667 0.3250000      7
#3  C1 -13.791667 0.3250000      7
#4  C1 -13.791667 0.3250000      7
#5  C1 -13.791667 0.3250000      7
#6  C1 -13.791667 0.3250000      7
#7  C1 -13.791667 0.3250000      7

person Michael Matta    schedule 23.08.2018    source источник
comment
Каковы входные аргументы для MPD с точки зрения вашего фрейма данных?   -  person Anonymous coward    schedule 23.08.2018
comment
Баллы, связанные с двумя фазами; a = данные, соответствующие фазе A (базовый уровень) и b = данные, соответствующие фазе B (вмешательство)   -  person Michael Matta    schedule 23.08.2018
comment
При копировании кода и запуске map2_df(.x = db$Scale, .y = db$ID, ~ MPD_meta(.x, .y)) я получаю другое значение для weight (12 вместо 7), есть идеи, почему?   -  person Aurèle    schedule 24.08.2018


Ответы (1)


Мы могли бы сделать:

distinct(db, Scale, ID) %>%
  {map2_dfr(.x = .$Scale, .y = .$ID, MPD_meta)}

#   Id         ES     stdES weight
# 1 C1 -13.791667 0.3250000     12
# 2 C2   7.500000 0.1388889      8
# 3 C2   4.500000 0.8888889     10
# 4 C1  -1.833333 0.4722222      9

По сути, это просто выполнение unique() (или distinct()) до вычисления, а не после.

person Aurèle    schedule 24.08.2018