【问题标题】:Replacing placeholder values in dataframe with values from another column用另一列中的值替换数据框中的占位符值
【发布时间】:2020-04-17 17:46:55
【问题描述】:

我有一个如下所示的数据框:

df <-
  structure(
    list(
      Exception1 = c(
        "Comments from {2}: {0}",
        "status updated to {1} by {2}. Description:{0}",
        "status updated to {1} by {2}. Description:{0}",
        "information only.",
        "status updated to {1} by {2}. Description:{0}",
        "status updated to {1} by {2}. Description:{0}"
      ),
      Exception2 = c(
        "Customer {0} said bla",
        "Status updated to {1}",
        "Customer said {2}",
        "User {0} foo",
        "{0} {1}",
        "{1} {2}"
      ),
      ARGUMENT1 = c("OK", " ", " ", "PAY9089723089-98391", " ", " "),
      ARGUMENT2 = c(
        "null",
        "Processing",
        "Reconciled",
        "null",
        "Processing",
        "Reconciled"
      ),
      ARGUMENT3 = c(
        "company name",
        "company name",
        "company name",
        "null",
        "company name",
        "company name"
      )
    ),
    row.names = c(NA, 6L),
    class = "data.frame"
  )

| Exception1                                    | Exception2            | ARGUMENT1           | ARGUMENT2  | ARGUMENT3    |
|-----------------------------------------------|-----------------------|---------------------|------------|--------------|
| Comments from {2}: {0}                        | Customer {0} said bla | OK                  | null       | company name |
| status updated to {1} by {2}. Description:{0} | Status updated to {1} |                     | Processing | company name |
| status updated to {1} by {2}. Description:{0} | Customer said {2}     |                     | Reconciled | company name |
| information only.                             | User {0} foo          | PAY9089723089-98391 | null       | null         |
| status updated to {1} by {2}. Description:{0} | {0} {1}               |                     | Processing | company name |
| status updated to {1} by {2}. Description:{0} | {1} {2}               |                     | Reconciled | company name |

Exception1 和 Exception 2 列(为了便于阅读,我删除了另外几个 Exception 列)包含用于替换为 ARGUMENT* 列中的值的占位符 {}。

我一直在寻找实现这一目标的方法,并且相对成功,但我仍然缺乏做得更好的经验。

我写了一个简单的函数,通过 gsub 进行替换:

excp_ren2 <- function(x) {
  x %<>%
    gsub("\\{1\\}", x["ARGUMENT2"], .) %>%
    gsub("\\{0\\}", x["ARGUMENT1"], .) %>%
    gsub("\\{2\\}", x["ARGUMENT3"], .)
  x
}

然后一直在使用 apply 及其差异。例如,我已经完成了一个 OK 的结果:

new_df <-
  df %>% apply(
    .,
    MARGIN = 1,
    FUN = function(x)
      excp_ren2(x)
  ) %>% as.data.frame()

唯一的问题是这会转置矩阵,这并不是真正的问题。

我正在寻找更好的方法来做到这一点,我以为我可以通过 mutate_* 做到这一点,但我认为我无法访问函数内行的列名,或者至少我不知道怎么做。关于更简单的方法来实现这一点的任何想法?

谢谢!

【问题讨论】:

  • 您在所有列上都使用applyMARGIN = 1。我猜你只对第一列感兴趣Exception1 ) 在这种情况下,只需在该列上应用函数

标签: r dplyr


【解决方案1】:

可能是这样的

clean_pipe <- . %>% 
  mutate(new_string = Exception1 %>% str_replace_all(pattern = "\\{0\\}",replacement = ARGUMENT1)) %>% 
  mutate(new_string = new_string %>% str_replace_all(pattern = "\\{1\\}",replacement = ARGUMENT2)) %>% 
  mutate(new_string = new_string %>% str_replace_all(pattern = "\\{2\\}",replacement = ARGUMENT3))

df %>% 
  clean_pipe

【讨论】:

    【解决方案2】:

    我们可以在管道中使用str_replace(矢量化),而不是逐行执行此操作(并将函数应用于每一列而不是'Exception1')

    library(stringr)
    library(dplyr)
    df %>%
      transmute(new =  str_replace_all(Exception1, "\\{1\\}", ARGUMENT2) %>% 
                       str_replace_all("\\{0\\}", ARGUMENT1) %>% 
                       str_replace_all("\\{2\\}", ARGUMENT3))
    #                                                  new
    #1                                  Comments from company name: OK
    #2 status updated to Processing by company name. \\nDescription:\n
    #3 status updated to Reconciled by company name. \\nDescription:\n
    #4                  PCard order invoices are for information only.
    #5 status updated to Processing by company name. \\nDescription:\n
    #6 status updated to Reconciled by company name. \\nDescription:\n
    

    如果我们有多个列,我们可以使用mutate_attransmute_at

    df %>%
       transmute_at(vars(starts_with("Exception")), ~ 
               str_replace_all(., "\\{1\\}", ARGUMENT2) %>% 
                       str_replace_all("\\{0\\}", ARGUMENT1) %>% 
                       str_replace_all("\\{2\\}", ARGUMENT3))
    #                    Exception1                   Exception2
    #1                              Comments from company name: OK         Customer OK said bla
    #2 status updated to Processing by company name. Description:  Status updated to Processing
    #3 status updated to Reconciled by company name. Description:    Customer said company name
    #4                                           information only. User PAY9089723089-98391 foo
    #5 status updated to Processing by company name. Description:                    Processing
    #6 status updated to Reconciled by company name. Description:       Reconciled company name
    

    【讨论】:

    • 这很好,但它只需要一个异常列,还有更多。您建议如何考虑 Exception2、Exception3 和 Exception4?
    • 我编辑了原始帖子,添加了一个额外的异常列,以更好地解释我的意思
    • @PauloCalvo。是否将相同的列“ARGUMENT1”、2、3 应用于所有列?
    • 是的,在所有异常列中替换相同的参数。
    • 太棒了,谢谢,我花了太多时间在 mutate 上,从没看过 transmute。
    【解决方案3】:

    您使用{ } 进行划分的方式让我想到了使用glue,它的操作方式类似。要制作与数据中的列名匹配的胶合模板,首先使用stringr::str_replace_all 中的命名列表来一次性匹配模式和替换。然后从"Exception*" 列创建glue 对象。根据这篇文章 (R dplyr: rowwise + mutate (+glue) - how to get/refer row content?),您需要使用 rowwise,否则它将尝试使用 all 模板的每个参数列的值.我想将两个 mutate_at 步骤放入一个函数中,但在范围界定方面遇到了一些问题,所以这是我能得到的最整洁的工作。

    library(dplyr)
    library(tidyr)
    
    replacements <- c("\\{1\\}" = "{ARGUMENT2}",
                      "\\{0\\}" = "{ARGUMENT1}",
                      "\\{2\\}" = "{ARGUMENT3}")
    
    as_tibble(df) %>%
      rowwise() %>%
      mutate_at(vars(starts_with("Exception")), stringr::str_replace_all, replacements) %>%
      mutate_at(vars(starts_with("Exception")), ~as.character(glue::glue(.)))
    #> Source: local data frame [6 x 5]
    #> Groups: <by row>
    #> 
    #> # A tibble: 6 x 5
    #>   Exception1                  Exception2       ARGUMENT1     ARGUMENT2 ARGUMENT3
    #>   <chr>                       <chr>            <chr>         <chr>     <chr>    
    #> 1 Comments from company name… Customer OK sai… OK            null      company …
    #> 2 "status updated to Process… Status updated … " "           Processi… company …
    #> 3 "status updated to Reconci… Customer said c… " "           Reconcil… company …
    #> 4 information only.           User PAY9089723… PAY908972308… null      null     
    #> 5 "status updated to Process… "  Processing"   " "           Processi… company …
    #> 6 "status updated to Reconci… Reconciled comp… " "           Reconcil… company …
    

    请注意,由于某些字符串是空的,因此您的结果中有多余的空格,您可以使用trimws 进行修剪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-21
      • 2014-03-20
      • 2016-01-03
      相关资源
      最近更新 更多