python中文文本聚类可视化_路透社文章的文本数据分析与可视化
作者|Manmohan Singh
编译|VK
来源|Towards Datas Science
当我要求您解释文本数据时, 您会采取哪些措施来实现这一目标? 您会采用哪些具体步骤来进行文本可视化设计?
本文将帮助你获得构建可视化和解释文本数据所需的信息。
从文本数据中获得的洞见有助于揭示关系网络的细节变化和动态模式特征。该方法被用来识别趋势和模式。通过研究过滤干扰因素的数据样本集合进行详细分析能够揭示潜在信息。
这种分析过程也被称为探索性文本数据分析(ETA)。采用K-means算法、Tf-IDF模型以及基于词频的数据处理方法对这些文本数据展开评估。此外,在数据清理这一环节中,ETA同样发挥了重要作用。
我们还使用Matplotlib、seaborn和Plotly库将结果显示为图形、词云和绘图中。
在分析文本数据之前,请完成这些预处理任务。
从数据源检索数据
有许多非结构化文本资料可用于研究分析。可通过指定平台提供的公开资源获取所需的数据集信息。其中一项具体的数据源是Kaggle上的Twitter文本数据库。
Reddit和twitter数据集使用API。
使用Beautifulsoup从网站上获取文章、。
采用路透社的SGML格式的文章。为了便于分析起见,打算采取beautoolsoup库从数据文件中提取所需信息。
Please refer to the following code to extract information from various data files and save the results into a single CSV file.
import pandas as pd
import csv
article_dict = {}
i = 0
list_of_data_num = []
for j in range(0,22):
if j < 10:
list_of_data_num.append("00" + str(j))
else:
list_of_data_num.append("0" + str(j))
循环所有文章以提取日期、标题和文章主体
for num in list_of_data_num:
try:
soup = BeautifulSoup(open("data/reut2-" + num + ".sgm"), features='lxml')
except:
continue
print(num)
data_reuters = soup.find_all('reuters')
for data in data_reuters:
article_dict[i] = {}
for date in data.find_all('date'):
try:
article_dict[i]["date"] = str(date.contents[0]).strip()
except:
article_dict[i]["date"] = None
print(date.contents[0])
for title in data.find_all('title'):
article_dict[i]["title"] = str(title.contents[0]).strip()
print(title.contents)
for text in data.find_all('text'):
try:
article_dict[i]["text"] = str(text.contents[4]).strip()
except:
article_dict[i]["text"] = None
i += 1
dataframe_article = pd.DataFrame(article_dict).T
该方法用于将dataframe_article导出为.articles_data.csv文件,并设置包含文件头标记、不包含索引标签以及应用完整的引用格式
print(dataframe_article)还可以调用print函数打印,并且能够结合正则表达式库与操作系统相关模块一起使用,或者按顺序处理每一个数据文件
每篇文章的正文以开头,因此使用find_all('reuters')。
你也可以使用pickle模块来保存数据,而不是CSV。
清洗数据
在本节中,我们将从文本数据中剔除诸如缺失值、标点符号、数字等无意义的数据.首先,我们删除包含缺失值的所有行.随后去除另一列中的缺失值.请注意,此处使用的Python代码应遵循正确的语法规范,确保第一条语句后紧跟第二条语句,避免语法错误.
从本地CSV文件中导入文章数据。
通过调用apply函数计算每列缺失值的数量,并输出结果。
移除包含缺失值的文章数据。
恢复索引以供后续操作。
def clean_text(text):
Convert the text to lowercase. Eliminate any text enclosed within square brackets. Remove newline characters. Eliminate punctuation marks and omit any word that includes numerical characters.
text = str(text).lower()
text = re.sub(‘<.>+’, ‘’, text)
text = re.sub(‘[%s]’ % re.escape(string.punctuation), ‘’, text)
text = re.sub(‘\n’, ‘’, text)
text = re.sub(‘\w*\d\w*’, ‘’, text)
return text
articles_nonNull[‘text_clean’]=articles_nonNull[‘text’]\
.apply(lambda x:clean_text(x))当我们删除文本列中的空值时,其他列中的空值也会消失.
我们使用re方法去除文本数据中的噪声。
在数据清理过程中涉及的步骤会根据文本数据的数量变化而调整。因此,请认真分析您的文本数据并相应地构建clean_text()方法。
随着预处理任务的完成,我们将继续分析文本数据。
让我们从分析开始。
1.路透社文章篇幅
考虑到文章篇幅存在差异性,在实际处理中我们选择对长度不低于一段的文章进行筛选分析。依据研究表明,在文本处理中通常设定单个句子的平均字节数在15至20之间较为合理。每个段落通常包含四个陈述句以增强论述深度和完整性。为了计算每篇文章中的平均单词数量我们采用如下方法:将每篇文章拆分成独立的句子并计算其总词数最后汇总统计得到完整的描述性统计信息作为数据基础进行后续分析。
articles_word_limit = articles_nonNull[articles_nonNull[‘word_length’] > 60]
plt.figure(figsize=(12,6))
p1 = sns.kdeplot(articles_word_limit['word_length'], filled=True, color=red).set_title('Kernel Density Distribution of Word Length')

我删除了那些篇幅不足60字的文章。
字长分布是右偏的。
大多数文章有150字左右。
包含事实或股票信息的路透社文章用词较少。
2.路透社文章中的常用词
在本节内容中,我们对文章中的用词数量进行了计算,并对其分布特征进行了系统考察。基于N-gram模型的方法被采用用于词频统计工作。N-gram作为一种基于特定数值窗口大小的单词组合分析方法,在语言处理领域具有重要应用价值
在文本处理过程中, 我们通过从文本数据中去除无意义词汇. 由于停用词被视为噪音, 并不影响分析结果的准确性.
1最常见的单字单词(N=1)
请我们在条形图上呈现单语词,并以这些单语词为基础生成关键词云
import remove_stopwords
import genism
from wordcloud import WordCloud
import numpy as np
import random
从gensim方法导入stopwords到stop_list变量
你也可以手动添加stopwords
gensim_stopwords = gensim.parsing.preprocessing.STOPWORDS
stopwords_list = list(set(gensim_stopwords))
stopwords_update = ["mln", "vs","cts","said","billion","pct","dlrs","dlr"]
stopwords = stopwords_list + stopwords_update
articles_word_limit['temp_list'] = articles_word_limit['text_clean'].apply(lambda x:str(x).split())
从文章中删除停用词
def remove_stopword(x):
return [word for word in x if word not in stopwords]
将temp_list_stopw字段重新赋值为temp_list字段应用移除停用词方法的结果。
生成ngram的单词
def generate_ngrams(text, n_gram=1):
ngrams = zip(*[text[i:] for i in range(n_gram)])
return [' '.join(ngram) for ngram in ngrams]
article_unigrams = defaultdict(int)
for tweet in articles_word_limit['temp_list_stopw']:
for word in generate_ngrams(tweet):
article_unigrams[word] += 1
该DataFrame基于sorted函数创建为一个逆序排列的基于键值对的有序数据结构
N=50
在路透社的文章中前50个常用的unigram
fig, axes = plt.subplots(figsize=(18, 50))
plt.tight_layout()
sns.barplot(y=article_unigrams_df[0].values[:N], x=article_unigrams_df[1].values[:N], color='red')
axes.spines['right'].set_visible(False)
axes.set_xlabel('')
axes.set_ylabel('')
axes.tick_params(axis='x', labelsize=13)
axes.tick_params(axis='y', labelsize=13)
axes.set_title(f'Top {N} most common unigrams in Reuters Articles', fontsize=15)
plt.show()
画出词云
def col_func(word, font_size, position, orientation, font_path, random_state):
colors = ['#b58900', '#cb4b16', '#dc322f', '#d33682', '#6c71c4',
'#268bd2', '#2aa198', '#859900']
return random.choice(colors)
fd = {
'fontsize': '32',
'fontweight' : 'normal',
'verticalalignment': 'baseline',
'horizontalalignment': 'center',
}
wc = WordCloud(width=2000, height=1000, collocations=False,
background_color="white",
color_func=col_func,
max_words=200,
随机种子被赋予从1到8生成的整数值,并基于文章的一元组序列生成频率分布
fig, ax = plt.subplots(figsize=(20,10))
ax.imshow(wc, interpolation='bilinear')
ax.axis("off")
ax.set_title(‘Unigram Words of Reuters Articles’, pad=24, fontdict=fd)
plt.show()


常用的术语一词多义地被广泛应用于股票市场与金融行业的内容中。
因此,我们可以说,大多数路透社文章属于金融和股票类。
2.最常见的Bigram词(N=2)
请以article_bigrams变量存储用于生成柱状图和word cloud的二元组单词频率数据。
for tweet in articles_word_limit[‘temp_list_stopw’]:
for word in generate_ngrams(tweet, n_gram=2):
article_bigrams[word] += 1
df_article_bigrams=pd.DataFrame(sorted(article_bigrams.items(),
key=lambda x: x[1])[::-1])
N=50
前50个单词的柱状图
fig, axes = plt.subplots(figsize=(18, 50), dpi=100)
plt.tight_layout()
sns.barplot(y=df_article_bigrams[0].values[:N],
x=df_article_bigrams[1].values[:N],
color=’red’)
axes.spines[‘right’].set_visible(False)
axes.set_xlabel(‘’)
axes.set_ylabel(‘’)
axes.tick_params(axis=’x’, labelsize=13)
axes.tick_params(axis=’y’, labelsize=13)
axes.set_title(f’Top {N} most common Bigrams in Reuters Articles’,
fontsize=15)
plt.show()
#词云
wc = WordCloud(width=2000, height=1000, collocations=False,
background_color=”white”,
color_func=col_func,
max_words=200,
random_state=np.random.randint(1,8))\
.generate_from_frequencies(article_bigrams)
fig, ax = plt.subplots(figsize=(20,10))
ax.imshow(wc, interpolation=’bilinear’)
ax.axis(“off”)
ax.set_title(‘Trigram Words of Reuters Articles’, pad=24,
fontdict=fd)
plt.show()


Bigrams encompass more textual information and contextual cues compared to unigrams. For instance, in the case of share loss, it reveals that a significant number of investors experience financial losses in the stock market.
3.最常用的Trigram词
为了生成TRIGMA单词的柱状图和词云图。article_trigrams = defaultdict(int)
for tweet in articles_word_limit[‘temp_list_stopw’]:
for word in generate_ngrams(tweet, n_gram=3):
article_trigrams[word] += 1
df_article_trigrams = pd.DataFrame(sorted(article_trigrams.items(),
key=lambda x: x[1])[::-1])
N=50
柱状图的前50个trigram
fig, axes = plt.subplots(figsize=(18, 50), dpi=100)
plt.tight_layout()
sns.barplot(y=df_article_trigrams[0].values[:N],
x=df_article_trigrams[1].values[:N],
color=’red’)
axes.spines[‘right’].set_visible(False)
axes.set_xlabel(‘’)
axes.set_ylabel(‘’)
axes.tick_params(axis=’x’, labelsize=13)
axes.tick_params(axis=’y’, labelsize=13)
axes.set_title(f’Top {N} most common Trigrams in Reuters articles’,
fontsize=15)
plt.show()
词云
wc = WordCloud(width=2000, height=1000, collocations=False,
background_color=”white”,
color_func=col_func,
max_words=200,
设置 random_state 参数为利用 numpy 库中的 randint 函数生成的整数(范围在 1 到 8 之间);然后调用 generate_from_frequencies 方法基于文章三元组的频率进行数据处理。
fig, ax = plt.subplots(figsize=(20,10))
ax.imshow(wc, interpolation=’bilinear’)
ax.axis(“off”)
ax.set_title(‘Trigrams Words of Reuters Articles’, pad=24,
fontdict=fd)
plt.show()


绝大多数三元组与双元组具有相似性,但缺乏进一步的信息。因此,在此阶段我们暂且终止本部分内容的讨论。
3.文本数据的命名实体识别(NER)标记
NER是处理文本数据的一种流程。通过帮助下(ner),我们能够识别文本中的位置信息、人名实体、日期值、数量标示以及组织机构名称等关键信息。深入学习关于NER的更多信息,请借助Spacy Python库来完成这项工作。import spacy
from matplotlib import cm
from matplotlib.pyplot import plt
nlp = spacy.load('en_core_web_sm')
ner_collection = {"Location":[],"Person":[],"Date":[],"Quantity":[],"Organisation":[]}
location = []
person = []
date = []
quantity = []
organisation = []
def ner_text(text):
doc = nlp(text)
ner_collection = {"Location":[],"Person":[],"Date":[],"Quantity":[],"Organisation":[]}
for ent in doc.ents:
if str(ent.label_) == "GPE":
ner_collection['Location'].append(ent.text)
location.append(ent.text)
elif str(ent.label_) == "DATE":
ner_collection['Date'].append(ent.text)
person.append(ent.text)
elif str(ent.label_) == "PERSON":
ner_collection['Person'].append(ent.text)
date.append(ent.text)
elif str(ent.label_) == "ORG":
ner_collection['Organisation'].append(ent.text)
quantity.append(ent.text)
elif str(ent.label_) == "QUANTITY":
ner_collection['Quantity'].append(ent.text)
organisation.append(ent.text)
else:
continue
return ner_collection
将articles_word_limit['text']中的NER信息提取出来,并将其赋值给articles_word_limit['ner_data']。
location_name = []
location_count = []
for i in location_counts.most_common()[:10]:
location_name.append(i[0].upper())
location_count.append(i[1])
fig, ax = plt.subplots(figsize=(15, 8), dpi=100)
ax.barh(location_name, location_count, alpha=0.7,
width = 0.5,
color=cm.Blues([i / 0.00525 for i in [ 0.00208, 0.00235, 0.00281, 0.00317, 0.00362,
0.00371, 0.00525, 0.00679, 0.00761, 0.00833]])
)
plt.rcParams.update({'font.size': 10})
rects = ax.patches
for i, label in enumerate(location_count):
ax.text(label+100 , i, str(label), size=10, ha='center', va='center')
ax.text(0, 1.02, 'Count of Location name Extracted from Reuters Articles',
transform=ax.transAxes, size=12, weight=600, color='#777777')
ax.xaxis.set_ticks_position('bottom')
ax.tick_params(axis='y', colors='black', labelsize=12)
ax.set_axisbelow(True)
ax.text(0, 1.08, 'TOP 10 Location Mention in Reuters Articles',
transform=ax.transAxes, size=22, weight=600, ha='left')
ax.text(0, -0.1, 'Source: http://kdd.ics.uci.edu/databases/reuters21578/reuters21578.html',
transform=ax.transAxes, size=12, weight=600, color='#777777')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
plt.tick_params(axis='y',which='both', left=False, top=False, labelbottom=False)
ax.set_xticks([])
plt.show()

通过分析这个图表,大致可以看出大多数文章的新闻来源主要集中在英语国家以及中国经济中心地区。
对美国的高度评价代表了路透在美业务的重点。
person变量表示1987年谁是名人。这些信息有助于我们了解这些人。
organization变量包含世界上提到最多的组织。
4.文本数据中的唯一词
我们将利用TF-IDF的方法来识别文章中的独特词汇。其中"词频(TF)"表示每个词汇在各篇文章中出现的次数,并将其与该文章的总长度进行比较。"反向文档频率(IDF)"则通过基于所涉及的所有文章来计算关键词的重要性,并结合其在整个语料库中的分布情况来量化其语义价值。
在一篇文献中其关键词的丰富程度较高而在另一篇文献中则不太可能出现或完全缺乏
为了精确地计算出TF-IDF分数,并进一步筛选出具有独特性特征的单词,请确保正确导入必要的文本处理工具包。具体而言,请使用sklearn库中的TfidfVectorizer模块来实现这一目标。
tfidf_vectorizer = TfidfVectorizer(use_idf=True)
tfidf_vectorizer_vectors = tfidf_vectorizer.fit_and_transform(articles_word_limit['text_clean'])
tfidf = tfidf_vectorizer_vectors.todense()
tfidf[tfidf == 0] = np.nan
使用numpy的nanmean,在计算均值时忽略nan
means = np.nanmean(tfidf, axis=0)
将其转换为一个字典,以便以后查找
Means_words = dict(zip(tfidf_vectorizer.get_feature_names(),
means.tolist()[0]))
unique_words=sorted(means_words.items(),
key=lambda x: x[1],
reverse=True)
print(unique_words)

5.用K-均值聚类文章
属于无监督学习范畴的一种机器学习算法属于K-Means家族
from sklearn.cluster import KMeans
from sklearn.metrics import adjusted_rand_score
vectorizer = TfidfVectorizer(stop_words=’english’,use_idf=True)
X = vectorizer.fit_transform(articles_word_limit[‘text_clean’])
k = 4
model = KMeans(n_clusters=k, init=’k-means++’,
max_iter=100, n_init=1)
model.fit(X)
order_centroids = model.cluster_centers_.argsort()[:, ::-1]
terms = vectorizer.get_feature_names()
clusters = model.labels_.tolist()
articles_word_limit.index = clusters
for i in range(k):
print(“Cluster %d words:” % i, end=’’)
for title in articles_word_limit.ix[i
[[‘text_clean’,’index’]].values.tolist():
print(‘ %s,’ % title, end=’’)
它有助于对文章按不同类别实施分类,并非单一领域所能涵盖。K-Means算法的整体分类准确率相对偏低。
结论
我的首选分析方法是NER与K-Means算法。其他研究者或许更倾向于采用N-gram和Unique words等方法。本文着重分享了广为人知的同时也鲜为人知的文本可视化与分析技术。所述的方法均为独特创新设计,在帮助您完成数据可视化的同时也能实现深入的数据分析。
我希望这篇文章能帮助你发现文本数据中的未知数。
