【问题标题】:Improve performance of replacing multiple strings提高替换多个字符串的性能
【发布时间】:2021-12-30 06:48:47
【问题描述】:

我在原始数据中隐藏了电话号码和个人姓名。我已经为我关于电话号码的工作询问并得到了here 的答案。

在屏蔽个人姓名的情况下,我有以下代码:

x = c("010-1234-5678",
      "John 010-8888-8888",
      "Phone: 010-1111-2222",
      "Peter 018.1111.3333",
      "Year(2007,2019,2020)",
      "Alice 01077776666")

df = data.frame(
  phoneNumber = x
)

delName = c("John", "Peter", "Alice")

for (name in delName) {
  df$phoneNumber <- gsub(name, "anonymous", df$phoneNumber)
}

那个代码对我来说不是问题,

> df
              phoneNumber
1           010-1234-5678
2 anonymous 010-8888-8888
3    Phone: 010-1111-2222
4 anonymous 018.1111.3333
5    Year(2007,2019,2020)
6   anonymous 01077776666

但我有超过 10,000 个个人姓名要掩盖。 R 现在正在处理第 789 个进程。时间可以解决,但我想知道减少处理时间的方法。我搜索了foreach,但我不知道如何调整我上面的原始代码。

【问题讨论】:

    标签: r performance foreach parallel-processing gsub


    【解决方案1】:

    这是另一个使用stringr 的选项,它比gsub 更快。

    library(stringr)
    
    str_replace_all(
      string = df$phoneNumber,
      pattern = paste(delName, collapse = '|'),
      replacement = "anonymous"
    )
    
    # [1] "010-1234-5678"          
    # [2] "anonymous 010-8888-8888"
    # [3] "Phone: 010-1111-2222"   
    # [4] "anonymous 018.1111.3333"
    # [5] "Year(2007,2019,2020)"   
    # [6] "anonymous 01077776666" 
    

    基准测试(感谢 @jay.sf 的 df2!)

    df2 <- df[sample(nrow(df), 1e5, replace=T),,drop=F]
    dim(df2)
    # [1] 100000      1
    
    bench::mark(
      stringr = str_replace_all(
        string = df2$phoneNumber,
        pattern = paste(delName, collapse = '|'),
        replacement = "anonymous"
      ),
      gsub = gsub(delNamec, 'anonymous', df2$phoneNumber)
    )
    
    # A tibble: 2 × 13
    #  expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time  
    #  <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
    # 1 stringr      45.4ms   46.7ms     20.9      781KB        0    11     0      525ms
    # 2 gsub           97ms  111.8ms      9.18     781KB        0     5     0      544ms
    

    【讨论】:

    • 感谢您的回答和基准示例,但就我而言,stringrgsub 的性能并没有显着差异。我把数据数改成了1e7,但是stringrgsub分别花费了3.45s和4.08s。
    • 我可以解决以下错误信息吗?我考虑将列表按 600 个名称拆分,但有些列表有超过 13,000 个名称。 Error in gsub(delNamec, "anonymous", emrMaster$cardex) : assertion 'tree-&gt;num_tags == num_tags' failed in executing regexp: file 'tre-compile.c', line 634
    • @InhoLee 这可能取决于第 634 行的内容,因为它在错误消息中。我不确定我是否可以在没有更多上下文的情况下确定它是什么。您最好发布一个新问题来解决该特定问题。
    • 好的,感谢您的补充意见! :D
    【解决方案2】:

    您可以先尝试不使用循环,然后将 paste 字符串与 \ 一起尝试。

    (delNamec <- paste(delName, collapse='|'))
    # [1] "John|Peter|Alice"
    
    gsub(delNamec, 'anonymous', df$phoneNumber)
    # [1] "010-1234-5678"          
    # [2] "anonymous 010-8888-8888"
    # [3] "Phone: 010-1111-2222"   
    # [4] "anonymous 018.1111.3333"
    # [5] "Year(2007,2019,2020)"   
    # [6] "anonymous 01077776666" 
    

    眨眼间运行,即使有 10 万行。

    df2 <- df[sample(nrow(df), 1e5, replace=T),,drop=F]
    dim(df2)
    # [1] 100000      1
    system.time(gsub(delNamec, 'anonymous', df2$phoneNumber))
    #  user  system elapsed 
    # 0.129   0.000   0.129 
    

    【讨论】:

    • 感谢您的回答! :D
    猜你喜欢
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 2016-02-25
    相关资源
    最近更新 更多