
数据科学用例几乎可以与任何能够累积大量数据的行业相关。 门店和电商网站是营销活动吸引而来的用户真正体验发生的地方,也是某个品牌或公司的宝贵购买数据被收集的地方。在这里,人们会做出最终决定:他们是否真的想买某件商品,是否对原本没计划购买的其他东西产生兴趣,愿意支付多少,是否会再次光顾这家店,以及会为自己的消费体验留下怎样的评价。
确实,客户评价是分析和理解整个销售流程中哪些地方可以改进或加强的坚实数据来源。以这种方式分析数据,有助于降低成本、提升运营效率、改善客户体验、发现新机会、推动业务增长,并最终提高收入。下面我们来仔细看看,如何利用数据科学算法对这些宝贵信息进行分析与建模,从而挖掘隐藏洞察,并把握每一位客户传递的整体诉求。
销售中的数据科学用例:分析客户情感
客户情感分析是指在客户使用某家公司产品或服务时,自动识别其情绪的过程。通常,它基于来自在线调研、社交媒体、工单、反馈表、产品评价、论坛、电话、电子邮件和聊天机器人等渠道的非结构化文本数据。在机器学习中,客户情感分析通过自然语言处理(NLP)来完成,后者运用统计和语言学方法,直接从文本数据中抽取正面、负面和中性情绪。本质上,它输出两个参数:
- 极性(Polarity):指示情绪是正面还是负面。
- 强度(Magnitude):指示该情绪的强弱程度。
客户情感分析是现代企业的关键工具,因为它有助于获得可执行的洞察,发现并修复让客户不满的关键反复性问题,强化引发客户正面情绪的产品或服务特性,并总体上做出更高效的数据驱动决策。在更细粒度的层面,客户情感分析可以帮助我们:
- 改进客户服务,从而提升客户体验,
- 提高客户忠诚度,
- 降低流失率,
- 及时升级产品与服务,
- 优化营销活动,
- 预判新趋势与新市场,
- 维护公司的良好声誉,
- 提升利润。
与任何文本分析任务一样,在进行客户情感分析时也可能遇到一些陷阱。例如,NLP 算法可能无法识别某些评价中的讽刺,导致分类错误;也可能偶尔无法解读非常特定的缩写或少见的俚语。
准备数据集
我们用一个 IMDB 电影评论的数据集来实际演示客户情感分析的工作方式:
import pandas as pd
movies = pd.read_csv('movies.csv', index_col=0).reset_index(drop=True)
print(f'Number of reviews: {movies.shape[0]:,}\n')
print(movies.head())
Number of reviews: 7,501
review label
0 This short spoof can be found on Elite's Mille... 0
1 A singularly unfunny musical comedy that artif... 0
2 An excellent series, masterfully acted and dir... 1
3 The master of movie spectacle Cecil B. De Mill... 1
4 I was gifted with this movie as it had such a ... 0
我们有两列:一列是每条评论的文本,另一列是对整体情感的判断:正面(1)或负面(0)。
让我们计算一下正面和负面评论所占的百分比:
round(movies['label'].value_counts()*100/len(movies['label'])).convert_dtypes()
0 50
1 50
Name: label, dtype: Int64
因此,正面与负面评论的比例几乎相等。
应用 BOW 方法
下一步,我们需要把文本数据转换为数值形式,因为机器学习模型只能处理数值特征。具体而言,我们将创建一些特征,用于统计每个词在相应评论中出现的次数。最基础、最直接的方法称为词袋(bag-of-words,BOW):它会构建文档中出现过的所有词的词汇表,并统计每条评论中每个词的出现频率。最终,我们会得到新的特征,每个词对应一个特征,取值为其出现频次。
让我们把 BOW 方法应用到数据集上:
from sklearn.feature_extraction.text import CountVectorizer
# Creating new features
vect = CountVectorizer(max_features=200)
vect.fit(movies.review)
X_review = vect.transform(movies.review)
X_df = pd.DataFrame(X_review.toarray(), columns=vect.get_feature_names())
# Combining the new features with the label
movies_bow = pd.concat([movies['label'], X_df], axis=1)
print(movies_bow.head())
label 10 about acting action actors actually after again all ... \
0 0 0 0 0 0 0 0 0 0 0 ...
1 0 1 0 1 0 1 0 0 0 3 ...
2 1 0 0 0 0 0 0 1 0 0 ...
3 1 0 0 0 1 0 0 0 0 0 ...
4 0 1 0 0 1 0 0 0 0 3 ...
will with without work world would years you young your
0 0 1 0 0 0 1 0 0 0 0
1 2 7 1 0 0 2 0 3 0 2
2 0 2 0 0 0 0 0 0 1 0
3 0 0 0 0 0 0 0 1 1 0
4 0 2 0 1 0 0 0 0 0 0
[5 rows x 201 columns]
上面我们使用了可选参数 max_features,仅考虑最常用的 200 个词,以避免模型潜在的过拟合。
使用监督式机器学习模型预测情感
现在我们将使用监督式机器学习模型来预测情感。由于我们希望根据已标注的评论来判断新评论的情感属于正面还是负面,因此这仍然是一个分类问题。我们继续使用逻辑回归算法,并衡量模型的准确率:
Accuracy score: 0.754
Confusion matrix:
[[37.62772101 13.23856064]
[11.32829853 37.80541981]]
可以看到,模型将所有正面评论中的 11% 误判为负面,而将负面评论中的 13% 误判为正面。为进一步提升模型准确率,我们可以考虑去除停用词(即“about”“will”“you”等出现频繁、信息量较低的词),并增大词汇表规模。
在应用 BOW 方法时,我们的数据框可能会产生数百甚至数千个新特征。这可能导致模型过于复杂:过拟合,且包含过多不必要的特征和参数。解决方法之一是使用正则化,用以约束模型的函数形式。这里需要调优的参数是 C,表示正则化强度。我们测试该参数的两个取值:100 和 0.1,看看哪一个能在测试数据上带来更好的表现:
lr_1 = LogisticRegression(C=100)
lr_1.fit(X_train, y_train)
predictions_1 = lr_1.predict(X_test)
lr_2 = LogisticRegression(C=0.1)
lr_2.fit(X_train, y_train)
predictions_2 = lr_2.predict(X_test)
print(f'Accuracy score, lr_1 model: {round(accuracy_score(y_test, predictions_1), 3)}\n'
f'Accuracy score, lr_2 model: {round(accuracy_score(y_test, predictions_2), 3)}\n\n'
f'Confusion matrix for lr_1 model, %:\n{confusion_matrix(y_test, predictions_1)/len(y_test)*100}\n\n'
f'Confusion matrix for lr_2 model, %:\n{confusion_matrix(y_test, predictions_2)/len(y_test)*100}')
Accuracy score, lr_1 model: 0.753
Accuracy score, lr_2 model: 0.756
Confusion matrix for lr_1 model, %:
[[37.53887161 13.32741004]
[11.32829853 37.80541981]]
Confusion matrix for lr_2 model, %:
[[37.67214571 13.19413594]
[11.19502443 37.93869391]]
在所选 C 参数取值下,模型准确率差异并不显著。通过进一步尝试更多取值,我们或许能找到能更明显提升模型表现的参数。不过在这里我们只有 200 个新特征,模型并不复杂,因此正则化步骤在本例中并非刚需。
除了使用 predict 函数预测标签 0 或 1,我们还可以使用 predict_proba 来预测情感的概率。需要注意的是,我们不能将准确率或混淆矩阵直接应用于概率预测结果,因为这些指标只适用于类别标签。因此,我们需要将概率进一步编码为类别。默认情况下,概率大于或等于 0.5 被映射为类别 1,否则为类别 0。
lr = LogisticRegression()
lr.fit(X_train, y_train)
# Predicting the probability of the 0 class
predictions_prob_0 = lr.predict_proba(X_test)[:, 0]
# Predicting the probability of the 1 class
predictions_prob_1 = lr.predict_proba(X_test)[:, 1]
print(f'First 10 predicted probabilities of class 0: {predictions_prob_0[:10].round(3)}\n'
f'First 10 predicted probabilities of class 1: {predictions_prob_1[:10].round(3)}')
First 10 predicted probabilities of class 0: [0.246 0.143 0.123 0.708 0.001 0.828 0.204 0.531 0.121 0.515]
First 10 predicted probabilities of class 1: [0.754 0.857 0.877 0.292 0.999 0.172 0.796 0.469 0.879 0.485]
结论
为了开展更细致的情感分析,我们还可以对数据集应用许多其他有用的方法:
- 使用 n-gram(词组组合)而非单个词,以保留上下文,
- 去除停用词,
- 基于词频上限或下限限制词汇表大小,
- 创建数值型额外特征,如每条评论的长度或标点符号数量(后者有时与情感强度相关),
- 排除数字、某些字符、特定长度的词,或考虑更复杂的词形模式,
- 应用词干提取和词形还原,即将单词还原为词根,
- 采用比 BOW 更复杂的构建词汇表的方法,例如 TfIdf(词频-逆文档频率),它会结合某个词在单条评论与其在其余评论中的出现频率来衡量重要性。
- 使用专门为情感分析设计的库,例如 TextBlob、SentiWordNet、VADER(Valence Aware Dictionary and Sentiment Reasoner)。
如果您有兴趣探索这些及其他有助于开展深入情感分析的技术,欢迎查看课程 Sentiment Analysis in Python。