numpy与pandas
大模型技术之numpy与pandas
第 1 章 环境搭建
1.1 Anaconda
1.1.1 什么是Anaconda
Anaconda官网地址:https://www.anaconda.com/
简单来说,Anaconda = Python + 包和环境管理器(Conda)+ 常用库 + 集成工具。它适合那些需要快速搭建数据科学或机器学习开发环境的用户。Anaconda和Python相当于是汽车和发动机的关系,安装Anaconda后,就像买了一台车,无需自己去安装发动机和其他零配件,而Python作为发动机提供Anaconda工作所需的内核。
Anaconda包及其依赖项和环境的管理工具为 conda 命令,与传统的 Python pip 工具相比Anaconda的conda可以更方便地在不同环境之间进行切换,环境管理较为简单。
为什么选择 Anaconda?
-
方便安装: 安装 Anaconda 就像安装一个应用程序一样简单,它为您预先安装好了许多常用的工具,无需单独配置。
-
包管理器: Anaconda 包含一个名为 Conda 的包管理器,用于安装、更新和管理软件包。Conda 不仅限于 Python,还支持多种其他语言的包管理。
-
环境管理: 使用 Anaconda,您可以轻松地创建和管理多个独立的 Python 环境,比如可以安装 python2 和 python3 环境,然后实现自由切换。这对于在不同项目中使用不同的库和工具版本非常有用,以避免版本冲突。
-
集成工具和库: Anaconda 捆绑了许多用于数据科学、机器学习和科学计算的重要工具和库,如 NumPy、Pandas、Matplotlib、SciPy、Scikit-learn 等。
-
Jupyter 笔记本: Jupyter 是一个交互式的计算环境,支持多种编程语言,但在 Anaconda 中主要用于 Python。它允许用户创建和共享包含实时代码、方程式、可视化和叙述文本的文档。
-
Spyder 集成开发环境: Anaconda 中集成了 Spyder,这是一个专为科学计算和数据分析而设计的开发环境,具有代码编辑、调试和数据可视化等功能。
-
跨平台性: Anaconda可在Windows、macOS和 Linux等操作系统上运行,使其成为一个跨平台的解决方案。
-
社区支持: Anaconda 拥有庞大的社区,用户可以在社区论坛上获取帮助、分享经验和解决问题。
1.1.2 Anaconda下载
进入官网,点击右上角Free Download 这部分不详写 搜一下都有的
若先前安装时未勾选添加环境变量,则需找到先前安装时设定的Anaconda安装路径。此处为“D:\ProgramFiles\anaconda3”,需对照自己的安装路径,在环境变量中点击“新建”依次添加如下路径:
D:\ProgramFiles\anaconda3(Anaconda安装路径)
D:\ProgramFiles\anaconda3\Library\mingw-w64\bin(Anaconda安装路径\Library\mingw-w64\bin)
D:\ProgramFiles\anaconda3\Library\usr\bin(Anaconda安装路径\Library\usr\bin)
D:\ProgramFiles\anaconda3\Library\bin(Anaconda安装路径\Library\bin)
D:\ProgramFiles\anaconda3\Scripts(Anaconda安装路径\Scripts)
按下“Win+R”,输入“cmd”,点击确定,打开命令提示符
输入conda info查看conda信息,输入python --version查看Python版本。Anaconda安装成功
1 | C:\Users\Lenovo>conda info |
因conda默认源服务器在海外,使用默认源下载第三方库时可能由于网络问题导致下载失败,故在此配置国内源。在命令提示符中执行conda config --set show_channel_urls yes,会在“C:\Users(用户)\用户名”路径下生成“.condarc”文件
双击“.condarc”文件,选择使用记事本打开,删除其中所有内容,并粘贴如下内容之后保存,这样就配置好了国内清华源
1 | channels: |
1 | C:\Users\Lenovo>conda info |
使用本地Jupyter
命令提示符中输入jupyter lab或jupyter notebook,会弹出浏览器页面直接进入主页面
pycharm集成Jupyter
conda env list
Jupyter快捷键
Ø esc:从输入模式退出到命令模式
Ø a:在当前cell上面创建一个新的cell
Ø b:在当前cell 下面创建一个新的cell
Ø dd:删除当前cell
Ø m:切换到markdown模式
Ø y:切换到code模式
Ø ctrl+回车:运行cell
Ø shift +回车:运行当前cell并创建一个新的cell
第 2 章 Numpy
1.1.什么是numpy
numpy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象、各种派生对象(例如掩码数组和矩阵)以及用于对数组进行快速操作的各种方法,包括数学、逻辑、形状操作、排序、选择、I/O 、离散傅里叶变换、基本线性代数、基本统计运算、随机模拟等等。
numpy的部分功能如下:
Ø ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。
Ø 用于对整组数据进行快速运算的标准数学函数(无需编写循环)。
Ø 用于读写磁盘数据的工具以及用于操作内存映射文件的工具。
Ø 线性代数、随机数生成以及傅里叶变换功能。
Ø 用于集成由C、C++、Fortran等语言编写的代码的API。
ndarray的限制
大多数numpy数组都有一些限制:
Ø 数组的所有元素必须具有相同的数据类型。
Ø 一旦创建,数组的总大小就不能改变。
Ø 形状必须是“矩形”,而不是“锯齿状”。例如二维数组的每一行必须具有相同的列数。
ndarray的属性
1)先安装numpy包
2)如果在Pycharm中加载不出来,可以通过如下命令安装
1 | conda activate python-2025-conda |
2)ndarray属性案例
1 | import numpy as np # 导入numpy |
1.2 ndarray的创建方式
1.2.1 array()与asarray()
array():将输入数据转换为ndarray,会进行copy。
asarray():将输入数据转换为ndarray,如果输入本身是ndarray则不会进行copy。
数组的创建方式
“”"
array:将输入的数据转换为ndarray,会进行copy
asarray:将输入的数据转换为ndarray,如果输入本身是ndarray,则不会进行copy
“”"
1 | import numpy as np |
元数据地址为:2323645134208
arr1地址为:2323607245360数组数据为:[1 2 3]
arr2地址为:2323645220400
arr2数组数据为:[1 2 3]
arr3地址为:2323607245360
arr3数组数据为:[1 2 3]
1.2.2 zeros()、ones()、empty()与zeros_like()、ones_like()、empty_like()
zeros():返回给定形状和类型的新数组,用0填充。
ones():返回给定形状和类型的新数组,用1填充。
empty():返回给定形状和类型的未初始化的新数组。
需要注意的是,np.empty 并不保证数组元素被初始化为 0,它只是分配内存空间,数组中的元素值是未初始化的,可能是内存中的任意值。
上述3个方法创建的数组元素类型默认都是float64。
zeros_like():返回与给定数组具有相同形状和类型的0新数组。
ones_like():返回与给定数组具有相同形状和类型的1新数组。
empty_like():返回与给定数组具有相同形状和类型的未初始化的新数组。
1 | arr1 = np.zeros((2, 5)) # 创建全0数组 |
注意:这里元素间的分隔符是空格,而不是小数点 .
1.2.3 full()与full_like()
full():返回给定形状和类型的新数组,用指定的值填充。
full_like():返回与给定数组具有相同形状和类型的用指定值填充的新数组。
1 | arr1 = np.full((2, 3), 6) |
1.2.4 arange()
arange():返回在给定范围内用均匀间隔的值填充的一维数组。
1 | arr1 = np.arange(0, 10, 2) |
1.2.5 linspace()与logspace()
linspace():返回指定范围和元素个数的等差数列。数组元素类型为浮点型。
logspace():返回指定指数范围、元素个数、底数的等比数列。
1 | arr1 = np.linspace(start=0, stop=10, num=5) |
默认endpoint=True时
如果把0到10看作一条线段,相当于用5个点将这条线段分成了4段,要计算每段的长度(即相邻元素的间隔),用总长度 (stop - start) 除以段数 (num - 1) ,得到间隔为 10-0 / 4 = 2.5。这样从起始点 0 开始,每次加上间隔 2.5 就能依次得到序列中的元素:0、2.5、5、7.5、10 。
若 endpoint=False 的情况
当 endpoint=False 时,意味着 stop 这个值不包含在生成的序列中,此时 [start, stop) 区间相当于一条右端点空心(不包含 stop 这个点)的线段。我们在这条线段上放置 num 个点进行划分,每一个点都会划分出一个新的区间段。比如,放 1 个点会把线段分成 1 段,放 2 个点会分成 2 段,放 num 个点就会分成 num 段,段数就等于点数 num,计算间隔的公式就变为 (stop - start) / num 。
1.2.6 创建随机数数组
random.rand():返回给定形状的数组,用 [0, 1) 上均匀分布的随机样本填充。
random.randint():返回给定形状的数组,用从低位(包含)到高位(不包含)上均匀分布的随机整数填充。
random.uniform():返回给定形状的数组,用从低位(包含)到高位(不包含)上均匀分布的随机浮点数填充。
random.randn():返回给定形状的数组,用标准正态分布(均值为0,标准差为1)的随机样本填充。
1 | arr1 = np.random.rand(2, 3) |
1.2.7 matrix()
matrix为ndarray的子类,只能生成二维的矩阵。
1 | arr1 = np.matrix("1 2; 3 4") |
1.3 ndarray的数据类型
| 数据类型 | 类型代码 | 说明 |
|---|---|---|
| bool | ? | 布尔类型 |
| int8、uint8 int16、uint16 int32、uint32 int64、uint64 | i1,u1 i2,u2 i4,u4 i8,u8 | 有符号、无符号的8位(1字节)整型 有符号、无符号的16位(2字节)整型 有符号、无符号的32位(4字节)整型 有符号、无符号的64位(8字节)整型 |
| float16 float32 float64 | f2 f4或f f8或d | 半精度浮点型 单精度浮点型 双精度浮点型 |
| complex64 complex128 | c8 c16 | 用两个32位浮点数表示的复数 用两个64位浮点数表示的复数 |
创建数组时可以使用dtype参数指定元素类型:
1 | arr1 = np.array([1, 2, 3], dtype=np.float64) |
1.4 ndarray切片和索引
ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。
可以通过内置的slice函数,或者冒号设置start, stop及step参数进行切片,从原数组中切割出一个新数组。
1 | import numpy as np |
1.5 numpy常用函数
1.5.1 基本函数
| 函数 | 说明 |
|---|---|
| np.abs() | 元素的绝对值,参数是 number 或 array |
| np.ceil() | 向上取整,参数是 number 或 array |
| np.floor() | 向下取整,参数是 number 或 array |
| np.rint() | 四舍五入,参数是 number 或 array |
| np.isnan() | 判断元素是否为NaN(Not a Number) ,参数是 number 或 array |
| np.multiply() | 元素相乘,参数是 number 或 array。如果第二个参数传递的是number,原数组中所有元素乘以这个数字,返回新的数组;如果第二个参数也是一个数组,是将两个数组中对应位置的元素相乘,返回一个新的数组,其形状与输入数组相同。 |
| np.divide() | 元素相除,参数是 number 或 array |
| np.where(condition, x, y) | 三元运算符,x if condition else y |
1 | arr1 = np.random.randn(2, 3) |
1.5.2 统计函数
| 函数 | 说明 |
|---|---|
| np.mean() | 所有元素的平均值 |
| np.sum() | 所有元素的和 |
| np.max() | 所有元素的最大值 |
| np.min() | 所有元素的最小值 |
| np.std() | 所有元素的标准差 |
| np.var() | 所有元素的方差 |
| np.argmax() | 最大值的下标索引值 |
| np.argmin() | 最小值的下标索引值 |
| np.cumsum() | 返回一个一维数组,每个元素都是之前所有元素的累加和 |
| np.cumprod() | 返回一个一维数组,每个元素都是之前所有元素的累乘积 |
多维数组在计算时默认计算全部维度,可以使用axis参数指定按某一维度为轴心统计,axis=0按列统计、axis=1按行统计。
1 | arr1 = np.random.randint(1, 5, (2, 3)) |
1.5.3 比较函数
| 函数 | 说明 |
|---|---|
| np.any() | 至少有一个元素满足指定条件,就返回True |
| np.all() | 所有的元素都满足指定条件,才返回True |
1 | arr1 = np.array([1, 2, 3, 4, 5]) |
1.5.4 排序函数
ndarray.sort():就地排序(直接修改原数组)。
1 | arr1 = np.random.randint(0, 10, (3, 3)) |
axis:指定排序的轴。默认值为 -1,表示沿着最后一个轴进行排序。在二维数组中,axis = 0 表示按列排序,axis = 1 表示按行排序。
在 NumPy 中,轴是对数组维度的一种抽象描述。对于多维数组,每个维度都对应一个轴,轴的编号从 0 开始。对于二维数组,它有两个轴:
轴 0:代表垂直方向,也就是行的方向。可以把二维数组想象成一个表格,轴 0 就像是表格中从上到下的行索引方向对列数据排序,所以axis=0表示按列排序。
轴 1:代表水平方向,也就是列的方向。就像是表格中从左到右的列索引方向对行数据进行排序,所以axis=1表示按行排序。
np.sort():返回排序后的副本(创建新的数组)。
1 | arr1 = np.random.randint(0, 10, (3, 3)) |
1.5.5 去重函数
np.unique():计算唯一值并返回有序结果。
1 | arr1 = np.random.randint(0, 5, (3, 3)) |
1.6 基本运算
numpy中的数组不用编写循环即可执行批量运算,称之为矢量化运算。
大小相等的数组之间的任何算术运算都会将运算应用到元素级。
1 | arr1 = np.array([[1, 2, 3], [4, 5, 6]]) |
数组与标量的算术运算会将标量值传播到各个元素,不同大小的数组之间的运算叫做广播。
1 | arr1 = np.array([[1, 2, 3], [4, 5, 6]]) |
广播机制是 NumPy 中一个强大的特性,它允许在不同形状的数组之间进行元素级运算。广播机制的规则如下:
- 规则1:如果俩个数组的维度数不相同,那么小维度数组的形状将会在最左边补1。
1 | import numpy as np |
- 规则2:如果俩个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度大小(元素个数)为1的维度开始扩展 ,(维度必须是1开始)直到所有维度都一样, 以匹配另一个数组的形状。
1 | import numpy as np |
- 规则3:如果俩个数组的形状在任何一个维度上都不匹配,并且没有任何一个维度大小等于1,那么会引发异常。
1 | import numpy as np |
1.7 矩阵乘法
通过*运算符和np.multiply()对两个数组相乘进行的是对位乘法而非矩阵乘法运算。
1 | arr1 = np.array([[1, 2, 3], [4, 5, 6]]) |
使用np.dot()、ndarray.dot()、@可以进行矩阵乘法运算。
1 | arr1 = np.array([[1, 2, 3], [4, 5, 6]]) |
矩阵乘法的规则是:结果矩阵中第 i 行第 j 列的元素等于第一个矩阵的第 i 行与第二个矩阵的第 j 列对应元素乘积之和。
结果矩阵第一行第一列的元素:
计算 arr1 的第一行 [1, 2, 3] 与 arr2 的第一列 [6, 4, 2] 对应元素乘积之和,即 16 + 24 + 3*2 = 6 + 8 + 6 = 20。
结果矩阵第一行第二列的元素:
计算 arr1 的第一行 [1, 2, 3] 与 arr2 的第二列 [5, 3, 1] 对应元素乘积之和,即 15 + 23 + 3*1 = 5 + 6 + 3 = 14。
结果矩阵第二行第一列的元素:
计算 arr1 的第二行 [4, 5, 6] 与 arr2 的第一列 [6, 4, 2] 对应元素乘积之和,即 46 + 54 + 6*2 = 24 + 20 + 12 = 56。
结果矩阵第二行第二列的元素:
计算 arr1 的第二行 [4, 5, 6] 与 arr2 的第二列 [5, 3, 1] 对应元素乘积之和,即 45 + 53 + 6*1 = 20 + 15 + 6 = 41。
所以,手动计算得到的结果矩阵是 [[20, 14], [56, 41]]。
第 3 章 Pandas
3.1 什么是Pandas
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。
Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。
Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。
用得最多的pandas对象是Series,一个一维的标签化数组对象,另一个是DataFrame,它是一个面向列的二维表结构
pandas兼具numpy高性能的数组计算功能以及电子表格和关系型数据库(如SQL)灵活的数据处理功能。它提供了复杂精细的索引功能,能更加便捷地完成重塑、切片和切块、聚合以及选取数据子集等操作。
pandas功能:
有标签轴的数据结构
在数据结构中,每个轴都被赋予了特定的标签,这些标签用于标识和引用轴上的数据元素,使得数据的组织、访问和操作更加直观和方便
-
集成时间序列功能。
-
相同的数据结构用于处理时间序列数据和非时间序列数据。
-
保存元数据的算术运算和压缩。
-
灵活处理缺失数据。
-
合并和其它流行数据库(例如基于SQL的数据库)的关系操作。
pandas这个名字源于panel data(面板数据,这是多维结构化数据集在计量经济学中的术语)以及Python data analysis(Python数据分析)。
3.2 Pandas数据结构-Series
Series 是 Pandas 中的一个核心数据结构,类似于一个一维的数组,具有数据和索引。
Series 可以存储任何数据类型(整数、浮点数、字符串等),并通过标签(索引)来访问元素。Series 的数据结构是非常有用的,因为它可以处理各种数据类型,同时保持了高效的数据操作能力,比如可以通过标签来快速访问和操作数据。
1)Series 特点:
Ø 一维数组:Series 中的每个元素都有一个对应的索引值。
Ø 索引: 每个数据元素都可以通过标签(索引)来访问,默认情况下索引是从 0 开始的整数,但你也可以自定义索引。
Ø 数据类型: Series 可以容纳不同数据类型的元素,包括整数、浮点数、字符串、Python 对象等。
Ø 大小不变性:Series 的大小在创建后是不变的,但可以通过某些操作(如 append 或 delete)来改变。
Ø 操作:Series 支持各种操作,如数学运算、统计分析、字符串处理等。
Ø 缺失数据:Series 可以包含缺失数据,Pandas 使用NaN(Not a Number)来表示缺失或无值。
Ø 自动对齐:当对多个 Series 进行运算时,Pandas 会自动根据索引对齐数据,这使得数据处理更加高效。
我们可以使用 Pandas 库来创建一个 Series 对象,并且可以为其指定索引(Index)、名称(Name)以及值(Values):
1.2.2 Series的创建
1)先安装pandas包,如果在Pycharm中加载不出来,可以通过如下命令安装
conda activate python-2025-conda
(python-2025-conda)xxx conda install pandas
2)直接通过列表创建Series
1 | import pandas as pd |
Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。
3)通过列表创建Series时指定索引
1 | s = pd.Series([4, 7, -5, 3], index=["a", "b", "c", "d"]) |
4)通过列表创建Series时指定索引和名称
1 | s = pd.Series([4, 7, -5, 3], index=["a", "b", "c", "d"],name="hello_python") |
5)直接通过字典创建Series
1 | dic = {"a": 4, "b": 7, "c": -5, "d": 3} |
1.2.3 Series的常用属性
| 属性 | 说明 |
|---|---|
| index | Series的索引对象 |
| values | Series的值 |
| ndim | Series的维度 |
| shape | Series的形状 |
| size | Series的元素个数 |
| dtype或dtypes | Series的元素类型 |
| name | Series的名称 |
| loc[] | 显式索引,按标签索引或切片 |
| iloc[] | 隐式索引,按位置索引或切片 |
| at[] | 使用标签访问单个元素 |
| iat[] | 使用位置访问单个元素 |
1 | import pandas as pd |
1.2.4 Series的常用方法
| 方法 | 说明 |
|---|---|
| head() | 查看前n行数据,默认5行 |
| tail() | 查看后n行数据,默认5行 |
| isin() | 元素是否包含在参数集合中 |
| isna() | 元素是否为缺失值(通常为 NaN 或 None) |
| sum() | 求和,会忽略 Series 中的缺失值 |
| mean() | 平均值 |
| min() | 最小值 |
| max() | 最大值 |
| var() | 方差 |
| std() | 标准差 |
| median() | 中位数 |
| mode() | 众数(出现频率最高的值),如果有多个值出现的频率相同且都是最高频率,这些值都会被包含在返回的 Series 中 |
| quantile(q,interpolation) | 指定位置的分位数 q的取值范围是 0 到 1 之间的浮点数或浮点数列表,如quantile(0.5)表示计算中位数(即第 50 百分位数); interpolation:指定在计算分位数时,如果分位数位置不在数据点上,采用的插值方法。默认值是线性插值 ‘linear’,还有其他可选值如 ‘lower’、‘higher’、‘midpoint’、‘nearest’ 等 |
| describe() | 常见统计信息 |
| value_count() | 每个元素的个数 |
| count() | 非缺失值元素的个数,如果要包含缺失值,用len() |
| drop_duplicates() | 去重 |
| unique() | 去重后的数组 |
| nunique() | 去重后元素个数 |
| sample() | 随机采样 |
| sort_index() | 按索引排序 |
| sort_values() | 按值排序 |
| replace() | 用指定值代替原有值 |
| to_frame() | 将Series转换为DataFrame |
| equals() | 判断两个Series是否相同 |
| keys() | 返回Series的索引对象 |
| corr() | 计算与另一个Series的相关系数 默认使用皮尔逊相关系数(Pearson correlation coefficient)来计算相关性。要求参与比较的数组元素类型都是数值型。 当相关系数为 1 时,表示两个变量完全正相关,即一个变量增加,另一个变量也随之增加。 当相关系数为 -1 时,表示两个变量完全负相关,即一个变量增加,另一个变量随之减少。 当相关系数为 0 时,表示两个变量之间不存在线性相关性。 例如,分析某地区的气温和冰淇淋销量之间的关系 |
| cov() | 计算与另一个Series的协方差 |
| hist() | 绘制直方图,用于展示数据的分布情况。它将数据划分为若干个区间(也称为 “bins”),并统计每个区间内数据的频数。 需要安装matplotlib包 |
| items() | 获取索引名以及值 |
1 | import pandas as pd |
1.2.5 Series的布尔索引
可以使用布尔索引从Series中筛选满足某些条件的值。
1 | s = pd.Series({"a": -1.2, "b": 3.5, "c": 6.8, "d": 2.9}) |
1.2.6 Series的运算
1)Series与标量运算
标量会与每个元素进行计算。
1 | s = pd.Series({"a": -1.2, "b": 3.5, "c": 6.8, "d": 2.9}) |
2)Series与Series运算
会根据标签索引进行对位计算,索引没有匹配上的会用NaN填充。
1 | s1 = pd.Series([1, 1, 1, 1]) |
1.3 Pandas数据结构-DataFrame
DataFrame是Pandas 中的另一个核心数据结构,类似于一个二维的表格或数据库中的数据表。它是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值),既有行索引也有列索引。

DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。它可以被看做由Series组成的字典(共同用一个索引)。提供了各种功能来进行数据访问、筛选、分割、合并、重塑、聚合以及转换等操作,广泛用于数据分析、清洗、转换、可视化等任务。

1.3.1 DataFrame的创建
1)直接通过字典创建DataFrame
1 | df = pd.DataFrame({"id": [101, 102, 103], "name": ["张三", "李四", "王五"], "age": [20, 30, 40]}) |
2)通过字典创建时指定列的顺序和行索引
1 | df = pd.DataFrame( |
1.3.2 DataFrame的常用属性
| 属性 | 说明 |
|---|---|
| index | DataFrame的行索引 |
| columns | DataFrame的列标签 |
| values | DataFrame的值 |
| ndim | DataFrame的维度 |
| shape | DataFrame的形状 |
| size | DataFrame的元素个数 |
| dtypes | DataFrame的元素类型 |
| T | 行列转置 |
| loc[] | 显式索引,按行列标签索引或切片 |
| iloc[] | 隐式索引,按行列位置索引或切片 |
| at[] | 使用行列标签访问单个元素 |
| iat[] | 使用行列位置访问单个元素 |
1 | import pandas as pd |
1.3.3 DataFrame的常用方法
| 方法 | 说明 |
|---|---|
| head() | 查看前n行数据,默认5行 |
| tail() | 查看后n行数据,默认5行 |
| isin() | 元素是否包含在参数集合中 |
| isna() | 元素是否为缺失值 |
| sum() | 求和 |
| mean() | 平均值 |
| min() | 最小值 |
| max() | 最大值 |
| var() | 方差 |
| std() | 标准差 |
| median() | 中位数 |
| mode() | 众数 |
| quantile() | 指定位置的分位数,如quantile(0.5) |
| describe() | 常见统计信息 |
| info() | 基本信息 |
| value_counts() | 每个元素的个数 |
| count() | 非空元素的个数 |
| drop_duplicates() | 去重 |
| sample() | 随机采样 |
| replace() | 用指定值代替原有值 |
| equals() | 判断两个DataFrame是否相同 |
| cummax() | 累计最大值 |
| cummin() | 累计最小值 |
| cumsum() | 累计和 |
| cumprod() | 累计积 |
| diff() | 一阶差分,对序列中的元素进行差分运算,也就是用当前元素减去前一个元素得到差值,默认情况下,它会计算一阶差分,即相邻元素之间的差值。参数: periods:整数,默认为 1。表示要向前或向后移动的周期数,用于计算差值。正数表示向前移动,负数表示向后移动。 axis:指定计算的轴方向。0 或 ‘index’ 表示按列计算,1 或 ‘columns’ 表示按行计算,默认值为 0。 |
| sort_index() | 按行索引排序 |
| sort_values() | 按某列的值排序,可传入列表来按多列排序,并通过ascending参数设置升序或降序 |
| nlargest() | 返回某列最大的n条数据 |
| nsmallest() | 返回某列最小的n条数据 |
在Pandas的 DataFrame 方法里,axis 是一个非常重要的参数,它用于指定操作的方向。
axis 参数可以取两个主要的值,即 0 或 ‘index’,以及 1 或 ‘columns’ ,其含义如下:
Ø axis=0 或 axis=‘index’:表示操作沿着行的方向进行,也就是对每一列的数据进行处理。例如,当计算每列的均值时,就是对每列中的所有行数据进行计算。
Ø axis=1 或 axis=‘columns’:表示操作沿着列的方向进行,也就是对每行的数据进行处理。例如,当计算每行的总和时,就是对每行中的所有列数据进行计算。
1 | import pandas as pd |
1.3.4 DataFrame的布尔索引
可以使用布尔索引从DataFrame中筛选满足某些条件的行。
1 | df = pd.DataFrame( |
1.3.5 DataFrame的运算
1)DataFrame与标量运算
标量与每个元素进行计算。
1 | df = pd.DataFrame( |
2)DataFrame与DataFrame运算
根据标签索引进行对位计算,索引没有匹配上的用NaN填充。
1 | df1 = pd.DataFrame( |
1.3.6 DataFrame的更改操作
1)设置行索引
创建DataFrame时如果不指定行索引,pandas会自动添加从0开始的索引。
1 | df = pd.DataFrame({"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"], "id": [101, 102, 103, 104]}) |
(1)通过set_index()设置行索引
1 | # df.set_index("id"):将 DataFrame df 的 "id" 列设为新的行索引(index)。 |
(2)通过reset_index()重置行索引
1 | df.reset_index(inplace=True) # 重置索引 |
2)修改行索引名和列名
(1)通过rename()修改行索引名和列名
1 | df = pd.DataFrame({"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"], "id": [101, 102, 103, 104]}) |
(2)将index和columns重新赋值
1 | df.index = ["Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ"] |
3)添加列
通过 df[“列名”] 添加列。
1 | df["phone"] = ["13333333333", "14444444444", "15555555555", "16666666666"] |
4)删除列
(1)通过 df.drop(“列名”, axis=1) 删除,也可是删除行 axis=0
1 | df.drop("phone", axis=1, inplace=True) # 删除phone,按列删除,inplace=True表示直接在原对象上修改 |
(2)通过 del df[“列名”] 删除
1 | del df["phone"] |
5)插入列
通过 insert(loc, column, value) 插入。该方法没有inplace参数,直接在原数据上修改。
1 | df.insert(loc=0, column="phone", value=df["age"] * df.index) |
1.3.7 DataFrame数据的导入与导出
1)导出数据
| 方法 | 说明 |
|---|---|
| to_csv() | 将数据保存为csv格式文件,数据之间以逗号分隔,可通过sep参数设置使用其他分隔符,可通过index参数设置是否保存行标签,可通过header参数设置是否保存列标签。 |
| to_pickle() | 如要保存的对象是计算的中间结果,或者保存的对象以后会在Python中复用,可把对象保存为.pickle文件。如果保存成pickle文件,只能在python中使用。文件的扩展名可以是.p、.pkl、.pickle。 |
| to_excel() | 保存为Excel文件,需安装openpyxl包。 |
| to_clipboard() | 保存到剪切板。 |
| to_dict() | 保存为字典。 |
| to_hdf() | 保存为HDF格式,需安装tables包。 |
| to_html() | 保存为HTML格式,需安装lxml、html5lib、beautifulsoup4包。 |
| to_json() | 保存为JSON格式。 |
| to_feather() | feather是一种文件格式,用于存储二进制对象。feather对象也可以加载到R语言中使用。feather格式的主要优点是在Python和R语言之间的读写速度要比csv文件快。feather数据格式通常只用中间数据格式,用于Python和R之间传递数据,一般不用做保存最终数据。需安装pyarrow包。 |
| to_sql() | 保存到数据库。 |
1 | import os |
2)导入数据
| 方法 | 说明 |
|---|---|
| read_csv() | 加载csv格式的数据。可通过sep参数指定分隔符,可通过index_col参数指定行索引。 |
| read_pickle() | 加载pickle格式的数据。 |
| read_excel() | 加载Excel格式的数据。 |
| read_clipboard() | 加载剪切板中的数据。 |
| read_hdf() | 加载HDF格式的数据。 |
| read_html() | 加载HTML格式的数据。 |
| read_json() | 加载JSON格式的数据。 |
| read_feather() | 加载feather格式的数据。 |
| read_sql() | 加载数据库中的数据。 |
1 | df_csv = pd.read_csv("data/df.csv", index_col="id") # 指定行索引 |
1.4 Pandas日期数据处理初识
1.4.1 to_datetime()进行日期格式转换
1)参数说明
| 参数名 | 说明 |
|---|---|
| arg | 要转换为日期时间的对象 |
| errors | ignore,raise,coerce, 默认为ignore,表示无效的解析将会返回原值 |
| dayfirst | 指定日期解析顺序。如果为True,则以日期开头解析日期,例如:“10/11/12”解析为2012-11-10。默认false |
| yearfirst | 如果为True,则以日期开头解析,例如:“10/11/12”解析为2010-11-12。如果dayfirst和yearfirst都为True,则yearfirst在前面。默认false。当日期字符串格式不明确时,指定年份是否在最前面。当日期字符串是 ‘2010/1/4’ 这种形式,由于年份是 4 位数字,pandas 能很清晰地识别出这是年份,所以即使 yearfirst 为 False,也不会影响其正确解析 |
| utc | 返回utc,即协调世界时间 |
| format | 格式化显示时间的格式,字符串,默认值为None |
| exact | 要求格式完全匹配 |
| unit | 参数的单位表示时间的单位 |
| infer_datetime_format | 如果为True且未给出格式,则尝试基于第一个非nan元素推断datetime字符串的格式,如果可以推断,则切换到更快的解析方法。在某些情况下,这可以将解析速度提高5-10倍。 |
| origin | 默认值为unix,定义参考日期1970-01-01 |
| cache | 使用唯一的已转换日期缓存来应用日期时间转换。在解析重复日期字符串时产生显著的加速。 |
2)将字符串字段转换为日期类型
1 | import pandas as pd |
1.4.2 时间属性访问器对象Series.dt,获取日期数据的年月日星期
1)获取年月日
1 | df['yy'],df['mm'],df['dd']=df['ymd'].dt.year,df['ymd'].dt.month,df['ymd'].dt.day |
2)获取星期
1 | df['week']=df['ymd'].dt.day_name() |
3)获取日期所在季度
1 | df['quarter']=df['ymd'].dt.quarter |
4)判断日期是否月底年底
1 | df['mend']=df['ymd'].dt.is_month_end |
1.4.3 to_period()获取统计周期
freq:这是 to_period() 方法最重要的参数,用于指定要转换的时间周期频率
常见的取值如下:
Ø “D”:按天周期,例如 2024-01-01 会转换为 2024-01-01 这个天的周期。
Ø “W”:按周周期,通常以周日作为一周的结束,比如日期落在某一周内,就会转换为该周的周期表示。
Ø “M”:按月周期,像 2024-05-15 会转换为 2024-05。
Ø “Q”:按季度周期,一年分为四个季度,日期会转换到对应的季度周期,例如 2024Q2 。
Ø “A” 或 “Y”:按年周期,如 2024-07-20 会转换为 2024 。
1 | df["ystat"] = df["ymd"].dt.to_period("Y") |
1.5 DataFrame数据分析入门
1.5.1 加载数据集
使用weather(天气)数据集。其中包含6个字段:
Ø date:日期,年-月-日格式。
Ø precipitation:降水量。
Ø temp_max:最高温度。
Ø temp_min:最低温度。
Ø wind:风力。
Ø weather:天气状况。
1 | import pandas as pd |
pandas与Python常用数据类型对照:
| pandas****类型 | Python****类型 | 说明 |
|---|---|---|
| object | string | 字符串类型 |
| int64 | int | 整型 |
| float64 | float | 浮点型 |
| datetime64 | datetime | 日期时间类型 |
1.5.2 查看部分数据
1)通过head()、tail()获取前n行或后n行
1 | print(df.head()) |
2)获取一列或多列数据
(1)加载一列数据
1 | df_date_series = df["date"] # 返回的是Series |
操作方式 返回类型 数据结构 适用场景 df["date"]Series一维 单列操作(如 .apply(),.str方法)df[["date"]]DataFrame二维 需要保持 DataFrame结构的操作(如.merge(),.join())为什么这样设计?
- 灵活性:
Series适合单列计算(如.str字符串操作、.dt时间操作),而DataFrame适合表格操作(如合并、分组)。- 一致性:
[["col1", "col2"]]总是返回DataFrame,即使只选一列,避免因列数不同而改变类型。
(2)加载多列数据
1 | df[["date", "temp_max", "temp_min"]] # 获取多列数据 |
3)按行获取数据
(1)loc:通过行标签获取数据
1 | df.loc[1] # 获取行标签为1的数据 |
(2)iloc:通过行位置获取数据
1 | df.iloc[0] # 获取行位置为0的数据 |
4)获取指定行与列的数据
1 | df.loc[1, "precipitation"] # 获取行标签为1,列标签为precipitation的数据 |
1.5.3 分组聚合计算
1 | df.groupby("分组字段")["要聚合的字段"].聚合函数() |
(1)将数据按月分组,并统计最大温度和最小温度的平均值
1 | # 将字符串类型的日期date转换为datetime日期pd.to_datetime(df["date"]) |
分组后默认会将分组字段作为行索引。如果分组字段有多个,得到的是复合索引。
(2)分组频数计算
统计每个月不同天气状况的数量。
1 | df.groupby("month")["weather"].nunique() |
1.5.4 基本绘图
plot():pandas 提供的绘图方法,它基于 matplotlib 库。将前面计算得到的均值结果绘制成图表,默认情况下会绘制折线图,其中 “month” 作为 x 轴,“temp_max” 和 “temp_min” 的均值作为 y 轴。
1 | df.groupby("month")[["temp_max", "temp_min"]].mean().plot() # 使用plot绘制折线图 |
1.5.5 常用统计值
可通过describe()查看常用统计信息。
1 | df.describe() # 查看常用统计信息 |
可通过include参数指定要统计哪些数据类型的列。
1 | df.describe(include="all") # 统计所有列 |
1.5.6 常用排序方法
1 | **nlargest(n, [****列名1,** **列名2, …])****:**按列排序的最大n个 |
(1)找到最高温度最大的30天
通过nlargest()找出temp_max最大的30条数据。
1 | df = pd.read_csv("data/weather.csv") |
(2)从最高温度最大的30天中找出最低温度最小的5天
通过nlargest()找出temp_min最小的5条数据。
1 | df.nlargest(30, "temp_max").nsmallest(5, "temp_min") |
(3)找出每年的最高温度
1 | df["year"] = pd.to_datetime(df["date"]).dt.to_period("Y").astype(str) # 将date转换为 年 格式 |
1.5.7 案例:简单数据分析练习
使用employees(员工)数据集,其中包含10个字段:
Ø employee_id:员工id。
Ø first_name:员工名称。
Ø last_name:员工姓氏。
Ø email:员工邮箱。
Ø phone_number:员工电话号码。
Ø job_id:员工工种。
Ø salary:员工薪资。
Ø commission_pct:员工佣金比例。
Ø manager_id:员工领导的id。
Ø department_id:员工的部门id。
1)加载数据
1 | import pandas as pd |
2)查看数据
1 | print(df.head()) # 查看前5行 |
3)找出薪资最低、最高的员工
1 | # 布尔索引 |
4)找出薪资最高的10名员工
1 | print(df.nlargest(10, "salary")) # 薪资最高的10名员工 |
5)查看所有部门id
1 | print(df["department_id"].unique()) # 所有部门id |
6)查看每个部门的员工数
1 | print(df.groupby("department_id")["employee_id"].count().rename("employee_count")) # 查看每个部门的员工数 |
7)绘图
1 | print(df.groupby("department_id")["employee_id"].count().rename("employee_count")) # 查看每个部门的员工数 |
8)薪资的分布
1 | print(df["salary"].mean()) # 平均值 |
9)找出平均薪资最高的部门id
1 | print(df.groupby("department_id")["salary"].mean().nlargest(1)) # 平均薪资最高的部门 |
1.6 Padas的数据组合函数
1.6.1 concat连接
沿着一条轴将多个对象堆叠到一起,可通过axis参数设置沿哪一条轴连接。
1)Series与Series连接
1 | s1 = pd.Series(["A", "B"], index=[1, 2]) |
2)DataFrame与Series连接
1 | df1 = pd.DataFrame(data={"a": [1, 2], "b": [4, 5]}, index=[1, 2]) |
3)DataFrame与DataFrame连接
1 | df1 = pd.DataFrame(data={"a": [1, 2], "b": [4, 5]}, index=[1, 2]) |
4)重置索引
1 | 可通过ignore_index=True来重置索引。 |
5)类似join的连接
默认的合并方式是对其他轴进行并集合并(join=outer),可以用join=inner实现其他轴上的交集合并。
1 | df1 = pd.DataFrame(data={"a": [1, 2], "b": [4, 5]}, index=[1, 2]) |
1.6.2 merge合并
通过一个或多个列将行连接。
1)数据连接的类型
merge()实现了三种数据连接的类型:一对一、多对一和多对多。
(1)一对一连接
1 | df1 = pd.DataFrame( |
(2)多对一连接
1 | 在需要连接的两个列中,有一列的值有重复。通过多对一连接获得的结果将会保留重复值。 |
(3)多对多连接
如果左右两个输入的共同列都包含重复值,那么合并的结果就是一种多对多连接。
1 | df1 = pd.DataFrame( |
多对多连接产生的是行的笛卡尔积。由于左边有2个Engineering,右边有2个Engineering,所以最终结果有4个Engineering。
2)设置合并的键与索引
merge()会将两个输入的一个或多个共同列作为键进行合并。但由于两个输入要合并的列通常都不是同名的,因此merge()提供了一些参数处理这个问题。
(1)通过on指定使用某个列连接,只能在有共同列名的时候使用
1 | df1 = pd.DataFrame( |
(2)两对象列名不同,通过left_on和right_on分别指定列名
1 | df1 = pd.DataFrame( |
(3)通过left_index和right_index设置合并的索引
通过设置merge()中的left_index、right_index参数将索引设置为键来实现合并。
1 | df1 = pd.DataFrame( |
DataFrame实现了join()方法,可以按照索引进行数据合并。但要求没有重叠的列,或通过lsuffix、rsuffix指定重叠列的后缀。
1 | import pandas as pd |
3)设置数据连接的集合操作规则
当一个值出现在一列,却没有出现在另一列时,就需要考虑集合操作规则了。
1 | df1 = pd.DataFrame({"name": ["Peter", "Paul", "Mary"], "food": ["fish", "beans", "bread"]}, columns=["name", "food"]) |
合并两个数据集,在name列中只有一个共同的值Mary。默认情况下,结果中只会包含两个输入集合的交集,这种连接方式被称为内连接(inner join)。
我们可以通过how参数设置连接方式,默认值为inner。how参数支持的数据连接方式还有outer、left和right。外连接(outer join)返回两个输入列的并集,所有缺失值都用 NaN 填充。
1 | print(pd.merge(df1, df2, how="outer")) |
4)重复列名的处理
可能会遇到两个输入DataFrame有重名列的情况,merge()会自动为其增加后缀_x和_y,也可以通过suffixes参数自定义后缀名。
1 | df1 = pd.DataFrame({"name": ["Bob", "Jake", "Lisa", "Sue"], "rank": [1, 2, 3, 4]}) |
1.7 Padas的缺失值处理函数
1.7.1 pandas中的缺失值
pandas使用浮点值NaN(Not a Number)表示缺失数据,使用NA(Not Available)表示缺失值。可以通过isnull()、isna()或notnull()、notna()方法判断某个值是否为缺失值。
Nan通常表示一个无效的或未定义的数字值,是浮点数的一种特殊取值,用于表示那些不能表示为正常数字的情况,如 0/0、∞-∞等数学运算的结果。nan与任何值(包括它自身)进行比较的结果都为False。例如在 Python 中,nan == nan返回False。
NA一般用于表示数据不可用或缺失的情况,它的含义更侧重于数据在某种上下文中是缺失或不存在的,不一定特指数字类型的缺失。
na和nan都用于表示缺失值,但nan更强调是数值计算中的特殊值,而na更强调数据的可用性或存在性。
1 | s = pd.Series([np.nan, None, pd.NA]) |
1.7.2 加载数据中包含缺失值
1 | df = pd.read_csv("data/weather_withna.csv") |
可以通过keep_default_na参数设置是否将空白值设置为缺失值。
1 | df = pd.read_csv("data/weather_withna.csv", keep_default_na=False) |
可通过na_values参数将指定值设置为缺失值。
1 | df = pd.read_csv("data/weather_withna.csv", na_values=["2015-12-31"]) |
1.7.3 查看缺失值
1)通过isnull()查看缺失值数量
1 | df = pd.read_csv("data/weather_withna.csv") |
2)通过missingno条形图展示缺失值
先安装missingno包:pip install missingno
1 | import missingno as msno |

3)通过热力图查看缺失值的相关性
missingno绘制的热力图能够展示数据集中不同列的缺失值之间的相关性。这里的相关性体现的是当某一列出现缺失值时,其他列出现缺失值的可能性。如果两个列的缺失值呈现正相关,意味着当其中一列有缺失值时,另一列也很可能有缺失值;若为负相关,则表示当一列有缺失值时,另一列更倾向于没有缺失值。
Ø 颜色与数值:热力图中的颜色和数值反映了列之间缺失值的相关性。接近 1 表示正相关,接近 -1 表示负相关,接近 0 则表示缺失值之间没有明显的关联。
Ø 示例说明:假如 A 列和 B 列在热力图中对应区域颜色较深且数值接近 1,这就表明当 A 列出现缺失值时,B 列也很可能出现缺失值;若数值接近 -1,情况则相反。
1 | msno.heatmap(df) |

1.7.4 剔除缺失值
通过dropna()方法来剔除缺失值。
1)Series剔除缺失值
1 | s = pd.Series([1, pd.NA, None]) |
2)DataFrame剔除缺失值
无法从DataFrame中单独剔除一个值,只能剔除缺失值所在的整行或整列。默认情况下,dropna()会剔除任何包含缺失值的整行数据。
1 | df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]]) |
可以设置按不同的坐标轴剔除缺失值,比如axis=1(或 axis=‘columns’)会剔除任何包含缺失值的整列数据。
1 | df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]]) |
有时只需要剔除全部是缺失值的行或列,或者绝大多数是缺失值的行或列。这些需求可以通过设置how或thresh参数来满足,它们可以设置剔除行或列缺失值的数量阈值。
1 | df = pd.DataFrame([[1, pd.NA, 2], [pd.NA, pd.NA, 5], [pd.NA, pd.NA, pd.NA]]) |
可以通过设置subset参数来设置某一列有缺失值则进行剔除。
1 | df = pd.DataFrame([[1, pd.NA, 2], [pd.NA, pd.NA, 5], [pd.NA, pd.NA, pd.NA]]) |
1.7.5 填充缺失值
1)使用固定值填充
通过fillna()方法,传入值或字典进行填充。
1 | df = pd.read_csv("data/weather_withna.csv") |
2)使用统计值填充
通过fillna()方法,传入统计后的值进行填充。
1 | print(df.fillna(df[["precipitation", "temp_max", "temp_min", "wind"]].mean()).tail()) # 使用平均值填充 |
3)使用前后的有效值填充
通过ffill()或bfill()方法使用前面或后面的有效值填充。
1 | print(df.ffill().tail()) # 使用前面的有效值填充 |
4)通过线性插值填充
通过interpolate()方法进行线性插值填充。线性插值操作,就是用于在已知数据点之间估算未知数据点的值。interpolate 方法支持多种插值方法,可通过 method 参数指定,常见的方法有:
Ø ‘linear’:线性插值,基于两点之间的直线来估算缺失值,适用于数据呈线性变化的情况。
Ø ‘time’:适用于时间序列数据,会考虑时间间隔进行插值。
Ø ‘polynomial’:多项式插值,通过拟合多项式曲线来估算缺失值,可通过 order 参数指定多项式的阶数。
1 | import pandas as pd |
1.8 Padas的apply函数
apply()函数可以对DataFrame或Series的数据进行逐行、逐列或逐元素的操作。可以使用自定义函数对数据进行变换、计算或处理,通常用于处理复杂的变换逻辑,或者处理不能通过向量化操作轻松完成的任务。
1.8.1 Series使用apply()
1 | def f(x): |
也可以传入lambda表达式。
1 | df = pd.DataFrame({"a": [10, 20, 30], "b": [40, 50, 60]}) |
传入带参数的函数。
1 | def f(x, y=10): |
1.8.2 DataFrame使用apply()
1 | def f(x): |
默认axis=0,按行方向进行操作,对列进行统计;
可以设置axis=1,按照列的方向进行操作,参数设置按行处理。
1 | def f(x): |
注意:df.apply 一次只能处理一个 Series(当 axis=0 时处理列,当 axis=1 时处理行),而你定义的函数 f 接收两个参数,不能直接使用 df.apply(f)
1.8.3 向量化函数
1 | def f(x, y): |
上述代码会报错,因为y==0中,y为向量而0为标量。
(1)可以通过np.vectorize()将函数向量化来进行计算
1 | def f(x, y): |
(2)也可以使用@np.vectorize装饰器将函数向量化
1 |
|
1.9 Padas的数据聚合、转换、过滤函数
1.9.1 DataFrameGroupBy对象
对DataFrame对象调用groupby()方法后,会返回DataFrameGroupBy对象。
1 | df = pd.read_csv("data/employees.csv") # 读取员工数据 |
这个对象可以看成是一种特殊形式的 DataFrame,里面隐藏着若干组数据,但是在没有应用累计函数之前不会计算。GroupBy对象是一种非常灵活的抽象类型。在大多数场景中,可以将它看成是DataFrame的集合。
1)查看分组
通过groups属性查看分组结果,返回一个字典,字典的键是分组的标签,值是属于该组的所有索引的列表。
1 | print(df.groupby("department_id").groups) # 查看分组结果 |
通过get_group()方法获取分组。
1 | print(df.groupby("department_id").get_group(50)) # 获取分组为50的数据 |
2)按列取值
1 | print(df.groupby("department_id")["salary"]) # 按department_id分组,取salary列 |
这里从原来的DataFrame中取某个列名作为一个Series组。与GroupBy对象一样,直到我们运行累计函数,才会开始计算。
1 | print(df.groupby("department_id")["salary"].mean()) # 计算每个部门平均薪资 |
3)按组迭代
GroupBy对象支持直接按组进行迭代,返回的每一组都是Series或DataFrame。
1 | for dept_id,group in df.groupby("department_id"): |
4)按多字段分组
1 | salary_mean = df.groupby(["department_id", "job_id"])[ |
5)cut()
pandas.cut()用于将连续数据(如数值型数据)分割成离散的区间。可以使用cut()来将数据划分为不同的类别或范围,通常用于数据的分箱处理。
cut()部分参数说明:
| 参数 | 说明 |
|---|---|
| x | 要分箱的数组或Series,通常是数值型数据。 |
| bins | 切分区间的数值列表或者整数。如果是整数,则表示将数据均匀地分成多少个区间。如果是列表,则需要指定每个区间的边界。 |
| right | 默认True,表示每个区间的右端点是闭区间,即包含右端点。如果设置为False,则左端点为闭区间。 |
| labels | 传入一个列表指定每个区间的标签。 |
1 | df = pd.read_csv("data/employees.csv") # 加载员工数据 |
1.9.2 分组聚合
df.groupby(“分组字段”)[“要聚合的字段”].聚合函数()
df.groupby([“分组字段”, “分组字段2”, …])[[“要聚合的字段”, “要聚合的字段2”, …]].聚合函数()
1)常用聚合函数
| 方法 | 说明 |
|---|---|
| sum() | 求和 |
| mean() | 平均值 |
| min() | 最小值 |
| max() | 最大值 |
| var() | 方差 |
| std() | 标准差 |
| median() | 中位数 |
| quantile() | 指定位置的分位数,如quantile(0.5) |
| describe() | 常见统计信息 |
| size() | 所有元素的个数 |
| count() | 非空元素的个数 |
| first | 第一行 |
| last | 最后一行 |
| nth | 第n行 |
2)一次计算多个统计值
可以通过agg()或aggregate()进行更复杂的操作,如一次计算多个统计值。
1 | df = pd.read_csv("data/employees.csv") # 读取员工数据 |
3)多个列计算不同的统计值
也可以在agg()中传入字典,对多个列计算不同的统计值。
1 | df = pd.read_csv("data/employees.csv") # 读取员工数据 |
4)重命名统计值
可以在agg()后通过rename()对统计后的列重命名。
df = pd.read_csv(“data/employees.csv”) # 读取员工数据
# 按department_id分组,统计job_id的种类数,commission_pct的平均值
1 | print( |
5)自定义函数
可以向agg()中传入自定义函数进行计算。
1 | df = pd.read_csv("data/employees.csv") # 读取员工数据 |
1.9.3 分组转换
聚合操作返回的是对组内全量数据缩减过的结果,而转换操作会返回一个新的全量数据。数据经过转换之后,其形状与原来的输入数据是一样的。
1)通过transform()将每一组的样本数据减去各组的均值,实现数据标准化
1 | df = pd.read_csv("data/employees.csv") # 读取员工数据 |
2)通过transform()按分组使用平均值填充缺失值
1 | df = pd.read_csv("data/employees.csv") # 读取员工数据 |
1.9.4 分组过滤
过滤操作可以让我们按照分组的属性丢弃若干数据。
例如,我们可能只需要保留commission_pct不包含空值的分组的数据。
1 | commission_pct_filter = df.groupby("department_id").filter( |
1.10 Pandas透视表
1.10.1 什么是透视表
透视表(pivot table)是各种电子表格程序和其他数据分析软件中一种常见的数据汇总工具。它可以根据多个行分组键和多个列分组键对数据进行聚合,并根据行和列上的分组键将数据分配到各个矩形区域中。
1.10.2 pivot_table()
pandas中提供了DataFrame.pivot_table()和pandas.pivot_table()方法来生成透视表。两者的区别是pandas.pivot_table()需要额外传入一个data参数指定对哪个DataFrame进行处理。
pivot_table()的参数如下:
| 参数 | 说明 |
|---|---|
| values | 待聚合的列,默认聚合所有数值列。 |
| index | 用作透视表行索引的列。即通过哪个(些)行来对数据进行分组,行索引决定了透视表的行维度。 |
| columns | 用作透视表列索引的列。即通过哪个(些)列来对数据进行分组,列索引决定了透视表的列维度。 |
| aggfunc | 聚合函数或函数列表,默认为mean。 |
| fill_value | 用于替换结果表中的缺失值。 |
| margins | 是否在透视表的边缘添加汇总行和列,显示总计。默认值是 False,如果设置为 True,会添加“总计”行和列,方便查看数据的总体汇总。 |
| dropna | 是否排除包含缺失值的行和列。默认为 True,即如果某个组合的行列数据中包含缺失值,则会被排除在外。如果设置为 False,则会保留这些含有缺失值的行和列。 |
| observerd | 是否显示所有组合数据,True:只显示实际存在的组合 |
1.10.3 案例:睡眠质量分析透视表
使用sleep(睡眠健康和生活方式)数据集,其中包含13个字段:
Ø person_id:每个人的唯一标识符。
Ø gender:个人的性别(男/女)。
Ø age:个人的年龄(以岁为单位)。
Ø occupation:个人的职业或就业状况(例如办公室职员、体力劳动者、学生)。
Ø sleep_duration:每天的睡眠总小时数。
Ø sleep_quality:睡眠质量的主观评分,范围从 1(差)到 10(极好)。
Ø physical_activity_level:每天花费在体力活动上的时间(以分钟为单位)。
Ø stress_level:压力水平的主观评级,范围从 1(低)到 10(高)。
Ø bmi_category:个人的 BMI 分类(体重过轻、正常、超重、肥胖)。
Ø blood_pressure:血压测量,显示为收缩压与舒张压的数值。
Ø heart_rate:静息心率,以每分钟心跳次数为单位。
Ø daily_steps:个人每天行走的步数。
Ø sleep_disorder:存在睡眠障碍(无、失眠、睡眠呼吸暂停)。
1)统计不同睡眠时间,不同压力等级下的睡眠质量
1 | df = pd.read_csv("data/sleep.csv") |
2)添加职业作为列维度
1 | print( |
3)添加性别作为第二个列维度
1 | print( |
1.11 Pandas时间序列
1.11.1 Python中的日期与时间工具
Python基本的日期与时间功能都在标准库的datetime模块中。
1 | from datetime import datetime |
1.11.2 pandas中的日期与时间
pandas的日期时间类型默认是datetime64[ns]。
Ø 针对时间戳数据,pandas提供了Timestamp类型。它本质上是Python原生datetime类型的替代品,但是在性能更好的numpy.datetime64类型的基础上创建。对应的索引数据结构是DatetimeIndex。
Ø 针对时间周期数据,pandas提供了Period类型。这是利用numpy.datetime64类型将固定频率的时间间隔进行编码。对应的索引数据结构是PeriodIndex。
Ø 针对时间增量或持续时间,pandas提供了Timedelta类型。Timedelta是一种代替Python原生datetime.timedelta类型的高性能数据结构,同样是基于numpy.timedelta64类型。对应的索引数据结构是TimedeltaIndex。
1)datetime64
to_datetime()可以解析许多日期与时间格式。对to_datetime()传递一个日期会返回一个Timestamp类型,传递一个时间序列会返回一个DatetimeIndex类型。
1 | print(pd.to_datetime("2015-01-01")) |
在加载数据时,可以通过to_datetime()将数据中的列解析为datetime64。
1 | df = pd.read_csv("data/weather.csv") |
在加载数据时也可以通过parse_dates参数将指定列解析为datetime64。
1 | df = pd.read_csv("data/weather.csv", parse_dates=[0]) |
2)提取日期的各个部分
(1)提取Timestamp
1 | d = pd.Timestamp("2015-01-01 09:08:07.123456") |
(2)对于Series对象,需要使用dt访问器
1 | df = pd.read_csv("data/weather.csv", parse_dates=[0]) |
3)period
可以通过to_period()方法和一个频率代码将datetime64类型转换成period类型。
1 | df = pd.read_csv("data/weather.csv") |
4)timedelta64
当用一个日期减去另一个日期,返回的结果是timedelta64类型。
1 | df = pd.read_csv("data/weather.csv", parse_dates=[0]) |
1.11.3 使用时间作为索引
1)DatetimeIndex
将datetime64类型的数据设置为索引,得到的就是DatetimeIndex。
1 | df = pd.read_csv("data/weather.csv") |
将时间作为索引后可以直接使用时间进行切片取值。
1 | print(df.loc["2013-01":"2013-06"]) # 获取2013年1~6月的数据 |
2)TimedeltaIndex
将timedelta64类型的数据设置为索引,得到的就是TimedeltaIndex。
1 | df = pd.read_csv("data/weather.csv", parse_dates=[0]) |
将时间作为索引后可以直接使用时间进行切片取值。
1 | print(df.loc["0 days":"5 days"]) |
1.11.4 生成时间序列
为了能更简便地创建有规律的时间序列,pandas提供了date_range()方法。
1)date_range()
date_range()通过开始日期、结束日期和频率代码(可选)创建一个有规律的日期序列,默认的频率是天。
1 | print(pd.date_range("2015-07-03", "2015-07-10")) |
2)时间频率与偏移量
(1)可通过freq参数设置时间频率
下表为常见时间频率代码与说明:
| 代码 | 说明 |
|---|---|
| D | 天(calendar day,按日历算,含双休日) |
| B | 天(business day,仅含工作日) |
| W | 周(weekly) |
| ME / M | 月末(month end) |
| BME | 月末(business month end,仅含工作日) |
| MS | 月初(month start) |
| BMS | 月初(business month start,仅含工作日) |
| QE / Q | 季末(quarter end) |
| BQE | 季末(business quarter end,仅含工作日) |
| QS | 季初(quarter start) |
| BQS | 季初(business quarter start,仅含工作日) |
| YE / Y | 年末(year end) |
| BYE | 年末(business year end,仅含工作日) |
| YS | 年初(year start) |
| BYS | 年初(business year start,仅含工作日) |
| h | 小时(hours) |
| bh | 小时(business hours,工作时间) |
| min | 分钟(minutes) |
| s | 秒(seconds) |
| ms | 毫秒(milliseonds) |
| us | 微秒(microseconds) |
| ns | 纳秒(nanoseconds) |
(2)偏移量
可以在频率代码后面加三位月份缩写字母来改变季、年频率的开始时间。
Ø QE-JAN、BQE-FEB、QS-MAR、BQS-APR等
Ø YE-JAN、BYE-FEB、YS-MAR、BYS-APR等
1 | print(pd.date_range("2015-07-03", periods=10, freq="QE-JAN")) # 设置1月为季度末 |
同理,也可以在后面加三位星期缩写字母来改变一周的开始时间。
Ø W-SUN、W-MON、W-TUE、W-WED等
1 | print(pd.date_range("2015-07-03", periods=10, freq="W-WED")) # 设置周三为一周的第一天 |
在这些代码的基础上,还可以将频率组合起来创建的新的周期。例如,可以用小时(h)和分钟(min)的组合来实现2小时30分钟。
1 | print(pd.date_range("2015-07-03", periods=10, freq="2h30min")) |
1.11.5 重新采样
处理时间序列数据时,经常需要按照新的频率(更高频率、更低频率)对数据进行重新采样。可以通过resample()方法解决这个问题。resample()方法以数据累计为基础,会将数据按指定的时间周期进行分组,之后可以对其使用聚合函数。
1 | df = pd.read_csv("data/weather.csv") |
1.12 Matplotlib可视化
1.12.1 Matplotlib简介
1)什么是Matplotlib
Matplotlib是一个Python绘图库,广泛用于创建各种类型的静态、动态和交互式图表。它是数据科学、机器学习、工程和科学计算领域中常用的绘图工具之一。
Ø 支持多种图表类型:折线图(Line plots)、散点图(Scatter plots)、柱状图(Bar charts)、直方图(Histograms)、饼图(Pie charts)、热图(Heatmaps)、箱型图(Box plots)、极坐标图(Polar plots)、3D图(3D plots,配合 mpl_toolkits.mplot3d)。
Ø 高度自定义:允许用户自定义图表的每个部分,包括标题、轴标签、刻度、图例等。 支持多种颜色、字体和线条样式。提供精确的图形渲染控制,如坐标轴范围、图形大小、字体大小等。
Ø 兼容性:与NumPy、Pandas等库紧密集成,特别适用于绘制基于数据框和数组的数据可视化。可以输出到多种格式(如PNG、PDF、SVG、EPS等)。
Ø 交互式绘图:在Jupyter Notebook 中,Matplotlib支持交互式绘图,可以动态更新图表。支持图形缩放、平移等交互操作。
Ø 动态图表:可以生成动画(使用FuncAnimation类),为用户提供动态数据的可视化。
2)不同开发环境下显示图形
Ø 在一个脚本文件中使用Matplotlib,那么显示图形的时候必须使用plt.show()。
Ø 在Notebook中使用Matplotlib,运行命令之后在每一个Notebook的单元中就会直接将PNG格式图形文件嵌入在单元中。
1.12.2 两种画图接口
Matplotlib有两种画图接口:一个是便捷的MATLAB风格的有状态的接口,另一个是功能更强大的面向对象接口。
1)状态接口
1 | import numpy as np |
2)面向对象接口
1 | import numpy as np |
1.12.3 单变量可视化
使用weather(天气)数据集。其中包含6个字段:
Ø date:日期,年-月-日格式。
Ø precipitation:降水量。
Ø temp_max:最高温度。
Ø temp_min:最低温度。
Ø wind:风力。
Ø weather:天气状况。
加载数据:
1 | import pandas as pd |
1.12.4 多变量可视化
1)双变量
使用散点图呈现降水量随最高气温变化的大致趋势。
1 | import pandas as pd |
2)多变量
使用散点图呈现降水量随最高气温变化的大致趋势,用不同颜色区分不同年份的数据。
1 | import pandas as pd |
1.13 Pandas可视化
pandas提供了非常方便的绘图功能,可以直接在DataFrame或Series上调用plot()方法来生成各种类型的图表。底层实现依赖于Matplotlib,pandas的绘图功能集成了许多常见的图形类型,易于使用。
1.13.1 单变量可视化
使用sleep(睡眠健康和生活方式)数据集,其中包含13个字段:
Ø person_id:每个人的唯一标识符。
Ø gender:个人的性别(男/女)。
Ø age:个人的年龄(以岁为单位)。
Ø occupation:个人的职业或就业状况(例如办公室职员、体力劳动者、学生)。
Ø sleep_duration:每天的睡眠总小时数。
Ø sleep_quality:睡眠质量的主观评分,范围从 1(差)到 10(极好)。
Ø physical_activity_level:每天花费在体力活动上的时间(以分钟为单位)。
Ø stress_level:压力水平的主观评级,范围从 1(低)到 10(高)。
Ø bmi_category:个人的 BMI 分类(体重过轻、正常、超重、肥胖)。
Ø blood_pressure:血压测量,显示为收缩压与舒张压的数值。
Ø heart_rate:静息心率,以每分钟心跳次数为单位。
Ø daily_steps:个人每天行走的步数。
Ø sleep_disorder:存在睡眠障碍(无、失眠、睡眠呼吸暂停)。
加载数据:
1 | import pandas as pd |
1)柱状图
柱状图用于展示类别数据的分布情况。它通过一系列矩形的高度(或长度)来展示数据值,适合对比不同类别之间的数量或频率。简单直观,容易理解和比较各类别数据。
使用柱状图展示不同睡眠时长的数量。
1 | pd.cut(df["sleep_duration"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().plot.bar( |
2)折线图
折线图通常用于展示连续数据的变化趋势。它通过一系列数据点连接成的线段来表示数据的变化。能够清晰地展示数据的趋势和波动。
使用折线图展示不同睡眠时长的数量。
pd.cut(df[“sleep_duration”], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot()
3)面积图
面积图是折线图的一种变体,线下的区域被填充颜色,用于强调数据的总量或变化。可以更直观地展示数据量的变化,适合用来展示多个分类的累计趋势。
使用面积图展示不同睡眠时长的数量。
pd.cut(df[“sleep_duration”], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot.area()
4)直方图
直方图用于展示数据的分布情况。它将数据范围分成多个区间,并通过矩形的高度显示每个区间内数据的频率或数量。可以揭示数据分布的模式,如偏态、峰度等。
使用直方图展示不同睡眠时长的数量。
df[“sleep_duration”].value_counts().plot.hist()
5)饼状图
饼状图用于展示一个整体中各个部分所占的比例。它通过一个圆形图形分割成不同的扇形,每个扇形的角度与各部分的比例成正比。能够快速展示各部分之间的比例关系,但不适合用于展示过多的类别或比较数值差异较小的部分。
使用饼状图展示不同睡眠时长的占比。
pd.cut(df[“sleep_duration”], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot.pie()
1.13.2 双变量可视化
1)散点图
散点图通过在二维坐标系中绘制数据点来展示两组数值数据之间的关系。能够揭示两个变量之间的相关性和趋势。
绘制睡眠时间与睡眠质量的散点图。
df.plot.scatter(x=“sleep_duration”, y=“sleep_quality”)
2)蜂窝图
蜂窝图是散点图的扩展,通常用于表示大量数据点之间的关系。它通过将数据点分布在一个六边形网格中,每个六边形的颜色代表其中的数据密度。适合展示大量数据点,避免了散点图中的过度重叠问题。
绘制睡眠时间与睡眠质量的蜂窝图。
df.plot.hexbin(x=“sleep_duration”, y=“sleep_quality”, gridsize=10)
3)堆叠图
堆叠图用于展示多个数据系列的累积变化。常见的堆叠图包括堆叠柱状图、堆叠面积图等。它通过将每个数据系列堆叠在前一个系列之上,展示数据的累积情况。能够清晰地展示不同部分的相对贡献,适合多个数据系列的比较。
绘制睡眠时间与睡眠质量的堆叠图。
1 | df["sleep_quality_stage"] = pd.cut(df["sleep_quality"], range(11)) |
4)折线图
df_pivot_table.plot.line()
1.14 Seaborn可视化
1.14.1 什么是Seaborn
Seaborn是一个基于Matplotlib的Python可视化库,旨在简化数据可视化的过程。它提供了更高级的接口,用于生成漂亮和复杂的统计图表,同时也能保持与Pandas数据结构的良好兼容性。
1.14.2 单变量可视化
使用penguins(企鹅🐧)数据集,其中包含7个字段:
Ø species:企鹅种类(Adelie、Gentoo、Chinstrap)。
Ø island:观测岛屿(Torgersen, Biscoe, Dream)。
Ø bill_length_mm:喙(嘴)长度(毫米)。
Ø bill_depth_mm:喙深度(毫米)。
Ø flipper_length_mm:脚蹼长度(毫米)。
Ø body_mass_g:体重(克)。
Ø sex:性别(Male、Female)。
加载数据:
1 | import pandas as pd |
1)直方图
绘制不同种类企鹅数量的直方图。
1 | sns.histplot(data=penguins, x="species") |
2)核密度估计图
核密度估计图(KDE,Kernel Density Estimate Plot)是一种用于显示数据分布的统计图表,它通过平滑直方图的方法来估计数据的概率密度函数,使得分布图看起来更加连续和平滑。核密度估计是一种非参数方法,用于估计随机变量的概率密度函数。其基本思想是,将每个数据点视为一个“核”(通常是高斯分布),然后将这些核的贡献相加以形成平滑的密度曲线。
绘制喙长度的核密度估计图。
1 | sns.kdeplot(data=penguins, x="bill_length_mm") |
3)计数图
计数图用于绘制分类变量的计数分布图,显示每个类别在数据集中出现的次数,是分析分类数据非常直观的工具,可以快速了解类别的分布情况。
绘制不同岛屿企鹅数量的计数图。
sns.countplot(data=penguins, x=“island”)
1.14.3 双变量可视化
1)散点图
绘制横轴为体重,纵轴为脚蹼长度的散点图。可通过hue参数设置不同组别进行对比。
sns.scatterplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, hue=“sex”)
也可以通过regplot()函数绘制散点图,同时会拟合回归曲线。可以通过fit_reg=False关闭拟合。
sns.regplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”)
也可以通过lmplot()函数绘制基于hue参数的分组回归图。
sns.lmplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, hue=“sex”)
也可以通过jointplot()函数绘制在每个轴上包含单个变量的散点图。
sns.jointplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”)
2)蜂窝图
通过jointplot()函数,设置kind="hex"来绘制蜂窝图。
sns.jointplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, kind=“hex”)
3)二维核密度估计图
通过kdeplot()函数,同时设置x参数和y参数来绘制二维核密度估计图。
sns.kdeplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”)
通过fill=True设置为填充,通过cbar=True设置显示颜色示意条。
sns.kdeplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, fill=True, cbar=True)
4)条形图
条形图会按x分组对y进行聚合,通过estimator参数设置聚合函数,并通过errorbar设置误差条,误差条默认会显示。可以通过误差条显示抽样数据统计结果的可能统计范围,如果数据不是抽样数据, 可以设置为None来关闭误差条。
sns.barplot(data=penguins, x=“species”, y=“bill_length_mm”, estimator=“mean”, errorbar=None
1.14.3 双变量可视化
1)散点图
绘制横轴为体重,纵轴为脚蹼长度的散点图。可通过hue参数设置不同组别进行对比。
sns.scatterplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, hue=“sex”)
也可以通过regplot()函数绘制散点图,同时会拟合回归曲线。可以通过fit_reg=False关闭拟合。
sns.regplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”)
也可以通过lmplot()函数绘制基于hue参数的分组回归图。
sns.lmplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, hue=“sex”)
也可以通过jointplot()函数绘制在每个轴上包含单个变量的散点图。
sns.jointplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”)
2)蜂窝图
通过jointplot()函数,设置kind="hex"来绘制蜂窝图。
sns.jointplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, kind=“hex”)
3)二维核密度估计图
通过kdeplot()函数,同时设置x参数和y参数来绘制二维核密度估计图。
sns.kdeplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”)
通过fill=True设置为填充,通过cbar=True设置显示颜色示意条。
sns.kdeplot(data=penguins, x=“body_mass_g”, y=“flipper_length_mm”, fill=True, cbar=True)
4)条形图
条形图会按x分组对y进行聚合,通过estimator参数设置聚合函数,并通过errorbar设置误差条,误差条默认会显示。可以通过误差条显示抽样数据统计结果的可能统计范围,如果数据不是抽样数据, 可以设置为None来关闭误差条。
sns.barplot(data=penguins, x=“species”, y=“bill_length_mm”, estimator=“mean”, errorbar=None)
5)箱线图
箱线图是一种用于展示数据分布、集中趋势、散布情况以及异常值的统计图表。它通过五个关键的统计量(最小值、第一四分位数、中位数、第三四分位数、最大值)来展示数据的分布情况。
箱线图通过箱体和须来表现数据的分布,能够有效地显示数据的偏斜、分散性以及异常值。箱线图的组成部分:
Ø 箱体(Box):
Ø 下四分位数(Q1):数据集下 25% 的位置,箱体的下边缘。
Ø 上四分位数(Q3):数据集下 75% 的位置,箱体的上边缘。
Ø 四分位间距(IQR, Interquartile Range):Q3 和 Q1 之间的距离,用来衡量数据的离散程度。
Ø 中位数(Median):箱体内部的水平线,表示数据集的中位数。
Ø 须(Whiskers):
Ø 下须:从 Q1 向下延伸,通常是数据集中最小值与 Q1 的距离,直到没有超过1.5倍 IQR 的数据点为止。
Ø 上须:从 Q3 向上延伸,通常是数据集中最大值与 Q3 的距离,直到没有超过1.5倍 IQR 的数据点为止。
Ø 异常值(Outliers):
Ø 超过1.5倍 IQR 的数据被认为是异常值,通常用点标记出来。异常值是数据中相对于其他数据点而言“非常大”或“非常小”的值。
sns.boxplot(data=penguins, x=“species”, y=“bill_length_mm”)
6)小提琴图
小提琴图(Violin Plot) 是一种结合了箱线图和核密度估计图(KDE)的可视化图表,用于展示数据的分布情况、集中趋势、散布情况以及异常值。小提琴图不仅可以显示数据的基本统计量(如中位数和四分位数),还可以展示数据的概率密度,提供比箱线图更丰富的信息。
sns.violinplot(data=penguins, x=“species”, y=“bill_length_mm”)
7)成对关系图
成对关系图是一种用于显示多个变量之间关系的可视化工具。它可以展示各个变量之间的成对关系,并且通过不同的图表形式帮助我们理解数据中各个变量之间的相互作用。
对角线上的图通常显示每个变量的分布(如直方图或核密度估计图),帮助观察每个变量的单变量特性。其他位置展示所有变量的两两关系,用散点图表示。
sns.pairplot(data=penguins, hue=“species”)
通常情况下成对关系图左上和右下对应位置的图的信息是相同的,可以通过PairGrid()为每个区域设置不同的图类型。
pair_grid = sns.PairGrid(data=penguins, hue=“species”)
# 通过 map 方法在网格上绘制不同的图形
pair_grid.map_upper(sns.scatterplot) # 上三角部分使用散点图
pair_grid.map_lower(sns.kdeplot) # 下三角部分使用核密度估计图
pair_grid.map_diag(sns.histplot) # 对角线部分使用直方图
1.1.2 多变量可视化
多数绘图函数都支持使用hue参数设置一个类别变量,统计时按此类别分组统计并在绘图时使用颜色区分。
例如对小提琴图设置hue参数添加性别类别:
sns.violinplot(data=penguins, x=“species”, y=“bill_length_mm”, hue=“sex”, split=True)
1.1.3 Seaborn样式
在Seaborn中,样式(style)控制了图表的整体外观,包括背景色、网格线、刻度线等元素。Seaborn提供了一些内置的样式选项,可以通过seaborn.set_style()来设置当前图表的样式。常见的样式有以下几种:
Ø white:纯白背景,没有网格线。
Ø dark:深色背景,带有网格线。
Ø whitegrid:白色背景,带有网格线。
Ø darkgrid:深色背景,带有网格线(默认样式)。
sns.set_style(“darkgrid”)
sns.histplot(data=penguins, x=“island”, kde=True)
第 4 章 综合案例:房地产市场洞察与价值评估
2.1 业务背景
在房地产市场中,准确的房价预测和深入的市场分析对于房产开发商、投资者以及购房者都至关重要。房产开发商需要根据市场趋势和不同因素对房价的影响来制定合理的定价策略,优化项目规划;投资者需要评估房产的潜在价值和投资回报率,做出明智的投资决策;购房者则希望了解市场行情,找到性价比高的房产。
某大型房地产数据研究机构收集了大量不同地区的房屋销售数据,这些数据包含了房屋的各种属性信息以及销售相关信息。为了更好地服务于市场参与者,该机构计划对这些数据进行全面深入的分析,挖掘数据背后的规律和价值。具体目标包括:
Ø 探究不同房屋特征(如卧室数量、浴室数量、居住面积等)对房价的影响程度,以便为房价预测模型提供依据。
Ø 分析不同地区(以邮政编码划分)的房地产市场差异,了解各地区的房价水平、市场活跃度等情况。
Ø 研究房屋的建造年份、翻新年份等时间因素对房价的影响,以及不同时间段的市场趋势变化。
Ø 通过可视化手段直观展示数据的分布和关系,为决策提供清晰的参考。
2.2 数据源介绍
| 字段名 | 含义 | 数据类型 | 说明 |
|---|---|---|---|
| id | 房屋销售记录的唯一标识符 | 整数 | 用于唯一标识每一条房屋销售记录 |
| date | 房屋销售日期 | 日期时间类型 | 记录房屋实际完成销售的日期,可用于时间序列分析,观察不同时间段的市场趋势 |
| price | 房屋销售价格 | 数值型 | 反映房屋在销售时的成交金额,是分析的核心指标之一,受多种房屋特征和市场因素影响 |
| bedrooms | 卧室数量 | 整数 | 体现房屋的居住功能布局,卧室数量的多少会影响房屋的整体实用性和市场需求 |
| bathrooms | 浴室数量 | 整数 | 同样是影响房屋舒适度和实用性的重要因素,与卧室数量共同影响房屋的居住体验 |
| sqft_living | 居住面积(平方英尺) | 数值型 | 指房屋内部可供居住使用的实际面积,是影响房价的关键因素之一 |
| sqft_lot | 土地面积(平方米) | 数值型 | 包括房屋所在土地的总面积,土地面积大小会影响房屋的整体价值和使用空间 |
| floors | 楼层数 | 整数 | 房屋的楼层数量会影响房屋的视野、采光、私密性等方面,进而对房价产生影响 |
| waterfront | 是否临水 | 整数(0 或 1) | 0 表示房屋不临水,1 表示房屋临水,临水房屋通常具有更高的景观价值和市场价格 |
| view | 景观评分 | 整数(0 - 4) | 对房屋周边景观的评分,评分越高表示景观越好,景观质量会影响房屋的吸引力和价格 |
| condition | 房屋状况评分 | 整数(1 - 5) | 反映房屋的整体状况,包括房屋的结构、装修、设施等方面的维护情况 |
| grade | 房屋整体质量评分 | 整数(1 - 13) | 综合评估房屋的建筑质量、设计水平等因素,是衡量房屋价值的重要指标 |
| sqft_above | 地上面积(平方米) | 数值型 | 指房屋地面以上部分的建筑面积,不包括地下室面积 |
| sqft_basement | 地下室面积(平方米) | 数值型 | 地下室面积可作为额外的存储空间或功能区域,对房屋的实用性和价值有一定影响 |
| yr_built | 建造年份 | 整数 | 记录房屋的建成时间,房屋的建造年份会影响房屋的折旧程度、建筑风格和市场竞争力 |
| yr_renovated | 翻新年份 | 整数 | 0 表示房屋未进行过翻新,非 0 值表示房屋进行翻新的具体年份,翻新可以提升房屋的价值和居住体验 |
| zipcode | 邮政编码 | 整数 | 用于标识房屋所在的地理位置区域,不同的邮政编码区域可能具有不同的市场特征和房价水平 |
| lat | 纬度 | 数值型 | 房屋所在位置的纬度坐标,结合经度可确定房屋的具体地理位置 |
| long | 经度 | 数值型 | 房屋所在位置的经度坐标,与纬度共同用于地理空间分析 |
2.3 待统计指标及说明
2.3.1 数值型列的描述性统计指标
Ø **均值(**Mean):一组数据的平均值,反映数据的集中趋势。例如,房价的均值可以让我们了解该地区房屋的平均销售价格水平。
Ø **中位数(****Median):将数据按升序或降序排列后,位于中间位置的数值。当数据存在极端值时,中位数比均值更能代表数据的一般水平。
Ø 标准差(Standard Deviation):衡量数据相对于均值的离散程度。标准差越大,说明数据越分散;反之,则越集中。比如房价的标准差可以反映该地区房价的波动情况。
Ø 最小值(Minimum):数据集中的最小数值,可用于了解数据的下限。
Ø 最大值(Maximum):数据集中的最大数值,可用于了解数据的上限。
Ø 四分位数(Quartiles):包括第一四分位数(Q1,25% 分位数)、第二四分位数(Q2,即中位数,50% 分位数)和第三四分位数(Q3,75% 分位数),能帮助了解数据的分布情况。
2.3.2 不同特征与房价的相关性
Ø 使用皮尔逊相关系数衡量特征与房价之间的线性关系强度和方向,系数绝对值越接近 1,相关性越强;正系数表示正相关,负系数表示负相关。
2.3.3 按邮政编码、是否翻新、房龄分组的统计指标
Ø 平均房价:各邮政编码区域内房屋的平均销售价格,用于对比不同区域的房价水平。
Ø 平均居住面积:各区域内房屋居住面积的平均值,反映区域房屋规模情况。
Ø 平均卧室数量:各区域内房屋卧室数量的平均值,体现区域房屋居住功能布局。
2.3.4 时间序列分析指标
Ø 每年平均房价(Average Price per Year):按销售年份分组计算的房屋平均销售价格,可用于观察房价随时间的变化趋势。
2.4 代码实现步骤
2.4.1 数据读取
1)代码
1 | import pandas as pd |
2)代码说明
使用 pandas 的 read_csv 函数读取 house_sales.csv 文件,将数据存储在 DataFrame 对象 data 中,方便后续处理,并查看数据基本信息。
2.4.2 数据清洗
1)代码
1 | # 检查缺失值 |
在统计学中,0.25(25%)和0.75(75%)的分位数分别被称为第一四分位数(Q1)**和**第三四分位数(Q3)。它们与**四分位距(IQR, Interquartile Range)**一起被广泛用于识别数据中的异常值(outliers)。以下是选择这两个特定值的原因:
1. 四分位数的统计意义
- Q1(25%分位数):数据中25%的值小于或等于Q1,它代表了数据的“较低部分”的分界线。
- Q3(75%分位数):数据中75%的值小于或等于Q3,它代表了数据的“较高部分”的分界线。
- IQR = Q3 - Q1:表示中间50%数据的范围,反映了数据的离散程度(排除极端值的影响)。
2. 为什么用1.5 × IQR定义异常值边界?
历史与经验规则
:1.5 × IQR 是统计学家John Tukey提出的经验法则,基于正态分布的假设。在正态分布中:
- 大约99.3%的数据会落在
[Q1 - 1.5×IQR, Q3 + 1.5×IQR]范围内。- 超出此范围的值极有可能是异常值(仅约0.7%的概率)。
稳健性:IQR对异常值不敏感(不像标准差受极端值影响大),因此用IQR定义的边界更可靠。
3. 上下界的计算逻辑
- 下界(Lower Bound):
Q1 - 1.5 × IQR低于此值的数据点可能异常小(如输入错误或极端情况)。- 上界(Upper Bound):
Q3 + 1.5 × IQR高于此值的数据点可能异常大。4. 为什么不用其他分位数(如0.1/0.9)?
- 平衡敏感性与实用性:0.25和0.75的选择能覆盖数据的中间50%,既不过于严格(如用0.1/0.9会漏掉更多潜在异常值),也不过于宽松(如用0.01/0.99可能保留太多异常值)。
- 行业标准:IQR法是被广泛接受的异常值检测方法,尤其在箱线图(Boxplot)中直观体现。
5. 你的代码在做什么?
通过以下步骤过滤数据中的“非典型”价格:
- 计算Q1、Q3和IQR。
- 定义合理价格的上下界(
lower_bound和upper_bound)。- 保留落在该区间内的数据,剔除可能的异常值。
注意事项
- 非对称分布:如果数据分布严重偏斜(如房价通常右偏),IQR法可能误判一些真实数据为异常值。此时可考虑调整倍数(如用3×IQR)或使用其他方法(如对数变换+Z-Score)。
- 领域知识:最终是否剔除异常值需结合业务背景。例如,奢侈品价格可能天然超出IQR边界,但属于合理数据。
总之,选择0.25和0.75是基于统计学的稳健性和通用性,而1.5×IQR是经验性的平衡点。
2)代码说明
缺失值处理:使用 isnull().sum() 统计各列缺失值数量,然后用 dropna() 删除包含缺失值的行。
异常值处理:使用 IQR(Inter - Quartile Range,四分位距)方法来检测和处理房价数据中的异常值。以房价为例,通过计算第一四分位数 Q1、第三四分位数 Q3 和四分位距 IQR,确定上下限,筛选出合理范围内的数据。
Ø data[‘price’].quantile(0.25):quantile 是 pandas 中用于计算分位数的方法。这里 0.25 表示计算 25% 分位数,也就是第一四分位数 Q1。第一四分位数意味着有 25% 的数据小于这个值。
Ø data[‘price’].quantile(0.75):同理,0.75 表示计算 75% 分位数,即第三四分位数 Q3。有 75% 的数据小于这个值。
Ø 四分位距 IQR 是第三四分位数 Q3 与第一四分位数 Q1 的差值。它衡量了数据中间 50% 的数据的分散程度。
Ø lower_bound:通过 Q1 - 1.5 * IQR 计算出异常值的下限。如果某个数据点小于这个下限,就可能被视为异常值。
Ø upper_bound:通过 Q3 + 1.5 * IQR 计算出异常值的上限。如果某个数据点大于这个上限,也可能被视为异常值。
Ø 这里的 1.5 是一个常用的系数,在很多情况下可以有效地识别出大部分异常值,但在某些特殊场景下可能需要调整。
Ø 使用布尔索引来筛选数据。(data[‘price’] >= lower_bound) & (data[‘price’] <= upper_bound) 表示筛选出 price 列中值大于等于下限且小于等于上限的数据,将这些数据重新赋值给 data,从而去除了可能的异常值。
2.4.3 数据类型转换
1)代码
1 | # 将日期列转换为日期类型 |
2)代码说明
使用 pandas 的 to_datetime 函数将 date 列转换为日期类型,便于进行时间序列分析。
2.4.4 创建新的特征
1)代码
1 | # 计算房屋的使用年限 |
2)代码说明
计算房屋使用年限:通过销售日期的年份减去建造年份,得到房屋的使用年限,存储在新列 age 中,这个特征可能会对房价产生影响。
创建是否翻新特征:使用 apply 方法和 lambda 函数对 yr_renovated 列进行判断,若值大于 0 则表示房屋已翻新,将 is_renovated 列对应的值设为 1,否则设为 0,以便后续分析翻新因素对房价的影响。
2.4.5 数据探索性分析-描述性统计
1)代码
1 | # 选择数值型列 |
2)代码说明
data.select_dtypes(include=[np.number]) 选择数据集中的数值型列,并获取其列名存储在 numeric_columns 中。
data[numeric_columns].describe(percentiles=[0.25, 0.5, 0.75]) 计算数值型列的描述性统计信息,包括均值、中位数、标准差、最小值、最大值、四分位数等,并将结果存储在 description 中,帮助我们了解各数值特征的分布情况。
2.4.6 数据探索性分析-相关性统计
1)代码
1 | # 计算不同特征与房价的相关性 |
2)代码说明
对数值型列使用 corr 方法计算相关系数矩阵,提取 price 列得到各特征与房价的相关性。
2.4.7 按照邮政编码分组分析
1)代码
1 | # 按邮政编码分组,计算每组的平均房价、平均居住面积、平均卧室数量 |
2)代码说明
使用 data.groupby(‘zipcode’) 按邮政编码对数据进行分组。
agg 方法对分组后的数据进行聚合操作,分别计算每组的平均房价、平均居住面积和平均卧室数量。
对结果的列名进行重命名,使其更具可读性,并打印输出,可对比不同邮政编码区域的房屋特征情况。
2.4.8 按照是否翻新分组分析
1)代码
1 | # 按是否翻新分组,计算每组的平均房价、平均居住面积、平均卧室数量 |
2)代码说明
按 is_renovated 特征对数据进行分组,分析翻新和未翻新房屋在房价、居住面积和卧室数量等方面的差异。同样使用 agg 方法进行聚合计算,得到相应的统计信息并打印。
2.4.9 按照房龄分组分析
1 | 1)代码 |
2)代码说明
使用 pd.cut 函数将房屋使用年限 age 划分为 5 个区间,创建新列 age_group。
按 age_group 分组,计算每组的平均房价、平均居住面积和平均卧室数量,了解不同使用年限房屋的特征差异。
2.4.10 时间序列分析-每年平均房价
1)代码
1 | # 按年份分组,计算每年的平均房价 |
2)代码说明
使用 data.groupby(data[‘date’].dt.year) 按销售日期的年份对数据进行分组。
对每组的 price 列计算均值,得到每年的平均房价,并存储在 yearly_avg_price 中进行打印输出,可观察房价随时间的变化趋势。
2.4.11 时间序列分析-不同翻新情况平均房价
1)代码
1 | # 按年份和是否翻新分组,计算每年不同翻新情况的平均房价 |
2)代码说明
按销售年份和是否翻新进行分组,计算每年翻新和未翻新房屋的平均房价,能让我们看到在不同年份,翻新因素对房价的影响变化。
2.4.12 可视化
1)房价分布直方图
1 | # 房价分布直方图 |
使用 plt.hist 函数绘制房价的分布直方图,bins=30 控制柱子的数量,edgecolor=‘k’ 为柱子添加黑色边框。添加标题和坐标轴标签,使图形更易理解,最后使用 plt.show() 显示图形。
2)卧室数量与房价的散点图
1 | # 卧室数量与房价的散点图 |
使用 plt.scatter 函数绘制卧室数量与房价的散点图,直观展示两者之间的关系。
3)各特征与房价的相关性热力图
1 | # 各特征与房价的相关性热力图 |
使用 plt.imshow 函数绘制相关性热力图,cmap=‘coolwarm’ 设置颜色映射,interpolation=‘nearest’ 控制插值方式。添加颜色条和坐标轴标签,显示各特征与房价的相关性,最后显示图形。
4)不同邮政编码区域平均房价的柱状图
1 | # 不同邮政编码区域平均房价的柱状图 |
使用 plt.bar 函数绘制不同邮政编码区域平均房价的柱状图,将 zipcode 转换为字符串类型。设置图形标题和坐标轴标签,旋转 x 轴标签避免重叠后显示图形。
5)每年平均房价的折线图
1 | # 每年平均房价的折线图 |
使用 plt.plot 函数绘制每年平均房价的折线图,展示房价随时间的变化趋势。
6)不同翻新情况的房价箱线图
1 | # 不同翻新情况的房价箱线图 |
使用 data.boxplot 方法绘制不同翻新情况的房价箱线图,展示翻新和未翻新房屋房价的分布情况
7)房屋使用年限与房价的散点图
1 | # 房屋使用年限与房价的散点图 |
使用 plt.scatter 函数绘制房屋使用年限与房价的散点图,观察两者之间的关系。
2.4.13 完整代码
1 | import pandas as pd |
