Переименование нескольких переменных с символами в одном столбце в R

#r

Вопрос:

У меня есть df:

 A       B                       C
NP     All M4                   6
NP     All M4                   8
NP     All FBS                  3
NI     C1_D2                    8
NI     C1D9: PT PI-4, A,B AM1   6
NI     C1D9: PT P3,4 B,E A6     9
NN     W1D5: PRE                2
NN     W1D5: PRE                6
NI     W1D5: PRE                5
 
 A <- c("NP", "NP", "NP", "NI", "NI", "N1", "NN", "NN", "N1")
B <- c("All M4", "All M4", "All FBS", "C1_D2", "C1D9: PT PI-4, A,B AM1", "C1D9: PT P3,4 B,E A6 ", "W1D5: PRE", "W1D5: PRE", "W1D5: PRE")
C <- c("6","8","3","8","6","9","2","6","5")

df <- data.frame(A, B, C)
df
 

И я хотел бы переименовать переменные в столбце B, а затем сгруппировать по столбцам A и D, чтобы получить сумму столбцов C. Мой текущий код до сих пор:

 df2 <- df %>% 
 mutate(D = case_when(
 startsWith(B, "All") ~ "ALL",
 startsWith(B, "C1_D") ~ "CASE 1 DEAL 2",
 startsWith(B, "C1D9") ~ "CASE 1 DEAL 9",
 startsWith(B, "W1D5") ~ "WELL 1 DEAL 5",
)) %>%
group_by(A, D) %>% summaries(C =n())
 

Я получаю код ошибки: проблема с вводом mutate() В случае x 3 (Начало с(B, «Все» ~ «ВСЕ») должно быть двусторонней формулой, а не вектором символов.
Любой другой способ более эффективного написания кода был бы признателен, так как я не предпочитаю использовать базу R.

df2 должен выглядеть так

 A   D                 C
NP  ALL               17
NI  CASE 1 DEAL 2     8
NI  CASE 1 DEAL 9     15
NN  WELL 1 DEAL 5     8
NI  WELL 1 DEAL 5     5
 

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

1. Вы хотите изменить всю строку или только начальную часть?

2. Привет, Крис, спасибо за ваш запрос. Я добавил, каким должен быть выход df2. Так что в принципе мне все равно, если столбец B перенесут в df2. Также они так, как я написал свой код, я создаю новый столбец D на основе столбца B. Но изменение переменных в столбце df B на ВСЕ, ВАРИАНТ 1, СДЕЛКА 2 и так далее Также было бы нормально.

3. См.Отредактированное решение. Помогает ли это?

4. В отличие от ответов ниже, я получаю ожидаемый результат без необходимости перехода startsWith на другую функцию, если исправлю пару ошибок (измените N1 на NI и измените summaries(C =n()) на summarise(C =sum(as.integer(N))) . Однако я использую R 4.1.1, где stringsAsFactors аргумент по data.frame умолчанию FALSE равен . Я подозреваю, что ошибка, которую вы получаете, может быть вызвана использованием более старой версии R, где этот аргумент по умолчанию TRUE равен . (Однако вы всегда можете явно установить это FALSE значение.)

5. Я должен добавить, что использование одной из тех других функций, предложенных в ответах (которые, как я полагаю, имеют дело со строками как факторами, принудительно возвращая данные в строку) вместо использования startsWith , также является прекрасным вариантом. Но я хотел добавить комментарий выше, просто чтобы уточнить, почему ваш первоначальный подход не увенчался успехом.

Ответ №1:

Это то, что тебе нужно?

 library(dplyr)
df %>%
  mutate(D = case_when(grepl("^All", B) ~ "ALL",
                       grepl("^C1_D", B) ~ "CASE 1 DEAL 2",
                       grepl("^C1D9", B) ~ "CASE 1 DEAL 9",
                       grepl("^W1D5", B) ~ "WELL 1 DEAL 5")) %>%
  group_by(A,D) %>%
  summarise(C = sum(as.numeric(C)))
# A tibble: 6 x 3
# Groups:   A [4]
  A     D                 C
  <chr> <chr>         <dbl>
1 N1    CASE 1 DEAL 9     9
2 N1    WELL 1 DEAL 5     5
3 NI    CASE 1 DEAL 2     8
4 NI    CASE 1 DEAL 9     6
5 NN    WELL 1 DEAL 5     8
6 NP    ALL              17
 

Ответ №2:

  1. str_detect из stringr пакета для обнаружения строк
  2. группа и summarise группа sum С
 df %>% 
    type.convert(as.is=TRUE) %>% 
    mutate(D = case_when(
        str_detect(B, "All") ~ "ALL",
        str_detect(B, "C1_D") ~ "CASE 1 DEAL 2",
        str_detect(B, "C1D9") ~ "CASE 1 DEAL 9",
        str_detect(B, "W1D5") ~ "WELL 1 DEAL 5",
        TRUE ~ NA_character_)) %>%
    group_by(D, A) %>% 
    summarise(C = sum(C)) %>% 
    select(A, D, C)
 
  A     D                 C
  <chr> <chr>         <int>
1 NP    ALL              17
2 NI    CASE 1 DEAL 2     8
3 N1    CASE 1 DEAL 9     9
4 NI    CASE 1 DEAL 9     6
5 N1    WELL 1 DEAL 5     5
6 NN    WELL 1 DEAL 5     8
 

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

1. примерно в то же время, что и ваше редактирование. твоя первая попытка была еще одной. поэтому я уйду! Поскольку ваше решение является хорошим, я проголосовал за него!

Ответ №3:

Мы можем создать набор данных ключ/значение и выполнить fuzzyjoin

 library(dplyr)
library(fuzzyjoin)

keydat <- tibble(B2 = c("All", "C1_D", "C1D9", "W1D5"),
    D = c("ALL", "CASE 1 DEAL 2", "CASE 1 DEAL 9", "WELL 1 DEAL 5"))
regex_left_join(df, keydat, by = c("B" = "B2")) %>%
      select(-B2) %>%
      group_by(D, A) %>% 
      summarise(C = sum(as.numeric(C)), .groups = 'drop')
# A tibble: 6 x 3
  D             A         C
  <chr>         <chr> <dbl>
1 ALL           NP       17
2 CASE 1 DEAL 2 NI        8
3 CASE 1 DEAL 9 N1        9
4 CASE 1 DEAL 9 NI        6
5 WELL 1 DEAL 5 N1        5
6 WELL 1 DEAL 5 NN        8