作者:禅与计算机程序设计艺术
1.背景介绍
信息过滤与关键信息提取是信息检索、数据挖掘、机器学习等领域的重要技术。其目的是从海量的数据中快速获取有效的信息,并将它们按照结构化的方式呈现出来。结构化思考与金字塔结构可以帮助我们更加深刻地理解这一重要概念,它提供了一种很好的抽象方式来看待复杂的事物。在过去的一段时间里,网络爬虫、搜索引擎以及其他的自动信息收集工具已经成为大众生活中的必备品。然而,这些技术往往缺乏有效的处理方法和规则来过滤无用的信息,导致用户获得不必要的信息而感到困惑甚至沮丧。所以,如何通过有效的算法设计和经验积累,让计算机能够对网页、新闻或文本进行智能、准确的过滤,提取出关键信息是我们需要关注的问题。 本文将以结构化思考和金字塔结构的视角,从信息过滤与关键信息提取的实际应用出发,给读者讲述如何通过有效的算法设计和经验积累,让计算机自动化地过滤网页、新闻或文本中的无用信息,以及如何提取出最具价值的关键信息。
2.核心概念与联系
2.1 结构化思维与金字塔结构
结构化思维(Structured Thinking)可以概括为“以逻辑的方式解决问题”或者“将复杂问题分解成简单、可管理的任务”。结构化思考指的是人们认识事物、分析问题、组织信息、制定计划、总结经验的方法论。这种方法可以帮助我们更好地解决各种问题,它将复杂的事物分解成不同层次的抽象,每一层都由上一层提供信息,下层再向上传递,直到到达一个比较宏观的视角。比如,房屋建设是一个复杂的过程,它需要设计人员、施工人员、审美人员、市场人员等多个参与方一起协作,才能最终达到目标。结构化思维的这种特性赋予了我们解决问题的能力。而金字塔结构则是结构化思维的一个重要的派生结构。它是将复杂问题划分成不同的层次,上层的信息传递到下层,逐渐向基层逼近,最后达到一个比较宏观的视角。比如,一棵树是一个金字塔型结构,由根部到叶子的逐层分解,逐步缩小范围,最终达到整体的情况。
图1:结构化思维与金字塔结构示意图
主题模型还可以实现一些改进,如改善主题的解释性、主题之间的关系等。
3.2 信息过滤算法——Naive Bayes分类器(贝叶斯分类)
贝叶斯分类器(Bayesian Classifier)是一种信息过滤算法,它基于贝叶斯定理,利用高斯分布假设条件独立假设下的特征组合对文档进行分类。贝叶斯分类器的假设是特征之间相互独立,因此可以简化计算,训练速度较快。另外,贝叶斯分类器也具备很好的容错能力,即当训练样本不足时,仍能做出较好的预测。信息过滤中的贝叶斯分类器有两类实现方法,一类是朴素贝叶斯,另一类是加权贝叶斯。两者的区别在于是否采用先验概率估计方法,即先验知识对类先验概率的估计。例如,朴素贝叶斯分类器假设每个特征都是相互独立的,但是可能存在共同的特征依赖关系,因此需要先验知识对相关特征的组合的先验概率进行估计;加权贝叶斯分类器假设每个特征独立,并使用信息增益法计算特征的权重,对类先验概率进行估计。 信息过滤算法流程如下:
- 特征选择:首先从原始数据中选取一组有代表性的特征,这些特征对文档的分类有较大的影响力。
- 数据预处理:对选定的特征进行预处理,包括分词、去除停用词等。
- 训练:根据预处理后的文档数据及其对应的类标签,训练贝叶斯分类器模型。
- 测试:对测试文档数据进行预测。
- 结果展示:得到预测结果后,可以对文档进行分类,对文档进行排名、归类、标记等。
贝叶斯分类器还可以使用核函数的形式进行扩展,扩展后的贝叶斯分类器可以在非线性分类、多分类问题上取得更好的效果。
3.3 信息过滤算法——信息熵(Entropy)
信息熵(Entropy)是信息理论中衡量随机变量不确定性的一种指标。在信息过滤中,信息熵用于衡量分类的有效程度。信息熵反映的是某一事件发生的概率对数。信息熵越大,表示类内信息越混乱,信息熵越小,表示类间信息越集中。在信息过滤算法中,信息熵用于衡量不同类别文档之间的差异性,降低分类误差。 信息过滤算法流程如下:
- 特征选择:首先从原始数据中选取一组有代表性的特征,这些特征对文档的分类有较大的影响力。
- 数据预处理:对选定的特征进行预处理,包括分词、去除停用词等。
- 训练:根据预处理后的文档数据及其对应的类标签,训练信息熵模型。
- 测试:对测试文档数据进行预测。
- 结果展示:得到预测结果后,可以对文档进行分类,对文档进行排名、归类、标记等。
3.4 关键信息提取算法——关键词提取与权重计算
关键词提取与权重计算是关键信息提取算法的两个关键部分。关键词提取通过文本挖掘的方法来发现重要的、具有代表性的词语,权重计算则根据词语的相关性对这些关键词进行打分。权重计算方法有TF-IDF、BM25等。在信息过滤过程中,关键词提取与权重计算可以帮助我们提取文档中的关键信息,并根据其权重给文档进行排序、归类、标记。关键词提取算法的流程如下:
- 数据预处理:对原始文档进行预处理,包括分词、去除停用词等。
- 关键词抽取:利用文本挖掘的相关方法来发现重要的、具有代表性的词语。如tf-idf、BM25。
- 权重计算:计算每个关键词的权重。
- 结果展示:输出各个文档的关键词及其权重,根据关键词的权重对文档进行排序、归类、标记。
3.5 混合模型与关键词密度法
关键词密度法(Keyword Density)是一种关键信息提取方法,它通过文本的关键词密度来判断文档的重要性。关键词密度法通过统计分析的方法来计算文本的关键词密度,并根据密度大小来对文档进行分类。通过设置阀值,可以调整判定关键词的最小权重,从而滤除那些权重很小的关键词。在信息过滤过程中,关键词密度法可以帮助我们提取文档中的关键信息,并根据其密度大小给文档进行分类、排序、归类、标记。关键词密度算法的流程如下: - 数据预处理:对原始文档进行预处理,包括分词、去除停用词等。
- 关键词抽取:利用文本挖掘的相关方法来发现重要的、具有代表性的词语。如tf-idf、BM25。
- 关键词密度计算:统计每个文档的关键词出现次数,计算关键词的密度,并对文档进行排序、归类、标记。
3.6 模型融合与融合策略
模型融合是关键信息提取方法的一种有效处理方法。它可以将多个模型的优点合并起来,更好地提升最终的结果。模型融合的策略有平均法、投票法、矩阵分解法、Blended Recommendation System等。在信息过滤过程中,模型融合可以帮助我们获得更精准的关键信息。模型融合算法的流程如下: - 特征选择:首先从原始数据中选取一组有代表性的特征,这些特征对文档的分类有较大的影响力。
- 数据预处理:对选定的特征进行预处理,包括分词、去除停用词等。
- 训练多个模型:使用不同的算法对预处理后的文档数据及其对应的类标签,训练多个模型。
- 融合多个模型:将多个模型的结果进行融合,得到最终的结果。
- 结果展示:输出最终的结果。
3.7 时序数据处理
时序数据处理(Time Series Analysis)是信息过滤中的一个重要的技巧。它通过时间序列数据对文档进行分类、排序、归类、标记。时序数据处理方法有时间窗法、聚类法、动态时间规整法等。在信息过滤过程中,时序数据处理可以帮助我们获得关于文档变化的时间趋势,从而对文档进行有效的分类、排序、归类、标记。时序数据处理算法的流程如下: - 数据预处理:对原始文档进行预处理,包括分词、去除停用词等。
- 时序特征抽取:对文档数据的时间特征进行抽取,如时间戳、时长、长度、主题词。
- 时序聚类:对文档数据的时序特征进行聚类,形成各个类的时序分布。
- 结果展示:对文档数据进行分类、排序、归类、标记,输出相关的文档。
3.8 抽象层次分析(Hierarchical Clustering)
抽象层次分析(Hierarchical Clustering)是信息过滤中一种重要的分析方法。它通过树形结构对文档进行分类、排序、归类、标记。抽象层次分析方法包括层次聚类法、平均链接法、马氏链法、凝聚层次聚类法、自组织映射聚类法、分类层次聚类法、关联规则挖掘法等。在信息过滤过程中,抽象层次分析可以帮助我们获得文档的层次性结构,并对文档进行有效的分类、排序、归类、标记。抽象层次分析算法的流程如下: - 数据预处理:对原始文档进行预处理,包括分词、去除停用词等。
- 概念抽取:通过提取文档的主题、热点词、聚类等方法,来形成文档的概念层次结构。
- 层次聚类:对文档的概念层次结构进行层次聚类,形成各个类的层次分布。
- 结果展示:对文档数据进行分类、排序、归类、标记,输出相关的文档。
4.具体代码实例和详细解释说明
4.1 关键信息提取算法——主题模型(Topic Modeling)
import numpy as np from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.cluster import KMeans
def topic_model(docs): vectorizer = TfidfVectorizer() X = vectorizer.fit_transform(docs)
km = KMeans(n_clusters=5)
y_pred = km.fit_predict(X)
return [vectorizer.get_feature_names(), km.cluster_centers_]
对于具体的代码实现细节,这里只做一些简单的阐述。
TfidfVectorizer用于转换文本数据到TF-IDF权重矩阵。KMeans用于对文档的特征向量进行聚类。此处的聚类数量设置为5,也可以根据实际情况进行调整。文档的特征向量由TF-IDF表示,而聚类的中心点则表示主题的分布。返回的结果包含词袋模型的词汇表、每个主题的词分布。
## 4.2 信息过滤算法——Naive Bayes分类器(贝叶斯分类)
```python
import math
from collections import defaultdict
from nltk.corpus import stopwords
class NaiveBayesClassifier:
def __init__(self):
self.classes = set()
self.vocabulary = set()
self.doc_count = defaultdict(int)
# train the model with documents and their corresponding classes
def fit(self, documents, classes):
self.classes = set(classes)
for doc in documents:
words = set([word for word in doc if word not in stopwords.words("english")])
self.vocabulary |= words
for word in words:
self.doc_count[(word, classes[documents.index(doc)])] += 1
# predict the class of a document based on its features
def predict(self, features):
logprobabilities = {}
denominator = sum([math.log(float(self.doc_count[(word, c)])) + len(features)*math.log((1 - float(self.doc_count[(word, c)]))/float(self.doc_count))
for word in self.vocabulary for c in self.classes])
for c in self.classes:
numerator = sum([math.log(float(self.doc_count[(word, c)]))*(features.count(word) / len(features))
for word in self.vocabulary if (word, c) in self.doc_count])
logprobabilities[c] = numerator + math.log(sum([float(self.doc_count[(word, c)]) for word in self.vocabulary])) - denominator
return max(logprobabilities, key=logprobabilities.get)
对于具体的代码实现细节,这里只做一些简单的阐述。 NaiveBayesClassifier用于对文档进行分类,利用贝叶斯分类器进行分类。类别的数量、文本的词汇表、文档的词频统计都存储在类实例变量中。fit方法接收训练集,用于训练模型。train_set是一个列表,元素为tuple,第一个元素为document(str),第二个元素为document的类别(str)。predict方法接收测试集,输出分类结果。特征向量被转换为文档的TF-IDF值,使用文档词频统计信息对文档的每个词在不同类别中的出现次数进行计数。对文档的每个类别进行独立计算概率,得到不同类别的最大概率值作为预测结果。
4.3 信息过滤算法——信息熵(Entropy)
import re
import string
import operator
def entropy(data):
p = dict([(i, data.count(i)/float(len(data))) for i in set(data)])
H = sum([-p[k]*math.log(p[k],2) for k in p])
return H
def preprocess_text(text):
text = text.lower().translate(str.maketrans("", "", string.punctuation)).replace('\n','')
tokens = re.findall(r'\w+', text)
table = str.maketrans('', '', string.digits)
tokens = [''.join([''if char.isdigit() else char for char in token]).strip() for token in tokens]
return list(map(lambda x: x.translate(table), tokens))
def filter_documents(documents):
entropies = []
filtered_documents = []
for document in documents:
preprocessed_document = preprocess_text(document)
unique_tokens = sorted(list(set(preprocessed_document)), reverse=True, key=len)
freqs = [(token, count/len(preprocessed_document)) for token, count in Counter(preprocessed_document).items()]
sorted_freqs = sorted(freqs, key=operator.itemgetter(1))[::-1][:min(len(unique_tokens), 10)]
weighted_entropy = sum([f[1]*entropy(' '.join([w for w in f[0].split()[1:] if w!= t]))
for t, f in zip(sorted_freqs[:10], freqs)
if t in ''.join([u[0] for u in sorted_freqs[:10]]) or len(t)<2][:-1])
entropies.append(weighted_entropy)
avg_entropy = sum(entropies)/len(documents)
for i in range(len(documents)):
if abs(entropies[i]-avg_entropy)>0.2*abs(max(entropies)-avg_entropy):
continue
else:
filtered_documents.append(documents[i])
return filtered_documents
对于具体的代码实现细节,这里只做一些简单的阐述。 entropy函数用于计算信息熵。preprocess_text函数用于对文档进行预处理,将其转换为标准化的单词列表。filter_documents函数接收文档列表,计算每份文档的信息熵,如果信息熵偏离平均值超过20%,则认为该文档与其他文档相比更具有独特性,将其加入到过滤后的文档列表中。返回过滤后的文档列表。
4.4 关键信息提取算法——关键词提取与权重计算
import gensim
import jieba
def extract_keywords(documents):
keywords = []
dictionary = gensim.corpora.Dictionary(jieba.cut(doc) for doc in documents)
corpus = [dictionary.doc2bow(jieba.cut(doc)) for doc in documents]
lda = gensim.models.ldamodel.LdaModel(corpus, id2word=dictionary, num_topics=10)
for i in range(lda.num_topics):
top_keywords = [dictionary[j] for j in lda.show_topic(i, 10)[0]]
weights = [w for _,w in lda.show_topic(i, 10)[1]]
keywords.append({keyword: weight for keyword, weight in zip(top_keywords, weights)})
return keywords
对于具体的代码实现细节,这里只做一些简单的阐述。 extract_keywords函数接收文档列表,利用gensim库中的LDA模型进行关键词抽取。文档的词汇表构建完成后,每个文档被转换为BoW格式的词袋模型,并根据文档的主题模型进行聚类。每组关键词的权重被记录在字典中,并按顺序放入关键字列表中。返回的结果为列表,每个元素对应一组抽取出的关键词。
4.5 混合模型与关键词密度法
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from scipy.stats import gaussian_kde
def find_keyphrases(text):
vec = CountVectorizer(stop_words='english')
bow = vec.fit_transform([text])
dense = bow.todense().tolist()[0]
df = pd.DataFrame({'term':vec.get_feature_names(),
'weight':dense})
df['weight'] /= sum(df['weight'])
smoothed = df[['term','weight']]
kernel = gaussian_kde(smoothed['weight'])
xs = np.linspace(0, smoothed['weight'].max()+0.1, 200)
plt.plot(xs, kernel(xs))
plt.ylim(-0.01, None)
phrase_idx = set([])
threshold = max(kernel(xs))*0.1
current_phrase = ''
phrases = []
while len(smoothed) > 0:
row = smoothed.iloc[np.argmax(kernel(smoothed['weight']))]
if row['weight'] >= threshold:
if current_phrase == '':
current_phrase = row['term']
else:
current_phrase =''.join([current_phrase, row['term']])
else:
phrases.append(current_phrase)
current_phrase = ''
phrase_idx.add(row.name)
mask = ~(smoothed.index.isin(phrase_idx)) & (~(smoothed['term']==row['term']))
smoothed = smoothed.loc[mask]
return phrases
对于具体的代码实现细节,这里只做一些简单的阐述。 find_keyphrases函数接收文档字符串,利用CountVectorizer进行词袋模型的构建。词袋模型中每篇文档的词频统计结果保存在列表中,并按照词的频率从高到底进行排序。利用Scipy中gaussian_kde函数进行密度估计,并画出密度分布曲线。计算密度分布的最高峰点,如果这个点高于10%的最大值,则认为这个点属于关键词。如果当前关键词为空,则将该词加入到关键词中;否则,将当前关键词与该词连接。重复以上步骤,直至所有的词都已经被加入到关键词中,或者密度分布的最大值大于某个阈值。返回关键词列表。