39

文本分析:不均衡分布数据的多分类预测1529089227116610

 5 years ago
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.

文本分析很有趣,之前已经分享了好多篇文章,如:

对于中文,nltk能做哪些事情  

使用sklearn做自然语言处理-1

使用sklearn做自然语言处理-2

机器学习|八大步骤解决90%的NLP问题    

后面还会继续分享的。互联网上的绝大多数文本分类文章和教程都是二元文本分类,如垃圾邮件过滤(垃圾邮件与火腿),情感分析(正面与负面)。 在大多数情况下,现实世界的分类问题比这更复杂的多。因此,今天我们想做一个多分类,使用的数据集来自美国政府数据公开网, 金融产品消费者吐槽数据集

本文使用Scikit-learn库做机器学习。

一、问题解读

这是有监督分类问题,我们的目标是通过使用有监督机器学习模型来更好的学习消费者吐槽与产品信息之间的关系。

当有新的吐槽信息时,我们可以基于之前训练的模型给出预测结果(消费者对什么产品吐槽),然后将消费者分发给相应产品部门售后服务部门,快速高效的对消费者做出售后服务保障,提高客户满意度。

二、 数据探索

这个数据集文件(Consumer_Complaints.csv)有565M,真的很大。在训练机器学习模型前,我们先看看数据有哪些字段,他们是什么形式。

import pandas as pd

df = pd.read_csv('Consumer_Complaints.csv')
#前5行数据
df.head(5)

eIJZzy2.jpg!web

在本案例我们只需要上面的两列 ProductConsumer 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)

JVFZjuE.png!web


三、不均衡数据问题

我们看看用户对不同产品吐槽的分布情况发现产品类别是不均衡分布的。消费者对于 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()

NnUfMj2.png!web

常规的机器学习算法能处理类别均匀分布的数据,但是当我们将其应用到不均衡分布的数据,常规机器学习的结果会产生偏差。

例如,如果让机器同时学习正面评论和负面评论,正面评论有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()

qiauuqV.png!web


四、文本特征提取

我们继续使用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() 

FvUFjuA.png!web

%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())
png

rmeEFbY.png!web

六、模型选择

我们准备使用逻辑回归、贝叶斯、支持向量机、随机森林这四种模型分别训练,并打印四种模型的表现

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()

AFZ3iq2.png!web

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

准确率有点低啊,不均衡的数据不是理想的数据,模型训练效果不好。今天就写到这里,大家有什么解决办法也可留言。

往期文章

100G Python学习资料:从入门到精通! 免费下载

上百G文本数据集等你来认领|免费领取

在校大学生如何用知识月入3000

为什么你要为2019,而不是2018做计划?     

史蛟:是什么同时导致了成功和热情?

2017年度15个最好的数据科学领域Python库

推荐系统与协同过滤、奇异值分解

机器学习之使用逻辑回归识别图片中的数字

应用PCA降维加速模型训练

对于中文,nltk能做哪些事情  

使用sklearn做自然语言处理-1

使用sklearn做自然语言处理-2

机器学习|八大步骤解决90%的NLP问题    

Python圈中的符号计算库-Sympy

Python中处理日期时间库的使用方法  

如何从文本中提取特征信息?

视频讲解】Scrapy递归抓取简书用户信息

美团商家信息采集神器

用chardect库解决网页乱码问题

gevent:异步理论与实战

selenium驱动器配置详解

使用pdfrw库对pdf文件进行读写操作

昨日财报

赞赏、点赞、转发、AD支持都是对大邓的认可和支持,希望大家在阅读后顺便帮大邓转发一下。谢谢大家支持!

ee26Fvq.png!web

MvMB3eB.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK