五、实现行业应用
本章为 NLP 的一些行业应用实现了端到端的解决方案。
-
食谱 1。消费者投诉分类
-
食谱 2。客户评论情绪预测
-
食谱三。使用记录链接的数据拼接
-
食谱 4。主题笔记的文本摘要
-
食谱 5。文档聚类
-
食谱 6。搜索引擎和学习排名
-
食谱 7。假新闻检测
-
食谱 8。电影类型标记
我们相信,经过四章的学习,您已经熟悉了自然语言处理的概念,并准备好解决一些业务问题。你需要记住所有的四个章节,并思考解决这些问题的方法。它可以是用于构建应用程序的一个概念或一系列概念。
所以,让我们一个接一个地看一下,以便更好地理解端到端的实现。
配方 5-1。实现多类分类
让我们通过解决金融行业的消费者投诉分类来了解如何在 Python 中对文本数据进行多类分类。
问题
每周,美国消费者金融保护局( www.consumerfinance.gov
)都会向公司发送数千份消费者对金融产品和服务的投诉,要求公司做出回应。您希望使用投诉描述将这些消费者投诉归入其所属的产品类别。
解决办法
该项目的目标是将投诉分类到特定的产品类别中。由于它有多个类别,所以它成为一个多类分类,可以通过许多机器学习算法来解决。
一旦算法到位,每当有新的投诉时,您可以轻松地对其进行分类,并将其重定向到相关人员。这可以节省大量时间,因为您可以最大限度地减少人工干预来决定该向谁投诉。
它是如何工作的
让我们探索数据,并使用许多机器学习算法建立分类问题,看看哪一个给出更好的结果。
步骤 1-1。从 Kaggle 那里获取数据
前往 www.kaggle.com/subhassing/exploring-consumer-complaint-data/data
下载数据。
步骤 1-2。导入库
这里是图书馆。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import string
from nltk.stem import SnowballStemmer
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
import os
from textblob import TextBlob
from nltk.stem import PorterStemmer
from textblob import Word
from sklearn.feature_extraction.text import CountVectorizer,TfidfVectorizer
import sklearn.feature_extraction.text as text
from sklearn import model_selection, preprocessing, linear_model, naive_bayes, metrics, svm
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC
from sklearn.model_selection import cross_val_score
from io import StringIO
import seaborn as sns
步骤 1-3。导入数据
导入在上一步中下载的数据。
Data = pd.read_csv("/Consumer_Complaints.csv",encoding='latin-1')
步骤 1-4。分析日期
我们来分析一下柱子。
Data.dtypes
date_received object
product object
sub_product object
issue object
sub_issue object
consumer_complaint_narrative object
company_public_response object
company object
state object
zipcode object
tags object
consumer_consent_provided object
submitted_via object
date_sent_to_company object
company_response_to_consumer object
timely_response object
consumer_disputed? object
complaint_id int64
# Selecting required columns and rows
Data = Data[['product', 'consumer_complaint_narrative']]
Data = Data[pd.notnull(Data['consumer_complaint_narrative'])]
# See top 5 rows
Data.head()
product consumer_complaint_narrative
190126 Debt collection XXXX has claimed I owe them {$27.00} for XXXX ...
190135 Consumer Loan Due to inconsistencies in the amount owed that...
190155 Mortgage In XX/XX/XXXX my wages that I earned at my job...
190207 Mortgage I have an open and current mortgage with Chase...
190208 Mortgage XXXX was submitted XX/XX/XXXX. At the time I s...
# Factorizing the category column
Data['category_id'] = Data['product'].factorize()[0]
Data.head()
product consumer_complaint_narrative \
190126 Debt collection XXXX has claimed I owe them {$27.00} for XXXX ...
190135 Consumer Loan Due to inconsistencies in the amount owed that...
category_id
190126 0
190135 1
# Check the distriution of complaints by category
Data.groupby('product').consumer_complaint_narrative.count()
product
Bank account or service 5711
Consumer Loan 3678
Credit card 7929
Credit reporting 12526
Debt collection 17552
Money transfers 666
Mortgage 14919
Other financial service 110
Payday loan 726
Prepaid card 861
Student loan 2128
# Lets plot it and see
fig = plt.figure(figsize=(8,6))
Data.groupby('product').consumer_complaint_narrative.count().plot.bar(ylim=0)
plt.show()
收债和抵押贷款的投诉数量最高。
步骤 1-5。拆分数据
将数据分为训练和验证。
train_x, valid_x, train_y, valid_y = model_selection.train_test_split(Data['consumer_complaint_narrative'], Data['product'])
步骤 1-6。使用 TF-IDF 进行特征工程
创建 TF-IDF 向量,如第三章所述。这里我们认为最大特征是 5000。
encoder = preprocessing.LabelEncoder()
train_y = encoder.fit_transform(train_y)
valid_y = encoder.fit_transform(valid_y)
tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000)
tfidf_vect.fit(Data['consumer_complaint_narrative'])
xtrain_tfidf = tfidf_vect.transform(train_x)
xvalid_tfidf = tfidf_vect.transform(valid_x)
步骤 1-7。建立模型并评估
让我们在单词级 TF-IDF 向量上建立一个线性分类器。默认的超参数用于分类器。可以像 C、max_iter 或 solver 一样更改参数,以获得更好的结果。
model = linear_model.LogisticRegression().fit(xtrain_tfidf, train_y)
# Model summary
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class="ovr", n_jobs=1,
penalty='l2', random_state=None, solver="liblinear", tol=0.0001,
verbose=0, warm_start=False)
# Checking accuracy
accuracy = metrics.accuracy_score(model.predict(xvalid_tfidf), valid_y)
print ("Accuracy: ", accuracy)
Accuracy: 0.845048497186
# Classification report
print(metrics.classification_report(valid_y, model.predict(xvalid_tfidf),target_names=Data['product'].unique()))
precision recall f1-score support
Debt collection 0.81 0.79 0.80 1414
Consumer Loan 0.81 0.56 0.66 942
Mortgage 0.80 0.82 0.81 1997
Credit card 0.85 0.85 0.85 3162
Credit reporting 0.82 0.90 0.86 4367
Student loan 0.77 0.48 0.59 151
Bank account or service 0.92 0.96 0.94 3717
Payday loan 0.00 0.00 0.00 26
Money transfers 0.76 0.23 0.35 172
Other financial service 0.77 0.57 0.65 209
Prepaid card 0.92 0.76 0.83 545
avg / total 0.84 0.85 0.84 16702
#confusion matrix
conf_mat = confusion_matrix(valid_y, model.predict(xvalid_tfidf))
# Vizualizing confusion matrix
category_id_df = Data[['product', 'category_id']].drop_duplicates().sort_values('category_id')
category_to_id = dict(category_id_df.values)
id_to_category = dict(category_id_df[['category_id', 'product']].values)
fig, ax = plt.subplots(figsize=(8,6))
sns.heatmap(conf_mat, annot=True, fmt="d", cmap="BuPu",
xticklabels=category_id_df[['product']].values, yticklabels=category_id_df[['product']].values)
plt.ylabel('Actual')
plt.xlabel('Predicted')
plt.show()
85%的准确度对于基线模型来说是好的。除了“发薪日贷款”之外,其他类别的精确度和召回率都相当不错如果你寻找有效负载贷款,大多数错误的预测是债务催收和信用卡,这可能是因为在这一类别的样本数量较少。听起来也像是信用卡的一个子类。您可以将这些样本添加到任何其他组中,以使模型更加稳定。让我们看看一个例子的预测是什么样的。
# Prediction example
texts = ["This company refuses to provide me verification and validation of debt"+ "per my right under the FDCPA. I do not believe this debt is mine."]
text_features = tfidf_vect.transform(texts)
predictions = model.predict(text_features)
print(texts)
print(" - Predicted as: '{}'".format(id_to_category[predictions[0]]))
Result :
['This company refuses to provide me verification and validation of debt per my right under the FDCPA. I do not believe this debt is mine.']
- Predicted as: 'Credit reporting'
为了提高准确性,您可以做以下事情。
-
用不同的算法重复这个过程,比如随机森林,SVM,GBM,神经网络,朴素贝叶斯。
-
也可以使用像 RNN 和 LSTM 这样的深度学习技术(在第六章讨论)。
-
在每一种算法中,都有许多参数需要调整以获得更好的结果。通过网格搜索可以很容易地做到这一点,网格搜索会尝试所有可能的组合并给出最佳结果。
食谱 5-2。实现情感分析
这个菜谱实现了一个流行的 NLP 工业应用:情绪分析。从商业的角度来看,了解客户对他们提供的产品/服务的反馈是非常重要的,以便对产品/服务进行即兴创作以满足客户的需求。
问题
你想实现情感分析。
解决办法
最简单的方法是使用TextBlob
或vaderSentiment
库。既然已经用了 TextBlob,现在就用 Vader 吧。
它是如何工作的
按照本节中的步骤对业务问题实现情感分析。
步骤 2-1。定义业务问题
了解产品在市场上的表现。客户对特定产品的反应如何?消费者跨产品的情绪是怎样的?使用情感分析可以回答更多类似的问题。
第 2-2 步。识别潜在的数据来源并提取洞察力
我们有亚马逊美食评论的数据集。让我们利用这些数据,从中获得真知灼见。您可以从 www.kaggle.com/snap/amazon-fine-food-reviews
下载数据。
# Import necessary libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
#Read the data
df = pd.read_csv('Reviews.csv')
# Look at the top 5 rows of the data
df.head(5)
#output
# Understand the data types of the columns
df.info()
# Output
Data columns (total 10 columns):
Id 5 non-null int64
ProductId 5 non-null object
UserId 5 non-null object
ProfileName 5 non-null object
HelpfulnessNumerator 5 non-null int64
HelpfulnessDenominator 5 non-null int64
Score 5 non-null int64
Time 5 non-null int64
Summary 5 non-null object
Text 5 non-null object
dtypes: int64(5), object(5)
# Looking at the summary of the reviews.
df.Summary.head(5)
# Output
0 Good Quality Dog Food
1 Not as Advertised
2 "Delight" says it all
3 Cough Medicine
4 Great taffy
# Looking at the description of the reviews
df.Text.head(5)
#output
0 I have bought several of the Vitality canned d...
1 Product arrived labeled as Jumbo Salted Peanut...
2 This is a confection that has been around a fe...
3 If you are looking for the secret ingredient i...
4 Great taffy at a great price. There was a wid...
第 2-3 步。预处理数据
你知道这一步的重要性。执行预处理任务,如第二章所述。
# Import libraries
from nltk.corpus import stopwords
from textblob import TextBlob
from textblob import Word
# Lower casing and removing punctuations
df['Text'] = df['Text'].apply(lambda x: " ".join(x.lower() for x in x.split()))
df['Text'] = df['Text'].str.replace('[^\w\s]',")
df.Text.head(5)
# Output
0 i have bought several of the vitality canned d...
1 product arrived labeled as jumbo salted peanut...
2 this is a confection that has been around a fe...
3 if you are looking for the secret ingredient i...
4 great taffy at a great price there was a wide ...
# Removal of stop words
stop = stopwords.words('english')
df['Text'] = df['Text'].apply(lambda x: " ".join(x for x in x.split() if x not in stop))
df.Text.head(5)
# Output
0 bought several vitality canned dog food produc...
1 product arrived labeled jumbo salted peanutsth...
2 confection around centuries light pillowy citr...
3 looking secret ingredient robitussin believe f...
4 great taffy great price wide assortment yummy ...
# Spelling correction
df['Text'] = df['Text'].apply(lambda x: str(TextBlob(x).correct()))
df.Text.head(5)
# Output
0 bought several vitality canned dog food produc...
1 product arrived labelled lumbo halted peanutst...
2 connection around centuries light pillow citie...
3 looking secret ingredient robitussin believe f...
4 great staff great price wide assortment mummy ...
# Lemmatization
df['Text'] = df['Text'].apply(lambda x: " ".join([Word(word).lemmatize() for word in x.split()]))
df.Text.head(5)
# Output
0 bought several vitality canned dog food produc...
1 product arrived labelled lumbo halted peanutst...
2 connection around century light pillow city ge...
3 looking secret ingredient robitussin believe f...
4 great staff great price wide assortment mummy ...
第 2-4 步。分析数据
这一步与预测情绪没有任何联系;我们在这里试图做的是更深入地挖掘数据并理解它。
# Create a new data frame "reviews" to perform exploratory data analysis upon that
reviews = df
# Dropping null values
reviews.dropna(inplace=True)
# The histogram reveals this dataset is highly unbalanced towards high rating.
reviews.Score.hist(bins=5,grid=False)
plt.show()
print(reviews.groupby('Score').count().Id)
# To make it balanced data, we sampled each score by the lowest n-count from above. (i.e. 29743 reviews scored as '2')
score_1 = reviews[reviews['Score'] == 1].sample(n=29743)
score_2 = reviews[reviews['Score'] == 2].sample(n=29743)
score_3 = reviews[reviews['Score'] == 3].sample(n=29743)
score_4 = reviews[reviews['Score'] == 4].sample(n=29743)
score_5 = reviews[reviews['Score'] == 5].sample(n=29743)
# Here we recreate a 'balanced' dataset.
reviews_sample = pd.concat([score_1,score_2,score_3,score_4,score_5],axis=0)
reviews_sample.reset_index(drop=True,inplace=True)
如果您正在从头开始训练自己的情感分类器,可以使用这个数据集。要做到这一点,你可以遵循与文本分类相同的步骤(方法 5-1)。这里,我们的目标变量将是使用 score 创建的正数、负数和中性变量。
-
分数< = 2:负
-
得分= 3:中性
-
得分> =4:正
说到这里,让我们回到我们的探索性数据分析。
# Printing count by 'Score' to check dataset is now balanced.
print(reviews_sample.groupby('Score').count().Id)
# Output
Score
1 29743
2 29743
3 29743
4 29743
5 29743
# Let's build a word cloud looking at the 'Summary' text
from wordcloud import WordCloud
from wordcloud import STOPWORDS
# Wordcloud function's input needs to be a single string of text.
# Here I'm concatenating all Summaries into a single string.
# similarly you can build for Text column
reviews_str = reviews_sample.Summary.str.cat()
wordcloud = WordCloud(background_color='white').generate(reviews_str)
plt.figure(figsize=(10,10))
plt.imshow(wordcloud,interpolation='bilinear')
plt.axis("off")
plt.show()
# Now let's split the data into Negative (Score is 1 or 2) and Positive (4 or #5) Reviews
.
negative_reviews = reviews_sample[reviews_sample['Score'].isin([1,2]) ]
positive_reviews = reviews_sample[reviews_sample['Score'].isin([4,5]) ]
# Transform to single string
negative_reviews_str = negative_reviews.Summary.str.cat()
positive_reviews_str = positive_reviews.Summary.str.cat()
# Create wordclouds
wordcloud_negative = WordCloud(background_color='white').generate(negative_reviews_str)
wordcloud_positive = WordCloud(background_color='white').generate(positive_reviews_str)
# Plot
fig = plt.figure(figsize=(10,10))
ax1 = fig.add_subplot(211)
ax1.imshow(wordcloud_negative,interpolation='bilinear')
ax1.axis("off")
ax1.set_title('Reviews with Negative Scores',fontsize=20)
ax2 = fig.add_subplot(212)
ax2.imshow(wordcloud_positive,interpolation='bilinear')
ax2.axis("off")
ax2.set_title('Reviews with Positive Scores',fontsize=20)
plt.show()
#output
第 2-5 步。使用预先训练好的模型
这一步不是必需的,因为我们不是从零开始构建模型;相反,我们使用来自 Vader perspection 库的预训练模型。
如果您想从头开始构建模型,您可以利用在探索时创建的正类和负类作为目标变量,然后训练模型。你可以按照配方 5-1 中解释的文本分类的相同步骤从头开始构建一个情感分类器。
第 2-6 步。做情感分析
在情感分析中,预训练模型从文本描述中获取输入,并为每个句子输出范围从–1 到+1 的情感得分。
#Importing required libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import re
import os
import sys
import ast
plt.style.use('fivethirtyeight')
# Function for getting the sentiment
cp = sns.color_palette()
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
analyzer = SentimentIntensityAnalyzer()
# Generating sentiment for all the sentence present in the dataset
emptyline=[]
for row in df['Text']:
vs=analyzer.polarity_scores(row)
emptyline.append(vs)
# Creating new dataframe with sentiments
df_sentiments=pd.DataFrame(emptyline)
df_sentiments.head(5)
# Output
compound neg neu pos
0 0.9413 0.000 0.503 0.497
1 -0.5719 0.258 0.644 0.099
2 0.8031 0.133 0.599 0.268
3 0.4404 0.000 0.854 0.146
4 0.9186 0.000 0.455 0.545
# Merging the sentiments back to reviews dataframe
df_c = pd.concat([df.reset_index(drop=True), d], axis=1)
df_c.head(3)
#output sample
# Convert scores into positive and negetive sentiments
using some threshold
df_c['Sentiment'] = np.where(df_c['compound'] >= 0 , 'Positive', 'Negative')
df_c.head(5)
#output sample
第 2-7 步。获得业务洞察力
让我们看看整体情绪是如何使用我们生成的情绪的。
result=df_c['Sentiment'].value_counts()
result.plot(kind='bar', rot=0,color='br');
我们只是抽取了 1000 条评论的样本,并完成了情感分析。如果你看,超过 900 (>90%)的评论是积极的,这对任何企业都有好处。
还可以对副产品进行分组,即情绪副产品,以了解高层客户对产品的反馈。
#Sample code snippet
result=df_c.groupby('ProductId')['Sentiment'].value_counts().unstack()
result[['Negative','Positive']].plot(kind='bar', rot=0,color='rb')
类似地,您可以使用时间列和许多其他类似的属性按月分析情绪。
食谱 5-3。应用文本相似度函数
这个食谱包括使用文本相似性的数据拼接。
问题
数据库中有多个表,有时没有一个公共的 ID 或键来连接它们,包括如下场景。
-
分散在多个表和系统中的客户信息
-
没有全局键将它们链接在一起
-
名字和地址有很多变化
解决办法
这可以通过对人口统计的列(如名字、姓氏、地址等)应用文本相似性函数来解决。根据几个公共列的相似性得分,您可以决定记录对是匹配还是不匹配。
它是如何工作的
按照本节中的步骤链接记录。
以下是技术挑战。
-
需要链接/拼接/消除重复数据的大量记录。
-
记录来自具有不同模式的不同系统。
没有要合并的全局关键字或客户 ID。数据拼接或链接记录有两种可能的情况。
-
同一个客户在同一个表中有多条记录,并且您希望进行重复数据删除。
-
需要合并多个表中相同客户的记录。
对于方案 3a,我们来解决方案 1,即重复数据消除,作为方案 3b 的一部分,我们来解决方案 2,即多个表的记录链接。
同一表中的重复数据删除
步骤 3a-1。阅读并理解数据
首先,你需要数据。
# Import package
!pip install recordlinkage
import recordlinkage
#For this demo let us use the built-in dataset from recordlinkage library
#import data set
from recordlinkage.datasets import load_febrl1
#create a dataframe - dfa
dfA = load_febrl1()
dfA.head()
#output
步骤 3a-2。提取阻止密钥
缩小比较窗口并创建记录对。
-
有非常多的记录;比方说,1 亿条记录意味着(1 亿条选择 2) ≈ 10¹⁶ 可能对
-
需要一种启发式方法来快速击倒 10¹⁶ 而不输掉很多比赛
这可以通过提取阻止密钥来实现。下面是一个例子。
-
记录:名:约翰,姓:罗伯茨,地址:马萨诸塞州梅因街 20 号,邮编:01111
-
封锁键:名字-约翰
-
搭配:约翰·雷…011
-
不会搭配:弗兰克·辛纳屈…07030
-
仅为同一块中的记录生成对
这里,阻塞是在“Sndx-SN”列上完成的,这是姓氏列的 Soundex 值,如第四章中所讨论的。
还有许多高级的阻塞技术,如下所示。
-
标准阻塞
-
单柱的
-
多列
-
-
排序邻域
-
Q-gram:模糊阻塞
-
激光冲徊化
-
树冠集群
这可能是一个全新的话题,但是现在,让我们使用名字作为阻塞索引来构建配对。
indexer = recordlinkage.BlockIndex(on='given_name')
pairs = indexer.index(dfA)
print (len(pairs))
#output
2082
步骤 3a-3。进行相似性匹配和评分
这里,我们计算上一步中生成的记录对之间的列(如名、姓和地址)的相似性得分。对于像出生日期、郊区和州这样的列,我们使用精确匹配,因为该列拥有精确的记录是很重要的。
我们使用 Jaro-Winkler,但是你可以使用在第四章中讨论的任何其他相似性度量。
# This cell can take some time to compute.
compare_cl = recordlinkage.Compare()
compare_cl.string('given_name', 'given_name',method='jarowinkler', label="given_name")
compare_cl.string('surname', 'surname', method="jarowinkler", label="surname")
compare_cl.exact('date_of_birth', 'date_of_birth', label="date_of_birth")
compare_cl.exact('suburb', 'suburb', label="suburb")
compare_cl.exact('state', 'state', label="state")
compare_cl.string('address_1', 'address_1',method='jarowinkler', label="address_1")
features = compare_cl.compute(pairs, dfA)
features.sample(5)
#output
这里,记录“rec-115-dup-0”与“rec-120-dup-0”进行了比较因为他们的名字(阻止列)匹配,所以在这些对的公共列上计算相似性分数。
步骤 3a-4。使用 ECM 分类器预测记录是否匹配
以下是计算记录匹配概率的无监督学习方法。
# select all the features except for given_name since its our blocking key
features1 = features[['suburb','state','surname','date_of_birth','address_1']]
# Unsupervised learning – probabilistic
ecm = recordlinkage.ECMClassifier()
result_ecm = ecm.learn((features1).astype(int),return_type = 'series')
result_ecm
#output
rec_id rec_id
rec-122-org rec-183-dup-0 0
rec-248-org 0
rec-469-org 0
rec-74-org 0
rec-183-org 0
rec-360-dup-0 0
rec-248-dup-0 0
rec-469-dup-0 0
rec-183-dup-0 rec-248-org 0
rec-469-org 0
rec-74-org 0
rec-183-org 1
rec-360-dup-0 0
rec-248-dup-0 0
rec-469-dup-0 0
rec-248-org rec-469-org 0
rec-74-org 0
rec-360-dup-0 0
rec-469-dup-0 0
rec-122-dup-0 rec-122-org 1
rec-183-dup-0 0
rec-248-org 0
rec-469-org 0
rec-74-org 0
rec-183-org 0
rec-360-dup-0 0
rec-248-dup-0 0
rec-469-dup-0 0
rec-469-org rec-74-org 0
rec-183-org rec-248-org 0
..
rec-208-dup-0 rec-208-org 1
rec-363-dup-0 rec-363-org 1
rec-265-dup-0 rec-265-org 1
rec-315-dup-0 rec-315-org 1
rec-410-dup-0 rec-410-org 1
rec-290-org rec-93-org 0
rec-460-dup-0 rec-460-org 1
rec-499-dup-0 rec-499-org 1
rec-11-dup-0 rec-11-org 1
rec-97-dup-0 rec-97-org 1
rec-213-dup-0 rec-421-dup-0 0
rec-349-dup-0 rec-376-dup-0 0
rec-371-dup-0 rec-371-org 1
rec-129-dup-0 rec-129-org 1
rec-462-dup-0 rec-462-org 1
rec-328-dup-0 rec-328-org 1
rec-308-dup-0 rec-308-org 1
rec-272-org rec-308-dup-0 0
rec-308-org 0
rec-5-dup-0 rec-5-org 1
rec-407-dup-0 rec-407-org 1
rec-367-dup-0 rec-367-org 1
rec-103-dup-0 rec-103-org 1
rec-195-dup-0 rec-195-org 1
rec-184-dup-0 rec-184-org 1
rec-252-dup-0 rec-252-org 1
rec-48-dup-0 rec-48-org 1
rec-298-dup-0 rec-298-org 1
rec-282-dup-0 rec-282-org 1
rec-327-org rec-411-org 0
输出清楚地显示“rec-183-dup-0”与“rec-183-org”匹配,并且可以链接到一个全局 ID。到目前为止,我们所做的被称为重复数据删除:从单个表中识别相同用户的多个记录。
多个表中相同客户的记录
接下来,让我们看看如果记录在多个表中,而没有唯一的 id 来合并,如何解决这个问题。
步骤 3b-1。阅读并理解数据
让我们使用 recordlinkage 库中的内置数据集。
from recordlinkage.datasets import load_febrl4
dfA, dfB = load_febrl4()
dfA.head()
#output
dfB.head()
#output
步骤 3b-2。块来缩小比较窗口并创建记录对
这与前面的解释相同,将 given_name 视为一个阻塞索引。
indexer = recordlinkage.BlockIndex(on='given_name')
pairs = indexer.index(dfA, dfB)
步骤 3b-3。做相似性匹配
解释是一样的。
compare_cl = recordlinkage.Compare()
compare_cl.string('given_name', 'given_name',method='jarowinkler', label="given_name")
compare_cl.string('surname', 'surname', method="jarowinkler", label="surname")
compare_cl.exact('date_of_birth', 'date_of_birth', label="date_of_birth")
compare_cl.exact('suburb', 'suburb', label="suburb")
compare_cl.exact('state', 'state', label="state")
compare_cl.string('address_1', 'address_1',method='jarowinkler', label="address_1")
features = compare_cl.compute(pairs, dfA, dfB)
features.head(10)
#output
因此,这里将记录“rec-1070-org”与“rec-3024-dup-0”、“rec-2371-dup-0”、“rec-4652-dup-0”、“rec-4795-dup-0”和“rec-1314-dup-0”进行比较,因为它们的名字(阻止列)是匹配的,并且在这些对的公共列上计算相似性得分。
步骤 3b-4。使用 ECM 分类器预测记录是否匹配
下面是一个无监督的学习方法来计算记录匹配的概率。
# select all the features except for given_name since its our blocking key
features1 = features[['suburb','state','surname','date_of_birth','address_1']]
# unsupervised learning - probablistic
ecm = recordlinkage.ECMClassifier()
result_ecm = ecm.learn((features1).astype(int),return_type = 'series')
result_ecm
#output sample
rec_id rec_id
rec-1070-org rec-3024-dup-0 0
rec-2371-dup-0 0
rec-4652-dup-0 0
rec-4795-dup-0 0
rec-1314-dup-0 0
rec-2371-org rec-3024-dup-0 0
rec-2371-dup-0 1
rec-4652-dup-0 0
rec-4795-dup-0 0
rec-1314-dup-0 0
rec-3582-org rec-3024-dup-0 0
rec-2371-dup-0 0
rec-4652-dup-0 0
rec-4795-dup-0 0
rec-1314-dup-0 0
rec-3024-org rec-3024-dup-0 1
rec-2371-dup-0 0
rec-4652-dup-0 0
rec-4795-dup-0 0
rec-1314-dup-0 0
rec-4652-org rec-3024-dup-0 0
rec-2371-dup-0 0
rec-4652-dup-0 1
rec-4795-dup-0 0
rec-1314-dup-0 0
rec-4795-org rec-3024-dup-0 0
rec-2371-dup-0 0
rec-4652-dup-0 0
rec-4795-dup-0 1
rec-1314-dup-0 0
..
rec-2820-org rec-2820-dup-0 1
rec-991-dup-0 0
rec-1984-org rec-1984-dup-0 1
rec-1662-org rec-1984-dup-0 0
rec-4415-org rec-1984-dup-0 0
rec-1920-org rec-1920-dup-0 1
rec-303-org rec-303-dup-0 1
rec-1915-org rec-1915-dup-0 1
rec-4739-org rec-4739-dup-0 1
rec-4865-dup-0 0
rec-681-org rec-4276-dup-0 0
rec-4603-org rec-4848-dup-0 0
rec-4603-dup-0 1
rec-3122-org rec-4848-dup-0 0
rec-4603-dup-0 0
rec-3711-org rec-3711-dup-0 1
rec-4912-org rec-4912-dup-0 1
rec-664-org rec-664-dup-0 1
rec-1311-dup-0 0
rec-4031-org rec-4031-dup-0 1
rec-1413-org rec-1413-dup-0 1
rec-735-org rec-735-dup-0 1
rec-1361-org rec-1361-dup-0 1
rec-3090-org rec-3090-dup-0 1
rec-2571-org rec-2571-dup-0 1
rec-4528-org rec-4528-dup-0 1
rec-4887-org rec-4887-dup-0 1
rec-4350-org rec-4350-dup-0 1
rec-4569-org rec-4569-dup-0 1
rec-3125-org rec-3125-dup-0 1
输出清楚地显示“rec-122-dup-0”与“rec-122-org”匹配,并且可以链接到一个全局 ID。
通过这种方式,您可以创建一个由惟一的全局 ID 和跨表的一致数据组成的数据湖,并执行统计分析。
食谱 5-4。汇总文本数据
如果你只是四处看看,有很多文章和书籍。让我们假设你想学习 NLP 中的一个概念,如果你谷歌它,你找到一篇文章。你喜欢这篇文章的内容,但它太长了,不能再看一遍。您希望对文章进行总结,并将其保存在某个地方,以便以后阅读。
NLP 有一个解决方案。文本摘要有助于做到这一点。你不必每次都阅读整篇文章或整本书。
问题
在 Python 中使用不同算法的文章/文档的文本摘要。
解决办法
文本摘要是在不丢失上下文的情况下将大文档变成小文档的过程,最终节省了读者的时间。这可以使用不同的技术来完成,如下所示。
-
TextRank:一种基于图的排序算法
-
基于特征的文本摘要
-
基于图的算法的 TF-IDF
-
基于主题的
-
使用句子嵌入
-
编码器-解码器模型:深度学习技术
它是如何工作的
探索这个食谱中的前两种方法。
步骤 4-1。使用文本排名
TextRank 是 NLP 的基于图的排序算法。它的灵感来自于 PageRank,这是谷歌搜索引擎中使用的,但专门为文本设计的。它提取主题,从中创建节点,并捕获节点之间的关系来总结文本。
让我们看看如何使用 Python 的 gensim 包来实现。功能是summarize
。
首先,让我们导入注释。假设你正在看一篇关于自然语言处理的维基百科文章。
# Import BeautifulSoup and urllib libraries to fetch data from Wikipedia.
from bs4 import BeautifulSoup
from urllib.request import urlopen
# Function to get data from Wikipedia
def get_only_text(url):
page = urlopen(url)
soup = BeautifulSoup(page)
text = ' '.join(map(lambda p: p.text, soup.find_all('p')))
print (text)
return soup.title.text, text
# Mention the Wikipedia url
url="https://en.wikipedia.org/wiki/Natural_language_processing"
# Call the function created above
text = get_only_text(url)
# Count the number of letters
len(".join(text))
Result:
Out[74]: 8519
# Lets see first 1000 letters from the text
text[:1000]
Result :
Out[72]: '(\'Natural language processing
- Wikipedia\', \'Natural language processing (NLP) is an area of computer science and artificial intelligence concerned with the interactions between computers and human (natural) languages, in particular how to program computers to process and analyze large amounts of natural language\\xa0data.\\n Challenges in natural language processing frequently involve speech recognition, natural language understanding, and natural language generation.\\n The history of natural language processing generally started in the 1950s, although work can be found from earlier periods.\\nIn 1950, Alan Turing published an article titled "Intelligence" which proposed what is now called the Turing test as a criterion of intelligence.\\n The Georgetown experiment in 1954 involved fully automatic translation of more than sixty Russian sentences into English. The authors claimed that within three or five years, machine translation would be a solved problem.[2] However, real progress was '
# Import summarize from gensim
from gensim.summarization.summarizer import summarize
from gensim.summarization import keywords
# Convert text to string format
text = str(text)
#Summarize the text with ratio 0.1 (10% of the total words.)
summarize(text, ratio=0.1)
Result:
Out[77]: 'However, part-of-speech tagging introduced the use of hidden Markov models to natural language processing, and increasingly, research has focused on statistical models, which make soft, probabilistic decisions based on attaching real-valued weights to the features making up the input data.\nSuch models are generally more robust when given unfamiliar input, especially input that contains errors (as is very common for real-world data), and produce more reliable results when integrated into a larger system comprising multiple subtasks.\\n Many
of the notable early successes occurred in the field of machine translation, due especially to work at IBM Research, where successively more complicated statistical models were developed.'
就是这样。生成的摘要就是这么简单。如果你看了这个总结和整篇文章,就足够接近了。但是,仍然有很大的改进空间。
#keywords
print(keywords(text, ratio=0.1))
Result:
learning
learn
languages
process
systems
worlds
world
real
natural language processing
research
researched
results
result
data
statistical
hand
generation
generally
generic
general
generated
tasks
task
large
human
intelligence
input
called
calling
calls
produced
produce
produces
producing
possibly
possible
corpora
base
based
第 4-2 步。使用基于特征的文本摘要
基于特征的文本摘要方法从句子中提取一个特征,并检查其重要性。位置、长度、术语频率、命名实体和许多其他特征用于计算分数。
Luhn 的算法是基于特征的算法之一。让我们看看如何使用 sumy 库来实现它。
# Install sumy
!pip install sumy
# Import the packages
from sumy.parsers.html import HtmlParser
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.lsa import LsaSummarizer
from sumy.nlp.stemmers import Stemmer
from sumy.utils import get_stop_words
from sumy.summarizers.luhn import LuhnSummarizer
# Extracting and summarizing
LANGUAGE = "english"
SENTENCES_COUNT = 10
url="https://en.wikipedia.org/wiki/Natural_language_processing"
parser = HtmlParser.from_url(url, Tokenizer(LANGUAGE))
summarizer = LsaSummarizer()
summarizer = LsaSummarizer(Stemmer(LANGUAGE))
summarizer.stop_words = get_stop_words(LANGUAGE)
for sentence in summarizer(parser.document, SENTENCES_COUNT):
print(sentence)
Result :
[2] However, real progress was much slower, and after the ALPAC report in 1966, which found that ten-year-long research had failed to fulfill the expectations, funding for machine translation was dramatically reduced.
However, there is an enormous amount of non-annotated data available (including, among other things, the entire content of the World Wide Web ), which can often make up for the inferior results if the algorithm used has a low enough time complexity to be practical
, which some such as Chinese Whispers do.
Since the so-called "statistical revolution"
in the late 1980s and mid 1990s, much natural language processing research has relied heavily on machine learning .
Increasingly, however, research has focused on statistical models , which make soft, probabilistic decisions based on attaching real-valued weights to each input feature.
Natural language understanding
Convert chunks of text into more formal representations such as first-order logic structures that are easier for computer programs to manipulate.
[18] ^ Implementing an online help desk system based on conversational agent Authors: Alisa Kongthon, Chatchawal Sangkeettrakarn, Sarawoot Kongyoung and Choochart Haruechaiyasak.
[ self-published source ] ^ Chomskyan linguistics encourages the investigation of " corner cases " that stress the limits of its theoretical models (comparable to pathological phenomena in mathematics), typically created using thought experiments , rather than the systematic investigation of typical phenomena that occur in real-world data, as is the case in corpus linguistics .
^ Antonio Di Marco - Roberto Navigili, "Clustering and Diversifying Web Search Results with Graph Based Word Sense Induction" , 2013 Goldberg, Yoav (2016).
Scripts, plans, goals, and understanding: An inquiry into human knowledge structures ^ Kishorjit, N., Vidya Raj RK., Nirmal Y., and Sivaji B.
^ PASCAL Recognizing Textual Entailment Challenge (RTE-7) https://tac.nist.gov//2011/RTE/ ^ Yi, Chucai; Tian, Yingli (2012), "Assistive Text Reading from Complex Background for Blind Persons" , Camera-Based Document Analysis and Recognition , Springer Berlin Heidelberg, pp.
问题解决了。现在你不必读所有的笔记;只要在我们时间不多的时候读一下摘要就可以了。
你可以使用深度学习技术来获得更好的准确性和更好的结果,比如编码器-解码器模型。你将在下一章看到如何去做。
食谱 5-5。聚类文档
文档聚类,也叫文本聚类,是对文本文档的聚类分析。一个典型的应用是文档管理。
问题
您希望根据模式和相似性对文档进行聚类或分组。
解决办法
文档聚类包括类似的步骤。
-
符号化。
-
词干化和词汇化。
-
删除停用词和标点符号。
-
计算术语频率或 TF-IDF。
-
聚类:k 均值/层次。然后,您可以使用任何聚类算法,根据我们生成的特征对不同的文档进行聚类
-
评估和可视化:可以通过将聚类绘制到二维空间中来可视化聚类结果。
它是如何工作的
步骤 5-1。导入数据和库
下面是库,后面是数据。
!pip install mpld3
import numpy as np
import pandas as pd
import nltk
from nltk.stem.snowball import SnowballStemmer
from bs4 import BeautifulSoup
import re
import os
import codecs
from sklearn import feature_extraction
import mpld3
from sklearn.metrics.pairwise import cosine_similarity
import os
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.manifold import MDS
#Lets use the same complaint dataset we use for classification
Data = pd.read_csv("/Consumer_Complaints.csv",encoding='latin-1')
#selecting required columns and rows
Data = Data[['consumer_complaint_narrative']]
Data = Data[pd.notnull(Data['consumer_complaint_narrative'])]
# lets do the clustering for just 200 documents
. Its easier to interpret.
Data_sample=Data.sample(200)
第 5-2 步。预处理和使用 TF-IDF 特征工程
现在我们来预处理一下。
# Remove unwanted symbol
Data_sample['consumer_complaint_narrative'] = Data_sample['consumer_complaint_narrative'].str.replace('XXXX',")
# Convert dataframe to list
complaints = Data_sample['consumer_complaint_narrative'].tolist()
# create the rank of documents – we will use it later
ranks = []
for i in range(1, len(complaints)+1):
ranks.append(i)
# Stop Words
stopwords = nltk.corpus.stopwords.words('english')
# Load 'stemmer'
stemmer = SnowballStemmer("english")
# Functions for sentence tokenizer, to remove numeric tokens and raw #punctuation
def tokenize_and_stem(text):
tokens = [word for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
filtered_tokens = []
for token in tokens:
if re.search('[a-zA-Z]', token):
filtered_tokens.append(token)
stems = [stemmer.stem(t) for t in filtered_tokens]
return stems
def tokenize_only(text):
tokens = [word.lower() for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
filtered_tokens = []
for token in tokens:
if re.search('[a-zA-Z]', token):
filtered_tokens.append(token)
return filtered_tokens
from sklearn.feature_extraction.text import TfidfVectorizer
# tfidf vectorizer
tfidf_vectorizer = TfidfVectorizer(max_df=0.8, max_features=200000,
min_df=0.2, stop_words="english",
use_idf=True, tokenizer=tokenize_and_stem, ngram_range=(1,3))
#fit the vectorizer to data
tfidf_matrix = tfidf_vectorizer.fit_transform(complaints)
terms = tfidf_vectorizer.get_feature_names()
print(tfidf_matrix.shape)
(200, 30)
第 5-3 步。使用 k-均值聚类
让我们开始聚类。
#Import Kmeans
from sklearn.cluster import KMeans
# Define number of clusters
num_clusters = 6
#Running clustering algorithm
km = KMeans(n_clusters=num_clusters)
km.fit(tfidf_matrix)
#final clusters
clusters = km.labels_.tolist()
complaints_data = { 'rank': ranks, 'complaints': complaints, 'cluster': clusters }
frame = pd.DataFrame(complaints_data, index = [clusters] , columns = ['rank', 'cluster'])
#number of docs per cluster
frame['cluster'].value_counts()
0 42
1 37
5 36
3 36
2 27
4 22
第 5-4 步。识别集群行为
确定最接近聚类质心的前五个单词。
totalvocab_stemmed = []
totalvocab_tokenized = []
for i in complaints:
allwords_stemmed = tokenize_and_stem(i)
totalvocab_stemmed.extend(allwords_stemmed)
allwords_tokenized = tokenize_only(i)
totalvocab_tokenized.extend(allwords_tokenized)
vocab_frame = pd.DataFrame({'words': totalvocab_tokenized}, index = totalvocab_stemmed)
#sort cluster centers by proximity to centroid
order_centroids = km.cluster_centers_.argsort()[:, ::-1]
for i in range(num_clusters):
print("Cluster %d words:" % i, end=")
for ind in order_centroids[i, :6]:
print(' %s' % vocab_frame.ix[terms[ind].split(' ')].values.tolist()[0][0].encode('utf-8', 'ignore'), end=',')
print()
Cluster 0 words: b'needs', b'time', b'bank', b'information', b'told'
Cluster 1 words: b'account', b'bank', b'credit', b'time', b'months'
Cluster 2 words: b'debt', b'collection', b'number', b'credit', b"n't"
Cluster 3 words: b'report', b'credit', b'credit', b'account', b'information'
Cluster 4 words: b'loan', b'payments', b'pay', b'months', b'state'
Cluster 5 words: b'payments', b'pay', b'told', b'did', b'credit'
第 5-5 步。在 2D 图上画出聚类图
最后,绘制聚类图。
#Similarity
similarity_distance = 1 - cosine_similarity(tfidf_matrix)
# Convert two components as we're plotting points in a two-dimensional plane
mds = MDS(n_components=2, dissimilarity="precomputed", random_state=1)
pos = mds.fit_transform(similarity_distance) # shape (n_components, n_samples)
xs, ys = pos[:, 0], pos[:, 1]
#Set up colors per clusters using a dict
cluster_colors = {0: '#1b9e77', 1: '#d95f02', 2: '#7570b3', 3: '#e7298a', 4: '#66a61e', 5: '#D2691E'}
#set up cluster names using a dict
cluster_names = {0: 'property, based, assist',
1: 'business, card',
2: 'authorized, approved, believe',
3: 'agreement, application,business',
4: 'closed, applied, additional',
5: 'applied, card'}
# Finally plot it
%matplotlib inline
#Create data frame that has the result of the MDS and the cluster
df = pd.DataFrame(dict(x=xs, y=ys, label=clusters))
groups = df.groupby('label')
# Set up plot
fig, ax = plt.subplots(figsize=(17, 9)) # set size
for name, group in groups:
ax.plot(group.x, group.y, marker="o", linestyle=", ms=20,
label=cluster_names[name], color=cluster_colors[name],
mec='none')
ax.set_aspect('auto')
ax.tick_params(\
axis= 'x',
which='both',
bottom='off',
top='off',
labelbottom='off')
ax.tick_params(\
axis= 'y',
which='both',
left='off',
top='off',
labelleft='off')
ax.legend(numpoints=1)
plt.show()
就是这样。使用 k-means 聚类将 200 个投诉分成六组。它使用 TF-IDF 将类似的投诉分为六类。你也可以使用嵌入这个词,并解决这个问题,以实现更好的集群。2D 图提供了一个易于理解的集群行为视图。您会看到相同颜色的点(文档)彼此更靠近。
配方 5-6。搜索引擎中的自然语言处理
这个菜谱从 NLP 的角度讨论了构建一个搜索引擎需要什么。然而,实现超出了本书的范围。
问题
你想知道构建搜索引擎的架构和 NLP 管道。
解决办法
图 5-1 显示了整个过程。每个步骤都在“工作原理”一节中进行了解释。
图 5-1
搜索引擎中的自然语言处理过程
它是如何工作的
从 NLP 的角度来看,一步一步地遵循这个架构来构建一个搜索引擎。
步骤 6-1。预处理
每当用户输入搜索查询时,它都会被传递到 NLP 预处理管道。
-
噪音和停用词的去除
-
标记化
-
堵塞物
-
词汇化
第 6-2 步。使用实体提取模型
来自管道的输出被输入到实体提取模型中。您可以通过使用任何像 StanfordNER 或 NLTK 这样的库来构建定制的实体识别模型。
或者,您可以使用条件随机场或马尔可夫模型从头开始构建实体识别模型。
例如,假设你正在为一个电子商务巨头建立一个搜索引擎。以下是可以用来训练模型的实体。
-
性别
-
颜色
-
品牌
-
积范畴
-
产品类型
-
价格
-
大小
你可以使用像 RNN 和 LSTM 这样的深度学习框架来构建命名实体消歧。这对实体提取器理解使用实体的内容是非常重要的。比如,粉色可以是一种颜色,也可以是一个品牌。内德有助于消除这种歧义。
书呆子模型构建步骤。
-
数据清理和预处理
-
培训 NER 模型
-
测试和验证
-
部署
培训/建立书呆子模型的方法
-
命名实体识别和消歧
-
斯坦福 NER 定制
-
循环神经网络(RNN)–LSTM(长短期记忆)使用上下文来消除歧义
-
联合命名实体识别和消歧
第 6-3 步。进行查询增强/扩展
理解实体可能的同义词非常重要,以确保搜索结果不会错过潜在的相关性。比如男鞋也可以叫做男鞋、男式运动鞋、男式正装鞋、男式休闲鞋,或者男式运动鞋。
使用本地训练的单词嵌入(使用单词 2vec/ 手套模型**)来实现这一点。**
第 6-4 步。使用搜索平台
Solr 或 Elasticsearch 等搜索平台的主要功能包括全文搜索点击突出显示、分面搜索、实时索引、动态聚类和数据库集成。这与 NLP 无关。从端到端应用的角度来看,我们刚刚向您介绍了这是什么。
第 6-5 步。学会排名
一旦从 Solr 或 Elasticsearch 获取了搜索结果,就应该使用过去的行为根据用户的偏好对它们进行排序。
食谱 5-7。检测假新闻
在社交媒体时代,假新闻带来了很多问题。当然,没有人会想到假新闻会成为这个时代最大的问题之一。但是,像所有问题一样,数据科学也有一个解决这个问题的方法,如果不是非常准确,也有一些可接受的准确性。
问题
为什么假新闻是一个需要解决的重要问题?近年来,假新闻的制造和传播显著增加,主要是在社交媒体平台上,如 WhatsApp、脸书和 Instagram。假新闻可以出现在任何类型的新闻中——政治、地方、健康、娱乐、技术相关问题等等。许多错误的决定都是基于未经证实的假新闻。区分真假新闻很有挑战性。
目标是建立一个二元分类模型,可以根据内容区分真实新闻和虚假新闻。
解决办法
这是一个二元分类问题。假新闻一类,真新闻一类。除了这些类,还有一组文本文档。以下是解决问题的步骤。
-
首先,将原始数据转换为数据帧,以便进一步处理。
-
预处理和清理文本数据。
-
清洗完数据后,进行特征工程。
-
对数据进行探索以发掘潜在的洞察力。
-
这些特征构建了模型,在本例中,是一个使用逻辑回归、随机森林、朴素贝叶斯、SVM 等算法的分类器模型。
-
模型的超参数被调整和评估。最后,对模型的结果进行了验证。
它是如何工作的
步骤 7-1。收集数据
让我们使用 http://web.eecs.umich.edu/~mihalcea/downloads/fakeNewsDatasets.zip/
的免费源数据集。一小部分数据已经被标记。
“假新闻”数据集包含六个不同的领域:商业、技术、政治、教育、体育和娱乐。数据集中包含的合法新闻来自各种新闻网站,如 ABC 新闻、今日美国、CNN、纽约时报、福克斯新闻频道、彭博等等。该数据集中的假新闻由使用 Mechanical Turk 编写的真实新闻的虚假版本组成。
所有的原始新闻都被聚合起来放在 fakenews_dataset.csv 中,这是本书用到的。
第 7-2 步。安装库
让我们导入该任务所需的所有库。
# Data Manipulation
import pandas as pd
import numpy as np
# Visualization
import matplotlib.pyplot as plt
import seaborn as sns
# Plot the Figures Inline
%matplotlib inline
#NLP
import nltk
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
from textblob import Word
from sklearn.feature_extraction.text import TfidfVectorizer
#Machine Learning
from sklearn.ensemble import RandomForestClassifier
from sklearn import model_selection, preprocessing, linear_model, naive_bayes, metrics, svm
from sklearn.model_selection import train_test_split
第 7-3 步。分析数据
让我们导入数据集。
#importing dataset
df = pd.read_csv(' fakenews_dataset.csv')
df.shape
(980, 3)
df.sample(5)
数据框由 980 个观测值和三列组成。
-
类别是新闻文章所属的类别(即名人、教育(edu)等。).
-
新闻是整个新闻内容
-
假的是标签;1 表示新闻文章是假的,0 表示是真的。
第 7-4 步。做探索性数据分析
我们来深入分析一下数据。
df['Category'].value_counts()
Celebrity 500
biz 80
tech 80
sports 80
entmt 80
polit 80
edu 80
Name: Category, dtype: int64
#no. of news per category
sns.countplot(x='Category', data=df)
#adding additional column for length
df['length']=df['News'].str.len()
df.head()
#Cheking max and min length of the News articles
maxlength = df['length'].max()
minlength = df['length'].min()
maxlength,minlength
(76490, 144)
合法新闻与假新闻的文章长度柱状图。
df.hist(column='length', by='Fake', bins=50,figsize=(12,4),color='orange')
假新闻文章大多不到 5000 字。
#各种类别的文章长度。
df.hist(column='length', by='Category', bins=50,figsize=(20,10),color='orange')
关于名人的文章比其他新闻文章要长。
第 7-5 步。预处理数据
数据预处理包括以下四个步骤。
-
将转换为小写。
df['News'] = df['News'].apply(lambda x: " ".join(x.lower() for x in x.split())) print(df['News'].head())
-
去掉标点符号。
df['News'] = df['News'].str.replace('[^\w\s]','') print(df['News'].head())
去掉停止的话。停用词从 nltk 库中导入。
stop = stopwords.words('english') df['News'] = df['News'].apply(lambda x: " ".join(x for x in x.split() if x not in stop))
-
做词汇化。
from nltk.stem import WordNetLemmatizer df['News'] = df['News'].apply(lambda x: " ".join([Word(word).lemmatize() for word in x.split()])) df['News'].head() 0 jennifer aniston hint friend reunionjennifer a... 1 brad pitt text jennifer aniston nonstop seek i... 2 jennifer aniston pregnant miracle baby 47 repo... 3 heartbroken jennifer aniston run border adoptj... 4 jennifer aniston cheated brad pitt matt leblan... Name: News, dtype: object
第 7-6 步。使用训练测试分割
从 sklearn.model_selection 导入 train_test_split 库,将数据帧分成两部分。
# splitting into training and testing data
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.3, random_state=100, stratify=y)
#validate the shape of train and test dataset
print (X_train.shape)
print (y_train.shape)
print (X_test.shape)
print (y_test.shape)
(686, 3)
(686,)
(294, 3)
(294,)
第 7-7 步。做特征工程
tfidf 矢量器库(来自sklearn.feature_extraction.text
)从文本中生成特征。
tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000)
tfidf_vect.fit(df['News'])
xtrain_tfidf = tfidf_vect.transform(X_train['News'])
xtest_tfidf = tfidf_vect.transform(X_test['News'])
这些特征是从文本中提取出来的。下一步让我们构建模型。
第 7-8 步。建立一个模型
这是一个以假新闻和真新闻为类的分类算法。文本已被转换为特征。我们来试试各种机器学习算法,看看哪种准确率更好。
建立模型时考虑了各种算法。
-
朴素贝叶斯分类器
-
线性分类器(逻辑回归)
-
支持向量机分类器
-
随机森林分类器
让我们构建一个可以用于各种算法的通用函数。
def train_model(classifier, feature_vector_train, label, feature_vector_test):
# fitting
classifier.fit(feature_vector_train, label)
# predicting
predictions = classifier.predict(feature_vector_test)
return metrics.accuracy_score(predictions, y_test)
先说朴素贝叶斯。
accuracy = train_model(naive_bayes.MultinomialNB(), xtrain_tfidf, y_train, xtest_tfidf)
print ("Accuracy of Naive Bayes: ", accuracy)
Accuracy: 0.47959183673469385
下面是逻辑回归。
accuracy = train_model(linear_model.LogisticRegression(), xtrain_tfidf, y_train, xtest_tfidf)
print ("Accuracy of logistic regression: ", accuracy)
Accuracy: 0.5374149659863946
#SVM。
accuracy = train_model(svm.SVC(), xtrain_tfidf, y_train, xtest_tfidf)
print ("Accuracy of SVM: ", accuracy)
Accuracy: 0.5306122448979592
下面是随机森林。
accuracy = train_model(RandomForestClassifier(), xtrain_tfidf, y_train, xtest_tfidf)
print ("Accuracy of RandomForest: ", accuracy)
Accuracy: 0.5884353741496599
观察:二项式线性分类器(logistics regression)被认为是这个问题中最合适的算法。让我们再次构建模型,并了解其他精度参数
LogisticRegression()
函数存在于 sklearn 的 linear_model 库中。
#fit the model
model=linear_model.LogisticRegression()
nb = model.fit(xtrain_tfidf,y_train)
nb
分类器模型的结果以二进制数组的形式显示预测,其中 1 表示虚假,0 表示合法。
## Model Results:
predictions = nb.predict(xtest_tfidf)
predictions
模型评估
可以基于两个参数来评估分类器模型。
| 长吨 | 冰点 | | 【数学】函数 | 东帝汶的网络域名代号 |- 混淆矩阵
以下是模型的混淆矩阵报告。
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
print(classification_report(y_test, predictions,target_names=["Legit", "Fake"]))
precision recall f1-score support
Legit 0.54 0.56 0.55 147
Fake 0.54 0.52 0.53 147
avg / total 0.54 0.54 0.54 294
数据的 f1 总分是 54%。
- AUC(曲线下面积)分数
AUC for the built model.
from sklearn.metrics import roc_auc_score
nb_auc = roc_auc_score(y_test, nb.predict_proba(xtest_tfidf)[:, 1])
print("AUC for Model: {:.3f}".format(nb_auc))
AUC for Model: 0.559
曲线下面积为 56%。
可以看到有高达 55%的准确率。您可以通过更多的标记数据收集和调整参数来提高准确性。
让我们看看超参数调整能否提高精度。
第 7-9 步。调整超参数
让我们使用网格搜索参数调整,它有条不紊地为网格中指定的每个参数组合构建和评估模型。
以下是超参数调整的步骤。
-
导入参数网格。
-
符合模型。
from sklearn.model_selection import GridSearchCV
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 15,20,100]}
- 进行网格搜索。
cf_model=linear_model.LogisticRegression()
- 将模型拟合到训练数据上。
grid_search = GridSearchCV(cf_model, param_grid, cv=5)
- 评估。
grid_search.fit(xtrain_tfidf, y_train)
- 找到模型的最佳参数。
print("Test set score: {:.2f}".format(grid_search.score(xtest_tfidf, y_test)))
Test set score: 0.54
- 使用这些调整后的参数重新构建模型。
print("Best parameters: {}".format(grid_search.best_params_))
print("Best cross-validation score: {:.2f}".format(grid_search.best_score_))
Best parameters: {'C': 20}
Best cross-validation score: 0.55
print("Best estimator:\n{}".format(grid_search.best_estimator_))
Best estimator:
LogisticRegression(C=20, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
verbose=0, warm_start=False)
model=linear_model.LogisticRegression(C=20, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
verbose=0, warm_start=False)
nb=model.fit(xtrain_tfidf, y_train)
nb
LogisticRegression(C=20, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
verbose=0, warm_start=False)
第 7-10 步。生效
一旦模型被最佳参数拟合,它就被交叉验证以检查模型在文本数据上的准确性。验证参数是相同的。
以下是模型的混淆矩阵报告。
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
print(classification_report(y_test, predictions,target_names=["Legit", "Fake"]))
precision recall f1-score support
Legit 0.53 0.54 0.53 147
Fake 0.53 0.52 0.53 147
accuracy 0.53 294
macro avg 0.53 0.53 0.53 294
weighted avg 0.53 0.53 0.53 294
AUC for the tuned model.
from sklearn.metrics import roc_auc_score
nb_auc = roc_auc_score(y_test, nb.predict_proba(xtest_tfidf)[:, 1])
print("AUC for tuned SVC model: {:.3f}".format(nb_auc))
AUC for tuned SVC model: 0.525
摘要
这个食谱为假新闻分类建立了一个基线模型,并使用了一个来自多个新闻频道的免费源数据集。首先,您学习了如何使用 TF-IDF 创建数据集、预处理数据以及执行特征工程。后来你看到了不同的机器学习方法来训练模型。最后,您观察到,与其他分类器相比,线性分类器的性能更好。
使用不同的方法来提高精确度还有很大的空间。这只是基线模型,您可以使用高级功能工程技术(如单词嵌入)来提高准确性。你也可以用深度学习的方法来调查是否有准确度的提高。
食谱 5-8。电影类型标记
多标记/标签分类源于对文本分类问题的研究,每个问题可以同时属于多个预定义的主题。例如,这可以基于电影的绘图摘要找到电影所属的流派类型。在多标签分类中,学习集由与一组标签相关联的实例组成。任务是通过分析具有已知标签集的学习实例来预测不可见的实例标签集。
多类别分类假设每个样本被分配给一个且仅一个标签:客户可以是流失客户,也可以不是,但不能两者都是。例如,多标签分类可能是文本可能同时涉及宗教、政治、金融、教育或任何这些内容。
问题
将电影分类是经典的人工智能问题之一。像 IMDb 这样的在线电影预订平台和评论网站将电影分为不同的类型。类型可以是动作片、冒险片、喜剧片、爱情片等等。
在 IMDb,每部电影都有一个与之相关的流派。但挑战在于,一部电影也可以有多种类型。例如,复仇者联盟*:残局*被标记为动作、冒险和幻想类型。
我们的目标是在给定电影描述的情况下标记电影类型。该模型必须预测一部电影可能属于的所有可能的类别(类型)。虽然你以前已经看过简单的多类分类,但是这个食谱探索了如何解决多标签学习和分类问题。
解决办法
你遇到过许多分类问题,所有这些问题要么是二元类问题,要么是多类问题。现在让我们探索一种独特的问题,称为多标签学习解决电影类型标签。
那么,什么是多标记分类或者俗称的多标记学习呢?数据集中的每个观察值(x)都有一个包含多个类别的目标变量(y)。例如,带有描述的电影名称是你的独立特征,相关的类型(动作、冒险、幻想)是因变量。
以下是解决多标签问题的一些方法。
-
一个对另一个
-
二元相关
-
分类链
-
powerset 标签
迎面流
但在此之前,你需要处理一些与文本相关的日常任务。以下是端到端解决这个问题的步骤。
-
数据预处理和清洗
-
特征生成
-
探索性数据分析
-
多标记分类器
-
验证和预测
它是如何工作的
步骤 8-1。收集数据
我们使用的是已经标记的免费源数据集。然而,只有一小部分数据被标记。数据量越大,模型的准确性和泛化能力就越强。
从 www.kaggle.com/cryptexcode/mpst-movie-plot-synopses-with-tags#mpst_full_data.csv
下载数据集。
步骤 8-2。安装库
导入文本挖掘任务所需的所有基本库。
# Data Manipulation
import numpy as np
import pandas as pd
# Visualization
import matplotlib.pyplot as plt
import seaborn as sns
# Plot the Figures Inline
%matplotlib inline
#Natural language processing
import nltk
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
from textblob import Word
from sklearn.feature_extraction.text import TfidfVectorizer
#Machine Learning
from sklearn.model_selection import train_test_split
步骤 8-3。分析数据
导入之前下载的数据集。
#Importing dataset
df = pd.read_csv('movies_genres1.csv',encoding = 'ISO-8859-1')
df.shape
(9502, 30)
#Top 5 rows to see the data
df.head()
df.columns
Index(['title', 'plot', 'Action', 'Adult', 'Adventure', 'Animation',
'Biography', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Family',
'Fantasy', 'Game-Show', 'History', 'Horror', 'Music', 'Musical',
'Mystery', 'News', 'Reality-TV', 'Romance', 'Sci-Fi', 'Short', 'Sport',
'Talk-Show', 'Thriller', 'War', 'Western', 'count', 'length', 'desc'],
dtype='object')
步骤 8-4。做探索性数据分析
连接电影标题和情节。
df["desc"] = df["title"].map(str) + df["plot"]
df = df[df['desc'].notnull()]
以下是按流派分类的标签。
print (df.apply(pd.to_numeric, errors='coerce').sum())
title 0.0
plot 0.0
Action 659.0
Adult 7.0
Adventure 547.0
Animation 689.0
Biography 71.0
Comedy 2217.0
Crime 914.0
Documentary 1377.0
Drama 3150.0
Family 1075.0
Fantasy 377.0
Game-Show 103.0
History 166.0
Horror 146.0
Music 194.0
Musical 29.0
Mystery 633.0
News 1069.0
Reality-TV 1008.0
Romance 1338.0
Sci-Fi 477.0
Short 61.0
Sport 286.0
Talk-Show 733.0
Thriller 488.0
War 67.0
Western 201.0
count 18082.0
length 3623621.0
desc 0.0
Total_tags 18082.0
dtype: float64
大多数电影被归入戏剧类,其次是喜剧类。
df.groupby(['Total_tags']).size()
Total_tags
1 4540
2 2969
3 1038
4 510
5 279
6 121
7 27
8 15
10 2
dtype: int64
4540 部电影只被标记为一种类型,大约 1000 部电影属于三种类型。
步骤 8-5。预处理数据
数据预处理包括以下四个步骤。
-
将转换为小写。
df['desc'] = df['desc'].apply(lambda x:" ".join(x.lower() for x in x.split()))
-
去掉标点符号。
df['desc'] = df['desc'].str.replace('\d+', '') df['desc'] = df['desc'].str.replace('[^\w\s]','')
-
移除停止字。
The stopwords are imported from the nltk library.
stop = stopwords.words('english') df['desc'] = df['desc'].apply(lambda x: " ".join(x for x in x.split() if x not in stop))
-
词汇化。
from nltk.stem import WordNetLemmatizer df['desc'] = df['desc'].apply(lambda x: " ".join([Word(word).lemmatize() for word in x.split()])) df['desc'].head()
0 dayslater dayslater interactive comedy series ...
1 lawstinwoods happening gang discus shock reali...
2 mykpop kpop growing check mnet america newest ...
3 allo allo general conference general gather co...
4 til death mixed double steph introduces eddie ...
Name: desc, dtype: object
在完成预处理步骤后,文本是干净的,可以进入下一步了。
步骤 8-6。使用训练测试分割
#create input dataset without including target variable( class column)
X = df['desc']
X.shape
(9501,)
#Create the target data with only class column
y = df.iloc[:,2:29]
y.shape
(9501, 27)
# splitting into training and testing data
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.3, random_state=100, stratify=y)
#validate the shape of train and test dataset
print (X_train.shape)
print (y_train.shape)
print (X_test.shape)
print (y_test.shape)
(6650,)
(6650, 27)
(2851,)
(2851, 27)
步骤 8-7。做特征工程
tfidf 矢量器库(来自sklearn.feature_extraction.text
)从文本中生成特征。
#Generating features using tfidf
tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000)
tfidf_vect.fit(df['desc'])
xtrain_tfidf = tfidf_vect.transform(X_train)
xtest_tfidf = tfidf_vect.transform(X_test)
第八步。做模型建立和预测
有两种方法可以解决这个问题。让我们看看所有的方法,并使用不同的库来实现它们。
-
问题转化
-
算法适应
先说问题转化方法。
问题转化
问题转换方法背后的基本思想是使用数据操作技术将多标签转换成单个标签。这是使用 skmultilearn 包完成的,它支持不同类型的转换。
有三种可能的转换类型。让我们讨论这三个并使用下面的库实现它们:二进制相关性,
二元相关性
二元相关性将每个标签转换成不同的单类分类问题。如果有五个标签,这种方法会为一个标签创建五个新数据集。这些创建的数据集分别用于单标签分类器。
让我们实现这个方法,看看结果是什么样的。
# Import the packages
from skmultilearn.problem_transform import BinaryRelevance
from sklearn.naive_bayes import GaussianNB
# initialize binary relevance multi-label classifier with a gaussian naive Bayes base classifier
classifier = BinaryRelevance(GaussianNB())
# train the algorithms
classifier.fit(xtrain_tfidf, y_train)
# predict
predictions = classifier.predict(xtest_tfidf)
#output
print(predictions)
(16, 0) 1
(38, 0) 1
(42, 0) 1
(49, 0) 1
(52, 0) 1
(56, 0) 1
(62, 0) 1
(72, 0) 1
(141, 0) 1
(171, 0) 1
(173, 0) 1
(198, 0) 1
(243, 0) 1
(258, 0) 1
(292, 0) 1
(343, 0) 1
(371, 0) 1
(398, 0) 1
(429, 0) 1
#Evaluation
from sklearn.metrics import accuracy_score
accuracy_score(y_test,predictions)
0.21220624342336022
metrics.hamming_loss(y_test, predictions)
0.07472361874326097
请注意,我们的准确率非常低,只有 21%。然而,它会随着更多的训练数据而增加。你可以多尝试几个算法,看能不能得出更好的数字。
现在让我们尝试二进制相关的 SVM,看看它对多标记分类的性能。
#import the library
from skmultilearn.problem_transform import BinaryRelevance
from sklearn.svm import SVC
# define the classifier
classifier = BinaryRelevance(
classifier=SVC(),
require_dense=[False, True]
)
# train
classifier.fit(xtrain_tfidf, y_train)
# predict
predictions = classifier.predict(xtest_tfidf)
# evaluation
accuracy_score(y_test,predictions)
0.09
即使是 SVM 也不能产生好的结果。
让我们转到下一种称为分类器链的多标记算法,看看它是否能提高精确度。
分类器链
分类器链是一个分类器链,因此得名。第一个分类器位于 x(独立特征)和其中一个标签之间。对于下一个分类器,甚至来自前一个分类器的标签也被用作输入。让我们通过下面的例子来理解这一点。
这里,x 是独立特征(文本),y 是标签/目标。
让我们使用多重学习库来实现。
# using classifier chains
from skmultilearn.problem_transform import ClassifierChain
from sklearn.naive_bayes import GaussianNB
# initialize classifier chains multi-label classifier
# with a gaussian naive Bayes base classifier
classifier = ClassifierChain(GaussianNB())
# train
classifier.fit(xtrain_tfidf, y_train)
# predict
predictions = classifier.predict(xtest_tfidf)
accuracy_score(y_test,predictions)
0.21255699754472115
即使这种方法也不能给出有希望的结果。让我们继续下一个类型,看看算法是如何执行的。
Powerset 标签
此方法将多标签分类器转换为多类分类器。在所有唯一标签组合上创建一个标签。
让我们用下面的例子来看看。
这就是实现。
# using Label Powerset
from skmultilearn.problem_transform import LabelPowerset
from sklearn.naive_bayes import GaussianNB
# initialize Label Powerset multi-label classifier
# with a gaussian naive bayes base classifier
classifier = LabelPowerset(GaussianNB())
# train
classifier.fit(xtrain_tfidf, y_train)
# predict
predictions = classifier.predict(xtest_tfidf)
accuracy_score(y_test,predictions)
0.32620133286566116
与以前的方法相比,精确度略有提高。让我们试试超参数调优,看看你能不能让它变得更好。
众所周知,超参数调整是提高精度和为算法选择最佳参数的一个重要方面。您可以利用 GridSearchCV 进行超参数调优,如下所示。
#Import libraries
from skmultilearn.problem_transform import LabelPowerset
from sklearn.model_selection import GridSearchCV
from sklearn.naive_bayes import MultinomialNB
from sklearn.ensemble import RandomForestClassifier
#define the parameters
parameters = [
{
'classifier': [MultinomialNB()],
'classifier__alpha': [0.7, 1.0],
},
{
'classifier': [RandomForestClassifier()],
'classifier__criterion': ['gini', 'entropy'],
'classifier__n_estimators': [10, 20, 50],
},
]
# tuning
clf = GridSearchCV(LabelPowerset(), parameters, scoring='accuracy')
clf.fit(xtrain_tfidf, y_train)
#print the best accuracy
print (clf.best_params_, clf.best_score_)
{'classifier': RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=50, n_jobs=None,
oob_score=False, random_state=None, verbose=0,
warm_start=False), 'classifier__criterion': 'gini', 'classifier__n_estimators': 50}
0.4548872180451128
这比以前的方法有了很大的改进。通过调优,可以达到 45%的准确率。
适应算法
适配的算法适配机器学习算法以直接执行多标签学习。例如,多标签版本的 kNN 由 MLkNN 表示。
来做实现吧。
#convert the data to matrix
y_train = y_train.as_matrix()
#import the package
from skmultilearn.adapt import MLkNN
classifier = MLkNN(k=20)
# train
classifier.fit(xtrain_tfidf, y_train)
# predict
predictions = classifier.predict(xtest_tfidf)
accuracy_score(y_test,predictions)
0.364784286215363
# import
from skmultilearn.adapt import BRkNNaClassifier
classifier = BRkNNaClassifier(k=3)
# train
classifier.fit(xtrain_tfidf, y_train)
# predict
predictions = classifier.predict(xtest_tfidf)
print(predictions)
(0, 7) 1
(1, 5) 1
(1, 8) 1
(2, 8) 1
(2, 19) 1
(3, 17) 1
(3, 23) 1
(4, 23) 1
(5, 5) 1
(5, 9) 1
(6, 5) 1
(6, 20) 1
(9, 19) 1
(10, 7) 1
(11, 17) 1
(11, 23) 1
(12, 8) 1
(13, 2) 1
(13, 7) 1
(14, 8) 1
(14, 19) 1
(15, 5) 1
(15, 9) 1
(16, 5) 1
(18, 6) 1
accuracy_score(y_test,predictions)
0.45001753770606806
类似地,您可以利用支持向量机,如下所示。
from skmultilearn.adapt import MLTSVM
classifier = MLTSVM(c_k = 2**-1)
# train
classifier.fit(xtrain_tfidf, y_train)
# predict
predictions = classifier.predict(xtest_tfidf)
accuracy_score(y_test,predictions)
你已经实现了一个几端 - 到 - 端的项目。不刺激吗?
下一章看在用 NLP 和深度学习解决问题。****