大家好!在这篇文章中,将详细探讨如何使用自然语言处理(NLP)的基本理念来解决一个实际的商业问题——消费者投诉分类。
假设已经熟悉自然语言处理的基本概念,比如特征提取、处理原始数据以及在文本数据上训练模型。如果对NLP的基础知识不太熟悉,可以参考写的一系列从零开始的详细文章。
金融保护局是一个组织,它发送成千上万的消费者对金融服务(如抵押贷款、学生贷款等)和产品(如信用卡、借记卡)的投诉,以获得一些回应。
投诉需要被分类并交付给相关部门,这提高了投诉的响应时间,因为减少了人工干预来分类投诉类别。
因此,需要构建一个模型,该模型可以阅读投诉内容,并告诉相关的部门,例如,与抵押贷款相关的投诉必须转发给抵押贷款部门,信用卡投诉则转发给银行产品部门。
本项目的目标是将投诉归类到它们相关的产品或类别部门。由于投诉可能涉及多个类别,因此它将是一个多类分类问题,可以通过使用NLP和机器学习算法来解决。
通过使用机器学习模型,可以轻松地对投诉进行分类,从而减少人工干预来分类投诉,减少投诉的响应时间。
注意:文本分类是监督机器学习的一个例子,因为正在使用标记过的数据进行训练和测试。
将使用金融消费者保护局提供的消费者金融投诉数据集。可以通过这个链接下载数据集,或者创建一个云笔记本并立即开始工作。
import pandas as pd
import numpy as np
df = pd.read_csv("../input/consumer-complaint-database/rows.csv", low_memory=False)
df.head()
这个数据集包含许多列,但只需要关注两列[产品,消费者投诉叙述]。
df1 = df[['Product', 'Consumer complaint narrative']]
df1.columns = ['Product', 'Consumer complaint']
已经将“消费者投诉叙述”重命名为“消费者投诉”,并保存在数据框df1中。
过滤掉没有文本内容的投诉(假投诉)。
df1 = df1[df1['Consumer complaint'].isna() != True]
在特征工程中,进行一些数据操作,以便更有效地训练模型,并深入理解数据。
pd.DataFrame(df1.Product.unique()).values
在数据集中,有18种不同的投诉类别,其中一些投诉类别是相互关联的。例如,“信用卡预付费卡”和“预付费卡”、“信用卡”是如此相关。
因此,需要重命名类别,以便合并相关类别。
重命名类别。
df1.replace({'Product': {
'Credit reporting': 'Repair or Credit reporting',
'Credit card': 'Credit card or prepaid card',
'Prepaid card': 'Credit card or prepaid card',
'credit repair services,Credit reporting , or other personal consumer reports': 'Repair or Credit reporting',
'Money transfer': 'Money transfer, virtual currency, or money service',
'Payday loan': 'title loan,Payday ,Personal loan',
'Virtual currency': 'Money transfer, virtual currency, or money service'
}}, inplace=True)
重命名后,只有13个类别/产品需要分类。
注意:正在处理的数据集非常大,包含120万行数据,因此在大数据上训练将非常耗时,因此将只取10000行样本进行训练,以节省时间。
df2 = df1.sample(10000, random_state=1).copy()
df2是将进一步工作的数据处理后的数据集,包含10000行和2列。
到目前为止,已经将数据集转换为文本,需要将投诉文本和类别转换为一些数字。
将类别(产品)转换为数字。
df2['category_id'] = df2['Product'].factorize()[0]
已经添加了一个新的列“category_id”,它将包含类别编号。
如所见,已经将类别标签转换为category_id,还需要数据来将category_id转换回类别标签,以便在预测时使用。为此,将创建一个字典。
category_id = df2[['Product', 'category_id']].drop_duplicates()
id_2_category = dict(category_id[['category_id', 'Product']].values)
将使用id_2_category字典将class_id转换为class_label。
在EDA中,探索数据,绘制图表以理解数据之间的关系和各种洞察。
绘制产品/类别与投诉数量的对比图。
import matplotlib.pyplot as plt
import seaborn as sns
fig = plt.figure(figsize=(8,6))
colors = ['grey','grey','grey','grey','grey','grey','grey','grey','grey',
'grey','darkblue','darkblue','darkblue']
df2.groupby('Product')['Consumer complaint'].count().sort_values().plot.barh(ylim=0, color=colors, title='NUMBER OF COMPLAINTS IN EACH PRODUCT CATEGORY')
plt.xlabel('Number of ocurrences', fontsize = 10)
可能会看到“信用报告、修理和其他”拥有最多的支持记录,而“其他金融服务”的记录非常少。这表明一些可能的数据不平衡,这可以通过从每个类别/产品中抽取相等的记录来解决。
现在需要将投诉文本转换为一些向量,因为机器无法理解文本数据。这个过程被称为特征提取。
将使用TF-IDF向量化器(逆文档频率)进行特征提取。如果对特征工程不熟悉,请参考文章。
TF-IDF评估一个词在其文档集合或一组文档中的重要性。
注意:在去除标点符号、将单词转换为小写之后,可以进行特征提取步骤。TF-IDF向量化器可以自行处理停用词。
词频(Term Frequency):这告诉一个给定的词在文档中出现的次数。
逆文档频率(Inverse Document Frequency):它是词频的相反。如果一个给定的词在文档中出现很多次,它将有一个低IDF分数。
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(sublinear_tf=True, min_df=5, ngram_range=(1, 2), stop_words='english')
features = tfidf.fit_transform(df2['Consumer complaint']).toarray()
labels = df2.category_id
min_df:它从词汇表中移除在“min_df”文件中出现次数少于“min_df”的单词。
sublinear_tf = True:在对数尺度上缩放词频。
stop_words:移除指定语言的停用词。
ngram_range = (1, 2):将考虑单字和双字。
max_df:它从词汇表中移除在“max_df”文件中出现次数超过“max_df”的单词。
分割数据集。将数据集分割为训练和测试分区。75%的记录将用于训练,其余将用于测试。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.25, random_state=0)
将使用LinearSVC,因为它表现良好,也可以尝试其他模型并检查它们的性能。
from sklearn.svm import LinearSVC
model = LinearSVC()
model.fit(X_train, y_train)
为了查看模型表现如何,将使用sklearn的metrics类。将使用分类报告和混淆矩阵。
from sklearn import metrics
from sklearn.metrics import classification_report
y_pred = model.predict(X_test)
print(metrics.classification_report(y_test, y_pred, target_names=df2['Product'].unique()))
正如所观察到的,拥有更多支持(数据行)的类别具有更好的f1分数。这是因为这些类别在更多数据上进行了训练。为了解决这个问题,应该平衡数据,正如已经讨论过的。
像“抵押贷款”、“学生贷款”、“信用报告、修理或其他”这样的类别可以更精确地分类。
绘制混淆矩阵。
import seaborn as sns
sns.set()
from sklearn.metrics import confusion_matrix
conf_mat = confusion_matrix(y_test, y_pred)
fig, ax = plt.subplots(figsize=(8,8))
sns.heatmap(conf_mat, annot=True, cmap="Blues", fmt='d', xticklabels=category_id.Product.values, yticklabels=category_id.Product.values)
plt.ylabel('Actual')
plt.xlabel('Predicted')
plt.title("CONFUSION MATRIX - LinearSVC", size=16);
可以清楚地观察到,信用卡报告和数据收集类别比其他类别具有更高的精确度。
是时候尝试模型进行一些预测了。将传递一个投诉文本,模型将根据其投诉类别进行分类。
complain = """在2019年重新注册了印度大学。几天前,被Navient骚扰。已经传真了文件,提供了他们想要的一切。但仍然接到电话要求付款。此外,Navient现在向信用局报告说付款晚了。在这一点上,Navient需要采取行动,以避免采取进一步的措施"""
complaint_id = (model.predict(tfidf.transform([complain])))
print("complain", id_2_category[complaint_id[0]])
输出:complain 学生贷款
可以清楚地看到,模型已经准确预测。
在这篇文章中,使用NLP解决了一个商业问题,使用了数据清洗、EDA、特征提取、特征工程等概念,并成功构建了模型,用于分类投诉类型。