Добавьте 1 к именам столбцов, которые заканчиваются целым числом r

#r #dplyr #rename

Вопрос:

Моя проблема довольно проста, у меня есть фрейм данных со множеством столбцов, некоторые из них начинаются q03b_ примерно так:

 ID  ...  q03b_0 q03b_1 q03b_2 ... q03b_14
 1  ...    a      b      c           m
 

Но мне нужно изменить имена столбцов на q03b_other_1 , q03b_other_2 , q03b_other_3 и т. Д. (Считая от 1 вместо 0). Мне удалось выбрать столбцы с rename_at помощью и добавить «другое» к именам столбцов, вот так:

 df  %>% 
  rename_at(vars(matches('q03b_')), list(~ str_replace(., "b_(\d )", "_other_\1")))
 

Что приводит к такому кадру данных, как этот:

 ID  ...  q03_other_0 q03_other_1 q03_other_2 ... q03_other_14
 1  ...    a               b          c               m
 

Но я изо всех сил пытаюсь добраться до финальной стадии, которая была бы такой:

 ID  ...  q03_other_1 q03_other_2 q03_other_3 ... q03_other_15
 1  ...    a                b           c                m
 

Я предполагаю , что мне нужно использовать комбинацию as.numeric и as.character , но из-за аккуратной оценки я изо всех сил пытаюсь найти способ заставить это работать. Есть какие-нибудь идеи?

Спасибо!

Ответ №1:

С gsubfn :

 library(dplyr)
library(readr)
library(gsubfn)

df %>%
  rename_at(vars(matches('q03b_')), 
            list(~ gsubfn("b_\d $", 
                          ~ paste0("_other_", 
                                   parse_number(x)   1), 
                          .)))
 

Выход

   q03_other_1 q03_other_2 q03_other_3
1           a           b           c
 

Комментарии:

1. Сработало как надо, спасибо! Забыл в вопросе, что мне нужно было убрать букву » б » из имени. Я сделал это, чтобы исправить это: df %>% rename_at(vars(matches('q03b_')), list(~ gsubfn::gsubfn("\d $", ~ paste("other", as.numeric(x) 1, sep = "_"), .) %>% str_replace('b', ''))) вы бы сказали, что это лучший способ? Большое спасибо!

2. Рад слышать. Я мог бы использовать parse_number от readr или альтернативу as.numeric , тогда вы также можете добавить «b_» в шаблон… дайте мне знать, если это сработает для вас…(я использовал extract_numeric от tidyr )…

3. Смотрите отредактированный ответ и дайте мне знать, работает ли это для вас…

Ответ №2:

Вот альтернативный способ использования 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
 

Ответ №3:

Мы также можем использовать

 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
 

данные

 df <- structure(list(ID = 1L, q03b_0 = "a", q03b_1 = "b", q03b_2 = "c"), class = "data.frame", row.names = c(NA, 
-1L))
 

Ответ №4:

Я не уверен, что вам нужно получить номер из исходных имен столбцов, добавьте к нему 1, чтобы создать новые столбцы.

Это работает и без этого —

 library(dplyr)

df %>%
  rename_with(~paste0('q03_other_', seq_along(.)), starts_with('q03b_'))

#  ID q03_other_1 q03_other_2 q03_other_3
#1  1           a           b           c
 

данные

 df <- data.frame(ID = 1, q03b_0 = 'a', q03b_1 = 'b', q03b_2 = 'c')
 

Ответ №5:

Попробуйте выполнить следующие действия:

 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
 

ИЗМЕНИТЬ: Более общее решение:

 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
 

Комментарии:

1. На практике мой фрейм данных содержит 27 столбцов, так что это не сработает. Я думаю, что использование индексов имен может быть немного нечитабельным и также подвержено ошибкам. В любом случае, спасибо

2. Непонятно, почему это не сработает, потому что у вас 27 столбцов, @JuanC.

3. Потому что это предполагает, что все столбцы, которые я хочу изменить, находятся после первого

4. Я думаю, @JuanC, вы искали что-то вроде моего второго решения:

5. Теперь мое отредактированное решение работает так, как вы хотите, @JuanC.