news 2026/9/10 12:57:08

Data-Science-For-Beginners 第 8 课:使用 Pandas 完成数据准备与清洗实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Data-Science-For-Beginners 第 8 课:使用 Pandas 完成数据准备与清洗实战指南

Data-Science-For-Beginners 第 8 课:使用 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「2-Working-With-Data」模块第 8 课的中文技术指南。原始文档为 translations/bg/2-Working-With-Data/08-data-preparation/README.md,所有代码示例均可直接在配套 Jupyter Notebook 2-Working-With-Data/08-data-preparation/notebook.ipynb 中运行验证。读完本文,你将掌握用 pandas 探索 DataFrame 结构、检测并处理缺失值(NaN / None)、去除重复记录三大类数据准备技能,并能独立完成课后「表单数据评估」实战作业。

无论数据来自何处,原始数据(raw data)都可能包含不一致之处,给后续分析与建模带来挑战。换句话说,这些数据可被归类为“脏数据”(dirty data),需要清洗。本课聚焦于清洗与转换数据的技术,以应对缺失、不准确或不完整的数据问题。所有主题均使用 Python 与 Pandas 库,完整演示见配套 notebook.ipynb。

为什么要清洗数据

数据清洗不是可有可无的收尾工作,它直接决定数据能否被有效使用。课程文档从三个层面阐述了其重要性:

  • 易于使用与复用(Ease of use and reuse):当数据被妥善组织与规范化后,搜索、使用和与他人共享都更轻松。
  • 一致性(Consistency):数据科学经常需要联合多个数据集,不同来源的数据需要被合并(join)。确保每个数据集有共同的标准格式,才能保证合并后的数据依然有用。
  • 模型准确性(Model accuracy):被清洗过的数据能提升依赖它的机器学习模型的准确率。这一点在 notebook 中也有呼应:机器学习模型无法自行处理缺失数据,因此在把数据送入模型之前必须先处理这些缺失值。

常见清洗目标与策略

在动手写代码前,先明确要解决哪几类数据问题。课程将常见目标归纳为四类:

  • 探索数据集(Exploring a dataset):数据探索(在本课程 4-Data-Science-Lifecycle/15-analyzing/README.md 中有详细讲解)能帮助你发现需要清洗的数据。目视检查数据集中的取值,可以建立对整体数据的预期,或发现可解决的问题。探索通常包括基本查询、可视化与抽样。
  • 格式化(Formatting):由于来源不同,数据在呈现方式上可能不一致,导致可视化或查询结果中取值“看得见却取不到”。常见格式化问题包括:空白字符(whitespace)、日期格式、数据类型。解决格式化问题通常取决于数据使用者——例如不同国家对日期和数字的呈现标准就不一样。
  • 重复(Duplications):多次出现的数据会产生不准确的结果,通常应被移除。这在合并两个或多个数据集时尤为常见。不过也有例外:合并数据集中的重复部分有时包含额外信息,可能需要保留。
  • 缺失数据(Missing Data):缺失数据会导致不准确,以及薄弱或有偏的结果。有时可通过“重新加载”数据解决,或用 Python 代码与计算填充缺失值,或直接移除该值及其对应数据。数据缺失的原因很多,采取的补救动作应视缺失的方式与原因而定。

探索 DataFrame 信息

学习目标:本小节结束后,你应该能熟练地在 pandas DataFrame 中找到关于数据的一般信息。

数据加载进 pandas 后,通常会以 DataFrame 形式存在(详细概念见前一课 2-Working-With-Data/07-python/README.md)。但如果你的 DataFrame 有 6 万行、400 列,该如何着手了解手中的数据?幸运的是,pandas 提供了便捷工具,可快速查看 DataFrame 的整体信息以及头尾若干行。

课程使用 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'])

shape 与 columns:先看规模与特征名

notebook 在info()之前先介绍了两组属性(注意它们是属性而非方法,所以不带括号):

iris_df.shape # 输出:(150, 4) iris_df.columns # Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', # 'petal width (cm)'], dtype='object')

shape告诉我们数据规模为 150 行 4 列:每行是一个数据点,每列是该数据点的一个特征;columns则给出特征名称,用于识别数据集包含哪些特征。

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

从输出可以立刻得到两个关键信息:① 每列的数据类型(dtype)——本数据全部为 64 位浮点数float64;② 每列的非空值数量(Non-Null Count)——本数据 4 列全部 150 non-null,即没有缺失记录。这两项正是数据准备的核心切入点。

DataFrame.describe:数值列的统计摘要

notebook 补充了课程 README 中未展开的方法describe():当数据集包含大量数值列时,可对每列做单变量统计(均值、中位数、四分位数等):

iris_df.describe()
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) count 150.000000 150.000000 150.000000 150.000000 mean 5.843333 3.057333 3.758000 1.199333 std 0.828066 0.435866 1.765298 0.762238 min 4.300000 2.000000 1.000000 0.100000 25% 5.100000 2.800000 1.600000 0.300000 50% 5.800000 3.000000 4.350000 1.300000 75% 6.400000 3.300000 5.100000 1.800000 max 7.900000 4.400000 6.900000 2.500000

输出依次为每列的样本数、均值、标准差、最小值、下四分位数(25%)、中位数(50%)、上四分位数(75%)与最大值,可用于快速发现异常分布。

head 与 tail:查看头尾数据

head()查看前几行,tail()查看最后几行:

iris_df.head() iris_df.tail()
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 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

两者默认返回 5 行,也可传入整数参数返回指定行数(notebook 中留了练习:如何显示超过 5 行?答案是iris_df.head(n))。在实际工作中,head/tail 对于在有序数据集中查找异常值尤其有用。

结论:仅凭 DataFrame 的元数据信息或头尾几个值,你就能立即对数据的规模、形状与内容形成直观认识。

处理缺失数据

学习目标:本小节结束后,你应该知道如何替换或移除 DataFrame 中的 null 值。

大多数实际数据集都包含缺失值。缺失数据的处理方式带有微妙的权衡,会直接影响最终分析与真实世界的结果。notebook 明确指出处理缺失数据的两种基本方式:① 删除包含缺失值的行;② 用其他值替换缺失值。下面先理解 pandas 中缺失值的两种表示,再逐一学习检测、删除、填充三大操作。

NaN 与 None:两种“空”

pandas 以两种方式处理缺失值:

  • NaN(Not a Number):这是 IEEE 浮点数规范中的特殊值,仅用于表示浮点数的缺失。对NaN的任何算术运算结果仍是NaN(如np.nan + 1np.nan * 0都返回nan);不过含NaN的数组做聚合(如sum()min()max())不会报错,只是结果同样是nan
  • None:Python 对象,用于非浮点类型数据的缺失。由于None来自 Python,它只能存在于dtypeobject的数组中;一旦出现None,整个数组会被“向上转型”(upcast)为 object 类型。这带来两个副作用:一是运算回落到解释型 Python 代码层面,大数据集下性能会变慢;二是对含None的数组执行sum()min()等聚合通常会直接报错(如TypeError: unsupported operand type(s) for +: 'int' and 'NoneType')。

虽然两者行为略有差异,但 pandas 在设计上可以互换处理它们:在 Series 与 DataFrame 为保证数据同质而向上转型的过程中,pandas 会在NoneNaN之间自动切换。因此可以把它们视为 pandas 中“null”的两种形态。这一点也体现在核心方法命名上:isnull()notnull()dropna()fillna()。补充:NaN只用于浮点缺失,整数、字符串或布尔类型没有对应的NaN等价物。

检测 null 值:isnull 与 notnull

isnull()notnull()是检测 null 数据的主要方法,都返回布尔掩码(Boolean mask):

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 将其视为有效值;
  • ''(空字符串)在第一章曾被用来表示空值,但它仍是字符串对象,在 pandas 看来不是null。

布尔掩码可以直接作为 Series 或 DataFrame 的索引使用,便于隔离出缺失(或非缺失)的值:

example1[example1.notnull()] # 等价于 example1.dropna() 的结果 example1.isnull().sum() # 统计缺失值总数,输出 2

结论isnull()notnull()在 DataFrame 上的结果类似:它们同时显示结果值及其索引,这在和数据“搏斗”时极其有用。

删除 null 值:dropna

在大数据集上,通常直接删除缺失值比用其他方式处理更可取。对 Series 使用dropna()

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

注意这与example1[example1.notnull()]的输出相似,区别在于dropna是把缺失值真正从 Series 中移除,而非仅做掩码索引。

DataFrame 是二维的,因此删除方式更多:不能只删单个值,必须整行或整列删除。由于数据科学中列一般代表变量、行代表观测,更常删除的是行dropna()的默认行为就是删除任何包含 null 值的行:

example2 = pd.DataFrame([[1, np.nan, 7], [2, 5, 8], [np.nan, 6, 9]]) example2.dropna() # 只保留第 1 行 [2.0, 5.0, 8]

(顺带一提:因为要容纳NaN,pandas 把两列自动向上转型成了浮点数。)

若需删除列,使用axis=1(即axis='columns'):

example2.dropna(axis='columns') # 只保留第 2 列 [7, 8, 9]

但按列删除可能误删大量想保留的数据,尤其在小数据集上。如果只想删除含若干甚至全部null 值的行/列,可用howthresh参数精细控制:

  • how:默认'any'(含任意 null 即删除);设为'all'则只删除全部为 null 的行或列。
  • thresh:设定一行/列需要拥有的非 null 值个数门槛,低于门槛才被删除。

先给example2增加一列全为NaN的新列:

example2[3] = np.nan example2
0 1 2 3 0 1.0 NaN 7.0 NaN 1 2.0 5.0 8.0 NaN 2 NaN 6.0 9.0 NaN
example2.dropna(axis='rows', thresh=3)
0 1 2 3 1 2.0 5.0 8.0 NaN

这里首尾两行因只含 2 个非 null 值(低于门槛 3)被删除,中间行保留。想查看dropna的全部参数,可在代码单元格中执行example2.dropna?

填充 null 值:fillna

有时填充 null 比删除更有意义。用isnull逐处填充费时费力,pandas 为此提供了fillna,它返回一个缺失值被替换后的 Series 或 DataFrame副本

example3 = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))

用单一常量填充(如0):

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

向前填充(forward-fill),用上一个有效值填充 null:

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

向后填充(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.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

注意:当向前填充时若前一个值也不存在(如第 2 行第 0 列),null 会原样保留。

用统计量填充:mode / mean / median

notebook 还演示了三种基于统计量的填充策略,比固定常量更贴近数据分布:

  • 众数 mode(针对分类型非数值列):例如一列布尔/类别数据,100 个样本中 90 个为True、8 个为False、2 个缺失,可用出现次数最多的True填充。notebook 中的示例用fill_with_mode[2].value_counts()先确认众数,再执行fill_with_mode[2].fillna('True', inplace=True)
  • 均值 mean(针对数值列)fill_with_mean[0].fillna(np.mean(fill_with_mean[0]), inplace=True)
  • 中位数 median(对离群值更稳健)fill_with_median[1].fillna(fill_with_median[1].median(), inplace=True)
  • 整表均值example4.fillna(example4.mean())用整个 DataFrame 各列的均值填充。

填充策略的选择应结合领域知识与数据特点——这正是“权衡”所在。

核心思想:处理缺失值的方式多种多样(删除、替换,以及替换的方法),具体策略必须由数据本身的特殊性决定。处理的数据越多,你越能培养出这种判断力。

删除重复数据

学习目标:本小节结束后,你应该能熟练识别并删除 DataFrame 中的重复值。

除了缺失数据,真实数据集里还经常出现重复数据。pandas 提供了简便的检测与删除工具。

识别重复:duplicated

duplicated返回布尔掩码,指示某条记录是否为此前某条记录的重复:

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

行 0 与行 2 均为('A', 1),因此行 2 被判为重复;行 3 与行 4 均为('B', 3),因此行 4 重复。

删除重复:drop_duplicates

drop_duplicates直接返回所有duplicatedFalse的副本:

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

duplicateddrop_duplicates默认检查所有列,但都可以通过传参只针对部分列判断重复:

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

(仅按letters列判断时,B只保留第一次出现的行 1。)

结论:删除重复数据几乎是每个数据科学项目必备的一步——重复数据会改变分析结果,给你不准确的结果!

notebook 中的综合实战:清洗一份“脏数据”

notebook 在最后用一个真实的dirty_data案例串起所有方法,是值得完整复现的参考流程:

  1. 定位数值列中的异常dirty_data['age'].describe()查看 age 列的统计摘要,发现异常取值;
  2. 删除非数值的年龄age_nonan = dirty_data['age'].dropna(),把年龄列中的无效/缺失值剔除后再分析;
  3. 识别重复姓名duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)],先对姓名做规范化(归一化)再按列找出重复记录;
  4. 去重并保留首条cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')
  5. 保留末条cleaned = cleaned.drop_duplicates(subset=['name'], keep='last')

其中keep参数控制保留哪一条:'first'保留首次出现、'last'保留末次出现、False则全部删除。这个“清洗 pipeline”示范了探索 → 检测 → 删除/填充 → 去重的完整链路。

课后挑战与作业

所有讨论过的材料都以 Jupyter Notebook 形式提供,每个小节后都有练习,建议逐一尝试。

课程还配套一个真实场景作业 评估表单数据:

  • 背景:一位客户用 一个小表单 收集其客户群的基础信息,并把结果交给你验证。你可以在浏览器中打开index.html查看表单。
  • 数据:提供了 CSV 记录数据集(含表单记录与一些基础可视化),客户指出部分可视化看起来不对,但不知如何解决。可在 作业 Notebook 中探索。
  • 要求:运用本课技术,就“如何改进表单以采集准确、一致的信息”提出建议。

从作业 notebook 的示例输出可以看到这份数据确实“脏”:birth_month列混有JanuaryJANSeptjanuarySeptember等多种大小写与缩写形态;state列混有CAHawaiiCaliforniaFloridaNaN等不同写法与缺失值;pet列也需统一。这正是格式化(大小写/缩写统一)、缺失值(NaN填充或删除)、规范化(状态全名 ↔ 缩写映射)等技术的用武之地。

复习与自学

数据准备与清洗是高度“动手实践”的步骤,发现并处理数据问题的方法远不止本课覆盖的这些。建议进一步探索:

  • 数据清洗挑战:日期解析(Parsing Dates)
  • 数据清洗挑战:数据缩放与归一化(Scale and Normalize Data)

本课完整代码与全部输出位于 2-Working-With-Data/08-data-preparation/notebook.ipynb,数据集位于 data/ 目录,可供反复练习;后续课程 4-Data-Science-Lifecycle/15-analyzing/README.md 还将继续讲解如何基于清洗后的数据做分析。

【免费下载链接】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 12:55:51

论文的免费大纲怎么分析?按章节信息量拆解

拿到一份免费生成的论文大纲,多数人的反应是照着写,写到一半才发现有的章挤成一团、有的章两三页就收尾,结构头重脚轻。大纲本身不会告诉你问题出在哪,需要你自己按章节信息量拆一遍:每章要讲什么、给多少篇幅、章与章…

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

从入门到进阶:一份完整的 3 阶段免费数学学习资源指南

从入门到进阶:一份完整的 3 阶段免费数学学习资源指南 【免费下载链接】awesome-math A curated list of awesome mathematics resources 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-math 打开浏览器搜"从哪里学数学",…

作者头像 李华
网站建设 2026/9/10 12:52:19

Python论文格式检查系统:从python-docx解析到LLM辅助的全流程实现

简介:这套基于Python的论文格式检查与处理源码,主要面向需要批量规范学术稿件格式的研究人员、期刊编辑以及有文本处理需求的Python开发者,可自动识别并修正标题层级、摘要、章节编号、图表标注、引用和参考文献等常见格式问题,显…

作者头像 李华