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¶
【提示】如果加载失败,学会如何在你的python环境下安装numpy和pandas这两个库
1.1.2 任务二:载入数据¶
(1) 使用相对路径载入数据
(2) 使用绝对路径载入数据
# "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 的缩写
【思考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 Comma Separated Values 逗号分隔值 逗号 ( ,).tsv Tab Separated Values 制表符分隔值 制表符 ( \t)要读取
.xlsx文件(Microsoft Excel 文件),需要使用 Pandas 配合一个专门处理 Excel 格式的引擎。用于读取
.xlsx文件的 Pandas 函数是pd.read_excel()。
读取
.xlsx文件的步骤¶1. 安装必要的库¶
Pandas 自己无法直接处理
.xlsx这种复杂格式的 Excel 文件,它需要一个后端库作为“引擎”来解析文件。最常用的库是openpyxl。如果你还没有安装,需要在命令行或终端运行以下命令:
2. 使用
pd.read_excel()¶安装完
openpyxl后,你就可以在 Python 中使用pd.read_excel()函数来读取.xlsx文件了。
1.1.3 任务三:每1000行为一个数据模块,逐块读取¶
chunker = pd.read_csv('train.csv', chunksize=100)
# chunksize=1000 关键参数: 指定每次读取文件时,要读取的行数。这里设置为 100行。
print(f"chunker 的类型是: {type(chunker)}")
# 2. 遍历 chunker
chunk_count = 0
for chunk in chunker:
chunk_count += 1
print("-" * 30)
print(f"这是第 {chunk_count} 个数据块 (chunk)")
print(f"数据块的类型是: {type(chunk)}")
print(f"数据块的行数是: {len(chunk)}")
print("\n数据块 (chunk) 的具体内容:")
# 打印每个数据块的前几行,以展示它是 DataFrame
print(chunk.head(3))
# 'chunker' 每次迭代都会返回一个包含 1000 行数据的 DataFrame
for chunk in chunker:
# 这里的 '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循环打印出来出处具体的样子是什么?
【思考1.】
- chunker(数据块)是什么类型?用
for循环打印出来出处具体的样子是什么?
chunker 的类型是:
上方程序有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 => 乘客等级(½/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。Pythondf = pd.read_csv( 'train.csv', names=['乘客ID', '是否幸存', '乘客等级', '乘客姓名', '性别', '年龄', '堂兄弟/妹个数', '父母与小孩个数', '船票信息', '票价', '客舱', '登船港口'], index_col='乘客ID', header=0 # 跳过原始表头 ) df.head()
方法 2:读取后修改列名和索引¶
先读取数据,再通过
columns属性和set_index()方法修改列名和索引。Pythondf = pd.read_csv('train.csv') # 修改列名 df.columns = ['乘客ID', '是否幸存', '乘客等级', '乘客姓名', '性别', '年龄', '堂兄弟/妹个数', '父母与小孩个数', '船票信息', '票价', '客舱', '登船港口'] # 设置索引 df = df.set_index('乘客ID') df.head()
方法 3:使用字典映射替换列名¶
通过字典映射替换列名,适合列名较多且需要动态修改的情况。
Pythondf = 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()方法逐列修改。
- 在上面的方法三、四中
inplace=Trues实现了什么功能
在 Pandas 中,
inplace=True是一个非常常见的参数,它的含义是:直接在原对象上进行修改,而不是返回一个新的对象。简单来说,就是“原地修改”。
详细对比¶
1. 默认情况 (
inplace=False)¶如果你不写这个参数,或者设置为
False(这是默认值),Pandas 不会改变原本的df变量,而是把修改后的结果作为一个新的 DataFrame 返回给你。你需要用变量去接收它。Python# ❌ 原来的 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本身变了。Python# ✅ 原来的 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 任务一:查看数据的基本信息¶
<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 = \mathbf{177}\) 个缺失值。
- 客舱: 只有 204 个非空值,意味着有 \(891 - 204 = \mathbf{687}\) 个缺失值(缺失率非常高)。
- 登船港口: 只有 889 个非空值,意味着有 \(\mathbf{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 的详细摘要(行数、列数、非空值、内存占用等)。- 你在数据分析中需要的:正是这个。
代码示例:
输出结果(示例):
Text Only<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+ KB
2.
df.info—— 查看对象(看说明书)¶
- 含义:这是在引用这个属性。你告诉 Python:“我想看看
df对象里名为info的那个东西是什么。”- 结果:Python 不会运行代码,而是告诉你:“这是一个绑定在 DataFrame 上的方法对象。”
- 你在数据分析中需要的:通常不需要,除非你在做高级编程(比如把这个函数赋值给另一个变量)。
代码示例:
输出结果(示例):
Text Only<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行的数据¶
记住相关语法就可以,这里就不展示结果了。
1.2.3任务三:判断数据是否为空,为空的地方返回True,其余地方返回False¶
.isnull()方法是查看空缺值 ,这里结合.head()方法一起使用。避免一次性输出过多
【总结】上面的操作都是数据分析中对于数据本身的观察
【思考】对于一个数据,还可以从哪些方面来观察?找找答案,这个将对下面的数据分析有很大的帮助
- 对于一个数据,还可以从哪些方面来观察?
除了上述的的查看头尾行 (
head/tail)、基本信息 (info) 和缺失值 (isnull) 之外,数据观察(Exploratory Data Analysis, EDA)通常还需要从以下几个核心维度进行深入:1. 描述性统计分析 (Descriptive Statistics)¶
这是最直接了解数据数值分布的方法。
- 方法:
df.describe()- 观察点:
- 均值 (mean) vs 中位数 (50%):如果两者相差很大,说明数据存在偏斜(Skewness)或异常值。
- 标准差 (std):数据波动大不大?
- 最小值 (min) / 最大值 (max):数据范围是否合理?(例如:年龄不应为负数,票价不应无穷大)。
2. 唯一值与计数 (Unique Values & Counts)¶
对于分类数据(如性别、登船港口、客舱等级),我们需要知道有哪些类别以及每个类别的数量。
- 方法:
df['列名'].unique():查看有哪些唯一值。df['列名'].value_counts():查看每个类别有多少条数据。- 观察点:
- 是否存在拼写错误的类别(如 "male" 和 "Male")?
- 样本是否均衡?(例如:幸存者和遇难者比例是否悬殊?)
3. 数据类型与格式检查 (Data Types & Format)¶
虽然
info()给了大概的类型,但有时需要更细致的检查。
- 观察点:
- 数值是否被存成了字符串?(例如票价列里混入了 "$" 符号导致变成 object 类型)。
- 时间格式是否正确?(例如日期是 "2021-01-01" 字符串还是 datetime 对象)。
4. 异常值检测 (Outlier Detection)¶
寻找那些“格格不入”的数据。
- 方法:
- 排序:
df.sort_values(by='列名'),看看最大和最小的几个值是否离谱。- 可视化(箱线图):虽然还没讲到绘图,但这是观察异常值最直观的方法。
- 观察点:
- 比如泰坦尼克号数据中,是否有年龄超过 100 岁或票价高达 5000 的记录?
5. 相关性分析 (Correlation)¶
观察特征之间,或者特征与目标变量(是否幸存)之间的关系。
- 方法:
df.corr()- 观察点:
- 票价越高,幸存率越高吗?
- 年龄和兄弟姐妹数量有关联吗?
总结代码示例¶
你可以尝试运行以下代码来扩展你的观察视角:
.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(无穷大):
- 默认情况下,无穷大被视为有效值(可以通过配置修改)。
代码演示¶
Pythonimport pandas as pd import numpy as np 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在工作和项目场景的运用。
复习:数据分析的第一步,加载数据我们已经学习完毕了。当数据展现在我们面前的时候,我们所要做的第一步就是认识他,今天我们要学习的就是了解字段含义以及初步观察数据。
1 第一章:pandas基础¶
1.4 知道你的数据叫什么——Series 和 DataFrame 初认识¶
在这一部分,你会学到:
pandas的两个核心数据结构:Series(一维) 和 DataFrame(二维表格),理解它们分别长什么样、适合装什么数据。- 能自己写出简单示例:
- 用字典创建
Series(如州名 → 数值映射)。- 用字典创建
DataFrame(如 state/year/pop 这样的表格数据)。- 重新加载
train.csv或上一节保存好的train_chinese.csv,并通过df.columns查看每一列的列名。- 学会两种访问列的方式,并理解它们的区别:
- 字典访问法:
df['Cabin']- 属性访问法:
df.Cabin知道什么时候必须用中括号索引(列名有空格、特殊字符、想用变量名等)。- 学会对比两个 DataFrame(如
train和test_1)的列差异:- 用集合运算找出“测试集中多出的列”。
- 用多种方式删除多余列:
del、drop(columns=...)、pop()或“只保留需要的列”的思路。- 理解
Unnamed: 0这类列名出现的原因:通常是保存时把索引写进 CSV、读取时又没指定index_col导致的。- 用
df.drop([...], axis=1)实现“临时隐藏几列只看其他列”,并理解:- 不加
inplace=True时,只是返回一个“修改后的视图/新对象”,原df不会被真正改动。- 何时适合用
inplace=True做“原地修改”。1.5 筛选的逻辑——用条件把数据“挑”出来¶
在这一部分,你会学到:
- 利用布尔条件对 DataFrame 做行筛选:
- 例如:
df[df["Age"] < 10]获取 10 岁以下乘客。- 构造多条件筛选,并用逻辑运算符组合条件:
- 使用
&表示“同时满足”(交集),|表示“满足其一”(并集),~表示取反。- 理解为什么每个条件外面都必须加一层括号。
- 完成“10 < Age < 50”的区间筛选,并将结果命名为
midage。- 使用
reset_index()重置筛选后 DataFrame 的索引:- 理解原索引可能是不连续、不是 0 开始的。
- 明白
reset_index()和reset_index(drop=True)的区别:一个保留旧索引为列,一个直接丢弃。- 知道何时需要先重置索引,再按“行号感觉”的方式去定位行。
- 使用
loc按“标签”选取数据:- 例如选出
midage中第 100 行指定列("Pclass"、"Sex")的数据。- 以及多行多列组合选择:
loc[[100, 105, 108], ['Pclass', 'Name', 'Sex']]。- 使用
iloc按“位置”选取数据:- 例如用
iloc[[100,105,108],[2,3,4]]通过“行号 + 列号”的方式选择相同的数据。- 通过对比
loc与iloc,理解它们的关键区别:loc:按标签(行索引名、列名)选取。iloc:按位置(整数下标)选取。- 切片区间在
loc中是闭区间,在iloc中是左闭右开
1.4 知道你的数据叫什么¶
我们学习pandas的基础操作,那么上一节通过pandas加载之后的数据,其数据类型是什么呢?
1.4.1 任务一:pandas中有两个数据类型DataFrame和Series,通过查找简单了解他们。然后自己写一个关于这两个数据类型的小例子🌰[开放题]¶
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
example_1 = pd.Series(sdata)
example_1
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002, 2003],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
example_2 = pd.DataFrame(data)
example_2
- Pandas 主要有两个核心数据结构 DataFrame和Series 的介绍
Pandas 主要有两个核心数据结构,以及存储在这些结构中的底层数据类型(dtypes)。
1. 核心数据结构 (Data Structures)¶
这是 Pandas 中最常用的两个对象:
Series (序列)
定义:一维数组对象。
- 理解:可以把它看作是 Excel 表格中的一列,或者是一个带标签(索引)的 Python 列表。
- 组成:由一组数据(Values)和一组与之相关的数据标签(Index)组成。
- 代码示例(参考你的
example_1):
DataFrame (数据框)
定义:二维表格型数据结构。
- 理解:可以把它看作是整个 Excel 表格或 SQL 表。
- 组成:它既有行索引(Index),也有列索引(Columns)。你可以把它看作是由多个 Series 组成的字典(共用同一个行索引)。
- 代码示例(参考你的
example_2):Python# 创建 DataFrame df = pd.DataFrame({ 'A': 1., 'B': pd.Timestamp('20130102'), 'C': pd.Series(1, index=list(range(4)), dtype='float32') })2. 底层数据类型 (Dtypes)¶
这是指存储在 Series 或 DataFrame 单元格中的具体数值类型。你可以通过
df.dtypes查看。常见的包括:
object:通常代表字符串(String),或者是混合类型的数据。int64:整数(Integer)。float64:浮点数(Float),即带小数点的数字。bool:布尔值(True/False)。datetime64:日期时间类型。
1.4.2 任务二:根据上节课的方法载入"train.csv"文件¶
也可以加载上一节课保存的"train_chinese.csv"文件。
1.4.3 任务三:查看DataFrame数据的每列的名称¶
1.4.4任务四:查看"Cabin"这列的所有值 [有多种方法]¶
df['Cabin'].head(3)、 df.Cabin.head(3)这两种方法的区别
这两种方法在当前这个例子中(访问名为 "Cabin" 的列)效果是完全一样的,都返回该列的数据。
但是,它们在适用场景和灵活性上有很大的区别。以下是详细对比:
1.
df['Cabin'](方括号法 / 字典访问法)¶这是最通用、最推荐的方法。
优点:
支持任意列名:如果列名包含空格(如
"First Name")、特殊符号(如"Price($)")或数字开头,必须用这种方法。支持变量:可以使用变量来动态访问列。
创建新列:必须用这种方法来添加新列。
避免冲突:如果列名和 Pandas 的内置方法名重名(比如列名叫
count,sum,class),这种方法依然能准确获取列数据。2.
df.Cabin(属性访问法 / 点号法)¶这是一种语法糖(Syntactic Sugar),主要是为了写起来方便。
优点:
- 书写快捷:少打两个引号和两个括号。
- 代码补全:在 Jupyter Notebook 或 IDE 中,输入
df.后按 Tab 键通常能自动补全列名。缺点(局限性):
- 不支持特殊列名:如果列名有空格(
df.First Name❌)或特殊字符,会报错。- 不能创建新列:
df.New_Column = 1只会给df对象添加一个普通的 Python 属性,而不会在 DataFrame 数据结构中真正添加一列数据。- 容易冲突:如果你的列名叫做
shape、index、T或者count,使用df.shape访问的是 DataFrame 的形状属性,而不是名为 "shape" 的那一列数据。总结建议¶
- 日常快速查看数据且列名规范(无空格、非关键字)时,可以用
df.ColumnName。- 编写正式脚本、处理复杂列名或创建新列时,请务必使用
df['ColumnName']。
1.4.5 任务五:加载文件"test_1.csv",然后对比"train.csv",看看有哪些多出的列,然后将多出的列删除¶
手动打印表头(df.columns)进行肉眼对比
经过我们的观察发现一个测试集test_1.csv有一列是多余的,我们需要将这个多余的列删去
【思考】还有其他的删除多余的列的方式吗?
以下是三种删除多余列的方法
- 使用 drop() 函数(最推荐)这是最标准的方法,因为它不会像 del 那样直接修改原数据(除非你指定 inplace=True),这在数据处理管道中更安全。
'''
#思考回答
# 方法 A:返回一个新的 DataFrame(不改变原数据)
test_1_clean = test_1.drop(['a'], axis=1)
# 方法 B:直接在原数据上修改(加上 inplace=True)
test_1.drop(['a'], axis=1, inplace=True)
# 方法 C:使用 columns 参数(更直观,不需要写 axis=1)
test_1.drop(columns=['a'], inplace=True)
# axis 参数用于指定操作的方向(行还是列)。
# axis=0 (默认):代表 行 (Rows/Index)。也就是纵向 ↓。
# axis=1:代表 列 (Columns)。也就是横向 →。
'''
- 使用 pop() 方法 这个方法会删除列,同时把被删除的列作为返回值弹出来。如果你需要把删掉的数据存起来备用,这个方法很有用。
- 列表切片/筛选(保留法)与其说是“删除”,不如说是“只保留想要的”。当你需要删除的列很多,而保留的列很少时,这种方法最快。
总结对比¶
方法 特点 适用场景 del df['col']Python 原生语法,直接修改原数据,无返回值。 快速删除单列,确定不再需要原数据。 df.drop()Pandas 专用,功能强大,支持多列,默认不修改原数据。 最通用,特别是需要删除多列或在链式调用中。 df.pop()删除并返回该列数据。 删除的同时还需要用到这列数据。 df[['col1']]筛选保留。 需要删除的列比保留的列多得多时。
补充:在Pandas 中如何高效、编程化地对比两个 DataFrame 的列差异?¶
使用 Python 的集合(Set)操作来快速找出不同之处。
方法:使用集合操作 (Set Operations)¶
集合操作可以让你瞬间找出:
- A 有但 B 没有的列(差集)
- B 有但 A 没有的列(差集)
- 两者共有的列(交集)
- 两者所有的列(并集)
假设你有两个 DataFrame:
train和test_1。Python# 获取列名集合 train_cols = set(df.columns) test_cols = set(test_1.columns) # 1. 找出 test_1 中多出的列 (test_1 有但 train 没有) diff = test_cols - train_cols print(f"test_1 多出的列: {diff}") # 2. 找出 train 中多出的列 (train 有但 test_1 没有) # diff_2 = train_cols - test_cols # print(f"train 多出的列: {diff_2}")为什么这种方法更高效?¶
- 自动化:不需要人工逐个单词去核对,避免眼花看错。
- 直接可用:结果是一个集合或列表,你可以直接把这个结果传给
drop()函数来删除多余的列。
这里不显示多余的列是因为 如果按顺序执行该程序 那么不同的列在上方已经被删除了.你需要注释或者删除上方程序后重新运行。
# 找出 test_1 中多余的列
extra_columns = set(test_1.columns) - set(df.columns)
print(f"多余的列是: {extra_columns}")
# 如果想直接删除这些多余的列
# test_1.drop(columns=extra_columns, inplace=True)
- 输出解释
'Unnamed: 0'。
- 这是 Pandas 读取 CSV 文件时非常常见的一个现象。
现在去观察一下你输入的两个.csv文件,train.csv的第一列是PassengerId,然而train_1.csv的第一列是一个无列名的序号列
所以读取时就会看到一个叫
Unnamed: 0的列。 你可以在 CSV 里给这一列补上列名(比如“序号”),再重新读取一次,对比一下输出,就会更直观地理解这个现象。它的含义是: 这通常是 CSV 文件中原本就存在的索引列(Index Column),但在保存时没有给它起名字,或者读取时没有指定它为索引。
详细解释¶
来源: 当你使用
df.to_csv('filename.csv')保存文件时,默认情况下 Pandas 会把 DataFrame 的行索引(0, 1, 2, ...) 也保存进 CSV 文件,作为第一列。 因为行索引通常没有名字,所以 CSV 文件的第一行(表头)的第一个位置是空的。读取时的表现: 当你再次用
pd.read_csv('filename.csv')读取这个文件时,Pandas 发现第一列有数据但表头是空的,它就会自动给这一列起一个名字,叫做Unnamed: 0(意思是:第 0 个没有名字的列)。如何解决/避免?¶
你有以下几种方法处理它:
方法一:读取时指定索引(推荐) 告诉 Pandas 第一列就是索引,不要把它当成普通数据列读取。
方法二:保存时不保存索引 如果你不需要保存行索引(通常 0,1,2... 这种默认索引是不需要保存的),在保存时加上
index=False。方法三:读取后删除(你现在的做法) 既然已经读进来了,就把它删掉。
1.4.6 任务六: 将['PassengerId','Name','Age','Ticket']这几个列元素隐藏,只观察其他几个列元素¶
【思考】对比任务五和任务六,是不是使用了不一样的方法(函数),如果使用一样的函数如何完成上面的不同的要求呢?
【思考回答】
如果你希望在原 DataFrame 上永久删除这些列,可以在 drop() 中使用 inplace=True。
本小节只是想“暂时隐藏这几列看一眼效果”,所以不加 inplace,让原数据保持不变。
1.5 筛选的逻辑¶
对于表格数据,最重要的能力之一就是筛选:把自己需要的信息挑出来,把当前分析不关心的先丢在一边。
下面还是用实战的方式,一边写代码一边体会 pandas 的筛选能力。
1.5.1 任务一: 我们以"Age"为筛选条件,显示年龄在10岁以下的乘客信息。¶
1.5.2 任务二: 以"Age"为条件,将年龄在10岁以上和50岁以下的乘客信息显示出来,并将这个数据命名为midage¶
【提示】了解pandas的条件筛选方式以及如何使用交集和并集操作
在 Pandas 中进行条件筛选(Boolean Indexing)时,逻辑运算与 Python 原生的
and/or有所不同。以下是核心规则和操作方式:
1. 核心逻辑符号¶
Pandas 使用位运算符来处理向量化的逻辑操作:
- 交集 (AND):使用符号
&
- 含义:同时满足所有条件。
- 并集 (OR):使用符号
|(竖线)
- 含义:只要满足其中一个条件即可。
- 取反 (NOT):使用符号
~(波浪号)
- 含义:排除满足该条件的数据。
2. !!!极其重要的语法规则:括号
()¶这是新手最容易报错的地方:每个独立的条件必须用括号括起来。
- 错误写法:
Pythondf[df['Age'] > 10 & df['Age'] < 50] # 报错原因:Python 中 & 的优先级比 > 高, # 它会先尝试计算 10 & df['Age'],导致逻辑混乱。
- 正确写法:
3. 实战示例¶
假设我们要处理泰坦尼克号的数据:
A. 交集 (AND) - 你的任务二
筛选年龄在 10 岁到 50 岁之间的人(大于10 且 小于50):
B. 并集 (OR)
筛选“小孩”或者“老人”(小于 10 岁 或者 大于 50 岁):
C. 列表筛选 (isin)
如果你要筛选某个字段等于多个特定值(比如筛选 1 等舱和 3 等舱),用
isin()更简洁,它本质上也是一种并集:
1.5.3 任务三:将midage的数据中第100行的"Pclass"和"Sex"的数据显示出来¶
reset_index(drop=True) 的作用是将 midage 的索引重置为默认的整数索引(0, 1, 2, ...),并且不保留原有的索引列(因为 drop=True)。
这样做可以让 midage 的索引变得连续、规范,方便后续按位置(或标签)访问或数据处理,避免因索引混乱导致的错误。
如果不加 drop=True(即写成 midage = midage.reset_index()),原有的索引会被还原为一列,变成 DataFrame 的普通数据列,而不是被直接丢弃。
具体表现为:
- 新的 DataFrame 会多出一列名为 "index"(或原索引名),内容是原来的索引值。
- 索引会被重置为默认的 0, 1, 2, ...。
这样做的结果是,原索引信息不会丢失,而是以新的一列保留在数据中。如果你不需要原索引,建议加 drop=True,否则会多出一列。
简要总结:
这行代码让 midage 的索引变为默认的连续数字索引,并且丢弃原来的索引,不再作为新的一列保留。
【思考】这个reset_index()函数的作用是什么?如果不用这个函数,下面的任务会出现什么情况?
reset_index() 函数是 Pandas DataFrame 的一个方法,主要作用是将索引(index)还原为普通列,并生成新的默认整数索引。常见用法有:
- df.reset_index():将当前索引变为普通列,索引重置为默认的 0, 1, 2, ...
- df.reset_index(drop=True):将索引重置为默认整数索引,但不保留原索引为列。
如果不用 reset_index(),在某些操作(如 groupby、set_index、过滤等)后,DataFrame 的索引可能不是默认的整数索引,而是某些列的值或多级索引。这样会导致:
- 数据显示时索引不是连续数字,可能影响可读性。
- 后续按位置(如 iloc)或合并、可视化等操作时,索引不规范可能导致报错或结果异常。
- 某些情况下,索引列不会参与普通的列运算或输出,容易遗漏。
举例说明:
假设 groupby 后:
此时 'A' 变成了索引。如果你想让 'A' 重新变成普通列,可以用:
如果不 reset_index,后续用 df2['A'] 会报错,因为 'A' 只是索引,不是普通列。
总结:reset_index() 让索引变回普通列,保证数据结构统一,便于后续处理。如果不用,可能导致数据操作和结果出现问题。
1.5.4 任务四:使用loc方法将midage的数据中第100,105,108行的"Pclass","Name"和"Sex"的数据显示出来¶
1.5.5 任务五:使用iloc方法将midage的数据中第100,105,108行的"Pclass","Name"和"Sex"的数据显示出来¶
【思考】对比iloc和loc的异同
iloc和loc都是 Pandas 中用于选取 DataFrame 或 Series 数据的索引器相同点:
- 都可以用于行、列的选取和切片。
- 都支持单个、多个、切片、布尔数组等多种索引方式。
不同点:
iloc(integer location) loc(label location) 索引方式 只能用整数位置(0, 1, 2, ...) 用标签(行/列名) 包含性 切片时,结尾不包含(左闭右开) 切片时,结尾包含(左闭右闭) 典型用法 df.iloc[0:3, 1:3] df.loc['a':'c', 'col1':'col3'] 错误类型 超出范围时报 IndexError 标签不存在时报 KeyError 举例:
Python# iloc 按位置 df.iloc[0:2, 1:3] # 选第0、1行,第1、2列 # loc 按标签 df.loc['row1':'row3', 'A':'C'] # 选标签从row1到row3,列A到C(都包含结尾)总结:
- iloc 用于“按位置”取数据,适合数字索引。
- loc 用于“按标签”取数据,适合行名、列名索引。
复习:在前面我们已经学习了Pandas基础,知道利用Pandas读取csv数据的增删查改,今天我们要学习的就是探索性数据分析,主要介绍如何利用Pandas进行排序、算术计算以及计算描述函数describe()的使用。
1 第一章:探索性数据分析¶
- 1.6 了解你的数据吗?整体思路 在这一部分,你会从几个小任务出发,体会「探索性数据分析(EDA)」的核心思路: 通过排序、算术运算和描述性统计,逐步提出问题、验证直觉、发现数据中的模式。
- 1.6.1 任务一:用 DataFrame 练习排序(升序) 在这一部分,你会用
np.arange()和pd.DataFrame()手动构造一个小数据表,学习:- 如何设置行索引和列索引;
- 如何使用
sort_values()、sort_index()按不同维度进行排序;- 理解按「数据内容」排序 vs 按「行/列标签」排序的区别。
- 1.6.2 任务二:按票价和年龄对泰坦尼克号乘客排序(降序) 在这一部分,你会对真实的泰坦尼克号数据用
sort_values(by=['票价', '年龄'], ascending=False)做多列排序,并尝试:- 观察票价高的乘客在生存上的差异;
- 练习从排序结果中总结出「业务含义」而不只是看代码输出。
- 1.6.3 任务三:DataFrame 之间的算术计算与对齐 在这一部分,你会创建两个有重叠/不完全相同行列标签的 DataFrame,并用
frame1_a + frame1_b等操作,理解:- Pandas 算术运算如何按「行列标签」自动对齐;
- 没有对齐上的位置为什么会变成
NaN;- 算术运算不仅是“加减乘除”,更是「自动对齐 + 缺失值处理」的一部分。
- 1.6.4 任务四:计算泰坦尼克号上“最大家族人数” 在这一部分,你会通过
text['兄弟姐妹个数'] + text['父母子女个数']来构造“家族规模”这一新特征,并用max()找出船上最大家族的人数,体验:- 如何通过列之间的运算构造新特征;
- 如何用一个简单指标(家族人数)帮助理解数据中的人物关系。
- 1.6.5 任务五:用
describe()获取数据的基本统计信息 在这一部分,你会对一个带缺失值的小型 DataFrame 使用describe(),并理解:count, mean, std, min, 25%, 50%, 75%, max各统计量的含义;- 为什么
describe()默认只统计数值型列;- 如何通过
.T转置让结果更方便阅读。- 1.6.6 任务六:分析票价和“父母子女个数”的统计特征 在这一部分,你会对真实的泰坦尼克号数据使用:
text['票价'].describe()分析票价分布和波动情况;text['父母子女个数'].describe()、(text['父母子女个数'] != 0).sum()观察有家属同行的乘客数量;info()、value_counts()、nunique()等函数,快速摸清数据的列类型、缺失情况、类别分布和唯一值数量。- 本章小结:从函数到“分析思维” 在这一部分,你会意识到:
- 探索性分析不仅是熟悉 API,更重要的是学会从结果中提出问题;
- 为后续的数据清洗和建模打下「理解数据」的基础
开始之前,导入numpy、pandas包和数据¶
# 载入之前保存的train_chinese.csv数据,关于泰坦尼克号的任务,我们就使用这个数据
text = pd.read_csv('train_chinese.csv')
text.head()
1.6 了解你的数据吗?¶
教材《Python for Data Analysis》第五章
1.6.1 任务一:利用Pandas对示例数据进行排序,要求升序¶
# 具体请看《利用Python进行数据分析》第五章 排序和排名 部分
#自己构建一个都为数字的DataFrame数据
frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
index=['2', '1'],
columns=['d', 'a', 'b', 'c'])
frame
【代码解析】
pd.DataFrame() :创建一个DataFrame对象
np.arange(8).reshape((2, 4)) :
- 生成一个 2 行 4 列的二维数组,第 1 行是 0,1,2,3,第 2 行是 4,5,6,7。
- 并重塑为2行4列的二维数组,作为DataFrame的数据内容。
index=['2', '1'] :DataFrame 对象的行索引;
columns=['d', 'a', 'b', 'c'] :DataFrame 对象的列索引。
# 大多数时候我们都是想根据列的值来排序,所以,将你构建的DataFrame中的数据根据某一列,升序排列
frame.sort_values(by='c', ascending=True)
可以看到sort_values这个函数中by参数指向要排列的列,ascending参数指向排序的方式(升序还是降序)
ascending=True:指定排序方式为升序(从小到大)。
注意:原始的 frame 不会被修改,除非加上 inplace=True 参数。
【总结】下面将不同的排序方式做一个小总结
下面对这几种排序方式进行对比分析:
Pythonframe.sort_values(by='c', ascending=True) # 按列 'c' 的值升序排序 frame.sort_index() # 按行索引升序排序 frame.sort_index(axis=1) # 按列索引升序排序 frame.sort_index(axis=1, ascending=False) # 按列索引降序排序 frame.sort_values(by=['a', 'c'], ascending=False) # 先按 'a',再按 'c',都降序排序
1.
frame.sort_values(by='c', ascending=True)¶
- 排序对象:数据内容(某一列的值)
- 排序依据:先比较
'c'列的值,值小的排前面- 常用场景:想按某一列的实际数据大小排序
2.
frame.sort_index()¶
- 排序对象:行索引(index)
- 排序依据:行标签(如 '1', '2', ...)的字母或数字顺序
- 常用场景:想让行的顺序变得有序(如从小到大)
3.
frame.sort_index(axis=1)¶
- 排序对象:列索引(columns)
- 排序依据:列标签(如 'a', 'b', ...)的字母或数字顺序
- 常用场景:让列的顺序变得有序(如从 a 到 z)
4.
frame.sort_index(axis=1, ascending=False)¶
- 排序对象:列索引(columns)
- 排序依据:列标签的逆序(如 z 到 a)
- 常用场景:想让列从大到小排列
5.
frame.sort_values(by=['a', 'c'], ascending=False)¶
- 排序对象:数据内容(多列的值)
- 排序依据:先按
'a'列降序排,如果'a'相同再按'c'列降序排- 常用场景:需要多重排序(比如先按成绩,再按年龄)
总结¶
sort_index是按标签(行或列名)排序,适合整理表头顺序。sort_values是按数据内容排序,适合分析和查找极值、排名等。by=['a', 'c']支持多列排序,优先级从左到右。axis=1控制是对行还是对列排序(0为行,1为列)。ascending控制升序还是降序。实际应用时,按内容排序更常用于数据分析,按索引排序更常用于数据展示和整理。
1.6.2 任务二:对泰坦尼克号数据(trian.csv)按票价和年龄两列进行综合排序(降序排列),从数据中你能发现什么¶
'''
在开始我们已经导入了train_chinese.csv数据,而且前面我们也学习了导入数据过程,根据上面学习,我们直接对目标列进行排序即可
head(20) : 读取前20条数据
'''
text.sort_values(by=['票价', '年龄'], ascending=False).head(20)
【思考】排序后,如果我们仅仅关注年龄和票价两列。根据常识我知道发现票价越高的应该客舱越好,所以我们会明显看出,票价前20的乘客中存活的有14人,这是相当高的一个比例,那么我们后面是不是可以进一步分析一下票价和存活之间的关系,年龄和存活之间的关系呢?当你开始发现数据之间的关系了,数据分析就开始了。
当然,这只是我的想法,你还可以有更多想法,欢迎写在你的学习笔记中。
1.6.3 任务三:利用Pandas进行算术计算,计算两个DataFrame数据相加结果¶
# 具体请看《利用Python进行数据分析》第五章 算术运算与数据对齐 部分
#建立一个例子
frame1_a = pd.DataFrame(np.arange(9.).reshape(3, 3),
columns=['a', 'b', 'c'],
index=['one', 'two', 'three'])
frame1_b = pd.DataFrame(np.arange(12.).reshape(4, 3),
columns=['a', 'e', 'c'],
index=['first', 'one', 'two', 'second'])
frame1_a
【提醒】两个DataFrame相加后,会返回一个新的DataFrame,对应的行和列的值会相加,没有对应的会变成空值NaN。当然,DataFrame还有很多算术运算,如减法,除法等,有兴趣的同学可以看《利用Python进行数据分析》第五章 算术运算与数据对齐 部分,多在网络上查找相关学习资料。
1.6.4 任务四:通过泰坦尼克号数据如何计算出在船上最大的家族有多少人?¶
'''
还是用之前导入的chinese_train.csv如果我们想看看在船上,最大的家族有多少人(‘兄弟姐妹个数’+‘父母子女个数’),我们该怎么做呢?
'''
max(text['兄弟姐妹个数'] + text['父母子女个数'])
是的,如上,很简单,我们只需找出兄弟姐妹个数和父母子女个数之和最大的数就行,先让这两列相加返回一个Series,然后用max函数求出最大值,当然你还可以想出很多方法和思考角度,欢迎你来说出你的看法。
1.6.5 任务五:学会使用Pandas describe()函数查看数据基本统计信息¶
#(1) 关键知识点示例做一遍(简单数据)
# 具体请看《利用Python进行数据分析》第五章 汇总和计算描述统计 部分
#建立一个例子
frame2 = pd.DataFrame([[1.4, np.nan],
[7.1, -4.5],
[np.nan, np.nan],
[0.75, -1.3]
], index=['a', 'b', 'c', 'd'], columns=['one', 'two'])
frame2
# 调用 describe 函数,观察frame2的数据基本信息
frame2.describe()
'''
count : 该列中非空(非 NaN)数据的数量。
mean : 样本数据的平均值
std : 样本数据的标准差
min : 样本数据的最小值
25% : 样本数据25%的时候的值
50% : 样本数据50%的时候的值
75% : 样本数据75%的时候的值
max : 样本数据的最大值
'''
# frame2.describe().T
# .T 是 DataFrame 的转置(transpose)操作,会把行和列互换。
1.6.6 任务六:分别看看泰坦尼克号数据集中 票价、父母子女 这列数据的基本统计数据,你能发现什么?¶
【思考】从上面数据我们可以看出, 一共有891个票价数据, 平均值约为:32.20, 标准差约为49.69,说明票价波动特别大, 25%的人的票价是低于7.91的,50%的人的票价低于14.45,75%的人的票价低于31.00, 票价最大值约为512.33,最小值为0。 当然,这只是我的想法,你还可以有更多想法,欢迎写在你的学习笔记中。
查看数据基本信息 info():非常强大,可以一次性看到: 每一列的名称 非空值的数量(可以间接看出缺失值) 数据类型(int, float, object 等) 内存占用
统计唯一值value_counts():统计某一列中每个值出现的次数(非常适合分类数据,比如性别、登船港口)
nunique():统计每一列有多少个不同的值。
【思考】有更多想法,欢迎写在你的学习笔记中。
【总结】本节中我们通过Pandas的一些内置函数对数据进行了初步统计查看,这个过程最重要的不是大家得掌握这些函数,而是看懂从这些函数出来的数据,构建自己的数据分析思维,这也是第一章最重要的点,希望大家学完第一章能对数据有个基本认识,了解自己在做什么,为什么这么做,后面的章节我们将开始对数据进行清洗,进一步分析。