资讯详情 Python数据分析实战:配套数据集加载、清洗与避坑指南
📅 2026/10/30 6:56:28
简介这份资源是《Python for Data Analysis, 2nd Edition》配套数据集面向正在学习或实践Python数据分析的读者尤其适合配合Wes McKinney原书做动手练习解决从数据导入、清洗到建模分析缺少真实样例数据的问题。压缩包共209个文件约40.36MB以txt说明与数据文件、csv表格、ipynb笔记本为主另含少量py脚本、json、pkl、xlsx及shp、dbf等地理数据文件覆盖书中示例与练习所需素材。已有350人学习下载。数据集涵盖股票行情、Haiti地震、volume、train/test等典型场景可直接用于Pandas的Series与DataFrame操作、缺失值处理、合并分组、时间序列分析及Matplotlib可视化练习帮助读者把书中知识点落到真实数据上提升数据清洗与探索性分析能力。1. 数据分析入门绕不开的那本书配套数据集到底怎么用很多人学 Python 数据分析卡住的地方不是语法而是拿到一份 CSV 之后不知道下一步该干什么。教材翻了几章pandas的 API 也认得几个可一上手真实数据就懵列名带空格、日期是字符串、缺失值藏在奇怪的位置。这种“看得懂代码、跑不通流程”的状态恰恰是缺少一套结构清晰、覆盖完整的数据集来练手造成的。Python for Data Analysis 第 2 版配套的那批数据集就是为这个场景准备的——它把 read_csv、groupby、时间序列、缺失值处理这些知识点全部挂在了真实可跑的数据文件上。这套东西适合谁适合已经会写 Python 基础语法、想系统过一遍数据分析全流程的人也适合带新人时找一套“有标准答案”的练习素材。下面我按自己复现这套数据集的路径把目录结构、加载方式、清洗套路和踩过的坑讲清楚。2. 数据集目录结构与加载路径先搞清楚文件都长什么样2.1 这批数据集里到底有哪些文件类型这套配套数据不是单一 CSV 集合而是刻意混了多种格式目的是让你在练pandas的同时把 IO 这一层也过一遍。常见的有这几类文件类型典型用途加载函数注意点.csv表格数据主力如电影评分、婴儿姓名pd.read_csv编码、分隔符、缺失值标记.txt制表符或竖线分隔的日志类数据pd.read_csv(sep...)分隔符必须显式指定.xlsx/.xls多 sheet 的报表数据pd.read_excel需要 openpyxl/xlrd.json嵌套结构的记录pd.read_json或json.load嵌套层级要手动展平.hdf5大数据集的二进制存储pd.read_hdf需要 tables 依赖.dta统计软件导出的数据pd.read_stata列类型可能被推断错我一般会先写一个扫描脚本把目录下所有文件的扩展名、大小、前几行打出来而不是凭记忆去猜哪个文件对应哪一章。这一步花五分钟后面能省半小时的“文件找不到”排查。import os import pandas as pd DATA_DIR ./pydata-book/datasets # 换成你自己的数据集根目录 for root, dirs, files in os.walk(DATA_DIR): for f in files: path os.path.join(root, f) size_kb os.path.getsize(path) / 1024 print(f{path:60s} {size_kb:8.1f} KB)这段代码的逻辑很直白递归遍历目录打印相对路径和文件大小。参数上唯一要改的是DATA_DIR指向你解压后的数据集根目录。跑完之后你会对“哪些文件大、哪些是辅助文件”有个整体印象比如某些.csv只有几十 KB那是教学用小样本有些.hdf5上百 MB那是用来练分块读取的。2.2 用 read_csv 加载时的四个必调参数直接pd.read_csv(xxx.csv)能跑通是运气跑不通才是常态。我一般固定带上这四个参数能挡掉大部分翻车df pd.read_csv( some_data.csv, sep,, # 分隔符txt 类文件常是 \t 或 | encodingutf-8, # 中文或特殊字符报 UnicodeDecodeError 时换 latin1 试 na_values[NA, null, -, ], # 显式声明缺失值标记 parse_dates[date_column] # 提前把日期列解析成 datetime )sep不写默认是逗号但日志类.txt经常是制表符不指定就会把整行读成一列。encoding是最常见的报错来源UnicodeDecodeError一出现先怀疑编码utf-8不行就试latin1或gbk。na_values的作用是把各种“伪缺失”统一成NaN否则groupby的时候这些字符串会混进统计里。parse_dates提前解析日期列比读进来再pd.to_datetime少一步而且能让后续的时间序列操作直接可用。提示parse_dates只对格式规范的日期字符串有效遇到2020/1/1和01-01-2020混排的列先读成字符串再手动转换更稳。2.3 相对路径与工作目录的坑数据集加载失败十次里有三次是路径问题。Jupyter 的工作目录是 notebook 所在目录而脚本的工作目录是执行命令时所在的目录两者经常不一致。我的习惯是在脚本开头打印一次os.getcwd()确认当前在哪再用相对于项目根目录的路径。如果数据集和代码不在同一层用pathlib拼绝对路径比手写../..可靠from pathlib import Path BASE Path(__file__).resolve().parent # 脚本所在目录 DATA BASE / datasets / some_data.csv df pd.read_csv(DATA)Path(__file__).resolve().parent拿到的是脚本文件的绝对父目录不管从哪里执行都不会错。这个写法在 notebook 里不适用没有__file__notebook 里就用Path.cwd()往上找。搞清楚这一点后面所有加载代码都能复用同一套路径逻辑。3. 数据清洗的标准流程从原始文件到可分析表3.1 先看结构再看内容info 和 describe 的分工拿到一个 DataFrame别急着head()。我一般先跑df.info()看列数、非空计数和 dtype再跑df.describe()看数值列的分布。这两个的输出回答的是不同问题info告诉你“数据完整不完整、类型对不对”describe告诉你“数值合不合理、有没有离谱的极值”。df.info() # 关注每列非空数量是否等于总行数object 类型的列是否本该是数值或日期 df.describe(includeall) # includeall 让 object 列也参与统计能看到唯一值数量和众数info里如果某列非空数明显少于总行数说明缺失严重要决定是删列还是填充。describe里如果min或max离均值差好几个数量级先怀疑单位不统一或录入错误。这一步不写代码逻辑纯粹是观察但决定了后面清洗策略的方向。3.2 缺失值处理的三种策略与选择依据缺失值不是一律dropna或一律fillna要看缺失比例和列的用途。我的判断顺序是缺失超过 60% 且不是关键列直接删缺失在 5% 到 60% 之间按列类型填充缺失低于 5%可以删行也可以填充看样本量够不够。# 统计每列缺失比例 missing_ratio df.isnull().mean().sort_values(ascendingFalse) print(missing_ratio[missing_ratio 0]) # 数值列用中位数填充比均值抗极值 num_cols df.select_dtypes(includenumber).columns df[num_cols] df[num_cols].fillna(df[num_cols].median()) # 类别列用众数填充 cat_cols df.select_dtypes(includeobject).columns for c in cat_cols: df[c] df[c].fillna(df[c].mode()[0])isnull().mean()算的是缺失比例比isnull().sum()更直观因为你能直接看出百分比。数值列选中位数而不是均值是因为中位数对极端值不敏感填充后不会把分布拉偏。类别列用众数填充有个前提该列的众数确实有代表性如果众数占比不到 30%填充等于引入噪声这时候宁可保留NaN或单独标一个“未知”类别。3.3 类型转换与重复值去重类型不对是groupby和绘图报错的常见根源。数值列被读成object多半是因为混进了1,234这种带千分位的字符串或者有unknown之类的占位符。处理方式是先pd.to_numeric(errorscoerce)强制转换转不了的变NaN再回头决定怎么处理这些NaN。df[price] pd.to_numeric( df[price].astype(str).str.replace(,, ), errorscoerce ) # 去重前先确认重复的判定口径 dup_count df.duplicated(subset[id], keepFalse).sum() print(f按 id 判定的重复行数{dup_count}) df df.drop_duplicates(subset[id], keepfirst)str.replace(,, )去掉千分位errorscoerce让无法转换的值变成NaN而不是抛异常这样你能一次性看到所有问题值。duplicated(subset[id])指定按业务主键判重比全列比对更符合实际——两行所有字段都一样才算重复往往漏掉“同一 id 多条记录”的情况。keepfirst保留第一条如果业务上应该保留最新一条就先按时间排序再keeplast。3.4 用 groupby 做第一轮聚合验证清洗完别急着往下分析先做一轮聚合验证数据是否“讲得通”。比如按类别分组算均值、计数看结果是否符合常识。这一步能抓出单位错误、编码错误、分组键选错等问题。summary ( df.groupby(category, dropnaFalse) .agg( count(id, count), avg_price(price, mean), max_price(price, max) ) .sort_values(count, ascendingFalse) ) print(summary.head(10))dropnaFalse让NaN分组也出现在结果里避免“明明有数据但分组后消失了”的困惑。agg里用字典形式给每个聚合起名字输出表头清晰。sort_values(count)按样本量排序能快速看出哪些类别样本太少、后续分析要不要合并。如果某个类别的avg_price是另一个的几十倍先别下结论回去查这一类的原始记录大概率是单位或录入问题。4. 时间序列与多表关联数据集里最容易翻车的两块4.1 日期解析失败的四种典型原因时间序列分析的前提是日期列真的是datetime类型。pd.to_datetime报错或静默产生NaT常见原因有四种格式不统一、带时区后缀、有非法日期如 2 月 30 日、混入了非日期字符串。我的处理套路是先errorscoerce转一遍统计NaT数量再抽样看这些失败的值长什么样。raw df[order_date].astype(str) parsed pd.to_datetime(raw, errorscoerce, formatmixed) bad df.loc[parsed.isna(), order_date].unique()[:20] print(解析失败的样本, bad) print(失败比例, parsed.isna().mean())formatmixed让 pandas 逐行推断格式适合格式不统一的列但速度比指定固定格式慢。先看失败样本再决定是清洗还是丢弃比盲目dropna稳妥。如果失败比例低于 1% 且这些行不影响主分析直接删如果比例高就得写针对性的替换规则。4.2 merge 的四种连接方式与键的选择多表关联翻车八成是键选错或连接方式选错。merge的how参数有inner、left、right、outer四种默认inner只保留两表都有的键容易“莫名其妙少了很多行”。merged pd.merge( orders, customers, oncustomer_id, howleft, validatemany_to_one, indicatorTrue ) print(merged[_merge].value_counts())howleft保留左表全部行右表匹配不上就填NaN这是最常用的方式。validatemany_to_one会在右表键不唯一时直接报错帮你提前发现“一对多被误当成一对一”的问题。indicatorTrue加一列_merge值有both、left_only、right_only跑完看一眼value_counts()就知道匹配率如何。如果left_only占比很高说明键的取值对不上可能是格式差异带空格、大小写或编码不同。4.3 时间序列重采样的频率参数怎么设resample的频率参数写错结果会静默出错而不是报错。常用的是D日、W周、M月、Q季、Y年但要注意M是月末MS是月初两者结果差一个月。ts df.set_index(order_date)[amount] monthly ts.resample(MS).sum() # 月初为锚点 weekly ts.resample(W-MON).sum() # 每周一为锚点MS和M的区别是血泪经验用M做月度汇总时间戳会落在月末和业务上“按月统计”的口径对不上时很难排查。W-MON指定周一为周锚点不写的话默认周日。重采样前确保索引是datetime且已排序否则结果顺序会乱。5. 避坑与排查这套数据集练手时最容易踩的五个坑5.1 编码报错反复出现现象read_csv抛UnicodeDecodeError: utf-8 codec cant decode byte...。原因文件不是 UTF-8 编码可能是latin1或gbk。解决先试encodinglatin1它能解码任意字节不报错读进来后看有没有乱码如果乱码集中在中文列换gbk。不要盲目errorsignore那会静默丢字符。5.2 数值列被读成 object现象df[price].mean()报TypeError或describe里这列只显示count、unique。原因列里混了非数值字符千分位、货币符号、N/A。解决先astype(str).str.replace清掉符号再pd.to_numeric(errorscoerce)最后统计NaN比例决定填充还是删行。5.3 groupby 之后行数对不上现象分组后某些类别消失了。原因分组键含NaN默认被丢弃。解决groupby(..., dropnaFalse)。另一个原因是分组前做了dropna()把整行删了回去检查清洗步骤的顺序。5.4 merge 后数据量暴增现象两表各几千行merge 完变成几十万行。原因连接键在某一侧不唯一形成笛卡尔积。解决merge 前对键做value_counts()检查唯一性加validateone_to_one或many_to_one让 pandas 帮你拦截。5.5 时间序列重采样结果为空现象resample(M).sum()返回空或全NaN。原因索引不是datetime类型或者没排序。解决df.index pd.to_datetime(df.index)后df df.sort_index()再重采样。排序这一步经常被忘不排序时resample行为不确定。6. 进阶技巧把数据集变成可复用的练习模板练完一遍就丢等于白练。我的习惯是把这套数据集的加载和清洗逻辑抽成一个可复用的小模块下次换数据只改配置不改结构。核心思路是把“路径、分隔符、编码、日期列、缺失标记”这些易变项放进一个字典加载函数读配置干活。import pandas as pd from pathlib import Path CONFIGS { orders: { file: orders.csv, sep: ,, encoding: utf-8, parse_dates: [order_date], na_values: [NA, ], }, customers: { file: customers.txt, sep: \t, encoding: latin1, parse_dates: [], na_values: [null], }, } def load_dataset(name, base_dir./datasets): cfg CONFIGS[name].copy() path Path(base_dir) / cfg.pop(file) return pd.read_csv(path, **cfg) orders load_dataset(orders) customers load_dataset(customers)这个模板的价值在于新增数据集只加一条配置加载逻辑不用动参数集中在一处排查时一眼能看到某个文件用了什么编码和分隔符。cfg.pop(file)把文件名从参数字典里摘出来单独拼路径剩下的键正好是read_csv的关键字参数直接**cfg展开。这种写法在数据集文件多、格式杂的场景下特别省事。验证清洗结果是否可靠我一般用两个交叉检查一是聚合后的总数和原始行数对得上没意外丢行二是关键数值列的describe在清洗前后分布没有剧烈偏移填充没引入偏差。这两条过了再往下做分析和建模才踏实。最后说个我自己的习惯每练完一个数据集把踩过的坑和对应的解决命令记在一个notes.md里按“现象 → 原因 → 命令”三列记。下次遇到同类报错翻笔记比搜引擎快得多。这套数据集真正的价值不在文件本身而在于它逼你把 IO、清洗、聚合、时间序列这几条链路都走一遍走完一遍再走第二遍速度会快很多。希望帮到你。本文还有配套的精品资源点击获取