大家会不会经常遇到这样的情况,需要在一系列的目标文本中,匹配搜索一系列特征文本,且这些特征文本可能在该某一目标文本中重复出现。例如如下数据集:
其中数据集news为上市公司新闻数据,变量NewsID为新闻的id编号;FullDeclareDate为新闻公布时间;TitleKeyWords为新闻的标题和关键词。
news[1:5]
NewsID | FullDeclareDate | TitleKeyWords |
---|---|---|
57285603 | 2/3/2010 12:00 | 富机达能正式挂牌 |
57463469 | 1/3/2010 15:22 | 新能源过剩事出有因 多晶硅风电获准松绑新能源,多晶硅,风电,松绑, |
57463473 | 1/3/2010 15:19 | 近9年元旦后首个交易日沪指走势一览 虎年怎开盘元旦,交易日,沪指,走势, |
57463477 | 1/3/2010 15:13 | 中央将下发2010年一号文件 出台新强农惠农政策一号文件,惠农新政,农民,收入,胡锦涛, |
57463479 | 1/3/2010 16:06 | 2010年首份年报12日亮相 1月共20家公司公布年报年报,上市公司,国海证券, |
数据集id为上市公司股票代码及名称,stkcd为上市公司股票代码,name为上市公司股票名称。
注:此处为了处理的方便,已经将上市公司中带有字母的部分进行了去除,例如带有字母A的万科A,以及带有ST字样的股票代码。 ”
id[1:5]
stkcd | name |
---|---|
000001 | 平安银行 |
000002 | 万科 |
000004 | 国农科技 |
000005 | 世纪星源 |
000006 | 深振业 |
如果需要对上市公司相关新闻进行研究,首先将相关上市公司的相关新闻进行筛选和标记。在本例中转化为代码需求,则需要在news的新闻标题和关键词中寻找是否存在某一个上市公司的名称,即需要将数据集id中的name字段匹配到数据集news中的TitleKeyWords字段中,看是否有一个或多个上市公司名称存在新闻标题中。
对于文本的分析首先会想到的是正则表达式,利用正则表达式进行处理的主要思想在于:
通过构建正则标准,对每一个特征文本在每一个目标文本中的存在性进行遍历。 ”
对如下代码进行解读可以发现,利用正则表达式进行处理有三个关键点:
paste(id[["name"]], collapse = "|")
代码,将上市公司名称的向量进行了整合,并在每一个名称用符号|
进行连接,从而进行补集操作,让至少对应一个上市公司名称的文本能够提取。stringr
包中str_extract_all
这样一个函数。相比于普通的str_extract
函数,在进行字符串提取时,不会仅仅只匹配第一个相关的项目,而是会把判断条件中的所有的潜在选项都进行匹配,从而对每一个目标文本生成一个相应的提取向量,最后以list
形式输出。str_extract_all
函数之后,需要对生成的list
,按照NewsID
变量进行展开,故而在之后用到%>% unlist()
和by = .(NewsID)
。library(stringr)
news_regex <- news[, .(name = str_extract_all(TitleKeyWords, paste(id[["name"]], collapse = "|"))%>% unlist()), by = .(NewsID)
][order(NewsID), .SD]
news_regex[1:5]
NewsID | name |
---|---|
57463479 | 国海证券 |
57463969 | 酒鬼酒 |
57463973 | 岳阳兴长 |
57463975 | 华闻传媒 |
57463981 | 广东鸿图 |
利用分词包jiebaR
进行分词处理的思想,主要在于:
将上市公司的名称当作一个新加入的词典,加入分词规则中,对目标文本整体进行分词,而后筛选除符合标准的分词结果。 ”
对如下代码进行解读可以发现三个关键点:
worker
函数添加一个引擎命名为cutter,而后用new_user_word()
函数将id[["name"]]添加到分词引擎cutter中。segment
,导入分词引擎cutter,对TitleKeyWords进行分词。nomatch = 0
。library(jiebaR)
cutter <- worker()
new_user_word(cutter, id[["name"]])
news_dict <- id[, .SD, .SDcols = c("name")
][news[, .(name = segment(TitleKeyWords, cutter)), by = .(NewsID)
], on = .(name), nomatch = 0
][order(NewsID), unique(.SD)]
news_dict[1:5]
TRUE
name | NewsID |
---|---|
国海证券 | 57463479 |
酒鬼酒 | 57463969 |
岳阳兴长 | 57463973 |
华闻传媒 | 57463975 |
广东鸿图 | 57463981 |
利用正则表达式二者之间是否存在一定的差异,下面分别进行运行时间的测度。
# 正则法
system.time(
news_regex <- news[1:100, .(name = str_extract_all(TitleKeyWords, paste(id[["name"]], collapse = "|"))%>% unlist()), by = .(NewsID)
][order(NewsID), .SD]
)
user system elapsed
0.58 0.00 0.58
# 分词法
system.time(
news_dict <- id[, .SD, .SDcols = c("name")
][news[1:100, .(name = segment(TitleKeyWords, cutter)), by = .(NewsID)
], on = .(name), nomatch = 0
][order(NewsID), unique(.SD)]
)
user system elapsed
0.08 0.03 0.11
# 正则法
system.time(
news_regex <- news[1:1000, .(name = str_extract_all(TitleKeyWords, paste(id[["name"]], collapse = "|"))%>% unlist()), by = .(NewsID)
][order(NewsID), .SD]
)
user system elapsed
5.50 0.02 5.68
# 分词法
system.time(
news_dict <- id[, .SD, .SDcols = c("name")
][news[1:1000, .(name = segment(TitleKeyWords, cutter)), by = .(NewsID)
], on = .(name), nomatch = 0
][order(NewsID), unique(.SD)]
)
user system elapsed
0.30 0.14 0.50
# 正则法
system.time(
news_regex <- news[1:10000, .(name = str_extract_all(TitleKeyWords, paste(id[["name"]], collapse = "|"))%>% unlist()), by = .(NewsID)
][order(NewsID), .SD]
)
user system elapsed
61.44 0.14 68.87
# 分词法
system.time(
news_dict <- id[, .SD, .SDcols = c("name")
][news[1:10000, .(name = segment(TitleKeyWords, cutter)), by = .(NewsID)
], on = .(name), nomatch = 0
][order(NewsID), unique(.SD)]
)
user system elapsed
2.40 2.13 4.84
通过对比上述运行时间可以发现,随着样本量的增大,利用分词包进行特征文本匹配的效率的优势逐渐凸显,更加建议在进行多特征文本匹配时,利用分词法进行操作!! ”