簡體   English   中英

過濾表以僅保留非冗余組

[英]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_2group_5group_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM