文本分析:不均衡分布数据的多分类预测1529089227116610
source link: https://mp.weixin.qq.com/s/j7MgFwKjLc5HmBeVud1dOg?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
文本分析很有趣,之前已经分享了好多篇文章,如:
后面还会继续分享的。互联网上的绝大多数文本分类文章和教程都是二元文本分类,如垃圾邮件过滤(垃圾邮件与火腿),情感分析(正面与负面)。 在大多数情况下,现实世界的分类问题比这更复杂的多。因此,今天我们想做一个多分类,使用的数据集来自美国政府数据公开网, 金融产品消费者吐槽数据集
本文使用Scikit-learn库做机器学习。
一、问题解读
这是有监督分类问题,我们的目标是通过使用有监督机器学习模型来更好的学习消费者吐槽与产品信息之间的关系。
当有新的吐槽信息时,我们可以基于之前训练的模型给出预测结果(消费者对什么产品吐槽),然后将消费者分发给相应产品部门售后服务部门,快速高效的对消费者做出售后服务保障,提高客户满意度。
二、 数据探索
这个数据集文件(Consumer_Complaints.csv)有565M,真的很大。在训练机器学习模型前,我们先看看数据有哪些字段,他们是什么形式。
import pandas as pd df = pd.read_csv('Consumer_Complaints.csv') #前5行数据 df.head(5)
在本案例我们只需要上面的两列 Product
和 Consumer complaint narrative
(产品类别、用户抱怨描述)。
机器学习输入端 输入的数据
为 Consumer complaint narrative
机器学习输出端 输出的数据
为 Product
我们将做两个主要工作:
-
剔除掉
Consumer complaint narrative
中的空值(NaN) -
将
Product
产品类别转化为数字类别
#只使用两列数据(注意:这里的方括号有两层) df = df[['Product', 'Consumer complaint narrative']] #剔除掉Consumer complaint narrative列中的空数据(注意方括号只有一层) df = df[pd.notnull(df['Consumer complaint narrative'])] #将列名调整,方便后续调用 df.columns = ['Product', 'Consumer_complaint_narrative']
factorize()
pandas有factorize()函数,可以将标称型数据转化为数字。
factorize()的返回结果是一个包含两个数组的元组。第一个数组是转化后得到的分类数字,第二个数组为原始类别
categories = ['a', 'b', 'c', 'a', 'a', 'd', 'f'] pd.factorize(categories)
(array([0, 1, 2, 0, 0, 3, 4]), array(['a', 'b', 'c', 'd', 'f'], dtype=object))
#将Product产品类别转化为类别数字,方便机器理解 df['category_id'] = pd.factorize(df['Product'])[0] #将类别与数字信息去重,排序 category_id_df = df[['Product', 'category_id']].drop_duplicates().sort_values('category_id') #类别转数字 category_to_id = dict(category_id_df) #数字转类别 id_to_category = dict(category_id_df[['category_id', 'Product']])
df.head(5)
三、不均衡数据问题
我们看看用户对不同产品吐槽的分布情况发现产品类别是不均衡分布的。消费者对于 Debt Collection、Credit report、Mortgage
槽点较多。
df.groupby('Product')
<pandas.core.groupby.dataframegroupby object="" at="" 0x1a3bd61278="" style="font-size: inherit;color: inherit;line-height: inherit;"></pandas.core.groupby.dataframegroupby>
df.groupby('Product').Consumer_complaint_narrative
<pandas.core.groupby.seriesgroupby object="" at="" 0x1a3bd617b8="" style="font-size: inherit;color: inherit;line-height: inherit;"></pandas.core.groupby.seriesgroupby>
df.groupby('Product').Consumer_complaint_narrative.count()
运行
Product Bank account or service 14887 Checking or savings account 7278 Consumer Loan 9474 Credit card 18842 Credit card or prepaid card 12058 Credit reporting 31593 Credit reporting, credit repair services, or other personal consumer reports 54480 Debt collection 66594 Money transfer, virtual currency, or money service 3494 Money transfers 1497 Mortgage 45133 Other financial service 293 Payday loan 1748 Payday loan, title loan, or personal loan 2445 Prepaid card 1450 Student loan 17380 Vehicle loan or lease 3153 Virtual currency 16 Name: Consumer_complaint_narrative, dtype: int64
%matplotlib inline import matplotlib.pyplot as plt fig = plt.figure(figsize=(8, 6)) df.groupby('Product').Consumer_complaint_narrative.count().plot.barh(ylim=0) plt.show()
常规的机器学习算法能处理类别均匀分布的数据,但是当我们将其应用到不均衡分布的数据,常规机器学习的结果会产生偏差。
例如,如果让机器同时学习正面评论和负面评论,正面评论有800条,负面评论有200条。经过训练,模型对正面评论预测会更准,但是对负面评论准确率会大大降低。原因是学习时,机器学的好评太多,差评太少。
这种不均衡数据,会出现的问题叫做 欠抽样(undersample)和过抽样(oversample)
。
然而在我们的例子中,为了对少数产品类别也能预测准确,我们需要对出现次数较多的产品类别信息量瘦身。让每种产品类别数据量相对均衡。
Virtual currency一共只有16条,我们将该类剔除掉。Other financial service有293条,我们以此为基准。每一类产品随机抽取300条数据。
Bank_account_or_service = df[df.Product=='Bank account or service'].sample(300) Checking_or_savings_account = df[df.Product=='Checking or savings account'].sample(300) Consumer_Loan = df[df.Product=='Consumer Loan'].sample(300) Credit_card = df[df.Product=='Credit card'].sample(300) Credit_card_or_prepaid_card = df[df.Product=='Credit card or prepaid card'].sample(300) Credit_reporting = df[df.Product=='Credit reporting'].sample(300) Credit_reporting_credit_repair_services_or_other_personal_consumer_reports = df[df.Product=='Credit reporting, credit repair services, or other personal consumer reports'].sample(300) Debt_collection = df[df.Product=='Debt collection'].sample(300) Money_transfer_virtual_currency_or_money_service = df[df.Product=='Money transfer, virtual currency, or money service'].sample(300) Money_transfers = df[df.Product=='Money transfers'].sample(300) Mortgage = df[df.Product=='Mortgage'].sample(300) Other_financial_service = df[df.Product=='Other financial service'] Payday_loan = df[df.Product=='Payday loan'].sample(300) Payday_loan_title_loan_or_personal_loan = df[df.Product=='Payday loan, title loan, or personal loan'].sample(300) Prepaid_card = df[df.Product=='Prepaid card'].sample(300) Student_loan = df[df.Product=='Student loan'].sample(300) Vehicle_loan_or_lease = df[df.Product=='Vehicle loan or lease'].sample(300) df_objs = [Bank_account_or_service, Checking_or_savings_account, Consumer_Loan, Credit_card, Credit_card_or_prepaid_card, Credit_reporting,Credit_reporting_credit_repair_services_or_other_personal_consumer_reports, Debt_collection,Money_transfer_virtual_currency_or_money_service,Money_transfers,Mortgage, Other_financial_service, Payday_loan, Payday_loan_title_loan_or_personal_loan, Prepaid_card, Student_loan,Vehicle_loan_or_lease] new_df = pd.concat(df_objs) new_df.describe()
四、文本特征提取
我们继续使用TfidfVectorizer作为文本特征提取器,TfidfVectorizer有以下参数:
-
sublinear_tf:设置为True以使用对数形式的频率。作用是将不同词语的词频量级保持在较小量级差异之内。
-
max_df: 整数或者小数(0-1),表示出现的文档数目或者文档比例。词语在文档集中出现次数超过max_df的,该词语特征不保留。 有些词语重复出现,不会带来信息量,max_df作用就是剔除掉这些词
-
min_df: 表示一个词语特征至少要出现min_df(跟max_df差不多,可以为整数或者小数),该特征才保留。
-
norm:范数,为了保证尽可能多的特征保留,使用
l2
-
ngram_range: 词元范围,这里设置为(1,2)表示我们只使用一元词袋和二元词袋。
-
stop_words:设置为
`english
剔除掉停止词
from sklearn.feature_extraction.text import TfidfVectorizer tfidf = TfidfVectorizer(sublinear_tf=True, min_df=5, max_df=0.8, norm='l2', ngram_range=(1, 2), stop_words='english') X = tfidf.fit_transform(new_df.Consumer_complaint_narrative).toarray() y = new_df.category_id X.shape
运行
(5093, 15131)
一共有5093条数据,特征数15131。
五、多分类训练
经过上面将数据变为均衡数据、提取文本特征,现在我们开始训练。朴素贝叶斯算法是非常适合应用到多分类文本分析之中的。我们使用yelloebrick做可视化查看模型预测能力,如果不熟悉的话可以查看之前的文章 《yellowbrick:机器学习的可视化分析诊断库》 。我们学习下如何查看训练的数据集是否均衡分布,这里使用yellowbrick。
from sklearn.naive_bayes import MultinomialNB from yellowbrick.classifier import ClassBalance clf = MultinomialNB() visualizer = ClassBalance(clf) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=True, random_state=100) visualizer.fit(X_train, y_train) visualizer.score(X_test, y_test) g = visualizer.poof()
%matplotlib inline import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.naive_bayes import MultinomialNB from yellowbrick.classifier import ClassificationReport def model_selection(X, y, estimator): X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=True, random_state=100) visualizer = ClassificationReport(estimator) visualizer.fit(X_train, y_train) visualizer.score(X_test, y_test) visualizer.poof() #看看MultinomialNB分类效果 model_selection(X, y, 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 import seaborn as sns models = [ RandomForestClassifier(), LinearSVC(), MultinomialNB(), LogisticRegression(random_state=0)] CV = 5 entries = [] for model in models: #模型的名字 model_name = model.__class__.__name__ accuracies = cross_val_score(model, X, y, scoring='accuracy', cv=CV) for fold_idx, accuracy in enumerate(accuracies): entries.append((model_name, fold_idx, accuracy)) cv_df = pd.DataFrame(entries, columns=['model_name', 'fold_idx', 'accuracy']) sns.boxplot(x='model_name', y='accuracy', data=cv_df) sns.stripplot(x='model_name', y='accuracy', data=cv_df, size=8, jitter=True, edgecolor="gray", linewidth=2) plt.show()
cv_df.groupby('model_name').accuracy.mean()
运行
model_name LinearSVC 0.592968 LogisticRegression 0.599053 MultinomialNB 0.586291 RandomForestClassifier 0.422151 Name: accuracy, dtype: float64
准确率有点低啊,不均衡的数据不是理想的数据,模型训练效果不好。今天就写到这里,大家有什么解决办法也可留言。
往期文章
昨日财报
赞赏、点赞、转发、AD支持都是对大邓的认可和支持,希望大家在阅读后顺便帮大邓转发一下。谢谢大家支持!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK