2017-03-27 140 views
0

我有一个数据框,其中一些列具有相同的数据,但列名不同。我想删除重复的列,但合并列名称。一个例子,在测试1和TEST4列是重复的:合并重复列名称

df 

     test1 test2 test3 test4 
    1  1  1  0  1 
    2  2  2  2  2 
    3  3  4  4  3 
    4  4  4  4  4 
    5  5  5  5  5 
    6  6  6  6  6 

,我想结果是这样的:

​​

下面是数据:

structure(list(test1 = c(1, 2, 3, 4, 5, 6), test2 = c(1, 2, 4, 
4, 5, 6), test3 = c(0, 2, 4, 4, 5, 6), test4 = c(1, 2, 3, 4, 
5, 6)), .Names = c("test1", "test2", "test3", "test4"), row.names = c(NA, 
-6L), class = "data.frame") 

请请注意,我不只是想删除重复的列。我也想在删除重复项后合并重复列的列名。

我可以手动为我发布的简单表格做这件事,但是我想在大型数据集上使用它,但事先并不知道哪些列是相同的。我不会手动删除和重命名列,因为我可能有超过50个重复的列。

+2

我们必须假设你用Google搜索“R删除重复列”。请说明为什么前几个命中没有帮助。否则,这个问题将作为重复被关闭。 – Henrik

+0

是的,我有。请查看结果表中的列名。我不仅想删除重复的列。我也想在删除重复项后合并重复列的列名。我可以手动完成我发布的简单表格,但我想在大型数据集上使用它。 – arielle

+0

您是否事先知道哪些列是重复的?或者你想自动确定 – MichaelChirico

回答

1

好的,使用从here的想法改进上述答案。将重复和非重复的列保存到数据框中。检查非重复项是否与任何重复项匹配,如果是,则连接它们的列名。所以,如果你有两个以上的重复列,现在就可以工作。

编辑:更改summarydigest。这有助于角色数据。

df <- structure(list(test1 = c(1, 2, 3, 4, 5, 6), test2 = c(1, 2, 4, 
4, 5, 6), test3 = c(0, 2, 4, 4, 5, 6), test4 = c(1, 2, 3, 4, 
5, 6)), .Names = c("test1", "test2", "test3", "test4"), row.names = c(NA, 
-6L), class = "data.frame") 

library(digest) 
nondups <- df[!duplicated(lapply(df, digest))] 

dups <- df[duplicated(lapply(df, digest))] 

for(i in 1:ncol(nondups)){ 
    for(j in 1:ncol(dups)){ 
    if(FALSE %in% paste0(nondups[,i] == dups[,j])) NULL 
    else names(nondups)[i] <- paste(names(nondups[i]), names(dups[j]), sep = "+") 
    } 
} 

nondups 

例2中,作为函数。

编辑:更改summarydigest并返回非重复和重复的数据帧。

age <- 18:29 
height <- c(76.1,77,78.1,78.2,78.8,79.7,79.9,81.1,81.2,81.8,82.8,83.5) 
gender <- c("M","F","M","M","F","F","M","M","F","M","F","M") 
testframe <- data.frame(age=age,height=height,height2=height,gender=gender,gender2=gender, gender3 = gender) 

dupcols <- function(df = testframe){ 
    nondups <- df[!duplicated(lapply(df, digest))] 

    dups <- df[duplicated(lapply(df, digest))] 

    for(i in 1:ncol(nondups)){ 
    for(j in 1:ncol(dups)){ 
     if(FALSE %in% paste0(nondups[,i] == dups[,j])) NULL 
     else names(nondups)[i] <- paste(names(nondups[i]), names(dups[j]), sep = "+") 
    } 
    } 

    return(list(df1 = nondups, df2 = dups)) 
} 

dupcols(df = testframe) 

Editted:这部分是新的。

例3:在一个大的数据帧

#Creating a 1500 column by 15000 row data frame 
dat <- do.call(data.frame, replicate(1500, rep(FALSE, 15000), simplify=FALSE)) 
names(dat) <- 1:1500 

#Fill the data frame with LETTERS across the rows 
#This part may take a while. Took my PC about 23 minutes. 
start <- Sys.time() 
    fill <- rep(LETTERS, times = ceiling((15000*1500)/26)) 
    j <- 0 
    for(i in 1:nrow(dat)){ 
    dat[i,] <- fill[(1+j):(1500+j)] 
    j <- j + 1500 
    } 
difftime(Sys.time(), start, "mins") 

#Run the function on the created data set 
#This took about 4 minutes to complete on my PC. 
start <- Sys.time() 
    result <- dupcols(df = dat) 
difftime(Sys.time(), start, "mins") 

names(result$df1) 
ncol(result$df1) 
ncol(result$df2) 
+0

它似乎工作得很漂亮,非常感谢! – arielle

+0

我猜测这可能需要一段时间才能运行非常大的数据帧,例如15000乘1500? – arielle

+0

测试它。使用我提供的示例并复制数据框很多次,它仍然运行得非常快。 'dfnew <-do.call(“data.frame”,replicate(500,testframe,simplify = FALSE)); ncol(dfnew); start < - Sys.time(); 结果< - dupcols(df = dfnew); difftime(Sys.time(),start,“secs”);'列名变得相当笨拙。 – Jake

0

它不是完全自动化的,但循环的输出将识别重复列对。然后,您必须删除其中一个重复列,然后根据重复的列重新命名。

df <- structure(list(test1 = c(1, 2, 3, 4, 5, 6), test2 = c(1, 2, 4, 
4, 5, 6), test3 = c(0, 2, 4, 4, 5, 6), test4 = c(1, 2, 3, 4, 
5, 6)), .Names = c("test1", "test2", "test3", "test4"), row.names = c(NA, 
-6L), class = "data.frame") 

for(i in 1:(ncol(df)-1)){ 
    for(j in 2:ncol(df)){ 
    if(i == j) NULL 
    else if(FALSE %in% paste0(df[,i] == df[,j])) NULL 
    else print(paste(i, j, sep = " + ")) 
    } 
} 

new <- df[,-4] 
names(new)[1] <- paste(names(df[1]), names(df[4]), sep = "+") 
new 
+0

这似乎是一个好的开始,但它不工作,如果有超过两列相同的数据,因为它会寻找所有可能的对... – arielle

+0

而且我真的寻找一种方法,无需手动删除和重命名列,因为我可能有超过50个重复的列 – arielle