My problem is quite straightforward, I have a dataframe with many columns, some of them start with q03b_
, like this:
ID ... q03b_0 q03b_1 q03b_2 ... q03b_14
1 ... a b c m
But I need to change the column names to q03b_other_1
, q03b_other_2
, q03b_other_3
, etc (counting from 1 instead of 0). I managed to select the columns with rename_at
and add the "other" to the column names, like this:
df %>%
rename_at(vars(matches('q03b_')), list(~ str_replace(., "b_(\\d )", "_other_\\1")))
Which brings a dataframe like this:
ID ... q03_other_0 q03_other_1 q03_other_2 ... q03_other_14
1 ... a b c m
But I'm struggling to get to the final stage, which would be this:
ID ... q03_other_1 q03_other_2 q03_other_3 ... q03_other_15
1 ... a b c m
I guess I need to use a combination of as.numeric
and as.character
, but because of tidy evaluation I'm struggling to find a way to make this work. Any ideas?
Thanks !
CodePudding user response:
With gsubfn
:
library(dplyr)
library(readr)
library(gsubfn)
df %>%
rename_at(vars(matches('q03b_')),
list(~ gsubfn("b_\\d $",
~ paste0("_other_",
parse_number(x) 1),
.)))
Output
q03_other_1 q03_other_2 q03_other_3
1 a b c
CodePudding user response:
Here is an alternative way using sprintf
:
library(dplyr)
library(stringr)
df %>%
select(-ID) %>%
rename_with(~str_replace(., "[0-9] $", sprintf("%.0f", 1:length(colnames(df))))) %>%
rename_with(~str_replace(., "b", "")) %>%
bind_cols(ID=df$ID)
q03_other_1 q03_other_2 q03_other_3 ID
1 a b c 1
CodePudding user response:
We can also use
library(dplyr)
library(stringr)
df %>%
rename_with(~ str_replace(., "b_\\d $", function(x)
str_c('_other_', readr::parse_number(x) 1)) , starts_with('q03b_'))
ID q03_other_1 q03_other_2 q03_other_3
1 1 a b c
data
df <- structure(list(ID = 1L, q03b_0 = "a", q03b_1 = "b", q03b_2 = "c"), class = "data.frame", row.names = c(NA,
-1L))
CodePudding user response:
Try the following:
library(tidyverse)
df <- data.frame(
stringsAsFactors = FALSE,
ID = c(1L),
q03b_0 = c("a"),
q03b_1 = c("b"),
q03b_2 = c("c")
)
names(df)[-1] <- names(df)[-1] %>%
str_remove("_.*") %>%
paste0("_other_",1:length(.))
df
#> ID q03b_other_1 q03b_other_2 q03b_other_3
#> 1 1 a b c
EDIT: A more general solution:
library(tidyverse)
df <- data.frame(
stringsAsFactors = FALSE,
ID = c(1L),
q03b_0 = c("a"),
q03b_1 = c("b"),
q03b_2 = c("c")
)
names(df)[str_detect(names(df), "^q03b_")] %<>%
str_split("_") %>%
map_chr(~ paste0(.x[1], "_other_", 1 as.numeric(.x[2])))
df
#> ID q03b_other_1 q03b_other_2 q03b_other_3
#> 1 1 a b c