您的位置:首页 > 汽车 > 新车 > 公司网站应该包括哪些内容_中国企业网是什么级别_常用的搜索引擎有哪些?_百度关键词刷搜索量

公司网站应该包括哪些内容_中国企业网是什么级别_常用的搜索引擎有哪些?_百度关键词刷搜索量

2024/12/26 1:03:41 来源:https://blog.csdn.net/q383965374/article/details/143093208  浏览:    关键词:公司网站应该包括哪些内容_中国企业网是什么级别_常用的搜索引擎有哪些?_百度关键词刷搜索量
公司网站应该包括哪些内容_中国企业网是什么级别_常用的搜索引擎有哪些?_百度关键词刷搜索量

PaddleNLP库与层次多标签文本分类任务

目前在实际的业务中,需要对原始数据做数据标注,标注后的数据格式整理为JSON如下:
[
{
“text”: “xxxxx”,
“tag”: “初始第一次开始”
}
]
这里的tag标注是一个层次分类。开始训练的一部分数据是人工标注的监督数据,那么对于新的数据,就是无监督数据,因此需要有一个模型来解决此问题。

PaddleNLP[1]是一款简单易用且功能强大的自然语言处理和大语言模型(LLM)开发库。聚合业界优质预训练模型并提供开箱即用的开发体验,覆盖NLP多场景的模型库搭配产业实践范例可满足开发者灵活定制的需求。
PaddleNLP主要的内容如下:
大模型全流程工具链[2],包含主流中文大模型的全流程方案。
精选模型库[3],包含优质预训练模型的端到端全流程使用。
多场景示例[4],了解如何使用PaddleNLP解决NLP多种技术问题,包含基础技术、系统应用与拓展应用。
交互式教程[5],在免费算力平台AI Studio上快速学习PaddleNLP。
区别于ModelScope魔塔社区更侧重于提供一个平台,让用户可以直接使用预训练模型,同时也有自己的社区支持模型分享和交流。
PaddleNLP是百度开源的NLP工具包,基于PaddlePaddle深度学习平台。它旨在为研究人员和开发者提供NLP任务的工具和预训练模型,以便于构建和训练NLP应用。
PaddleNLP提供了预训练模型示例 Model Zoo[6],场景示例文档 examples[7];在这两个资源库中,可以挖掘到许多的NLP应用场景。
层次分类任务
介绍
什么是层次分类?那就要先谈到自然语言处理(NLP)下的文本分类任务。
文本分类简单来说就是对给定的一个句子或一段文本使用分类模型分类。文本分类应用涵盖多分类(multi class)、多标签(multi label)、层次多标签分类(Hierarchical-Multilabel-Text-Classification,hmtc)三种场景。如下所示:图片
PaddleNLP库提供了文本分类应用[8]的支持,针对多分类、多标签、层次分类等高频场景开源了产业级分类应用方案,打通数据标注-模型训练-模型调优-模型压缩-预测部署全流程,旨在解决细分场景应用的痛点和难点,快速实现文本分类产品落地。PaddleNLP的文本分类方案全覆盖:
图片
189114232-bb706af4-45a9-4e63-8857-76945a63d081.png
层次文本分类任务的中数据样本具有多个标签且标签之间存在特定的层级结构,目标是预测输入句子/文本可能来自于不同级标签类别中的某一个或几个类别。
层次多标签数据集
PaddleNLP提供通用场景下基于预训练模型微调的层次分类端到端应用方案,打通数据标注-模型训练-模型调优-模型压缩-预测部署全流程,有效缩短开发周期,降低AI开发落地门槛。官方文档:层次分类指南[9]。
预训练模型指的是ERNIE系列基座模型,文心一言大模型的基座模型也是它。
PaddleNLP库的文档中,要求训练、开发、测试数据集的格式与我要求的格式是一致的——层次分类。如下:
<文本>‘\t’<标签>‘,’<标签>‘,’<标签>
<文本>‘\t’<标签>‘,’<标签>

样例如下:
又要停产裁员6000!通用汽车罢工危机再升级股价大跌市值蒸发近300亿! 组织行为,组织行为##罢工,组织关系,组织关系##裁员
上海一改建厂房坍塌已救出19人其中5人死亡 人生,人生##死亡,灾害/意外,灾害/意外##坍/垮塌
车闻:广本召回9万余辆;领动上市,10.98万起;艾力绅混动 产品行为,产品行为##召回
86岁老翁过马路遭挖掘机碾压身亡警方:正在侦办中 灾害/意外,灾害/意外##车祸,人生,人生##死亡

分类标签文件: 包含数据集中所有标签,每个标签一行。
label.txt 文件格式:
<一级标签>
<一级标签>‘##’<二级标签>
<一级标签>‘##’<二级标签>‘##’<三级标签>

label.txt 文件样例:
人生
人生##死亡
灾害/意外
灾害/意外##坍/垮塌
灾害/意外##车祸
产品行为
产品行为##召回

待预测数据文件: 包含需要预测标签的文本数据,每条数据一行。
data.txt 文件格式:
<文本>
<文本>

data.txt 文件样例:
金属卡扣安装不到位,上海乐扣乐扣贸易有限公司将召回捣碎器1162件
卡车超载致使跨桥侧翻,没那么简单
消失的“外企光环”,5月份在华裁员900余人,香饽饽变“臭”了

完整的内容可以查看官方文档说明。从这里来看,完全符合层次多标签文本分类数据格式。只是说要将原始数据整理出来即可。也可以通过doccano数据标注平台来做。
预训练模型微调
在源码的 /PaddleNLP/applications/text_classification/hierarchical下,基于预训练模型上,做领域业务数据的微调。脚本如下:
python train.py
–dataset_dir “data”
–device “gpu”
–max_seq_length 128
–model_name “ernie-3.0-medium-zh”
–batch_size 32
–early_stop
–epochs 100
生成checkpoint文件夹,这就是最终的微调参数文件。
图片
image.png
模型导出与推理
训练好数据后,将参数文件导出,并做推理。
导出命令:
python export_model.py --params_path ./checkpoint/ --output_path ./export
微调命令:源码的 /PaddleNLP/applications/text_classification/hierarchical/deploy/predictor下执行如下脚本
python infer.py
–device “gpu”
–model_path_prefix “…/…/export/float32”
–model_name_or_path “ernie-3.0-medium-zh”
–max_seq_length 128
–batch_size 32
–dataset_dir “…/…/data”

PaddleNLP方案解决层次多标签分类

在之前的系列文章中,阐述并实践了基于PaddleNLP方案解决层次多标签分类的问题。诚然,基于预训练PT+微调FT的策略是通用且逐步流行的NLP解决方案。本文从源码架构设计的角度来分析下PaddleNLP是如何解决层次多标签问题的。
源码结构拆解
模型调用
首先下载PaddleNLP源码包[1]。其次根据文档查看微调训练时的脚本:
python train.py
–dataset_dir “data”
–device “gpu”
–max_seq_length 128
–model_name “ernie-3.0-medium-zh”
–batch_size 32
–early_stop
–epochs 100
可以看到其本质上是在执行train.py文件。关键的代码如下:
from paddlenlp.transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
LinearDecayWithWarmup,
)

def train():
tokenizer = AutoTokenizer.from_pretrained(args.model_name)
trans_func = functools.partial(
preprocess_function, tokenizer=tokenizer, max_seq_length=args.max_seq_length, label_nums=len(label_list)
)
# define model
model = AutoModelForSequenceClassification.from_pretrained(args.model_name, num_classes=len(label_list))
if args.init_from_ckpt and os.path.isfile(args.init_from_ckpt):
state_dict = paddle.load(args.init_from_ckpt)
model.set_dict(state_dict)
model = paddle.DataParallel(model)
for epoch in range(1, args.epochs + 1):

    if args.early_stop and early_stop_count >= args.early_stop_nums:logger.info("Early stop!")breakfor step, batch in enumerate(train_data_loader, start=1):labels = batch.pop("labels")logits = model(**batch)loss = criterion(logits, labels)loss.backward()optimizer.step()if args.warmup:lr_scheduler.step()optimizer.clear_grad()global_step += 1if global_step % args.logging_steps == 0 and rank == 0:logger.info("global step %d, epoch: %d, batch: %d, loss: %.5f, speed: %.2f step/s"% (global_step, epoch, step, loss, 10 / (time.time() - tic_train)))tic_train = time.time()early_stop_count += 1micro_f1_score, macro_f1_score = evaluate(model, criterion, metric, dev_data_loader)save_best_path = args.save_dirif not os.path.exists(save_best_path):os.makedirs(save_best_path)# save modelsif macro_f1_score > best_f1_score:early_stop_count = 0best_f1_score = macro_f1_scoremodel._layers.save_pretrained(save_best_path)tokenizer.save_pretrained(save_best_path)logger.info("Current best macro f1 score: %.5f" % (best_f1_score))
logger.info("Final best macro f1 score: %.5f" % (best_f1_score))

在train的方法中,其逻辑就像是平常在玩transformers库一样,定义模型类,分词类;然后执行模型类,前向传播、反向传播、计算损失;同时评估模型的得分等,总的来说,还是神经网络模型的那一套。
而在这里面,最关键的就是模型类了,虽然这里显示的是AutoModelForSequenceClassification类,但实际执行的肯定不是这个,因为加载的模型是ERINE。
模型类
打印实际的模型调用类:
model = AutoModelForSequenceClassification.from_pretrained(‘ernie-3.0-medium-zh’)
print(type(model))
图片定位到其源码位置:图片其源码结构是:图片
模型类配置
先查看下configuration.py配置类,看下加载了哪些关键的配置:
ERNIE_PRETRAINED_INIT_CONFIGURATION = {
# Deprecated, alias for ernie-1.0-base-zh
“ernie-1.0”: {
“attention_probs_dropout_prob”: 0.1,
“hidden_act”: “relu”,
“hidden_dropout_prob”: 0.1,
“hidden_size”: 768,
“initializer_range”: 0.02,
“max_position_embeddings”: 513,
“num_attention_heads”: 12,
“num_hidden_layers”: 12,
“type_vocab_size”: 2,
“vocab_size”: 18000,
“pad_token_id”: 0,
},
“ernie-3.0-medium-zh”: {
“attention_probs_dropout_prob”: 0.1,
“hidden_act”: “gelu”,
“hidden_dropout_prob”: 0.1,
“hidden_size”: 768,
“intermediate_size”: 3072,
“initializer_range”: 0.02,
“max_position_embeddings”: 2048,
“num_attention_heads”: 12,
“num_hidden_layers”: 6,
“task_type_vocab_size”: 16,
“type_vocab_size”: 4,
“use_task_id”: True,
“vocab_size”: 40000,
},
“uie-medium”: {
“attention_probs_dropout_prob”: 0.1,
“hidden_act”: “gelu”,
“hidden_dropout_prob”: 0.1,
“hidden_size”: 768,
“intermediate_size”: 3072,
“initializer_range”: 0.02,
“max_position_embeddings”: 2048,
“num_attention_heads”: 12,
“num_hidden_layers”: 6,
“task_type_vocab_size”: 16,
“type_vocab_size”: 4,
“use_task_id”: True,
“vocab_size”: 40000,
}
}

ERNIE_PRETRAINED_INIT_CONFIGURATION配置类定义了关键的模型参数,譬如隐藏层大小,激活函数,隐藏层数,注意力头数等等;而且还配置了NLP各个维度的任务,譬如UIE、问答、分类等。
ErnieForSequenceClassification类
在模型类modeling文件中,定义了多个Model,用于解决各个NLP任务。代码如下:
all = [
“ErnieModel”,
“ErniePretrainedModel”,
“ErnieForSequenceClassification”,
“ErnieForTokenClassification”,
“ErnieForQuestionAnswering”,
“ErnieForPretraining”,
“ErniePretrainingCriterion”,
“ErnieForMaskedLM”,
“ErnieForMultipleChoice”,
“UIE”,
“UTC”,
]
ErnieForSequenceClassification类的注解是:
Ernie Model with a linear layer on top of the output layer,
designed for sequence classification/regression tasks like GLUE tasks.

Ernie模型————输出层上有线性层;
设计用于序列分类/回归任务,如GLUE任务。
其初始化方法是:
def init(self, config):
super(ErnieForSequenceClassification, self).init(config)
# 定义模型
self.ernie = ErnieModel(config)
# 标签数:添加到模型的最后一层中要使用的标签数量,通常用于分类任务。
self.num_labels = config.num_labels
# 定义丢失率
self.dropout = nn.Dropout(
config.classifier_dropout if config.classifier_dropout is not None else config.hidden_dropout_prob
)
# 定义分类器
self.classifier = nn.Linear(config.hidden_size, config.num_labels)
前向传播forward方法:
def forward(
self,
input_ids: Optional[Tensor] = None,
token_type_ids: Optional[Tensor] = None,
position_ids: Optional[Tensor] = None,
attention_mask: Optional[Tensor] = None,
inputs_embeds: Optional[Tensor] = None,
labels: Optional[Tensor] = None,
output_hidden_states: Optional[bool] = None,
output_attentions: Optional[bool] = None,
return_dict: Optional[bool] = None,
):
# 调用模型
outputs = self.ernie(
input_ids,
token_type_ids=token_type_ids,
position_ids=position_ids,
attention_mask=attention_mask,
inputs_embeds=inputs_embeds,
output_attentions=output_attentions,
output_hidden_states=output_hidden_states,
return_dict=return_dict,
)
pooled_output = outputs[1]
pooled_output = self.dropout(pooled_output)
# 计算分类概率
logits = self.classifier(pooled_output)
# …其它代码…
return SequenceClassifierOutput(
loss=loss,
logits=logits,
hidden_states=outputs.hidden_states,
attentions=outputs.attentions,
)

将模型返回的数据,丢入分类器中,返回其概率,最终返回到用户端。最关键的还是在模型类ErnieModel。
ErnieModel类
在该类的构造函数中,定义了向量层与encoder层等。
def init(self, config: ErnieConfig):
super(ErnieModel, self).init(config)
self.pad_token_id = config.pad_token_id
self.initializer_range = config.initializer_range
weight_attr = paddle.ParamAttr(
initializer=nn.initializer.TruncatedNormal(mean=0.0, std=self.initializer_range)
)
# 向量嵌入
self.embeddings = ErnieEmbeddings(config=config, weight_attr=weight_attr)
# 编码器
encoder_layer = nn.TransformerEncoderLayer(
config.hidden_size,
config.num_attention_heads,
config.intermediate_size,
dropout=config.hidden_dropout_prob,
activation=config.hidden_act,
attn_dropout=config.attention_probs_dropout_prob,
act_dropout=0,
weight_attr=weight_attr,
normalize_before=False,
)
self.encoder = nn.TransformerEncoder(encoder_layer, config.num_hidden_layers)
self.pooler = ErniePooler(config, weight_attr)
前向传播forward函数:
def forward(
self,
input_ids: Optional[Tensor] = None,
token_type_ids: Optional[Tensor] = None,
position_ids: Optional[Tensor] = None,
attention_mask: Optional[Tensor] = None,
task_type_ids: Optional[Tensor] = None,
past_key_values: Optional[Tuple[Tuple[Tensor]]] = None,
inputs_embeds: Optional[Tensor] = None,
use_cache: Optional[bool] = None,
output_hidden_states: Optional[bool] = None,
output_attentions: Optional[bool] = None,
return_dict: Optional[bool] = None,
):

处理掩码

if attention_mask is None:
attention_mask = paddle.unsqueeze(
(input_ids == self.pad_token_id).astype(self.pooler.dense.weight.dtype) * -1e4, axis=[1, 2]
)
if past_key_values is not None:
batch_size = past_key_values[0][0].shape[0]
past_mask = paddle.zeros([batch_size, 1, 1, past_key_values_length], dtype=attention_mask.dtype)
attention_mask = paddle.concat([past_mask, attention_mask], axis=-1)

For 2D attention_mask from tokenizer

elif attention_mask.ndim == 2:
attention_mask = paddle.unsqueeze(attention_mask, axis=[1, 2]).astype(paddle.get_default_dtype())
attention_mask = (1.0 - attention_mask) * -1e4

attention_mask.stop_gradient = True

处理嵌入层

embedding_output = self.embeddings(
input_ids=input_ids,
position_ids=position_ids,
token_type_ids=token_type_ids,
task_type_ids=task_type_ids,
inputs_embeds=inputs_embeds,
past_key_values_length=past_key_values_length,
)

训练编码器

self.encoder._use_cache = use_cache # To be consistent with HF
encoder_outputs = self.encoder(
embedding_output,
src_mask=attention_mask,
cache=past_key_values,
output_attentions=output_attentions,
output_hidden_states=output_hidden_states,
return_dict=return_dict,
)
if isinstance(encoder_outputs, type(embedding_output)):
sequence_output = encoder_outputs
pooled_output = self.pooler(sequence_output)
return (sequence_output, pooled_output)
else:
sequence_output = encoder_outputs[0]
pooled_output = self.pooler(sequence_output)
if not return_dict:
return (sequence_output, pooled_output) + encoder_outputs[1:]
return BaseModelOutputWithPoolingAndCrossAttentions(
last_hidden_state=sequence_output,
pooler_output=pooled_output,
past_key_values=encoder_outputs.past_key_values,
hidden_states=encoder_outputs.hidden_states,
attentions=encoder_outputs.attentions,
)

这就是神经网络模型实际执行的地方。
总结
之所以会想要梳理模型类,是想剥开大模型的外衣,看看其内部的运作逻辑。其实拆解下来后,其逻辑原理就是最初学习神经网络transformer模型时,跑的示例代码一样。总的来说,还是那些固定的流程。当然,涉及到其深入的设计,譬如掩码MASK、注意力层、transformer层等,就需要更深的功底。
参考资料
[1]
PaddleNLP源码包: https://github.com/PaddlePaddle/PaddleNLP/blob/develop/README.md

使用Python进行用户画像构建的案例分析

用户画像,又称为用户档案或客户画像,是一种通过收集和分析用户的行为、偏好、需求等多维度信息,创建的虚拟用户模型。它是对目标用户群体的一种抽象和概括,旨在帮助企业更好地理解其客户,以便为他们提供更加个性化和精准的产品和服务。

本文将详细介绍如何使用Python进行用户画像的构建,并结合实际应用场景,给出每个阶段的任务和系统框架。

用户画像

用户画像通常包含以下几个方面的内容:

基本属性:包括用户的年龄、性别、职业、教育水平、地理位置等基本信息。
心理特征:涉及用户的个性、生活态度、价值观念等心理层面的特征。
行为特征:用户在互联网上的行为习惯,如浏览网页、使用应用、购物、社交互动等。
消费习惯:用户的购买行为、购买频率、偏好产品、消费能力等消费相关的信息。
需求和偏好:用户的具体需求、兴趣爱好、品牌偏好等。
用户画像的构建通常涉及以下几个步骤:

数据收集:从多个渠道收集用户数据,包括在线行为数据、交易记录、调查问卷、社交媒体等。
数据预处理:对收集到的数据进行清洗和整理,处理缺失值、异常值,将非结构化数据转化为结构化数据。
特征工程:从原始数据中提取有用的特征,创建能够代表用户属性和行为的新指标。
用户分群:使用聚类分析等方法将用户划分为不同的群体,每个群体具有相似的特征和行为。
画像构建:根据分群结果,为每个群体创建详细的用户画像,包括关键属性和行为模式的描述。
应用与优化:将用户画像应用于市场营销、产品设计、客户服务等业务领域,根据实际效果和反馈不断优化和更新用户画像。
用户画像是企业了解和服务目标客户群体的重要工具。通过收集和分析用户的行为数据、偏好、需求等信息,企业可以构建出细分的用户群体模型,进而实现精准营销和服务改进。

  1. 数据收集与预处理

任务:

收集用户行为数据
清洗数据,处理缺失值和异常值
转换数据格式,为分析做准备
系统框架组件:

数据收集模块:使用Python的requests库从数据库、API或第三方平台获取数据。
数据清洗模块:使用pandas库进行数据的预处理,包括去除重复值、填充或删除缺失值、数据类型转换等。
2. 特征工程

任务:

确定用户画像的关键特征
创建用户行为和偏好的指标
进行特征选择,剔除不重要的特征
系统框架组件:

特征构建模块:根据业务需求,使用pandas和numpy进行特征创建,如用户活跃度、购买频率等。
特征选择模块:使用scikit-learn中的SelectKBest或Recursive Feature Elimination方法进行特征选择。
3. 用户分群

任务:

使用分群算法将用户划分为不同的群体
分析每个群体的特征和行为模式
系统框架组件:

分群算法模块:使用scikit-learn中的KMeans或DBSCAN等聚类算法对用户进行分群。
群体分析模块:对分群结果进行分析,提取每个群体的特征和行为模式。
4. 用户画像建模

任务:

构建预测模型,预测用户的行为和偏好
评估模型的性能和准确性
系统框架组件:

建模模块:使用scikit-learn中的分类或回归算法构建用户行为预测模型。
评估模块:使用交叉验证、ROC曲线等方法对模型进行评估和优化。
5. 应用与优化

任务:

将用户画像应用于实际业务场景
根据反馈和业务变化不断优化用户画像
系统框架组件:

应用模块:将用户画像集成到推荐系统、营销活动等业务流程中。
优化模块:根据业务反馈和新的数据不断调整和改进用户画像模型。
实际应用场景

假设我们是一家电子商务公司,希望通过用户画像提高用户的购物体验和满意度。我们可以按照以下步骤进行:

数据收集与预处理:从网站后台和数据库中收集用户的浏览记录、购买历史、注册信息等数据,并进行清洗和格式化。
特征工程:根据业务需求,构建用户活跃度、购买频率、平均消费金额等特征,并筛选出对用户行为预测最有影响的特征。
用户分群:使用聚类算法将用户分为几个群体,比如高价值用户、活跃用户、潜在流失用户等。
用户画像建模:针对每个用户群体,构建预测模型,预测他们的购买行为和偏好变化。
应用与优化:将用户画像应用于个性化推荐、定向营销、客户服务等环节,并根据用户反馈和业务效果进行持续优化。
通过上述步骤,我们可以构建出一个完整的用户画像系统,帮助企业更好地理解客户,实现精准营销和服务改进。

代码示例

以下是一个更具体的Python代码片段,用于构建用户画像的示例。这个例子中,我们将使用KMeans聚类算法来对用户进行分群,并创建一些基本的用户特征。

导入必要的库

import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score

假设我们有一个DataFrame ‘df’,包含用户的行为数据

df = pd.read_csv(‘user_data.csv’) # 读取数据

这里我们创建一个示例DataFrame

data = {
‘UserID’: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
‘Age’: [25, 30, 22, 35, 40, 23, 29, 31, 39, 24],
‘Gender’: [‘F’, ‘M’, ‘F’, ‘M’, ‘F’, ‘M’, ‘F’, ‘M’, ‘F’, ‘M’],
‘Total_Spent’: [50, 200, 150, 450, 120, 250, 130, 320, 180, 300],
‘Avg_Daily_Visits’: [1.2, 1.5, 0.8, 2.0, 1.0, 2.2, 1.0, 1.8, 1.5, 2.0],
‘Product_Interests’: [‘Tech, Fashion’, ‘Books, Tech’, ‘Fashion, Home’, ‘Books, Health’, ‘Tech, Sports’, ‘Books’, ‘Fashion, Sports’, ‘Home, Health’, ‘Tech’, ‘Books, Fashion’]
}

df = pd.DataFrame(data)

数据预处理

将Gender和Product_Interests转换为数值型数据

df[‘Gender’] = df[‘Gender’].map({‘F’: 1, ‘M’: 0})

将Product_Interests拆分为多列

interests = df[‘Product_Interests’].str.split(‘,’, expand=True)
df = df.drop(‘Product_Interests’, axis=1)
df = pd.concat([df, interests], axis=1)

特征工程

创建新的特征,例如用户价值

df[‘User_Value’] = df[‘Total_Spent’] * df[‘Avg_Daily_Visits’]

标准化特征

scaler = StandardScaler()
df_scaled = scaler.fit_transform(df[[‘Age’, ‘Total_Spent’, ‘Avg_Daily_Visits’, ‘User_Value’]])

用户分群

使用KMeans算法对用户进行分群

kmeans = KMeans(n_clusters=3, random_state=42)
df[‘Cluster’] = kmeans.fit_predict(df_scaled)

计算轮廓系数,评估分群效果

sil_score = silhouette_score(df_scaled, df[‘Cluster’])
print(f"Silhouette Score: {sil_score}")

输出前几个用户的信息和分群结果

print(df[[‘UserID’, ‘Gender’, ‘Cluster’]].head())
在这个代码片段中,我们首先创建了一个包含用户数据的DataFrame。然后,我们进行了一些基本的数据预处理,包括将性别和产品兴趣转换为数值型数据,并创建了新的特征User_Value来表示用户价值。

接着,我们对特征进行了标准化处理,并使用KMeans算法对用户进行了分群。我们还计算了轮廓系数来评估分群的效果,并输出了前几个用户的信息和分群结果。

请注意,这个示例是为了演示如何使用Python进行用户画像构建的基本流程。在实际应用中,你可能需要处理更复杂的数据集,构建更复杂的特征,使用更高级的分群和预测模型,并进行详细的模型评估和优化。此外,对于产品兴趣这样的类别型特征,可能需要使用更复杂的编码方法,如独热编码(One-Hot Encoding)或其他文本向量化技术。

pandas实战:用户消费行为画像

该项目主要对某平台用户消费行为进行画像分析,通过pandas的灵活使用,对月销量、客户复购率、回购率、客户分层、高质量客户、留存率、消费间隔等进行多维度分析。以下为部分节选内容,完整数据和代码可在文末扫码了解👇

首先,加载用户的消费数据。

columns=[“user_id”,“order_dt”,“order_product”,“order_amount”]
df = pd.read_csv(‘data.txt’, sep=‘\s+’, names=columns)
图片
user_id:客户ID
order_dt:订单日期
order_product:订单产品
order_amount:订单金额
1.统计每个客户购买的总数量和平均金额
使用groupby+agg聚合的方法得到统计结果,并按order_product降序排序。

(
df.groupby(“user_id”,as_index=False)
.agg({“order_product”:np.sum,“order_amount”:np.mean})
.sort_values([‘order_product’],ascending=False)
)
图片
2.统计每个月销售额的情况
(
df.groupby(“order_month”)[‘order_amount’].sum()
.plot(figsize=(10,6),marker=‘o’)
)
图片
3.每笔订单对应的金额分布
一笔订单对应的总金额分布

df.plot.scatter(x=“order_product”,y=“order_amount”)
图片
每个用户每笔订单对应的总金额分布

(
df.groupby(“user_id”)[[‘order_product’,‘order_amount’]].sum()
.plot.scatter(x=“order_product”,y=“order_amount”)
)
4.单个用户的消费行为
plt.figure(figsize=(12,4))
plt.subplot(121)
df.order_amount.hist(bins=30) #订单金额直方图分布

plt.subplot(122)
df.groupby(“user_id”).order_product.sum().hist(bins=30) #每个用户购买总量的直方图
plt.tight_layout()
图片
反映出大部分人的消费额和购买数量都是较低,符合一般消费规律。

5.复购率分析
复购率定义:在一个月内消费次数2次及以上的用户所占的比例。

首先通过透视表pivot_table统计每个用户各月的消费次数,然后加工出复购的标识,将每月消费次数2次以上的记为1,一次的记为0,没有消费的记为NaN。

pc = df.pivot_table(index=“user_id”,
columns=“order_month”,
values=“order_date”,
aggfunc=“count”).fillna(0)
pct = pc.applymap(lambda x:1 if x>=2 else np.NAN if x==0 else 0)

按月统计复购率

pct.mean().plot(figsize=(10,6),marker=‘o’)
图片
6.回购率分析
回购率:本月消费并在下月继续消费的客户占比

这里的定义是在一个月之内只要消费次数大于1即可认为是消费。

步骤:

首先,加工出本月有过消费的标识字段,通过轴旋转变为宽表形式。
对if_has_order是否消费变量向上偏移一个单位
计算加工出是否回购变量if_reorder
可视化
pp = (
pc.applymap(lambda x:1 if x > 1 else 0)
.stack()
.to_frame(name=‘if_has_order’)
.reset_index()
)

回购计算逻辑

pp[‘if_has_order_next_month’] = pp[‘if_has_order’].shift(-1)
pp[‘if_reorder’] = 0
pp.loc[(pp1[‘if_has_order’] == 1)&(pp[‘if_has_order_next_month’]==1),‘if_reorder’] = 1
pp.loc[(pp1[‘if_has_order’] == 1)&(pp[‘if_has_order_next_month’]==0),‘if_reorder’] = 0
pp.loc[(pp1[‘if_has_order’] == 0),‘if_reorder’] = np.nan

(
pp.pivot_table(index=‘order_month’,values=‘if_reorder’,aggfunc=‘mean’)
.plot(figsize=(10,6),marker=‘o’)
)
图片
整体回购率约为25%,其中新客户质量低于老客户,老客户的忠诚度较高。最后一期降为0是由于没有下一期数据,可以视为异常忽略。

  1. 客户分层分析
    根据客户的活跃程度可将客户分为沉默户、新户、活跃户、不活跃户、回流用户,具体定义如下:

沉默户:从未发生过消费的客户

新户:第一次消费的客户

活跃户:老客户,在时间窗口内发生过消费的客户

不活跃户:老客户,在时间窗口内未发生过消费的客户

回流:上个月未消费但本月消费过的客户

为了给每个客户在各观察月打上客户分层标签,需要借助一些辅助列。通过分组内偏移、排序、累计求和等方法实现。分组内的各种骚操作可以了解东哥的pandas进阶宝典。

pp[‘order_month’] = pd.to_datetime(pp[‘order_month’])
pp = pp.sort_values([‘user_id’,‘order_month’],ascending=[True,True])

加工辅助列

pp[‘if_has_order_last_month’] = pp.groupby([‘user_id’])[‘if_has_order’].transform(lambda x:x.shift(1))
pp[‘if_has_order_next_month’] = pp.groupby([‘user_id’])[‘if_has_order’].transform(lambda x:x.shift(-1))

pp[‘order_rank’] = pp.groupby([‘user_id’])[‘order_month’].transform(lambda x: x.rank(method=‘first’))
pp[‘order_cumsum’] = pp.groupby([‘user_id’])[‘if_has_order’].transform(‘cumsum’)
然后,生成客户分层的变量user_status,按照不同的条件进行赋值。

pp[‘user_status’] = ‘’

silent

pp.loc[(pp[‘order_cumsum’]==0),‘user_status’] = ‘silent’

new

pp.loc[(pp[‘order_rank’]==1)&(pp[‘if_has_order’]==1),‘user_status’] = ‘new’
pp.loc[(~(pp[‘order_rank’]==1))&(pp[‘if_has_order’]==1)&(pp[‘order_cumsum’]==1),‘user_status’] = ‘new’

unactive

pp.loc[(pp[‘order_cumsum’]>0)&(pp[‘if_has_order’]==0),‘user_status’] = ‘unactive’

active

pp.loc[(pp[‘order_cumsum’]>1)&(pp[‘if_has_order’]==1)&(pp[‘if_has_order_last_month’]==1),‘user_status’] = ‘active’

return

pp.loc[(pp[‘order_cumsum’]>1)&(pp[‘if_has_order’]==1)&(pp[‘if_has_order_last_month’]==0),‘user_status’] = ‘return’
最后用面积图进行分层客户的可视化。蓝色的面积表示活跃客户,绿色表示回流客户,4个月后基本稳定,说明没有新客。

pp1 = pp.replace(“silent”,np.NaN)
pp2 = pp1.pivot_table(index=‘order_month’,columns=‘user_status’,values=‘user_id’,aggfunc=‘count’,fill_value=0)
pp2.plot.area(figsize=(12,6))
图片
8.高质量客户分析
按客户ID分组对订单金额求和,然后计算每个客户的订单总和占累计求和的比例。

ua = df.groupby(“user_id”).order_amount.sum().sort_values().reset_index()
ua[“amount_cumsum”] = ua.order_amount.cumsum()
ua[“amount_sum”] = ua.order_amount.sum()

ua[“prop”] = ua.apply(lambda x:x.amount_cumsum/x.amount_sum,axis=1 )
ua.prop.plot(figsize=(12,6))
可以看到,前20000的客户贡献了40%的消费,后面4000的客户贡献了60%的金额,呈现二八倾向。

图片
9.计算用户生命周期
求出每个客户的最早和最晚的消费日期作差得到最早和最晚的时间间隔时长,即为客户的生命周期。

user_purchase = df[[“user_id”,“order_product”,“order_amount”,“order_date”]]
order_date_min = user_purchase.groupby(“user_id”).order_date.min() #按客户分组求最早的消费日期
order_date_max = user_purchase.groupby(“user_id”).order_date.max() #按客户分组求最近的消费日期
(order_date_max-order_date_min).dt.days.hist(bins=40,figsize=(10,6))
大部分客户只消费了一次,开始时间和结束时间都是一样的所以相减为0,因此大部分客户集中在0。

图片
剔除只消费1次的,对消费2次及以上的客户进行分析。

lft = (order_date_max-order_date_min).dt.days
lft[lft>0].hist(bins=100,figsize=(10,6))
图片
消费2次及以上的客户生命周期呈现双峰趋势,处于左峰部分的客户生命周期在0至100天内,虽然消费了2次但没有能持性,因此在该部分客户首次消费30天后应该进行主动营销引导后续消费;处于右侧峰部分的客户生命周期集中在400天以后,属于忠诚用户;而集中在50-300天的属于普通型的生命周期。

Python数据分析消费者用户画像

一个聚类和降维结合的项目,分为两块内容:
直接使用原数据,经过数据预处理和编码后,基于原生的K-Means和PCA/T-SNE实现用户的聚类
使用基于Transformer的预训练模型转换后的高维数据,再使用K-Means和PCA/T-SNE实现用户的聚类

In [1]:
import pandas as pd
import numpy as np

np.random.seed(42)

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import plotly.express as px
import plotly.graph_objects as go
import seaborn as sns
import shap

from sklearn.cluster import KMeans
from sklearn.preprocessing import PowerTransformer, OrdinalEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.manifold import TSNE
from sklearn.metrics import silhouette_score, silhouette_samples, accuracy_score, classification_report

from pyod.models.ecod import ECOD
from yellowbrick.cluster import KElbowVisualizer

import lightgbm as lgb
import prince

from tqdm.notebook import tqdm
from time import sleep

import warnings
warnings.filterwarnings(“ignore”)
3 读取数据

In [2]:
df = pd.read_csv(“train/train.csv”,sep=“;”)
数据的探索性分析过程,了解数据基本信息:
In [3]:
df.shape
Out[3]:
(45211, 17)
In [4]:
df.columns
Out[4]:
Index([‘age’, ‘job’, ‘marital’, ‘education’, ‘default’, ‘balance’, ‘housing’,
‘loan’, ‘contact’, ‘day’, ‘month’, ‘duration’, ‘campaign’, ‘pdays’,
‘previous’, ‘poutcome’, ‘y’],
dtype=‘object’)
In [5]:
df.dtypes
Out[5]:
age int64
job object
marital object
education object
default object
balance int64
housing object
loan object
contact object
day int64
month object
duration int64
campaign int64
pdays int64
previous int64
poutcome object
y object
dtype: object
In [6]:
pd.Series.value_counts(df.dtypes)
Out[6]:
object 10
int64 7
Name: count, dtype: int64
In [7]:

缺失值信息

df.isnull().sum()
Out[7]:
age 0
job 0
marital 0
education 0
default 0
balance 0
housing 0
loan 0
contact 0
day 0
month 0
duration 0
campaign 0
pdays 0
previous 0
poutcome 0
y 0
dtype: int64
结果表明数据中没有缺失值。
In [8]:

取出前面8个特征进行建模

df = df.iloc[:, 0:8]
4 数据预处理Preprocessing

主要是针对分类型的数据进行编码工作:
In [9]:

1-独热码

categorical_transformer_onehot = Pipeline(
steps = [(“encoder”, OneHotEncoder(handle_unknown=“ignore”,drop=“first”, sparse=False))])

2-顺序编码

caterogorical_transformer_ordinal = Pipeline(
steps=[(“encoder”, OrdinalEncoder())]
)

3-数据转换(对数变换、标准化、归一化等)

num = Pipeline(
steps=[(“encoder”,PowerTransformer())]
)
In [10]:
df.dtypes
Out[10]:
age int64
job object
marital object
education object
default object
balance int64
housing object
loan object
dtype: object
设定数据预处理器:
In [11]:
preprocessor = ColumnTransformer(transformers=[
(“cat_onehot”, categorical_transformer_onehot, [“default”,“housing”,“loan”,“job”,“marital”]),
(“cat_ordinal”, caterogorical_transformer_ordinal, [“education”]),
(“num”, num, [“age”, “balance”])
])
5 创建pipeline

In [12]:
pipeline = Pipeline(
steps=[(“preprocessor”, preprocessor)]
)

训练

pipe_fit = pipeline.fit(df)
In [13]:
data = pd.DataFrame(pipe_fit.transform(df), columns=pipe_fit.get_feature_names_out().tolist())
data.shape
Out[13]:
(45211, 19)
In [14]:
data.columns
Out[14]:
Index([‘cat_onehot__default_yes’, ‘cat_onehot__housing_yes’,
‘cat_onehot__loan_yes’, ‘cat_onehot__job_blue-collar’,
‘cat_onehot__job_entrepreneur’, ‘cat_onehot__job_housemaid’,
‘cat_onehot__job_management’, ‘cat_onehot__job_retired’,
‘cat_onehot__job_self-employed’, ‘cat_onehot__job_services’,
‘cat_onehot__job_student’, ‘cat_onehot__job_technician’,
‘cat_onehot__job_unemployed’, ‘cat_onehot__job_unknown’,
‘cat_onehot__marital_married’, ‘cat_onehot__marital_single’,
‘cat_ordinal__education’, ‘num__age’, ‘num__balance’],
dtype=‘object’)
6 异常处理(ECOD)

基于Python Outlier Detection库进行异常值处理(Kmeans对异常值敏感)。
另外一种方法ECOD(empirical cumulative distribution functions for outlier detection)基于经验累积分布函数的异常值检测方法。
In [15]:
from pyod.models.ecod import ECOD

clf = ECOD()
clf.fit(data)

outliers = clf.predict(data)
outliers
Out[15]:
array([0, 0, 0, …, 1, 0, 0])
In [16]:
data[“outliers”] = outliers # 添加预测结果
df[“outliers”] = outliers # 原始数据添加预测结果
In [17]:

包含异常值和不含包单独处理

data无异常值

data_no_outliers = data[data[“outliers”] == 0]
data_no_outliers = data_no_outliers.drop([“outliers”],axis=1)

data有异常值

data_with_outliers = data.copy()
data_with_outliers = data_with_outliers.drop([“outliers”],axis=1)

原始数据无异常值

df_no_outliers = df[df[“outliers”] == 0]
df_no_outliers = df_no_outliers.drop([“outliers”], axis = 1)
In [18]:
data_no_outliers.head()
Out[18]:
图片
查看数据量:
In [19]:
data_no_outliers.shape
Out[19]:
(40690, 19)
In [20]:
data_with_outliers.shape
Out[20]:
(45211, 19)
7 聚类建模(K-Means)

7.1 肘图识别k值

聚类过程中的k值如何确定?介绍基于肘图的方法,详细参考:
https://www.geeksforgeeks.org/elbow-method-for-optimal-value-of-k-in-kmeans/
In [21]:
from yellowbrick.cluster import KElbowVisualizer

km = KMeans(init=“k-means++”, random_state=0, n_init=“auto”)
visualizer = KElbowVisualizer(km, k=(2,10))

visualizer.fit(data_no_outliers)
visualizer.show()
Out[21]:
图片
<Axes: title={‘center’: ‘Distortion Score Elbow for KMeans Clustering’}, xlabel=‘k’, ylabel=‘distortion score’>
我们可以看到k=6的时候是最好的。
7.2 轮廓系数变化

In [22]:
from sklearn.metrics import davies_bouldin_score, silhouette_score, silhouette_samples
import matplotlib.cm as cm

def make_Silhouette_plot(X, n_clusters):
plt.xlim([-0.1, 1])
plt.ylim([0, len(X) + (n_clusters + 1) * 10])
# 建立聚类模型
clusterer = KMeans(n_clusters=n_clusters,
max_iter=1000,
n_init=10,
init=“k-means++”,
random_state=10)

# 聚类预测生成标签label
cluster_label = clusterer.fit_predict(X)
# 计算轮廓系数均值(整体数据样本)
silhouette_avg = silhouette_score(X,cluster_label)
print(f"n_clusterers: {n_clusters}, silhouette_score_avg:{silhouette_avg}")# 单个数据样本
sample_silhouette_value = silhouette_samples(X, cluster_label)
y_lower = 10for i in range(n_clusters):# 第i个簇群的轮廓系数i_cluster_silhouette_value = sample_silhouette_value[cluster_label == i]# 进行排序i_cluster_silhouette_value.sort()size_cluster_i = i_cluster_silhouette_value.shape[0]y_upper = y_lower + size_cluster_i# 颜色设置color = cm.nipy_spectral(float(i) / n_clusters)# 边界填充plt.fill_betweenx(np.arange(y_lower, y_upper),0,i_cluster_silhouette_value,facecolor=color,edgecolor=color,alpha=0.7)# 添加文本信息plt.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))y_lower = y_upper + 10plt.title(f"The Silhouette Plot for n_cluster = {n_clusters}", fontsize=26)plt.xlabel("The silhouette coefficient values", fontsize=24)plt.ylabel("Cluter Label", fontsize=24)plt.axvline(x=silhouette_avg, color="red", linestyle="--")# x-y轴的刻度标签plt.xticks([-0.1,0,0.2,0.4,0.6,0.8,1])plt.yticks([])

range_n_clusters = list(range(2, 10))

for n in range_n_clusters:
print(f"N cluster:{n}“)
make_Silhouette_plot(data_no_outliers, n)
plt.savefig(f"Silhouette_Plot_{n}.png”)
plt.close()
N cluster:2
n_clusterers: 2, silhouette_score_avg:0.18112038570087005

N cluster:9
n_clusterers: 9, silhouette_score_avg:0.1465020645956104
不同k值下的轮廓系数对比:
图片
图片
图片
图片
图片
图片
图片
图片
7.3 实施聚类

从结果来说,k=6或者5效果都还OK,在这里我们最终选择k=5进行聚类分群:
In [23]:
km = KMeans(n_clusters=5,
init=“k-means++”,
n_init=10,
max_iter=100,
random_state=42
)

对无离群点数据的聚类

clusters_predict = km.fit_predict(data_no_outliers)
7.4 评价聚类效果

聚类效果如何评价?常用的三种评价指标:
Davies-Bouldin指数
Calinski-Harabasz Score
Silhouette Score
In [24]:
from sklearn.metrics import silhouette_score # 轮廓系数
from sklearn.metrics import calinski_harabasz_score
from sklearn.metrics import davies_bouldin_score # 戴维森堡丁指数(DBI)
Davies-Bouldin指数

Davies-Bouldin指数是聚类算法的一种评估方法,其值越小则表示聚类结果越好。该指数的原理是通过比较不同聚类簇之间的距离和不同聚类簇内部距离来测量聚类的效果。其计算方法如下:
对于每一个聚类簇,计算其中心点(centroid)。
计算每个聚类簇内点与其中心点的距离,并求其平均值,得到聚类内部距离(intra-cluster distance)。
计算不同聚类簇之间中心点的距离,并求其平均值,得到聚类间距离(inter-cluster distance)。
对于每个聚类簇,计算其Davies-Bouldin指数:除该簇外所有其他簇中心点与该簇中心点距离的平均值与该簇内部距离的比值。
对所有聚类簇的Davies-Bouldin指数求平均值,得到聚类总体的Davies-Bouldin指数。
通过Davies-Bouldin指数,我们可以比较不同聚类算法、不同参数下的聚类效果,从而选择最佳的聚类方案。Davies-Bouldin指数能够考虑到聚类结果的波动情况,对于相似的聚类结果,其Davies-Bouldin指数较大。因此,Davies-Bouldin指数能够区分不同聚类结果的相似程度。
此外,Davies-Bouldin指数没有假设聚类簇形状和大小的先验知识,因此可以适用于不同聚类场景。
Calinski-Harabasz Score

Calinski-Harabasz Score是一种用于评估聚类质量的指标,它基于聚类中心之间的方差和聚类内部的方差之比来计算。该指数越大,表示聚类效果越好。
Calinski-Harbasz Score是通过评估类之间方差和类内方差来计算得分,具体公式表示为:
其中,代表聚类类别数,代表全部数据数目,是类间方差,是类内方差。
的计算公式:

trace只考虑了矩阵对角上的元素,即类中所有数据点到类的欧几里得距离。
的计算公式为:

其中,是类中所有数据的集合,是类q的质点,是所有数据的中心点,是类数据点的总数。
Silhouette Score

Silhouette Score表示为轮廓系数。
Silhouette Score 是一种衡量聚类结果质量的指标,它结合了聚类内部的紧密度和不同簇之间的分离度。对于每个数据点,Silhouette Score 考虑了以下几个因素:
a:数据点到同簇其他点的平均距离(簇内紧密度)
b:数据点到最近不同簇的平均距离(簇间分离度)
具体而言,Silhouette Score 计算公式为:

轮廓系数的取值在 -1 到 1 之间,越接近 1 表示聚类效果越好,越接近 -1 则表示聚类结果较差。
In [25]:
print(f"Davies bouldin score: {davies_bouldin_score(data_no_outliers,clusters_predict)}“)
print(f"Calinski Score: {calinski_harabasz_score(data_no_outliers,clusters_predict)}”)
print(f"Silhouette Score: {silhouette_score(data_no_outliers,clusters_predict)}")
Davies bouldin score: 1.6775659296391374
Calinski Score: 6914.724747148267
Silhouette Score: 0.1672869940907178
8 降维(基于Prince.PCA)

参考官网学习地址:https://github.com/MaxHalford/prince
8.1 降维函数

In [26]:
import prince
import plotly.express as px

def get_pca_2d(df, predict):
“”"
建立聚类模型,保留2个主成分
“”"
pca_2d_object = prince.PCA(
n_components=2, # 保留两个主成分
n_iter=3, # 迭代次数
rescale_with_mean=True, # 基于均值和标准差的尺度缩放
rescale_with_std=True,
copy=True,
check_input=True,
engine=“sklearn”,
random_state=42
)
# 模型训练
pca_2d_object.fit(df)
# 原数据转换
df_pca_2d = pca_2d_object.transform(df)
df_pca_2d.columns = [“comp1”, “comp2”]
# 添加聚类预测结果
df_pca_2d[“cluster”] = predict

return pca_2d_object, df_pca_2d

同样的方式创建保留3个主成分的功能函数

def get_pca_3d(df, predict):
“”"
保留3个主成分
“”"
pca_3d_object = prince.PCA(
n_components=3, # 保留3个主成分
n_iter=3,
rescale_with_mean=True,
rescale_with_std=True,
copy=True,
check_input=True,
engine=‘sklearn’,
random_state=42
)

pca_3d_object.fit(df)df_pca_3d = pca_3d_object.transform(df)
df_pca_3d.columns = ["comp1", "comp2", "comp3"]
df_pca_3d["cluster"] = predictreturn pca_3d_object, df_pca_3d

8.2 降维可视化

下面是基于2个主成分的可视化绘图函数:
In [27]:
def plot_pca_2d(df, title=“PCA Space”, opacity=0.8, width_line=0.1):
“”"
2个主成分的降维可视化
“”"
df = df.astype({“cluster”: “object”}) # 指定字段的数据类型
df = df.sort_values(“cluster”)

columns = df.columns[0:3].tolist()# 绘图
fig = px.scatter(df,x=columns[0], y=columns[1], color='cluster',template="plotly",color_discrete_sequence=px.colors.qualitative.Vivid,title=title)# trace更新
fig.update_traces(marker={"size": 8,"opacity": opacity,"line":{"width": width_line,"color":"black"}
})

layout更新

fig.update_layout(width=800,  # 长宽height=700,autosize=False,showlegend = True,legend=dict(title_font_family="Times New Roman", font=dict(size= 20)),scene = dict(xaxis=dict(title = 'comp1', titlefont_color = 'black'),yaxis=dict(title = 'comp2', titlefont_color = 'black')),font = dict(family = "Gilroy", color  = 'black', size = 15))fig.show()    

下面是基于3个主成分的可视化绘图函数:
In [28]:
def plot_pca_3d(df, title=“PCA Space”, opacity=0.8, width_line=0.1):
“”"
3个主成分的降维可视化
“”"
df = df.astype({“cluster”: “object”})
df = df.sort_values(“cluster”)

# 定义fig
fig = px.scatter_3d(df,x='comp1', y='comp2', z='comp3',color='cluster',template="plotly",color_discrete_sequence=px.colors.qualitative.Vivid,title=title
)# trace更新
fig.update_traces(marker={"size":4,"opacity":opacity,"line":{"width":width_line,"color":"black"}
})# layout更新
fig.update_layout(width=800,  # 长宽height=800,autosize=True,showlegend = True,legend=dict(title_font_family="Times New Roman", font=dict(size= 20)),scene = dict(xaxis=dict(title = 'comp1', titlefont_color = 'black'),yaxis=dict(title = 'comp2', titlefont_color = 'black'),zaxis=dict(title = 'comp3', titlefont_color = 'black')),font = dict(family = "Gilroy", color  = 'black', size = 15))fig.show()

8.2.1 2维

下面是2维可视化的效果:
In [29]:
pca_2d_object, df_pca_2d = get_pca_2d(data_no_outliers, clusters_predict)
In [30]:
plot_pca_2d(df_pca_2d, title = “PCA Space”, opacity=1, width_line = 0.1)
图片
可以看到聚类效果并不是很好,数据并没有隔离开。
8.2.2 3维

下面是3维可视化的效果:
In [31]:
pca_3d_object, df_pca_3d = get_pca_3d(data_no_outliers, clusters_predict)
In [32]:
plot_pca_3d(df_pca_3d, title = “PCA Space”, opacity=1, width_line = 0.1)

print("The variability is : ", pca_3d_object.eigenvalues_summary)
图片
图片
图片
The variability is : eigenvalue % of variance % of variance (cumulative)
component
0 2.245 11.81% 11.81%
1 1.774 9.34% 21.15%
2 1.298 6.83% 27.98%
从结果中看到,聚类效果并不是很好,样本并没有分离开。
前面3个主成分的占比总共为27.98%,不足以捕捉到原始的数据信息和模式。下面介绍基于T-SNE的降维,该方法主要是用于高维数据的降维可视化:
9 降维优化(基于T-SNE)

取出部分样本
In [33]:
from sklearn.manifold import TSNE

无离群点的数据随机取数

sampling_data = data_no_outliers.sample(frac=0.5, replace=True, random_state=1)

聚类后的数据随机取数

clusters_predict 表示从聚类结果中随机取数

sampling_cluster = pd.DataFrame(clusters_predict).sample(frac=0.5, replace=True, random_state=1)[0].values
sampling_cluster
Out[33]:
array([4, 1, 1, …, 2, 0, 4])
9.1 实施2D降维

9.1.1 降维

In [34]:

建立降维模型

tsne2 = TSNE(
n_components=2,
learning_rate=500,
init=‘random’,
perplexity=200,
n_iter = 5000)
In [35]:
data_tsne_2d = tsne2.fit_transform(sampling_data)
In [36]:

转成df格式 + 原聚类结果

df_tsne_2d = pd.DataFrame(data_tsne_2d, columns=[“comp1”,“comp2”])
df_tsne_2d[“cluster”] = sampling_cluster
9.1.2 可视化

In [37]:
plot_pca_2d(df_tsne_2d, title = “T-SNE Space”, opacity=1, width_line = 0.1)
图片
9.2 实施3D降维

9.2.1 降维

对聚类后的结果实施T-SNE降维:
In [38]:

建立3D降维模型

tsne3 = TSNE(
n_components=3,
learning_rate=500,
init=‘random’,
perplexity=200,
n_iter = 5000
)
In [39]:

模型训练并转换数据

data_tsne_3d = tsne3.fit_transform(sampling_data)
In [40]:

转成df格式 + 原聚类结果

df_tsne_3d = pd.DataFrame(data_tsne_3d, columns=[“comp1”,“comp2”,“comp3”])
df_tsne_3d[“cluster”] = sampling_cluster
9.2.2 降维结果可视化

In [41]:
plot_pca_3d(df_tsne_3d, title = “T-SNE Space”, opacity=1, width_line = 0.1)
图片
图片
对比两种降维方法在二维效果上的比较:很明显,T-SNE的效果好很多~
图片
10 基于LGBMClassifer的分类

将无异常的原始数据df_no_outliers作为特征X,聚类后的标签clusters_predict作为目标标签y,建立一个LGBMClassifer分类模型:
10.1 建立模型

In [42]:
import lightgbm as lgb
import shap

clf_lgb = lgb.LGBMClassifier(colsample_by_tree=0.8)

将部分字段的数据类型进行转化

for col in [“job”,“marital”,“education”,“housing”,“loan”,“default”]:
df_no_outliers[col] = df_no_outliers[col].astype(“category”)

clf_lgb.fit(X=df_no_outliers,
y=clusters_predict,
feature_name = “auto”,
categorical_feature = “auto”
)
[LightGBM] [Warning] Unknown parameter: colsample_by_tree
[LightGBM] [Warning] Unknown parameter: colsample_by_tree
[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.000593 seconds.
You can set force_row_wise=true to remove the overhead.
And if memory is not enough, you can set force_col_wise=true.
[LightGBM] [Info] Total Bins 342
[LightGBM] [Info] Number of data points in the train set: 40690, number of used features: 8
[LightGBM] [Info] Start training from score -1.626166
[LightGBM] [Info] Start training from score -1.292930
[LightGBM] [Info] Start training from score -1.412943
[LightGBM] [Info] Start training from score -2.815215
[LightGBM] [Info] Start training from score -1.489282
Out[42]:
LGBMClassifier
LGBMClassifier(colsample_by_tree=0.8)
10.2 shap可视化

In [43]:
explainer = shap.TreeExplainer(clf_lgb) # 建立解释器
shap_values = explainer.shap_values(df_no_outliers) # 求出shap值

shap.summary_plot(shap_values, df_no_outliers, plot_type=“bar”,plot_size=(15,10))
图片
从结果中可以看到,age字段是最为重要的。
10.3 模型预测

In [44]:
y_pred = clf_lgb.predict(df_no_outliers) # 预测
acc = accuracy_score(y_pred, clusters_predict) # 预测值和真实值计算acc

acc

print(‘Training-set accuracy score: {0:0.4f}’. format(acc))
[LightGBM] [Warning] Unknown parameter: colsample_by_tree
Training-set accuracy score: 1.0000
In [45]:

分类报告

print(classification_report(clusters_predict, y_pred))
precision recall f1-score support

       0       1.00      1.00      1.00      80031       1.00      1.00      1.00     111682       1.00      1.00      1.00      99053       1.00      1.00      1.00      24374       1.00      1.00      1.00      9177accuracy                           1.00     40690

macro avg 1.00 1.00 1.00 40690
weighted avg 1.00 1.00 1.00 40690
10.4 聚合结果

In [46]:

原始数据无异常

df_no_outliers = df[df.outliers == 0]
df_no_outliers[“cluster”] = clusters_predict # 聚类结果
以聚类的簇结果cluster为分组字段:
统计数值型字段的均值(mean)
分类型字段的最高频数字段(分组后的第一个数据信息)
In [47]:
df_no_outliers.groupby(“cluster”).agg({
“job”:lambda x: x.value_counts().index[0],
“marital”: lambda x: x.value_counts().index[0],
“education”:lambda x: x.value_counts().index[0],
“housing”:lambda x: x.value_counts().index[0],
“loan”:lambda x: x.value_counts().index[0],
“age”:“mean”,
“balance”:“mean”,
“default”:lambda x: x.value_counts().index[0]
}).sort_values(“age”).reset_index()
Out[47]:

cluster job marital education housing loan age balance default
0 4 technician single secondary yes no 32.069740 794.696306 no
1 2 blue-collar married secondary yes no 34.569409 592.025644 no
2 3 management married secondary yes no 42.183012 7526.310217 no
3 0 management married tertiary no no 43.773960 872.797951 no
4 1 blue-collar married secondary no no 50.220989 836.407504 no
参考

参考原英文学习地址:https://towardsdatascience.com/mastering-customer-segmentation-with-llm-3d9008235f41
后面会给大家分享Transformer模型+Kmeans+PCA/T-SNE的方案~
代码已经整理完成

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com