R:删除重复的名称列,同时保持每个位置的最大值

R: remove duplicate by name columns while keeping the max value per every position

到 2000 年,我有一个很大的 table 5000,其值如下。 我需要删除具有相同名称的列,同时保留列中每个位置的最大值(对于所有重复项)。

我卡住了..我有一个类似的代码,用于按行名删除重复项

x <- setDT(x)[, lapply(.SD, max), cName]

但我不知道如何使用相同的技巧,只能按列

prot1   prot1   prot1   prot2   prot3
0.889618286 0.907433399 0.085730039 0.010259207 0.01203583
0.766053072 0.061778787 0.193634896 0.387856898 0.029151237
0.399227213 0.980691544 0.30179994  0.768697098 0.749744349
0.089657475 0.353170832 0.85146464  0.580683125 0.606756472
0.341599883 0.790159839 0.653031942 0.011711575 0.569486433
0.627587607 0.363081942 0.628312001 0.137380824 0.535160381

所以清理后的版本是

prot1   prot2   prot3
0.907433399 0.010259207 0.01203583
0.766053072 0.387856898 0.029151237
0.980691544 0.768697098 0.749744349
0.85146464  0.580683125 0.606756472
0.790159839 0.011711575 0.569486433
0.628312001 0.137380824 0.535160381

base R 中,我们可以使用 'x' 的唯一列创建一个新数据集 ('x1')。按列名称拆分 'prot' 列的序列,使用该索引对 'x' 进行子集化,使用 pmax 获取每行的 max 值,并在列表中分配输出到 'x1'.

的 'prot' 列
 x1 <- x[unique(colnames(x))]
 x1[-1] <- lapply(split(2:ncol(x), colnames(x)[-1]),
     function(i) do.call(pmax, x[i]))
 x1
 #   cName    prot1      prot2      prot3
 #1    c1 0.9074334 0.01025921 0.01203583
 #2    c2 0.7660531 0.38785690 0.02915124
 #3    c3 0.9806915 0.76869710 0.74974435
 #4    c4 0.8514646 0.58068312 0.60675647
 #5    c5 0.7901598 0.01171158 0.56948643
 #6    c6 0.6283120 0.13738082 0.53516038

或者使用data.table,我们可以得到向量中唯一列名的索引('nm1'),创建一个'data.table',列数等于'nm1' 和与原始数据集相同的行数 ('dt1')。将 data.frame 转换为 data.table (setDT)。使用 for 循环,我们可以 set 'dt1' 的每一列中的值作为 'x' 中每个唯一列名称的行的最大值(do.call(pmax,).

library(data.table)
nm1 <- unique(colnames(x)[-1])
dt1 <- as.data.table(matrix(NA, ncol=length(nm1), nrow=nrow(x), 
                dimnames=list(NULL, nm1)))
setDT(x)

for(j in seq_along(dt1)){
 set(dt1, i=NULL, j=j, value= do.call(pmax,x[,colnames(x) %chin% 
                           nm1[j], with=FALSE]))
 }

 dt1
 #      prot1      prot2      prot3
 #1: 0.9074334 0.01025921 0.01203583
 #2: 0.7660531 0.38785690 0.02915124
 #3: 0.9806915 0.76869710 0.74974435
 #4: 0.8514646 0.58068312 0.60675647
 #5: 0.7901598 0.01171158 0.56948643
 #6: 0.6283120 0.13738082 0.53516038

基准

在更大的数据集上

 set.seed(24)
 x1 <- as.data.frame(matrix(rnorm(5000*2000), ncol=5000))
 set.seed(42)
 colnames(x1) <- sample(paste0('prot', 1:100), 5000, replace=TRUE)

 library(gtools)
 nm2 <- mixedsort(unique(colnames(x1)))
 dt2 <- as.data.table(matrix(NA, ncol= length(nm2),
          nrow=nrow(x1), dimnames=list(NULL, nm2)))
 setDT(x1)
 system.time({
    for(j in seq_along(dt1)){
       set(dt2, i=NULL, j=j, value= do.call(pmax,x1[,colnames(x1) %chin% 
                           nm2[j], with=FALSE]))
   }
})

# user  system elapsed 
#  0.019   0.000   0.019 

数据

x <- structure(list(cName = c("c1", "c2", "c3", "c4", "c5", "c6"), 
prot1 = c(0.889618286, 0.766053072, 0.399227213, 0.089657475, 
0.341599883, 0.627587607), prot1 = c(0.907433399, 0.061778787, 
0.980691544, 0.353170832, 0.790159839, 0.363081942), prot1 =
c(0.085730039, 
0.193634896, 0.30179994, 0.85146464, 0.653031942, 0.628312001
), prot2 = c(0.010259207, 0.387856898, 0.768697098, 0.580683125, 
0.011711575, 0.137380824), prot3 = c(0.01203583, 0.029151237, 
0.749744349, 0.606756472, 0.569486433, 0.535160381)), 
.Names =   c("cName", 
"prot1", "prot1", "prot1", "prot2", "prot3"), class = "data.frame",
row.names = c(NA, -6L))

添加到 Akrun 的回答中: 第一个解决方案适用于小型数据集,但假设您的变量按 ascending/alphabetical 顺序排列。如果您的变量未排序,您可以使用以下内容(使用 Akrun 的 post 中的 x):

x1 <- data.frame(sapply(split(1:ncol(x), colnames(x)), function(i) do.call(pmax, x[i])))