泛化 R %in% 运算符以匹配元组
Posted
技术标签:
【中文标题】泛化 R %in% 运算符以匹配元组【英文标题】:Generalize R %in% operator to match tuples 【发布时间】:2014-04-20 07:08:05 【问题描述】:前几天我花了一段时间寻找一种方法来检查行向量是否包含在 R 中的某些行向量中。基本上,我想概括 %in%
运算符以匹配元组而不是每个条目在一个向量中。例如,我想要:
row.vec = c("A", 3)
row.vec
# [1] "A" "3"
data.set = rbind(c("A",1),c("B",3),c("C",2))
data.set
# [,1] [,2]
# [1,] "A" "1"
# [2,] "B" "3"
# [3,] "C" "2"
row.vec %tuple.in% data.set
# [1] FALSE
对于我虚构的运算符 %tuple.in%
,因为行向量 c("A",3)
不是 data.set 中的行向量。使用%in%
运算符给出:
row.vec %in% data.set
# [1] TRUE TRUE
因为“A”和 3 在data.set
中,这不是我想要的。
我有两个问题。首先,有什么好的现有解决方案吗?
其次,由于我找不到它们(即使它们存在),我尝试编写自己的函数来完成它。它适用于行向量的输入矩阵,但我想知道是否有专家提出改进:
is.tuple.in <- function(matrix1, matrix2)
# Apply rbind() so that matrix1 has columns even if it is a row vector.
matrix1 = rbind(matrix1)
if(ncol(matrix1) != ncol(matrix2))
stop("Matrices must have the same number of columns.")
# Now check for the first row and handle other rows recursively
row.vec = matrix1[1,]
tuple.found = FALSE
for(i in 1:nrow(matrix2))
# If we find a match, then this row exists in matrix 2 and we can break the loop
if(all(row.vec == matrix2[i,]))
tuple.found = TRUE
break
# If there are more rows to be checked, use a recursive call
if(nrow(matrix1) > 1)
return(c(tuple.found, is.tuple.in(matrix1[2:nrow(matrix1),],matrix2)))
else
return(tuple.found)
我发现了一些我不知道如何解决的问题。首先,我希望在函数开始时明确基本情况。我没能做到这一点,因为我在递归调用中传递了matrix1[2:nrow(matrix1),]
,如果matrix1
有一行,则会产生错误。因此,我没有遇到matrix1
为空的情况,而是在最后有一个 if 条件来决定是否需要更多迭代。
其次,我认为在开始时使用rbind()
很草率,但是当matrix1
减少到单行时我需要它。如果不使用rbind()
,ncol(matrix1)
在 1 行情况下会产生错误。我认为我的问题与缺乏关于 R 数据类型的知识有关。
任何帮助将不胜感激。
【问题讨论】:
***.com/questions/7943695/matrix-in-matrix对此有一些解决方案 【参考方案1】:我想知道你是否把它弄得比现在更复杂一些。例如,
set.seed(1618)
vec <- c(1,3)
mat <- matrix(rpois(1000,3), ncol = 2)
rownames(mat) <- 1:nrow(mat)
mat[sapply(1:nrow(mat), function(x) all(vec %in% mat[x, ])), ]
# gives me this
# [,1] [,2]
# 6 3 1
# 38 3 1
# 39 3 1
# 85 1 3
# 88 1 3
# 89 1 3
# 95 3 1
# 113 1 3
# ...
如果您关心订单,可以进一步细分 或者你可以稍微修改一下函数:
mat[sapply(1:nrow(mat), function(x)
all(paste(vec, collapse = '') %in% paste(mat[x, ], collapse = ''))), ]
# [,1] [,2]
# 85 1 3
# 88 1 3
# 89 1 3
# 113 1 3
# 133 1 3
# 139 1 3
# 187 1 3
# ...
另一个向量更长的例子
set.seed(1618)
vec <- c(1,4,5,2)
mat <- matrix(rpois(10000, 3), ncol = 4)
rownames(mat) <- 1:nrow(mat)
mat[sapply(1:nrow(mat), function(x) all(vec %in% mat[x, ])), ]
# [,1] [,2] [,3] [,4]
# 57 2 5 1 4
# 147 1 5 2 4
# 279 1 2 5 4
# 303 1 5 2 4
# 437 1 5 4 2
# 443 1 4 5 2
# 580 5 4 2 1
# ...
我看到一对匹配的:
mat[sapply(1:nrow(mat), function(x)
all(paste(vec, collapse = '') %in% paste(mat[x, ], collapse = ''))), ]
# [,1] [,2] [,3] [,4]
# 443 1 4 5 2
# 901 1 4 5 2
# 1047 1 4 5 2
但只有三个
对于您的单行案例:
vec <- c(1,4,5,2)
mat <- matrix(c(1,4,5,2), ncol = 4)
rownames(mat) <- 1:nrow(mat)
mat[sapply(1:nrow(mat), function(x)
all(paste(vec, collapse = '') %in% paste(mat[x, ], collapse = ''))), ]
# [1] 1 4 5 2
这是上面代码的一个简单函数
is.tuplein <- function(vec, mat, exact = TRUE)
rownames(mat) <- 1:nrow(mat)
if (exact)
tmp <- mat[sapply(1:nrow(mat), function(x)
all(paste(vec, collapse = '') %in% paste(mat[x, ], collapse = ''))), ]
else tmp <- mat[sapply(1:nrow(mat), function(x) all(vec %in% mat[x, ])), ]
return(tmp)
is.tuplein(vec = vec, mat = mat)
# [1] 1 4 5 2
似乎可行,所以让我们自己创建%in%
运算符:
`%tuple%` <- function(x, y) is.tuplein(vec = x, mat = y, exact = TRUE)
`%tuple1%` <- function(x, y) is.tuplein(vec = x, mat = y, exact = FALSE)
试一试
set.seed(1618)
c(1,2,3) %tuple% matrix(rpois(1002,3), ncol = 3)
# [,1] [,2] [,3]
# 133 1 2 3
# 190 1 2 3
# 321 1 2 3
set.seed(1618)
c(1,2,3) %tuple1% matrix(rpois(1002,3), ncol = 3)
# [,1] [,2] [,3]
# 48 2 3 1
# 64 2 3 1
# 71 1 3 2
# 73 3 1 2
# 108 3 1 2
# 112 1 3 2
# 133 1 2 3
# 166 2 1 3
【讨论】:
我想先粘贴,就像斯蒂芬的回答一样,应该比逐行粘贴要快。 +1 用于实际制作%tuple.in%
运算符。
使用sapply()
绝对是个好主意;这是我不熟悉的众多 R 功能之一。感谢您的帖子。【参考方案2】:
这是否符合您的要求(即使超过 2 列)?
paste(row.vec,collapse="_") %in% apply(data.set,1,paste,collapse="_")
【讨论】:
row.vec = 'c('a_b', 'c')'; data.set = data.frame('a', 'b_c')
- 显然这不是一个通用的解决方案。它可以通过转义分隔符变得通用,但它不漂亮,也不高效。以上是关于泛化 R %in% 运算符以匹配元组的主要内容,如果未能解决你的问题,请参考以下文章