我有一个充满名称的数据帧。
对于数据帧中的给定行,我想将该行与df中其上方的每一行进行比较,并确定每一行的匹配名称数是否小于或等于4。
玩具示例,其中第3行是感兴趣的行
-
"Jim"、"Dwight"、"Michael"、"Andy"、"Stanley"、"Creed">
-
"Jim"、"Dwight"、"Angela"、"Pam"、"Ryan"、"Jan">
-
"Jim"、"Dwight"、"Angela"、"Pam"、"Creed"、"Ryan"<---感兴趣行
因此,首先我们将第3行与第1行进行比较,发现名称重叠为3,满足<=4个标准。
然后,我们将第3行与第2行进行比较,发现名称重叠为5,这使<4个标准,最终返回<上面每行4个。
现在我正在使用for循环进行此操作,但速度对于我使用的数据帧大小来说太慢了。
示例数据
df <- as.data.frame(rbind(
c("Jim","Dwight","Michael","Andy","Stanley","Creed"),
c("Jim","Dwight","Angela","Pam","Ryan","Jan"),
c("Jim","Dwight","Angela","Pam","Creed","Ryan")
), stringsAsFactors = FALSE)
df
# V1 V2 V3 V4 V5 V6
# 1 Jim Dwight Michael Andy Stanley Creed
# 2 Jim Dwight Angela Pam Ryan Jan
# 3 Jim Dwight Angela Pam Creed Ryan
操作和输出(用%in%
和rowSums
巧妙地越过列(
out_lgl <- rowSums(sapply(df, '%in%', unlist(df[3,]))) <= 4
out_lgl
# [1] TRUE FALSE FALSE
which(out_lgl)
# [1] 1
解释:
对于每一列,将每个元素与第三行(向量unlist(df[3,])
(进行比较。如果存在匹配,则输出是具有与df
、TRUE
相同维度的逻辑值的矩阵。
sapply(df, '%in%', unlist(df[3,]))
# V1 V2 V3 V4 V5 V6
# [1,] TRUE TRUE FALSE FALSE FALSE TRUE
# [2,] TRUE TRUE TRUE TRUE TRUE FALSE
# [3,] TRUE TRUE TRUE TRUE TRUE TRUE
然后我们可以对TRUE
s求和,以查看每行的匹配数量
rowSums(sapply(df, '%in%', unlist(df[3,])))
# [1] 3 5 6
编辑:
我已经在上面的df
的创建中添加了stringsAsFactors = FALSE
选项。然而,据我所知,无论是比较不同级别或不同特征的因素,%in%
的输出都是相同的,所以我不认为这会以任何方式改变结果。参见以下示例
x <- c('b', 'c', 'z')
y <- c('a', 'b', 'g')
all.equal(x %in% y, factor(x) %in% factor(y))
# [1] TRUE
类似于IceCreamToucan的解决方案,但适用于任何行。
对于数据帧:
df <- as.data.frame(rbind(
c("Jim","Dwight","Michael","Andy","Stanley","Creed"),
c("Jim","Dwight","Angela","Pam","Ryan","Jan"),
c("Jim","Dwight","Angela","Pam","Creed","Ryan")
)
对于任何行号i:
f <- function(i) {
if(i == 1) return(T)
r <- vapply(df[1:(i-1),], '%in%', unlist(df[i,]), FUN.VALUE = logical(i-1))
out_lgl <- rowSums(as.matrix(r)) <= 4
return(all(out_lgl))
}