setNames后缀为前缀

时间:2016-07-13 06:22:50

标签: r dplyr

我有一个数据集,其中包含一系列具有各种后缀的变量,我想将其作为前缀。数据集还包括一些没有任何后缀的变量。类似的东西:

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 thisthis,让我:

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)
)

2 个答案:

答案 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="_")