Hands-on data analysis— 动手学数据分析
写在最前面
这门课程得主要目的是通过真实的数据,以实战的方式了解数据分析的流程和熟悉数据分析python的基本操作。知道了课程的目的之后,我们接下来我们要正式的开始数据分析的实战教学,完成kaggle上泰坦尼克的任务,实战数据分析全流程。
这里有两份资料需要大家准备:图书《Python for Data Analysis》第六章和 baidu.com &google.com(善用搜索引擎)
来自Github开源项目Github项目地址
作者仅对于学习中遇到的问题进行标注整理 供大家学习讨论
本实验数据集和资料可以私信作者, 鼓励有条件的同学自行到Github上查阅下载
一、这篇笔记你将学到什么?
这篇笔记是基于 Kaggle 泰坦尼克项目的数据,从 0 带你走一遍数据分析最开始的几步:数据加载 → 初步观察 → 简单保存与导出,同时熟悉
numpy和pandas的常用操作。1. 数据加载:把数据“请进来”
- 如何导入
numpy、pandas并在报错时自己安装库。- 使用相对路径和绝对路径加载本地 CSV 文件,搞清楚“当前工作目录”的概念。
- 理解
pd.read_csv()与pd.read_table()的区别(默认分隔符不同),以及.csv、.tsv、.xlsx这几种常见数据格式应该如何读取。- 学会用
chunksize按块读取大文件,明白为什么要“逐块读取”来节省内存。- 学会把英文表头替换为中文列名,并把“乘客ID”设置为索引,同时理解
inplace=True是“原地修改”。2. 初步观察:快速给数据做个“体检”
- 使用
df.info()了解数据的整体结构:行数、列数、每列缺失值情况、数据类型和内存占用。- 使用
head()/tail()查看前几行、后几行,快速感受数据长什么样。- 使用
isnull()判断缺失值,理解哪些东西会被视为“空”(比如 NaN、None、NaT),哪些不会(比如 0、空字符串)。- 延伸出更多观察维度的思路:描述性统计(
describe)、类别分布(value_counts)、极端值和相关性等,为后续真正的数据分析打基础。3. 保存数据:把修改结果“带走”
- 学会把修改过列名、索引后的 DataFrame 导出为新的 CSV 文件。
- 知道文件默认保存位置是当前工作目录,也能指定保存路径。
- 知道如何通过设置编码解决中文乱码问题(如
utf-8、gbk等)。
1 第一章:数据加载
1.1 载入数据
数据集下载 https://www.kaggle.com/c/titanic/overview
1.1.1 任务一:导入numpy和pandas
importnumpyasnpimportpandasaspd【提示】如果加载失败,学会如何在你的python环境下安装numpy和pandas这两个库
1.1.2 任务二:载入数据
(1) 使用相对路径载入数据
(2) 使用绝对路径载入数据
df=pd.read_csv('train.csv')df.head(3)# "E:\pycharm\Python3_9\hands-on-data-analysis\第一单元项目集合\train.csv"# 注意:Windows系统的路径中反斜杠\需要用双反斜杠\\或者斜杠/来表示,否则会报错df=pd.read_table('E:\\pycharm\\Python3_9\\hands-on-data-analysis\\第一单元项目集合\\train.csv',sep=',')df.head(3)【提示】相对路径载入报错时,尝试使用os.getcwd()查看当前工作目录。
- cwd 是 Current Working Directory 的缩写
importos# 打印当前工作目录print("当前工作目录:",os.getcwd())【思考1.】知道数据加载的方法后,试试pd.read_csv()和pd.read_table()的不同,如果想让他们效果一样,需要怎么做?了解一下’.tsv’和’.csv’的不同,如何加载这两个数据集?
【总结】加载的数据是所有工作的第一步,我们的工作会接触到不同的数据格式(eg:.csv;.tsv;.xlsx),但是加载的方法和思路都是一样的,在以后工作和做项目的过程中,遇到之前没有碰到的问题,要多多查资料吗,使用google,了解业务逻辑,明白输入和输出是什么。
- 【思考1.】
pd.read_csv()和pd.read_table()的区别,以及如何处理.csv和.tsv文件。
1.
pd.read_csv()与pd.read_table()的主要区别这两个函数在 Pandas 中都用于从文本文件加载数据到 DataFrame 中,但它们被设计用来处理不同默认分隔符的文件。
特性 pd.read_csv()pd.read_table()默认分隔符( sep参数)逗号( ,)制表符( \t)使用场景 主要用于 .csv文件(Comma Separated Values)。主要用于 .tsv文件(Tab Separated Values)或通用文本文件。默认索引列 无( index_col=None)无( index_col=None)在功能上,
pd.read_csv()是更常用的和推荐的。实际上,pd.read_table()只是pd.read_csv()的一个包装器(Wrapper),它在内部调用pd.read_csv()并自动将分隔符设置为制表符。如何让它们效果一样?
要让
pd.read_csv()和pd.read_table()读取同一个文件并产生相同的效果,你需要手动设置它们的分隔符 (sep) 参数,使其保持一致:场景 A:读取逗号分隔的文件(
.csv)
函数 代码 说明 pd.read_csv()pd.read_csv('data.csv')使用默认值:逗号 pd.read_table()pd.read_table('data.csv', sep=',')手动指定分隔符为逗号 sep 是 Separator(分隔符)的缩写 场景 B:读取制表符分隔的文件(
.tsv)
函数 代码 说明 pd.read_csv()pd.read_csv('data.tsv', sep='\t')手动指定分隔符为制表符 pd.read_table()pd.read_table('data.tsv')使用默认值:制表符 2.
.tsv与.csv的区别及加载方法
.csv和.tsv都是常用的纯文本数据存储格式,它们的主要区别在于字段(列)之间是如何被分隔开的。什么是分隔符?
分隔符(Delimiter)是一种特殊的字符,用于将数据行中的不同字段分开。
文件后缀 全称 含义 分隔符 .csv CommaSeparatedValues 逗号分隔值 逗号( ,).tsv TabSeparatedValues 制表符分隔值 制表符( \t)要读取
.xlsx文件(Microsoft Excel 文件),需要使用Pandas配合一个专门处理 Excel 格式的引擎。用于读取
.xlsx文件的 Pandas 函数是pd.read_excel()。读取
.xlsx文件的步骤1. 安装必要的库
Pandas 自己无法直接处理
.xlsx这种复杂格式的 Excel 文件,它需要一个后端库作为“引擎”来解析文件。最常用的库是openpyxl。如果你还没有安装,需要在命令行或终端运行以下命令:
pipinstallpandas openpyxl2. 使用
pd.read_excel()安装完
openpyxl后,你就可以在 Python 中使用pd.read_excel()函数来读取.xlsx文件了。importpandasaspd# 假设你的文件名为 'my_data.xlsx'file_path='my_data.xlsx'# 使用 pd.read_excel() 读取文件df=pd.read_excel(file_path)print(df.head())
1.1.3 任务三:每1000行为一个数据模块,逐块读取
chunker=pd.read_csv('train.csv',chunksize=100)# chunksize=1000 关键参数: 指定每次读取文件时,要读取的行数。这里设置为 100行。print(f"chunker 的类型是:{type(chunker)}")# 2. 遍历 chunkerchunk_count=0forchunkinchunker:chunk_count+=1print("-"*30)print(f"这是第{chunk_count}个数据块 (chunk)")print(f"数据块的类型是:{type(chunk)}")print(f"数据块的行数是:{len(chunk)}")print("\n数据块 (chunk) 的具体内容:")# 打印每个数据块的前几行,以展示它是 DataFrameprint(chunk.head(3))# 'chunker' 每次迭代都会返回一个包含 1000 行数据的 DataFrameforchunkinchunker:# 这里的 'chunk' 就是一个标准的 Pandas DataFrame,但它只有 1000 行。# 可以在这里对这 1000 行数据进行计算、筛选或聚合等操作print(f"当前数据块的行数:{len(chunk)}")# 示例:计算每块数据的平均值average=chunk['Age'].mean()print(f"平均值:{average}")# 如果需要,可以将每块处理结果保存到外部列表或文件中# results.append(average)输出结果如下:
chunker 的类型是:<class'pandas.io.parsers.readers.TextFileReader'>------------------------------ 这是第1个数据块(chunk)数据块的类型是:<class'pandas.core.frame.DataFrame'>数据块的行数是:100数据块(chunk)的具体内容:......【思考1.】什么是逐块读取?为什么要逐块读取呢?
【提示】大家可以chunker(数据块)是什么类型?用for循环打印出来出处具体的样子是什么?
- chunker(数据块)是什么类型?用
for循环打印出来出处具体的样子是什么?
chunker 的类型是: <class ‘pandas.io.parsers.readers.TextFileReader’>
上方程序有chunker迭代出的内容
- 什么是逐块读取?为什么要逐块读取呢?
Chunks是一个使用Pandas库来读取大型 CSV 文件时非常高效的技巧。
核心作用是:“不要一次性把整个大文件加载到内存中,而是把它分成一个个小的‘数据块’(Chunks),可以逐块处理。”
chunker = pd.read_csv('train.csv', chunksize=100)代码逐段解释
代码段 含义 pd.read_csv(...)告知 Pandas 库,我们要读取一个 CSV 文件。 'train.csv'指定要读取的文件名(假设这是一个很大的训练数据集文件)。 chunksize=1000关键参数:指定每次读取文件时,要读取的行数。这里设置为1000 行。 chunker = ...将读取的结果赋值给一个名为 chunker的变量。
chunksize参数的作用和原理当一个文件非常大(比如有几百万行,甚至几 GB)时,你的计算机内存可能不足以一次性存储整个文件,或者一次性加载会导致程序运行缓慢甚至崩溃。
设置了
chunksize后,pd.read_csv()就不会返回一个完整的DataFrame,而是返回一个特殊的迭代器 (Iterator)对象,我们在这里命名为chunker。1.
chunker是什么?
chunker不是一个完整的 DataFrame,它是一个可以被循环的对象。你可以把它想象成一个**“文件搬运工”**。你告诉搬运工:“每次只给我搬 1000 行数据。”
2. 如何使用
chunker?你需要使用
for循环来从chunker中逐块地取出数据,进行处理3. 为什么使用分块读取?
- 节省内存 (Memory Efficiency):你的程序永远只在内存中处理 1000 行数据,而不是整个文件。
- 处理超大文件 (Big Data):即使文件大小超过了你电脑的可用内存,也可以完整地处理它。
- 进度跟踪 (Progress Tracking):可以清晰地知道处理数据的进度。
总而言之,
chunker = pd.read_csv('train.csv', chunksize=1000)的作用就是开启了分批加载大文件的模式,以提高内存使用效率和处理速度。
1.1.4 任务四:将表头改成中文,索引改为乘客ID [对于某些英文资料,我们可以通过翻译来更直观的熟悉我们的数据]
PassengerId => 乘客ID
Survived => 是否幸存
Pclass => 乘客等级(1/2/3等舱位)
Name => 乘客姓名
Sex => 性别
Age => 年龄
SibSp => 堂兄弟/妹个数
Parch => 父母与小孩个数
Ticket => 船票信息
Fare => 票价
Cabin => 客舱
Embarked => 登船港口
df=pd.read_csv('train.csv',names=['乘客ID','是否幸存','仓位等级','姓名','性别','年龄','兄弟姐妹个数','父母子女个数','船票信息','票价','客舱','登船港口'],index_col='乘客ID',header=0)df.head()# 查看数据前5行输出(默认),如果想要多查看几行可以对head()传参【思考】所谓将表头改为中文其中一个思路是:将英文列名表头替换成中文。还有其他的方法吗?
将表头改成中文并将索引改为乘客ID,可以通过以下几种方式实现:
方法 1:在读取数据时直接指定列名和索引
使用
pd.read_csv()的names参数指定中文列名,同时通过index_col参数设置索引为乘客ID。df=pd.read_csv('train.csv',names=['乘客ID','是否幸存','乘客等级','乘客姓名','性别','年龄','堂兄弟/妹个数','父母与小孩个数','船票信息','票价','客舱','登船港口'],index_col='乘客ID',header=0# 跳过原始表头)df.head()方法 2:读取后修改列名和索引
先读取数据,再通过
columns属性和set_index()方法修改列名和索引。df=pd.read_csv('train.csv')# 修改列名df.columns=['乘客ID','是否幸存','乘客等级','乘客姓名','性别','年龄','堂兄弟/妹个数','父母与小孩个数','船票信息','票价','客舱','登船港口']# 设置索引df=df.set_index('乘客ID')df.head()方法 3:使用字典映射替换列名
通过字典映射替换列名,适合列名较多且需要动态修改的情况。
df=pd.read_csv('train.csv')# 创建英文到中文的映射字典column_mapping={'PassengerId':'乘客ID','Survived':'是否幸存','Pclass':'乘客等级','Name':'乘客姓名','Sex':'性别','Age':'年龄','SibSp':'堂兄弟/妹个数','Parch':'父母与小孩个数','Ticket':'船票信息','Fare':'票价','Cabin':'客舱','Embarked':'登船港口'}# 替换列名df.rename(columns=column_mapping,inplace=True)# 设置索引df.set_index('乘客ID',inplace=True)df.head()方法 4:逐列修改列名
如果只需要修改部分列名,可以通过
rename()方法逐列修改。df=pd.read_csv('train.csv')# 修改部分列名df.rename(columns={'PassengerId':'乘客ID','Survived':'是否幸存'},inplace=True)# 设置索引df.set_index('乘客ID',inplace=True)df.head()
- 在上面的方法三、四中
inplace=Trues实现了什么功能
在 Pandas 中,
inplace=True是一个非常常见的参数,它的含义是:直接在原对象上进行修改,而不是返回一个新的对象。简单来说,就是**“原地修改”**。
详细对比
1. 默认情况 (
inplace=False)如果你不写这个参数,或者设置为
False(这是默认值),Pandas 不会改变原本的df变量,而是把修改后的结果作为一个新的 DataFrame返回给你。你需要用变量去接收它。# ❌ 原来的 df 不会变df.rename(columns=column_mapping)# ✅ 需要赋值给变量才能保存修改df_new=df.rename(columns=column_mapping)# 或者覆盖原变量df=df.rename(columns=column_mapping)2. 使用
inplace=True如果你设置为
True,Pandas 会直接修改内存中的df对象。这个操作没有返回值(返回None),但df本身变了。# ✅ 原来的 df 直接被修改了df.rename(columns=column_mapping,inplace=True)# ❌ 千万不要这样写,因为 inplace=True 返回的是 None# df = df.rename(columns=column_mapping, inplace=True) <-- 这样 df 会变成 None总结
inplace=False(默认):“给我一份改好的复印件,原件不要动。”(安全,适合链式调用)inplace=True:“直接在原件上改。”(省去赋值步骤,代码看起来简洁一些)
1.2 初步观察
导入数据后,你可能要对数据的整体结构和样例进行概览,比如说,数据大小、有多少列,各列都是什么格式的,是否包含null等
1.2.1 任务一:查看数据的基本信息
df.info()<class 'pandas.core.frame.DataFrame'> Index: 891 entries, 1 to 891 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 是否幸存 891 non-null int64 1 仓位等级 891 non-null int64 2 姓名 891 non-null object 3 性别 891 non-null object 4 年龄 714 non-null float64 5 兄弟姐妹个数 891 non-null int64 6 父母子女个数 891 non-null int64 7 船票信息 891 non-null object 8 票价 891 non-null float64 9 客舱 204 non-null object 10 登船港口 889 non-null object dtypes: float64(2), int64(4), object(5) memory usage: 83.5+ KB- 输出结果解释
Pandas DataFrame 的
.info()方法的运行结果,它提供了关于这个数据集(DataFrame)的简洁、概要的信息。我们可以将这些信息分为几个关键部分来理解:
1. 整体结构信息
<class 'pandas.core.frame.DataFrame'>:
- 含义:确认这个对象是一个Pandas DataFrame类型,这是 Pandas 中最常用的二维(表格型)数据结构。
Int64Index: 891 entries, 1 to 891:
- 含义:描述数据的行信息。
- 总行数 (Entries):共有891条记录(或行)。
- 索引 (Index):索引类型是 64 位整数 (
Int64Index),范围是从1 到 891。这表明数据的索引是从 1 开始的,而不是默认的 0 开始。Data columns (total 11 columns):
- 含义:描述数据的列信息。
- 总列数:共有11列。
2. 列详细信息(数据质量检查的核心)
这部分是
.info()输出最重要的部分,它详细列出了每一列的数据情况。
序号 列名 (Column) 非空值计数 (Non-Null Count) 数据类型 (Dtype) 缺失值情况 0 是否幸存 891 non-null int64无缺失值(891/891) 1 仓位等级 891 non-null int64无缺失值(891/891) 2 姓名 891 non-null object无缺失值 3 性别 891 non-null object无缺失值 4 年龄 714 non-null float64有缺失值(177 个) 5 兄弟姐妹个数 891 non-null int64无缺失值 9 客舱 204 non-null object严重缺失(687 个) 10 登船港口 889 non-null object有缺失值(2 个) 关键数据类型解释:
int64(Integer 64-bit):64 位整数。通常用于存储整数数据(如计数、ID、等级)。float64(Float 64-bit):64 位浮点数。用于存储小数数据(如年龄、票价)。object:字符串(文本)类型。用于存储文本数据(如姓名、客舱号)。缺失值分析:
通过比较总行数 (891) 和 Non-Null Count,我们可以迅速发现数据集中的缺失数据 (Missing Values):
- 年龄:只有 714 个非空值,意味着有891 − 714 = 177 891 - 714 = \mathbf{177}891−714=177个缺失值。
- 客舱:只有 204 个非空值,意味着有891 − 204 = 687 891 - 204 = \mathbf{687}891−204=687个缺失值(缺失率非常高)。
- 登船港口:只有 889 个非空值,意味着有2 \mathbf{2}2个缺失值。
这些缺失值需要在后续的数据清洗和预处理阶段进行处理(比如填充或删除)。
3. 资源使用信息
dtypes: float64(2), int64(4), object(5):
- 含义:总结了数据类型在整个 DataFrame 中的分布。
- 有 2 列是
float64类型。- 有 4 列是
int64类型。- 有 5 列是
object(字符串)类型。memory usage: 83.5+ KB:
- 含义:估算这个 DataFrame 在内存中所占用的空间大约是83.5 千字节 (KB)。这个数值可以帮助你评估处理更大文件时的内存需求。
总而言之,
.info()是进行初步数据探索和数据质量检查时最重要的一步,它让你快速了解数据的规模、类型和完整性。
df.info 和 df.info()有什么区别
这是一个非常经典的 Python 初学者问题,触及了**方法调用(Call)与对象引用(Reference)**的核心区别。
简单来说:带括号是“做动作”,不带括号是“看说明书”。
以下是详细对比分析:
1.
df.info()—— 执行方法(做动作)
- 含义:这是在调用(Call)这个函数。你告诉 Python:“现在立刻运行
info这个功能。”- 结果:Python 会执行
info内部的代码,计算并打印出 DataFrame 的详细摘要(行数、列数、非空值、内存占用等)。- 你在数据分析中需要的:正是这个。
代码示例:
df.info()输出结果(示例):
<class 'pandas.core.frame.DataFrame'> Int64Index: 891 entries, 1 to 891 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 是否幸存 891 non-null int64 ... (省略中间内容) ... dtypes: float64(2), int64(5), object(5) memory usage: 90.5+ KB2.
df.info—— 查看对象(看说明书)
- 含义:这是在引用这个属性。你告诉 Python:“我想看看
df对象里名为info的那个东西是什么。”- 结果:Python 不会运行代码,而是告诉你:“这是一个绑定在 DataFrame 上的方法对象。”
- 你在数据分析中需要的:通常不需要,除非你在做高级编程(比如把这个函数赋值给另一个变量)。
代码示例:
df.info输出结果(示例):
<bound method DataFrame.info of 是否幸存 仓位等级 姓名 性别 年龄 ... 父母子女个数 船票信息 票价 客舱 登船港口 乘客ID ... 1 0 3 Braund... male 22.0 ... 0 A/5 21171 7.25 NaN S 2 1 1 Cuming... female 38.0 ... 0 PC 17599 71.28 C85 C ... [891 rows x 11 columns]>(注意:它只是打印出了这个方法的描述信息,并没有统计数据的非空值或类型)
总结对比表
特性 df.info()(带括号)df.info(不带括号)本质 函数调用 (Function Call) 对象引用 (Object Reference) 比喻 按下遥控器上的“播放”键 手指着遥控器上的“播放”键 作用 执行代码,计算并显示数据摘要 查看这个方法本身在内存中的样子 是否有返回值 有(通常打印到控制台或返回 None) 有(返回方法对象本身) 常用场景 99.9% 的情况(查看数据信息) 极少(调试或高阶函数式编程) 结论
在做数据分析查看数据概况时,请务必加上括号
()。
1.2.2 任务二:观察表格前10行的数据和后15行的数据
df.head(10)df.tail(15)记住相关语法就可以,这里就不展示结果了。
1.2.3任务三:判断数据是否为空,为空的地方返回True,其余地方返回False
df.isnull().head()# 展示前 5 行数据的缺失值分布情况(True 表示缺失)
.isnull()方法是查看空缺值 ,这里结合.head()方法一起使用。避免一次性输出过多
【总结】上面的操作都是数据分析中对于数据本身的观察
【思考】对于一个数据,还可以从哪些方面来观察?找找答案,这个将对下面的数据分析有很大的帮助
- 对于一个数据,还可以从哪些方面来观察?
除了上述的的查看头尾行 (
head/tail)、基本信息 (info) 和缺失值 (isnull) 之外,数据观察(Exploratory Data Analysis, EDA)通常还需要从以下几个核心维度进行深入:1. 描述性统计分析 (Descriptive Statistics)
这是最直接了解数据数值分布的方法。
- 方法:
df.describe()- 观察点:
- 均值 (mean)vs中位数 (50%):如果两者相差很大,说明数据存在偏斜(Skewness)或异常值。
- 标准差 (std):数据波动大不大?
- 最小值 (min) / 最大值 (max):数据范围是否合理?(例如:年龄不应为负数,票价不应无穷大)。
# 查看数值型列的统计摘要df.describe()2. 唯一值与计数 (Unique Values & Counts)
对于分类数据(如性别、登船港口、客舱等级),我们需要知道有哪些类别以及每个类别的数量。
- 方法:
df['列名'].unique():查看有哪些唯一值。df['列名'].value_counts():查看每个类别有多少条数据。- 观察点:
- 是否存在拼写错误的类别(如 “male” 和 “Male”)?
- 样本是否均衡?(例如:幸存者和遇难者比例是否悬殊?)
# 查看“性别”列有哪些值,以及各有多少人df['性别'].value_counts()3. 数据类型与格式检查 (Data Types & Format)
虽然
info()给了大概的类型,但有时需要更细致的检查。
- 观察点:
- 数值是否被存成了字符串?(例如票价列里混入了 “$” 符号导致变成 object 类型)。
- 时间格式是否正确?(例如日期是 “2021-01-01” 字符串还是 datetime 对象)。
4. 异常值检测 (Outlier Detection)
寻找那些“格格不入”的数据。
- 方法:
- 排序:
df.sort_values(by='列名'),看看最大和最小的几个值是否离谱。- 可视化(箱线图):虽然还没讲到绘图,但这是观察异常值最直观的方法。
- 观察点:
- 比如泰坦尼克号数据中,是否有年龄超过 100 岁或票价高达 5000 的记录?
5. 相关性分析 (Correlation)
观察特征之间,或者特征与目标变量(是否幸存)之间的关系。
- 方法:
df.corr()- 观察点:
- 票价越高,幸存率越高吗?
- 年龄和兄弟姐妹数量有关联吗?
总结代码示例
你可以尝试运行以下代码来扩展你的观察视角:
# 1. 统计摘要(快速看数值分布)print("--- 统计摘要 ---")print(df.describe())# 2. 查看分类数据的分布(例如:查看男女比例)print("\n--- 性别分布 ---")print(df['性别'].value_counts())# 3. 排序观察(例如:看看票价最高的前 5 个人)print("\n--- 票价最高的 5 人 ---")print(df.sort_values(by='票价',ascending=False).head(5))
.isnull()判断为空的机制是什么? 空值可能是没有填充 Nan None…
理解 Pandas 如何定义“空值”对于数据清洗至关重要。
1.
df.isnull().head()语句解释这行代码是两个方法的链式调用,我们可以把它拆解来看:
df.isnull():
- 作用:它会遍历整个 DataFrame,判断每一个单元格是否为“空”。
- 返回结果:返回一个与原 DataFrame 形状完全一样的新 DataFrame,但里面的内容变成了布尔值(Boolean):
- 如果原位置是空值,显示
True。- 如果原位置有数据,显示
False。.head():
- 作用:取前 5 行。
- 目的:因为整个表可能很大,打印出来看不清,我们只看前 5 行的布尔值结果,快速检查一下哪些列可能存在缺失数据。
总结:这行代码的作用是**“展示前 5 行数据的缺失值分布情况(True 表示缺失)”**。
2. Pandas 判断“空值”的机制
Pandas 在判断是否为
null时,主要依据底层NumPy的标准以及 Python 的对象标准。被判定为
True(是空值) 的情况:Pandas 的
isnull()(以及它的别名isna()) 会将以下情况视为缺失值:
NaN(Not a Number):
- 这是标准的浮点数缺失值(IEEE 754 标准)。
- 这是 Pandas 中最常见的缺失值形式(数值列通常都用这个)。
None(Python 的 None 对象):
- Python 自带的“无”对象。
- 在 Pandas 的
object类型(字符串/混合类型)列中,None会被保留并视为缺失值。- 在数值列中,Pandas 通常会自动把
None转换为NaN。NaT(Not a Time):
- 专门用于时间序列(Datetime)类型的缺失值。
被判定为
False(不是空值) 的情况(易错点):很多初学者容易混淆以下情况,Pandas不认为它们是空值:
- 空字符串
""或" ":
- 注意:这是最容易踩坑的地方!在 Pandas 看来,空字符串是一个长度为 0 的有效字符串对象,不是 Null。
- 字符串
"NaN"或"null":
- 如果你读取 CSV 时没有正确解析,这些只是普通的文本字符,不是真正的缺失值。
- 数字
0:
- 0 是一个有效的数字,不是空。
False:
- 布尔值的 False 是有效值。
inf(无穷大):
- 默认情况下,无穷大被视为有效值(可以通过配置修改)。
代码演示
importpandasaspdimportnumpyasnp data={'数值':[1,np.nan,0],# np.nan 是空,0 不是'对象':['abc',None,''],# None 是空,空字符串 '' 不是'时间':[pd.Timestamp('20210101'),pd.NaT,pd.Timestamp('20210102')]# NaT 是空}df_test=pd.DataFrame(data)print("原始数据:")print(df_test)print("-"*20)print("isnull() 判断结果:")print(df_test.isnull())输出结果预演:
np.nan-> TrueNone-> Truepd.NaT-> True0->False''(空字符串) ->False
1.3 保存数据
1.3.1 任务一:将你加载并做出改变的数据,在工作目录下保存为一个新文件train_chinese.csv
# 注意:不同的操作系统保存下来可能会有乱码。大家可以加入`encoding='GBK' 或者 ’encoding = ’utf-8‘‘`df.to_csv('train_chinese.csv')默认会将文件保存在当前的“工作目录”(Current Working Directory)下。
也可以指定绝对路径保存注意反斜杠的问题
【总结】数据的加载以及入门,接下来就要接触数据本身的运算,我们将主要掌握numpy和pandas在工作和项目场景的运用。