2016-08-21 64 views
4

此問題由How can I quickly see if any elements of multiple vectors are equal in R?驅動,但不完全相同/重複。如何執行配對操作(如'%in%')並設置操作列表向量

作爲一個小例子,假設我們有4個矢量的列表:

set.seed(0) 
lst <- list(vec1 = sample(1:10, 2, TRUE), vec2 = sample(1:10, 3, TRUE), 
      vec3 = sample(1:10, 4, TRUE), vec4 = sample(1:10, 5, TRUE)) 

我們如何執行成對二進制運算像%in%和設置操作說intersectunionsetdiff

假設我們想要配對"%in%",我們怎樣才能在每一對中進一步執行any()/all()/which()

注意:我不想使用combn()

+1

也許不能直接適用,但在這裏,在類似案件中,經典的'表/(T)crossprod'方法可以透露一些成對的關係 - 'crossprod( table(val = unlist(lst,,FALSE),vec = rep(seq_along(lst),lengths(lst))))'。儘管通過製表所有內存限制可能會造成問題 –

回答

4

我們可以使用outer(x, y, FUN)xy不需要是像數值向量/矩陣那樣的「數字」輸入;像「list」/「矩陣列表」這樣的矢量輸入也是允許的。

例如,我們用

z <- outer(lst, lst, FUN = Vectorize("%in%", SIMPLIFY = FALSE, USE.NAMES = FALSE)) 
#  vec1  vec2  vec3  vec4  
#vec1 Logical,2 Logical,2 Logical,2 Logical,2 
#vec2 Logical,3 Logical,3 Logical,3 Logical,3 
#vec3 Logical,4 Logical,4 Logical,4 Logical,4 
#vec4 Logical,5 Logical,5 Logical,5 Logical,5 

由於"%in%"本身不是矢量申請配對"%in%"操作,我們使用Vectorized("%in%")。我們還需要SIMPLIFY = FALSE,以便FUN爲每對(x[[i]], y[[j]])返回一個長度爲1的列表。這一點很重要,因爲outer作品,如:

y[[4]] | FUN(x[[1]], y[[4]]) FUN(x[[2]], y[[4]]) FUN(x[[1]], y[[4]]) FUN(x[[2]], y[[4]]) 
y[[3]] | FUN(x[[1]], y[[3]]) FUN(x[[2]], y[[3]]) FUN(x[[1]], y[[3]]) FUN(x[[2]], y[[4]]) 
y[[2]] | FUN(x[[1]], y[[2]]) FUN(x[[2]], y[[2]]) FUN(x[[1]], y[[2]]) FUN(x[[2]], y[[4]]) 
y[[1]] | FUN(x[[1]], y[[1]]) FUN(x[[2]], y[[1]]) FUN(x[[1]], y[[1]]) FUN(x[[2]], y[[4]]) 
     ------------------- ------------------- ------------------- ------------------- 
     x[[1]]    x[[2]]    x[[3]]    x[[4]] 

必須確信length(FUN(x, y)) == length(x) * length(y)。雖然如果SIMPLIFY = FALSE,這並不一定成立。

以上結果z是「矩陣列表」,其中class(z)爲「矩陣」,但typeof(z)爲「列表」。請閱讀Why is this matrix not numeric?瞭解更多信息。


如果我們想進一步施加一定的彙總函數的z每個元素,我們可以使用lapply。這裏我會舉兩個例子。

實施例1:應用any()

由於any(a %in% b)any(b %in% a)爲相同的,即,操作是對稱的,我們只需要具有z下三角的工作:

lz <- z[lower.tri(z)] 

lapply返回一個未命名的列表,但爲了便於閱讀,我們需要一個命名列表。我們可以利用矩陣索引(i, j)姓名:

ind <- which(lower.tri(z), arr.ind = TRUE) 
NAME <- paste(ind[,1], ind[,2], sep = ":") 
any_lz <- setNames(lapply(lz, any), NAME) 

#List of 6 
# $ 2:1: logi FALSE 
# $ 3:1: logi TRUE 
# $ 4:1: logi TRUE 
# $ 3:2: logi TRUE 
# $ 4:2: logi FALSE 
# $ 4:3: logi TRUE 

Set操作像intersectunionsetequal也是我們能與工作同樣對稱操作。

例2:應用which()

which(a %in% b)不是對稱的操作,所以我們必須用全矩陣工作。

NAME <- paste(1:nrow(z), rep(1:nrow(z), each = ncol(z)), sep = ":") 
which_z <- setNames(lapply(z, which), NAME) 

# List of 16 
# $ 1:1: int [1:2] 1 2 
# $ 2:1: int(0) 
# $ 3:1: int [1:2] 1 2 
# $ 4:1: int 3 
# $ 1:2: int(0) 
# $ 2:2: int [1:3] 1 2 3 
# ... 

setdiff這樣的設置操作也是不對稱的,可以類似地處理。


替代

除了使用outer(),我們也可以使用ř表達式來獲得z上方。同樣,我採取二元運算"%in%"爲例:

op <- "'%in%'" ## operator 

lst_name <- names(lst) 
op_call <- paste0(op, "(", lst_name, ", ", rep(lst_name, each = length(lst)), ")") 
# [1] "'%in%'(vec1, vec1)" "'%in%'(vec2, vec1)" "'%in%'(vec3, vec1)" 
# [4] "'%in%'(vec4, vec1)" "'%in%'(vec1, vec2)" "'%in%'(vec2, vec2)" 
# ... 

然後我們可以在lst分析和評估這些表達式。我們可能會使用組合索引結果列表中的名稱:

NAME <- paste(1:length(lst), rep(1:length(lst), each = length(lst)), sep = ":") 
z <- setNames(lapply(parse(text = op_call), eval, lst), NAME) 

# List of 16 
# $ 1:1: logi [1:2] TRUE TRUE 
# $ 2:1: logi [1:3] FALSE FALSE FALSE 
# $ 3:1: logi [1:4] TRUE TRUE FALSE FALSE 
# $ 4:1: logi [1:5] FALSE FALSE TRUE FALSE FALSE 
# $ 1:2: logi [1:2] FALSE FALSE 
# ...