Grep-in-for循环在100万次迭代中检测名称,速度太慢

Grep-in-for循环在100万次迭代中检测名称,速度太慢,r,string,loops,for-loop,R,String,Loops,For Loop,我有一个100万个名字的列表,我想在一个有15万行的列的每个单元格中查找它们。我正在使用Grep逐个查找名称,如果在任何单元格中找到,请将该单元格设置为空白。我正在运行这个循环100万次,但它需要很多时间。 如何加速循环 install.packages("babynames") install.packages("randomNames") names = babynames::babynames ###creating a random dataset for this example te

我有一个100万个名字的列表,我想在一个有15万行的列的每个单元格中查找它们。我正在使用Grep逐个查找名称,如果在任何单元格中找到,请将该单元格设置为空白。我正在运行这个循环100万次,但它需要很多时间。 如何加速循环

install.packages("babynames")
install.packages("randomNames")
names = babynames::babynames ###creating a random dataset for this example
temp_new2= data.frame(names$name) ##temp_new2 is a single column name dataframe

random_names<-strsplit((randomNames(n=1000,
                            which.names="first",
                            name.sep=" ",
                            sample.with.replacement=TRUE,
                            return.complete.data=FALSE
)
),"\n")
count = 0
t=0
list_of_names = list()

for (i in random_names)
    {
      if (length(grep(paste0("\\b",i,"\\b"),temp_new2$cleaned_names,ignore.case = TRUE)) != 0) 
      {
        p = length(grep(paste0("\\b",i,"\\b"),temp_new2$cleaned_names,ignore.case = TRUE))
        print(i)
        list_of_names = append(list_of_names,i)
      }
      else
      {t=0
       p=0
      }

      count = count + p
      temp_new2[grep(paste0("\\b",i,"\\b"),temp_new2$cleaned_names,ignore.case = TRUE),]<- ""

    }
install.packages(“babynames”)
安装程序包(“随机名称”)
names=babynames::babynames####为本例创建随机数据集
temp_new2=data.frame(names$name)35;#temp_new2是一个单列名数据帧

随机命名我玩了一会儿,用microbenchmark得到了以下结果:

microbenchmark::microbenchmark(your_fun(), fun_initialize_list(), fun_list_one_grep(), fun_lapply())
Unit: milliseconds
                  expr      min       lq     mean   median       uq       max neval
            your_fun() 51.02420 52.61047 55.19147 54.20093 55.98069  77.55637   100
 fun_initialize_list() 50.86644 52.81099 55.52799 54.23134 56.37564 102.21945   100
   fun_list_one_grep() 25.68943 26.31398 28.51748 27.73832 28.46759  56.01566   100
          fun_lapply() 25.22339 26.02261 27.83738 27.26183 27.90310  43.80443   100
函数定义如下,只是不同过程的包装器。正如@RuiBarradas已经指出的,
grep
调用执行了3次。 在我的例子中,减少这个,将执行时间减少50%

你的方法

your_fun <- function() {

  count <- 0
  t <- 0
  list_of_names <- list()

  for (i in random_names) {
    if (length(grep(paste0("\\b",i,"\\b"), temp_new2$cleaned_names,ignore.case = TRUE)) != 0) {
      p <- length(grep(paste0("\\b",i,"\\b"), temp_new2$cleaned_names,ignore.case = TRUE))
      list_of_names <- append(list_of_names,i)
    } else {
      t <- 0
      p <- 0
    }
    count <- count + p
    temp_new2[grep(paste0("\\b",i,"\\b"),temp_new2$cleaned_names,ignore.case = TRUE),] <- ""
  }

}
仅使用一次呼叫grep

fun_list_one_grep <- function() {
  count <- 0
  t <- 0
  list_of_names <- logical(length(random_names))
  k <- 0

  for (i in random_names) {
    k <- k + 1
    name_match <- grep(paste0("\\b",i,"\\b"), temp_new2$cleaned_names, ignore.case = TRUE)
    len_match <- length(name_match)
    if (len_match != 0) {
      p <- len_match
      list_of_names[k] <- TRUE
    } else {
      t <- 0
      p <- 0
      list_of_names[k] <- FALSE
    }
    count <- count + p
    temp_new2[name_match, ] <- ""
  }

  list_of_names <- random_names[list_of_names]
}

fun\u list\u one\u grep
list\u of\u names=list()
这可能是您的起点。您正在使用for looop增加一个列表,这会使您的代码变慢。使用适当的长度初始化列表。请尝试为您的问题提供一个可复制的示例。什么是随机的名字?temp_new2看起来怎么样?使用
dput
dput(head(您的数据))
并查看名称列表,您的名称将包含将在temp\u new2数据列中匹配的100万个名称中的名称。因此,我无法确定列表中的元素数量。请使用其他信息编辑问题,不要将其放入评论中。可能(容易)加入问题。。但是先发布一些示例数据….,请参阅@kathYou的评论,您在循环中运行了非常相同的
grep
3次!!!其中至少有两个将始终执行。在我的测试中,只需一次调用,
grep
就占了总执行时间的99%。还有
stringr::stru detect
,在字符串和模式上都进行了向量化。
fun_list_one_grep <- function() {
  count <- 0
  t <- 0
  list_of_names <- logical(length(random_names))
  k <- 0

  for (i in random_names) {
    k <- k + 1
    name_match <- grep(paste0("\\b",i,"\\b"), temp_new2$cleaned_names, ignore.case = TRUE)
    len_match <- length(name_match)
    if (len_match != 0) {
      p <- len_match
      list_of_names[k] <- TRUE
    } else {
      t <- 0
      p <- 0
      list_of_names[k] <- FALSE
    }
    count <- count + p
    temp_new2[name_match, ] <- ""
  }

  list_of_names <- random_names[list_of_names]
}
fun_lapply <- function() {
  random_matches <- lapply(random_names, function(i) {
    grep(paste0("\\b",i,"\\b"), temp_new2$cleaned_names, ignore.case = TRUE)
  })

  temp_new2[unlist(random_matches), ] <- ""
  count <- length(unique(unlist(random_matches)))

  list_of_names <- random_names[!sapply(random_matches, is.null)]
}
names = babynames::babynames ###creating a random dataset for this example
temp_new2 = data.frame(cleaned_names = names$name[1:1000], 
                       stringsAsFactors = FALSE) ##temp_new2 is a single column name dataframe

set.seed(23)

random_names <- strsplit((
  randomNames::randomNames(
    n = 100,
    which.names = "first",
    name.sep = " ",
    sample.with.replacement = TRUE,
    return.complete.data = FALSE
  )), "\n")