统计一个词是否出现在400万观察数据集的每一行中
Count if a word occurs in each row of a 4 million observation data set
我正在使用 R 并编写一个脚本来计算在 400 万个观察数据文件的每一行中是否出现约 2000 个单词中的一个。包含观察值 (df) 的数据集包含两列,一列包含文本 (df$lead_paragraph),一列包含日期 (df$date).
使用以下内容,我可以计算列表 (p) 中的任何单词是否出现在 df 文件的 lead_paragraph 列的每一行中,并将答案输出为新列。
df$pcount<-((rowSums(sapply(p, grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
但是,如果我在列表 p 中包含太多单词,运行 代码会导致 R 崩溃。
我的替代策略是将其简单地分解成多个部分,但我想知道是否有更好、更优雅的编码解决方案可用于此处。我倾向于使用 for 循环,但我正在阅读的所有内容都表明这在 R 中不是首选。我是 R 的新手而且不是一个很好的编码员,所以如果不清楚,我深表歉意。
df$pcount1<-((rowSums(sapply(p[1:100], grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
df$pcount2<-((rowSums(sapply(p[101:200], grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
...
df$pcount22<-((rowSums(sapply(p[2101:2200], grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
我没有完成这个...但这应该为您指明了正确的方向。使用 data.table
包速度更快,但希望这能让您了解该过程。
我使用随机日期和字符串重新创建了你的数据集
从 http://www.norvig.com/big.txt 提取到 data.frame
名为 nrv_df
library(stringi)
> head(nrv_df)
lead_para date
1 The Project Gutenberg EBook of The Adventures of Sherlock Holmes 2018-11-16
2 by Sir Arthur Conan Doyle 2019-06-05
3 15 in our series by Sir Arthur Conan Doyle 2017-08-08
4 Copyright laws are changing all over the world Be sure to check the 2014-12-17
5 copyright laws for your country before downloading or redistributing 2016-09-13
6 this or any other Project Gutenberg eBook 2015-06-15
> dim(nrv_df)
[1] 103598 2
I then randomly sampled words from the entire body to get 2000 unique words
> length(p)
[1] 2000
> head(p)
[1] "The" "Project" "Gutenberg" "EBook" "of" "Adventures"
> tail(p)
[1] "accomplice" "engaged" "guessed" "row" "moist" "red"
然后,利用 stringi
包并使用正则表达式匹配完成
单词的情况下,我将每个字符串加入向量 p
中,并且
collapsed then with a |
, 所以我们正在寻找任何带有 word-boundary
的单词
之前或之后:
> p_join2 <- stri_join(sprintf("\b%s\b", p), collapse = "|")
> p_join2
[1] "\bThe\b|\bProject\b|\bGutenberg\b|\bEBook\b|\bof\b|\bAdventures\b|\bSherlock\b|\bHolmes\b|\bby\b|\bSir\b|\bArthur\b|\bConan\b|\bDoyle\b|\b15\b|\bin\b|\bour\b|\bseries\b|\bCopyright\b|\blaws\b|\bare\b|\bchanging\b|\ball\b|\bover\b|\bthe\b|\bworld\b|\bBe\b|\bsure\b|\bto\b|\bcheck\b|\bcopyright\b|\bfor\b|\byour\b|\bcountry\b|..."
然后简单地计算单词数,您可以nrv_df$counts <-
将其添加为一列...
> stri_count_regex(nrv_df$lead_para[25000:26000], p_join2, stri_opts_regex(case_insensitive = TRUE))
[1] 12 11 8 13 7 7 6 7 6 8 12 1 6 7 8 3 5 3 5 5 5 4 7 5 5 5 5 5 10 2 8 13 5 8 9 7 6 5 7 5 9 8 7 5 7 8 5 6 0 8 6
[52] 3 4 0 10 7 9 8 4 6 8 8 7 6 6 6 0 3 5 4 7 6 5 7 10 8 10 10 11
编辑:
因为查找匹配项的数量无关紧要...
首先是一个函数,用于对每个段落进行处理,并检测 p2
中的任何 stirngs 是否存在于 lead_paragraph
的正文中
f <- function(i, j){
if(any(stri_detect_fixed(i, j, omit_no_match = TRUE))){
1
}else {
0
}
}
现在...在 linux 上使用 parallel
库。并且只测试 1000 行,因为它是一个例子给了我们:
library(parallel)
library(stringi)
> rst <- mcmapply(function(x){
f(i = x, j = p2)
}, vdf2$lead_paragraph[1:1000],
mc.cores = detectCores() - 2,
USE.NAMES = FALSE)
> rst
[1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[70] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[139] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
[208] 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[277] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[346] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1
[415] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[484] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[553] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[622] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[691] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[760] 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[829] 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[898] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1
[967] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
这也有效:
library(corpus)
# simulate the problem as in @carl-boneri's answer
lead_para <- readLines("http://www.norvig.com/big.txt")
# get a random sample of 2000 word types
types <- text_types(lead_para, collapse = TRUE)
p <- sample(types, 2000)
# find whether each entry has at least one of the terms in `p`
ix <- text_detect(lead_para, p)
即使只使用单核,它也比以前的解决方案快 20 多倍:
system.time(ix <- text_detect(lead_para, p))
## user system elapsed
## 0.231 0.008 0.240
system.time(rst <- mcmapply(function(x) f(i = x, j = p_join2),
lead_para, mc.cores = detectCores() - 2,
USE.NAMES = FALSE))
## user system elapsed
## 11.604 0.240 5.805
我正在使用 R 并编写一个脚本来计算在 400 万个观察数据文件的每一行中是否出现约 2000 个单词中的一个。包含观察值 (df) 的数据集包含两列,一列包含文本 (df$lead_paragraph),一列包含日期 (df$date).
使用以下内容,我可以计算列表 (p) 中的任何单词是否出现在 df 文件的 lead_paragraph 列的每一行中,并将答案输出为新列。
df$pcount<-((rowSums(sapply(p, grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
但是,如果我在列表 p 中包含太多单词,运行 代码会导致 R 崩溃。
我的替代策略是将其简单地分解成多个部分,但我想知道是否有更好、更优雅的编码解决方案可用于此处。我倾向于使用 for 循环,但我正在阅读的所有内容都表明这在 R 中不是首选。我是 R 的新手而且不是一个很好的编码员,所以如果不清楚,我深表歉意。
df$pcount1<-((rowSums(sapply(p[1:100], grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
df$pcount2<-((rowSums(sapply(p[101:200], grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
...
df$pcount22<-((rowSums(sapply(p[2101:2200], grepl, df$lead_paragraph,
ignore.case=TRUE) == TRUE, na.rm=T) > 0) * 1)
我没有完成这个...但这应该为您指明了正确的方向。使用 data.table
包速度更快,但希望这能让您了解该过程。
我使用随机日期和字符串重新创建了你的数据集
从 http://www.norvig.com/big.txt 提取到 data.frame
名为 nrv_df
library(stringi)
> head(nrv_df)
lead_para date
1 The Project Gutenberg EBook of The Adventures of Sherlock Holmes 2018-11-16
2 by Sir Arthur Conan Doyle 2019-06-05
3 15 in our series by Sir Arthur Conan Doyle 2017-08-08
4 Copyright laws are changing all over the world Be sure to check the 2014-12-17
5 copyright laws for your country before downloading or redistributing 2016-09-13
6 this or any other Project Gutenberg eBook 2015-06-15
> dim(nrv_df)
[1] 103598 2
I then randomly sampled words from the entire body to get 2000 unique words
> length(p)
[1] 2000
> head(p)
[1] "The" "Project" "Gutenberg" "EBook" "of" "Adventures"
> tail(p)
[1] "accomplice" "engaged" "guessed" "row" "moist" "red"
然后,利用 stringi
包并使用正则表达式匹配完成
单词的情况下,我将每个字符串加入向量 p
中,并且
collapsed then with a |
, 所以我们正在寻找任何带有 word-boundary
的单词
之前或之后:
> p_join2 <- stri_join(sprintf("\b%s\b", p), collapse = "|")
> p_join2
[1] "\bThe\b|\bProject\b|\bGutenberg\b|\bEBook\b|\bof\b|\bAdventures\b|\bSherlock\b|\bHolmes\b|\bby\b|\bSir\b|\bArthur\b|\bConan\b|\bDoyle\b|\b15\b|\bin\b|\bour\b|\bseries\b|\bCopyright\b|\blaws\b|\bare\b|\bchanging\b|\ball\b|\bover\b|\bthe\b|\bworld\b|\bBe\b|\bsure\b|\bto\b|\bcheck\b|\bcopyright\b|\bfor\b|\byour\b|\bcountry\b|..."
然后简单地计算单词数,您可以nrv_df$counts <-
将其添加为一列...
> stri_count_regex(nrv_df$lead_para[25000:26000], p_join2, stri_opts_regex(case_insensitive = TRUE))
[1] 12 11 8 13 7 7 6 7 6 8 12 1 6 7 8 3 5 3 5 5 5 4 7 5 5 5 5 5 10 2 8 13 5 8 9 7 6 5 7 5 9 8 7 5 7 8 5 6 0 8 6
[52] 3 4 0 10 7 9 8 4 6 8 8 7 6 6 6 0 3 5 4 7 6 5 7 10 8 10 10 11
编辑:
因为查找匹配项的数量无关紧要...
首先是一个函数,用于对每个段落进行处理,并检测 p2
中的任何 stirngs 是否存在于 lead_paragraph
f <- function(i, j){
if(any(stri_detect_fixed(i, j, omit_no_match = TRUE))){
1
}else {
0
}
}
现在...在 linux 上使用 parallel
库。并且只测试 1000 行,因为它是一个例子给了我们:
library(parallel)
library(stringi)
> rst <- mcmapply(function(x){
f(i = x, j = p2)
}, vdf2$lead_paragraph[1:1000],
mc.cores = detectCores() - 2,
USE.NAMES = FALSE)
> rst
[1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[70] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[139] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
[208] 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[277] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[346] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1
[415] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[484] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[553] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[622] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[691] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[760] 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[829] 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[898] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1
[967] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
这也有效:
library(corpus)
# simulate the problem as in @carl-boneri's answer
lead_para <- readLines("http://www.norvig.com/big.txt")
# get a random sample of 2000 word types
types <- text_types(lead_para, collapse = TRUE)
p <- sample(types, 2000)
# find whether each entry has at least one of the terms in `p`
ix <- text_detect(lead_para, p)
即使只使用单核,它也比以前的解决方案快 20 多倍:
system.time(ix <- text_detect(lead_para, p))
## user system elapsed
## 0.231 0.008 0.240
system.time(rst <- mcmapply(function(x) f(i = x, j = p_join2),
lead_para, mc.cores = detectCores() - 2,
USE.NAMES = FALSE))
## user system elapsed
## 11.604 0.240 5.805