
简介面向高职与本科院校大数据相关专业学生也适合转行数据分析的自学者这份实操数据包聚焦数据清洗环节覆盖缺失值处理、异常值检测、格式统一、重复值剔除等常见预处理场景。压缩包共含11个文件包括3个数据库脚本、2个逗号分隔表格、2个文本文档、2个Excel电子表格、1个JSON数据文件和1个XML数据文件整体体积仅96KB便于下载和课堂分发。已有528人学习下载适合教学演示与自主训练。借助这套多格式数据源读者可配合Python的Pandas库、数据库查询或ETL工具完整经历从原始数据导入、清洗到输出可用数据集的流程理解不同文件格式下的编码问题、缺失值填充与一致性检查要点并体会数据质量对后续分析结论的影响。同时多类型数据还能用于模拟异构数据合并、清洗规则编写与效果验证等实战任务为真实项目中的数据预处理奠定扎实基础。1. 拿到“数据清洗数据源.zip”之后先别急着解压做数据分析这行隔三差五就会收到这样的压缩包名字叫“数据清洗数据源.zip”里面可能是几个CSV、Excel文件也可能夹着JSON、TXT甚至还有子文件夹。刚入职那会儿我也踩过坑拿到压缩包直接双击解压然后拖进编辑器就开始跑结果数据量一大直接内存爆炸字段类型全乱套日期格式五花八门中文字段名乱码……光清洗就花了三天。实际上“数据清洗数据源.zip”这个标题背后藏着一个典型的数据处理场景你拿到的是一个多文件、多格式、需要统一处理的原始数据集第一步不是写清洗逻辑而是先把“数据源”这层皮扒干净。也就是要做好解压、文件结构摸底、编码识别、字段探查这几件基础工作后面再谈清洗。这篇文章按我自己的实操路径来写适用场景是本地或邮件收到一个zip压缩包里面是多张表需要合并清洗后输出给下游分析或建模。涉及的核心工具是Python的pandas加标准库zipfile也会穿插一些命令行技巧。2. 解压与数据源摸底这一步做得好后面省一半事2.1 用Python解压而不是双击双击解压当然方便但在数据工程场景里我建议用脚本解压原因有三个可复现下次拿到同样结构的压缩包跑一遍脚本就行。可处理异常比如压缩包损坏、编码异常、密码保护等脚本里能捕获。可自动登记解压后直接生成文件清单方便后续做数据字典。zipfile是Python标准库不需要额外安装。基础用法如下import zipfile from pathlib import Path zip_path Path(数据清洗数据源.zip) extract_dir Path(./data_raw) extract_dir.mkdir(exist_okTrue) with zipfile.ZipFile(zip_path, r) as zf: # 先打印压缩包里的文件清单 for info in zf.infolist(): print(f{info.filename} | 原始大小: {info.file_size} | 压缩后: {info.compress_size}) zf.extractall(extract_dir)这里有个细节直接用extractall()解压如果压缩包里文件名包含中文在部分Windows系统上会出现乱码。原因在于zipfile库默认用cp437编码解析文件名而中文Windows环境下很多压缩包是用GBK编码写入的。解决办法是手动重命名import zipfile with zipfile.ZipFile(zip_path, r) as zf: for info in zf.infolist(): # 尝试用gbk解码文件名失败则保持原样 try: decoded_name info.filename.encode(cp437).decode(gbk) except (UnicodeDecodeError, UnicodeEncodeError): decoded_name info.filename zf.extract(info, extract_dir) # 如果解码后的名字和原始名字不同重命名文件 if decoded_name ! info.filename: (Path(extract_dir) / info.filename).rename(Path(extract_dir) / decoded_name)注意以上重命名写法要求文件在压缩包内是平铺的如果有嵌套目录需要先拼接完整路径再做rename。更稳妥的做法是遍历zf.infolist()对每个entry构建目标路径后再移动。2.2 用命令行unzip快速摸底如果你在Linux服务器或macOS终端上操作unzip -l这个命令我几乎每次都用它在不真正解压文件的情况下列出压缩包内容效率极高unzip -l 数据清洗数据源.zip输出类似Archive: 数据清洗数据源.zip Length Date Time Name --------- ---------- ----- ---- 1024 2024-01-15 09:30 order_202401.csv 2048 2024-01-15 09:31 user_info.xlsx 512 2024-01-15 09:32 readme.txt通过这个清单你能快速判断有几张表、什么格式、大概多大。如果发现里面有readme.txt或数据字典.docx这类文件先读它往往比你自己猜字段含义高效得多。2.3 压缩包损坏先排查再干别的如果你解压时遇到invalid zip archive: could not find eocd这类报错先别急着怀疑代码。这个错误的意思是“找不到中央目录结束标记End of Central Directory”常见原因有两个文件下载不完整zip文件被截断了。文件本身不是zip格式只是扩展名改了。排查方式file 数据清洗数据源.zip如果输出显示Zip archive data说明格式没问题如果显示data或HTML document说明文件就不是zip硬解压肯定失败。另外也可以用unzip -t测试压缩包完整性unzip -t 数据清洗数据源.zip输出末尾如果显示No errors detected in compressed data of 数据清洗数据源.zip说明文件完整。3. 读数据别一把梭多源格式的读取策略3.1 先看扩展名再选读取函数解压完之后你手里可能是这样一个文件集合文件格式预计用途order_202401.csvCSV订单表user_info.xlsxExcel用户信息表product_detail.jsonJSON商品明细readme.txt文本字段说明pandas提供了read_csv、read_excel、read_json等函数分别对应不同格式但实际工作中最常见、也最容易出问题的是CSV。我见过太多人在read_csv上栽跟头核心原因就两个分隔符不对和编码不对。import pandas as pd # 读取CSV时建议显式指定编码和分隔符 df_order pd.read_csv( data_raw/order_202401.csv, encodingutf-8-sig, # 带BOM的utf-8也能读 sep,, dtype{order_id: str}, # 防止订单号被读成科学计数法 )encodingutf-8-sig比encodingutf-8多一个好处它能自动处理带BOM头的文件。如果你不确定文件编码推荐用chardet或charset-normalizer检测一下from charset_normalizer import from_path result from_path(data_raw/order_202401.csv).best() print(result.encoding)Excel文件的读取相对省心但要注意.xls和.xlsx的差异——read_excel底层依赖openpyxl针对.xlsx和xlrd针对.xls新版本xlrd只支持.xls不支持.xlsx如果环境里没装对应的库读取会直接报错。建议提前安装好依赖pip install pandas openpyxl xlrd3.2 字段类型推断pandas的“好心”有时候是帮倒忙pandas读取数据时会自动推断字段类型这看起来很方便但实际使用中坑很多。举个例子订单号如果只有数字组成且超过15位pandas会自动读成int64后面做字符串匹配时就容易出问题如果没有数据超过15位但字段本身应该保留前导零如“00123”pandas会直接去掉前导零。所以在读取阶段就统一指定dtype是一门必修课。我通常是这样处理的dtype_mapping { order_id: str, user_id: str, product_id: str, amount: float, quantity: int, } df pd.read_csv(data_raw/order_202401.csv, dtypedtype_mapping)注意如果你指定了dtype为str但原字段里有空值pandas读出来的空值会变成NaNfloat类型而不是None或空字符串。这一点在后续清洗时要特别留意。3.3 多数据源的表结构对齐如果压缩包里的多张表需要合并强烈建议先打印每个表的columns和dtypes形成一张“字段对比表”。别急着merge先确认哪些字段是公共键、哪些字段同名不同义、哪些字段同义不同名。for name, df in [(order, df_order), (user, df_user)]: print(f {name} ) print(df.columns.tolist()) print(df.dtypes) print(f行数: {len(df)})这一步能帮你发现很多问题比如订单表里的user_id是字符串用户表里的user_id是整数后面merge时明明看起来一样的值却匹配不上十有八九就是类型不一致。我遇到过的真实案例中这种问题占比非常高。3.4 数据量大的时候别一次性全读进内存如果你的CSV有几百MB甚至几个GBpd.read_csv()默认会全部读入内存很容易导致内存不足。更合理的做法是分块读取或只读取需要的列# 只读取需要的列 df pd.read_csv( data_raw/order_202401.csv, usecols[order_id, user_id, amount, created_at], ) # 分块读取适合做清洗预览 chunk_iter pd.read_csv( data_raw/order_202401.csv, chunksize50000, # 每次读5万行 ) for chunk in chunk_iter: # 对chunk做清洗然后增量写入目标文件 process(chunk)对于真正的大文件我还会考虑用polars替代pandas它的惰性计算和内存效率在多数场景下优于pandas。不过这是另一个话题今天先不展开。4. 清洗实操从无到有建一套可复用的处理流水线4.1 缺失值处理先问“为什么缺失”再决定怎么填缺失值处理是数据清洗里最核心的环节但很多人上来就fillna(0)或dropna()这是比较危险的做法。我的原则是先搞清楚缺失的机制。缺失分为三种完全随机缺失、随机缺失、非随机缺失。不同的缺失机制对应的处理策略完全不同。举个例子订单表中的pay_time字段如果大量缺失一种可能是用户下单后未支付业务原因另一种可能是上游系统没记录技术原因。前者不需要填充后者可能需要从其他表补数据。实操上第一步是摸清缺失情况import pandas as pd def missing_report(df): missing df.isnull().sum() missing_pct missing / len(df) * 100 report pd.DataFrame({ 缺失数量: missing, 缺失占比(%): missing_pct.round(2), }) return report[report[缺失数量] 0].sort_values(缺失数量, ascendingFalse) print(missing_report(df_order))然后根据业务含义分情况处理场景处理方式数值型字段缺失且业务上不允许为空用中位数或均值填充但必须记录填充逻辑分类型字段缺失单独给一个“未知”类别不要强行填众数时间字段缺失如果同表有下单时间可以用下单时间近似不重要且缺失占比70%直接删列但要在清洗报告中记录提示任何填充动作都要在清洗报告中留痕。这也是专业数据工作者和业余选手的分水岭。4.2 重复值处理不是所有重复都要删很多重复值处理教程一上来就教你drop_duplicates()但实际业务里的“重复”需要自己定义——是全部字段重复才算还是关键字段重复就算比如订单表里同一个订单号可能因为系统重推而出现两行记录这两行中有一个字段如update_time不同。这时候如果你用drop_duplicates(subset[order_id])默认保留第一个出现的记录你可能会丢掉最新更新的那一版。正确做法是先按时间排序再删除重复df_order df_order.sort_values(update_time, ascendingFalse) df_order df_order.drop_duplicates(subset[order_id], keepfirst)这段代码的含义是按更新时间倒序排然后对每个order_id保留最新的记录。要注意的是keepfirst是保留排序后的第一条所以先排倒序再保留“第一条”取到的就是最新记录。如果你想看清楚重复的规模可以先分组统计dup_count df_order.groupby(order_id).size() dup_records dup_count[dup_count 1] print(f重复订单数: {len(dup_records)})4.3 格式统一与异常值清洗格式统一是数据清洗里最琐碎、也最体现耐心的部分。常见问题包括日期格式不统一2024/01/01、2024-01-01、20240101共存字符串字段里有不可见字符全角空格、换行符、\u3000数值字段里混入千分位逗号或货币符号手机号、身份证号等字段被Excel科学计数法“改造”过日期格式统一是我最常用的操作推荐用pd.to_datetime()并指定errors参数df[created_at] pd.to_datetime( df[created_at], formatmixed, # pandas 2.0支持自动混合格式解析 errorscoerce, # 解析失败转成NaT而不是直接报错 )注意解析失败转成NaT后你需要回头检查这些无法解析的值它们往往隐藏着数据质量问题的线索。字符串清洗方面我习惯用.str系列方法# 去首尾空白包括全角空格 df[user_name] df[user_name].astype(str).str.strip() # 去掉中间的全角空格 df[user_name] df[user_name].str.replace(\u3000, ) # 统一大小写比如邮箱 df[email] df[email].str.lower()4.4 中文乱码的终极大法处理中文数据源最怕的就是乱码。解决思路分三步用charset_normalizer检测原始编码。读取时明确指定编码。输出时统一用utf-8-sig方便Excel直接打开不乱码。df_order.to_csv(output/order_cleaned.csv, indexFalse, encodingutf-8-sig)如果数据源已经乱码了想“还原”几乎不可能因为信息已经在编码转换中丢失了。这种情况下只能回到源头重新获取正确编码的文件。这也是为什么我一直在强调读文件时先检测编码不要用默认参数。5. 数据源合并多表关联的正确打开方式5.1 merge前的“三查”多数据源清洗的最后一步通常是合并而合并之前的准备工作决定了合并的质量。我每次merge前都会做三件事查键类型关联字段类型必须一致见4.3中提到的user_id例子。查键重复如果关联键在左表或右表有重复merge后会产生笛卡尔积行数会暴增。所以先检查重复。查键覆盖率用isin或merge(howleft, indicatorTrue)确认左表有多少记录能匹配到右表。df_merged df_order.merge( df_user, onuser_id, howleft, indicatorTrue, ) # 检查匹配情况 print(df_merged[_merge].value_counts())_merge列的值有三种both两边都有、left_only只在左表、right_only只在右表。如果left_only占比过高说明很多订单对应的用户信息缺失这种数据在下游分析时是要特别标注的。5.2 concat追加多表时的字段对齐如果压缩包里是多个结构相同的月度文件比如order_202401.csv、order_202402.csv用pd.concat纵向拼接df_all pd.concat([df_jan, df_feb, df_mar], ignore_indexTrue)这里有个隐藏坑如果某个月份文件新增了一列其他月份没有直接concat后缺失的列会自动补NaN。这本身不是问题但如果新列的业务含义需要统一就要在合并前对齐列名。一种更稳妥的做法是先统一列顺序common_cols df_jan.columns.tolist() df_feb df_feb.reindex(columnscommon_cols)5.3 多数据源的“数据血缘”记录数据清洗做完之后我强烈建议你顺手生成一份“数据血缘说明”至少包含每个字段来自哪个源文件、做了哪些清洗操作、清洗前后的行数和关键指标对比、输出文件路径。这份说明不仅是给同事看的也是给未来的自己看的——三个月后你回过头来用这批数据时如果没有这份记录几乎等于重新踩一遍坑。6. 常见问题排查打包好的避坑指南6.1 zip解压相关的报错报错信息可能原因解决办法could not find eocd文件下载不完整或不是zip用file命令确认格式重新获取文件not all files were readable压缩包内某个文件损坏用unzip -t逐文件检查单独提取损坏文件文件名乱码编码问题GBK vs UTF-8用cp437重编码再解码或改解压库缺少分卷zip分卷压缩后只拿到一部分确认所有.z01、.zip文件在同一目录6.2 pandas读数据报错报错信息可能原因解决办法ParserError: Error tokenizing data分隔符不是逗号指定sep常见的有\t、;、UnicodeDecodeError编码不对用charset_normalizer检测编码MemoryError文件太大分块读取、只读必要列、换polarsExcel file format cannot be determined文件扩展名和实际格式不符用file命令确认改用正确读取方式6.3 清洗过程中容易“翻车”的三个细节不要在原DataFrame上直接改建议操作前先df_copy df.copy()避免后续代码出错时数据已经被污染。不要用循环逐行清洗pandas的向量化操作比逐行iterrows()快几个数量级数据量大时差距尤其明显。不要忽视索引合并或分组后索引可能乱掉需要时用reset_index(dropTrue)。根据我自己的实操经验数据清洗这件事80%的时间花在“处理数据源本身的问题”上只有20%的时间真正花在写清洗逻辑上。很多人一上来就写清洗函数结果被乱七八糟的数据源折磨得欲哭无泪。这个数据清洗数据源.zip的案例正好说明从解压、摸底、读取、探查到清洗、合并每一步都有章可循。把这套流程跑熟了后面遇到任何“新压缩包”都不会慌。本文还有配套的精品资源点击获取