[英]Filter a table to keep only non-redundant groups
我已经在R语言中进行了一段时间的系统发育分析,使用了像ape,phangorn和phytools这样的库。
在解决问题时,我遇到了一个存在/不存在的data.frame,它指定目标基因是否属于(或不属于)某个特定组。
例如:
gene11 gene25 gene33 gene54 gene55 gene65 gene73 gene88
group_1 1 1 0 0 0 0 0 0
group_2 1 1 1 0 0 0 0 0
group_3 1 0 1 0 0 0 0 0
group_4 0 1 1 0 0 0 0 0
group_5 0 0 0 1 1 0 0 0
group_6 0 0 0 1 0 0 0 0
group_7 0 0 0 0 1 0 0 0
group_8 0 0 0 0 0 1 1 1
group_9 0 0 0 0 0 1 1 0
group_10 0 0 0 0 0 1 0 1
group_11 0 0 0 0 0 0 1 1
正如处理生物实体组时所预期的那样,该实体之间存在多种联系方式:基因11、25和33组成一个组,并且它们的关系也可以描述为较小的组,描述成对关系。
因此,这很重要 : group_2 , group_5和group_8是生物学上相关的基因组,因此它们事先不被称为相关组 。 其他较小的组是这些相关组中显示的关系的结果:group_1与gene11和gene25相关,但是是嵌套在较宽 (且相关)group_2中的组。 在其他情况下也是如此:group_8描述了gene65,gene73和gene88之间的关系; 与这些基因有关的其他组(group_9,group_10和group_11)仅仅是描述更广泛的group_8组中各基因之间存在成对关系的子组。
事先已知的是,基因形成不相交的簇,每个簇由其他(逐渐变小的)簇组成。 我有兴趣捕获最大的不相交的群体。
另一个用户(@Shree) 对问题进行了清晰的定义 :
找到最小数量的组,以使所有其他组都是这些组中至少一个的子组。 另外,一组必须至少具有2个基因,即连续两个1s。 同样假设,1,01,0是的子群
1,1,1,0
,但0,1,1,1
是不是一个亚组1,1,1,0
。
预先感谢所有人!
这是使用混合整数编程方法的一种方法。 我正在使用ompr
进行数学建模,并使用glpk
(免费开源)作为求解器。 建模逻辑以注释形式提供。
我认为这个问题可以用数学方法描述如下:
过滤数据框以最小化行数,以使所有列的总和为1。选定的行称为主要组,而每隔一行应是主要组的子组。 一列(基因)只能属于一个主要组。 当所有位置(列)上的
subgroup <= primary group
时,任何未选择的行都是主组的subgroup <= primary group
。 因此,(0,0,1,1)
是亚组(0,1,1,1)
但是(1,0,1,1)
是不是一个子组(0,1,1,1)
library(dplyr)
library(ROI)
library(ROI.plugin.glpk)
library(ompr)
library(ompr.roi)
gene_mat <- as.matrix(df)
nr <- nrow(gene_mat)
nc <- ncol(gene_mat)
model <- MIPModel() %>%
# binary variable x[i] is 1 if row i is selected else 0
add_variable(x[i], i = 1:nr, type = "binary") %>%
# minimize total rows selected
set_objective(sum_expr(x[i], i = 1:nr), "min") %>%
# sum of columns of selected rows must be = 1
add_constraint(sum_expr(gene_mat[i,j]*x[i], i = 1:nr) == 1, j = 1:nc) %>%
solve_model(with_ROI(solver = "glpk"))
# get rows selected
group_rows <- model %>%
get_solution(x[i]) %>%
filter(value > 0) %>%
pull(i) %>%
print()
result <- df[group_rows, ]
gene11 gene25 gene33 gene54 gene55 gene65 gene73 gene88
group_2 1 1 1 0 0 0 0 0
group_5 0 0 0 1 1 0 0 0
group_8 0 0 0 0 0 1 1 1
重要的提示 -
上面的表述不是针对subgroup <= primary group
,而是基于OP提及“事先知道基因形成不相交基团的簇”的事实。 这意味着数据中不存在如下所示的情况,因为行1、3、4不会形成不相交的组,即列3属于2个主要组,这是不允许的。
1 1 0 0 0
0 1 0 0 0
1 0 1 0 0 <- this row is not a subgroup of any row
0 0 1 1 1
无论如何,这里的代码会进行安全检查,以确保所有未选中的行都是一个主要组的子组-
test <- lapply(group_rows, function(x) {
sweep(df, 2, as.numeric(df[x, ]), "<=") %>%
{which(rowSums(.) == ncol(df))}
})
# all is okay if below returns TRUE
length(Reduce(intersect, test)) == 0
数据-
df <- structure(list(
gene11 = c(1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L,0L, 0L),
gene25 = c(1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L),
gene33 = c(0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L),
gene54 = c(0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L),
gene55 = c(0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L),
gene65 = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L),
gene73 = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L),
gene88 = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 1L)),
class = "data.frame",
row.names = c("group_1", "group_2", "group_3", "group_4",
"group_5", "group_6", "group_7", "group_8",
"group_9", "group_10", "group_11")
)
这里我们一种选择split
的数据与创建的分组索引数据列的块rep
(这里,1和2对应于第一3个接下来的2列),然后通过循环list
,使用filter_all
提取全为1的行,并通过将NA替换为0进行mutate
library(dplyr)
library(purrr)
library(tibble)
split.default(df, rep(1:2, c(3, 2))) %>%
map_dfr(~ .x %>%
rownames_to_column('rn') %>%
filter_at(-1, all_vars(.==1))) %>%
mutate_all(replace_na, 0) %>%
column_to_rownames('rn')
#. gene1 gene2 gene3 gene4 gene5
#group_1 1 1 1 0 0
#group_7 0 0 0 1 1
df <- structure(list(gene1 = c(1L, 0L, 1L, 1L, 0L, 0L, 0L), gene2 = c(1L,
1L, 1L, 0L, 0L, 0L, 0L), gene3 = c(1L, 1L, 0L, 1L, 0L, 0L, 0L
), gene4 = c(0L, 0L, 0L, 0L, 1L, 0L, 1L), gene5 = c(0L, 0L, 0L,
0L, 0L, 1L, 1L)), .Names = c("gene1", "gene2", "gene3", "gene4",
"gene5"), class = "data.frame", row.names = c("group_1", "group_2",
"group_3", "group_4", "group_5", "group_6", "group_7"))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.