dplyr中的rename()和rename_with()无法重命名重复列名的问题

4
给定一个包含重复列名的tibble或data.frame,我想使用dplyr::rename或dplyr::rename_with来执行以下操作之一:
(a) 使用序列数字后缀('a_1','a_2'等)区分重复的名称,或者
(b) 完全重命名每个列。
library(tidyverse)

d <- tibble(a = 1:3, a = letters[1:3], .name_repair = "minimal")

d
# A tibble: 3 x 2
      a a    
  <int> <chr>
1     1 a    
2     2 b    
3     3 c  

需要:

tibble(a_1 = 1:3, a_2 = letters[1:3])

# A tibble: 3 x 2
    a_1 a_2           # or even just: x, y    
  <int> <chr>
1     1 a    
2     2 b    
3     3 c   

看起来可以期望使用 rename/rename_with 来执行这个操作,特别是因为 colnames(d) <- c("a_1", "a_2") 看起来很明显和简单。

但截至目前为止我尝试了三种方法都得到了不同的错误和/或意外行为:

1. 使用 rename(),一个列被重命名,另一个则没有:

d %>% rename(x = "a", y = "a")  

# A tibble: 3 x 2
        y a    
    <int> <chr>
  1     1 a    
  2     2 b    
  3     3 c   

2. 使用rename_with()时,我使用一个函数添加数字后缀,出现了以下错误:

d %>% rename_with(~paste(.x, 1:2, sep = "_"))

Error: Names must be unique.
x These names are duplicated:
  * "a" at locations 1 and 2.

请注意,仅当数据没有重复列名时,使用 rename_with 才能按预期工作:
no_dupe <- tibble(a = 1:3, b = letters[1:3])
no_dupe %>% rename_with(~paste(.x, 1:2, sep = "_"))

# A tibble: 3 x 2
    a_1 b_2  
  <int> <chr>
1     1 a    
2     2 b    
3     3 c    

3. 使用旧版的 rename_all(),我收到了不同的错误提示:

d %>% rename_all(paste0, 1:2)

Error: Can't rename duplicate variables to `{name}`.

我发现了一个关于在tidyselect GitHub问题中使用rename处理重复列名的讨论,但这只是针对如果用户使用rename()创建了重复列名时要怎么做,而不是如何去除重复列名。

我是否遗漏了语法,还是说dplyr::rename系列函数无法处理重复列名?

(我还想更好地理解为什么上面的示例中rename只重命名了一个列,但这更多的是出于我的好奇心而非实际需求。)

提前感谢。


3
"rename" 不知道之前所做的更改,因此它会将同一列重复重命名。这个操作d %>% rename(x = "a") %>% rename(y = "a")是有效的。 - Ronak Shah
1
关于为什么 rename_with 不能处理重复的列名,我认为是因为这一行代码 https://github.com/tidyverse/dplyr/blob/master/R/rename.R#L70 。我们不允许传递自己的 repair 参数,它总是 "check_unique" - Ronak Shah
很好的发现,@RonakShah,感谢你挖掘这个。我主要关心的是 rename_with(),因为我希望找到一种编程方法来给重复列名分配后缀。你能写个答案吗?还有关于 rename() 没有“记忆”也知道了,谢谢。 - andrew_reece
为什么不将所有列名存储在一个向量中。创建另一个长度相等的1:n向量。将两个向量连接起来,并用结果向量替换列名。 - AnilGoyal
3个回答

3

rename 命令无法知道之前的名称更改。例如:

library(dplyr)
mtcars %>% rename(a = mpg, b = a)

错误:无法重命名不存在的列。 x 列 a 不存在。

因此,这个问题

d %>% rename(x = "a", y = "a")  

将相同的a列重命名两次,首先用x,然后用y。另一种方法是中断管道并进行重命名。

d %>% rename(x = "a") %>% rename(y = "a")  

# A tibble: 3 x 2
#      x y    
#  <int> <chr>
#1     1 a    
#2     2 b    
#3     3 c 

rename_with 不允许重命名包含重复列的 dataframe/tibbles,因为 https://github.com/tidyverse/dplyr/blob/master/R/rename.R#L70。在这种情况下,我认为你最好使用基本的 R 方法。


2

试试这个:

new_names <- c('a_1', 'a_2')
names(d) <- make.unique(dput(names(d)))
d %>% 
  rename_with(~new_names)
  # rename_at(vars(names(d)), ~new_names)

输出:

    a_1 a_2  
  <int> <chr>
1     1 a    
2     2 b    
3     3 c    

0
假设您有多个具有重复甚至三次重复列名的列,您也可以尝试这种方法。
使用colnames将所有列名提取到名为v的向量中。然后,按照以下方法进行操作。
v <- c("a", "a", "b", "c", "c", "c", "d", "e")

df <- tibble(v)


df <- df %>% mutate(id = 1) %>% 
  group_by(v) %>% 
  summarise(id = cumsum(id)) %>% 
  mutate(v2 = paste(v,id, sep = "_")) %>%
  mutate(v2 = ifelse(id==1, v, v2)) 

使用df$v2替换列名。

> df$v2
[1] "a"   "a_2" "b"   "c"   "c_2" "c_3" "d"   "e" 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接