使用 dplyr 的 rename() 包括不在数据集中的变量名

Using dplyr's rename() including variable names not in data set

我正在尝试将一些 plyr 代码转换为 dplyr,并在 dplyr 中使用 rename() 的新功能。我希望能够为一组具有重叠但原始名称不同的数据集重用单个 rename() 表达式。例如,

sample1 <- data.frame(A=1:10, B=letters[1:10])

sample2 <- data.frame(B=11:20, C=letters[11:20])

然后,

 rename(sample1, var1 = A, var2 = B, var3 = C)

我希望结果是变量 A 重命名为 var1,B 重命名为 var2,在这种情况下不添加 var3。相反,我得到

错误:未知变量:C.

相比之下,plyr 语法会让我使用

rename(sample1, c("A" = "var1", "B" = "var2", "C" = "var3"))
rename(sample2, c("A" = "var1", "B" = "var2", "C" = "var3"))

并且不会抛出错误。有没有办法在 dplyr 中获得相同的结果而不会出现未知变量错误?

    #no need to use rename 

    oldnames<-unique(c(names(sample1),names(sample2)))
    newnames<-c("var1","var2","var3")
    name_df<-data.frame(oldnames,newnames)
    mydata<-list(sample1,sample2) # combined two datasets as a list
#one liner
    finaldata <- lapply(mydata, function(i) {colnames(i)<-name_df[name_df[,1] %in%  colnames(i),2]
return(i)})
> finaldata
[[1]]
   var1 var2
1     1    a
2     2    b
3     3    c
4     4    d
5     5    e
6     6    f
7     7    g
8     8    h
9     9    i
10   10    j

[[2]]
   var2 var3
1    11    k
2    12    l
3    13    m
4    14    n
5    15    o
6    16    p
7    17    q
8    18    r
9    19    s
10   20    t

完全忽略您关于如何使用 dplyr 执行此操作的实际请求,我想建议使用查找的不同方法 table:

sample1 <- data.frame(A=1:10, B=letters[1:10])
sample2 <- data.frame(B=11:20, C=letters[11:20])

rename_map <- c("A"="var1",
                "B"="var2",
                "C"="var3")

names(sample1) <- rename_map[names(sample1)]
str(sample1)

names(sample2) <- rename_map[names(sample2)]
str(sample2)

基本上算法很简单:

  1. 构建查找 table 当前变量名称到所需名称
  2. 使用 names() 函数,使用映射索引查找映射并将这些映射变量分配给适当的列。

编辑:根据 Hadley 的建议,我使用命名向量而不是列表,让生活更轻松。我总是忘记命名向量:(

我以前用过 @earino 的答案 我自己,但发现它可能不安全。如果数据的列名 命名向量(的名称)中缺少框架,这些列名称被默默地替换为 NA,这当然不是您想要的。

d1 <- data.frame(A = 1:10, B = letters[1:10], stringsAsFactors = FALSE)

rename_vec <- c("B" = "var2", "C" = "var3")

names(d1) <- rename_vec[names(d1)]
str(d1)
#> 'data.frame':    10 obs. of  2 variables:
#>  $ NA  : int  1 2 3 4 5 6 7 8 9 10
#>  $ var2: chr  "a" "b" "c" "d" ...

同样的事情也会发生,如果你 运行 names(d1) <- rename_vec[names(d1)] 两次是偶然的,因为当你 运行 第二次时, none colnames(d1)names(rename_vec).

names(d1) <- rename_vec[names(d1)]
str(d1)
#> 'data.frame':    10 obs. of  2 variables:
#>  $ NA: int  1 2 3 4 5 6 7 8 9 10
#>  $ NA: chr  "a" "b" "c" "d" ...

我们只需要 select 重命名向量中数据框 中的那些列。

d2 <- data.frame(B1 = 1:10, B = letters[1:10], stringsAsFactors = FALSE)

sel <- is.element(colnames(d2), names(rename_vec))
names(d2)[sel] <- rename_vec[names(d2)][sel]
str(d2)
#> 'data.frame':    10 obs. of  2 variables:
#>  $ B1  : int  1 2 3 4 5 6 7 8 9 10
#>  $ var2: chr  "a" "b" "c" "d" ...

更新:我最初在这里有一个涉及字符串替换的解决方案,结果证明它也不安全,因为它允许部分匹配。我觉得这个比较好

使用 dplyr,我们可以使用一个命名向量,旧名称作为值,新名称作为名称,然后只取消引用 name_vec 中与数据集中的名称匹配的值。 rename 支持不加引号的字符,因此无需事先将它们转换为 sym

library(dplyr)

name_vec <- c(var1 = "A", var2 = "B", var3 = "C")

sample1 %>%
  rename(!!name_vec[name_vec %in% names(.)])

sample2 %>%
  rename(!!name_vec[name_vec %in% names(.)])

还有 setNames:

name_vec <- c(A = "var1", B = "var2", C = "var3")

sample1 %>%
  setNames(name_vec[names(.)])

sample2 %>%
  setNames(name_vec[names(.)])

输出:

   var1 var2
1     1    a
2     2    b
3     3    c
4     4    d
5     5    e
6     6    f
7     7    g
8     8    h
9     9    i
10   10    j

   var2 var3
1    11    k
2    12    l
3    13    m
4    14    n
5    15    o
6    16    p
7    17    q
8    18    r
9    19    s
10   20    t