全民AI计划:通过抬杠,了解文本摘要的实现原理
“今日一整天,气候都不错。温度不冷不热,风也刚刚好,很适合出门。”
“少废话,说要点!”——“今日、气候、适合”
拣要紧的说,这便是——文本摘要。
我就废话许多,东一句,西一句,有的没的,常常受到读者的批评。
有图为证!
我想,我怎样才干像上面那些大牛相同呢?他们没有废话,看问题直达实质。我叽叽歪歪几千字,他们一句话就点透了。
于是,我驱车五个小时,来到一座深山,去请教一位大师。
我一坐下,大师便说:“爱过!”
我说,误会了大师,我是搞程序的,我单身。
大师慢慢睁开眼睛,似乎这突如其来的光线,有点扎眼,他问:“你们不是一块来的?”
我摇了摇头:“大师,我此番前来,想请教怎样才干捉住一段话中的要点!”
词频 Term Frequency
大师说:“送你一句话。屡次三番,必有大事。”
假如一些词语反复呈现,那么它们便是重要的要害词。至于其他的词,能够疏忽,你少重视即可得要点,去吧!下一位!
我点了允许:“嗯,确实如此!怪不得每次领导开会,一些字眼总是反复强调、屡次声明,原来是由于重要啊!”
听完,我立即写了一段代码,去核算一段话中词语呈现的次数。一个词在文章中呈现的频率,就叫“词频”(Term Frequency,TF)。
我挑选了一段小组长开早会时的讲话。
“今日咱们召开这次会议,主题是安全出产。作为一家公司,安满是咱们开展的基石,关乎咱们每一个人的生命安全和财产安全,因而,咱们必须高度重视和加强安全工作。”
python代码如下:
text = "今日 咱们 召开 这次 会议 , 主题 是 安全 出产……"
words = text.split(" ")
print(words)
由于要核算要害词,所以先将文本拆分成词语。这一步叫“分词”。英文是不用做分词处理的。由于“Today we are holding this meeting with……”它天然带有空格。
text.split(" ")
能够将那段话,以空格为边界拆分成数组。最后咱们打印数组,成果如下:
['今日', '咱们', '召开', '这次', '会议', ',', '主题', '是', '安全', …… '加强', '安全', '工作', '。']
有了词语的数组,下面咱们来核算每个词呈现的次数。
python代码如下:
from collections import Counter
count_dict = Counter(words)
sorted_dict = dict(sorted(count_dict.items(), key=lambda x: x[1], reverse=True))
for key, value in sorted_dict.items():
print(f'[{key}] 呈现了 [{value}] 次')
其中,Counter
这个类会对数组中重复的元素进行核算。核算成果以字典的方式({“安全”:5})保存在count_dict
中。随后,咱们经过sorted
函数进行排序。排序规矩为按照每个词呈现的次数,由大到小,降序摆放。
终究输出成果:
[安全] 呈现了 [5] 次
[, ] 呈现了 [5] 次
[咱们] 呈现了 [4] 次
[是 ] 呈现了 [2] 次
[。 ] 呈现了 [2] 次
[的 ] 呈现了 [2] 次
[和 ] 呈现了 [2] 次
[今日] 呈现了 [1] 次
[召开] 呈现了 [1] 次
……
咱们看到“安全”的词频最大。那么数据显示,这段话的要点便是“安全”。哇哦,小组长开确实实是安全出产会议。
感谢大师!我悟到了!
停用词 Stop Words
后来,我又去找大师。由于,我发现了一个问题。
我用上述算法,对下面这段文本做了要害信息提取。
这是咱们老板说的原话,“你们这是争辩什么?什么是你的我的他的,争辩这没含义,这些客户都是公司的!”
按照规矩,排名前三的词语是:
[是 ] 呈现了 [3] 次
[的 ] 呈现了 [3] 次
[什么] 呈现了 [2] 次
[争辩] 呈现了 [2] 次
我了个去,这它喵的要害词是什么?
大师说:“我再送你一句话吧。少则得,多则惑。”
过于众多的东西,必定是不重要的。它只会扰乱你、迷惑你。物以稀为亏,真理往往掌握在少数人的手中。
我仔细一想,还真是这样。比方“的”、“是”、“在”这些词汇。它们自身关于成果是没有效果的,反而还常常占有第一,属于“占着茅坑不拉屎”的行为。这类词,咱们要停止它们的效果,因而就叫“停用词”(Stop Words)。
关于停用词,许多机构都整理过详细的文件,咱们能够直接用。
比方[ ? ]、[ “ ]、[ ” ]、[ 。 ]……这些符号。或者是“然后”、“其次”、“那个”、“所以”这类无含义的辅助词。
我查了下,大约有成百上千个,有多的有少的,咱们能够自己来挑选。有时分这或许也和职业有关。比方在农业上,“就在此刻”含义不大。可是在小说中,“就在此刻”或许很要害,标志着剧情反转,基本上大侠就要呈现了。
去掉停用词之后,上述文中的词频最高的是“争辩”。
[争辩] 呈现了 [2] 次
[含义] 呈现了 [1] 次
[客户] 呈现了 [1] 次
……
那么我认为,他那句话的要点在于发生了“争辩”。
逆文档频率 Inverse Document Frequency
大师开门要去倒尿盆:“咦,你怎样又来了?!”
我说,大师啊,我不想总是找你抬杠。但我核算一段话的要害词时,发现词频都相同,我拿不准啊!
便是这句:“武汉人吃米饭和热干面”。这里,“米饭”和“热干面”呈现的频次挨近,那到底该选哪一个呢?
“这还不简单”大师提起盆要走,“成年人两个都要!”
我急速拦住了大师。
大师说:“再送你一句话。不识庐山真面目,只缘身在此山中。”
我苦笑一下:“大师,这正话反话,全都让您说了。你先前说重复才重要,后来又说众多要疏忽。这次,你给我讲明白!”
身处庐山之中,只能看到一部分景色,认识上具有局限性,不要容易妄下结论。看完大千世界,才干获得更准确的成果。究竟米饭和热干面,哪个能代表武汉?这得放眼全国来看。
“在北京、上海、广州、深圳,米饭呈现的多吗?”
我说,日常生活中常常呈现。
“那热干面呢?”
我回答,好像只在武汉十分流行。
这就对了!假如一个词并不是随处可见,但在某个场子里呈现屡次。那么这个词,多数会成为这个场子的代名词。
在那段话里,假如米饭的权重是1,那热干面得是5。呈现4次米饭,也抵不上呈现1次热干面。这种在群众视野里出镜率高的词,权重值反而会低,而出镜率低的词,权重又会高。这类逆着频次的权重,叫做“逆文档频率”(Inverse Document Frequency, IDF)。
上面说的“群众视野”其实类似于一个语料库(corpus)。它是经过采集许多的言语材料,整理成的一个仓库,所以叫语料库。
语料库是相对的。这就像是一个人的阅历和见识。有的人语料库很丰富,读过许多书,去过许多地方,通晓多种言语。也有的人语料库比较匮乏,乃至没有听过“米饭”这个词。
一个词在语料库中的方位,也便是IDF的权重值大不大,这要看它在每篇文章中被提到的频率。假如三句话不离吃喝,那么“吃喝”的权重就很低,它就无法作为一个特征去差异于其他群组。
那么,该怎样确定IDF的数值呢?
假如有这么一个小语料库,里边有两句话(这也叫库?为了便于了解,咱们乃至把每句话称为一个文档):
- Java是编程言语。
- Python是编程言语。
咱们能够看到“编程言语”一词,每个文档中都有。而“Java”和“Python”,只有在50%的文档中提到了它们。“IT”这个词,在这个语料库中找不到。
ITF的思路是越常见,值越低;越稀缺,值越高。
我想了想,感觉用“总文档数包括该词的数量”能解决。
-
“编程言语”的ITF=一共2个文档呈现2次=1。
-
“Python”的ITF=一共2个文档呈现1次=2。
这似乎是完成了越众多值越小。
可是,轮到“IT”这个词时,“IT”的ITF=一共2个文档呈现0次。这呈现了分母为0的状况,这是数学错误。
不瞎猜了,还是看人家怎样弄的吧。
逆文档频率(IDF)=log(语料库文档总数(包括该词文档数+1))。
这个设计就很奇妙了。
x轴中那个+1,避免了字母为0的状况。当一个词在每个文档中都有的时分,x轴的值向1挨近,它的权重向0接近。 红色部分是变量,处于分母的方位。所以,当一个词在语料库出镜率高时,x变小,y变小。反之都会变大。
大师问我听明白了没有?
我说听得很明白。语料库就适当于我的公司,权重就像是找财政催报销,我去10趟,不如总经理去1趟。
TF-IDF 代码实践
TF是词频,IDF是逆文档频率。TF-IDF这种核算办法便是“TF词频IDF词的权重”。
咱们是能够用TF-IDF来提取要害信息。这就类似于经过多大的人物呈现了几回来了解状况。假如连总经理都去催了20次,估计这事小不了。
下面,咱们就用python代码来操作一个例子。
我供给了三段话,出自我之前的博客:
- 由于练习数据的输入序列格局咱们能够操控,咱们也用它练习了一个模型。可是当预测时,输入格局是千奇百怪的。
- 解决问题思路还得敞开些,几许不可就用代数。我是编程扮演艺术家TF男孩,擅长编程扮演。
- 咱们老说时刻不可,时刻不可,所以代码写的不规范。可是有一天,时刻给得很足够,你是否会突然就写好代码了。
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
# 示例文本
corpus = [
"由于练习数据的……",
"解决问题思路还……",
"咱们老说时刻不……"
]
# 分词和去除停用词
stop_words = ["的", "是", "在", "了", "有", "和", "中"]
corpus_list = []
for text in corpus:
words = [word for word in jieba.cut(text) if word not in stop_words]
corpus_list.append(" ".join(words))
# 创立TfidfVectorizer目标
vectorizer = TfidfVectorizer()
# 将文本转换为tf-idf向量
tfidf = vectorizer.fit_transform(corpus_list)
# 提取要害词
feature_names = vectorizer.get_feature_names()
top_keywords = {}
for i in range(len(corpus)):
scores = tfidf[i].toarray()[0]
keyword_scores = [(feature_names[j], scores[j]) for j in range(len(feature_names))]
sorted_keyword_scores = sorted(keyword_scores, key=lambda x: x[1], reverse=True)
top_keywords[i] = sorted_keyword_scores[:3]
# 输出要害词排名
for i in range(len(corpus)):
print("文章{}的要害词:{}".format(i + 1, top_keywords[i]))
终究成果如下:
文章1的要害词:[('格局', 0.4), ('练习', 0.4), ('输入', 0.4)]
文章2的要害词:[('编程', 0.5), ('tf', 0.2), ('不可', 0.2)]
文章3的要害词:[('时刻', 0.5), ('不可', 0.3), ('代码', 0.4)]
上的代码用了两个类库,jieba
(中文分词)和sklearn
(scikit-learn,机器学习库)。因而,需求先pip install jieba
、pip install jieba
。
运用jieba
库,对示例文本jieba.cut(text)
进行分词操作,并去除了一些常见的停用词。
然后,咱们创立了一个TfidfVectorizer
目标,将分词后的文本集作为参数,传递给fit_transform
办法。它是专门为处理TF-IDF封装的办法,它会核算那些权重啥的,还会生成了一个稀少矩阵。
接下来,咱们运用get_feature_names
办法获取特征称号,即一切呈现过的单词列表。
最后,关于每个文档,咱们将每个单词的得分与特征称号,组成一个元组。再将一切元组按得分从高到低排序,取前3个作为终究要害词输出。
这就经过TF-IDF完成了文本的要害信息提取。
更成熟的方案
上面的例子,仅适用于教学演示以及原理解说。
其实TF-IDF很初级,也存在许多问题,间隔真实的文本摘要,还差很远。
假如我们乐意进一步实践,能够去 huggingface.co/ 上找找更高端的NLP模型。
筛选项能够挑选Tasks下Natural Language Processing的“Summarization”,Languages挑选“Chinese”。里边会有许多优秀的模型供您研究与学习。
我是@TF男孩,致力于向群众遍及人工智能。