【问题标题】:R - find name in string that matches a lookup field using regexR - 使用正则表达式在字符串中查找与查找字段匹配的名称
【发布时间】:2016-05-18 02:52:12
【问题描述】:

我有一个宠物广告列表数据框:

ID    Ad_title
1     1 year old ball python
2     Young red Blood python. - For Sale
3     1 Year Old Male Bearded Dragon - For Sale

我想使用 Ad_listing 中的通用名称(即 ball pyton)并使用该物种的拉丁名称创建一个新字段。为了提供帮助,我还有另一个包含拉丁名称和常用名称的数据框:

ID    Latin_name           Common_name
1     Python regius        E: Ball Python, Royal Python G: Königspython
2     Python brongersmai   E: Red Blood Python, Malaysian Blood Python
3     Pogona barbata       E: Eastern Bearded Dragon, Bearded Dragon

我该怎么做呢?棘手的部分是通用名称隐藏在广告列表和 Common_name 中的文本之间。如果不是这样,我可以使用 %in%。如果有使用正则表达式的方法/功能,我认为这会有所帮助。

【问题讨论】:

  • 您的输入文件都是字符串,对吧?您是否尝试过修改第二个数据框,使其成为所有常用名称的列表/向量?

标签: sql regex r gsub stringr


【解决方案1】:

另一个答案很好地概述了一般逻辑,所以这里有一些关于简单(虽然没有优化!!)方法的想法:

首先,您需要制作一个大表,其中包含所有“常用名称”的两列(每个名称都有自己的一行)以及它的拉丁名称。你也可以在这里制作字典,但我喜欢表格。

    reference_table <- data.frame(common = c("cat", "kitty", "dog"), technical = c("feline", "feline", "canine"))

  common technical
1    cat    feline
2  kitty    feline
3    dog    canine

从这里开始,只需循环遍历“ad_title”的每个元素(使用 apply() 或 for 循环,具体取决于您的偏好)。现在使用这样的东西:

apply(reference_table,1, function(X) {
if (length(grep(X$common, ad_title)) > 0){ #If the common name was found in the ad_title
[code to replace the string]})

要插入新字符串,请使用常规正则表达式工具。或者,使用 strsplit(ad_title, X$common)。您将能够使用 paste() 重建 ad_title,以及组成 strsplit 的部分。

同样,这不是最好的方法,但希望逻辑很简单。

【讨论】:

  • 逻辑帮助了我很多,谢谢。我的问题是有时广告列表中的通用名称与查找表中的拼写略有不同,因此 grep 不计算在内。例如,在广告中它可能是“Bearded-Dragon”,但它没有被 grep 拾取,因为在查找中它是“Bearded Dragon”。我担心我可能需要为这些情况构建自定义正则表达式。
【解决方案2】:

好吧,我尝试为您的要求创建一个可行的解决方案。不过,可能有更好的方法来执行它,可能使用诸如data.table 和/或stringr 之类的包。无论如何,这个 sn-p 可能是一个工作起点。哦,我稍微修改了Ad_title 数据,使物种名称采用标题格式。

# Re-create data
Ad_title <- c("1 year old Ball Python", "Young Red Blood Python. - For Sale",
              "1 Year Old Male Bearded Dragon - For Sale")
df2 <- data.frame(Latin_name = c("Python regius", "Python brongersmai", "Pogona barbata"),
                  Common_name = c("E: Ball Python, Royal Python G: Königspython",
                                  "E: Red Blood Python, Malaysian Blood Python",
                                  "E: Eastern Bearded Dragon, Bearded Dragon"),
                  stringsAsFactors = F)

# Aggregate common names
Common_name <- paste(df2$Common_name, collapse = ", ")
Common_name <- unlist(strsplit(Common_name, "(E: )|( G: )|(, )"))
Common_name <- Common_name[Common_name != ""]

# Data frame latin names vs common names
df3 <- data.frame(Common_name, Latin_name = sapply(Common_name, grep, df2$Common_name),
                  row.names = NULL, stringsAsFactors = F)
df3$Latin_name <- df2$Latin_name[df3$Latin_name]

# Data frame Ad vs common names
Ad_Common_name <- unlist(sapply(Common_name, grep, Ad_title))
df4 <- data.frame(Ad_title, Common_name = sapply(1:3, function(i) names(Ad_Common_name[Ad_Common_name==i])),
                  stringsAsFactors = F)

【讨论】:

    【解决方案3】:

    显然,在执行简单的正则表达式之前,您需要一个用于所有常用名称查找表的循环结构和另一个以逗号分隔此复合字段的循环。没有理智的正则表达式可以做到这一切。 将来避免使用需要打包和拆包的打包/复合结构。它看起来很适合人类消费,但在语义上和计算机程序消费中,您有多个数据值打包在单个字段中,即它不是“通用名称”,而是用逗号分隔的“通用名称”。

    对不起,如果我没有提供 R 或任何具体的答案。我是一名技术老手,根据问题和可用资源使用多种语言/技术。您将需要遍历拉丁名称查找表的每条记录,在其中您需要遍历“通用名称”的逗号分隔压缩字段,因此您一次使用一个通用名称。使用您使用正则表达式或任何可用的方法在整个输入文件中搜索/替换的单个通用名称。很简单,您需要从那一端开始,即查找表。你需要迭代/循环通过它。您应该熟悉迭代/循环,因为它是任何程序/脚本的基本构建块。这种程序逻辑不是正则表达式本身的能力(或所需功能)的一部分。我假设你知道如何在 R 或任何你使用的东西中创建一个迭代构造。

    【讨论】:

    • 你能详细说明你所说的循环结构是什么意思吗?另外,我希望我的数据结构更好——这样不是一个选择。
    猜你喜欢
    • 2015-06-15
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 2015-04-02
    相关资源
    最近更新 更多