我有一个数据集,其中包含一系列具有各种后缀的变量,我想将其作为前缀。数据集还包括一些没有任何后缀的变量。类似的东西:
df <- data.frame(
home_loc = rnorm(5),
work_loc = rnorm(5),
x1 = rnorm(5),
walk_act = rnorm(5),
bike_act = rnorm(5),
x2 = rnorm(5),
happy_yest = rnorm(5),
sad_yest = rnorm(5)
)
我能够提出以下解决方案:
suff_to_pre <- function(x, suffix, prefix) {
for (i in seq_along(names(x))) {
if (grepl(suffix, names(x)[i])) {
names(x)[i] <- sub(suffix, "", names(x)[i])
names(x)[i] <- paste0(prefix, names(x)[i])
}
}
names(x)
}
names(df) <- suff_to_pre(df, suffix = "_loc", prefix = "loc_")
names(df) <- suff_to_pre(df, suffix = "_act", prefix = "act_")
names(df) <- suff_to_pre(df, suffix = "_yest", prefix = "yest_")
names(df)
[1] "loc_home" "loc_work" "x1" "act_walk" "act_bike" "x2" "yest_happy"
[8] "yest_sad"
但是,我对此并不十分满意。具体来说,我真的想要一种使用dplyr获得相同结果的方法。 I found this和this,让我:
a <- df %>%
select(ends_with("_loc")) %>%
setNames(sub("_loc", "", names(.))) %>%
setNames(paste0("loc_", names(.)))
b <- df %>%
select(ends_with("_act")) %>%
setNames(sub("_act", "", names(.))) %>%
setNames(paste0("act_", names(.)))
c <- df %>%
select(ends_with("_yest")) %>%
setNames(sub("_yest", "", names(.))) %>%
setNames(paste0("yest_", names(.)))
df <- cbind(
select(df, x1, x2), a, b, c
)
这显然不太理想。我希望有人在那里建议使用dplyr更优雅的解决方案。
修改
@docendo discimus和@ zx8754提供了非常有用的答案,但我应该更加明确。我也有包含下划线的变量,但不是我想要更改为前缀的后缀。
例如(见free_time):
df <- data.frame(
home_loc = rnorm(5),
work_loc = rnorm(5),
x_1 = rnorm(5),
walk_act = rnorm(5),
bike_act = rnorm(5),
x_2 = rnorm(5),
happy_yest = rnorm(5),
sad_yest = rnorm(5),
free_time = rnorm(5)
)
答案 0 :(得分:4)
单个sub
电话就足够了:
sub("^(.*)_(.*)$", "\\2_\\1", names(df))
#[1] "loc_home" "loc_work" "x1" "act_walk" "act_bike" "x2" "yest_happy" "yest_sad"
当然要更改名称,请将其分配回来:
names(df) <- sub("^(.*)_(.*)$", "\\2_\\1", names(df))
在dplyr-pipe中你可以使用setNames
:
df %>% setNames(sub("^(.*)_(.*)$", "\\2_\\1", names(.)))
模式"^(.*)_(.*)$"
创建两个捕获组,一个在下划线之前,一个在它之后。在替换"\\2_\\1"
中,我们告诉R首先提取第二组,然后是下划线,并且是第一个组成后缀前缀的组。但是,如果在条目中找不到带下划线的模式,则不会更改任何内容。
问题更新后更新:
对于稍微复杂的案例,您可以执行以下操作:
1)将所有需要更改的后缀存储为前缀:
suf <- c("act", "loc", "yest")
2)根据后缀创建正则表达式模式:
pat <- paste0("^(.*)_(", paste(suf, collapse = "|"), ")$")
pat
#[1] "^(.*)_(act|loc|yest)$"
3)像以前一样继续:
sub(pat, "\\2_\\1", names(df))
# [1] "loc_home" "loc_work" "x_1" "act_walk" "act_bike" "x_2" "yest_happy" "yest_sad" "free_time"
或
df %>% setNames(sub(pat, "\\2_\\1", names(.)))
答案 1 :(得分:1)
我们可以使用str_replace
中的stringr
。这里的想法是使用捕获模式作为一组,即在(..)
内。第一个捕获组(([^_])*
)表示零个或多个字符不是_
后跟_
,后跟另一个捕获组(([^_])
)并且在替换中我们只是切换反向引用。
library(stringr)
names(df) <- str_replace(names(df), "^([^_]*)_([^_]*)$", "\\2_\\1")
names(df)
#[1] "loc_home" "loc_work" "x1" "act_walk"
#[5] "act_bike" "x2" "yest_happy" "yest_sad"
如果我们需要将它与管道一起使用
library(magrittr)
df %<>%
setNames(str_replace(names(.), "^([^_]*)_([^_]*)$", "\\2_\\1"))
或者不使用任何正则表达式
sapply(sapply(strsplit(names(df), "_"), rev), paste, collapse="_")