【问题标题】:R - How to count the occurence of a specific string for large textfilesR - 如何计算大型文本文件中特定字符串的出现次数
【发布时间】:2015-09-29 15:06:52
【问题描述】:

我试图在电子邮件列表中找到大约 10.000 个不同位置的出现。 我需要的是每个电子邮件中最常提及位置的一个向量,一个第二个最频繁的向量,一个第三个最频繁的向量!

由于我的数据集很大,我的性能存在问题。我用 stringi 和并行包尝试了它,但它仍然运行得很慢(20.000 个电子邮件和 10.000 个位置大约需要 15 分钟)。 输入数据(电子邮件和城市)如下所示:

SearchVector = c('Berlin, 'Amsterdam', San Francisco', 'Los Angeles') ...
g$Message = c('This is the first mail from paris. Berlin is a nice place', 'This is the 2nd mail from San francisco. Beirut is a nice place to stay', 'This is the 3rd mail. Los Angeles is a great place') ...

这是我使用 stringi 的代码:

# libraries
library(doParallel)
library(stringi)

detectCores()
registerDoParallel(cores=7)
getDoParWorkers()

# function
getCount <- function(data, keyword)
{ 
  keyword2 = paste0( "^(", keyword, ")|(", keyword, ")$|[ ](", keyword, ")[ ]" )
  wcount <- stri_count(data, regex=keyword2)
  return(data.frame(wcount))
}

SearchVector = as.vector(countryList2)
Text = g$Message

cityName1 = character()
cityName2 = character()

result = foreach(i=Text, .combine=rbind, .inorder=FALSE, .packages=c('stringi'), .errorhandling=c('remove')) %dopar% 
{

  cities = as.data.frame(t(getCount(i, SearchVector)))
  colnames(cities) = SearchVector

  if ( length(cities[which(cities > 0)]) == 1 ) {
    cityName1 = names(sort(cities, decreasing = TRUE))[1]
    cityName2 = NA
  }
  else if ( length(cities[which(cities > 0)]) > 1 ) {
    cityName1 = names(sort(cities, decreasing = TRUE))[1]
    cityName2 = names(sort(cities, decreasing = TRUE))[2] 
  }

  else  {
    cityName1 = NA
    cityName2 = NA 

  }

  return(data.frame(cityName1, cityName2))
}


g$cityName1 = result[, 1]
g$cityName2 = result[, 2]

有什么想法可以通过例如使用索引或等于来加快速度吗? 我真的很期待在这个问题上获得帮助。

非常感谢 克莱门斯

【问题讨论】:

    标签: r parallel-processing stringi


    【解决方案1】:

    评论这个有点太乱了,但试一试:

    library(data.table)
    library(stringr)
    
    dt = data.table(Text = g$Message, cleantext = tolower(g$Message))
    dt[, place := str_extract_all(cleantext, paste0("(", paste(tolower(SearchVector), collapse = ")|("), ")"))]
    

    您在问题中的SearchVector 也缺少一些引号。

    data.table 对于这样的事情通常快如闪电,但在一个子集上尝试一下,看看它是否可以接受的快。

    place 列看起来像一堆用逗号分隔的地名,但在内部它是一个列表,因此很容易进行各种聚合,例如计算每个文本中的位置,计算每个地方被提及的次数等.

    dt[, n := lapply(place, length)]; dt
    nplace = data.table(place = dt[, unlist(place)])[, .N, place]
    

    在搜索好运时,我还将所有文本都更改为小写(这可能不是不区分大小写的最快方法,但对我来说它看起来最明确)。

    【讨论】:

    • 我用 10 封电子邮件测试了代码,它仍在工作(现在超过 2 分钟)。一定是发生了什么奇怪的事情......(“搜索字符串”中有 2500 个位置)
    • 您可以添加这 10 封电子邮件的样本吗?我只是用问题中的 3 试了一下,它在几秒钟内运行。我可以想象,如果情况确实如此,它可能不是合适的解决方案..
    • 哦,没看到。好的,是的,对于字符串搜索来说,这可能有点太长了。实际上,我会采取不同的方法在文本上执行txt = strsplit(..., " "),并将SearchVector[SearchVector %in% txt] 作为函数执行,然后通过数据表调用它。基本上我不认为这必须是并行化的,%in% 会比字符串操作快很多。
    • 我之前尝试过,但很难因为位置有 2 个或更多单词(旧金山等)。在 data.table 中使用索引有什么想法吗?
    • 对于 2 个单词的地点,首先将它们标记化,即在地点列表中搜索 " " 以获取所有超过 1 个单词的地点,然后使用 gsub 遍历每个地点的文本或str_replace 并将 "a b" 替换为 "a@b"。这会很快,因为它只搜索非常少量的字符串,并摆脱了这个问题。不确定您打算如何处理索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-08
    相关资源
    最近更新 更多