Stata连享会 主页 || 视频 || 推文 || 知乎 || Bilibili 站
温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。
New!
lianxh
命令发布了:
随时搜索推文、Stata 资源。安装:
. ssc install lianxh
详情参见帮助文件 (有惊喜):
. help lianxh
连享会新命令:cnssc
,ihelp
,rdbalance
,gitee
,installpkg
⛳ Stata 系列推文:
作者: 赵汗青 (华南理工大学)
邮箱: hqingzh@gmail.com
编者按:本推文部分摘译自如下论文,特此致谢!
Source:Schwarz, C. (2019). lsemantica: A command for text similarity based on latent semantic analysis. The Stata Journal, 19(1), 129-142. -PDF-
目录
在基于词频的文本相似度分析中,主要存在以下问题:
为了解决该问题,Deerwester 等 (1990) 提出了潜在语义分析 (latent semantic analysisa, LSA)。该方法的主要特征如下:
这些属性使得 LSA 有着广泛的应用场景,包括:
虽然 Stata 中已经提供了 strdist
命令用于计算 Levenshtein 编辑距离、txttool
命令用于文本数据的清理和标记化、以及 ldagibbs
命令可以按相似主题对文本进行分类,但如果要计算文本之间的相似程度,我们还需要 lsemantica
命令。
LSA 基本原理是通过计算每个文档中词汇分布情况的相似程度,来分析文档间的相似性,因此 lsemantica
命令首先要基于词袋模型创建一个 “文档-词汇” 矩阵 (document-term matrix)。
在矩阵
接着,lsemantica
根据 TFIDF (termfrequency-inverse-document-frequency) 对矩阵
其中,textfind
实现。TFIDF 加权的意义在于降低那些同时出现在多个文档中的单词权重,因为这些单词对于文档的整体意义通常不够重要。TFIDF加权后,矩阵
当文档较多时,即 lsemantica
命令会对矩阵
之后,lsemantica
对分解后的矩阵进行截断降维。矩阵
值得注意的是,
lsemantica
基于 lsemantica cosine
对该矩阵的各个行向量计算余弦相似度,可以得到各个文档之间的相似度。除此之外,lsemantica
还可以保存 “单词-成分” 矩阵 lsemantica_word_comp
读取。该矩阵主要用于判断单个单词之间的词义相似度,即用于识别多词同义的情形。
*命令安装
net install st0552.pkg, replace
*语法介绍
lsemantica varname, components(integer) tfidf min char(integer) ///
stopwords(string) min freq(integer) max freq(real) ///
name new var(string) mat save path(string)
components(integer)
指定语义空间应该减少到的组件数量。组件的数量通常基于词汇表的大小来选择,默认值为 components(300)
;tfidf
指定在应用截断奇异值分解之前是否应该使用 tfidf 重新加权。在大多数情况下,tfidf 重新加权将改善结果;min_char(integer)
允许从文本中删除短词。字符少于最小字符的单词将从 LSA 中排除。默认值为 min_char(0)
;stopwords(string)
指定要从 lsemantica 中排除停用词;min_freq(integer)
允许删除出现在较少文档中的单词。默认值为min_freq(0)
;max_freq(real)
允许删除文档中频繁出现的单词。默认值为 max_freq(1)
;name_new_var(string)
指定 lsemantica 创建的输出变量的名称。这些变量包含每个文档的组件。默认情况下,变量的名称前缀是 component;mat_save
指定是否应保存单词成分矩阵 path(string)
设置保存单词分量矩阵的路径。
本例子的数据集为 1980-2016 年在经济期刊上发表的 41349 篇文章的标题。在进行 LSA 之前,先删除标题中的非字母数字字符,并列出前三篇文章清洗后的标题。
. *数据获取
. cap mkdir tmp //建立临时文件夹
. cd "./tmp"
. net get st0552.pkg, replace ///
> from(http://www.stata-journal.com/software/sj19-1/)
. use example_data.dta, clear
. gen text_strings = title
. *剔除非字母和数字字符
. replace text_strings=strlower(text_strings)
. replace text_strings = ustrregexra(text_strings, "[^a-zA-Z ]", "")
. replace text_strings = stritrim(text_strings)
. list text_strings in 1/3
+------------------------------------------------------------------+
| text_strings |
|------------------------------------------------------------------|
1. | what is labor supply and do taxes affect it |
2. | tax rules and the mismanagment of monetary policy |
3. | a consistent characterization of a nearcentury of price behavior |
+------------------------------------------------------------------+
首先,lsemantica
生成 “文档-词汇” 矩阵,从数据中删除小于 4 个字符的单词和出现在少于 10 个文档或超过一半文档中的单词,并将定义的停止词列表 stopwords 中的单词从数据中删除。
然后,lsemantica
使用 TFIDF 对生成的 “文档-词汇” 矩阵进行重新加权。每当处理了 10% 的词汇表时,该命令都会报告。
. *自定义被排除的单词列表 (停止词)
. global stopwords "a able about across after all almost also
> am among an and any are as at be because been but by can
> cannot could dear did do does either else ever every for
> from get got had has have he her hers him his how however
> i if in into is it its just east let like likely may me
> might most must my neither no nor not of off often on
> only or other our own rather said say says she should
> since so some than that the their them then there these
> they this tis to too twas us wants was we were what when
> where which while who whom why will with would yet you your"
. *进行潜在语义分析
. lsemantica text_strings, components(300) min_char(4) ///
> min_freq(10) max_freq(0.5) tfidf stopwords("$stopwords") ///
> path("$path") mat_save
如果某些文档在文本清洗后没有剩下的单词文本,这些样本将被删除。因为它们干扰了截断奇异值分解。lsemantica
会报告哪些文档已经从数据中删除,以及词汇表的大小。在本示例中,167 个文档被删除。
需要注意的是,在 lsemantica
计算截断奇异值分解的过程中需要较多的算力,可能会运行较长时间,有时候 Stata 会变得无响应。其计算时长时间随着 “文档-词汇矩阵” 的大小而增加,即随着文档数量和词汇表的大小而增加。
在 lsemantica
运行完毕后,可以使用 lsemantica_cosine
命令计算分量向量之间的余弦相似度,即各文档间相似度。lsemantica_cosine
计算了与其他文档标题的平均相似度以及最大和最小相似度。
. lsemantica_cosine component_1-component_300, mean_cosine ///
> min_cosine max_cosine find_similar(10) find_similar_cosine(10)
. *查看平均相似度描述性统计
. summarize mean_similarity, detail
mean_similarity
-------------------------------------------------------------
Percentiles Smallest
1% .004445 .0019212
5% .0064652 .002039
10% .0078351 .0022063 Obs 41,187
25% .0106501 .0023181 Sum of Wgt. 41,187
50% .0145226 Mean .0151535
Largest Std. Dev. .0060212
75% .018957 .0410298
90% .0232855 .0423272 Variance .0000363
95% .0260129 .0429791 Skewness .573504
99% .0315491 .0431718 Kurtosis 3.174497
. *查看最大相似度描述性统计
. summarize max_similarity, detail
max_similarity
-------------------------------------------------------------
Percentiles Smallest
1% .566003 .3102426
5% .6279272 .3372106
10% .6633787 .3501289 Obs 41,187
25% .7301425 .3673398 Sum of Wgt. 41,187
50% .8161867 Mean .8236289
Largest Std. Dev. .1225668
75% .94531 1
90% .9939191 1 Variance .0150226
95% .9984688 1 Skewness -.1232839
99% 1 1 Kurtosis 2.12262
. *查看最小相似度描述性统计
. summarize min_similarity, detail
min_similarity
-------------------------------------------------------------
Percentiles Smallest
1% -.2540156 -.4333508
5% -.192361 -.4333508
10% -.1627325 -.4326484 Obs 41,187
25% -.1244975 -.4326484 Sum of Wgt. 41,187
50% -.0941637 Mean -.1053932
Largest Std. Dev. .0439186
75% -.0745706 -.0296279
90% -.0628191 -.0296218 Variance .0019288
95% -.0572771 -.0287106 Skewness -1.664787
99% -.0482183 -.0284858 Kurtosis 7.269679
由于余弦相似度矩阵的维数一般比较大 (DxD),因此将其存储在 Mata 中。如果需要,可以在 lsemantica_cosine
命令后使用 getmata (cosin_*) = cosine_sim
从 Mata 中检索完整的余弦相似矩阵。当然,也可以将其储存为 mata 文件,以便下次读取使用。
. *在 Stata 中运行 Mata 命令,以下代码需要同时运行
. *Stata 中运行 Mata,保存和读取余弦相似矩阵
. mata
------------------- mata (type end to exit) ---------
: // 保存 Mata 文件
: mata matsave cosine cosine_sim, replace
(saving cosine_sim[41187,41187])
file cosine.mmat saved
: // Mata 读取文件
: mata matuse cosine, replace
(loading cosine_sim[41187,41187])
: end
-----------------------------------------------------
此外,lsemantica_cosine
可以为数据中的每一篇文章找到最相似的文章。在这个例子中,计算了 10 篇最相似的文章。然后,列出数据中第一篇文章的五个最相似的文章标题。可以看到,LSA 准确地识别了所有讨论劳动力供应问题的高度相似的文章。
. list most_similar_* cosine_most_similar_* if _n ==1
+---------------------------------------------------------------------------++
| 28468 | 513 | 6288 | 27267 | 34267 | 26707 | 38850 | 29322 | 29305 | 38932 |
+----------------------------------------------------------------------------+
. list title if _n==1 | _n==28468 | _n==513 | _n==6288 | _n==27267 | _n==34267
+----------------------------------------------------------------------+
| title
| ----------------------------------------------------------------------
| 1.| What Is Labor Supply and Do Taxes Affect It?
| 513.| Family Labor Supply with Taxes
| 6288. | The Effect of Taxes on Labor Supply in the Underground Economy
| 27267.| Low-Skilled Immigration and the Labor Supply of Highly Skilled Women
| 28468.| Labor Supply and Taxes: A Survey
| 34267.| Worktime Regulations and Spousal Labor Supply
+----------------------------------------------------------------------+
lsemantica
可以计算与原始文章高度相似的文章数量。在这个例子中,选择了余弦相似度为 0.7 5的截止值,通过 Mata 代码生成一个名为 high_sim_articles
的新变量,即余弦相似度大于 0.75 的文档的数量。
. sort pub_year
. mata
----------------- mata (type end to exit) ----------------
: pub_year = st_data(., "pub_year")
: high_sim_paper= J(0,1,.)
: for (y=1980 ; y<=2016 ; y++){
> cosine_submat = select(cosine_sim, pub_year:==y)
> cosine_submat = select(cosine_submat',pub_year:>=y)'
> high_sim = rowsum(( cosine_submat:>=J(rows(cosine_submat),
> cols(cosine_submat), 0.75) ))
> high_sim_paper = high_sim_paper \ high_sim
: var = st_addvar("double", "high_sim_paper")
: st_store(., "high_sim_paper", high_sim_paper)
: end
----------------------------------------------------------
对引用数量和高相似文章数量的回归分析表明,两个变量之间存在显著的正相关关系,即高相似文章数量越多的文章越多文章引用。
. reg citations high_sim_paper i.pub_year
Source | SS df MS Number of obs = 41,182
-------------+---------------------------------- F(37, 41144) = 79.43
Model | 34007739.4 37 919128.091 Prob > F = 0.0000
Residual | 476071505 41,144 11570.861 R-squared = 0.0667
-------------+---------------------------------- Adj R-squared = 0.0658
Total | 510079244 41,181 12386.2763 Root MSE = 107.57
--------------------------------------------------------------------------------
citations | Coef. Std. Err. t P>|t| [95% Conf. Interval]
---------------+----------------------------------------------------------------
high_sim_paper | -.0244854 .4637143 -0.05 0.958 -.9333754 .8844046
pub_year |
1981 | 18.96915 15.03021 1.26 0.207 -10.49039 48.4287
(output omitted)
2016 | -44.62202 10.75611 -4.15 0.000 -65.70423 -23.53981
_cons | 48.41729 10.50983 4.61 0.000 27.81779 69.0168
--------------------------------------------------------------------------------
最后,lsemantica
可以比较词语的语义关系和相似度。使用lsemantica_word_comp
,可以导入 lsemantica
存储的 “单词-成分” 矩阵。同样,lsemantica
余弦可以用于计算数据中单词之间的余弦相似度,以找到最相似的单词。例如,在下例中,lsemantica
识别出 “division”、“force”、“frictional”、“labor”、“monopsony” 和“segemented” 这几个词是相互关联的。
. lsemantica_word_comp using "word_comp.mata"
. lsemantica_cosine component_1-component_300, ///
> find_similar(10) find_similar_cosine(10)
. list most_similar_* if _n ==1516, noheader table
+------------------------------+-----------------------------+
| 1768 812 1144 2465 1111 291 1394 1309 2253 2232 |
+------------------------------------------------------------+
. list word if _n==1516 | _n==812 | _n==1144 | _n==2465 | _n==1111 | _n==1768
+--------------------+
| | words |
| ----- |------------|
| 812. | division |
| 1111. | force |
| 1144. | frictional |
| 1516. | labor |
| 1768. | monopsony |
| 2465. | segmented |
+--------------------+
本实例仅分析平安银行 (证券代码 000001) 2001-2019 年的管理层讨论与分析的文本 (MD&A) 数据。同样,在 LSA 之前进行文字清洗,仅保留中文。
. use "https://gitee.com/arlionn/data/raw/master/
> data01/lsemantica/MD_A.dta", clear
. gen text_strings = mda
. *仅保留中文字符
. replace text_strings=ustrregexra(text_strings,"[^\u4e00-\u9fa5]+"," ")
. *去除中文数字
. replace text_strings=ustrregexra(text_strings,"[一二三四五六七八九十]+"," ")
由于中文和英文单词不同,没有空格用于区分各个单词,故这里需要在 Stata 中调用 Python 中的 jieba
库,对文本进行分词。
*调用python进行中文分词
python
import jieba
from sfi import Data
import pandas as pd
dct = Data.getAsDict('Symbol text_strings')
txtdf =pd.DataFrame(dct)
txtdf['text_strings']=txtdf['text_strings'].apply(lambda x:" ".join(jieba.cut(x, cut_all=False)))
from sfi import Data
Data.setObsTotal(len(txtdf))
Data.addVarStr("text",100)
Data.store("text",None,txtdf['text_strings'],None)
end
接着进行 LSA 分析,先计算 “文档-词汇” 矩阵,由于本示例中只有 19 条文本,词汇量较少,故只能提取出较少成分,否则在 SVD 分解过程中会报错,故这里 components(15)
。同时纳入计算的词汇标准也降低,最小字符长度定义为 1,词频范围 0~1。
. lsemantica text, components(15) min_char(1) ///
> min_freq(0) max_freq(1)
*计算向量间余弦相似度
. lsemantica_cosine component_1-component_10, ///
> mean_cosine min_cosine max_cosine find_similar(5) ///
> find_similar_cosine(5)
. list most_similar_* if _n ==1, noheader
+------------------------------------------------------+
1. | 2 3 4 8 9 |
+------------------------------------------------------+
. list Year if _n==1 | _n==2 |_n==3 |_n==4 |_n==2 |_n==8
+-------------+
| | Year |
| ---- |------|
| 1. | 2001 |
| 2. | 2002 |
| 3. | 2003 |
| 4. | 2004 |
| 8. | 2008 |
+-------------+
从 Mata 中获取余弦相似度矩阵,生成变量 cosin_1-cosin_19,分别表示与 2001~2019 年管理层讨论与分析文本的相似度。通过循环构建变量 Similarity 表示与上一年年报中管理层讨论与分析文本的相似度,并查看其描述性统计。
. getmata (cosin_*) = cosine_sim
. gen Similarity=.
. foreach num of numlist 1/19 {
. replace Similarity=cosin_`num' if _n==(`num'+1)
}
. summarize Similarity,detail
Similarity
-------------------------------------------------------------
Percentiles Smallest
1% .0898155 .0898155
5% .0898155 .1218855
10% .1218855 .2486546 Obs 18
25% .4395948 .3753533 Sum of Wgt. 18
50% .7880501 Mean .689412
Largest Std. Dev. .3095546
75% .9507129 .9534972
90% .9966181 .995663 Variance .095824
95% .9967352 .9966181 Skewness -.7702948
99% .9967352 .9967352 Kurtosis 2.224078
Note:产生如下推文列表的 Stata 命令为:
lianxh 爬虫 文本
安装最新版lianxh
命令:
ssc install lianxh, replace
免费公开课
最新课程-直播课
专题 | 嘉宾 | 直播/回看视频 |
---|---|---|
⭐ 最新专题 | 文本分析、机器学习、效率专题、生存分析等 | |
研究设计 | 连玉君 | 我的特斯拉-实证研究设计,-幻灯片- |
面板模型 | 连玉君 | 动态面板模型,-幻灯片- |
面板模型 | 连玉君 | 直击面板数据模型 [免费公开课,2小时] |
⛳ 课程主页
⛳ 课程主页
关于我们
课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法
等
连享会小程序:扫一扫,看推文,看视频……
扫码加入连享会微信群,提问交流更方便
✏ 连享会-常见问题解答:
✨ https://gitee.com/lianxh/Course/wikis
New!
lianxh
命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh