news 2026/9/10 0:47:04

Data-Science-For-Beginners 数据准备实战:用 Pandas 清洗缺失值与重复数据的完整工作流

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Data-Science-For-Beginners 数据准备实战:用 Pandas 清洗缺失值与重复数据的完整工作流

Data-Science-For-Beginners 数据准备实战:用 Pandas 清洗缺失值与重复数据的完整工作流

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

本文基于 Data-Science-For-Beginners 课程第 8 课“Working with Data: Data Preparation”(本仓库translations/bn目录下提供了该课的孟加拉语译本,英文原文为 08-data-preparation/README.md),系统讲解“脏数据”的识别与清洗方法:如何用info()head()tail()快速摸清 DataFrame 的规模与结构,如何检测并处理NaN/None两类缺失值(isnull()dropna()fillna()),以及如何用duplicated()drop_duplicates()消除重复记录。读完后你将掌握一条可直接复用的数据准备流水线:从元数据探查、缺失值策略选择,到重复数据去除,并可用仓库内置的 Notebook 与课后作业数据集动手验证。

为什么数据准备是数据分析的必经环节

原始数据的来源各不相同,往往携带着会阻碍分析与建模的不一致性——课程把这类数据统称为“dirty”(脏数据),必须经过清洗和转换。根据来源不同,数据中可能缺失值、错误值或残缺记录,本课程的 Python + Pandas 示例全部演示在同目录下的 notebook.ipynb 中。

课程给出的清洗数据的三大理由:

  • 易用与易复用:数据经过合理组织与归一化后,检索、使用和与他人共享都会更容易;
  • 一致性:数据科学经常需要把来自多个来源的数据集合并(join)。只有当每个数据集遵循共同的标准化约定时,合并后的整体才仍然可用;
  • 模型精度:经过清洗的数据能提升依赖它的模型的准确度。

对应的四类常见清洗目标与策略:

目标说明
数据集探索数据探索(后续 15-analyzing 课程 会深入展开)能帮你发现哪些数据需要清洗。可视化地观察数值可以建立对整体分布的预期,或暴露可解决的问题。探索通常包括基础查询、可视化与抽样
格式不同来源的数据在呈现方式上可能不一致,导致“数据在集中看得到,却在可视化或查询结果中表现异常”。常见格式问题包括空白字符、日期与数据类型;格式约定往往因国家/地区而异(例如日期与数字的写法)
重复同一事件出现多次会产生不精确的结果,通常需要删除;两个或多个数据集合并时最容易引入重复。但合并产生的“重复行”有时携带互补信息,可能需要保留
缺失缺失值会造成不准确、薄弱甚至带偏差的结果。解决手段包括重新加载数据、用 Python 等代码计算填充,或直接删除该值及对应记录——具体策略取决于数据“为何、以何种方式”缺失

探查 DataFrame 的元数据

学习目标:本小节结束时,你应能自如地获取 pandas DataFrame 中数据的一般性信息。

数据加载进 pandas 后通常就是一个DataFrame(DataFrame 的完整概览见 07-python 课程)。但面对一个 60,000 行 × 400 列的 DataFrame,你如何起步?pandas 提供了便捷的元数据工具,配合首尾若干行的快速浏览,能让你立刻了解手头数据的规模、形状与内容。

课程选择 scikit-learn 中的经典Iris 数据集作为演练对象:

import pandas as pd from sklearn.datasets import load_iris iris = load_iris() iris_df = pd.DataFrame(data=iris['data'], columns=iris['feature_names'])
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
45.03.61.40.2

DataFrame.info:结构总览

info()打印 DataFrame 内容摘要:

iris_df.info()
RangeIndex: 150 entries, 0 to 149 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 sepal length (cm) 150 non-null float64 1 sepal width (cm) 150 non-null float64 2 petal length (cm) 150 non-null float64 3 petal width (cm) 150 non-null float64 dtypes: float64(4) memory usage: 4.8 KB

由此可知:Iris 数据集共 150 条记录、4 列,无任何 null 值,所有数据都以 64 位浮点数(float64)存储。

DataFrame.head() 与 DataFrame.tail():首尾内容

iris_df.head()
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) 0 5.1 3.5 1.4 0.2 1 4.9 3.0 1.4 0.2 2 4.7 3.2 1.3 0.2 3 4.6 3.1 1.5 0.2 4 5.0 3.6 1.4 0.2
iris_df.tail()
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) 145 6.7 3.0 5.2 2.3 146 6.3 2.5 5.0 1.9 147 6.5 3.0 5.2 2.0 148 6.2 3.4 5.4 2.3 149 5.9 3.0 5.1 1.8

要点:仅凭 DataFrame 的元数据(或首尾几行值),你就能对数据的大小、形状和内容形成即时印象。

Notebook 中的进阶探查:shape、columns 与 describe()

本课程的 notebook.ipynb 在 README 的基础上补充了三个更细粒度的探查手段,值得纳入你的标准检查清单:

  • iris_df.shape:返回(150, 4)。注意shape是属性而非方法,所以后面没有括号。它直接回答“有多少个样本点、每个样本点有几个特征”;
  • iris_df.columns:返回 4 个列名,是识别数据集特征名的基本手段;
  • iris_df.describe():对数值列输出统计摘要——样本数、均值、标准差、最小值、25% 分位、中位数、75% 分位与最大值。在数据探索阶段(即前面提到的“数据集探索”策略)它是发现异常值最快的工具之一。

Notebook 还附带了练习提示:默认head()只返回前 5 行,可尝试通过iris_df.head?查阅文档找出显示更多行的方式。

处理缺失数据

学习目标:本小节结束时,你应知道如何从 DataFrame 中替换或删除 null 值。

你希望使用的(或不得不使用的)数据集大多含有缺失值。缺失数据如何被处理,其中微妙的取舍会直接影响最终分析与现实结果。

两种缺失值表示:NaN 与 None

pandas 用两种机制处理缺失值:

  • NaN(Not a Number):IEEE 浮点规范中的一个特殊值,只用于表示缺失的浮点数值
  • None(Python 对象):用于浮点以外的其他类型的缺失值。

两种机制并存看似混乱,但有合理的编程设计原因;实际使用中 pandas 由此在绝大多数场景下取得了良好的折中。需要注意两者都有限制,例如(notebook.ipynb 中的深入讨论):

  • None只能存在于dtype='object'的 NumPy/pandas 数组中,因为它来自 Python。数组中一旦出现None,就意味着你在处理 Python 对象:运算退回到解释器层面而非编译后的 NumPy 代码(大集合上会变慢),且sum()min()等聚合可能报错(整数与None的加法未定义);
  • NaN支持快速向量运算,但对NaN的任何算术运算结果永远是NaN(如np.nan + 1np.nan * 0);
  • pandas 在处理时会主动在NoneNaN之间切换(例如把含None的整型Series升格为浮点型),因此可以把它们理解为 pandas 中“null 的两种口味”。核心方法命名也印证了这一点:isnull()notnull()dropna()fillna()

检测 null:isnull() / notnull()

import numpy as np example1 = pd.Series([0, np.nan, '', None]) example1.isnull()
0 False 1 True 2 False 3 True dtype: bool

仔细看这个输出,有没有出乎意料的点?0虽是算术上的“零”,但它仍是完全正常的整数,pandas 不会把它当作 null;''(空字符串)则更微妙——它仍然是字符串对象,在 pandas 眼中不是null 的表示。这正是数据准备中“格式问题”的实际体现:看似空白的单元格未必是缺失值。

布尔掩码还可以直接作为Series/DataFrame的索引使用,方便你把缺失(或存在)的值隔离出来单独处理,例如example1[example1.notnull()]

要点isnull()notnull()DataFrame上产生类似结果:显示结果及其索引,让你在和数据“搏斗”时定位问题。

删除 null:dropna()

在大型数据集上,直接剔除缺失 [NA] 值往往比设法填补更明智。

example1 = example1.dropna() example1
0 0 2 dtype: object

这与example1[example1.notnull()]的索引结果一致,区别在于dropna()直接把缺失值从Series中移除。

DataFrame是二维的,因此删除选项更多:

example2 = pd.DataFrame([[1, np.nan, 7], [2, 5, 8], [np.nan, 6, 9]]) example2
012
01.0NaN7
12.05.08
2NaN6.09

(注意 pandas 为容纳NaN把两列升格成了浮点数——这正是上一节讨论的类型升格行为。)

你不能从DataFrame中删除单个值,只能整行或整列删除。在数据科学中列通常代表变量、行代表观测,因此你更常删的是行;dropna()的默认行为就是删除含有任意 null 值的所有行

example2.dropna()
0 1 2 1 2.0 5.0 8

必要时也可以按列删除,使用axis=1(等价写法axis='columns'):

example2.dropna(axis='columns')
2 0 7 1 8 2 9

注意:在小型数据集上这可能会删掉大量你想保留的数据。如果你只想删除“含多个甚至全部为 null”的行/列,用howthresh两个参数控制:

  • 默认how='any'(即只要存在任一 null 就删);可改为how='all',仅当整行/整列全是 null 才删除(想看完整参数,可在代码单元格里运行example2.dropna?);
  • thresh提供更细粒度的控制:设置一行/列要保留所必须具备的non-null值数量。

example2扩展一列后(example2[3] = np.nan):

0123
01.0NaN7NaN
12.05.08NaN
2NaN6.09NaN
example2.dropna(axis='rows', thresh=3)
0 1 2 3 1 2.0 5.0 8 NaN

第一行和最后一行各只有两个 non-null 值,未达阈值 3,因此被删除。

填充 null:fillna()

有时用有效值填充 null 比直接删除更有意义。手动用isnull逐格替换很繁琐,pandas 因此提供fillna,返回一个缺失值被替换后的副本(不修改原对象)。

example3 = pd.Series([1, np.nan, 2, None, 3], index=list('abcde')) example3
a 1.0 b NaN c 2.0 d NaN e 3.0 dtype: float64

(1)用单一常量填充

example3.fillna(0)
a 1.0 b 0.0 c 2.0 d 0.0 e 3.0 dtype: float64

(2)前向填充(forward-fill):用最后一个有效值填补缺失:

example3.fillna(method='ffill')
a 1.0 b 1.0 c 2.0 d 2.0 e 3.0 dtype: float64

(3)后向填充(back-fill):把下一个有效值反向传播来填充缺失:

example3.fillna(method='bfill')
a 1.0 b 2.0 c 2.0 d 3.0 e 3.0 dtype: float64

DataFrame同理,但你可以指定沿哪个axis填充。复用前面的example2

example2.fillna(method='ffill', axis=1)
0 1 2 3 0 1.0 1.0 7.0 7.0 1 2.0 5.0 8.0 8.0 2 NaN 6.0 9.0 9.0

当 forward-fill 取不到前驱值时(如第 2 行的第 0 列),null 原样保留。

要点:处理缺失值的方法有很多种。选择哪种策略(删除、替换,以及以何种方式替换)应由该数据的具体特征决定。你接触的数据集越多,对缺失值处理的直觉就越成熟。

Notebook 中的填充策略扩展:mode、均值与中位数

notebook.ipynb 在ffill/bfill之外补充了基于领域知识的统计填充策略,实战中更常用:

  • 分类(非数值)数据用众数填充:例如某列 100 条记录中 90 条为True、8 条为False、2 条未填,则用value_counts()找到众数后fillna('True')填入;
  • 数值数据用均值或中位数填充:数据近似正态时用列均值(np.mean(col));数据偏态、含离群点时用中位数(col.median()),因为中位数对离群值更稳健;
  • 向量化填充技巧example2.fillna(example2.mean())可以直接用各列均值向量一次性填充(默认沿行方向对齐,整列为 NaN 的列保持无值)。

Notebook 还顺带介绍了数据准备中紧随其后的“编码分类数据”环节:Label Encoding(把每个类别映射为数字,适合类别较多或类别有顺序的场景)与 One-Hot Encoding(pd.get_dummies,每个类别展开一列 0/1,适合类别少且无序的场景)——这是把清洗后的数据交给机器模型前的常见步骤。

移除重复数据

学习目标:本小节结束时,你应能自如地识别并删除 DataFrame 中的重复值。

真实数据集中,重复数据与缺失数据一样常见。pandas提供了便捷的检测与删除手段。

识别重复:duplicated()

example4 = pd.DataFrame({'letters': ['A','B'] * 2 + ['B'], 'numbers': [1, 2, 1, 3, 3]}) example4
lettersnumbers
0A1
1B2
2A1
3B3
4B3
example4.duplicated()
0 False 1 False 2 True 3 False 4 True dtype: bool

duplicated()返回布尔掩码,标记某一行是否是之前某行的重复(即首次出现的那行永远为False)。

删除重复:drop_duplicates()

drop_duplicates()直接返回所有duplicated值为False的数据副本:

example4.drop_duplicates()
letters numbers 0 A 1 1 B 2 3 B 3

两者默认考察全部列,也可以只检查列的一个子集:

example4.drop_duplicates(['letters'])
letters numbers 0 A 1 1 B 2

要点:删除重复数据几乎是每个数据科学项目的必经环节——重复数据会改变分析结果,让你得到不准确的结论!

Notebook 中的实战延伸:真实世界的数据质量检查

notebook.ipynb 的“Real-World Data Quality Checks”一节把本课技术组合成一条完整清洗流水线,针对一个刻意构造的“脏数据”样例(含拼写不一致的国家名、199 岁与 -5 岁的年龄值、John Smith这类带多余空白的近似重名):

  1. 分类值标准化:先unique()/value_counts()暴露同一类别的不同拼法(USAU.S.AUnited States),再用“转小写 + 映射字典”(str.lower().map(mapping))归一化;更复杂的场景可借助模糊字符串匹配;
  2. 异常数值检测:先用领域知识筛掉不可能值(年龄 < 0 或 > 120),再用 IQR 法(Q1 - 1.5*IQRQ3 + 1.5*IQR)与 Z-score 法(通常 |Z| > 3)统计检测离群点;检测后可按“删除 / 截断到边界值 / 替换为 NaN 再插补 / 保留”四种策略处置;
  3. 近似重复检测:对名称列做str.strip().str.lower()归一化后用duplicated(subset=[...], keep=False)找出疑似同人,再按keep='first'等策略调用drop_duplicates合并。

最后 Notebook 把上述步骤封装为一个clean_dataset(df)函数(标准化分类列 → 清洗年龄 → 去重),展示了把零散技巧沉淀为可复用函数的思路。

课后实战:从一个表单评估数据质量

本课程的配套作业 Evaluating Data from a Form(英文原版见 assignment.md)是检验本课技能的最佳场景:

一位客户用一个 小表单 收集客户基本信息,并把收集到的数据交给你验证。表单的index.html可用浏览器打开查看;同时提供了 csv 记录数据集(含表单条目与基础可视化)。客户指出部分可视化“看起来不对”,但不知如何解决。你可以在 作业 Notebook 中探索。

任务要求:使用本课学到的技术,对表单提出改进建议,使其能采集准确、一致的信息。

看看 data/form.csv 的原始内容,问题一目了然:

birth_month,state,pet January,,Cats JAN,CA,Cats Sept,Hawaii,Dog january,AK,Dog July,RI,Cats September,California,Cats April,CA,Dog January,California,Cats November,FL,Dog December,Florida,Cats

数据中的格式不一致恰好对应“常见清洗目标”一节讨论的问题:

  • 大小写与缩写不一致January/JAN/january指同一个月;CACaliforniaFLFlorida指同一个州,且存在州字段为空的缺失记录;
  • 作业 Notebook 的复现路径:assignment.ipynb 先pd.read_csv载入数据,再分别对statebirth_month列做value_counts()并绘制条形图——正是因为上述不一致,CACalifornia被统计成了两个独立类别,柱状图自然“看起来不对”。

用本课方法即可修复:对birth_month统一大小写/展开缩写(标准映射),对state建立“缩写 ↔ 全称”归一化映射,再对空值做dropna()fillna()处理。这也印证了课程“格式问题的解决通常取决于使用数据的人”这一观点。

练习与延伸阅读

  • 本课全部示例均可在 Jupyter Notebook 中运行,且每个小节之后都附有练习(如“能否显示超过 5 行?”“ffillbfillaxis=1上分别产生什么输出?”),建议逐一尝试;
  • 课程还推荐了两类 Kaggle 数据清洗挑战作为自我练习:Parsing Dates(日期解析)与Scale and Normalize Data(数据缩放与归一化),用于探索本课未覆盖的清洗技巧;
  • 缺失值背后的统计直觉与数据探索方法,可在后续 4-Data-Science-Lifecycle/15-analyzing 课程及其 Notebook 中继续深化。

总结:数据准备是“hands-on”经验驱动的环节。本课给出的标准路径可以概括为三步——先用shape/info()/describe()/head()/tail()建立对数据的整体认知;再针对缺失值在“检测(isnull/notnull)→ 删除(dropnaaxis/how/thresh)→ 填充(常量、ffill/bfill、mode/均值/中位数)”之间依据数据特征选择策略;最后用duplicated/drop_duplicates(可限定列子集)清除重复记录,并配合标准化映射、离群点检测处理格式不一致与异常值。把这三步沉淀为可复用的清洗函数(如 Notebook 中的clean_dataset),你的数据才真正准备好进入分析与建模阶段。

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

基于双层优化的大规模电动汽车充放电时空调度策略及Matlab实现

做电动汽车调度研究的同学&#xff0c;大概率都遇见过一种困境&#xff1a;模型建得很完整&#xff0c;约束抠得很细&#xff0c;但一跑出来&#xff0c;调度中心自己很满意&#xff0c;车主却根本不愿意配合。原因很简单&#xff0c;你替车主做的决定&#xff0c;没考虑车主自…

作者头像 李华
网站建设 2026/9/10 0:46:15

国产AI芯片三国杀:昇腾、平头哥、寒武纪的算力格局与选型指南

去年下半年开始&#xff0c;我身边越来越多做AI基础设施的朋友&#xff0c;都不约而同在聊同一个话题&#xff1a;一批批算力集群开始交付&#xff0c;一颗颗AI芯片被插进服务器&#xff0c;整个行业像在玩一场饥饿游戏。有人把这个盘子粗算成“420万颗芯片”&#xff0c;华为昇…

作者头像 李华
网站建设 2026/9/10 0:45:26

我用三个月整理出的Java面试高频考点清单

去年秋天&#xff0c;我花了整整三个月备战Java后端面试。起初和大多数人一样&#xff0c;打开各种“面经合集”就开始死记硬背——从HashMap扩容到线程池参数&#xff0c;从JVM垃圾回收到MySQL隔离级别&#xff0c;恨不得把每一道题的标准答案刻进脑子里。直到一次模拟面试&am…

作者头像 李华
网站建设 2026/9/10 0:39:51

接口测试完全指南:从HTTP协议到自动化实战

1. 接口测试到底在测什么 很多刚接触接口测试的朋友&#xff0c;第一个困惑就是&#xff1a;接口测试和功能测试到底有什么区别&#xff1f;我直接用UI点点点不也一样能发现问题吗&#xff1f;这个问题的答案&#xff0c;得从接口测试的定位说起。 接口测试测的是系统内部模块…

作者头像 李华