2015-07-21 89 views
2

我有一個數據幀的結構是這樣的測試:R:通過組,如果對於一個變量的每一個值,該值存在於另一個可變

a <- c(1,1,1,2,2,2,3,3,3,3,4,4) 
b <- c(1,2,3,1,2,3,1,2,3,4,1,2) 
c <- c(NA, NA, 2, NA, 1, 1, NA, NA, 1, 1, NA, NA) 

df <- data.frame(a,b,c) 

ab唯一標識的觀察。我想要創建一個新變量d,它指示b的每個觀察值是否在c中至少存在一次,如a分組。這樣d是:

[1] 0 1 0 1 0 0 1 0 0 0 0 0 

我可以寫一個for循環,這將這樣的伎倆,

attach(df) 
for (i in unique(a)) { 
    for (j in b[a == i]) { 
    df$d[a == i & b == j] <- ifelse(j %in% c[a == i], 1, 0) 
    } 
} 

但肯定R中必須有實現相同的結果的清潔劑/更快的方法?

回答

9

使用data.table

library(data.table) 
setDT(df) #convert df to a data.table without copying 
# +() is code golf for as.integer 
df[ , d := +(b %in% c), by = a] 
#  a b c d 
# 1: 1 1 NA 0 
# 2: 1 2 NA 1 
# 3: 1 3 2 0 
# 4: 2 1 NA 1 
# 5: 2 2 1 0 
# 6: 2 3 1 0 
# 7: 3 1 NA 1 
# 8: 3 2 NA 0 
# 9: 3 3 1 0 
# 10: 3 4 1 0 
# 11: 4 1 NA 0 
# 12: 4 2 NA 0 

添加dplyr版本對於那些勸說。所有信用歸因於@akrun。

library(dplyr) 
df %>% group_by(a) %>% mutate(d = +(b %in% c)) 

和對子孫後代的,一個baseR版本,以及(通過下面@thelatemail)

df <- df[order(df$a, df$b), ] 
df$d <- unlist(by(df, df$a, FUN = function(x) (x$b %in% x$c) + 0L)) 
+0

這是'+'轉換邏輯向量的有趣用法。 – thelatemail

+0

所有功勞歸於@Frank。 FWIW基本上與'as.logical'一樣快。 – MichaelChirico

+1

您可以包含'dplyr'版本以及'df%>%group_by(a)%>%mutate(d = +(b%in%c))' – akrun

2

通過MichaelChirico以上回答顯然運作良好,是正確的。我很少使用data.table,所以我不理解語法。這是在沒有data.table的情況下獲得相同結果的一種方法。

invisible(lapply(unique(df$a), function(x) { 
    df$d[df$a==x] <<- 0L + (df$b[df$a==x] %in% df$c[df$a==x]) 
})) 

該代碼獲取a的所有唯一級別,然後使用您請求的邏輯修改該級別的data.frame。 < < - 是必要的,因爲df將在適用範圍內進行修改,而不是在.GlobalEnv中進行修改。通過< < - 它找到df被定義的父級環境,並在那裏設置df。

此外,請注意稍微不同的+「技巧」版本,其中前導0使得讀者更清楚地知道結果向量是整數,因爲必須將其轉換爲添加才能工作。 0之後的L表示0是整數而不是雙精度。請注意,MichaelChirico爲此投射使用的符號給出了相同的結果(整數類的一列)。

相關問題