str_replace внутри mutate(через()), соответствующий n-му символу из cur_column

#r #str-replace #dplyr #across

#r #str-заменить #dplyr #через

Вопрос:

Краткое изложение моей цели

У меня есть следующая структура фрейма данных:

 my.df <-data.frame("col1_A.C"=c("AA","AC","CC"),
                   "col2_A.T"=c("TT","AT","TT"),
                   "col3_C.G"=c("GG","CG","CG"))

my.df
#   col1_A.C col2_A.T col1_C.G
# 1       AA       TT       GG
# 2       AC       AT       CG
# 3       CC       TT       CG
  

Для каждого столбца я хочу заменить любой символ, который соответствует 3-му последнему символу имени столбца, символом «R».

Таким образом, используя приведенный выше фрейм данных, я хотел бы получить это:

 my.df2 <- data.frame("col1_A.C"=c("RR","RC","CC"),
                   "col2_A.T"=c("TT","RT","TT"),
                   "col3_C.G"=c("GG","RG","RG"))

my.df2
#   col1_A.C col2_A.T col1_C.G
# 1       RR       TT       GG
# 2       RC       RT       RG
# 3       CC       TT       RG
  

Например, в первом столбце имя столбца равно col1_A.C, а A — 3-й последний символ. Таким образом, все буквы A были заменены на R.

Мой код до сих пор

Для достижения этой цели я создал следующий код

 my.df2 <- my.df %>% mutate(across(.cols=everything(),
                                  .funs=str_replace_all(.,
                                                        substr(cur_column(),
                                                               nchar(cur_column()-2),
                                                               nchar(cur_column()-2)
                                                              ),
                                                        "R")
                                  )
                           )
  

К сожалению, результирующий фрейм данных my.df2 выглядит точно так же, как my.df, и замены символов не произошло. Хотя ошибка не возвращается.

Я протестировал подход str_replace_all() следующим образом, и он работает с вектором. Я полагаю, тогда есть что-то, чего я не понимаю / не понимаю в том, как str_replace_all() интерпретируется в функции mutate(across()) .

 first.column <- c("CC","CT","CC")

first.column <- str_replace_all(first.column,
                                substr(colnames(my.df)[1],
                                       nchar(colnames(my.df)[1])-2,
                                       nchar(colnames(my.df)[1])-2
                                       ),
                                "R")
print(first.column)
# [1] "RR" "RT" "RR"
  

У меня закончились идеи о том, что может не работать. Мое понимание R и его функций не очень полное, поэтому я приношу извинения, если я пропустил что-то простое. Я также искал похожие вопросы, но безрезультатно.

Ответ №1:

Я думаю, вам просто нужна была тильда ~ , и использовать .fns вместо .funs .

 my.df %>% 
  mutate(
    across(
      .cols = everything(),
      .fns = ~ str_replace_all(
        string = ..1, 
        pattern = str_sub(cur_column(), nchar(cur_column()) - 2, nchar(cur_column()) - 2), 
        replacement = "R"
      )
    )
  )
  

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

1. 1, потому что он исправляет исходный код, которым я поделился. Но я сохраняю ответ Ронака как принятый, поскольку он быстрее. @Ronak ‘ # пользовательская система истекла # 0.002 0.000 0.001 ‘ CourtesyBus ‘ # пользовательская система истекла # 0.004 0.000 0.004 ‘

2. Кроме того, что делает ‘string = ..1’?

3. да, согласен, что базовое R-решение более эффективно. ..1 является заполнителем для вашей .cols справки. вы можете использовать .x или просто . (как вы делали в своем исходном коде), но я предпочитаю ..1

4. Работал с <.> вместо <..1>

Ответ №2:

Вы можете использовать Map :

 my.df[] <- Map(function(x, y) gsub(y, 'R', x), my.df, 
      substring(names(my.df), nchar(names(my.df)) - 2,nchar(names(my.df)) - 2))

my.df
#  col1_A.C col2_A.T col3_C.G
31       RR       TT       GG
#2       RC       RT       RG
#3       CC       TT       RG
  

Используя chartr трюк @thelatemail с imap_dfc помощью from purrr :

 purrr::imap_dfc(my.df, ~chartr(substr(.y, nchar(.y)-2, nchar(.y)-2), 'R', .x))
  

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

1. У меня была похожая мысль, но chartr вместо этого я использовал — my.df[] <- Map(chartr, my.df, old=substr(names(my.df), nchar(names(my.df))-2, nchar(names(my.df))-2), new='R')

2. Ронак, посмотрел функцию Map, поэтому, чтобы правильно понять, функция substring возвращает vector (‘A’,’A’,’C’). Итак, на первой итерации y в gsub — это ‘A’, а x — первый столбец «col1_A.C», следовательно, A заменяется на ‘R’, а на второй итерации y снова ‘A’, а x — второй столбец и так далее .. Правильно ли я понимаю?

Ответ №3:

То же самое может быть достигнуто путем первого преобразования ваших данных из широкого в длинный формат:

 library(tidyverse)

my.df %>%
  gather(colx, rowx) %>%
  mutate(rowx = str_replace_all(rowx, substring(colx, nchar(colx) - 2, nchar(colx) - 
                  2), "R")) %>%
  group_by(colx) %>% 
  mutate(id = row_number()) %>%
  pivot_wider(names_from = colx, values_from = rowx)