查看全课大纲(第 41 / 45 节)
- 1.课程简介
- 2.环境搭建
- 3.预备知识
- 4.pyecharts初体验
- 5.数据可视化概述
- 6.数据可视化的目标和作用
- 7.数据可视化工具对比分析
- 8.数据可视化基本流程
- 9.数据可视化设计原则
- 10.pyecharts简介
- 11.官方图表样例
- 12.常用图表的基本结构
- 13.数据格式
- 14.图表的分类
- 15.柱状图与条形图
- 16.其他对比图表
- 17.常用配置项(一)
- 18.常用配置项(二)
- 19.折线图 面积图
- 20.K线图
- 21.其他时间图表
- 22.常用配置项
- 23.散点图 气泡图
- 24.热力图
- 25.其他相关性图表
- 26.饼图
- 27.矩形树图
- 28.其他成分比例图表
- 29.箱型图与直方图
- 30.3D柱状图与折线图
- 31.其他统计图表
- 32.地图 Map
- 33.地理坐标系Geo
- 34.3D 地图
- 35.网络关系图
- 36.主题河流图
- 37.词云图
- 38.组合图表组件
- 39.仪表盘相关图表
- 40.项目介绍
- 41.数据准备
- 42.子图制作(一)
- 43.子图制作(二)
- 44.数据大屏制作
- 45.项目总结
数据准备
数据准备:从原始数据到干净数据集
小象实战讲义 · ECharts 数据可视化
欢迎来到《综合项目:电商用户行为数据可视化分析》的数据准备环节。在上一节,我们了解了项目的整体背景和目标。本节,我们将直面一个真实项目中至关重要的第一步:数据准备。你将学习如何将一个庞大、原始的电商数据集,通过数据清洗与处理,转变为一份干净、结构清晰、可直接用于后续可视化分析的数据集。这是构建任何可靠数据图表的基础,也是数据分析师和可视化工程师的核心技能。
💡 核心导读
- 认识数据集:了解淘宝用户行为数据集的来源、规模、字段含义及数据脱敏概念。
- 掌握数据清洗:学习使用 pandas 检查并处理重复记录、缺失值,以及删除无关字段。
- 进行数据处理:通过映射添加描述列、拆分并转换时间字段、按需排序数据,使数据更易于理解和分析。
- 保存工作成果:将清洗处理后的干净数据集保存为新文件,为后续的可视化分析提供高效的数据源。
一、 项目数据集说明
我们本次项目使用的数据集来源于淘宝 APP 的真实用户行为日志,经过脱敏处理,以保护用户隐私。脱敏是指对数据中的敏感信息(如真实用户ID、地理位置等)进行技术处理,使其无法关联到具体个人,同时保留数据的分析价值。
该数据集规模较大,包含约 1225万条 记录,原始 CSV 文件大小超过 500MB。对于如此规模的数据,传统的 Excel 等工具难以有效处理,我们必须使用 Python 的 pandas 库在内存中进行操作。这要求你的计算机内存至少在 4GB 以上,对于本数据集而言是足够的。若数据量达到 TB 级别,则需考虑分布式计算框架,这超出了本课程的范畴。
数据集记录了 2018年11月18日至2018年12月18日 期间的用户行为,共包含 6个字段:
| 字段名 | 说明 |
|---|---|
user_id | 用户ID(已脱敏) |
item_id | 商品ID(已脱敏) |
behavior_type | 用户行为类型,用数字1-4表示:1-点击,2-收藏,3-加入购物车,4-支付 |
user_geohash | 用户地理位置哈希值(部分记录为空) |
item_category | 商品品类ID |
time | 用户行为发生的时间,格式为 日期 小时(如 2018-11-25 00) |
拿到数据后,我们的首要任务不是直接绘图,而是进行数据预览、清洗与处理,确保数据的质量和可用性。
二、 数据清洗:去除杂质,保留精华
数据清洗的目标是发现并修正数据集中的错误、不一致和冗余,通常包括删除重复记录、处理缺失值、删除无用列等。让我们开始动手操作。
首先,导入必要的库并加载数据。
import pandas as pd
data_df = pd.DataFrame([
[1001, 2001, 1, None, 301, "2018-11-25 00"],
[1001, 2001, 1, None, 301, "2018-11-25 00"],
[1001, 2002, 2, "9q", 302, "2018-11-25 08"],
[1002, 2003, 3, "8x", 303, "2018-11-26 12"],
[1002, 2003, 4, "8x", 303, "2018-11-26 18"],
], columns=["user_id", "item_id", "behavior_type", "user_geohash", "item_category", "time"])
print("原始数据行数:", len(data_df))
data_df = data_df.drop_duplicates().reset_index(drop=True)
data_df = data_df.drop(columns=["user_geohash"])
data_df["behavior_desc"] = data_df["behavior_type"].map({1: "点击", 2: "收藏", 3: "加入购物车", 4: "支付"})
data_df[["date_str", "hour_str"]] = data_df["time"].str.split(" ", expand=True)
data_df["date"] = pd.to_datetime(data_df["date_str"])
data_df["hour"] = data_df["hour_str"].astype(int)
data_df = data_df.drop(columns=["date_str", "hour_str"])
data_df["weekday"] = data_df["date"].dt.weekday
print("去重后行数:", len(data_df))
print(data_df[["user_id", "behavior_desc", "date", "hour"]].to_string(index=False))
print(data_df["behavior_desc"].value_counts().sort_index().to_string())原始数据行数: 5
去重后行数: 4
user_id behavior_desc date hour
1001 点击 2018-11-25 0
1001 收藏 2018-11-25 8
1002 加入购物车 2018-11-26 12
1002 支付 2018-11-26 18
behavior_desc
加入购物车 1
支付 1
收藏 1
点击 1加载完成后,我们先预览一下数据的前几行,对数据结构有一个直观的认识。
# 预览数据前5行
print(data_df.head()) user_id item_id behavior_type user_geohash item_category time
0 323862 286245 1 NaN 4076 2018-11-25 00
1 323862 286245 1 NaN 4076 2018-11-25 00
2 323862 286245 1 NaN 4076 2018-11-25 00
3 323862 286245 1 NaN 4076 2018-11-25 00
4 323862 286245 1 NaN 4076 2018-11-25 00可以看到,user_geohash 列存在 NaN(空值)。接着,我们查看数据的整体信息,包括行数、列数、数据类型和内存使用情况。
# 查看数据集基本信息
print(data_df.info())<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12256906 entries, 0 to 12256905
Data columns (total 6 columns):
# Column Dtype
--- ------ -----
0 user_id int64
1 item_id int64
2 behavior_type int64
3 user_geohash object
4 item_category int64
5 time object
dtypes: int64(4), object(2)
memory usage: 561.0+ MB信息显示,数据集有超过1225万条记录,6列。time 列目前是对象(字符串)类型,user_geohash 也是对象类型且包含空值。
清洗步骤1:检查并删除重复记录 重复记录会扭曲分析结果。我们检查并删除完全相同的行。
# 检查重复记录数量
duplicate_count = data_df.duplicated().sum()
print(f"数据集中的重复记录数为:{duplicate_count}")
# 删除重复记录,直接在原数据框上修改
data_df.drop_duplicates(inplace=True)
print(f"删除重复记录后,数据形状为:{data_df.shape}")数据集中的重复记录数为:4092866
删除重复记录后,数据形状为:(8164040, 6)成功删除了约409.3万条重复记录,数据量降至约816.4万条。
清洗步骤2:删除无用列 本项目不涉及地理位置分析,且 user_geohash 列存在大量空值,因此将其删除。
# 删除 user_geohash 列
data_df.drop(columns=['user_geohash'], inplace=True)
print(f"删除无用列后,数据形状为:{data_df.shape}")删除无用列后,数据形状为:(8164040, 5)清洗步骤3:检查缺失值 检查剩余列中是否还有缺失值。
# 检查各列缺失值数量
print(data_df.isnull().sum())user_id 0
item_id 0
behavior_type 0
item_category 0
time 0
dtypes: int64很好,剩余字段均无缺失值。至此,数据清洗的主要工作已完成。我们预览一下清洗后的数据。
print(data_df.head()) user_id item_id behavior_type item_category time
0 323862 286245 1 4076 2018-11-25 00
1 323862 286245 1 4076 2018-11-25 00
2 323862 286245 1 4076 2018-11-25 00
3 323862 286245 1 4076 2018-11-25 00
4 323862 286245 1 4076 2018-11-25 00三、 数据处理:优化结构,赋能分析
数据处理是在清洗的基础上,对数据进行转换、衍生和重构,使其更符合分析需求。主要包括添加辅助信息、更改数据类型和排序。
处理步骤1:添加行为类型描述列 behavior_type 列用数字1-4表示行为,不直观。我们添加一个文本描述列。
# 定义行为类型映射字典
behavior_type_dict = {
1: '点击',
2: '收藏',
3: '加入购物车',
4: '支付'
}
# 使用 map 方法添加新列
data_df['behavior_desc'] = data_df['behavior_type'].map(behavior_type_dict)
print(data_df[['behavior_type', 'behavior_desc']].head()) behavior_type behavior_desc
0 1 点击
1 1 点击
2 1 点击
3 1 点击
4 1 点击处理步骤2:拆分并转换时间字段 原始 time 列是“日期 小时”的字符串格式。我们将其拆分为 date(日期)和 hour(小时)两列,并转换为合适的数据类型。
# 拆分 time 列
data_df[['date_str', 'hour_str']] = data_df['time'].str.split(' ', expand=True)
# 转换数据类型
data_df['date'] = pd.to_datetime(data_df['date_str']) # 转换为 datetime 类型
data_df['hour'] = data_df['hour_str'].astype('int') # 转换为整数类型
# 删除临时的拆分字符串列
data_df.drop(columns=['date_str', 'hour_str'], inplace=True)
print(data_df[['time', 'date', 'hour']].head())
print("\n数据类型信息:")
print(data_df[['date', 'hour']].dtypes) time date hour
0 2018-11-25 00 2018-11-25 0
1 2018-11-25 00 2018-11-25 0
2 2018-11-25 00 2018-11-25 0
3 2018-11-25 00 2018-11-25 0
4 2018-11-25 00 2018-11-25 0
数据类型信息:
date datetime64[ns]
hour int64
dtypes: object将 date 转换为 datetime 类型后,我们可以方便地进行日期相关的计算和比较,例如验证数据的时间范围。
# 验证数据时间范围
print(f"数据记录的最早日期:{data_df['date'].min()}")
print(f"数据记录的最晚日期:{data_df['date'].max()}")数据记录的最早日期:2018-11-18 00:00:00
数据记录的最晚日期:2018-12-18 00:00:00这与数据说明中的时间段完全吻合。
处理步骤3:按时间排序 为了使数据在后续分析(如时间序列分析)中更有序,我们按日期和小时进行排序。
# 按日期和小时升序排序
data_df = data_df.sort_values(by=['date', 'hour'])
print(data_df[['date', 'hour', 'user_id', 'behavior_desc']].head(10)) date hour user_id behavior_desc
8164039 2018-11-18 0 279598 点击
8164038 2018-11-18 0 279598 点击
8164037 2018-11-18 0 279598 点击
8164036 2018-11-18 0 279598 点击
8164035 2018-11-18 0 279598 点击
8164034 2018-11-18 0 279598 点击
8164033 2018-11-18 0 279598 点击
8164032 2018-11-18 0 279598 点击
8164031 2018-11-18 0 279598 点击
8164030 2018-11-18 0 279598 点击可以看到,在同一个时间点(2018-11-18 00时),有大量来自不同用户(此处显示为同一用户,是因为我们只看了前10行,实际有大量用户)的行为发生。
四、 保存干净数据集
经过清洗和处理,我们得到了一份干净、结构清晰的数据集。为了在后续课程中无需重复这些步骤,我们将它保存为一个新的 CSV 文件。
# 保存清洗处理后的数据集
output_path = './cln_proj_dataset.csv'
data_df.to_csv(output_path, index=False, encoding='utf-8')
print(f"干净数据集已保存至:{output_path}")
print(f"最终数据形状:{data_df.shape}")干净数据集已保存至:./cln_proj_dataset.csv
最终数据形状:(8164040, 8)最终数据集包含约816.4万条记录、8个字段:user_id、item_id、behavior_type、item_category、time、behavior_desc、date、hour。其中删除 user_geohash 后由6列变为5列,新增 behavior_desc 后变为6列,再由 time 衍生 date 和 hour 并删除临时拆分列,最终为8列。
📝 动手练一练
- 数据验证:在删除
user_geohash列之前,如果我们想先查看该列非空(非NaN)的记录有多少条,该如何编写代码?请写出代码并给出结果(提示:使用notna()方法)。
点击查看参考答案
# 查看 user_geohash 列非空记录数
non_null_geo_count = data_df['user_geohash'].notna().sum()
print(f"user_geohash 列非空记录数为:{non_null_geo_count}")(注意:此代码需在删除 user_geohash 列之前执行。根据原始数据情况,非空记录数是一个固定值,例如可能为 2000000。)
- 数据衍生:除了按日期和小时排序,有时我们还需要按“周几”进行分析。请尝试从
date列中衍生出一个新的列weekday,表示星期几(0为周一,6为周日),并查看前10条数据中,星期一的记录有多少条。
点击查看参考答案
# 衍生 weekday 列
data_df['weekday'] = data_df['date'].dt.weekday # 注意:在较新pandas版本中,weekday属性返回0-6(周一到周日)
# 查看前10条数据中星期一的记录数 (weekday == 0)
monday_count_in_first_10 = (data_df.head(10)['weekday'] == 0).sum()
print(f"前10条数据中,星期一的记录有 {monday_count_in_first_10} 条。")
# 也可以查看整个数据集中各星期的分布(可选)
print("\n整个数据集中各星期记录数:")
print(data_df['weekday'].value_counts().sort_index())本章小结
本节我们完成了综合项目中至关重要的一步——数据准备。我们不仅学习了如何处理一个真实、大规模的数据集,更掌握了数据工作的标准流程:认识数据 → 清洗数据 → 处理数据 → 保存成果。这份干净的 cln_proj_dataset.csv 文件,将成为我们后续所有可视化图表的坚实数据基础。
📋 行动清单
- 理解数据清洗三要素:能清晰说出检查重复值、缺失值和无用列的具体方法及其在 pandas 中的实现函数(
duplicated(),isnull(),drop())。 - 掌握数据处理关键操作:能够使用
map()方法为分类数据添加描述,使用str.split()和pd.to_datetime()正确处理时间字符串,并理解按多列排序的意义。 - 养成保存中间成果的习惯:在完成重要数据处理阶段后,及时将干净数据保存为独立文件,提升后续分析效率。
—— 小象教研组