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

时间:2015-02-25 01:14:59

标签: r plyr dplyr

我正在尝试将一些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中获得相同的结果而不会得到未知变量错误?

4 个答案:

答案 0 :(得分:4)

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

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. 将当前变量名称的查找表构建为所需名称
  2. 使用names()函数,使用映射索引查找映射,并将这些映射变量分配给相应的列。
  3. 编辑:根据哈德利的建议,我使用了一个命名向量而不是列表,让生活变得更轻松。我总是忘记命名的载体:(

答案 1 :(得分:1)

    #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

答案 2 :(得分:0)

我之前使用过@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)],可能会发生同样的情况 偶然两次,因为当您第二次运行时,没有 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" ...

一种更安全的方法是对列名称进行字符串替换, 例如与{stringr}包中的str_replace_all()一起使用。

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

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" ...

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

答案 3 :(得分:0)

使用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