如何优化 R 中词干提取和拼写检查的性能?

2024-01-20

我有大约 1,400 万个文档,每个文档的平均字符数为(中位数:250 和平均值:470)。

我想在对它们进行分类之前执行拼写检查和词干提取。

模拟文档:

sentence <- "We aree drivng as fast as we drove yestrday or evven fastter zysxzw" %>%
    rep(times = 6) %>%
    paste(collapse = " ")

nchar(sentence)
[1] 407 

函数首先执行拼写检查,然后执行词干提取

library(hunspell)
library(magrittr)

spellAndStem <- function(sent, language = "en_US"){
  words <- sentence %>%
    strsplit(split = " ") %>%
    unlist

  # spelling
  correct <- hunspell_check(
        words = words, 
        dict = dictionary(language)
  )

  words[!correct] %<>%
    hunspell_suggest(dict = language) %>%
    sapply(FUN = "[", 1)

  # stemming
  words %>%
    hunspell_stem(dict = dictionary(language)) %>%
    unlist %>%
    paste(collapse = " ")
}

我查看了hunspell()函数将整个文档作为一个整体以提高性能,但我不知道如何按该顺序进行拼写检查和词干提取。

时间测量:

> library(microbenchmark)
> microbenchmark(spellAndStem(sentence), times = 100)
Unit: milliseconds
                   expr      min       lq     mean   median       uq      max neval
 spellAndStem(sentence) 680.3601 689.8842 700.7957 694.3781 702.7493 798.9544   100

如果每个文档 0.7 秒,则需要 0.7*1400000/3600/24 = 11.3 天来计算。

问题:

我怎样才能优化这个性能?

最后评论:

目标语言为 98% 德语和 2% 英语。不确定这些信息是否重要,只是为了完整性。


您可以通过对词汇表而不是文档中的所有单词执行昂贵的步骤来大幅优化代码。这quanteda包提供了一个非常有用的对象类或称为tokens:

toks <- quanteda::tokens(sentence)
unclass(toks)
#> $text1
#>  [1]  1  2  3  4  5  4  6  7  8  9 10 11 12  1  2  3  4  5  4  6  7  8  9 10 11
#> [26] 12  1  2  3  4  5  4  6  7  8  9 10 11 12  1  2  3  4  5  4  6  7  8  9 10
#> [51] 11 12  1  2  3  4  5  4  6  7  8  9 10 11 12  1  2  3  4  5  4  6  7  8  9
#> [76] 10 11 12
#> 
#> attr(,"types")
#>  [1] "We"       "aree"     "drivng"   "as"       "fast"     "we"      
#>  [7] "drove"    "yestrday" "or"       "evven"    "fastter"  "zysxzw"  
#> attr(,"padding")
#> [1] FALSE
#> attr(,"what")
#> [1] "word"
#> attr(,"ngrams")
#> [1] 1
#> attr(,"skip")
#> [1] 0
#> attr(,"concatenator")
#> [1] "_"
#> attr(,"docvars")
#> data frame with 0 columns and 1 row

如您所见,文本被分为词汇(types)和单词的位置。我们可以使用它来优化您的代码,方法是执行types而不是整个文本:

spellAndStem_tokens <- function(sent, language = "en_US") {

  sent_t <- quanteda::tokens(sent)

  # extract types to only work on them
  types <- quanteda::types(sent_t)

  # spelling
  correct <- hunspell_check(
    words = as.character(types), 
    dict = hunspell::dictionary(language)
  )

  pattern <- types[!correct]
  replacement <- sapply(hunspell_suggest(pattern, dict = language), FUN = "[", 1)

  types <- stringi::stri_replace_all_fixed(
    types,
    pattern, 
    replacement,
    vectorize_all = FALSE
  )

  # stemming
  types <- hunspell_stem(types, dict = dictionary(language))


  # replace original tokens
  sent_t_new <- quanteda::tokens_replace(sent_t, quanteda::types(sent_t), as.character(types))

  sent_t_new <- quanteda::tokens_remove(sent_t_new, pattern = "NULL", valuetype = "fixed")

  paste(as.character(sent_t_new), collapse = " ")
}

我正在使用bench包来进行基准测试,因为它还检查两个函数的结果是否相同,而且我发现它总体上更舒服:

res <- bench::mark(
  spellAndStem(sentence),
  spellAndStem_tokens(sentence)
)

res
#> # A tibble: 2 x 6
#>   expression                         min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>                    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 spellAndStem(sentence)           807ms    807ms      1.24     259KB        0
#> 2 spellAndStem_tokens(sentence)    148ms    150ms      6.61     289KB        0

summary(res, relative = TRUE)
#> # A tibble: 2 x 6
#>   expression                      min median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>                    <dbl>  <dbl>     <dbl>     <dbl>    <dbl>
#> 1 spellAndStem(sentence)         5.44   5.37      1         1         NaN
#> 2 spellAndStem_tokens(sentence)  1      1         5.33      1.11      NaN

新函数比原来的函数快了 5.44 倍。请注意,输入文本越大,差异就越明显:

sentence <- "We aree drivng as fast as we drove yestrday or evven fastter zysxzw" %>%
  rep(times = 600) %>%
  paste(collapse = " ")

res_big <- bench::mark(
  spellAndStem(sentence),
  spellAndStem_tokens(sentence)
)

res_big
#> # A tibble: 2 x 6
#>   expression                         min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>                    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 spellAndStem(sentence)         1.27m    1.27m      0.0131  749.81KB        0
#> 2 spellAndStem_tokens(sentence)  178.26ms 182.12ms   5.51      1.94MB        0
summary(res_big, relative = TRUE)
#> # A tibble: 2 x 6
#>   expression                      min median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>                    <dbl>  <dbl>     <dbl>     <dbl>    <dbl>
#> 1 spellAndStem(sentence)         428.   419.        1       1         NaN
#> 2 spellAndStem_tokens(sentence)   1      1       420.       2.65      NaN

正如您所看到的,处理 100 倍大的样本所需的时间与处理较小样本所需的时间几乎相同。这是因为两者之间的词汇是完全一样的。假设这个更大的样本代表您的 100 个文档,我们可以根据此结果推断出您的整个数据集。该函数应该花费不到一个小时(0.17826 * 14000 / 3600 = 0.69),但计算确实不完美,因为在真实数据上运行它所需的实际时间几乎完全取决于词汇表的大小。

除了编程/性能方面之外,我还有一些可能不适用于您的具体情况的问题:

  1. 我建议将函数中的最后一行更改为sapply(as.list(sent_t_new), paste, collapse = " ")因为这不会将所有文档折叠成一长串,而是将它们分开。
  2. 目前,您的设置会删除其中的单词hunspell找不到任何建议。我复制了这个方法(参见tokens_remove命令),但您可能需要考虑至少输出丢弃的单词,而不是默默地删除它们。
  3. 如果上面的函数是为其他一些文本分析做准备,那么在执行词干提取和拼写检查之前将数据直接转换为文档术语矩阵会更有意义。
  4. 词干提取只是词形还原的一种近似,词形还原是实际找到单词基本形式的过程。此外,词干提取在德语中的效果通常很差。根据您正在做的事情,您可能想要进行词形还原(例如,使用spacyr)或者干脆将其关闭,因为词干很少能改善德语的结果。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何优化 R 中词干提取和拼写检查的性能? 的相关文章

  • r : 直方图上的 ECDF

    在 R 中 与ecdf我可以绘制经验累积分布函数 plot ecdf mydata 与hist我可以绘制数据的直方图 hist mydata 如何在同一图中绘制直方图和 ecdf EDIT 我尝试做类似的东西 https mathemati
  • 闪亮的演示文稿 (ioslides):自定义 CSS 和徽标

    我安装了以下内容 RStudio 预览版 版本 0 98 864 2014 年 5 月 24 日 knitr 和shiny 的开发版本 来自 devtools install github c yihui knitr rstudio shi
  • 如何从 data.frame 中选择行和列的子集

    我有这个 d d Age gt 2 它返回 Age 超过 2 的所有行 但我只想返回几列中的值 例如 d X 和 d Y 而不是全部 无论如何我可以做到这一点吗 Thanks d d Age gt 2 c X Y
  • Quarto/Rmarkdown 中的美人鱼图:狭窄且模糊

    我正在尝试生成 pdf 格式的四开文档 稍后会生成 word 格式 我遇到了美人鱼图的问题 请在下面找到一个示例 qmd 文件来说明该问题 所以首先它应该支持 mermaid 标签 但当我这样做时 我无法在 rstudio 中 运行 单元
  • R 中大型稀疏矩阵的聚类分析

    我有一个包含 250000 笔交易 行 和 2183 项 列 的交易数据集 我想将其转换为稀疏矩阵 然后对其进行分层聚类 我尝试了包 sparcl 但它似乎不适用于稀疏矩阵 关于如何解决这个问题有什么建议吗 或者我可以使用任何其他包对稀疏矩
  • 包检查时如何有效处理未压缩的保存?

    在最近开发一个包的过程中 我将数据集包含在data 我的包的文件夹 在我的具体情况下 我有 5 个数据集 所有这些数据集都位于data table格式 尽管我在下面描述的问题仍然存在 如果我将它们保留为data frame 我已将每个人单独
  • 正则表达式挑选括号之间的一些文本[重复]

    这个问题在这里已经有答案了 可能的重复 提取 R 中所有括号内的信息 正则表达式 https stackoverflow com questions 8613237 extract info inside all parenthesis i
  • ggplot 中跨组的连续线

    我有一个数据时间序列 其中观察了一些数据 模拟了一些数据 我想生成整个数据系列随时间变化的图 其中颜色表示数据源 但是 我只能弄清楚如何使 ggplot 中的 geom line 连接同一组中的点 这是一个例子来说明 Create samp
  • 将文本添加到 ggplot 中的轴标签

    我从下表中绘制了一个图表 BoatPhs fit se lower upper 1 Before 3 685875 0 3287521 3 038621 4 333130 2 After0 20NTA 3 317189 0 6254079
  • 如何用日语创建 ggplot2 标题?

    我正在准备日语演示文稿 并希望图像的标题和图例名称为日语 我可以让文本在 RStudio 中渲染得很好 但是当渲染图像时 日语字符仅显示为方框 x 10 10 y x x df data frame x y ggplot df aes x
  • 在ggplot2中创建部分虚线

    我正在 R 中创建一个图 并且需要创建一条线 其中某些值是投影 投影用虚线表示 这是代码 df data frame date c rep 2008 2013 by 1 value c 303 407 538 696 881 1094 gg
  • 为什么我在 ddply 中看到“错误:length(rows) == 1 is not TRUE”?

    我有一个数据框 比如工资单 例如 payroll lt read table text AgencyName Rate PayBasis Status NumRate HousingAuthority 26 843 00 Annual Fu
  • R中有字典功能吗

    有没有办法在 R 中创建一个 字典 使其具有对 一些效果 x dictionary c Hi Why water c 1 5 4 x Why 5 我问这个是因为我实际上正在寻找两个分类变量函数 所以如果 x dictionary c a b
  • 我可以调整scale_color_brewer的下限吗?

    我已经订购了我想使用 color Brewer 的分类数据 但我很难看到非常低的值 有没有办法去掉这些较低的值或设置范围的下限 ggplot data frame x 1 6 y 10 15 w letters 1 6 aes x y co
  • 使用亚毫秒日期时间从字符->POSIXct->字符准确转换

    我的文件中有一个字符日期时间列 我加载文件 到data table 并执行需要将列转换为的操作POSIXct 然后我需要写POSIXct值返回文件 但日期时间不会相同 因为打印不正确 这个打印 格式问题是众所周知的 并且已经被讨论过多次 我
  • 在 Linux 下更改 RStudio 用户界面(不是图形等)中的字体大小

    This is not关于更改使用 RStudio 生成的图表中的字体大小的问题 我已经知道该怎么做了 我在配备 视网膜 显示屏的 MacBook Pro 上的 Linux 下使用 RStudio 我使用 KDE 作为我的窗口管理器 我可以
  • 在 R Shiny 中显示/隐藏整个框元素

    我目前正在尝试找到一种方法来隐藏 显示 R Shiny 中的整个 box 元素 以及里面的所有内容 我想创建一个可能的按钮 它允许用户展开特定框 然后使用相同 甚至不同 的按钮隐藏它 我不想使用条件面板 因为我的应用程序非常大并且会产生一些
  • 在 ggplot 中过滤管道 df

    我正在使用 dplyr 管道来清理我的 df 然后直接输入到 ggplot 中 但是 我只想一次只绘制一组 因此我需要过滤到该组 问题是 我希望比例保持不变 就好像所有群体都存在一样 是否可以在 ggplot 命令中进一步过滤管道 df 例
  • 使用插入符和方法 = gamLoess 进行训练时 R 崩溃

    当我运行下面的代码时 R 崩溃了 如果我在训练调用中注释掉tuneGrid行 就不会发生崩溃 我已经用另一个数据集尝试过此操作 但仍然使 R 崩溃 崩溃消息是 R 会话中止 R遇到致命错误 会话被终止 开始新会话 代码是 library s
  • R Shiny - 使用 DataTable 移动列名称

    我有一个非常复杂的闪亮代码 其中有几个面板和这些面板内的几个表格 启动应用程序时 列名称与列值正确对齐 但是 一旦我更改应用程序表格下的页码 列名称就会移动到左侧 而值仍保留在中间 如何强制应用程序使列名称与列值对齐 一个可重现的例子 li

随机推荐

  • Seaborn 热图 pandas 对 isnull 的计算

    生成数据帧的一系列计算 以提供 NaN 占行总数的百分比 如下所示 data df isnull sum len df 100 RecordID 0 000000 ContactID 0 000000 EmailAddress 0 0000
  • “this”语法如何工作?

    这条线是 this attr id replace button 相当于这个 this attr id replace button since this始终包含对object of invocation 这确实取决于where你调用该代码
  • Pip 通过需求文件安装单个包的多个额外依赖项

    一些包 例如DVC https dvc org doc install linux install with pip允许您安装额外的依赖项以使用附加功能 安装单个额外的依赖项 无论是通过命令行还是在requirements txt 你只需使
  • 如何从 jquery 手风琴中删除活动轮廓?

    我正在使用 Jquery 手风琴 活动链接有一个轮廓 我尝试过使用CSS accordion a focus outline none accordion a active outline none font weight bold and
  • 如何突出显示 UITextView 的文本的一部分?

    我想做的是 如果我的详细视图被调用 我想仅突出显示文本的一部分UITextView元素 让我们说一下里面的文字UITextView is blatextbla 然后我只想动态突出显示text or late或用户想到的任何内容 我怎样才能做
  • 在 Node.js 中使用“网页”Phantom 模块

    我正在尝试将 PhantomJS 脚本包装在 node js 进程中 phantom 脚本从命令行提供的参数中获取 url 并输出 pdf 与 pahntom 安装中包含的 rasterize js 示例非常相似 我的幻像脚本工作正常 只是
  • 如何强制 Emacs 超时?

    我在 emacs 中经常使用 TRAMP 然而 有时服务器会宕机 流浪汉会等待超时 通常是在做了之后C x f在 ido 模式下打开一个新文件 我必须等待一段令人烦恼的漫长时间 有没有一种简单的方法可以告诉 TRAMP 超时并让 ido 模
  • 在流星中导入 svg 文件

    我正在开发一个使用 Meteor React 作为前端和后端的项目 对于前端 UI 我使用 element react https eleme github io element react en US quick start https
  • Matlab如何绘制平滑的等高线图?

    我想用 2D 格式的 2 个变量表示数据 该值由颜色表示 2 个变量作为第 2 个轴 我正在使用轮廓函数来绘制我的数据 clc clear load dataM mat cMap jet 256 set the colomap using
  • 刷新用户函数 t-SQL 的元数据

    我正在做一些 T SQL 编程 并且在我的数据库上定义了一些视图 这些天数据模型仍在变化 我定义了一些表函数 有时我故意使用 select from MYVIEW 在这样的表函数中返回所有列 如果视图 或表 发生变化 函数就会崩溃 我需要重
  • 滑动导航抽屉不处理菜单项android的点击

    我正在尝试在应用程序中使用滑动导航抽屉 然而 它似乎没有处理 OnItemClick 方法 当我点击一个项目时没有任何反应 我怎样才能让它工作 谢谢 主要活动 protected void onCreate Bundle savedInst
  • C++ 编译时子字符串

    我有非常大的代码库 它使用 FILE 广泛用于日志记录 但是 它包含完整路径 这是 1 不需要的 2 可能会发生安全违规 我正在尝试编写编译时子字符串表达式 最终以这个解决方案 https blog galowicz de 2016 02
  • 高级类型的辅助模式

    编辑 这是问题的一个更简单的表述 使用Foo作为一个例子Aux模式其中does work Foo is a simple Aux pattern type trait Foo A B type Out object Foo type Aux
  • Python 的“unittest”缺少“assertHasAttr”方法,我应该使用什么来代替?

    在众多的断言方法中Python的标准unittest package https docs python org 3 library unittest html assertHasAttr 奇怪的是缺席了 在编写一些单元测试时 我遇到了一种
  • 防止对 PHP 的虚假循环 ajax 请求

    在我的网站上 我为博客文章创建了评论部分 用户可以编写评论 单击按钮 AJAX 请求将发送到包含 JSON 数据的 PHP PHP 将处理和验证数据 然后将其插入数据库 成功后 将从数据库中检索所有评论 并使用 JQuery 重新加载页面的
  • 将 MySQL 数据库移动到远程服务器后,“用户访问被拒绝”

    我在访问数据库时遇到一些问题 该脚本之前在我的本地主机上运行过 我将其导入到另一台服务器中 另一台服务器给我一条访问被拒绝的消息 给出的消息是 Access denied for user root 10 4 1 163 using pas
  • 对 USB 传输电缆进行编程/与 USB 设备驱动程序通信

    如何以编程方式访问 USB 传输电缆 例如 Belkin 的易传输电缆 http www belkin com easytransfercable 从Windows 我熟悉libusb win32 http libusb win32 sou
  • 如何显示eclipse项目类型

    在 Eclipse IDE 中 有图标显示项目类型 但我找不到文字描述 我希望右键单击 gt 属性来显示此信息 但根据此所有项目都是 项目 类型 即使它们是 java 项目或 Maven 项目等 有人知道吗 Thanks 根据 您不会在 E
  • 如何使用 TELETHON 按日期获取消息?

    如何获取今天发布的消息TELETHON 我正在使用下面的代码 date of post datetime datetime 2019 12 24 with TelegramClient name api id api hash as cli
  • 如何优化 R 中词干提取和拼写检查的性能?

    我有大约 1 400 万个文档 每个文档的平均字符数为 中位数 250 和平均值 470 我想在对它们进行分类之前执行拼写检查和词干提取 模拟文档 sentence lt We aree drivng as fast as we drove