使用sets包的一种可能解决方案...
按照给定的设置进行操作:
aa <- c(0, 0, 0, 1, 1, 0, 0)
bb <- c(1, 1, 0, 0, 1, 0, 1)
cc <- c(0, 1, 0, 0, 0, 1, 0)
d <- data.frame(aa, bb, cc)
准备环境...
require(sets, quietly = T)
require(data.table, quietly = T)
通过从
d
创建一组集合,按 'set' 顺序创建唯一名称列表。
namesets <- sapply(seq_len(nrow(d)), function(i) {
gset(colnames(d), memberships = d[i, ])
})
setnames <- sapply(namesets, function(s) {
ifelse(set_is_empty(s), "none", paste(as.character(s), collapse = ""))
})
names(namesets) <- setnames
namesets <- as.set(namesets)
print(namesets)
setnames <- ordered(setnames, levels = names(namesets))
print(setnames)
将
d
转换为 data.table,我们可以以各种方式填充成员集列...
dt <- data.table(membership = setnames, d, key = "membership")
print(dt)
membership.map <- t(sapply(dt$membership, function(m) {
m == levels(dt$membership)
}) * 1)
colnames(membership.map) <- levels(dt$membership)
dt <- cbind(dt, split = " ==> ", membership.map)
print(dt)
这一切都可以用一个快速而简单的函数来实现,如下所示:
membership.table <- function(df) {
namesets <- sapply(seq_len(nrow(d)), function(i) {
gset(colnames(d), memberships = d[i, ])
})
setnames <- sapply(namesets, function(s) {
ifelse(set_is_empty(s), "none", paste(as.character(s), collapse = ""))
})
names(namesets) <- setnames
namesets <- as.set(namesets)
setnames <- ordered(setnames, levels = names(namesets))
dt <- data.table(membership = setnames, d, key = "membership")
membership.map <- t(sapply(dt$membership, function(m) {
m == levels(dt$membership)
}) * 1)
colnames(membership.map) <- levels(dt$membership)
cbind(dt, split = " ==> ", membership.map)
}
mt <- membership.table(d)
identical(dt, mt)
现在,当我们按键总结成员表并从原始数据创建广义集时,应该得到匹配结果的成员信息。
mt[, lapply(.SD, sum), by = membership, .SDcols = seq(3 + ncol(d), ncol(mt))]
as.list(as.gset(d))
请注意,在成员表中,
bb
的总和为
2
,广义集列表中的第三个项目(表示
bb
)也显示了 2 个这样的集合。
如果将同样的算法应用于洪先生的示例,则结果如下:
虽然这个解决方案做了更多的事情(例如排序和排序),但与Hong的解决方案相比,时间并不太可怕;但与Thomas的解决方案相比...
两种解决方案都很慢。如果只需要处理集合,那么可能需要在集合说明文档中花费一些时间,特别是对于较大的成员。
sapply(2:30, function(n)choose(30,n))
的列吗? - user1609452