knitr::opts_chunk$set(collapse = FALSE,
                      comment = "##")

软件包安装 {#installing-the-package}

quanteda已上传在CRAN上,所以可以使用GUI的R软件包安装程序进行安装,或执行:

install.packages("quanteda")

请参阅https://github.com/quanteda/quanteda上的说明来安装GitHub版本。

推荐安装 {#additional-recommended-packages}

我们建议安装以下软件包,以便更好地支持和扩展quanteda的功能:

devtools::install_github("quanteda/quanteda.corpora")
devtools::install_github("kbenoit/quanteda.dictionaries")

创建语料库 {#creating-a-corpus}

加载quanteda以便使用软件包中的数据和功能。

library(quanteda)

目前可用的语料库资源 {#currently-available-corpus-sources}

quanteda有一个简单而强大的配套软件包用于加载文本文件: readtext。 这个软件包的主函数readtext()从磁盘或者URL中读取文件或者文件集,并且返回一个可以直接和corpus()构造函数一起使用的data.frame,可用来创建一个quanteda语料库。

readtext()可读取:

语料库创建函数corpus()可用于:

从字符向量构建语料库 {#building-a-corpus-from-a-character-vector}

最简单的方式是从R中已经存在的文本向量创建一个语料库。这使得高级R用户可以灵活地选择文本输入,因为R有很多可以读取文本向量的方法。

一旦我们有了这种格式的文本数据,我们就可以直接调用语料库构造函数。以从内置的英国政党2010年选举宣言(data_char_ukimmig2010)中提取的有关移民政策的文本为例:

corp_uk <- corpus(data_char_ukimmig2010)  # 从文本构建语料库
summary(corp_uk)

我们也可以添加一些文档变量-- quanteda 称之为此语料库的docvars()

我们可以使用R的names()函数来读取字符向量data_char_ukimmig2010的名称,并且将其给文档变量赋值。

docvars(corp_uk, "Party") <- names(data_char_ukimmig2010)
docvars(corp_uk, "Year") <- 2010
summary(corp_uk)

readtext软件包加载文件 {#loading-in-files-using-the-readtext-package}

require(readtext)

# Twitter json
dat_json <- readtext("~/Dropbox/QUANTESS/social media/zombies/tweets.json")
corp_twitter <- corpus(dat_json)
summary(corp_twitter, 5)
# 通用json - 需要“textfield”说明符
dat_sotu <- readtext("~/Dropbox/QUANTESS/Manuscripts/collocations/Corpora/sotu/sotu.json",
                     textfield = "text")
summary(corpus(dat_sotu), 5)
# 文本文件
dat_txtone <- readtext("~/Dropbox/QUANTESS/corpora/project_gutenberg/pg2701.txt", cache = FALSE)
summary(corpus(dat_txtone), 5)
# 多文本文件
dat_txtmultiple1 <- readtext("~/Dropbox/QUANTESS/corpora/inaugural/*.txt", cache = FALSE)
summary(corpus(dat_txtmultiple1), 5)
# 包含取自文件名的docvars的多个文本文件
dat_txtmultiple2 <- readtext("~/Dropbox/QUANTESS/corpora/inaugural/*.txt",
                             docvarsfrom = "filenames", sep = "-", docvarnames = c("Year", "President"))
summary(corpus(dat_txtmultiple2), 5)
# XML 数据
dat_xml <- readtext("~/Dropbox/QUANTESS/quanteda_working_files/xmlData/plant_catalog.xml",
                    dat_xml = "COMMON")
summary(corpus(dat_xml), 5)
# csv 文件
write.csv(data.frame(inaug_speech = as.character(data_corpus_inaugural),
                     docvars(data_corpus_inaugural)),
          file = "/tmp/inaug_texts.csv", row.names = FALSE)
dat_csv <- readtext("/tmp/inaug_texts.csv", textfield = "inaug_speech")
summary(corpus(dat_csv), 5)

quanteda语料库工作方式 {#how-a-quanteda-corpus-works}

语料库的原则 {#corpus-principles}

语料库被设计成原始文档的“库”,该文档被转换为UTF-8编码的纯文本文件,并与元数据一起分别存储于语料库级和文档级。我们给文档级元数据一个特殊的名字:docvars()。这些变量或特征描述了每个文档的属性。

从处理和分析的角度,语料库被设计成相对静态的文本容器。这意味着语料库中的文本不能从内部通过(例如)清理或预处理改变,比如词干提取或去除标点符号。相反,作为处理过程的一部分文本可以从语料库中提取,并赋值给新的对象,但是设计的思路是将语料库作为原始参考副本保留下来,以便于其他分析 - 例如那些需要词干和标点符号的分析-比如分析阅读难易指数 - 可以在相同的语料库上执行。

为了从语料库中提取文本,我们使用一个名为as.character()的提取器。

as.character(data_corpus_inaugural)[2]

为了总结语料库中的文本,我们可以调用一个为语料库定义的函数summary()

data(data_corpus_irishbudget2010, package = "quanteda.textmodels")
summary(data_corpus_irishbudget2010)

我们可以将汇总命令的输出保存为data.frame,并用这些信息绘制出一些基本的描述性统计信息:

tokeninfo <- summary(data_corpus_inaugural)
if (require(ggplot2))
    ggplot(data = tokeninfo, aes(x = Year, y = Tokens, group = 1)) +
    geom_line() +
    geom_point() +
    scale_x_continuous(labels = c(seq(1789, 2017, 12)), breaks = seq(1789, 2017, 12))

# 最长的就职演说: William Henry Harrison
tokeninfo[which.max(tokeninfo$Tokens), ]

处理语料库对象的功能 {#tools-for-handling-corpus-objects}

合并两个语料库对象 {#adding-two-corpus-objects-together}

+运算符提供了一个连接两个语料库对象的简单方法。如果它们包含了不同的文档级别的变量,这些也将被合并起来以保证不丢失任何信息。语料库级别的元数据也被连接在一起。

library(quanteda)
corp1 <- corpus(data_corpus_inaugural[1:5])
corp2 <- corpus(data_corpus_inaugural[53:58])
corp3 <- corp1 + corp2
summary(corp3)

提取语料库的子集 {#subsetting-corpus-objects}

corpus_subset()是为语料库定义的一个函数,用于根据基于docvars()的逻辑条件提取语料库子集:

summary(corpus_subset(data_corpus_inaugural, Year > 1990))
summary(corpus_subset(data_corpus_inaugural, President == "Adams"))

浏览语料库文本 {#exploring-corpus-texts}

kwic功能(keywords-in-context)可以搜索一个指定的词并显示它的上下文:

data_tokens_inaugural <- tokens(data_corpus_inaugural)
kwic(data_tokens_inaugural, pattern = "terror")
kwic(data_tokens_inaugural, pattern = "terror", valuetype = "regex")
kwic(data_tokens_inaugural, pattern = "communist*")

在上面的汇总中,YearPresident是与每个文档相关的变量。我们可以用docvars()函数访问这些变量。

# 浏览文档变量
head(docvars(data_corpus_inaugural))

quanteda.corpora软件包提供更多语料库资源。

从语料库中提取特征 {#extracting-features-from-a-corpus}

为了执行文档缩放等统计分析,我们必须提取一个将某些特征与文档关联起来矩阵。在quanteda中,dfm函数用来生成这样一个矩阵。“dfm”是文档特征矩阵的缩写,矩阵的行总是为文档而列为“特征”。我们这样定义矩阵的行与列是因为在数据分析中标准的做法是将一个分析单元作为行,而将与每个单元有关的特征或变量作为列。我们称之为“特征”而不是“词项”,因为特征比词项更通用:词项可以被定义为原始词项,词干词项,词性词项,停用词去除后的词项,或者词项归属的字典。而特征可以是完全通用的,例如ngram或者句法依存,我们对矩阵的定义持开放式态度。

文本分词 {#tokenizing-texts}

为了简单地对文本分词,quanteda提供了一个强大的命令tokens()。这个命令会产生了一个以字符向量形式存在的分词表,表中的每单元元素 都对应于一个输入文档。

tokens()有意设计成保守的,意味着除非有指令,它不会从文本中删除任何东西。

txt <- c(text1 = "This is $10 in 999 different ways,\n up and down; left and right!",
         text2 = "@kenbenoit working: on #quanteda 2day\t4ever, http://textasdata.com?page=123.")
tokens(txt)
tokens(txt, remove_numbers = TRUE,  remove_punct = TRUE)
tokens(txt, remove_numbers = FALSE, remove_punct = TRUE)
tokens(txt, remove_numbers = TRUE,  remove_punct = FALSE)
tokens(txt, remove_numbers = FALSE, remove_punct = FALSE)
tokens(txt, remove_numbers = FALSE, remove_punct = FALSE, remove_separators = FALSE)

也可以按字符分词:

tokens("Great website: http://textasdata.com?page=123.", what = "character")
tokens("Great website: http://textasdata.com?page=123.", what = "character",
         remove_separators = FALSE)

以及按句子分词:

# sentence level         
tokens(c("Kurt Vongeut said; only assholes use semi-colons.",
         "Today is Thursday in Canberra:  It is yesterday in London.",
         "En el caso de que no puedas ir con ellos, ¿quieres ir con nosotros?"),
       what = "sentence")

构建文档特征矩阵 {#constructing-a-document-feature-matrix}

分词只是一个中间结果,而大多数用户都希望直接构建一个文档特征矩阵。为此,我们提供一个瑞士军刀功能dfm(),此项功能执行分词并将所提取的特征归纳成文档特征矩阵。不同于tokens()所采用的保守方法,dfm()函数默认某些应用选项,比如toLower() - 一个单独的用于转换为小写的函数,以及 - 删除标点符号。不过tokens()的所有选项都可以传递给dfm()

corp_inaug_post1990 <- corpus_subset(data_corpus_inaugural, Year > 1990)

# 构建dfm
dfmat_inaug_post1990 <- tokens(corp_inaug_post1990) |>
    dfm()
dfmat_inaug_post1990[, 1:5]

dfm()的其他选项还包括去除停用词和分词的词干提取。

# 构建dfm, 去除停用词以及提取词干

dfmat_inaug_post1990_stem <- tokens(corp_inaug_post1990, remove_punct = TRUE) |>
  tokens_remove(stopwords("english")) |>
  tokens_wordstem("en") |>
  dfm()
dfmat_inaug_post1990_stem[, 1:5]

remove选项提供一个需要被去除的分词的列表。大多数用户会提供一个为多语种预定义的“停用词”的列表,可通过stopwords()函数获取:

head(stopwords("en"), 20)
head(stopwords("ru"), 10)
head(stopwords("ar", source = "misc"), 10)

查看文档特征矩阵 {#viewing-the-document-feature-matrix}

可以在RStudio 的Enviroment pane中查看dfm,或者调用R的View功能。调用plotdfm将调用wordcloud软件包绘制词云图。

dfmat_uk <- tokens(data_char_ukimmig2010, remove_punct = TRUE) |>
  tokens_remove(stopwords("en")) |>
  dfm()
dfmat_uk

使用topfeatures()可以访问出现频率最高的特征:

topfeatures(dfmat_uk, 20)  # 20 词频最高的词

使用textplot_wordcloud()可以绘制dfm对象的词云图。这个函数将参数传递给wordcloud包的wordcloud()函数,并且可以使用相同的参数来对图进行美化:

set.seed(100)
library("quanteda.textplots")
textplot_wordcloud(dfmat_uk, min_count = 6, random_order = FALSE,
                   rotation = .25,
                   color = RColorBrewer::brewer.pal(8, "Dark2"))

按文档变量对文档分组 {#grouping-documents-by-document-variable}

通常,我们感兴趣的是根据可能存在于文档变量中实质性因素来分析文本是如何不同的,而不仅仅是根据文档文件的边界。创建dfm时,我们可以将具有相同文档变量的文档分成一组:

dfmat_ire <- tokens(data_corpus_irishbudget2010, remove_punct = TRUE) |>
  tokens_remove(stopwords("en")) |>
  dfm() |>
  dfm_group(groups = party)

我们可以对这个dfm进行排序,并查看:

dfm_sort(dfmat_ire)[, 1:10]

请注意,最常出现的特征是“will”,这个词通常出现在英语停用词表中,但是并不包含在quanteda的内置英语停用词表中。

按字典或等价的类别对词汇分组 {#grouping-words-by-dictionary-or-equivalence-class}

在某些应用中,关于文本中我们感兴趣的单词集合我们有先验知识。例如,在电影评论中,通用的正面词汇的列表可能表示对电影正面的评价,或者我们可能会有一个与特定的意识形态立场相关的政治词汇的字典。在这些情况下,为了分析的目的,将这些词组等同处理并将其计数归类是有用的。

例如,我们来看看总统在就职演讲的语料库中,与恐怖主义有关的词汇和与经济相关的词语在总统之间是如何变化的。从原语料库中,我们选择自克林顿以来的总统:

corp_inaug_post1991 <- corpus_subset(data_corpus_inaugural, Year > 1991)

现在我们定义一个用于展示的字典:

dict <- dictionary(list(terror = c("terrorism", "terrorists", "threat"),
                        economy = c("jobs", "business", "grow", "work")))

我们也可在构建dfm时使用字典:

dfmat_inaug_post1991_dict <- tokens(corp_inaug_post1991) |>
  tokens_lookup(dictionary = dict) |>
  dfm()
dfmat_inaug_post1991_dict

构造函数dictionary()也适用于两种常见的“外来”字典格式:LIWC 和 Provalis Research' Wordstat。例如,我们可以加载 LIWC 并将其应用于总统就职演讲语料库:

dictliwc <- dictionary(file = "~/Dropbox/QUANTESS/dictionaries/LIWC/LIWC2001_English.dic",
                       format = "LIWC")
dfmat_inaug_subset <- dfm(tokens(data_corpus_inaugural[52:58]), dictionary = dicliwc)
dfmat_inaug_subset[, 1:10]

更多范例 {#further-examples}

文本之间的相似度 {#similarities-between-texts}

dfmat_inaug_post1980 <- corpus_subset(data_corpus_inaugural, Year > 1980) |>
  tokens(remove_punct = TRUE) |>
  tokens_remove(stopwords("english")) |>
  tokens_wordstem("en") |>
  dfm()
library("quanteda.textstats")

tstat_obama <- textstat_simil(dfmat_inaug_post1980,
                              dfmat_inaug_post1980[c("2009-Obama", "2013-Obama"), ],
                              margin = "documents", method = "cosine")
tstat_obama
# dotchart(as.list(obama_simil)$"2009-Obama", xlab = "Cosine similarity")

我们可以用这些距离来绘制树状图,聚类分析总统:

data_corpus_sotu <- readRDS(url("https://quanteda.org/data/data_corpus_sotu.rds"))

dfmat_sotu <- corpus_subset(data_corpus_sotu, Date > as.Date("1980-01-01")) |>
  tokens(remove_punct = TRUE) |>
  tokens_remove(stopwords("english")) |>
  tokens_wordstem("en") |>
  dfm()
dfmat_sotu <- dfm_trim(dfmat_sotu, min_termfreq = 5, min_docfreq = 3)

#分层聚类 -  在归一化dfm上计算距离
tstat_dist <- textstat_dist(dfm_weight(dfmat_sotu, scheme = "prop"))
# 聚类分析文本距离
pres_cluster <- hclust(as.dist(tstat_dist))
# 按文档名标注
pres_cluster$labels <- docnames(dfmat_sotu)
# 绘制树状图
plot(pres_cluster, xlab = "", sub = "",
     main = "Euclidean Distance on Normalized Token Frequency")

我们也可查看特征相似度:

tstat_sim <- textstat_simil(dfmat_sotu, dfmat_sotu[, c("fair", "health", "terror")],
                      method = "cosine", margin = "features")
lapply(as.list(tstat_sim), head, 10)

文档位置的缩放分析 {#scaling-document-positions}

我们在textmodel_wordfish()功能上做了大量的开发工作,这里仅演示“wordfish”模型的无监督文档缩放分析:

# make prettier document names
library("quanteda.textmodels")
dfmat_ire <- dfm(tokens(data_corpus_irishbudget2010))
tmod_wf <- textmodel_wordfish(dfmat_ire, dir = c(2, 1))

# plot the Wordfish estimates by party
textplot_scale1d(tmod_wf, groups = docvars(dfmat_ire, "party"))

主题模型 {#topic-models}

quanteda可以很轻松训练主题模型:

quant_dfm <- tokens(data_corpus_irishbudget2010, remove_punct = TRUE, remove_numbers = TRUE) |>
  tokens_remove(stopwords("en")) |>
  dfm()
quant_dfm <- dfm_trim(quant_dfm, min_termfreq = 4, max_docfreq = 10)
quant_dfm
set.seed(100)
if (require("stm")) {
    my_lda_fit20 <- stm(quant_dfm, K = 20, verbose = FALSE)
    plot(my_lda_fit20)    
}

注:以上这个指南翻译于英文版quickstart.

Quanteda处理中文文档 {#processing-chinese-documentation}

中文停用词:取自百度停用词 {#chinese-stop-words}

# 读取中文停用词
stopw_zh <- stopwords("zh", source = "misc")

tokens("中华人民共和国成立于1949 年")

# 除去停用词
tokens("中华人民共和国成立于1949 年") |>
    tokens_remove(stopwords("zh", source = "misc"))

例子:中国总理的“政府工作报告” {#chinese-government-report}

四十九份中国总理的“政府工作报告”,1954 - 2017

# 读取文件
load("examples/data/data_corpus_chinesegovreport.rda")
summary(data_corpus_chinesegovreport, 10)

# 分词
toks_china <- data_corpus_chinesegovreport |>
    tokens(remove_punct = TRUE) |>
    tokens_remove(stopwords("zh", source = "misc"))

# 创建 dfm
dfmat_china <- dfm(toks_china)
topfeatures(dfmat_china)
#发展 经济 社会 建设 改革 人民 主义 工作 企业 国家 
#5627 5036 4255 4248 2931 2897 2817 2642 2627 2595 

# 绘制词云图
set.seed(100)
dfmat_china_trim <- dfm_trim(dfmat_china, min_termfreq = 500)
# 设置适用于MacOS的字体
textplot_wordcloud(dfmat_china_trim, min_count = 6, 
                   rotation = .25, max_words = 100,
                   min_size = .5, max_size = 2.8,
                   font = if (Sys.info()["sysname"] == "Darwin") "SimHei" else NULL,
                   color = RColorBrewer::brewer.pal(8, "Dark2"))

文本缩放模型 {#wordfish}

wfm <- textmodel_wordfish(dfmat_china)
y <- 1954:2017
y <- y[-which(y == 1963 | y == 1961 | y == 1962 | (y > 1964 & y < 1975) | y == 1976 | y == 1977)]
plot(y, wfm$theta, xlab = "Year", ylab = "Position")

词组 - 双词词组/三词词组等 {#collocation}

# 所有报告中的双词词组
tstat_col <- textstat_collocations(toks_china, size = 2, min_count = 20, tolower = TRUE)
head(tstat_col, 10)

注:以上这部分介绍翻译于英文版.



quanteda/quanteda documentation built on April 15, 2024, 7:59 a.m.