r语言 - 使用 apply() 及其相关替换循环以应用异常值测试(例如)



我有一个行为任务的数据,看起来像这样(假设数据框名为 data):

data <- data.frame(subject = c(rep(8666, 6), rep(5452, 6)), RT = c(714, 877, 665, 854, 1092, 1960, 770, 4551, 1483, 1061, 755, 1090))
data
subject  RT
8666      714
8666      877
8666      665
8666      854
8666     1092
8666     1960
5452      770
5452     4551
5452     1483
5452     1061
5452      755
5452     1090

也就是说,对于这个问题,我正在研究一系列主题和反应时间。(总共有183名受试者,每人156次试验。使用 reshape 的 cast() 函数,我为每个主题计算了一个值,我想用它来排除某些试验。

outl <- function(x) {
    2.5 * mad(x) + median(x)
    }
melteddata <- melt(data, id.vars="subject", measure.vars = "RT")
outliers <- cast(melteddata, subject ~ ., outl)
colnames(outliers)[2] <- "outlier"

这将输出如下内容:

  subject    outlier
1    5452   2235.635
2    8666   1517.844
...

现在,我通常这样做的方法是编写一个循环,对于每个唯一的主题编号,将其RT与该主题的异常值进行比较:

data$outliers <- 0
for(subject in unique(data$subject)) {
    temp <- data[data$subject == subject,]
    temp$outliers <- ifelse(temp$RT > outliers[outliers$subject == subject,]$outlier, 0, 1)
    data[data$subject == subject,]$outliers <- temp$outliers
    }

。这标志着受试者 8666 的 1960 年 RT 和 5452 的 4551 年作为异常值。

但是,我觉得必须有一种更R的方式来做到这一点。感觉 apply() 应该能够做同样的事情,当然这需要很长时间才能作为循环运行。有什么建议吗?

编辑:我意识到我可以使用library(plyr)包中的ddply()来做到这一点,而不是使用melt()和cast():

library(plyr)
outliers <- ddply(data, .(subject), summarize, median = median(RT), mad = mad(RT), outlier = median(RT) + 2.5 * mad(RT))

这是一个尝试。将异常值数据框转换为命名向量:

out <- outliers$outlier
names(out) <- outliers$subject

然后将其用作查找表,以选择RT列小于主题异常值的所有数据行:

data[data$RT < out[as.character(data$subject)], ]

as.character是必需的,因为主题 ID 是整数,并且您不想获得例如 out 的第 8666 个元素。

编辑以添加dplyr解决方案:

group_by(data, subject) %>% summarize(outlier = 2.5 * mad(RT) + median(RT)) -> outliers
merge(data, outliers)
filter(data, RT < outlier)

最新更新