![](/img/trans.png)
[英]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.