news 2026/10/3 2:43:42

用户画像源码实战:Jupyter Notebook数据清洗与特征提取

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用户画像源码实战:Jupyter Notebook数据清洗与特征提取

简介:这份源码包面向数据分析初学者与用户研究从业者,提供一套基于Jupyter Notebook的Python用户画像构建完整流程,帮助读者理解如何从原始用户行为数据出发,完成数据清洗、特征提取与画像建模。资源共20个文件,以13个CSV数据文件为主要数据载体,配合4个IPython Notebook文件承载核心分析代码,另含1个Python源文件、1个PNG图像与1个Markdown说明文档,压缩包约118.46MB,目录结构清晰,便于按模块查阅与复现。已有125人学习下载。读者可从中获得一套可直接运行的Notebook分析模板,涵盖Pandas数据处理、Matplotlib或Seaborn可视化呈现,以及泰坦尼克号等经典数据挖掘案例的实操参考,适合作为课程设计、项目练手或用户画像入门学习的工具集。

1. 从一份 20 文件的压缩包说起:这套用户画像源码到底能跑出什么

很多人第一次接触用户画像,是被业务方一句“给我做个用户分层”逼上梁山的。手上只有几张 CSV,字段名还是拼音缩写,Jupyter Notebook 打开一片空白,不知道从哪下手。这份 upload.zip 里的 02用户画像 目录,就是冲着这个场景来的:它把一套完整的用户画像构建流程拆成了可运行的 Notebook,外加 13 个 CSV 数据文件、1 个 Python 源文件、1 张 PNG 结果图和 1 份 readme.txt,总共 20 个文件。核心不是某个高深算法,而是把“数据加载 → 清洗 → 特征提取 → 标签化 → 可视化”这条链路用 Jupyter Notebook 串起来,让你能对着改、对着跑。适合两类人:一是刚学完 Pandas 想找个完整案例练手的 Python 入门者,二是需要快速搭出用户画像原型、再往生产环境迁移的数据分析从业者。泰坦尼克号那个子目录是经典的数据挖掘流程演示,stormzudi 目录则更贴近真实用户行为数据,两者互补。

2. 拆包先看目录:Jupyter Notebook 工程结构与数据文件怎么对应

2.1 目录树还原与文件角色划分

拿到压缩包先别急着双击 .ipynb,先把目录结构看清楚。根据项目正文,解压后大致是这样:

02用户画像/ ├── 用户画像/ │ ├── data/ │ │ ├── train.csv │ │ ├── test.csv │ │ └── ...(其余 CSV 数据文件) │ ├── stormzudi/ │ │ └── ...(用户行为相关数据与 Notebook) │ ├── img/ │ │ └── ...(PNG 图像文件) │ ├── 01泰坦尼克号/ │ │ └── 泰坦尼克-数据挖掘流程.ipynb │ ├── readme.txt │ └── ...(其余 IPython Notebook 文件) └── .ipynb_checkpoints/

这里有几个关键点。第一,.ipynb_checkpoints是 Jupyter 自动生成的检查点目录,不是源码的一部分,迁移或打包时可以删掉,否则会多出一堆无用的 -checkpoint.ipynb 文件。第二,13 个 CSV 是数据载体,4 个 IPython Notebook 是代码主体,1 个 Python 源文件大概率是抽出来的工具函数,1 个 Markdown 文档负责说明设计思路。第三,01泰坦尼克号和stormzudi是两个独立的数据挖掘场景,前者用于验证流程,后者用于真实用户画像构建。

2.2 用 Python 脚本快速盘点文件与数据规模

在启动 Jupyter 之前,我习惯先用一段独立脚本把文件清单和 CSV 的基本信息扫一遍,避免在 Notebook 里反复试错。这段代码可以直接在终端里用python check_files.py跑:

import os import pandas as pd # 把这里换成你解压后的实际路径 base_dir = "./02用户画像/用户画像" # 遍历目录,统计文件类型 for root, dirs, files in os.walk(base_dir): # 跳过 Jupyter 检查点目录 if ".ipynb_checkpoints" in root: continue for f in files: path = os.path.join(root, f) size_kb = os.path.getsize(path) / 1024 print(f"{path} | {size_kb:.1f} KB") # 单独看 data 目录下的 CSV 结构 data_dir = os.path.join(base_dir, "data") if os.path.exists(data_dir): for csv_file in os.listdir(data_dir): if csv_file.endswith(".csv"): df = pd.read_csv(os.path.join(data_dir, csv_file), nrows=5) print(f"\n=== {csv_file} ===") print(f"列名: {list(df.columns)}") print(f"前5行预览:\n{df.head()}")

逻辑说明:os.walk递归遍历时主动跳过.ipynb_checkpoints,避免把检查点文件当成源码统计。nrows=5只读前 5 行,防止大 CSV 一次性吃满内存。参数上,base_dir必须指向解压后的用户画像目录,而不是压缩包根目录,否则会找不到 data 子目录。跑完这段,你就能知道每个 CSV 有哪些字段、大概是什么业务含义,再决定用哪个 Notebook 去处理它。

2.3 Notebook 与数据文件的绑定关系

4 个 IPython Notebook 不是随便放的。常见做法是:泰坦尼克-数据挖掘流程.ipynb对应data/train.csv和data/test.csv,用来演示标准的监督学习流程;stormzudi目录下的 Notebook 则读取同目录或 data 目录下的用户行为 CSV,做无监督的标签聚类和画像生成。打开 Notebook 后第一件事是检查pd.read_csv()里的路径是相对路径还是绝对路径。如果是作者本机的绝对路径,比如/Users/xxx/Desktop/...,你必须改成自己的相对路径,否则一运行就报FileNotFoundError。这是新手翻车率最高的一步,没有之一。

3. 跑通第一个 Notebook:Pandas 数据清洗与用户特征提取

3.1 环境准备与 Jupyter Notebook 启动

这套源码基于 Python 和 Jupyter Notebook,环境配置不复杂,但版本兼容性有讲究。推荐用 Miniconda 建独立环境,避免和系统 Python 打架:

# 创建独立环境,指定 Python 3.9 或 3.10 都比较稳 conda create -n user_profile python=3.10 -y conda activate user_profile # 安装核心依赖 pip install pandas numpy matplotlib seaborn scikit-learn jupyter # 启动 Notebook,注意在解压后的项目根目录执行 jupyter notebook

参数说明:python=3.10是我实测下来对 Pandas 和 Scikit-learn 兼容性较好的版本,太新的 Python 有时会让某些老版本依赖编译失败。jupyter notebook启动后默认监听 8888 端口,浏览器会自动打开文件浏览界面。如果你遇到“jupyter notebook 启动时显示找不到指定的程序”,大概率是 conda 环境里的 Scripts 目录没加进 PATH,用conda activate后直接运行python -m jupyter notebook可以绕过这个问题。

3.2 数据加载与缺失值处理

打开泰坦尼克-数据挖掘流程.ipynb,前几个 cell 通常是导入库和加载数据。我一般会在作者代码基础上补一段缺失值审计,因为用户画像对缺失值特别敏感——一个字段缺失率超过 60%,硬填反而会引入噪声:

import pandas as pd import numpy as np # 加载训练数据,注意路径改成你自己的 train = pd.read_csv("./data/train.csv") # 缺失值审计 missing = train.isnull().sum().sort_values(ascending=False) missing_pct = (missing / len(train) * 100).round(2) missing_df = pd.DataFrame({"缺失数": missing, "缺失率%": missing_pct}) print(missing_df[missing_df["缺失数"] > 0]) # 按缺失率分策略处理 # 缺失率 < 5%:数值列用中位数填充,类别列用众数填充 # 缺失率 5% ~ 60%:考虑用模型预测填充或保留缺失标志 # 缺失率 > 60%:直接丢弃该列 threshold_high = 0.6 cols_to_drop = missing_pct[missing_pct > threshold_high * 100].index.tolist() train.drop(columns=cols_to_drop, inplace=True) print(f"已丢弃高缺失列: {cols_to_drop}") # 对 Age 这类中等缺失率的数值列,用中位数填充并加缺失标志 if "Age" in train.columns: train["Age_missing"] = train["Age"].isnull().astype(int) train["Age"].fillna(train["Age"].median(), inplace=True)

逻辑说明:isnull().sum()统计每列缺失数量,除以总行数得到缺失率。threshold_high = 0.6是我常用的经验阈值,超过 60% 的列在用户画像场景下基本没有区分度。给Age加Age_missing标志位是个小技巧——有时候“是否缺失”本身就是一个有信息量的特征,比如某些渠道的用户就是不愿意填年龄。参数上,中位数比均值更抗极端值,用户行为数据里长尾分布很常见,这一点要特别注意。

3.3 类别特征编码与用户标签生成

用户画像的核心是把原始字段转成可解释的标签。泰坦尼克号数据集里Sex、Embarked是典型类别特征,stormzudi里的用户行为数据则可能有city、device_type等。常见做法是先用 Pandas 的get_dummies做独热编码,再用分箱把连续变量变成离散标签:

# 类别特征独热编码 cat_cols = [c for c in ["Sex", "Embarked", "Pclass"] if c in train.columns] train_encoded = pd.get_dummies(train, columns=cat_cols, drop_first=True) # 连续变量分箱,生成用户标签 # 以 Fare 为例,分成低、中、高消费三档 if "Fare" in train_encoded.columns: train_encoded["Fare_Level"] = pd.cut( train_encoded["Fare"], bins=[-1, 10, 50, np.inf], labels=["低消费", "中消费", "高消费"] ) # 组合标签:性别 + 消费等级,形成粗粒度用户画像 if "Sex_male" in train_encoded.columns and "Fare_Level" in train_encoded.columns: train_encoded["User_Persona"] = ( train_encoded["Sex_male"].map({0: "女性", 1: "男性"}) + "_" + train_encoded["Fare_Level"].astype(str) ) print(train_encoded["User_Persona"].value_counts())

逻辑说明:drop_first=True在独热编码时丢弃第一个类别,避免多重共线性,这对后续如果要用逻辑回归建模很重要。pd.cut的分箱边界[-1, 10, 50, np.inf]是根据 Fare 的实际分布调的,你的数据如果不一样,先用train["Fare"].describe()看分位数再定边界。组合标签那一步是用户画像的雏形——把两个维度交叉,得到“男性_高消费”“女性_低消费”这样的可读标签,业务方一看就懂。参数上,astype(str)不能省,否则pd.cut返回的 Categorical 类型和字符串拼接会报错。

4. 避坑与排查:Jupyter Notebook 跑用户画像源码的五个血泪经验

4.1 路径错误导致 FileNotFoundError

现象:Notebook 第一个 cell 就报FileNotFoundError: [Errno 2] No such file or directory: 'train.csv'。原因:作者写代码时用的是本机绝对路径,或者相对路径的基准目录和你当前启动 Jupyter 的目录不一致。解决:在 Notebook 开头加一段import os; print(os.getcwd()),确认当前工作目录,然后把所有pd.read_csv()的路径改成相对于该目录的正确路径。我一般会统一改成./data/xxx.csv这种形式,并且把 Notebook 和 data 目录放在同一级。

4.2 中文列名或中文路径引发编码报错

现象:读取 CSV 时报UnicodeDecodeError: 'utf-8' codec can't decode byte...。原因:Windows 下用 Excel 保存的 CSV 默认是 GBK 编码,而 Pandas 默认按 UTF-8 读。解决:pd.read_csv("./data/xxx.csv", encoding="gbk"),如果还不行就试encoding="gb18030"。另外,项目路径里如果有中文,某些老版本 Jupyter 也会出问题,尽量把项目放在纯英文路径下,比如D:/projects/user_profile/。

4.3 Notebook 内核与依赖版本不匹配

现象:import sklearn成功,但调用某个函数时报AttributeError: module 'sklearn' has no attribute 'xxx'。原因:Notebook 使用的内核不是你刚创建的那个 conda 环境,或者 Scikit-learn 版本太老。解决:在 Notebook 里运行import sys; print(sys.executable)确认内核路径,如果不是你 conda 环境下的 python.exe,通过 Kernel → Change Kernel 切换。依赖版本用pip install -U scikit-learn pandas统一升级到较新版本。

4.4 大数据 CSV 导致内存溢出

现象:读取一个几百 MB 的 CSV 时,Notebook 内核直接挂掉,报MemoryError。原因:pd.read_csv()默认把所有列按最占内存的类型读进来,字符串列尤其吃内存。解决:用dtype参数指定列类型,或者用usecols只读需要的列,再或者用chunksize分块读取。示例:pd.read_csv("big.csv", usecols=["user_id", "action", "timestamp"], dtype={"user_id": "int32"})。用户画像不需要全量字段,先想清楚要哪些维度再读。

4.5 可视化图表中文显示为方块

现象:Matplotlib 或 Seaborn 画的图里,中文标签全变成方框。原因:Matplotlib 默认字体不支持中文。解决:在 Notebook 开头加两行配置:

import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei"] # Windows 用黑体 plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题

Mac 系统把SimHei换成Arial Unicode MS或PingFang SC。这个坑不解决,后面所有画像分布图都白画。

5. 从泰坦尼克到 stormzudi:把画像流程迁移到真实用户行为数据

5.1 两个数据集的字段差异与迁移策略

泰坦尼克号数据集是结构化表格,字段少、含义明确,适合验证流程。stormzudi目录下的数据更接近真实用户行为日志,可能有用户 ID、时间戳、页面停留、点击事件等字段。迁移时不能直接套用泰坦尼克的代码,核心差异在于:泰坦尼克是“一个用户一行”,行为日志是“一个用户多行”。你需要先做聚合,把多行行为压缩成一行用户特征。常见做法是用groupby("user_id").agg()计算每个用户的点击次数、平均停留时长、活跃天数等统计量,再把这些统计量作为画像的输入维度。

# 假设行为日志有 user_id, event_type, duration 三列 logs = pd.read_csv("./stormzudi/user_logs.csv") # 聚合到用户粒度 user_features = logs.groupby("user_id").agg( 点击次数=("event_type", "count"), 平均停留=("duration", "mean"), 最大停留=("duration", "max"), 活跃天数=("event_type", lambda x: x.nunique()) # 这里按实际字段调整 ).reset_index() print(user_features.describe())

逻辑说明:groupby("user_id").agg()是行为数据转用户画像的标准入口。lambda x: x.nunique()这里只是示意,实际要看你的字段含义——如果 event_type 是事件类型,nunique 统计的是事件种类数,不是活跃天数。活跃天数应该用时间戳字段的dt.date.nunique()。参数上,聚合后的列名建议用中文,方便后续和业务方沟通,但要注意编码问题。

5.2 用 Scikit-learn 做用户聚类与画像命名

聚合完特征,下一步是无监督聚类。常见做法是用 KMeans 把用户分成几群,再对每群的特征均值做排序,人工命名画像标签:

from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans # 选取用于聚类的特征列 feature_cols = ["点击次数", "平均停留", "最大停留"] X = user_features[feature_cols].fillna(0) # 标准化,消除量纲影响 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 聚成 4 类,具体几类看业务需要 kmeans = KMeans(n_clusters=4, random_state=42, n_init=10) user_features["cluster"] = kmeans.fit_predict(X_scaled) # 看每类的特征均值,用于命名 print(user_features.groupby("cluster")[feature_cols].mean().round(2))

逻辑说明:StandardScaler必须做,否则“点击次数”几千的量级会完全压制“平均停留”几十的量级。n_init=10让 KMeans 用不同初始点跑 10 次取最优,避免陷入局部最优。random_state=42保证结果可复现。聚类完看均值表,比如某一类点击次数高、停留短,可以命名为“高频浅层用户”;另一类点击少但停留长,叫“低频深度用户”。这就是用户画像从数据到标签的落地过程。

5.3 画像结果的可视化与导出

最后一步是把画像结果可视化并导出,方便写报告或对接下游。用 Seaborn 画个简单的散点图或箱线图:

import seaborn as sns import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False # 箱线图看各聚类在平均停留上的分布 plt.figure(figsize=(8, 5)) sns.boxplot(x="cluster", y="平均停留", data=user_features) plt.title("各用户群体的平均停留时长分布") plt.xlabel("用户群体编号") plt.ylabel("平均停留时长") plt.tight_layout() plt.savefig("./img/user_cluster_boxplot.png", dpi=150) plt.show() # 导出带画像标签的用户表 user_features.to_csv("./stormzudi/user_persona_output.csv", index=False, encoding="utf-8-sig")

逻辑说明:encoding="utf-8-sig"导出 CSV 时带 BOM 头,Excel 打开不会乱码,这是给业务方发文件的必备操作。dpi=150保证图片清晰度够放进 PPT。tight_layout()防止中文标签被截断。导出的user_persona_output.csv就是最终交付物,包含 user_id、各特征列、cluster 编号,下游可以直接用来做分层运营。

5.4 从 Notebook 到脚本:把画像流程固化下来

Notebook 适合探索,但每次手动跑 cell 效率低。我一般会在流程稳定后,把核心步骤抽成 Python 脚本,用python build_persona.py一键跑完。项目里那个 Python 源文件大概率就是干这个的。你可以照着 Notebook 的逻辑,把数据加载、清洗、聚合、聚类、导出串成一个main()函数,加上if __name__ == "__main__":入口。这样下次数据更新,只需要替换 CSV 文件,重新跑脚本就行,不用再打开 Notebook 逐个 cell 执行。参数方面,把n_clusters、feature_cols、文件路径这些提取成脚本开头的常量或命令行参数,改起来更方便。

从那以后我每次拿到新的用户行为数据,都强制先跑一遍缺失值审计和字段类型检查,再动手写画像逻辑。这套源码最大的价值不是代码本身多精妙,而是它把一条完整的分析链路摊开给你看,让你知道每一步该看什么、该改什么。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 2:43:13

机器学习算法Python源码包:从统计学习方法到可运行代码

简介&#xff1a;面向机器学习入门者的Python算法实现与理论笔记整理包&#xff0c;围绕《统计学习方法》梳理了概率统计中的总体/样本均值、方差、无偏估计、协方差矩阵等基础概念&#xff0c;并给出Apriori、决策树、HMM维特比、朴素贝叶斯、Logistic回归及三类线性回归&…

作者头像 李华
网站建设 2026/10/3 2:42:50

三只羊(富国街店)能做不辣的口味吗,专业程度如何

深夜的富国街&#xff0c;炭火的光映着一排排烧烤炉&#xff0c;肉串在火上翻动&#xff0c;油脂滴落激起细小的火苗&#xff0c;香气顺着街口飘出去很远。徐州人吃烧烤的习惯&#xff0c;是刻在骨子里的&#xff0c;而三只羊(富国街店)就在这条街上&#xff0c;用十年时间&…

作者头像 李华
网站建设 2026/10/3 2:42:48

东北GEO机构怎么选 吉林省焕腾科技有限公司服务不错的专业推荐

东北GEO机构怎么选?吉林省焕腾科技有限公司&#xff1a;AI搜索时代值得了解的专业服务商当用户开始习惯直接问豆包吉林哪家企业靠谱、问DeepSeek东北哪家服务商口碑好时&#xff0c;企业获客的主战场已经从传统搜索引擎转移到AI平台。吉林省焕腾科技有限公司正是瞄准这一趋势&…

作者头像 李华
网站建设 2026/10/3 2:42:14

性能第一价格腰斩的顶级模型刚发布,普通人掏钱却用不上

性能第一价格腰斩的顶级模型刚发布&#xff0c;普通人掏钱却用不上 如果有人告诉你&#xff0c;一家科技巨头刚造出了全球最顶尖的超级人工智能&#xff0c;不仅在多项权威考试里拿了第一&#xff0c;价格还直接腰斩&#xff0c;但你现在哪怕掏钱也根本用不上&#xff0c;你大概…

作者头像 李华
网站建设 2026/10/3 2:41:31

ros2_control与Gazebo仿真配置避坑指南:URDF/控制器/launch对齐详解

1. 写在前面&#xff1a;为什么ros2_control与Gazebo这对组合最容易埋坑搞机器人仿真这两年&#xff0c;我见过最多的求助帖就是“ros2_control加载不上控制器”“Gazebo里模型乱跳”“joint_state一直没数据”。我自己也在这些坑里滚过好多遍&#xff0c;后来才慢慢摸清楚&…

作者头像 李华
网站建设 2026/10/3 2:41:23

武汉实力强的汽车发动机维修专业公司案例实力盘点

最近在武汉&#xff0c;搜汽车发动机维修专业机构发动机烧机油免拆治理发动机异响抖动维修哪家靠谱的车主明显多了起来。车越跑越多&#xff0c;车龄五年以上的家用车、天天在路上跑的网约车&#xff0c;发动机或多或少都会出状况&#xff1a;烧机油、怠速抖动、加速无力、异响…

作者头像 李华