[英]replace loops with apply family functions (or dplyr), using logical functions in R
[英]How to replace mutiple nested for loops with apply family functions in R?
我的数据集 (dat) 中有四个主要变量。
对于变量 1、2 和 3 的每个组合,我想更改反应时间,以便将高于第三四分位数 + 1.5IQR 的所有值设置为第三四分位数 + 1.5 IQR 的值。
TUK <- function (a,b,c) {
....
}
基本上,for循环逻辑是:
for (i in dat$SubjectID):
for (j in dat$Group):
for (k in dat$Object) :
TUK(i,j,k)
如何使用 apply 函数系列来做到这一点?
谢谢!
添加可重现的示例:
SubjectID <- c(3772113,3772468)
Group <- c("Easy","Hard")
Object <- c("A","B")
dat <- data.frame(expand.grid(SubjectID,Group,Object))
dat$RT <- rnorm(8,1500,700)
colnames(dat) <- c("SubjectID","Group","Object","RT")
TUK <- function (SUBJ,GROUP,OBJECT){
p <- dat[dat$SubjectID==SUBJ & dat$Group== GROUP & dat$Object==OBJECT, "RT"]
p[p$RT< 1000 | p$RT> 2000,] <- NA
dat[dat$SubjectID==SUBJ & dat$Group== GROUP & dat$Object==OBJECT, "RT"]<<- p
}
您的问题的很大一部分是您的TUK
功能很糟糕。 以下是一些原因
问题:这取决于在全局环境中有一个名为dat
的数据框。 更改数据的名称,它会中断。
dat
应该是一个参数。 问题:应该避免全局赋值<<-
。 在某些高级情况下它是必要的(例如,有时在 Shiny 应用程序中),但通常它会使函数以非常非 R 的方式运行。
return()
一个值并像任何其他普通 R 函数一样分配它。 问题:它过于复杂。 您通过传入 SUBJ、GROUP 和 OBJECT,但仅使用它们来子集您尝试在函数内部执行的dplyr
或data.table
或base::ave
擅长的“分组”位。 就好像您试图以某种方式构建您的函数,以便 if 只能用于嵌入这个特定的for
循环中。
dplyr
或data.table
或ave
(甚至是for
循环)对其进行拆分-应用-组合。 这也使您的功能更普遍有用,而不是固定在这种特殊情况下。考虑到上述情况,这里尝试重写:
TUK2 <- function (RT){
RT[RT < 1000 | RT > 2000] <- NA
return(RT)
}
看看有多简单! 现在,如果我们想将此函数应用于数据中的每个 GROUP:SUBJ:OBJECT 分组,并用结果替换 RT 列,我们使用dplyr
执行此dplyr
:
library(dplyr)
group_by(dat, Group, SubjectID, Object) %>%
mutate(new_RT = TUK2(RT))
dplyr
对数据进行分组,数据的拆分,将简单的功能应用于每个部分,然后为我们将它们全部组合在一起。
现在,在你的问题中,你说
对于变量 1、2 和 3 的每个组合,我想更改反应时间,以便将高于第三四分位数 + 1.5IQR 的所有值设置为第三四分位数 + 1.5 IQR 的值。
这听起来不像你的函数所做的。 仅基于此描述,我会将其编码为
group_by(dat, Group, SubjectID, Object) %>%
mutate(new_RT = pmin(RT, quantile(RT, probs = 0.75) + 1.5 * IQR(RT)))
pmin
用于并行最小值,它是一种采用两个向量中较小者的向量化方式。 尝试,例如, pmin(1:10, 7)
,看看它做了什么。
在这两个例子中, dplyr
数据框当然不会被保存,除非你用dat <- group_by(dat, ...)
等重新分配它。这是函数式编程的做事方式 -没有全局分配.
附加说明:使用重写的函数,您仍然可以使用循环而不是dplyr
。 我不知道你为什么会 - 当然dplyr
语法更好 - 但我只是想说明小的构建块函数通常很有用,它不是dplyr
原始函数那样“烘焙” dplyr
在”特定的 for 循环中。
for (sub %in% unique(dat$SubjectID)) {
for (obj %in% unique(dat$Object)) {
for (grp %in% unique(dat$Group)) {
dat[dat$SubjectID == sub &
dat$Object == obj &
dat$Group == grp, "RT"] <-
TUK2(
dat[dat$SubjectID == sub &
dat$Object == obj &
dat$Group == grp, "RT"]
)
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.