【问题标题】:R: gsub only if negation occurs within n letters before the targetR:仅当否定出现在目标之前的 n 个字母内时才使用 gsub
【发布时间】:2016-10-28 17:04:32
【问题描述】:

我正在研究一种原始语音分析算法。现在我想改进它如何处理正面/负面陈述的否定。目前,我仅在否定直接发生时才添加字符串“NOT_”:

s_commentsOut$gsubContent <- gsub("not ","not NOT_",gsub("n't ","n't NOT_",s_commentsOut$lowCo))

例如

"This is not good"

变成

"This is not NOT_good"

现在我想实现当目标词向量和否定之间有n个字符时也添加“NOT_”,例如:

targetList <- c("nice", "perfect", "good", "love")

现在借助上面的列表,下面的字符串:

"This isn't a very good way"

应该变成

"This isn't a very NOT_good way"

仅当否定出现在目标之前的n(例如15)字符时,才应进行此替换,例如以下不应该转换(因为目标和否定之间的距离是&gt; 15):

"This is not going to work. However you did this very nicely."

我发现了以下 SO 文章: Negation of several characters before pattern

How to replace a character in a string but only if it occurs within a delimited substring?

但我很难做到正确。与此同时,我帮助自己从文本中删除诸如“like”、“an”、“a”之类的字符串......

进一步的测试短语:

"Nottingham is the love of my life."

"This is good. Nottingham is a town."

"This is not very good"

"This is not good. This is not good. This is not very good. This is nice. This very nice. This is not very nice."

【问题讨论】:

  • 第n个字符的东西是从哪里来的? ifelse(grepl('not|n\'t', x), gsub(sprintf("(?=%s)", paste(targetList, collapse = '|')), "NOT_", x, perl = TRUE), x)
  • 谢谢@rawr - 我编辑了上面的帖子以使其更清晰。

标签: r regex gsub negation


【解决方案1】:

这应该可以工作(用 n 更新)

library(stringr)
negation=function(x,n)
{
  target=c("nice", "perfect", "good")
  negate=c("not ","n't")
  out=x
  a=as.data.frame(str_locate(x,negate))
  negate_end=as.numeric(a[!is.na(a$end),]$end)
  b=as.data.frame(str_locate(x,target))
  target_start=as.numeric(b[!is.na(b$start),]$start)
  distance=target_start-negate_end
  distance=ifelse(length(distance)==0,9999999,distance)
  if(sum(!is.na(str_match(x,target)))>0 & distance<=n & distance>=0)
    out=str_replace_all(x,target,paste("NOT_",target,sep=''))[which(!is.na(str_match(x,target)))]
  return(out)
}

【讨论】:

  • 你在哪里定义n?对于n,我的意思是在notn't 之类的否定存在的情况下,商品将被否定的字母数量。
  • 抱歉 florian 之前错过了 n..现在检查它应该可以工作
  • 谢谢你,我们已经接近了,但我们还没有完全做到。 Atm 似乎考虑了 15 个字符附近的否定,但它应该只考虑前面的否定。像诺丁汉这样的词也不应该触发它:测试:negation("This is good. Nottingham is a town.", 15) 返回:"This is NOT_good. Nottingham is a town."
  • 谢谢弗洛里安。它实际上不是在诺丁汉识别,而是在不存在否定词的情况下努力否定。我已经更正了脚本以现在处理它。另外,如果您可以为我提供更多的测试输入和输出,那么我可以对其进行微调(以防更新的脚本不起作用)
  • 谢谢...嗯,现在我尝试将它应用到包含 500k 文本元素的向量中,但收到以下警告:s_commentsOut$gsubContent &lt;- lapply(s_commentsOut$lowCo, function(x) { negation(x, 15) })Warning messages: 1: In target_start - negate_end : longer object length is not a multiple of shorter object length
【解决方案2】:

您可以尝试以下方法:(请进行测试,因为我不是 100% 确定)

require(stringr)
negate <- function(word, phrase, distance_allowed){

  not_pos <- str_locate(tolower(phrase), "^not |not$| not ")

  if (!is.na(not_pos[1])){

      word_pos <- str_locate(tolower(phrase), word)

      if(!is.na(word_pos[1])){

          neg_dist <- ifelse(word_pos[1] > not_pos[1], word_pos[2] - not_pos[1], not_pos[2] - word_pos[1])

        if(neg_dist < distance_allowed ){

             phrase <- gsub(word, paste0("NOT_", word), phrase)

        }


      }

  }
      return(phrase)

}

我的谦虚逻辑如下:

  1. 在短语中查找 not(它要么开始短语,在单词之间,要么结束它,只是为了避免像什么都没有的单词,因为我不太擅长讨厌的正则表达式)

  2. 如果没有找到单词的位置,如果找到了单词,则计算not位置与单词之间的距离(如果单词在not之前,则计算单词末尾之间的距离单词和非单词的开头,否则结尾不是单词的开头)

  3. 如果此距离小于您允许的距离(在您的情况下 n = 15),请进行更改

请测试一下!希望对你有帮助

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2017-06-17
相关资源
最近更新 更多