【问题标题】:How to efficiently match and combine strings in data.table如何有效地匹配和组合 data.table 中的字符串
【发布时间】:2019-03-13 17:12:18
【问题描述】:

考虑一个示例数据集:

dt <- data.table(data.frame(V1 = c("C1/R3","M2/R4")))
> dt
      V1
1: C1/R3
2: M2/R4

对于dt 的每一行,我想提取连接的字符 C、M 或 R。例如,

dt[,V2 := stri_join_list(str_match_all(V1,"[CMR],sep="",collapse=""),by=seq_len(nrow(dt))]
> dt
         V1 V2
1:    C1/R3 CR
2:    M2/R4 MR

但是,我有 4200 万行,上面的代码还不够高效。有没有办法在不使用逐行操作的情况下做到这一点?当我跳过 by 参数时,我会为每一行获得条目 CRMR

【问题讨论】:

  • 这些不是矢量化函数,因此您不需要by=? - dt[,V2 := stri_join_list(str_match_all(V1,"[CMR]"))] - 我不确定你是如何得到 NA 值的,但你可能希望在你的示例中包含一个这样做的行。
  • 您能否澄清一下,在您的真实数据中:1)所有的字母都是大写的吗? 2) 模式是否始终只是 1 个字母后跟一个数字,然后是 / 后跟 1 个字母,后跟一个数字 - 如果不是,请指定字母和数字的重复长度,例如任何长度?因为效率对您很重要,包括这些细节将有助于防止过度概括(可能较慢)的解决方案,或者避免过度简化的解决方案(作为一个公平的假设)正确解决您提出的问题。
  • @thelatemail,将其矢量化实际上会从所有行组合中返回 [CMR]。 IE,两个条目都是“CRMR”。
  • @krads,更新示例。
  • @hipHopMetropolisHastings - 使用我建议的矢量化代码有效。根据更新前的原始dt,它为第一行提供CR,为第二行提供MR。您需要删除代码中的collapse=""(而不是我的代码)。

标签: r string data.table


【解决方案1】:

一个选项使用sub

dt <- data.table(data.frame(V1 = c("C1/R3","M2/R4")))
dt$V2 <- sub("^([A-Z]+)[0-9]+/([A-Z]+)[0-9]+", "\\1\\2", dt$V1)
dt
     V1 V2
1 C1/R3 CR
2 M2/R4 MR

Demo

【讨论】:

    【解决方案2】:

    如您所说,如果您希望将字母 C、M 和 R 捕获到您的 data.table 的新列中,那么通过就地分配应该可以有效地执行以下操作:

    dt[, V2 := gsub('[^CMR]', '', V1, perl=TRUE, useBytes=TRUE)]
    

    模式[^CMR] 匹配任何 C M 或R 的字符,然后我们替换为空字符串''

    根据?gsub的帮助:“如果可以使用useBytes = TRUE,则匹配前不会检查字符串,实际匹配会更快。”

    最后,根据我的阅读,使用perl=TRUE 我相信应该比省略它更快。但是,也许您可​​以测试两种方式并使用您的真实数据回复结果以向我们确认?

    【讨论】:

    • 所以有一些额外的值包含[CMR],但不是上述格式。例如,有一个名称“ZMR 14-B”,我想为其捕获“NA”。稍后将使用更完整的示例更新问题。我想捕获所有“[CMR](?=\d)”,但使用“[^[CMR](?=\d)]”只是捕获第一个实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 2017-11-23
    • 2014-05-19
    • 1970-01-01
    相关资源
    最近更新 更多