【问题标题】:Merge duplicated column names合并重复的列名
【发布时间】:2017-03-27 17:28:25
【问题描述】:

我有一个数据框,其中某些列具有相同的数据,但列名不同。我想删除重复的列,但合并列名。一个例子,其中 test1 和 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

我希望结果是这样的:

df

      test1+test4 test2 test3 
    1           1     1     0     
    2           2     2     2     
    3           3     4     4     
    4           4     4     4     
    5           5     5     5     
    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 个重复的列。

【问题讨论】:

  • 我们必须假设您搜索了“r 删除重复列”。请澄清为什么前几次点击没有帮助。否则,此问题将作为重复项关闭。
  • 是的,我有。请查看结果表中的列名。我不仅想删除重复的列。在删除重复项后,我还想合并重复列的列名。我可以为我发布的简单表手动执行此操作,但我想在大型数据集上使用它。
  • 你提前知道哪些列是重复的吗?或者您希望自动确定
  • 我希望它能够自动确定。我想这样的事情会起作用:duplicated(t(df))
  • matchunique 可以处理“列表”(此处为“data.frame”),因此match(df, unique.default(df)) 可以为相同的列提供映射作为一个简单的开始。你的数据有多大?有多少个唯一值?

标签: r


【解决方案1】:

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

已编辑:summary 更改为 digest。这有助于处理字符数据。

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,作为函数。

已编辑:summary 更改为digest 并返回非重复和重复的数据帧。

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)

已编辑:此部分是新的。

示例 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)

【讨论】:

  • 我猜这可能需要一段时间才能运行非常大的数据帧,例如 15000 x 1500?
  • 测试一下。使用我提供的示例,并多次复制数据框,它仍然可以很快工作。 dfnew &lt;-do.call("data.frame", replicate(500, testframe, simplify = FALSE)); ncol(dfnew); start &lt;- Sys.time(); result &lt;- dupcols(df = dfnew); difftime(Sys.time(), start, "secs"); 虽然列名变得相当笨拙。
  • 好的,我在一个大数据框上测试了一下,已经运行了至少15分钟,所以我一定是做错了什么,我会想办法解决的。
  • 我编辑了我的答案以改进该功能并提供一个大型数据框的示例,因此它与您希望如何使用它更相关。
  • 谢谢!最后你以前的版本运行良好,我只需要调整一些东西,但是这个也很有趣。感谢您提供不同的版本!
【解决方案2】:

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

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

【讨论】:

  • 这似乎是一个好的开始,但是如果有两个以上的列具有相同的数据,它就不起作用了,因为它会寻找所有可能的对...
  • 我真的在寻找一种不必手动删除和重命名列的方法,因为我可能有超过 50 个重复的列
猜你喜欢
  • 2017-05-10
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 2011-11-13
  • 2014-03-12
  • 2015-01-01
  • 1970-01-01
  • 2015-12-08
相关资源
最近更新 更多