knitr::opts_chunk$set(collapse = FALSE, comment = "##")
quanteda已上传在CRAN上,所以可以使用GUI的R软件包安装程序进行安装,或执行:
install.packages("quanteda")
请参阅https://github.com/quanteda/quanteda上的说明来安装GitHub版本。
我们建议安装以下软件包,以便更好地支持和扩展quanteda的功能:
devtools::install_github("quanteda/quanteda.corpora")
devtools::install_github("kbenoit/quanteda.dictionaries")
加载quanteda以便使用软件包中的数据和功能。
library(quanteda)
quanteda有一个简单而强大的配套软件包用于加载文本文件: readtext。 这个软件包的主函数readtext()
从磁盘或者URL中读取文件或者文件集,并且返回一个可以直接和corpus()
构造函数一起使用的data.frame,可用来创建一个quanteda语料库。
readtext()
可读取:
.txt
).csv
)文本文件语料库创建函数corpus()
可用于:
VCorpus
语料库对象最简单的方式是从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)
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)
语料库被设计成原始文档的“库”,该文档被转换为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), ]
+
运算符提供了一个连接两个语料库对象的简单方法。如果它们包含了不同的文档级别的变量,这些也将被合并起来以保证不丢失任何信息。语料库级别的元数据也被连接在一起。
library(quanteda) corp1 <- corpus(data_corpus_inaugural[1:5]) corp2 <- corpus(data_corpus_inaugural[53:58]) corp3 <- corp1 + corp2 summary(corp3)
corpus_subset()
是为语料库定义的一个函数,用于根据基于docvars()
的逻辑条件提取语料库子集:
summary(corpus_subset(data_corpus_inaugural, Year > 1990)) summary(corpus_subset(data_corpus_inaugural, President == "Adams"))
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*")
在上面的汇总中,Year
和President
是与每个文档相关的变量。我们可以用docvars()
函数访问这些变量。
# 浏览文档变量 head(docvars(data_corpus_inaugural))
quanteda.corpora软件包提供更多语料库资源。
为了执行文档缩放等统计分析,我们必须提取一个将某些特征与文档关联起来矩阵。在quanteda中,dfm函数用来生成这样一个矩阵。“dfm”是文档特征矩阵的缩写,矩阵的行总是为文档而列为“特征”。我们这样定义矩阵的行与列是因为在数据分析中标准的做法是将一个分析单元作为行,而将与每个单元有关的特征或变量作为列。我们称之为“特征”而不是“词项”,因为特征比词项更通用:词项可以被定义为原始词项,词干词项,词性词项,停用词去除后的词项,或者词项归属的字典。而特征可以是完全通用的,例如ngram或者句法依存,我们对矩阵的定义持开放式态度。
为了简单地对文本分词,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")
分词只是一个中间结果,而大多数用户都希望直接构建一个文档特征矩阵。为此,我们提供一个瑞士军刀功能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)
可以在RStudio 的Enviroment pane中查看dfm,或者调用R的View功能。调用plot
dfm将调用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"))
通常,我们感兴趣的是根据可能存在于文档变量中实质性因素来分析文本是如何不同的,而不仅仅是根据文档文件的边界。创建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的内置英语停用词表中。
在某些应用中,关于文本中我们感兴趣的单词集合我们有先验知识。例如,在电影评论中,通用的正面词汇的列表可能表示对电影正面的评价,或者我们可能会有一个与特定的意识形态立场相关的政治词汇的字典。在这些情况下,为了分析的目的,将这些词组等同处理并将其计数归类是有用的。
例如,我们来看看总统在就职演讲的语料库中,与恐怖主义有关的词汇和与经济相关的词语在总统之间是如何变化的。从原语料库中,我们选择自克林顿以来的总统:
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]
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)
我们在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"))
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.
# 读取中文停用词 stopw_zh <- stopwords("zh", source = "misc") tokens("中华人民共和国成立于1949 年") # 除去停用词 tokens("中华人民共和国成立于1949 年") |> tokens_remove(stopwords("zh", source = "misc"))
四十九份中国总理的“政府工作报告”,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"))
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")
# 所有报告中的双词词组 tstat_col <- textstat_collocations(toks_china, size = 2, min_count = 20, tolower = TRUE) head(tstat_col, 10)
注:以上这部分介绍翻译于英文版.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.