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