diff --git a/source/_posts/A04-Hexo-blog-topic-personalization.md b/source/_posts/A04-Hexo-blog-topic-personalization.md index c000a4b8dfa9afd36954609140caabfa0c91c054..eef04677d44788dd18758ce85e4b6643c24ace7f 100644 --- a/source/_posts/A04-Hexo-blog-topic-personalization.md +++ b/source/_posts/A04-Hexo-blog-topic-personalization.md @@ -1,6 +1,5 @@ --- title: Hexo 博客主题个性化 -top: true categories: Hexo tags: - 主题个性化 diff --git a/source/_posts/A27-image-hosting.md b/source/_posts/A27-image-hosting.md index d2b065f0f916f929ab1000bd6cdc1b9f121bfa9c..ba07be7e32981ed4f009679d901b122146985cd1 100644 --- a/source/_posts/A27-image-hosting.md +++ b/source/_posts/A27-image-hosting.md @@ -77,7 +77,7 @@ avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png - 指定存储路径:填写想要储存的路径,如【ITRHX-PIC/】,这样就会在仓库下创建一个名为 ITRHX-PIC 的文件夹,图片将会储存在此文件夹中 -- 设定自定义域名:它的作用是,在图片上传后,PicGo 会按照【自定义域名+储存路径+上传的图片名】的方式生成访问链接,并放到粘贴板上,因为我们要使用 jsDelivr 加速访问,所以可以设置为【https://cdn.jsdelivr.net/gh/用户名/图床仓库名 】,上传完毕后,我们就可以通过【https://cdn.jsdelivr.net/gh/用户名/图床仓库名/图片路径 】加速访问我们的图片了,比如上图的图片链接为:https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A27/08.png +- 设定自定义域名:它的作用是,在图片上传后,PicGo 会按照【自定义域名+储存路径+上传的图片名】的方式生成访问链接,并放到粘贴板上,因为我们要使用 jsDelivr 加速访问,所以可以设置为【https://cdn.jsdelivr.net/gh/用户名/图床仓库名 】,上传完毕后,我们就可以通过【https://cdn.jsdelivr.net/gh/用户名/图床仓库名/图片路径 】加速访问我们的图片了,比如上图的图片链接为:https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A27/08.jpg 关于 jsDelivr 具体是如何引用资源的可以参考我的另一篇博客:[《免费CDN:jsDelivr+Github》](https://www.itrhx.com/2019/02/10/A18-free-cdn/) diff --git a/source/_posts/A60-2019-summary.md b/source/_posts/A60-2019-summary.md index 2d6d688d7b3e20fd3e9a6761389ec96d9e8474d8..46eaf0f434fcc7fe9d9b40acd55dc36ae83b604b 100644 --- a/source/_posts/A60-2019-summary.md +++ b/source/_posts/A60-2019-summary.md @@ -9,6 +9,7 @@ music: type: song id: 413829859 avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@3.0.4/images/trhx.png +top: true --- diff --git a/source/_posts/A62-NumPy-01.md b/source/_posts/A62-NumPy-01.md new file mode 100644 index 0000000000000000000000000000000000000000..6068b50c31dc1d57f3cfdd455443312169017f23 --- /dev/null +++ b/source/_posts/A62-NumPy-01.md @@ -0,0 +1,1181 @@ +--- +title: Python 数据分析三剑客之 NumPy(一):理解 NumPy / 数组基础 +tags: + - NumPy + - 数组 +categories: + - Python 数据分析 + - NumPy +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/numpy.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 NumPy(一):理解 NumPy 基本概念、了解数组基础。 +--- + +NumPy 系列文章: + +- [Python 数据分析三剑客之 NumPy(一):理解 NumPy / 数组基础](https://www.itrhx.com/2020/03/20/A62-NumPy-01/) +- [Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割](https://www.itrhx.com/2020/03/22/A63-NumPy-02/) +- [Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算](https://www.itrhx.com/2020/03/24/A64-NumPy-03/) +- [Python 数据分析三剑客之 NumPy(四):字符串函数总结与对比](https://www.itrhx.com/2020/03/26/A65-NumPy-04/) +- [Python 数据分析三剑客之 NumPy(五):数学 / 算术 / 统计 / 排序 / 条件 / 判断函数合集](https://www.itrhx.com/2020/03/28/A66-NumPy-05/) +- [Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作](https://www.itrhx.com/2020/03/30/A67-NumPy-06/) + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/104870084 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】了解 NumPy + +NumPy 是使用 Python 进行科学计算的基础包,支持大量的维度数组与矩阵运算,对数组运算提供大量的数学函数库。NumPy 重在数值计算,是大部分 Python 科学计算库的基础库,多用于在大型、多维数组上执行数值运算。 + +NumPy 主要包含如下的内容: + +- 一个强大的 N 维数组对象(Ndarray); +- 复杂的广播功能函数; +- 集成 C/C++/Fortran 代码的工具; +- 具有线性代数、傅里叶变换、随机数生成等功能。 + +## 【2x00】NumPy 数组与 Python 列表的区别 + +Numpy 使用 Ndarray 对象来处理多维数组,Python 列表通常存储一维数组,通过列表的嵌套也可以实现多维数组。 + +Numpy 的 Ndarray 对象是一个快速而灵活的大数据容器。Numpy 专门针对数组的操作和运算进行了设计,所以数组的存储效率和输入输出性能远优于 Python 中的嵌套列表,数组越大,Numpy 的优势就越明显。 + +通常 Numpy 数组中的所有元素的类型都是相同的,而 Python 列表中的元素类型是任意的,所以在通用性能方面 Numpy 数组不及 Python 列表,但在科学计算中,可以省掉很多循环语句,代码使用方面比 Python 列表简单的多。 + +Python 列表的元素不同类型举例: + +```python +>>> l = [True, '2', 3.2, 5] +>>> [type(item) for item in l] +[, , , ] +``` + +Python 列表中的每一项必须包含各自的类型信息、引用计数和其他信息,也就是说,每一项都是一个完整的 Python 对象,同时,Python 列表还包含一个指向指针块的指针,其中的每一个指针对应一个完整的 Python 对象,另外,列表的优势是灵活,因为每个列表元素是一个包含数据和类型信息的完整结构体。相反 NumPy 数组缺乏这种灵活性,但是 NumPy 却能更有效地存储和操作数据。 + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A62/01.png) + +## 【3x00】理解 NumPy Ndarray 对象 + +NumPy 提供了一个 N 维数组类型,即 Ndarray,它是一系列同类型数据的集合,是用于存放同类型元素的多维数组,以 0 下标为开始进行集合中元素的索引,所有 Ndarray 中的每个元素在内存中都有相同存储大小的区域。 + +Ndarray 内部由以下内容组成: + +- 一个指向数据(内存或内存映射文件中的一块数据)的指针; +- 数据类型或 dtype,描述在数组中的固定大小值的格子; +- 一个表示数组形状(shape)的元组,表示各维度大小的元组; +- 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要“跨过”的字节数。 + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A62/02.png) + +## 【4x00】理解不同维度的数组 + +NumPy 数组的维数称为秩(rank),秩就是轴的数量,即数组的维度,一维数组的秩为 1,二维数组的秩为 2,以此类推。 + +在 NumPy 中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量 — 秩,就是数组的维数。 + +很多时候可以声明 axis,axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第 1 轴进行操作,即对每一行进行操作。 + +一维数组: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4]) +>>> print(a) +[1 2 3 4] +>>> print(a.shape) +(4,) +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A62/03.png) + +--- + +二维数组: + +```python + +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) +>>> print(a) +[[1 2 3 4] + [5 6 7 8]] +>>> print(a.shape) +(2, 4) +``` + +> a.shape 输出数组的维度,对于此二维数组,可以理解为 2 行 4 列。 + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A62/04.png) + +--- + +三维数组: + +```python +>>> import numpy as np +>>> a = np.array([[[1,2,3,4], [5,6,7,8]], [[9,10,11,12], [13,14,15,16]], [[17,18,19,20], [21,22,23,24]]]) +>>> print(a) +[[[ 1 2 3 4] + [ 5 6 7 8]] + + [[ 9 10 11 12] + [13 14 15 16]] + + [[17 18 19 20] + [21 22 23 24]]] + +>>> print(a.shape) +(3, 2, 4) +``` + +> a.shape 输出数组的维度,对于此三维数组,可以理解为 3 块,每块有 2 行 4 列。 + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A62/05.png) + +有网友对三维数组的这个图有疑问,认为横线应该是 axis=0,竖线是 axis=1,斜线是 axis=2,这个确实有点儿绕,不要受到前面一维二维的影响,我把我的理解又画了一张图出来,另外大家可以尝试去取三维数组里面的某个值,多想一下就可以理解了。欢迎各位大佬一起交流学习! + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A62/06.png) + +## 【5x00】创建 Ndarray 对象(创建数组) + +### 【5x01】一张表快速了解创建数组的不同方法 + +| 方法 | 描述 | +| ------ | ------ | +| numpy.array() | 将输入数据(列表、元组、Ndarray 等)转换为数组形式
**当数据源为 Ndarray 时,该方法仍然会 copy 出一个副本,占用新的内存** | +| numpy.asarray() | 将输入数据(列表、元组、Ndarray 等)转换为数组形式
**当数据源为 Ndarray 时,该方法不会 copy 出一个副本,不占用新的内存** | +| numpy.arange() | 创建一个一维数组,该数组由一个等差数列构成
**通过指定开始值、终值和步长创建等差数列,得到的结果数组不包含终值** | +| numpy.linspace() | 创建一个一维数组,该数组由一个等差数列构成
**通过指定开始值、终值和元素个数创建等差数列,可通过 endpoint 参数指定是否包含终值** | +| numpy.logspace() | 创建一个一维数组,该数组由一个等比数列构成 | +| numpy.empty() | 创建一个指定形状、数据类型且未初始化的数组 | +| numpy.zeros() | 创建一个指定大小的数组,数组元素以 0 来填充 | +| numpy.ones() | 创建一个指定大小的数组,数组元素以 1 来填充 | +| numpy.eye() | 创建一个对角矩阵数组,返回一个二维数组,对角线上值为 1,其余位置为 0 | +| numpy.frombuffer() | 将缓冲区解释为一维数组,接受 buffer 输入参数,以流的形式读入并转化成 Ndarray 对象 | +| numpy.fromiter() | 从可迭代对象中建立 Ndarray 对象,返回一个一维数组 | + +### 【5x02】numpy.array() + +调用 NumPy 的 array 方法即可创建一个 Ndarray 对象,即创建一个数组。 + +基本语法:`numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| object | 数组或嵌套的数列 | +| dtype | 数组元素的数据类型,可选 | +| copy | 对象是否需要复制,可选 | +| order | 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认) | +| subok | 默认返回一个与基类类型一致的数组 | +| ndmin | 指定生成数组的最小维度 | + +创建一个一维数组: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3]) +>>> print(a) +[1 2 3] +>>> print(type(a)) + +``` + +创建一个二维数组: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6]]) +>>> print(a) +[[1 2 3] + [4 5 6]] +>>> print(type(a)) + +``` + +创建一个三维数组: + +```python +>>> import numpy as np +>>> a = np.array([[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]]]) +>>> print(a) +[[[ 1 2 3] + [ 4 5 6]] + + [[ 7 8 9] + [10 11 12]]] +``` + +### 【5x03】numpy.asarray() + +numpy.asarray() 方法将输入数据(列表、元组、Ndarray 等)转换为数组形式,与 numpy.array() 方法类似,但 asarray 参数比 array 少两个,另外最大的区别是**当数据源为 Ndarray 时**,array 方法仍然会 copy 出一个副本,占用新的内存,但 asarray 方法不会。 + +基本语法:`numpy.asarray(a, dtype=None, order=None)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| a | 待转换对象,可以是列表,元组,列表元组,元组列表,多维数组等 | +| dtype | 可选项,指定数据类型 | +| order | 可选项,以行优先(C)或列优先(F)的顺序存储多维数据在内存中 | + +将列表转换为 Ndarray: + +```python +>>> import numpy as np +>>> l = [1,2,3,4] +>>> n = np.asarray(l) +>>> print(n) +[1 2 3 4] +>>> print(type(n)) + +``` + +将元组转换为 Ndarray: + +```python +>>> import numpy as np +>>> l = (1,2,3,4) +>>> n = np.asarray(l) +>>> print(n) +[1 2 3 4] +>>> print(type(n)) + +``` + +将元组列表转换为 Ndarray: + +```python +>>> import numpy as np +>>> l = [(1,2,3),(4,5)] +>>> n = np.asarray(l) +>>> print(n) +[(1, 2, 3) (4, 5)] +>>> print(type(n)) + +``` + +指定 dtype 参数: + +```python +>>> import numpy as np +>>> l = [1,2,3] +>>> n = np.asarray(l, dtype=float) +>>> print(n) +[1. 2. 3.] +>>> print(type(n)) + +``` + +numpy.asarray() 方法和 numpy.array() 的区别演示: + +当输入数据为列表、元组等格式时,两者没有区别,都可以将其转为数组格式: + +```python +>>> import numpy as np +>>> a = [[1,2,3], [4,5,6], [7,8,9]] +>>> b = np.array(a) +>>> c = np.asarray(a) +>>> a[1] = 0 +>>> print(a) +[[1, 2, 3], 0, [7, 8, 9]] +>>> print(type(a)) # a 为列表 + +>>> print(b) # 列表对象 a 的值改变,array 方法得到的值不会改变 +[[1 2 3] + [4 5 6] + [7 8 9]] +>>> print(c) # 列表对象 a 的值改变,asarray 方法得到的值不会改变 +[[1 2 3] + [4 5 6] + [7 8 9]] +``` + +当输入数据为 Ndarray 时,array 方法仍然会 copy 出一个副本,占用新的内存,但 asarray 方法不会: + +```python +>>> import numpy as np +>>> a = np.ones((3,3)) +>>> b = np.array(a) +>>> c = np.asarray(a) +>>> a[1][1] = 2 +>>> print(a) +[[1. 1. 1.] + [1. 2. 1.] + [1. 1. 1.]] +>>> print(type(a)) # a 为 Ndarray 对象 + +>>> print(b) # Ndarray 对象 a 的值改变,array 方法得到的值不会改变 +[[1. 1. 1.] + [1. 1. 1.] + [1. 1. 1.]] +>>> print(c) # Ndarray 对象 a 的值改变,asarray 方法得到的值也将改变 +[[1. 1. 1.] + [1. 2. 1.] + [1. 1. 1.]] +``` + +### 【5x04】numpy.arange() + +numpy.arange() 方法用于创建一个一维数组,在指定的间隔内返回均匀间隔的数字并组成数组(Ndarray 对象),即该数组是一个等差数列构成的。arange() 类似 Python 的 range(),但是 arange() 的步长可以为小数,而 range() 的步长只能是整数。 + +基本语法:`numpy.arange([start, ]stop, [step, ]dtype=None)` + +参数解释: + +| 参数 | 描述 | +| ------- | ------- | +| start | 起始值,数字,可选项,默认起始值为 0,生成的元素包括起始值 | +| stop | 结束值,数字,生成的元素不包括结束值 | +| step | 步长,数字,可选项, 默认步长为 1,如果指定了 step,则必须给出 start | +| dtype | 输出数组的类型,如果未给出 dtype,则从其他输入参数推断数据类型 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.arange(5) # 相当于 np.array([0, 1, 2, 3, 4]) +>>> b = np.arange(2, 5) # 相当于 np.array([2, 3, 4]) +>>> c = np.arange(2, 9, 3) +>>> print('a = %s\nb = %s\nc = %s' %(a,b,c)) +a = [0 1 2 3 4] +b = [2 3 4] +c = [2 5 8] +``` + +### 【5x05】numpy.linspace() + +numpy.linspace() 方法用于创建一个一维数组,在指定的间隔内返回均匀间隔的数字并组成数组(Ndarray 对象),即该数组是一个等差数列构成的。linspace() 方法类似于 arange(),两者除了参数有差别以外,还有以下的区别: + +- arange() 方法类似于内置函数 range(),通过指定**开始值、终值和步长**创建表示等差数列的一维数组,得到的结果数组不包含终值。 + +- linspace() 通过指定**开始值、终值和元素个数**创建表示等差数列的一维数组,可以通过 endpoint 参数指定是否包含终值,默认值为True,即包含终值。 + +基本语法:`numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| start | 序列的起始值 | +| stop | 序列的终止值,如果 endpoint 为 True,则该值将包含于数列中 | +| num | 可选项,int 类型,要生成的等步长的样本数量,即元素个数,默认为 50 | +| endpoint | 可选项,bool 类型,该值为 True 时,数列中将包含 stop 值,反之则不包含,默认为 True | +| retstep | 可选项,bool 类型,该值为 True 时,生成的数组中会显示间距,反之则不显示,默认为 False | +| dtype | 可选项,Ndarray 的数据类型 | +| axis | 可选项,int 类型,结果中的轴用于存储样本。仅当 start 或 stop 类似于数组时才相关
默认情况下为 0,采样将沿着在开始处插入的新轴进行,使用 -1 来获得轴的末端 | + +应用举例: + +不指定 num 值,将默认生成 50 个元素,数列中将包含 stop 值: + +```python +>>> import numpy as np +>>> a = np.linspace(1, 10) +>>> print(a) +[ 1. 1.18367347 1.36734694 1.55102041 1.73469388 1.91836735 + 2.10204082 2.28571429 2.46938776 2.65306122 2.83673469 3.02040816 + 3.20408163 3.3877551 3.57142857 3.75510204 3.93877551 4.12244898 + 4.30612245 4.48979592 4.67346939 4.85714286 5.04081633 5.2244898 + 5.40816327 5.59183673 5.7755102 5.95918367 6.14285714 6.32653061 + 6.51020408 6.69387755 6.87755102 7.06122449 7.24489796 7.42857143 + 7.6122449 7.79591837 7.97959184 8.16326531 8.34693878 8.53061224 + 8.71428571 8.89795918 9.08163265 9.26530612 9.44897959 9.63265306 + 9.81632653 10. ] +``` + +指定 num 值为 10,将生成 10 个元素,数列中将包含 stop 值: + +```python +>>> import numpy as np +>>> a = np.linspace(1, 10, 10) +>>> print(a) +[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.] +``` + +指定 endpoint 值为 False,retstep 值为 True,数列中不包含 stop 值,生成的数组中会显示间距: + +```python +>>> import numpy as np +>>> a = np.linspace(1, 10, 10, endpoint=False, retstep=True) +>>> print(a) +(array([1. , 1.9, 2.8, 3.7, 4.6, 5.5, 6.4, 7.3, 8.2, 9.1]), 0.9) +``` + +指定 dtype 类型为 int: + +```python +>>> import numpy as np +>>> a = np.linspace(1, 10, 10, endpoint=False, retstep=True, dtype=int) +>>> print(a) +(array([1, 1, 2, 3, 4, 5, 6, 7, 8, 9]), 0.9) +``` + +### 【5x06】numpy.logspace() + +numpy.logspace() 方法用于创建一个一维数组,该数组由一个等比数列构成。 + +基本语法:`numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| start | 序列的起始值 | +| stop | 序列的终止值,如果 endpoint 为 True,则该值将包含于数列中 | +| num | 可选项,int 类型,要生成的等步长的样本数量,即元素个数,默认为 50 | +| endpoint | 可选项,bool 类型,该值为 True 时,数列中将包含 stop 值,反之则不包含,默认为 True | +| base | 可选项,float 类型,对数 log 的底数,即取对数的时候 log 的下标 ,默认为 10.0 | +| dtype | 可选项,Ndarray 的数据类型 | +| axis | 可选项,int 类型,结果中的轴用于存储样本。仅当 start 或 stop 类似于数组时才相关
默认情况下为 0,采样将沿着在开始处插入的新轴进行,使用 -1 来获得轴的末端 | + +应用举例: + +指定起始值为 0,,终止值为 9,**base 默认值为 10**,代表的是 **10** 的幂,即 0 代表 **10** 的 0 次方,9 代表 **10** 的 9 次方: + +```python +>>> import numpy as np +>>> a = np.logspace(0, 9, num = 10) +>>> print(a) +[1.e+00 1.e+01 1.e+02 1.e+03 1.e+04 1.e+05 1.e+06 1.e+07 1.e+08 1.e+09] +``` + +指定起始值为 0,,终止值为 9,**base 值为 2**,代表的是 **2** 的幂,即 0 代表 **2** 的 0 次方,9 代表 **2** 的 9 次方: + +```python +>>> import numpy as np +>>> a = np.logspace(0, 9, num = 10, base = 2) +>>> print(a) +[ 1. 2. 4. 8. 16. 32. 64. 128. 256. 512.] +``` + +起始值和终止值都可以为 float 类型: + +```python +>>> import numpy as np +>>> a = np.logspace(1.0, 2.0, num = 10) +>>> print(a) +[ 10. 12.91549665 16.68100537 21.5443469 27.82559402 + 35.93813664 46.41588834 59.94842503 77.42636827 100. ] +``` + +定义 dtype 属性值为 int 类型: + +```python +>>> import numpy as np +>>> a = np.logspace(0.0, 9.0, num = 10, base = 2, dtype = int) +>>> print(a) +[ 1 2 4 8 16 32 64 128 256 512] +``` + + + +### 【5x07】numpy.empty() + +numpy.empty() 方法可用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组。 + +基本语法:`numpy.empty(shape, dtype = float, order = 'C')` + +参数解释: + +| 参数 | 描述 | +| ------- | ------ | +| shape | 数组形状 | +| dtype | 数据类型,可选 | +| order | 以行优先(C)或列优先(F)的顺序存储多维数据在内存中 | + +创建一个一维空数组(传递一个参数即可,代表数组长度,数组元素为随机值,因为它们未初始化): + +```python +>>> import numpy as np +>>> a = np.empty(3) +>>> print(a) +[3.538e-321 3.538e-321 0.000e+000] +>>> print(type(a)) + +>>> +>>> a = np.empty(3, dtype = int) # 定义类型为整数 +>>> print(a) +[716 0 716] +``` + +创建一个二维空数组(传递两个参数,分别代表行数和列数): + +```python +>>> import numpy as np +>>> a = np.empty([3, 2]) +>>> print(a) +[[6.23042070e-307 3.56043053e-307] + [1.37961641e-306 1.11258854e-306] + [8.90100843e-307 1.11261027e-306]] +>>> print(type(a)) + +``` + +创建一个三维空数组(传递三个参数,分别代表块数、每一块的行数和列数): + +```python +>>> import numpy as np +>>> a = np.empty([3, 2, 4]) +>>> print(a) +[[[0. 0. 0. 0.] + [0. 0. 0. 0.]] + + [[0. 0. 0. 0.] + [0. 0. 0. 0.]] + + [[0. 0. 0. 0.] + [0. 0. 0. 0.]]] +``` + +### 【5x08】numpy.zeros() + +numpy.zeros() 方法用于创建指定大小的数组,数组元素以 0 来填充。 + +基本语法:`numpy.zeros(shape, dtype = float, order = 'C')` + +参数解释: + +| 参数 | 描述 | +| ------- | ------- | +| shape | 数组形状 | +| dtype | 数据类型,可选 | +| order | 以行优先(C)或列优先(F)的顺序存储多维数据在内存中 | + +创建一个一维数组(传递一个参数即可,代表数组长度,数组元素以 0 填充): + +```python +>>> import numpy as np +>>> a = np.zeros(5) +>>> print(a) +[0. 0. 0. 0. 0.] +>>> print(type(a)) + +>>> +>>> a = np.zeros(5, dtype = int) # 定义类型为整数 +>>> print(a) +[0 0 0 0 0] +``` + +创建一个二维数组(传递两个参数,分别代表行数和列数): + +```python +>>> import numpy as np +>>> a = np.zeros([2, 3]) +>>> print(a) +[[0. 0. 0.] + [0. 0. 0.]] +>>> print(type(a)) + +``` + +创建一个三维空数组(传递三个参数,分别代表块数、每一块的行数和列数): + +```python +>>> import numpy as np +>>> a = np.zeros([4, 2, 3]) +>>> print(a) +[[[0. 0. 0.] + [0. 0. 0.]] + + [[0. 0. 0.] + [0. 0. 0.]] + + [[0. 0. 0.] + [0. 0. 0.]] + + [[0. 0. 0.] + [0. 0. 0.]]] +>>> print(type(a)) + +``` + +### 【5x09】numpy.ones() + +numpy.ones() 方法用于创建指定大小的数组,数组元素以 1 来填充。 + +基本语法:`numpy.ones(shape, dtype = None, order = 'C')` + +参数解释: + +| 参数 | 描述 | +| ------- | ------- | +| shape | 数组形状 | +| dtype | 数据类型,可选 | +| order | 以行优先(C)或列优先(F)的顺序存储多维数据在内存中 | + +创建一个一维数组(传递一个参数即可,代表数组长度,数组元素以 0 填充): + +```python +>>> import numpy as np +>>> a = np.ones(5) +>>> print(a) +[1. 1. 1. 1. 1.] +>>> print(type(a)) + +>>> +>>> a = np.ones(5, dtype = int) # 定义类型为整数 +>>> print(a) +[1 1 1 1 1] +>>> print(type(a)) + +``` + +创建一个二维数组(传递两个参数,分别代表行数和列数): + +```python +>>> import numpy as np +>>> a = np.ones([2, 3]) +>>> print(a) +[[1. 1. 1.] + [1. 1. 1.]] +>>> print(type(a)) + +``` + +创建一个三维数组(传递三个参数,分别代表块数、每一块的行数和列数): + +```python +>>> import numpy as np +>>> a = np.ones([3, 2 ,5]) +>>> print(a) +[[[1. 1. 1. 1. 1.] + [1. 1. 1. 1. 1.]] + + [[1. 1. 1. 1. 1.] + [1. 1. 1. 1. 1.]] + + [[1. 1. 1. 1. 1.] + [1. 1. 1. 1. 1.]]] +>>> print(type(a)) + +``` + +### 【5x10】numpy.eye() + +numpy.eye() 方法用于创建对角矩阵数组,返回一个二维数组,对角线上值为 1,其余位置为 0。 + +基本语法:`numpy.eye(N, M=None, k=0, dtype=, order='C')` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| N | int 类型,目标数组的行数 | +| M | int 类型,可选项,目标数组的列数,如果未指定,则默认与行数(N)相同 | +| k | int 类型,可选项,对角线索引,0(默认值)为主对角线,正值为上对角线,负值为下对角线
简单来说可以理解成将值为 1 的对角线向左右平移 k 个单位,默认值 0 即对角线为 1,k 为正值右移,负值左移 | +| dtype | 可选项,返回数组的数据类型 | +| order | 可选项,以行优先(C)或列优先(F)的顺序存储多维数据在内存中 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.eye(5, 5)) # 创建一个对角矩阵 +[[1. 0. 0. 0. 0.] + [0. 1. 0. 0. 0.] + [0. 0. 1. 0. 0.] + [0. 0. 0. 1. 0.] + [0. 0. 0. 0. 1.]] +>>> print(np.eye(5, 5, k=1)) # 将值为 1 的对角线向右移 1 个单位 +[[0. 1. 0. 0. 0.] + [0. 0. 1. 0. 0.] + [0. 0. 0. 1. 0.] + [0. 0. 0. 0. 1.] + [0. 0. 0. 0. 0.]] +>>> print(np.eye(5, 5, k=-2)) # 将值为 1 的对角线向右左移 2 个单位 +[[0. 0. 0. 0. 0.] + [0. 0. 0. 0. 0.] + [1. 0. 0. 0. 0.] + [0. 1. 0. 0. 0.] + [0. 0. 1. 0. 0.]] +>>> print(np.eye(5, dtype=int)) # 指定为 int 类型 +[[1 0 0 0 0] + [0 1 0 0 0] + [0 0 1 0 0] + [0 0 0 1 0] + [0 0 0 0 1]] +``` + +### 【5x11】numpy.frombuffer() + +numpy.frombuffer() 方法将缓冲区解释为一维数组,接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象。当 buffer 是字符串时,Python3 默认 str 是 Unicode 类型,所以要转成 bytestring,即在原 str 前加上 b。 + +基本语法:`numpy.frombuffer(buffer, dtype=float, count=-1, offset=0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| buffer | 可以是任意对象,会以流的形式读入 | +| dtype | 可选项,返回数组的数据类型 | +| count | 可选项,读取的数据数量,默认为 -1,即读取缓冲区中所有数据 | +| offset | 可选项,读取的起始位置,以字节为单位,默认为 0 | + +应用举例: + +```python +>>> import numpy as np +>>> a = b'I love python!' +>>> b = np.frombuffer(a, dtype='S1') +>>> print(b) +[b'I' b' ' b'l' b'o' b'v' b'e' b' ' b'p' b'y' b't' b'h' b'o' b'n' b'!'] +>>> +>>> b = np.frombuffer(a, dtype='S1', count=5) # 指定要读取的数据量 +>>> print(b) +[b'I' b' ' b'l' b'o' b'v'] +>>> +>>> b = np.frombuffer(a, dtype='S1', count=5, offset=6) # 指定读取数据的起始位置 +>>> print(b) +[b' ' b'p' b'y' b't' b'h'] +>>> +>>> import numpy as np +>>> a = b'\x01\x02' +>>> b = np.frombuffer(a, dtype='uint8') +>>> print(b) +[1 2] +``` + +### 【5x12】numpy.fromiter() + +numpy.fromiter() 方法可以从可迭代对象中建立 Ndarray 对象,返回一个一维数组。 + +基本语法:`numpy.fromiter(iterable, dtype, count=-1)` + +参数解释: + +| 参数 | 描述 | +| ------- | ------- | +| iterable | 可迭代对象 | +| dtype | 返回数组的数据类型 | +| count | 读取的数据数量,默认为 -1,即读取所有数据 | + +应用举例: + +```python +>>> import numpy as np +>>> l = range(5) +>>> i = iter(l) # iter() 方法用于生成迭代器 +>>> n = np.fromiter(i, dtype=float) # 从可迭代对象中建立 Ndarray 对象 +>>> print(l, type(l)) +range(0, 5) +>>> print(i, type(i)) + +>>> print(n, type(n)) +[0. 1. 2. 3. 4.] +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/104870084 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【6x00】改变数组的维度或者形状 + +### 【6x01】numpy.reshape() + +numpy.reshape() 方法用于重新调整数组的维数(重塑)。 + +基本语法:`numpy.reshape(a, newshape, order='C')` + +参数解释: + +**a**:要重塑的数组 + +**newshape**:重塑后的形状,新形状应与原始形状兼容。如果是整数,则结果将是该长度的一维数组。一个形状维度可以是-1。在这种情况下,将根据数组的长度和剩余维度推断该值。举个例子,原数组 a 是一个 4 行 n 列的二维数组,现在要将其转换成只有 1 行的一维数组,由于不清楚原二维数组有多少列,也就不清楚一共有多少元素,所以可以使用 `np.reshape(a, (1, -1))` 语句将其转化为一维数组,其中 -1 会让程序自动计算有多少列,此概念将在后面举例具体说明。 + +**order**:可选值为 C、F、A,使用索引顺序读取 a 的元素,并按照索引顺序将元素放到变换后的的数组中,默认参数为 C。 + +**`C` 指的是用类 C 写的读/索引顺序的元素,最后一个维度变化最快,第一个维度变化最慢。横着读,横着写,优先读/写一行。** + +**`F` 是指用 FORTRAN 类索引顺序读/写元素,最后一个维度变化最慢,第一个维度变化最快。竖着读,竖着写,优先读/写一列。注意,C 和 F 选项不考虑底层数组的内存布局,只引用索引的顺序。** + +**`A` 选项所生成的数组的效果与原数组 a 的数据存储方式有关,如果数据是按照 FORTRAN 存储的话,它的生成效果与 F 相同,否则与 C 相同。** + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1,2,3,4,5,6,7,8]) # 创建一个一维数组 +>>> print(a) +[1 2 3 4 5 6 7 8] +>>> b = np.reshape(a, (2,4)) # 重塑为一个二维数组 +>>> print(b) +[[1 2 3 4] + [5 6 7 8]] +>>> c = np.reshape(a, (2,2,2)) # 重塑为一个三维数组 +>>> print(c) +[[[1 2] + [3 4]] + + [[5 6] + [7 8]]] +``` + +添加 order 参数举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2,3], [4,5,6]]) # 创建一个二维数组 +>>> print(a) +[[1 2 3] + [4 5 6]] +>>> b = np.reshape(a, 6, order='C') # 按照行优先 +>>> print(b) +[1 2 3 4 5 6] +>>> b = np.reshape(a, 6, order='F') # 按照列优先 +>>> print(b) +[1 4 2 5 3 6] +``` + +另外,reshape 方法新生成的数组和原数组共用一个内存,不管改变哪个都会互相影响: + +```python +>>> import numpy as np +>>> a = np.array([1,2,3,4,5,6,7,8]) +>>> b = np.reshape(a, (2,4)) +>>> print(a) +[1 2 3 4 5 6 7 8] +>>> print(b) +[[1 2 3 4] + [5 6 7 8]] +>>> a[0] = 666 +>>> print(a) +[666 2 3 4 5 6 7 8] +>>> print(b) +[[666 2 3 4] + [ 5 6 7 8]] +``` + +newshape 重塑后的形状维度可以是 -1,简单举例: + +- `reshape(1,-1)`:将原数组转化成一行 N 列 + +- `reshape(2,-1)`:将原数组转换成两行 N 列 + +- `reshape(-1,1)`:将原数组转换成一列 N 行 + +- `reshape(-1,2)`:将原数组转化成两列 N 行 + +```python +>>> import numpy as np +>>> a = np.arange(16) # 生成一个由 0-15 组成的一维数组 +>>> print(a) +[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15] +>>> b = np.reshape(a, (2,8)) # 将一维数组 a 转换成一个 2 行 8 列的二维数组 b +>>> print(b) +[[ 0 1 2 3 4 5 6 7] + [ 8 9 10 11 12 13 14 15]] +>>> c = np.reshape(b, (8,-1)) # 将二维数组 b 转换成 8 行的格式,程序自动计算列数(列数:16/8=2) +>>> print(c) +[[ 0 1] + [ 2 3] + [ 4 5] + [ 6 7] + [ 8 9] + [10 11] + [12 13] + [14 15]] +>>> d = np.reshape(c, (-1,4)) # 将二维数组 c 转换成 4 列的格式,程序自动计算行数(行数:16/4=4) +>>> print(d) +[[ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + [12 13 14 15]] +``` + +### 【6x02】numpy.ravel() + +numpy.ravel() 方法用于完成展平的操作。 + +基本语法:`numpy.ravel(a, order='C')` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| a | 待转换的数组 | +| order | 值可以是 `C` `F` `A` `K`,含义与 reshape 方法中参数的一样,与 reshape 方法不同的是多了个值 `K`
`K` 表示按顺序在内存中读取元素,但在跨距为负时会反转数据 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[[1,2,3,4], [5,6,7,8]], [[9,10,11,12], [13,14,15,16]], [[17,18,19,20], [21,22,23,24]]]) +>>> print(a) +[[[ 1 2 3 4] + [ 5 6 7 8]] + + [[ 9 10 11 12] + [13 14 15 16]] + + [[17 18 19 20] + [21 22 23 24]]] +>>> print(a.ravel()) +[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24] +>>> print(np.ravel(a)) +[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24] +``` + +### 【6x03】numpy.resize() + +numpy.resize() 方法会**直接修改所操作的数组**,返回具有指定形状的新数组,如果新数组大于原始数组,则新数组将填充 a 的重复副本。 + +基本语法:`numpy.resize(a, new_shape)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| a | 待转换的数组 | +| new_shape | 新数组的大小形状 | + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6]]) +>>> print(a) +[[1 2 3] + [4 5 6]] +>>> print(np.resize(a, (3, 2))) +[[1 2] + [3 4] + [5 6]] +>>> print(np.resize(a, (3, 3))) +[[1 2 3] + [4 5 6] + [1 2 3]] +>>> print(np.resize(a, (2, 4))) +[[1 2 3 4] + [5 6 1 2]] +``` + +### 【6x04】numpy.ndarray.flatten() + +numpy.ndarray.flatten() 方法恰如其名,flatten 就是展平的意思,与 ravel 函数的功能相同,二者的不同之处在于:flatten 方法会请求分配新的内存来保存结果,而 ravel 方法只是返回数组的一个视图(view)。 + +基本语法:`ndarray.flatten(order='C')` + +其 order 参数的值可以是 `C` `F` `A` `K`,含义与 reshape 和 ravel 方法中参数的一样. + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[[1,2,3,4], [5,6,7,8]], [[9,10,11,12], [13,14,15,16]], [[17,18,19,20], [21,22,23,24]]]) +>>> print(a) +[[[ 1 2 3 4] + [ 5 6 7 8]] + + [[ 9 10 11 12] + [13 14 15 16]] + + [[17 18 19 20] + [21 22 23 24]]] +>>> print(a.flatten()) +[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24] +``` + +### 【6x05】numpy.ndarray.shape + +numpy.ndarray.shape 本来是 Ndarray 对象的一个属性,但可以通过直接用一个正整数元组对其赋值来设置数组的维度: + +```python +>>> import numpy as np +>>> a = np.array([[[1,2,3,4], [5,6,7,8]], [[9,10,11,12], [13,14,15,16]], [[17,18,19,20], [21,22,23,24]]]) +>>> print(a) +[[[ 1 2 3 4] + [ 5 6 7 8]] + + [[ 9 10 11 12] + [13 14 15 16]] + + [[17 18 19 20] + [21 22 23 24]]] +>>> a.shape = (3, 8) +>>> print(a) +[[ 1 2 3 4 5 6 7 8] + [ 9 10 11 12 13 14 15 16] + [17 18 19 20 21 22 23 24]] +``` + +### 【6x06】numpy.ndarray.transpose() & numpy.ndarray.T + +ndarray.transpose() 和 ndarray.T 方法的作用是对数组进行转置,即原来的行变成列,原来的列变成行。 + +```python +>>> import numpy as np +>>> a = np.array([[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17]]) +>>> print(a) +[[ 0 1 2 3 4 5] + [ 6 7 8 9 10 11] + [12 13 14 15 16 17]] +>>> print(a.transpose()) +[[ 0 6 12] + [ 1 7 13] + [ 2 8 14] + [ 3 9 15] + [ 4 10 16] + [ 5 11 17]] +>>> print(a.T) +[[ 0 6 12] + [ 1 7 13] + [ 2 8 14] + [ 3 9 15] + [ 4 10 16] + [ 5 11 17]] +``` + +### 【6x07】numpy.swapaxes() + +numpy.swapaxes() 方法用于对换数组的两个轴 + +基本语法:`numpy.swapaxes(a, axis1, axis2)` + +参数解释:a 为原始数组,axis1、axis2 分别对应两个轴,类型为整数 + +```python +>>> import numpy as np +>>> a = np.array([[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17]]) +>>> print(a) +[[ 0 1 2 3 4 5] + [ 6 7 8 9 10 11] + [12 13 14 15 16 17]] +>>> print(np.swapaxes(a, 1, 0)) # 交换 1 轴和 0 轴,此处相当于数组的转置,与【6x06】效果相同 +[[ 0 6 12] + [ 1 7 13] + [ 2 8 14] + [ 3 9 15] + [ 4 10 16] + [ 5 11 17]] +``` + +## 【7x00】NumPy 数据类型 + +NumPy 数组包含同一类型的值,支持的数据类型比 Python 内置的类型更多,构建一个数组时,可以用一个字符串参数 dtype 来指定数据类型: + +```python +np.zeros(10, dtype='int16') +``` + +```python +np.zeros(10, dtype=np.int16) +``` + +| 数据类型 |
描述
| +| ------------ | :------ | +| bool_ |               **布尔值**(True 或者 False),用一个字节存储 | +| int_ |               **默认的整型**(类似于 C 语言中的 long,通常情况下是 int32 或 int64) | +| intc |               **同 C 语言的 int 相同**(通常是 int32 或 int64) | +| intp |               **用作索引的整型**(和 C 语言的 ssize_t 相同,通常情况下是 int32 或 int64) | +| int8 |               **字节**(byte,范围从 –128 到 127),可用 i1 缩写代替 | +| int16 |               **整型**(范围从 –32768 到 32767),可用 i2 缩写代替 | +| int32 |               **整型**(范围从 –2147483648 到 2147483647),可用 i4 缩写代替 | +| int64 |               **整型**(范围从 –9223372036854775808 到 9223372036854775807),可用 i8 缩写代替 | +| uint8 |               **无符号整型**(范围从 0 到 255) | +| uint16 |               **无符号整型**(范围从 0 到 65535) | +| uint32 |               **无符号整型**(范围从 0 到 4294967295) | +| uint64 |               **无符号整型**(范围从 0 到 18446744073709551615) | +| float_ |               **float64** 的简化形式 | +| float16 |               **半精度浮点型**,包括:1 比特位符号,5 比特位指数,10 比特位尾数 | +| float32 |               **单精度浮点型**,包括:1 比特位符号,8 比特位指数,23 比特位尾数 | +| float64 |               **双精度浮点型**,包括:1 比特位符号,11 比特位指数,52 比特位尾数 | +| complex_ |               **complex128** 的简化形式 | +| complex64 |               **复数**,表示双 32 位浮点数(实数部分和虚数部分) | +| complex128 |               **复数**,表示双 64 位浮点数(实数部分和虚数部分) | + +## 【8x00】NumPy 数组属性 + +| 属性 | 描述 | +| ------ | ------ | +| ndarray.ndim | 秩,即轴的数量或维度的数量,一维数组的秩为 1,二维数组的秩为 2,以此类推 | +| ndarray.shape | 数组的维度,对于矩阵,n 行 m 列 | +| ndarray.size | 数组元素的总个数,相当于 .shape 中 n*m 的值 | +| ndarray.dtype | ndarray 对象的元素类型 | +| ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 | +| ndarray.flags | ndarray 对象的内存信息 | +| ndarray.real | ndarray元素的实部 | +| ndarray.imag | ndarray 元素的虚部 | +| ndarray.data | 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性 | + +其中 ndarray.flags 包含以下属性: + +| 属性 | 描述 | +| ------ | ------ | +| `C_CONTIGUOUS (C)` | 数据是在一个单一的 C 风格的连续段中 | +| `F_CONTIGUOUS (F)` | 数据是在一个单一的 Fortran 风格的连续段中 | +| `OWNDATA (O)` | 数组拥有它所使用的内存或从另一个对象中借用它 | +| `WRITEABLE (W)` | 数据区域可以被写入,将该值设置为 False,则数据为只读 | +| `ALIGNED (A)` | 数据和所有元素都适当地对齐到硬件上 | +| `UPDATEIFCOPY (U)` | 这个数组是其它数组的一个副本,当这个数组被释放时,原数组的内容将被更新 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1,2,3,4,5]) +>>> print(a.flags) + C_CONTIGUOUS : True + F_CONTIGUOUS : True + OWNDATA : True + WRITEABLE : True + ALIGNED : True + WRITEBACKIFCOPY : False + UPDATEIFCOPY : False +``` + +ndarray.shape 查看数组维度以及更改数组形状: + +```python +>>> import numpy as np +>>> a = np.array([[1,2,3],[4,5,6]]) +>>> print(a) +[[1 2 3] + [4 5 6]] +>>> print(a.shape) +(2, 3) +>>> a.shape = (3, 2) +>>> print(a) +[[1 2] + [3 4] + [5 6]] +>>> print(a.shape) +(3, 2) +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/104870084 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A63-NumPy-02.md b/source/_posts/A63-NumPy-02.md new file mode 100644 index 0000000000000000000000000000000000000000..d18b23f91a7f81d5821aeefa829a97e53ac7f07e --- /dev/null +++ b/source/_posts/A63-NumPy-02.md @@ -0,0 +1,1412 @@ +--- +title: Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割 +tags: + - NumPy + - 数组 + - 索引 + - 切片 + - 广播 + - 拼接 + - 分割 +categories: + - Python 数据分析 + - NumPy +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/numpy.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 NumPy(二):数组的索引、切片、广播、拼接、分割等操作。 +--- + +NumPy 系列文章: + +- [Python 数据分析三剑客之 NumPy(一):理解 NumPy / 数组基础](https://www.itrhx.com/2020/03/20/A62-NumPy-01/) +- [Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割](https://www.itrhx.com/2020/03/22/A63-NumPy-02/) +- [Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算](https://www.itrhx.com/2020/03/24/A64-NumPy-03/) +- [Python 数据分析三剑客之 NumPy(四):字符串函数总结与对比](https://www.itrhx.com/2020/03/26/A65-NumPy-04/) +- [Python 数据分析三剑客之 NumPy(五):数学 / 算术 / 统计 / 排序 / 条件 / 判断函数合集](https://www.itrhx.com/2020/03/28/A66-NumPy-05/) +- [Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作](https://www.itrhx.com/2020/03/30/A67-NumPy-06/) + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/104988137 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】认识 Numpy 中的 nan 和 inf + +nan(NAN,Nan):全称 not a number,即不是一个数字 +inf(-inf,inf):全称 infinity,inf 表示正无穷,-inf 表示负无穷 + +以下情况 Numpy 中会出现 nan: + +- 当读取本地的文件为 float 的时候,如果有缺失,就会出现 nan +- 当做了一个不合适的计算的时候(如:无穷大减去无穷大) + +以下情况会出现 inf 或者 -inf: + +- 比如一个数字除以 0,在 Python 中直接会报错,但在 Numpy 中则是一个 inf 或者 -inf + +指定一个 nan 或者 inf: + +```python +>>> import numpy as np +>>> a = np.nan +>>> b = np.inf +>>> print(a) +nan +>>> print(b) +inf +>>> type(a) + +>>> type(b) + +``` + +注意两个 nan 并不相等,而两个 inf 是相等的 + +```python +>>> np.nan == np.nan +False +>>> np.inf == np.inf +True +``` + +nan 和任何值计算都为 nan: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4, 5]) +>>> b = np.array([1, 2, np.nan, 4, np.nan]) +>>> print(a+b) +[ 2. 4. nan 8. nan] +``` + +### 【1x01】判断是否为 nan 和 inf + +- isnan:判断元素是否为 nan(非数字) +- isinf:判断元素是否为正无穷大或负无穷大 +- isposinf:判断元素是否为正无穷大 +- isneginf:判断元素是否为负无穷大 +- isfinite:判断元素是否为有限的(不是非数字,正无穷大和负无穷大中的一个) + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [np.nan, 6, 7, np.nan], [9 ,np.nan, 10, 11]]) +>>> print(a) +[[ 1. 2. 3. 4.] + [nan 6. 7. nan] + [ 9. nan 10. 11.]] +>>> np.isnan(a) +array([[False, False, False, False], + [ True, False, False, True], + [False, True, False, False]]) +``` + +### 【1x02】统计数组中 nan 的个数 + +1、利用 `np.count_nonzero` 方法,结合两个 nan 不相等的属性,可以判断数组中 nan 的个数: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [np.nan, 6, 7, np.nan], [9 ,np.nan, 10, 11]]) +>>> print(a) +[[ 1. 2. 3. 4.] + [nan 6. 7. nan] + [ 9. nan 10. 11.]] +>>> np.count_nonzero(a != a) # 判断 nan 的个数,a != a 即为 nan,nan != nan +3 +``` + +2、`isnan()` 方法可以判断哪些是 nan,再结合 `np.count_nonzero` 方法可以判断数组中 nan 的个数: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [np.nan, 6, 7, np.nan], [9 ,np.nan, 10, 11]]) +>>> print(a) +[[ 1. 2. 3. 4.] + [nan 6. 7. nan] + [ 9. nan 10. 11.]] +>>> np.isnan(a) # np.isnan(a) 与 a != a 效果相同,判断那些是 nan +array([[False, False, False, False], + [ True, False, False, True], + [False, True, False, False]]) +>>> np.count_nonzero(np.isnan(a)) +3 +``` + +3、利用 `collections` 模块的 `Counter` 方法来统计 nan 的个数(此方法仅适用于一维数组): + +```python +>>> from collections import Counter +>>> import numpy as np +>>> a = np.array([1, 2, np.nan, 4, np.nan]) +>>> print(Counter(np.isnan(a))) +Counter({False: 3, True: 2}) +``` + +### 【1x03】统计数组中 inf 的个数 + +1、`isinf()` 方法可以判断哪些是 inf,再结合 `np.count_nonzero` 方法可以判断数组中 inf 的个数: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [np.inf, 6, 7, -np.inf], [9 ,-np.inf, 10, 11]]) +>>> print(a) +[[ 1. 2. 3. 4.] + [ inf 6. 7. -inf] + [ 9. -inf 10. 11.]] +>>> np.isinf(a) +array([[False, False, False, False], + [ True, False, False, True], + [False, True, False, False]]) +>>> np.count_nonzero(np.isinf(a)) +3 +``` + +2、利用 `collections` 模块的 `Counter` 方法来统计 inf 的个数(此方法仅适用于一维数组): + +```python +>>> from collections import Counter +>>> import numpy as np +>>> a = np.array([1, 2, np.inf, 4, -np.inf]) +>>> print(Counter(np.isinf(a))) +Counter({False: 3, True: 2}) +``` + +### 【1x04】替换 inf 和 nan + +`numpy.nan_to_num()` 方法可以将 nan 替换为零,将 inf 替换为有限数。 + +```python +>>> import numpy as np +>>> a = np.array([[1, np.nan, 3, 4], [np.inf, 6, 7, -np.inf], [9 ,-np.inf, 10, np.nan]]) +>>> print(a) +[[ 1. nan 3. 4.] + [ inf 6. 7. -inf] + [ 9. -inf 10. nan]] +>>> print(np.nan_to_num(a)) +[[ 1.00000000e+000 0.00000000e+000 3.00000000e+000 4.00000000e+000] + [ 1.79769313e+308 6.00000000e+000 7.00000000e+000 -1.79769313e+308] + [ 9.00000000e+000 -1.79769313e+308 1.00000000e+001 0.00000000e+000]] +``` + +如果要将 nan 和 inf 替换成特定的值,则可以用以下方法: + +```python +>>> import numpy as np +>>> a = np.array([[1, np.nan, 3, 4], [np.inf, 6, 7, -np.inf], [9 ,-np.inf, 10, np.nan]]) +>>> print(a) +[[ 1. nan 3. 4.] + [ inf 6. 7. -inf] + [ 9. -inf 10. nan]] +>>> loc_nan = np.isnan(a) +>>> loc_inf = np.isinf(a) +>>> a[loc_nan] = 111 +>>> a[loc_inf] = 222 +>>> print(a) +[[ 1. 111. 3. 4.] + [222. 6. 7. 222.] + [ 9. 222. 10. 111.]] +``` + +## 【2x00】NumPy 索引 + +### 【2x01】获取具体元素 + +NumPy 的索引和 Python 列表的索引类似,可以通过中括号指定索引获取第 i 个值(从 0 开始计数): + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4]) +>>> print(a[0]) +1 +>>> print(a[2]) +3 +>>> print(a[-1]) +4 +>>> print(a[-2]) +3 +``` + +在多维数组中,可以用逗号分隔的索引元组获取具体某个元素: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) +>>> print(a) +[[1 2 3] + [4 5 6] + [7 8 9]] +>>> print(a[1, 2]) +6 +>>> print(a[0, -2]) +2 +``` + +```python +>>> a = np.array([[[1,2,3,4], [5,6,7,8]], [[9,10,11,12], [13,14,15,16]], [[17,18,19,20], [21,22,23,24]]]) +>>> print(a) +[[[ 1 2 3 4] + [ 5 6 7 8]] + + [[ 9 10 11 12] + [13 14 15 16]] + + [[17 18 19 20] + [21 22 23 24]]] +>>> print(a[0, 1, 2]) +7 +>>> print(a[1, 0, -1]) +12 +``` + +### 【2x02】获取行或列 + +```python +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) +>>> print(a) +[[ 1 2 3] + [ 4 5 6] + [ 7 8 9] + [10 11 12]] +>>> print(a[1]) # 取一整行 +[4 5 6] +>>> print(a[1, :]) # 取一整行,效果同上 +[4 5 6] +>>> print(a[1, ...]) # 取一整行,效果同上 +[4 5 6] +>>> print(a[:, 2]) # 取一整列 +[ 3 6 9 12] +>>> print(a[..., 2]) # 取一整列,效果同上 +[ 3 6 9 12] +>>> print(a[1:3]) # 取多行 +[[4 5 6] + [7 8 9]] +>>> print(a[:, 0:2]) # 取多列 +[[ 1 2] + [ 4 5] + [ 7 8] + [10 11]] +>>> print(a[[1, 3], :]) # 取第一、三行和所有列 +[[ 4 5 6] + [10 11 12]] +>>> print(a[:, [0, 2]]) # 取第零、二列和所有行 +[[ 1 3] + [ 4 6] + [ 7 9] + [10 12]] +``` + +### 【2x03】布尔索引 + +除了直接获取元素以外,还可以通过一个布尔数组来索引目标数组,即通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。 + +以下实例将筛选出大于 6 的元素: + +```python +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) +>>> print(a) +[[ 1 2 3] + [ 4 5 6] + [ 7 8 9] + [10 11 12]] +>>> print(a[a > 6]) +[ 7 8 9 10 11 12] +``` + +以下实例使用取补运算符 `~` 来过滤掉 inf: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, np.inf, 3, -np.inf, 4, 5]) +>>> print(a) +[ 1. 2. inf 3. -inf 4. 5.] +>>> print(a[~np.isinf(a)]) +[1. 2. 3. 4. 5.] +``` + +### 【2x04】花式索引 + + +花式索引:传递一个索引数组来一次性获得多个数组元素,花式索引总是将数据复制到新数组中。 + +花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。 + +花式索引结果的形状与**索引数组**的形状一致,而不是与**被索引数组**的形状一致。 + +一维数组中的应用: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4, 5, 6]) +>>> print([a[0], a[2], a[-1]]) +[1, 3, 6] +``` + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4, 5, 6]) +>>> ind = [0, 2, -1] +>>> print(a[ind]) +[1 3 6] +``` + +二维数组中的应用: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) +>>> print(a) +[[ 1 2 3 4] + [ 5 6 7 8] + [ 9 10 11 12]] +>>> print([a[0, 1], a[1, 2], a[2, 3]]) +[2, 7, 12] +``` + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) +>>> row = np.array([0, 1, 2]) # 行 +>>> col = np.array([1, 2, 3]) # 列 +>>> print(a[row, col]) +[ 2 7 12] +``` + +## 【3x00】NumPy 切片 + +Ndarray 数组对象基于 `0 - n` 的下标进行索引,与 Python 中列表的切片操作一样,NumPy 的切片也可以通过冒号分隔切片参数 `[start:stop:step]` 来进行切片操作,另外,NumPy 也提供了一个内置函数 `slice(start, stop, step)` 来进行切片操作。 + +slice 方法应用: + +```python +>>> import numpy as np +>>> a = np.arange(10) +>>> print(a) +[0 1 2 3 4 5 6 7 8 9] +>>> b = slice(2, 8, 2) # 从索引 2 开始到索引 8 停止,步长为 2 +>>> print(a[b]) +[2 4 6] +``` + +通过冒号分隔切片参数 `[start:stop:step]` 来进行切片: + +```python +>>> import numpy as np +>>> a = np.arange(12) +>>> print(a) +[ 0 1 2 3 4 5 6 7 8 9 10 11] +>>> print(a[1:9:2]) # 从索引 1 开始到索引 9 停止,步长为 2 +[1 3 5 7] +>>> print(a[5:]) +[ 5 6 7 8 9 10 11] # 从索引 5 开始一直到最后一个元素 +``` + +二数组中的切片,格式类似于 `a[start:stop:step, start:stop:step]`,以逗号来分割行与列。 + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8 ,9], [10, 11, 12], [13, 14, 15], [16, 17, 18]]) +>>> print(a) +[[ 1 2 3] + [ 4 5 6] + [ 7 8 9] + [10 11 12] + [13 14 15] + [16 17 18]] +>>> print(a[0:4:2]) # 按照行从索引 0 开始到索引 4 停止,步长为 2 +[[1 2 3] + [7 8 9]] +>>> print(a[0:4:2,...]) # 与上述方法相同,... 与 : 作用相同 +[[1 2 3] + [7 8 9]] +>>> print(a[...,1:]) # 按照列从索引 1 开始一直到最后一个元素 +[[ 2 3] + [ 5 6] + [ 8 9] + [11 12] + [14 15] + [17 18]] +>>> print(a[1:5:2,1:]) # 分别按照行从索引 1 开始到索引 5 停止,步长为 2,按照列从索引 1 开始一直到最后一个元素 +[[ 5 6] + [11 12]] +``` + +三数组中的切片,格式类似于 `a[start:stop:step, start:stop:step, start:stop:step]`,以逗号来分割块、行与列。 + +```python +>>> import numpy as np +>>> a = np.array([[[1,2,3,4], [5,6,7,8]], [[9,10,11,12], [13,14,15,16]], [[17,18,19,20], [21,22,23,24]]]) +>>> print(a) +[[[ 1 2 3 4] + [ 5 6 7 8]] + + [[ 9 10 11 12] + [13 14 15 16]] + + [[17 18 19 20] + [21 22 23 24]]] +>>> print(a[1,:,0:2]) # 取索引为 1 的块数、所有行、索引为 0 到 2 的列 +[[ 9 10] + [13 14]] +>>> print(a[1,:,:]) # 取索引为 1 的块数、所有行与列 +[[ 9 10 11 12] + [13 14 15 16]] +>>> print(a[1,...,:]) # ... 与 : 作用相同 +[[ 9 10 11 12] + [13 14 15 16]] +``` + +## 【4x00】NumPy 数组运算以及广播原则 + +NumPy 数组与数之间、数组与数组之间都支持加减乘除的计算。 + +- 对于**数组与数**之间的计算,由于 NumPy 的广播机制,加减乘除都会对数组的每一个元素进行操作。 + +- 对于**数组与数组**之间的计算,相同维度的,相同位置元素之间会进行计算,不同维度的,将自动触发广播机制。 + +**广播(Broadcast)原则:**如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符,或其中的一方的长度为 1,则认为它们是广播兼容的。广播会在缺失和(或)长度为 1 的维度上进行。 + +通俗理解,以下情况的两个数组均可进行广播: + +1、两个数组各维度大小从后往前比对均一致: + +```python +>>> import numpy as np +>>> a = np.ones((3, 4, 5)) +>>> b = np.ones((4, 5)) +>>> print((a+b).shape) +(3, 4, 5) +>>> +>>> +>>> c = np.ones((3)) +>>> d = np.ones((2, 3)) +>>> print((c+d).shape) +(2, 3) +>>> +>>> +>>> e = np.ones((3, 4, 5)) +>>> f = np.ones((4, 2)) +>>> print((e+f).shape) +Traceback (most recent call last): + File "", line 1, in + print((e+f).shape) +ValueError: operands could not be broadcast together with shapes (3,4,5) (4,2) +# 因为 e 和 f 维度大小此前往后对比不一致,所以会抛出异常 +``` + +2、两个数组存在一些维度大小不相等时,在其中一个数组中,这个不相等的维度大小为 1: + +```python +>>> import numpy as np +>>> a = np.ones((3, 4, 5)) +>>> b = np.ones((4, 1)) +>>> print((a+b).shape) +(3, 4, 5) +# 此时虽然 a 与 b 的维度大小此前往后对比不一致,但是 b 数组的这个维度大小为 1,所以仍然可以相加 +``` + +那么当两个数组之间可以进行广播的时候,具体是怎样广播、怎样计算的呢?以下通过代码和图解来更进一步理解广播机制: + +数组与数之间的运算: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4, 5]) +>>> print(a) +[1 2 3 4 5] +>>> print(a+1) # 对数组每一个元素都 +1 +[2 3 4 5 6] +>>> print(a-1) # 对数组每一个元素都 -1 +[0 1 2 3 4] +>>> print(a*2) # 对数组每一个元素都 *1 +[ 2 4 6 8 10] +>>> print(a/2) # 对数组每一个元素都 /1 +[0.5 1. 1.5 2. 2.5] +``` + +相同维度的数组与数组之间的运算: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) +>>> b = np.array([[11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]) +>>> print(a) +[[ 1 2 3 4 5] + [ 6 7 8 9 10]] +>>> print(b) +[[11 12 13 14 15] + [16 17 18 19 20]] +>>> print(a+b) +[[12 14 16 18 20] + [22 24 26 28 30]] +>>> print(b-a) +[[10 10 10 10 10] + [10 10 10 10 10]] +>>> print(a*b) +[[ 11 24 39 56 75] + [ 96 119 144 171 200]] +>>> print(b/a) +[[11. 6. 4.33333333 3.5 3. ] + [ 2.66666667 2.42857143 2.25 2.11111111 2. ]] +``` + +不同维度的数组与数组之间的运算: + +实例一:一个**二维数组**与一个**一维数组**相加,此时就会触发广播机制,代码与图解如下: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) +>>> b = np.array([20, 20, 20]) +>>> print(a) +[[ 1 2 3] + [ 4 5 6] + [ 7 8 9] + [10 11 12]] +>>> print(b) +[20 20 20] +>>> print(a+b) +[[21 22 23] + [24 25 26] + [27 28 29] + [30 31 32]] +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A63/01.png) + +实例二:一个 **4 行 3 列**的二维数组与一个 **4 行 1 列**的二维数组相加,此时就会触发广播机制,代码与图解如下: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) +>>> b = np.array([[1], [2], [3], [4]]) +>>> print(a) +[[ 1 2 3] + [ 4 5 6] + [ 7 8 9] + [10 11 12]] +>>> print(b) +[[1] + [2] + [3] + [4]] +>>> print(a+b) +[[ 2 3 4] + [ 6 7 8] + [10 11 12] + [14 15 16]] +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A63/02.png) + +实例三:一个 **3 块 4 行 2 列,即 shape=(3, 4, 2)** 的三维数组与一个 **1 块 4 行 2 列,即 shape=(1, 4, 2)** 的三维数组相加,此时就会触发广播机制,代码与图解如下: + +```python +>>> import numpy as np +>>> a = np.array([[[1, 2], [3, 4], [5, 6], [7, 8]], [[9, 10], [11, 12], [13, 14], [15, 16]], [[17, 18], [19, 20], [21, 22], [23, 24]]]) +>>> b = np.array([[[1, 2], [3, 4], [5, 6], [7, 8]]]) +>>> print(a) +[[[ 1 2] + [ 3 4] + [ 5 6] + [ 7 8]] + + [[ 9 10] + [11 12] + [13 14] + [15 16]] + + [[17 18] + [19 20] + [21 22] + [23 24]]] +>>> print(b) +[[[1 2] + [3 4] + [5 6] + [7 8]]] +>>> print(a.shape) +(3, 4, 2) +>>> print(b.shape) +(1, 4, 2) +>>> print(a+b) +[[[ 2 4] + [ 6 8] + [10 12] + [14 16]] + + [[10 12] + [14 16] + [18 20] + [22 24]] + + [[18 20] + [22 24] + [26 28] + [30 32]]] +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A63/03.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/104988137 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【5x00】数组的拼接与元素的添加 + +### 【5x01】将数组转换成列表,拼接完成再转换成数组 + +数组的拼接,可以先将数组转成列表,利用列表的拼接函数,如:append()、extend() 等进行拼接处理,然后再将列表转成数组即可。 + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3]) +>>> b = np.array([4, 5, 6]) +>>> a_list = list(a) +>>> b_list = list(b) +>>> for i in b_list: + a_list.append(i) + + +>>> a_list +[1, 2, 3, 4, 5, 6] +>>> a = np.array(a_list) +>>> a +array([1, 2, 3, 4, 5, 6]) +``` + +### 【5x02】numpy.append() + +numpy.append() 方法可以将一个数组附加到另一个数组的尾部,与 Python 列表中的 append 方法类似,仅支持两个数组之间的拼接,不能一次性拼接多个数组。 + +基本语法:`numpy.append(a, values, axis=None)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| a | 被添加元素的目标数组 | +| values | 要添加元素的目标数组,即将该数组添加到 a 数组的尾部
**如果指定了 axis 的值,则要求该数组的维度必须与 a 相同** | +| axis | 指定轴,按照指定轴的方向进行拼接
如果未指定轴,则在使用前会将 a 和 values 都展平 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3]) +>>> b = np.array([4, 5, 6]) +>>> print(np.append(a, b)) # 两个一维数组进行拼接 +[1 2 3 4 5 6] +>>> +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) +>>> b = np.array([10, 11, 12]) +>>> print(np.append(a, b)) # 一维数组与二维数组进行拼接 +[ 1 2 3 4 5 6 7 8 9 10 11 12] +>>> +>>> a = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) +>>> b = np.array([[13, 14, 15], [16, 17, 18]]) +>>> print(np.append(a, b)) # 二维数组与三维数组进行拼接 +[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18] +>>> print(type(np.append(a, b))) # 拼接后的数组仍然是一个 ndarray 对象 + +``` + +指定 axis 的值举例(指定了 axis 的值,要求两个数组的维度必须相同): + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6]]) +>>> b = np.array([[7, 8, 9]]) +>>> print(np.append(a, b, axis=0)) # a、b 均为二维数组,指定 axis 值为 0 +[[1 2 3] + [4 5 6] + [7 8 9]] +>>> +>>> a = np.array([[1, 2, 3], [4, 5, 6]]) +>>> b = np.array([7, 8, 9]) +>>> print(np.append(a, b, axis=0)) # a 为二维数组,b 为一维数组,指定 axis 值为 0,此时会报错 +Traceback (most recent call last): + ... + ... +ValueError: all the input arrays must have same number of dimensions, ... +``` + +### 【5x03】numpy.concatenate() + +numpy.concatenate() 方法能够一次完成多个相同形状数组的拼接。该方法效率更高,适合大规模的数据拼接。 + +基本语法:`numpy.concatenate((a1, a2, ...), axis=0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| a1, a2, … | 要拼接的多个数组,**要求各数组形状相同** | +| axis | 指定轴,按照指定轴的方向进行拼接,默认为 0 轴 | + +**要求各数组形状相同**举例:如果 axis=0,则要求 1 轴(竖轴)相同,如果 axis=1,则要求 0 轴(横轴)相同。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) +>>> b = np.array([[10, 11, 12], [13, 14, 15]]) +>>> c = np.array([[16, 17, 18]]) # 三个二维数组的 1 轴(竖轴)相同 +>>> print(np.concatenate((a, b, c))) # 三个二维数组默认沿 0 轴(横轴)进行拼接 +[[ 1 2 3] + [ 4 5 6] + [ 7 8 9] + [10 11 12] + [13 14 15] + [16 17 18]] +``` + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) +>>> b = np.array([[9, 10, 11], [12, 13, 14]]) +>>> c = np.array([[15, 16], [17, 18]]) # 三个二维数组的 0 轴(横轴)相同 +>>> print(np.concatenate((a, b, c), axis=1)) # 三个二维数组沿 1 轴(竖轴)进行拼接 +[[ 1 2 3 4 9 10 11 15 16] + [ 5 6 7 8 12 13 14 17 18]] +``` + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) +>>> b = np.array([[9, 10, 11], [12, 13, 14]]) +>>> c = np.array([[15, 16], [17, 18]]) # 三个二维数组的 0 轴(横轴)相同 +>>> print(np.concatenate((a, b, c), axis=0)) # 三个二维数组沿 0 轴(横轴)进行拼接将会报错 +Traceback (most recent call last): + ... + ... +ValueError: all the input array dimensions for the concatenation axis must match exactly, ... +``` + +### 【5x04】numpy.stack() +numpy.stack() 方法用于沿新轴连接数组序列。 + +基本语法:`numpy.stack(arrays, axis=0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| arrays | 相同形状的数组序列 | +| axis | 返回数组中的轴,输入数组将沿着该轴来进行堆叠 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3]) +>>> b = np.array([4, 5, 6]) +>>> print(np.stack((a, b),axis=0)) +[[1 2 3] + [4 5 6]] +>>> print(np.stack((a, b),axis=1)) +[[1 4] + [2 5] + [3 6]] +``` + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4]]) +>>> b = np.array([[5,6],[7,8]]) +>>> print(np.stack((a,b),axis=0)) +[[[1 2] + [3 4]] + + [[5 6] + [7 8]]] +>>> print(np.stack((a,b),axis=1)) +[[[1 2] + [5 6]] + + [[3 4] + [7 8]]] +``` + +### 【5x05】numpy.vstack() + +numpy.vstack() 方法通过垂直堆叠来生成数组。 + +基本语法:`numpy.vstack(tup)` + +参数解释:tup:数组序列,如果是一维数组进行堆叠,则数组长度必须相同,其它数组除了**第一个轴(axis=0)**的长度可以不同外,其它轴的长度必须相同。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3]) +>>> b = np.array([4, 5, 6]) +>>> print(np.vstack((a,b))) +[[1 2 3] + [4 5 6]] +>>> +>>> b = np.array([4, 5]) +>>> print(np.vstack((a,b))) # 一维数组长度不一样时将抛出异常 +Traceback (most recent call last): + ... + ... +ValueError: all the input array dimensions for the concatenation axis must match exactly, ... +``` + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4]]) +>>> b = np.array([[5,6],[7,8]]) +>>> a.shape +(2, 2) +>>> b.shape +(2, 2) +>>> print(np.vstack((a,b))) +[[1 2] + [3 4] + [5 6] + [7 8]] +``` + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4]]) +>>> b = np.array([[5,6],[7,8],[9,10]]) +>>> a.shape +(2, 2) +>>> b.shape +(3, 2) +>>> print(np.vstack((a,b))) # 第一个轴(axis=0)可以不同,其它轴必须相同 +[[ 1 2] + [ 3 4] + [ 5 6] + [ 7 8] + [ 9 10]] +``` + +### 【5x06】numpy.hstack() + +numpy.hstack() 方法通过水平堆叠来生成数组。 + +基本语法:`numpy.hstack(tup)` + +参数解释:tup:数组序列,除了一维数组的堆叠可以是不同长度外,其它数组堆叠时,除了**第二个轴(axis=1)**的长度可以不同外,其它轴的长度必须相同。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3]) +>>> b = np.array([4, 5]) +>>> print(np.hstack((a,b))) +[1 2 3 4 5] +``` + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4]]) +>>> b = np.array([[5,6],[7,8]]) +>>> a.shape +(2, 2) +>>> b.shape +(2, 2) +>>> print(np.hstack((a,b))) +[[1 2 5 6] + [3 4 7 8]] +``` + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4]]) +>>> b = np.array([[5,6,7],[8,9,10]]) +>>> a.shape +(2, 2) +>>> b.shape +(2, 3) +>>> print(np.hstack((a,b))) # 第二个轴(axis=1)可以不同,其它轴必须相同 +[[ 1 2 5 6 7] + [ 3 4 8 9 10]] +``` + +### 【5x07】numpy.dstack() + +numpy.dstack() 方法会沿着第三个维度拼接数组。 + +基本语法:`numpy.dstack(tup)` + +参数解释:tup:数组序列,除了**第三个轴(axis=2)**的长度可以不同外,其它轴的长度必须相同。一维或二维数组必须具有相同的形状。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) +>>> b = np.array([[[9], [10]], [[11], [12]]]) +>>> a.shape +(2, 2, 2) +>>> b.shape +(2, 2, 1) +>>> print(np.dstack((a,b))) # a 与 b 的第三个轴(axis=2)一个是 2,另一个是 1,可以不同,但其他轴必须相同 +[[[ 1 2 9] + [ 3 4 10]] + + [[ 5 6 11] + [ 7 8 12]]] +``` + +```python +>>> import numpy as np +>>> a = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) +>>> b = np.array([[[9, 10], [11, 12]]]) +>>> a.shape +(2, 2, 2) +>>> b.shape +(1, 2, 2) +>>> print(np.dstack((a,b))) # a 与 b 的第一个轴(axis=0)不同,将会抛出异常 +[[[ 1 2 9] + [ 3 4 10]] + + [[ 5 6 11] + [ 7 8 12]]] +>>> print(np.dstack((a,b))) +Traceback (most recent call last): + ... + ... +ValueError: all the input array dimensions for the concatenation axis must match exactly, ... +``` + +### 【5x08】以上几种方法的区别 + +- `concatenate()` 方法在 `axis=0` 的时候相当于 `vstack()` 方法; +- `concatenate()` 方法在 `axis=1` 的时候相当于 `hstack()` 方法; +- `concatenate()` 方法在 `axis=2` 的时候相当于 `dstack()` 方法; +- `concatenate()` 方法**不会**生成一个新的维度,且数组的维度不一定相同,而 stack() 方法**会**生成一个新的维度,并且要求所有数组形状都要一样。 + +`concatenate()` 方法与 `stack()` 方法比较: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3]) +>>> b = np.array([4, 5, 6]) +>>> c = np.stack((a, b), axis=0) +>>> d = np.concatenate((a, b), axis=0) +>>> a.shape +(3,) +>>> b.shape +(3,) +>>> c.shape +(2, 3) +>>> d.shape +(6,) +>>> print(c) +[[1 2 3] + [4 5 6]] +>>> print(d) +[1 2 3 4 5 6] +``` + +### 【5x09】numpy.insert() + +numpy.insert() 方法沿指定轴在指定索引之前插入值。 + +基本语法:`numpy.insert(arr, obj, values, axis=None)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| arr | 原数组 | +| obj | 索引值,将在其之前插入值 | +| values | 要插入的值 | +| axis | 轴,将沿着该轴进行插入操作,如果未指定,则插入前,原数组会被展开,变为一维数组 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4],[5,6]]) +>>> print(np.insert(a, 3, [0, 0])) # 未指定 axis 参数,在插入之前原数组会被展开 +[1 2 3 0 0 4 5 6] +>>> print(np.insert(a, 1, [0], axis = 0)) # 沿 0 轴广播插入 +[[1 2] + [0 0] + [3 4] + [5 6]] +>>> print(np.insert(a, 1, 11, axis = 1)) # 沿 1 轴广播插入 +[[ 1 11 2] + [ 3 11 4] + [ 5 11 6]] +``` + +### 【5x10】numpy.r_ + +numpy.r_:`r` 为 `row(行)` 的缩写,即按照行连接两个矩阵,要求列数相等。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3],[7, 8, 9]]) +>>> b = np.array([[4, 5, 6],[1, 2, 3]]) +>>> +>>> np.r_[a, b] +array([[1, 2, 3], + [7, 8, 9], + [4, 5, 6], + [1, 2, 3]]) +``` + +### 【5x11】numpy.c_ + +numpy.c_:`c` 为 `column(列)` 的缩写,即按照列连接两个矩阵,要求行数相等。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3],[7, 8, 9]]) +>>> b = np.array([[4, 5, 6],[1, 2, 3]]) +>>> +>>> np.c_[a, b] +array([[1, 2, 3, 4, 5, 6], + [7, 8, 9, 1, 2, 3]]) +``` + +## 【6x00】数组的分割与元素的删除 + +### 【6x01】numpy.split() + +numpy.split() 方法可以沿特定的轴将数组**均等**的分割为子数组。如果不能等分,将抛出异常。 + +基本语法:`numpy.split(ary, indices_or_sections, axis=0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| ary | 被分割的数组 | +| indices_or_sections | 如果是一个整数 N,则该数组将沿 axis **均分**为 N 个数组
如果是一维整数数组,则数组元素代表每个分割点位置(左闭右开),N 个分裂点会得到 N + 1 个子数组 | +| axis | 沿着哪个维度进行分割,默认为 0,横向分割;为 1 时,纵向分割 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.arange(10) +>>> print(a) +[0 1 2 3 4 5 6 7 8 9] +>>> print(np.split(a, 5)) # 将数组分为五个大小相等的子数组 +[array([0, 1]), + array([2, 3]), + array([4, 5]), + array([6, 7]), + array([8, 9])] +>>> +>>> print(np.split(a, 4)) # 无法等分的情况下将抛出异常 +Traceback (most recent call last): + ... + ... +ValueError: array split does not result in an equal division +>>> +>>> print(np.split(a, [4, 8])) # 分割点为索引 4 和 8 的位置,相当于 a[:4]、a[4:8]、a[8:] +[array([0, 1, 2, 3]), + array([4, 5, 6, 7]), + array([8, 9])] +>>> +>>> a = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) +>>> print(np.split(a, 5, axis=1)) # 指定 axis=1,按照纵向分割数组 +[array([[1], + [6]]), + array([[2], + [7]]), + array([[3], + [8]]), + array([[4], + [9]]), + array([[ 5], + [10]])] +``` + +### 【6x02】numpy.array_split() + +numpy.array_split() 的用法和作用都与 split() 方法一致,都可以用一个整数或者整数列表来分割数组。 + +两者的区别:如果输入的是一个 int 类型的数字,那么在 split() 方法中,数组必须是均等的分割,否则就会报错,而在 array_split() 方法中是可以进行不均等的分割的。 + +基本语法:`numpy.array_split(ary, indices_or_sections, axis=0)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| ary | 被分割的数组 | +| indices_or_sections | 如果是一个整数 N,则该数组将沿 axis 分割为 N 个数组,**可以不是均分的**
如果是一维整数数组,则数组元素代表每个分割点位置(左闭右开),N 个分裂点会得到 N + 1 个子数组 | +| axis | 沿着哪个维度进行分割,默认为 0,横向分割;为 1 时,纵向分割 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4, 5, 6, 7]) +>>> print(np.array_split(a, 3)) +[array([1, 2, 3]), array([4, 5]), array([6, 7])] # 可以是不均分的 +>>> +>>> print(np.array_split(a, 4)) +[array([1, 2]), array([3, 4]), array([5, 6]), array([7])] +``` + +### 【6x03】numpy.vsplit() + +numpy.vsplit() 方法相当于 split() 方法在 axis=0 时的效果,即横向分割数组。 + +基本语法:`numpy.vsplit(ary, indices_or_sections)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| ary | 被分割的数组 | +| indices_or_sections | 如果是一个整数 N,则该数组将沿 axis 分为 N 个相等的数组
如果是一维整数数组,则数组元素代表每个分割点位置(左闭右开),N 个分裂点会得到 N + 1 个子数组 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) +>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) +>>> print(np.vsplit(a, 2)) +[array([[1, 2, 3], + [4, 5, 6]]), + array([[ 7, 8, 9], + [10, 11, 12]])] +>>> +>>> print(np.vsplit(a, [1, 3])) +[array([[1, 2, 3]]), + array([[4, 5, 6], + [7, 8, 9]]), + array([[10, 11, 12]])] +``` + +### 【6x04】numpy.hsplit() + +numpy.hsplit() 方法相当于 split() 方法在 axis=1 时的效果,即纵向分割数组。 + +基本语法:`numpy.hsplit(ary, indices_or_sections)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| ary | 被分割的数组 | +| indices_or_sections | 如果是一个整数 N,则该数组将沿 axis 分为 N 个相等的数组
如果是一维整数数组,则数组元素代表每个分割点位置(左闭右开),N 个分裂点会得到 N + 1 个子数组 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) +>>> print(np.hsplit(a, 5)) +[array([[1], + [6]]), + array([[2], + [7]]), + array([[3], + [8]]), + array([[4], + [9]]), + array([[ 5], + [10]])] +>>> +>>> print(np.hsplit(a, [1, 3])) +[array([[1], + [6]]), + array([[2, 3], + [7, 8]]), + array([[ 4, 5], + [ 9, 10]])] +``` + +### 【6x05】numpy.dsplit() + +numpy.dsplit() 方法相当于 split() 方法在 axis=2 时的效果,即沿第三轴将数组拆分为多个子数组。 + +基本语法:`numpy.dsplit(ary, indices_or_sections)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| ary | 被分割的数组 | +| indices_or_sections | 如果是一个整数 N,则该数组将沿 axis 分为 N 个相等的数组
如果是一维整数数组,则数组元素代表每个分割点位置(左闭右开),N 个分裂点会得到 N + 1 个子数组 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.arange(16).reshape(2, 2, 4) +>>> print(a) +[[[ 0 1 2 3] + [ 4 5 6 7]] + + [[ 8 9 10 11] + [12 13 14 15]]] +>>> print(np.dsplit(a, 2)) +[array([[[ 0, 1], + [ 4, 5]], + [[ 8, 9], + [12, 13]]]), + array([[[ 2, 3], + [ 6, 7]], + [[10, 11], + [14, 15]]])] +>>> +>>> print(np.dsplit(a, [3, 6])) +[array([[[ 0, 1, 2], + [ 4, 5, 6]], + [[ 8, 9, 10], + [12, 13, 14]]]), + array([[[ 3], + [ 7]], + [[11], + [15]]]), + array([], shape=(2, 2, 0), dtype=int32)] +``` + +### 【6x06】numpy.delete() + +numpy.delete() 方法返回一个从原数组中删除了指定子数组的新数组。 + +基本语法:`numpy.delete(arr,obj,axis=None)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| arr | 原数组 | +| obj | 可以是切片、整数或整数数组形式,表示沿指定轴删除的子数组的索引
当 obj 为切片形式时,要用 `np.s_[:]` 的格式 | +| axis | 轴,将沿着该轴进行插入操作,如果未指定,则插入前,原数组会被展开,变为一维数组 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) +>>> print(np.delete(a, 8)) # 未指定 axis 参数,在插入之前原数组会被展开,然后再删除索引为 8 的元素 +[ 1 2 3 4 5 6 7 8 10 11 12] +>>> +>>> print(np.delete(a, 1, axis=0)) # 指定 axis=0,删除索引值为 1 即第二行 +[[ 1 2 3 4] + [ 9 10 11 12]] +>>> +>>> print(np.delete(a, 1, axis=1)) # 指定 axis=1,删除索引值为 1 即第二列 +[[ 1 3 4] + [ 5 7 8] + [ 9 11 12]] +>>> +>>> print(np.delete(a, np.s_[:2], axis=1)) # 切片形式,删除前两列 +[[ 3 4] + [ 7 8] + [11 12]] +>>> +>>> print(np.delete(a, [0, 2], axis=1)) # 数组形式,删除索引值为 0 和 2 的列 +[[ 2 4] + [ 6 8] + [10 12]] +``` + +### 【6x07】numpy.unique() + +numpy.unique() 方法用于去除数组中的重复元素。 + +基本语法:`numpy.unique(arr, return_index=False, return_inverse=False, return_counts=False, axis=None)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| arr | 原数组,如果不是一维数组则会被展开为一维数组 | +| return_index | 如果为 true,则返回新列表元素在旧列表中的位置(下标),并以列表形式储 | +| return_inverse | 如果为 true,则返回旧列表元素在新列表中的位置(下标),并以列表形式储 | +| return_counts | 如果为 true,则返回去重数组中的元素在原数组中的出现次数 | +| axis | 指定轴 | + +应用举例: + +未指定 axis 值,原数组将会被展开: + +```python +>>> import numpy as np +>>> a = np.array([1, 1, 2, 2, 3, 4, 5, 5]) +>>> b = np.array([[1, 1], [2, 3], [3, 4]]) +>>> print(np.unique(a)) +[1 2 3 4 5] +>>> print(np.unique(b)) +[1 2 3 4] +``` + +指定 axis 值: + +```python +>>> import numpy as np +>>> a = np.array([[1, 0, 1], [1, 0, 1], [2, 3, 2], [5, 6, 5]]) +>>> print(a) +[[1 0 1] + [1 0 1] + [2 3 2] + [5 6 5]] +>>> print(np.unique(a, axis=0)) # 删除相同的行 +[[1 0 1] + [2 3 2] + [5 6 5]] +>>> print(np.unique(a, axis=1)) # 删除相同的列 +[[0 1] + [0 1] + [3 2] + [6 5]] +``` + +return_counts 为 True 时,返回去重数组中的元素在原数组中的出现次数: + +```python +>>> import numpy as np +>>> a = np.array([1, 1, 1, 2, 2, 3, 4, 5, 5]) +>>> print(np.unique(a, return_counts=True)) +(array([1, 2, 3, 4, 5]), array([3, 2, 1, 1, 2], dtype=int64)) +# 前一个 array 表示去重后的数组,后一个 array 表示每一个元素在原数组中出现的次数 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/104988137 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A64-NumPy-03.md b/source/_posts/A64-NumPy-03.md new file mode 100644 index 0000000000000000000000000000000000000000..45c542928ffe979dd32fa5f4b1c00dd106deb13f --- /dev/null +++ b/source/_posts/A64-NumPy-03.md @@ -0,0 +1,639 @@ +--- +title: Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算 +tags: + - NumPy + - 迭代 + - 位运算 +categories: + - Python 数据分析 + - NumPy +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/numpy.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算。 +--- + +NumPy 系列文章: + +- [Python 数据分析三剑客之 NumPy(一):理解 NumPy / 数组基础](https://www.itrhx.com/2020/03/20/A62-NumPy-01/) +- [Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割](https://www.itrhx.com/2020/03/22/A63-NumPy-02/) +- [Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算](https://www.itrhx.com/2020/03/24/A64-NumPy-03/) +- [Python 数据分析三剑客之 NumPy(四):字符串函数总结与对比](https://www.itrhx.com/2020/03/26/A65-NumPy-04/) +- [Python 数据分析三剑客之 NumPy(五):数学 / 算术 / 统计 / 排序 / 条件 / 判断函数合集](https://www.itrhx.com/2020/03/28/A66-NumPy-05/) +- [Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作](https://www.itrhx.com/2020/03/30/A67-NumPy-06/) + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105185337 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】numpy.nditer 迭代器对象 + +numpy.nditer 是 NumPy 的迭代器对象,迭代器对象提供了许多灵活的方法来访问一个或多个数组中的所有元素,简单来说,迭代器最基本的任务就是完成对数组元素的访问。 + +### 【1x01】单数组的迭代 + +单数组迭代示例: + +```python +>>> import numpy as np +>>> a = np.arange(10).reshape(2, 5) +>>> print(a) +[[0 1 2 3 4] + [5 6 7 8 9]] +>>> for i in np.nditer(a): + print(i, end=' ') + + +0 1 2 3 4 5 6 7 8 9 +``` + +注意:默认对数组元素的访问顺序,既不是以标准 C(行优先) 也不是 Fortran 顺序(列优先),选择的顺序是和数组内存布局一致的,这样做是为了提高访问效率,反映了默认情况下只需要访问每个元素而不关心特定排序的想法。以下用一个数组的转置来理解这种访问机制。 + +```python +>>> import numpy as np +>>> a = np.arange(10).reshape(2, 5) +>>> print(a) +[[0 1 2 3 4] + [5 6 7 8 9]] +>>> +>>> b = a.T +>>> print(b) +[[0 5] + [1 6] + [2 7] + [3 8] + [4 9]] +>>> +>>> c = a.T.copy(order='C') +>>> print(c) +[[0 5] + [1 6] + [2 7] + [3 8] + [4 9]] +>>> +>>> for i in np.nditer(a): + print(i, end=' ') + + +0 1 2 3 4 5 6 7 8 9 +>>> +>>> for i in np.nditer(b): + print(i, end=' ') + + +0 1 2 3 4 5 6 7 8 9 +>>> +>>> for i in np.nditer(c): + print(i, end=' ') + + +0 5 1 6 2 7 3 8 4 9 +``` + +例子中 a 是一个 2 行 5 列的数组,b 数组对 a 进行了转置,而 c 数组则是对 a 进行转置后按照 C order(行优先)的形式复制到新内存中储存,b 数组虽然进行了转置操作,但是其元素在内存当中的储存顺序仍然和 a 一样,所以对其迭代的效果也和 a 一样,c 数组元素在新内存当中的储存顺序不同于 a 和 b,因此对其迭代的效果也不一样。 + +### 【1x02】控制迭代顺序 + +如果想要按照特定顺序来对数组进行迭代,nditer 同样也提供了 order 参数,可选值为:`C` `F` `A` `K` + +- `numpy.nditer(a, order='C')`:标准 C 顺序,即行优先; +- `numpy.nditer(a, order='F')`: Fortran 顺序,即列优先; +- `numpy.nditer(a, order='A')`:如果所有数组都是 Fortran 顺序的,则 A 表示以 F 顺序,否则以 C 顺序; +- `numpy.nditer(a, order='K')`:默认值,保持原数组在内存当中的顺序。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.arange(12).reshape(3, 4) +>>> print(a) +[[ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11]] +>>> +>>> for i in np.nditer(a, order='C'): + print(i, end= ' ') + + +0 1 2 3 4 5 6 7 8 9 10 11 +>>> +>>> for i in np.nditer(a, order='F'): + print(i, end= ' ') + + +0 4 8 1 5 9 2 6 10 3 7 11 +>>> +>>> for i in np.nditer(a, order='K'): + print(i, end= ' ') + + +0 1 2 3 4 5 6 7 8 9 10 11 +``` + +### 【1x03】修改数组元素 + +nditer 对象提供了可选参数 `op_flags`,默认情况下,该参数值为 `readonly`(只读),如果在遍历数组的同时,要实现对数组中元素值的修改,则可指定 `op_flags` 值为 `readwrite`(读写) 或者 `writeonly`(只读)。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.arange(10).reshape(2, 5) +>>> print(a) +[[0 1 2 3 4] + [5 6 7 8 9]] +>>> +>>> for i in np.nditer(a, op_flags=['readwrite']): + i[...] = i+1 + + +>>> print(a) +[[ 1 2 3 4 5] + [ 6 7 8 9 10]] +``` + +```python +>>> import numpy as np +>>> li = [] +>>> a = np.arange(12).reshape(3, 4) +>>> print(a) +[[ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11]] +>>> +>>> for i in np.nditer(a, op_flags=['readwrite']): + li.append(i*2) + + +>>> print(li) +[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22] +``` + +### 【1x04】使用外部循环 + +nditer 对象支持 `flags` 参数,该参数最常用的值是 `external_loop`,表示使给定的值为具有多个值的一维数组。 + +通俗来讲,当 Ndarray 的顺序和遍历的顺序一致时,就会将所有元素组成一个一维数组返回;当 Ndarray 的顺序和遍历的顺序不一致时,则返回每次遍历的一维数组 + +官方介绍:[https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#using-an-external-loop](https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#using-an-external-loop) + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[0,1,2,3], [4,5,6,7], [8,9,10,11]], order='C') +>>> for i in np.nditer(a, flags=['external_loop'], order='C' ): + print(i, end=' ') + + +[ 0 1 2 3 4 5 6 7 8 9 10 11] +>>> for i in np.nditer(a, flags=['external_loop'], order='F' ): + print(i, end=' ') + + +[0 4 8] [1 5 9] [ 2 6 10] [ 3 7 11] +``` + +### 【1x05】跟踪元素索引 + +在迭代期间,我们有可能希望在计算中使用当前元素的索引值,同样可以通过指定 `flags` 参数的取值来实现: + +| 参数 | 描述 | +| ------ | ------| +| `c_index` | 跟踪 C 顺序索引 | +| `f_index` | 跟踪 Fortran 顺序索引 | +| `multi_index` | 跟踪多个索引或每个迭代维度一个索引的元组(多重索引) | + +在以下实例当中: + +当参数为 `c_index` 和 `f_index` 时,`it.index` 用于输出元素的索引值 + +当参数为 `multi_index` 时,`it.multi_index` 用于输出元素的索引值 + +`it.iternext()` 表示进入下一次迭代,直到迭代完成为止 + +`multi_index` 可理解为对迭代对象进行多重索引 + +```python +>>> import numpy as np +>>> a = np.arange(6).reshape(2, 3) +>>> it = np.nditer(a, flags=['c_index']) +>>> while not it.finished: + print('%d <%s>' %(it[0], it.index)) + it.iternext() + + +0 <0> +True +1 <1> +True +2 <2> +True +3 <3> +True +4 <4> +True +5 <5> +False +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A64/01.png) + +```python +>>> import numpy as np +>>> a = np.arange(6).reshape(2, 3) +>>> it = np.nditer(a, flags=['f_index']) +>>> while not it.finished: + print('%d <%s>' %(it[0], it.index)) + it.iternext() + + +0 <0> +True +1 <2> +True +2 <4> +True +3 <1> +True +4 <3> +True +5 <5> +False +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A64/02.png) + +```python +>>> import numpy as np +>>> a = np.arange(6).reshape(2, 3) +>>> it = np.nditer(a, flags=['multi_index']) +>>> while not it.finished: + print('%d <%s>' %(it[0], it.multi_index)) + it.iternext() + + +0 <(0, 0)> +True +1 <(0, 1)> +True +2 <(0, 2)> +True +3 <(1, 0)> +True +4 <(1, 1)> +True +5 <(1, 2)> +False +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A64/03.png) + +### 【1x06】广播数组迭代 + +如果两个数组满足[广播原则](https://itrhx.blog.csdn.net/article/details/104988137#font_colorff00004x00NumPy_font_429),nditer 对象能够同时迭代它们,即广播数组迭代(多数组的迭代)。 + +```python +>>> import numpy as np +>>> a = np.arange(3) +>>> b = np.arange(6).reshape(2,3) +>>> print(a) +[0 1 2] +>>> print(b) +[[0 1 2] + [3 4 5]] +>>> for m, n in np.nditer([a,b]): + print(m,n) + + +0 0 +1 1 +2 2 +0 3 +1 4 +2 5 +``` + +如果两个数组不满足广播原则,将会抛出异常: + +```python +>>> import numpy as np +>>> a = np.arange(4) +>>> b = np.arange(6).reshape(2,3) +>>> print(a) +[0 1 2 3] +>>> print(b) +[[0 1 2] + [3 4 5]] +>>> for m, n in np.nditer([a,b]): + print(m,n) + + +Traceback (most recent call last): + File "", line 1, in + for m, n in np.nditer([a,b]): +ValueError: operands could not be broadcast together with shapes (4,) (2,3) +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105185337 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【2x00】NumPy 位运算 + +由于位运算是直接对整数在内存中的二进制位进行操作,所以有必要先了解一下如何来表示数字的二进制。 + +在 Python 中,提供了一个内置函数 `bin()`,将整数转换为以 `0b` 为前缀的二进制字符串,如果要去掉 `0b` 前缀,则可以使用 `format` 方法,因为返回的是字符串,所以也可以使用切片等其他方法去掉前缀。 + +```python +>>> bin(3) +'0b11' +>>> format(3, 'b') +'11' +>>> f'{3:b}' +'11' +``` + +除了内置函数以外,NumPy 还提供了一个 `numpy.binary_repr` 函数,该函数的作用也是以字符串形式返回输入数字的二进制表示形式。 + +基本语法:`numpy.binary_repr(num, width=None)` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| num | 要表示的数,只能是整数形式 | +| width | 可选项,对于负数,如果未指定 width,则会在前面添加减号,如果指定了 width,则返回该宽度的负数的二进制补码 | + +```python +>>> import numpy as np +>>> np.binary_repr(3) +'11' +>>> np.binary_repr(-3) +'-11' +>>> np.binary_repr(-3, width=4) +'1101' +>>> np.binary_repr(3, width=4) +'0011' +``` + +--- + +以下是 NumPy 数组当中用到的位运算函数,各函数与其对应的用操作符计算的作用相同。 + +| 函数 | 描述 | 操作符 | +| ------ | ------ | ------- | +| `bitwise_and` | 对数组元素进行按位**与(AND)**操作 | & | +| `bitwise_or` | 对数组元素进行按位**或(OR)**操作 | \| | +| `bitwise_xor` | 对数组元素执行按位**异或(XOR)**操作 | ^ | +| `invert` | 对数组元素执行按位**取反(NOT)**操作 | ~ | +| `left_shift` | 将数组元素的二进制形式向**左移**动指定位,右侧附加相等数量的 0 | << | +| `right_shift` | 将数组元素的二进制形式向**右移**动指定位,左侧附加相等数量的 0 | >> | + + +### 【2x01】numpy.bitwise_and() + +numpy.bitwise_and() 函数对数组元素进行按位与(AND)操作。 + +```python +>>> import numpy as np +>>> np.binary_repr(10), np.binary_repr(15) +('1010', '1111') +>>> np.bitwise_and(10, 15) +10 +>>> np.binary_repr(10) +'1010' +``` + +numpy.bitwise_and() 函数还支持多个元素同时进行按位与操作: + +```python +>>> import numpy as np +>>> np.bitwise_and([14,3], 13) +array([12, 1], dtype=int32) +``` + +```python +>>> import numpy as np +>>> np.bitwise_and([11,7], [4,25]) +array([0, 1], dtype=int32) +>>> +>>> np.array([11,7]) & np.array([4,25]) # 函数与 & 操作符作用一样 +array([0, 1], dtype=int32) +``` + +还可以传入布尔值: + +```python +>>> import numpy as np +>>> np.bitwise_and([True,False,True],[True,True,True]) +array([ True, False, True]) +``` + +### 【2x02】numpy.bitwise_or() + +numpy.bitwise_or() 函数对数组元素进行按位或(OR)操作。 + +```python +>>> import numpy as np +>>> np.binary_repr(10), np.binary_repr(14) +('1010', '1110') +>>> np.bitwise_or(10, 14) +14 +>>> np.binary_repr(14) +'1110' +``` + +和按位与操作一样,numpy.bitwise_or() 函数也支持传入布尔值和多个元素同时进行操作: + +```python +>>> import numpy as np +>>> np.bitwise_or([33,4], 1) +array([33, 5], dtype=int32) +>>> +>>> np.bitwise_or([33,4], [1,2]) +array([33, 6], dtype=int32) +>>> +>>> np.bitwise_or(np.array([2,5,255]), np.array([4,4,4])) +array([ 6, 5, 255], dtype=int32) +>>> +>>> np.array([2,5,255]) | np.array([4,4,4]) # 函数与 | 运算符作用相同 +array([ 6, 5, 255], dtype=int32) +>>> +>>> np.bitwise_or([True, True], [False,True]) +array([ True, True]) +``` + +### 【2x03】numpy.bitwise_xor() + +numpy.bitwise_xor() 函数对数组元素执行按位异或(XOR)操作。 + +```python +>>> import numpy as np +>>> bin(13), bin(17) +('0b1101', '0b10001') +>>> np.bitwise_xor(13,17) +28 +>>> bin(28) +'0b11100' +``` + +```python +>>> import numpy as np +>>> np.bitwise_xor([31,3], 5) +array([26, 6], dtype=int32) +>>> +>>> np.bitwise_xor([31,3], [5,6]) +array([26, 5], dtype=int32) +>>> +>>> np.array([31,3]) ^ np.array([5,6]) # 函数与 ^ 运算符作用相同 +array([26, 5], dtype=int32) +>>> +>>> np.bitwise_xor([True, True], [False, True]) +array([ True, False]) +``` + +### 【2x04】numpy.invert() + +numpy.invert() 函数将对数组元素执行按位取反(NOT)操作,注意**按位取反****取反**操作不同。 + +**按位取反通用公式:~x = -(x+1)** + +我们将原来的数称为 A,按位取反后的数称为 B,按位取反的步骤如下: +先求 A 的补码,对 A 的补码每一位取反(包括符号位),得到的数为 B 的补码,将 B 的补码转换为 B 的原码得到最终结果。 + +分情况具体讨论: + +
正数按位取反步骤
+ +1、将其转换成二进制形式; +2、求其补码(正数的原码、反码、补码都相同); +3、将补码每一位进行取反操作(包括符号位); +【经过步骤 3 后的结果为一个二进制形式的负数补码,接下来将这个负数补码转换成原码(负数原码到补码的逆运算)】 +4、对步骤 3 得到的负数 -1 得到反码; +5、对步骤 4 得到的反码再进行取反得到原码; +6、将步骤 5 得到的原码转回十进制即是最终结果。 + +
负数按位取反步骤
+ +1、将其转换成二进制形式; +2、求其补码(先求其反码、符号位不变,末尾 +1 得到其补码); +3、将补码每一位进行取反操作(包括符号位); +【经过步骤 3 后的结果为一个二进制形式的正数,接下来将这个正数转换成原码即可】 +4、由于正数的原码、反码、补码都相同,所以直接将其转换成十进制即为最终结果。 + +**注意:第 3 步的取反操作,包括符号位都要取反,与求反码不同,求反码时符号位不变。** + +具体计算举例(二进制前 4 位为符号位): + +
9 的按位取反
+ +① 原码:0000 1001 +② 反码:0000 1001 +③ 补码:0000 1001 +④ 取反:1111 0110 (包括符号位一起取反,得到新的补码) +⑤ 反码:1111 0101 (将新的补码 -1 得到其反码) +⑥ 原码:1111 1010 (将反码取反得到原码) +⑦ 转为十进制:-10 + +
-9 的按位取反
+ +① 原码:1111 1001 +② 反码:1111 0110 +③ 补码:1111 0111 +④ 取反:0000 1000 (包括符号位一起取反,得到新的补码) +⑤ 原码:0000 1000 (由于新的补码为正数,所以原码补码相同) +⑥ 转为十进制:8 + +--- + +其他关于按位取反操作的知识: + +- [按位取反运计算方法](https://blog.csdn.net/xiexievv/article/details/8124108) + +- [[干货]按位取反怎么算?~图文详解](https://baijiahao.baidu.com/s?id=1631845959953469880) + +--- + +Python 代码应用示例: + +```python +>>> import numpy as np +>>> np.binary_repr(9, width=8) +'00001001' +>>> np.invert(9) +-10 +>>> np.invert(-9) +8 +``` + + +### 【2x05】numpy.left_shift() + +numpy.left_shift() 函数将数组元素的二进制形式向左移动指定位,右侧附加相等数量的 0。 + +应用举例: + +```python +>>> import numpy as np +>>> np.binary_repr(10, width=8) +'00001010' +>>> np.left_shift(10, 2) +40 +>>> 10 << 2 # numpy.left_shift 函数相当于 Python 当中的 << 运算符 +40 +>>> np.binary_repr(40, width=8) +'00101000' +``` + +### 【2x06】numpy.right_shift() + +numpy.right_shift() 函数将数组元素的二进制形式向右移动指定位,左侧附加相等数量的 0 + +```python +>>> import numpy as np +>>> np.binary_repr(10, width=8) +'00001010' +>>> np.right_shift(10, 2) +2 +>>> 10 >> 2 # numpy.right_shift 函数相当于 Python 当中的 >> 运算符 +2 +>>> np.binary_repr(2, width=8) +'00000010' +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105185337 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A65-NumPy-04.md b/source/_posts/A65-NumPy-04.md new file mode 100644 index 0000000000000000000000000000000000000000..eb887799e0ea6720d2569034336fb27822f5f292 --- /dev/null +++ b/source/_posts/A65-NumPy-04.md @@ -0,0 +1,621 @@ +--- +title: Python 数据分析三剑客之 NumPy(四):字符串函数总结与对比 +tags: + - NumPy + - 字符串函数 +categories: + - Python 数据分析 + - NumPy +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/numpy.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 NumPy(四):字符串相关函数的总结与对比。 +--- + +NumPy 系列文章: + +- [Python 数据分析三剑客之 NumPy(一):理解 NumPy / 数组基础](https://www.itrhx.com/2020/03/20/A62-NumPy-01/) +- [Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割](https://www.itrhx.com/2020/03/22/A63-NumPy-02/) +- [Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算](https://www.itrhx.com/2020/03/24/A64-NumPy-03/) +- [Python 数据分析三剑客之 NumPy(四):字符串函数总结与对比](https://www.itrhx.com/2020/03/26/A65-NumPy-04/) +- [Python 数据分析三剑客之 NumPy(五):数学 / 算术 / 统计 / 排序 / 条件 / 判断函数合集](https://www.itrhx.com/2020/03/28/A66-NumPy-05/) +- [Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作](https://www.itrhx.com/2020/03/30/A67-NumPy-06/) + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105350414 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01】NumPy 字符串函数速查表 + +和 Python 一样,NumPy 也可以进行字符串相关操作。字符串函数在字符数组类(`numpy.char`)中定义。 + +
NumPy 字符串函数速查表
+ +| 函数 | 描述 | +| ------ | ------ | +| add() | 对两个数组的字符串元素进行连接 | +| join() | 通过指定分隔符来连接数组中的元素 | +| mod() | 格式化字符串,相当于 Python 字符串中的 % 和 format | +| multiply() | 按照给定值返回元素多重连接后的字符串 | +| capitalize() | 将字符串(字符串可同时包含字母和数字,只要是连续的都会被视为一个同字符串)第一个字母转换为大写 | +| title() | 将单词(仅包含字母,若同时包含数字和字母,则数字之后元素被视为另一个单词)第一个字母转换为大写 | +| lower() | 将数组中所有的元素转换为小写 | +| upper() | 将数组中所有的元素转换为大写 | +| swapcase() | 将数组中每个元素字母大写转为小写,小写转为大写 | +| center() | 居中字符串,并使用指定字符在左右侧进行填充 | +| ljust() | 左对齐字符串,并使用指定字符在右侧进行填充 | +| rjust() | 右对齐字符串,并使用指定字符在左侧进行填充 | +| zfill() | 在数组元素的左边填充指定个数的数字 0 | +| strip() | 移除数组每个元素开头和者结尾处的特定字符 | +| lstrip() | 移除数组每个元素开头(最左边)的特定字符 | +| rstrip() | 移除数组每个元素结尾(最右边)的特定字符 | +| partition() | 指定分割符对字符串进行分割(从最左边的分割符开始分割,仅分割一次,返回三个元素) | +| rpartition() | 指定分割符对字符串进行分割(从最右边的分割符开始分割,仅分割一次,返回三个元素) | +| split() | 指定分割符对字符串进行分割(从最左边的分割符开始分割,可指定分割次数,返回多个元素) | +| rsplit() | 指定分割符对字符串进行分割(从最右边的分割符开始分割,可指定分割次数,返回多个元素) | +| replace() | 使用新字符串替换原字符串中的子字符串 | +| splitlines() | 以换行符作为分隔符来分割字符串 | +| translate() | 将数组元素字符串按照给定的转换表进行映射 | +| encode() | 编码操作,数组元素依次调用 str.encode | +| decode() | 解码操作,数组元素依次调用 str.decode | + + +## 【02】numpy.char.add() + +numpy.char.add() 函数用于对两个数组的字符串元素进行连接。 + +基本语法:`numpy.char.add(x1, x2)`,数组 x1 和 x2 必须具有相同的形状。 + +| 参数 | 描述 | +| ------ | ------ | +| x1 | 要处理的 str 或 unicode 数组 | +| x2 | 要处理的 str 或 unicode 数组 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.add(['hello'],[' world'])) +['hello world'] +>>> print(np.char.add(['123', 'abc'], [' 456', ' def'])) +['123 456' 'abc def'] +``` + +## 【03】numpy.char.join() + +numpy.char.join() 函数通过指定分隔符来连接数组中的元素。 + +基本语法:`numpy.char.join(sep1, seq2)` + +| 参数 | 描述 | +| ------ | ------ | +| seq1 | 分割符,str 或 unicode 数组 | +| seq2 | 被分割的 str 或 unicode 数组 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.join('-', 'python')) +p-y-t-h-o-n +>>> +>>> print(np.char.join(['+','-'],['python','java'])) +['p+y+t+h+o+n' 'j-a-v-a'] +``` + +## 【04】numpy.char.mod() + +numpy.char.mod() 函数用于格式化字符串,相当于 Python 字符串中的 % 和 format。 + +基本语法:`numpy.char.mod(value , a)` + +```python +>>> import numpy as np +>>> print(np.char.mod('value=%.2f', np.arange(6))) +['value=0.00' 'value=1.00' 'value=2.00' 'value=3.00' 'value=4.00' 'value=5.00'] +>>> +>>> print(np.char.mod('value=%.4f', [[1.1, 2, 3.021], [4.12, 5, 6.1]])) +[['value=1.1000' 'value=2.0000' 'value=3.0210'] + ['value=4.1200' 'value=5.0000' 'value=6.1000']] +``` + +## 【05】numpy.char.multiply() + +numpy.char.multiply() 函数用于元素的多重连接,即返回 `a*i`。 + +基本语法:`numpy.char.multiply(a, i)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| i | 整数数组 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.multiply('Python ', 4)) +Python Python Python Python +``` + +## 【06】numpy.char.capitalize() + +numpy.char.capitalize() 函数将字符串第一个字母转换为大写。 + +基本语法:`numpy.char.capitalize(a)` + +参数解释:`a`:要处理的 str 或 unicode 数组。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.capitalize('python')) +Python +>>> print(np.char.capitalize(['a1b2','1b2a','b2a1','2a1b'])) +['A1b2' '1b2a' 'B2a1' '2a1b'] +``` + +## 【07】numpy.char.title() + +numpy.char.title() 函数将数组元素字符串的每个单词的第一个字母转换为大写。注意:如果一个字符串中间有非字母,则非字母之后的字符串会被视为另一个单词。 + +基本语法:`numpy.char.title(a)` + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.title('i love python!')) +I Love Python! +>>> print(np.char.title('a1bc2def3h')) +A1Bc2Def3H +>>> print(np.char.title(['a1bc', 'a 1bc', 'a1 bc', 'a1b c'])) +['A1Bc' 'A 1Bc' 'A1 Bc' 'A1B C'] +``` + +## 【08】numpy.char.lower() + +numpy.char.lower() 函数将数组中所有的元素转换为小写。 + +基本语法:`numpy.char.lower(a)` + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.lower('PYTHON')) +python +>>> print(np.char.lower(['PYTHON', 'A123C', 'Ba1A'])) +['python' 'a123c' 'ba1a'] +``` + +## 【09】numpy.char.upper() + +numpy.char.upper() 函数将数组中所有的元素转换为大写。 + +基本语法:`numpy.char.upper(a)` + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.upper('python')) +PYTHON +>>> print(np.char.upper(['python', 'a123c', 'ba1A'])) +['PYTHON' 'A123C' 'BA1A'] +``` + +## 【10】numpy.char.swapcase() + +numpy.char.swapcase() 函数将数组中每个元素字母大写转为小写,小写转为大写。 + +基本语法:`numpy.char.swapcase(a)` + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.swapcase('Abc123DEf456gHI')) +aBC123deF456Ghi +>>> print(np.char.swapcase(['Abc', '1De', '23F', 'Ghi'])) +['aBC' '1dE' '23f' 'gHI'] +``` + +## 【11】numpy.char.center() + +numpy.char.center() 函数用于**居中**字符串,并使用指定字符在**左右侧**进行填充。 + +基本语法:`numpy.char.center(a, width[, fillchar=' '])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| width | int 类型,结果字符串的总长度 | +| fillchar | 可选项,str 或 unicode 数组,要使用的填充字符,默认为空格 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.center('python', 10)) + python +>>> print(np.char.center('python', 12, fillchar='-')) +---python--- +>>> print(np.char.center('python', 11, fillchar='-')) +---python-- +``` + +## 【12】numpy.char.ljust() + +numpy.char.ljust() 函数用于**左对齐**字符串,并使用指定字符在**右侧**进行填充。 + +基本语法:`numpy.char.ljust(a, width[, fillchar=' '])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| width | int 类型,结果字符串的总长度 | +| fillchar | 可选项,str 或 unicode 数组,要使用的填充字符,默认为空格 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.ljust('python', 10, fillchar='-')) +python---- +``` + +## 【13】numpy.char.rjust() +numpy.char.ljust() 函数用于**右对齐**字符串,并使用指定字符在**左侧**进行填充。 + +基本语法:`numpy.char.rjust(a, width[, fillchar=' '])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| width | int 类型,结果字符串的总长度 | +| fillchar | 可选项,str 或 unicode 数组,要使用的填充字符,默认为空格 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.rjust('python', 10, fillchar='-')) +----python +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105350414 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【14】numpy.char.zfill() + +numpy.char.zfill() 函数在数组元素的左边填充指定个数的数字 0。 + +基本语法:`numpy.char.zfill(a, width)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| width | int 类型,数组字符串在左边填充 0 后整个字符串的宽度
如果宽度小于原字符串的宽度,则结果会去掉原字符串中多余的元素 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.zfill('python', 3)) +pyt +>>> print(np.char.zfill('python', 10)) +0000python +``` + +## 【15】numpy.char.strip() + +numpy.char.strip() 函数用于移除开头和结尾处的特定字符。 + +基本语法:`numpy.char.strip(a[, chars=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| chars | 可选项,str 类型,指定要删除的字符集,如果省略或者为 None,则默认为删除空白 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.strip('alibaba','a')) +libab +>>> +>>> print(np.char.strip(['Alibaba','admin','java', 'ABBA'],'a')) +['Alibab' 'dmin' 'jav' 'ABBA'] +``` + +## 【16】numpy.char.lstrip() + +numpy.char.lstrip() 函数用于移除数组每个元素最右边的特定字符。 + +基本语法:`numpy.char.lstrip(a[, chars=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| chars | 可选项,str 类型,指定要删除的字符集,如果省略或者为 None,则默认为删除空白 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.lstrip('alibaba','a')) +libaba +>>> +>>> print(np.char.lstrip(['Alibaba','admin','java', 'aBBa'],'a')) +['Alibaba' 'dmin' 'java' 'BBa'] +``` + +## 【17】numpy.char.rstrip() + +numpy.char.rstrip() 函数用于移除数组每个元素最右边的特定字符。 + +基本语法:`numpy.char.rstrip(a[, chars=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| chars | 可选项,str 类型,指定要删除的字符集,如果省略或者为 None,则默认为删除空白 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.rstrip('alibaba','a')) +alibab +>>> print(np.char.rstrip(['Alibaba','admin','java', 'aBBa'],'a')) +['Alibab' 'admin' 'jav' 'aBB'] +``` + +## 【18】numpy.char.partition() + +numpy.char.partition() 函数通过指定分割符对字符串进行分割,从**最左边**第一次出现的分割符开始分割,仅分割一次,返回三个元素。 + +基本语法:`numpy.char.partition(a, sep)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| sep | 分割字符,str 或 unicode 类型,返回三个元素:分割字符前的字符,分割字符,分割字符后的字符
如果元素包含多个分割字符,以**最左边**的为准,如果找不到分隔符,则返回三个元素:**字符串本身以及两个空字符串** | + +应用举例: + +```python +>>> print(np.char.partition('111a222','a')) +['111' 'a' '222'] +>>> print(np.char.partition('111a222a333','a')) +['111' 'a' '222a333'] +>>> print(np.char.partition('111a222a333','b')) +['111a222a333' '' ''] +>>> print(np.char.partition(['111a222', '23a45'],'a')) +[['111' 'a' '222'] + ['23' 'a' '45']] +``` + +## 【19】numpy.char.rpartition() + +numpy.char.partition() 函数通过指定分割符对字符串进行分割,从**最右边**第一次出现的分割符开始分割,仅分割一次,返回三个元素。 + +基本语法:`numpy.char.rpartition(a, sep)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| sep | 分割字符,str 或 unicode 类型,返回三个元素:分割字符前的字符,分割字符,分割字符后的字符
如果元素包含多个分割字符,以**最右边**的为准,如果找不到分隔符,则返回三个元素:**两个空字符串以及字符串本身** | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.rpartition('111a222a333','a')) +['111a222' 'a' '333'] +>>> print(np.char.rpartition('111a222a333','b')) +['' '' '111a222a333'] +>>> print(np.char.rpartition(['111a222a333', '23a45'],'a')) +[['111a222' 'a' '333'] + ['23' 'a' '45']] +``` + +## 【20】numpy.char.split() + +numpy.char.split() 函数通过指定分割符对字符串进行分割,从**最左边**的分割符开始分割,可指定分割次数,返回多个元素。 + +基本语法:`numpy.char.split(a[, sep=None, maxsplit=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| sep | 分隔符,可选项,str 或者 unicode 类型,如果 sep 未指定或者为 None,则默认为空格 | +| maxsplit | 可选项,int 类型,如果指定 maxsplit,则最多完成 maxsplit 次分割 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.split('I love python!')) +['I', 'love', 'python!'] +>>> print(np.char.split('www.itrhx.com', sep='.')) +['www', 'itrhx', 'com'] +>>> print(np.char.split('one.two.itrhx.com', sep='.', maxsplit=2)) +['one', 'two', 'itrhx.com'] +>>> print(np.char.split('one.two.itrhx.com', '.', 2)) +['one', 'two', 'itrhx.com'] +``` + +## 【21】numpy.char.rsplit() + +numpy.char.split() 函数通过指定分割符对字符串进行分割,从**最右边**的分割符开始分割,可指定分割次数,返回多个元素。 + +基本语法:`numpy.char.rsplit(a[, sep=None, maxsplit=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| sep | 分隔符,可选项,str 或者 unicode 类型,如果 sep 未指定或者为 None,则默认为空格 | +| maxsplit | 可选项,int 类型,如果指定 maxsplit,则最多完成 maxsplit 次分割 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.rsplit('one.two.itrhx.com', '.', 2)) +['one.two', 'itrhx', 'com'] +``` + +## 【22】numpy.char.replace() + +numpy.char.replace() 函数可以使用新字符串来替换原字符串中的子字符串。 + +基本语法:`numpy.char.replace(a, old, new[, count=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| old | 旧的字符串,即要替换的字符串,str 或 unicode 类型 | +| new | 新的字符串,即替换的字符串,str 或 unicode 类型 | +| count | int 类型,如果指定该值 N,则会替换 old 中出现的前 N 个字符串 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.replace('i like python', 'python', 'java')) +i like java +>>> +>>> print(np.char.replace('aaaaaaa', 'a', 'b', count=3)) +bbbaaaa +>>> +>>> print(np.char.replace('a111a11a1a111aa', 'a', 'A', count=3)) +A111A11A1a111aa +``` + +## 【23】numpy.char.splitlines() + +numpy.char.splitlines() 函数以换行符作为分隔符来分割字符串,并返回数组。 + +基本语法:`numpy.char.splitlines(a[, keepends=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| keepends | 如果指定 keepends 为 True,则换行符会包含在结果列表中,否则不包含 | + +```python +>>> import numpy as np +>>> print(np.char.splitlines('hi python!\nhi java!')) +['hi python!', 'hi java!'] +>>> print(np.char.splitlines('hi python!\nhi java!', keepends=True)) +['hi python!\n', 'hi java!'] +``` + +## 【24】numpy.char.translate() + +numpy.char.translate() 函数将数组元素字符串按照给定的转换表进行映射。 + +基本语法:`numpy.char.translate(a, table[, deletechars=None])` + +| 参数 | 描述 | +| ------- | ------- | +| a | 要处理的 str 或 unicode 数组 | +| table | 包含 256 个字符的映射表,映射表通过 `str.maketrans()` 方法转换而来 | +| deletechars | 可选项,str 类型,字符串中要过滤的字符列表 | + +应用举例: + +```python +>>> import numpy as np +>>> intab = 'abcdef' +>>> outtab = '123456' +>>> table = str.maketrans(intab, outtab) # 制作映射表 +>>> print(np.char.translate('this is a translate example!', table)) +this is 1 tr1nsl1t5 5x1mpl5! +``` + +## 【25】numpy.char.encode() + +numpy.char.encode() 函数用于编码操作,数组元素依次调用 str.encode,可以使用 Python 标准库中的编解码器。 + +基本语法:`numpy.char.encode(a[, encoding=None, errors=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| encoding | 编码名称,可选项,str 类型,默认编码为 utf-8 | +| errors | 指定如何处理编码错误,可选项,str 类型 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.encode('python', 'cp500')) +b'\x97\xa8\xa3\x88\x96\x95' +>>> +>>> print(np.char.encode(['aAaAaA', ' aA ', 'abBABba'], 'cp037')) +[b'\x81\xc1\x81\xc1\x81\xc1' b'@@\x81\xc1@@' b'\x81\x82\xc2\xc1\xc2\x82\x81'] +``` + +## 【26】numpy.char.decode() + +numpy.char.decode() 函数用于解码操作,数组元素依次调用 str.decode,可以使用 Python 标准库中的编解码器。 + +基本语法:`numpy.char.decode(a[, encoding=None, errors=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要处理的 str 或 unicode 数组 | +| encoding | 编码名称,可选项,str 类型,默认编码为 utf-8 | +| errors | 指定如何处理编码错误,可选项,str 类型 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.char.decode(b'\x97\xa8\xa3\x88\x96\x95', 'cp500')) +python +>>> +>>> print(np.char.decode([b'\x81\xc1\x81\xc1\x81\xc1' b'@@\x81\xc1@@' b'\x81\x82\xc2\xc1\xc2\x82\x81'], 'cp500')) +['aAaAaA aA abBABba'] +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105350414 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A66-NumPy-05.md b/source/_posts/A66-NumPy-05.md new file mode 100644 index 0000000000000000000000000000000000000000..daab7063afaaa8a0017e3a48523daf57d95ffd38 --- /dev/null +++ b/source/_posts/A66-NumPy-05.md @@ -0,0 +1,1269 @@ +--- +title: Python 数据分析三剑客之 NumPy(五):数学 / 算术 / 统计 / 排序 / 条件 / 判断函数合集 +tags: + - NumPy + - 数学函数 + - 算术函数 + - 统计函数 + - 排序函数 + - 条件函数 + - 判断函数 +categories: + - Python 数据分析 + - NumPy +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/numpy.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 NumPy(五):数学、算术、统计、排序、条件、判断相关的函数合集。 +--- + +NumPy 系列文章: + +- [Python 数据分析三剑客之 NumPy(一):理解 NumPy / 数组基础](https://www.itrhx.com/2020/03/20/A62-NumPy-01/) +- [Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割](https://www.itrhx.com/2020/03/22/A63-NumPy-02/) +- [Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算](https://www.itrhx.com/2020/03/24/A64-NumPy-03/) +- [Python 数据分析三剑客之 NumPy(四):字符串函数总结与对比](https://www.itrhx.com/2020/03/26/A65-NumPy-04/) +- [Python 数据分析三剑客之 NumPy(五):数学 / 算术 / 统计 / 排序 / 条件 / 判断函数合集](https://www.itrhx.com/2020/03/28/A66-NumPy-05/) +- [Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作](https://www.itrhx.com/2020/03/30/A67-NumPy-06/) + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105398131 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】NumPy 函数速查表 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NumPy 三角函数
函数描述
sin()正弦函数
cos()余弦函数
tan()正切函数
arcsin()反正弦函数
arccos()反余弦函数
arctan()反正切函数
NumPy 舍入函数
函数描述
around()将指定数字四舍五入到指定的小数位
rint()将指定数字四舍五入到最近的整数
floor()返回小于或者等于指定表达式的最大整数,即向下取整
ceil()返回大于或者等于指定表达式的最小整数,即向上取整
NumPy 算术函数
函数描述
add()数组元素加法运算
subtract()数组元素减法运算
multiply()数组元素乘法运算
divide()数组元素除法运算
reciprocal()返回数组元素的倒数
power()返回数组元素的乘幂
mod()返回数组元素的相除后的余数
remainder()返回数组元素的相除后的余数
NumPy 统计函数
函数描述
amax()计算数组元素沿指定轴的最大值
amin()计算数组元素沿指定轴的最小值
argmax()计算数组元素沿指定轴的最大值的索引值
argmin()计算数组元素沿指定轴的最小值的索引值
sum()计算数组中所有元素的和
cumsum()返回一个一维数组,每个元素都是之前所有元素的累加和
cumprod()返回一个一维数组,每个元素都是之前所有元素的累乘积
ptp()计算数组元素最大值与最小值的差
percentile()计算多维数组的任意百分位数
median()计算数组元素的中位数
mean()计算数组元素的算术平均值
average()计算数组元素的加权平均值
std()计算数组元素的标准差
var()计算数组元素的方差
NumPy 排序函数
sort()将原数组元素按照从小到大排序
msort()将原数组元素按照第一个轴的从小到大排序
argsort()将元素从小到大排列,提取对应的索引值并返回
lexsort()将多个序列按照从小到大排序,返回其索引值
sort_complex()对复数数组进行从小到大排序
partition()对数组进行分区排序
argpartition()对数组进行分区排序,返回元素的索引值
unique()将数组元素去重后返回从小到大的排序结果
NumPy 条件函数
nonzero()返回原数组中非零元素的索引值
where()返回数组中满足指定条件的元素的索引值
extract()返回数组中满足指定条件的元素
NumPy 判断函数
any()至少有一个元素满足指定条件,则返回 True,否则返回 False
all()所有的元素满足指定条件,则返回 True,否则返回 False
+ +## 【2x00】NumPy 数学函数 + +NumPy 数学函数包含三角函数、舍入函数等。 + +### 【2x01】sin() / cos() / tan() + +`numpy.sin()`、`numpy.cos()`、`numpy.tan()` 分别对应**正弦函数****余弦函数****正切函数**。 + +在求三角函数时,会先将角度转化成弧度,在 NumPy 中的转化公式:`角度 * numpy.pi/180` + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([0, 30, 45, 60 ,90]) +>>> print(np.sin(a*np.pi/180)) +[0. 0.5 0.70710678 0.8660254 1. ] +>>> print(np.cos(a*np.pi/180)) +[1.00000000e+00 8.66025404e-01 7.07106781e-01 5.00000000e-01 6.12323400e-17] +>>> print(np.tan(a*np.pi/180)) +[0.00000000e+00 5.77350269e-01 1.00000000e+00 1.73205081e+00 1.63312394e+16] +``` + +--- + +### 【2x02】arcsin() / arccos() / arctan() + +`numpy.arcsin()`、`numpy.arccos()`、`numpy.arctan()` 分别对应**反正弦函数****反余弦函数****反正切函数**。 + +在求三角函数时,会先将角度转化成弧度,在 NumPy 中的转化公式:`角度 * numpy.pi/180` + + +arcsin、arccos、arctan 接收的参数是三角函数值,函数返回给定角度的 sin,cos 和 tan 的反三角函数,如果 sinθ=x,那么 arcsinx=θ,其他类似,这些函数的结果可以通过 `numpy.degrees()` 函数将弧度转换为角度。 + +```python +>>> import numpy as np +>>> a = np.array([0, 30, 45, 60 ,90]) +>>> a_sin = np.sin(a*np.pi/180) +>>> a_arcsin = np.arcsin(a_sin) +>>> print(a_sin) # 角度的正弦值 +[0. 0.5 0.70710678 0.8660254 1. ] +>>> print(a_arcsin) # 角度的反正弦值,返回值的单位为弧度 +[0. 0.52359878 0.78539816 1.04719755 1.57079633] +>>> print(np.degrees(a_arcsin)) # 弧度转化为角度 +[ 0. 30. 45. 60. 90.] +``` + +--- + +### 【2x03】around() / rint() / floor() / ceil() + + +1、`numpy.around()` 函数将指定数字四舍五入到**指定的小数位**,可指定保留的小数位数。 + +基本语法:`numpy.around(a[, decimals=0, out=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 输入数组 | +| decimals | int 类型,可选项,舍入的小数位数,默认值为 0,如果为负,整数将四舍五入到小数点左侧的位置 | +| out | ndarray 对象,可选项,放置结果的备用输出数组。它必须具有与预期输出相同的形状,但是如有必要,将强制转换输出值的类型 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([13, 1.4, 6.23, 12.834]) +>>> print(np.around(a)) +[13. 1. 6. 13.] +>>> print(np.around(a, decimals=1)) +[13. 1.4 6.2 12.8] +>>> print(np.around(a, decimals=-1)) +[10. 0. 10. 10.] +``` + +2、`numpy.rint()` 函数将指定数字四舍五入到**最近的整数**,不保留小数位。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.rint([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0])) +[-2. -2. -0. 0. 2. 2. 2.] +``` + + +3、`numpy.floor()` 函数会返回小于或者等于指定表达式的最大整数,即**向下取整**。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.floor([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0])) +[-2. -2. -1. 0. 1. 1. 2.] +``` + +4、`numpy.ceil()` 函数会返回大于或者等于指定表达式的最小整数,即**向上取整**。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.ceil([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0])) +[-1. -1. -0. 1. 2. 2. 2.] +``` + +## 【3x00】NumPy 算术函数 + +NumPy 算术函数包含了基本的加减乘除运算、求倒数、幂、余数等。 + +### 【3x01】add() / subtract() / multiply() / divide() + +`add()`、`subtract()`、`multiply()`、`divide()` 分别对应 `NumPy` 中的**加减乘除**运算。 + +注意:两个数组必须具有相同的形状或符合数组的广播规则才能进行运算。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) +>>> b = np.array([5, 5, 5]) +>>> print(np.add(a, b)) +[[ 5 6 7] + [ 8 9 10] + [11 12 13]] +>>> print(np.subtract(a, b)) +[[-5 -4 -3] + [-2 -1 0] + [ 1 2 3]] +>>> print(np.multiply(a, b)) +[[ 0 5 10] + [15 20 25] + [30 35 40]] +>>> print(np.divide(a, b)) +[[0. 0.2 0.4] + [0.6 0.8 1. ] + [1.2 1.4 1.6]] +``` + +### 【3x02】reciprocal() / power() / mod() / remainder() + +1、`numpy.reciprocal()` 函数用于返回各数组元素的**倒数**。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.reciprocal([0.25, 4, 1, 2.10])) +[4. 0.25 1. 0.47619048] +``` + +2、`numpy.power()` 函数将第一个数组中的元素作为底数,计算它与第二个数组中相应元素的**幂**。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([5, 10, 100]) +>>> b = np.array([3, 2, 1]) +>>> print(np.power(a, b)) +[125 100 100] +>>> +>>> print(np.power(a, 2)) +[ 25 100 10000] +``` + +3、`numpy.mod()` 与 ` numpy.remainder()` 都可以计算数组中相应元素相除后的**余数**。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([10, 15, 20]) +>>> b = np.array([3, 4, 5]) +>>> print(np.mod(a, b)) +[1 3 0] +>>> print(np.remainder(a, b)) +[1 3 0] +>>> print(np.mod(a, 6)) +[4 3 2] +>>> print(np.remainder(a, 9)) +[1 6 2] +``` + +### 【3x03】absolute() / isnan() + +1、`numpy.absolute()` 函数用于计算**元素的绝对值**。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.absolute([-1.2, 1.2, 13, -10])) +[ 1.2 1.2 13. 10. ] +``` + +2、`numpy.isnan()` 函数用于**判断元素是否为 NaN(Not a Number)**。 + +应用举例: + +```python +>>> import numpy as np +>>> np.isnan(np.nan) +True +>>> np.isnan(np.inf) +False +>>> print(np.isnan([np.nan, 2, 3, np.nan])) +[ True False False True] +``` + +## 【4x00】NumPy 统计函数 + +NumPy 统计函数包含了计算最大值、最小值、最大值与最小值的差、百分位数、中位数、算术平均值、加权平均值、标准差与方差等。 + +### 【4x01】amax() / amin() + +`numpy.amax()` 和 `numpy.amin()` 函数分别用于计算数组中的元素沿指定轴的**最大值****最小值**。 + +基本语法: + +`numpy.amax(a[, axis=None, out=None, keepdims=, initial=, where=])` + +`numpy.amin(a[, axis=None, out=None, keepdims=, initial=, where=])` + +参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| out | ndarray 对象,可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | +| keepdims | bool 类型,可选项,是否保持数组的二维特性 | +| initial | 初始值标量,可选项,如果设置了标量,则除了元素之间的比较外,还会和标量进行对比 | +| where | 比较条件,通常和 initial 参数一起使用
如果当前是 amax 函数,where 为 True 时则会比较最大值, Flase 则会比较最小值
该参数含义比较模糊,参考资料较少,准确描述请参考[官方文档](https://numpy.org/doc/1.18/reference/generated/numpy.amax.html) | + + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[2, 4], [8, 9]]) +>>> print(a) +[[2 4] + [8 9]] +>>> +>>> print(np.amax(a)) +9 +>>> +>>> print(np.amax(a, axis=0)) # 元素按行比较 +[8 9] +>>> +>>> print(np.amax(a, axis=0, keepdims=True)) # 元素按行比较并保持数组的二维特性 +[[8 9]] +>>> +>>> print(np.amax(a, axis=1)) # 元素按列比较 +[4 9] +>>> +>>> print(np.amax(a, axis=1, initial=5)) # 元素按列比较(包括标量一起比较) +[5 9] +``` + +### 【4x02】argmax() / argmin() + +`numpy.argmax()` 和 `numpy.argmin()` 函数分别沿指定轴返回**最大元素和最小元素的索引值**。 + +基本语法:`numpy.argmax(a[, axis=None, out=None])`;`numpy.argmin(a[, axis=None, out=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型,若未指定,则在操作前会将数组展开 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[30,40,70],[80,20,10],[50,90,60]]) +>>> print(a) +[[30 40 70] + [80 20 10] + [50 90 60]] +>>> +>>> print (np.argmax(a)) +7 +>>> +>>> print(np.argmin(a)) +5 +>>> +>>> print(np.argmax(a, axis=0)) +[1 2 0] +>>> +>>> print(np.argmin(a, axis=0)) +[0 1 1] +``` + +### 【4x03】sum() + +`numpy.sum()` 函数用于计算所有元素的**和**。 + +基本语法:`numpy.sum(a, axis=None, dtype=None, out=None, keepdims=, initial=, where=)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型,若未指定则运算前会将数组展平 | +| dtype | 指定数据类型,可选项 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | +| keepdims | bool 类型,可选项,是否保持数组的二维特性 | +| initial | 初始值标量,可选项,如果设置了标量,则除了元素之间的求和外,还会和标量进行求和 | +| where | 求和条件,总和中要包括的元素 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.sum([[0, 1], [0, 5]])) +6 +>>> print(np.sum([[0, 1], [0, 5]], axis=0)) +[0 6] +>>> print(np.sum([[0, 1], [0, 5]], axis=1)) +[1 5] +>>> print(np.sum([[0, 1], [np.nan, 5]], where=[False, True], axis=1)) +[1. 5.] +>>> print(np.sum([10], initial=5)) +15 +``` + +### 【4x04】cumsum() / cumprod() + +`numpy.cumsum()`:返回一个一维数组,每个元素都是之前所有元素的**累加和**。 +`numpy.cumprod()`:返回一个一维数组,每个元素都是之前所有元素的**累乘积**。 + +基本语法:`numpy.cumsum(a, axis=None, dtype=None, out=None)`;`numpy.cumprod(a, axis=None, dtype=None, out=None)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型,若未指定则运算前会将数组展平 | +| dtype | 指定数据类型,可选项 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2,3], [4,5,6]]) +>>> print(np.cumsum(a)) +[ 1 3 6 10 15 21] +>>> +>>> print(np.cumsum(a, axis=0)) +[[1 2 3] + [5 7 9]] +>>> +>>> print(np.cumsum(a, axis=1)) +[[ 1 3 6] + [ 4 9 15]] +>>> +>>> print(np.cumprod(a)) +[ 1 2 6 24 120 720] +>>> +>>> print(np.cumprod(a, axis=0)) +[[ 1 2 3] + [ 4 10 18]] +>>> +>>> print(np.cumprod(a, axis=1)) +[[ 1 2 6] + [ 4 20 120]] +``` + +### 【4x05】ptp() + +`numpy.ptp()` 函数用于计算数组中元素**最大值与最小值的差**。 + +基本语法:`numpy.ptp(a[, axis=None, out=None, keepdims=])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | +| keepdims | bool 类型,可选项,是否保持数组的二维特性 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[2,5,8],[7,6,3],[2,9,4]]) +>>> print(a) +[[2 5 8] + [7 6 3] + [2 9 4]] +>>> print(np.ptp(a)) +7 +>>> +>>> print(np.ptp(a, axis=0)) +[5 4 5] +>>> +>>> print(np.ptp(a, axis=1)) +[6 4 7] +>>> print(np.ptp(a, axis=1, keepdims=True)) +[[6] + [4] + [7]] +``` + +### 【4x06】percentile() + +`numpy.percentile()` 函数用于计算一个多维数组的任意**百分位数**。 + +百分位数:统计学术语,如果将一组数据从小到大排序,并计算相应的累计百分位,则某一百分位所对应数据的值就称为这一百分位的百分位数。可表示为:一组 n 个观测值按数值大小排列。如:处于 p% 位置的值称第 p 百分位数。 + +基本语法:`numpy.percentile(a, q[, axis=None, out=None, overwrite_input=False, interpolation='linear', keepdims=False])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| q | 要计算的百分位数,在 [0, 100] 之间 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | +| overwrite_input | bool 值,可选项,如果为True,则允许通过中间计算来修改输入数组 a 以节省内存
在这种情况下,此操作完成后 a 的内容是不确定的 | +| interpolation | 可选项,指定当所需百分比位于两个数据点 `i**linear**:`i + (j - i) * fraction`,其中 fraction 是由 i 和 j 包围的索引的分数部分
**lower**:`i`;**higher**:`j`;**nearest**:`i` 或 `j`,以最近者为准;**midpoint**:`(i + j) / 2` | +| keepdims | bool 类型,可选项,是否保持数组的二维特性 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[10, 7, 4], [3, 2, 1]]) +>>> print(a) +[[10 7 4] + [ 3 2 1]] +>>> +>>> print(np.percentile(a, 50)) +3.5 +>>> +>>> print(np.percentile(a, 50, axis=0)) +[6.5 4.5 2.5] +>>> +>>> print(np.percentile(a, 50, axis=1)) +[7. 2.] +>>> +>>> print(np.percentile(a, 50, axis=1, keepdims=True)) +[[7.] + [2.]] +``` + +### 【4x07】median() + +`numpy.median()` 函数用于计算数组元素的**中位数**。 + +基本语法:`numpy.median(a[, axis=None, out=None, overwrite_input=False, keepdims=False])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | +| overwrite_input | bool 值,可选项,如果为True,则允许通过中间计算来修改输入数组 a 以节省内存
在这种情况下,此操作完成后 a 的内容是不确定的 | +| keepdims | bool 类型,可选项,是否保持数组的二维特性 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[10, 7, 4], [3, 2, 1]]) +>>> print(a) +[[10 7 4] + [ 3 2 1]] +>>> +>>> print(np.median(a)) +3.5 +>>> +>>> print(np.median(a, axis=0)) +[6.5 4.5 2.5] +>>> +>>> print(np.median(a, axis=1)) +[7. 2.] +``` + +### 【4x08】mean() + +`numpy.mean()` 函数计算数组中元素的**算术平均值**。 + +算术平均值:沿轴的元素的总和除以元素的数量。 + +基本语法:`numpy.mean(a[, axis=None, dtype=None, out=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| dtype | 可选项,用于计算平均值的类型 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[10, 7, 4], [3, 2, 1]]) +>>> print(a) +[[10 7 4] + [ 3 2 1]] +>>> +>>> print(np.mean(a)) +4.5 +>>> +>>> print(np.mean(a, axis=0)) +[6.5 4.5 2.5] +>>> +>>> print(np.mean(a, axis=1)) +[7. 2.] +``` + +### 【4x09】average() + +`numpy.average()` 函数根据在另一个数组中给出的各自的权重来计算数组中元素的**加权平均值**。 + +加权平均值:将各数值乘以相应的权数,然后加总求和得到总体值,再除以总的单位数。 + +例如:现有数组 `[1, 2, 3, 4]`,相应的权重为 `[5, 6, 7, 8]`,则计算方法为:`(1*5+2*6+3*7+4*8)/(5+6+7+8)≈ 2.6923` + +基本语法:`numpy.average(a[, axis=None, weights=None, returned=False])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| weights | 可选项,与 a 中的值相关联的权重数组,如果 weights=None,则 a 中的所有数据都具有 1 的权重,相当于 `mean` 函数 | +| returned | 可选项,bool 类型,默认为 False,如果为 True,则返回元组 `(加权平均值, 权重)`,否则只返回加权平均值 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4]) +>>> print(np.average(a)) # 不指定权重时相当于 mean 函数 +2.5 +>>> +>>> print(np.average(a, weights=[5, 6, 7, 8])) +2.6923076923076925 +>>> +>>> print(np.average(a, weights=[5, 6, 7, 8], returned=True)) +(2.6923076923076925, 26.0) +``` + +### 【4x10】std() / var() + +`numpy.std()` 和 `numpy.var()` 分别用于计算数组元素的**标准差****方差**。 + +标准差是一组数据平均值分散程度的一种度量,标准差是方差的算术平方根。 + +方差为 S2,标准差为 S,计算公式如下: + +$$S^2 = \frac {1} {n} \sum_{i=1} ^ {n} (x_i - \overline {x})^2$$ + +$$S = \sqrt {S^2}$$ + +基本语法: + +`numpy.std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=)` + +`numpy.var(a[, axis=None, dtype=None, out=None, ddof=0, keepdims=])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| dtype | 可选项,值的数据类型 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | +| ddof | 自由度(Delta Degrees of Freedom),计算中使用的除数是 N-ddof,其中 N 表示元素的数量,ddof 默认为零 | +| keepdims | bool 类型,可选项,是否保持数组的二维特性 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2], [3, 4]]) +>>> print(a) +[[1 2] + [3 4]] +>>> +>>> print(np.std(a)) +1.118033988749895 +>>> +>>> print(np.std(a, axis=0)) +[1. 1.] +>>> +>>> print(np.std(a, axis=1)) +[0.5 0.5] +>>> +>>> print(np.var(a)) +1.25 +>>> +>>> print(np.var(a, axis=0)) +[1. 1.] +>>> +>>> print(np.var(a, axis=1)) +[0.25 0.25] +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105398131 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【5x00】NumPy 排序函数 + +NumPy 排序函数中可以指定使用的排序方法,各种分类算法的特征在于它们的平均速度,最坏情况下的性能,工作空间大小以及它们是否稳定,三种算法对比如下: + +| 方法 | 速度 | 最坏情况 | 工作空间 | 稳定性 | +| ------ | ------ | ------------- | ------------ | ---------- | +| 快速排序(quicksort) | 1 | O(n^2) | 0 | no | +| 归并排序(mergesort) | 2 | O(n*log(n)) | ~n/2 | yes | +| 堆排序(heapsort) | 3 | O(n*log(n)) | 0 | no | + +### 【5x01】sort() + +`numpy.sort()` 函数会将原数组元素**从小到大排序**,返回输入数组的排序副本。 + +基本语法:`numpy.sort(a[, axis=-1, kind='quicksort', order=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要排序的数组 | +| axis | 要排序的轴,可选项,如果为 None,则在排序之前会将数组展平,默认值为 -1,它沿着最后一个轴排序 | +| kind | 排序算法,可选项,默认值为快速排序(quicksort) | +| order | 字符串或者字符串列表,可选项,若指定 order 值,将按照该字段进行排序 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,4],[3,1]]) +>>> print(np.sort(a)) +[[1 4] + [1 3]] +>>> +>>> print(np.sort(a, axis=None)) # 数组将展平 +[1 1 3 4] +>>> +>>> print(np.sort(a, axis=0)) +[[1 1] + [3 4]] +>>> +>>> print(np.sort(a, axis=1)) +[[1 4] + [1 3]] +``` + +```python +>>> import numpy as np +>>> dtype = [('name', 'S10'), ('height', float), ('age', int)] +>>> values = [('Arthur', 1.8, 41), ('Lancelot', 1.9, 38), ('Galahad', 1.7, 38)] +>>> a = np.array(values, dtype=dtype) +>>> print(a) +[(b'Arthur', 1.8, 41) (b'Lancelot', 1.9, 38) (b'Galahad', 1.7, 38)] +>>> +>>> print(np.sort(a, order='height')) # 按 height 排序 +[(b'Galahad', 1.7, 38) (b'Arthur', 1.8, 41) (b'Lancelot', 1.9, 38)] +>>> +>>> print(np.sort(a, order=['age', 'height'])) # 按 age 排序,如果 age 相等,则按 height 排序 +[(b'Galahad', 1.7, 38) (b'Lancelot', 1.9, 38) (b'Arthur', 1.8, 41)] +``` + +### 【5x02】msort() + +`numpy.msort()` 函数将数组**按第一个轴从小到大排序**,返回排序后的数组副本,相当于 `numpy.sort(a, axis=0)` + +应用举例: + +```python +>>> import numpy as np +>>> print(np.msort([[1, 4, 5], [2, 1, 3]])) +[[1 1 3] + [2 4 5]] +>>> print(np.sort([[1, 4, 5], [2, 1, 3]], axis=0)) +[[1 1 3] + [2 4 5]] +``` + +### 【5x03】argsort() + +`numpy.argsort()` 函数将原数组元素**从小到大排列**,提取其对应在原数组中的**索引值**并返回。 + +举例:原数组为:`[3, 1, 2]`,从小到大排列:`[1, 2, 3]`,排列后的各元素在原数组中对应的索引值:`[1, 2, 0]` + +基本语法:`numpy.argsort(a[, axis=-1, kind=None, order=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 要排序的数组 | +| axis | 要排序的轴,可选项,如果为 None,则在排序之前会将数组展平,默认值为 -1,它沿着最后一个轴排序 | +| kind | 排序算法,可选项,默认值为快速排序(quicksort) | +| order | 字符串或者字符串列表,可选项,若指定 order 值,将按照该字段进行排序 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([3, 1, 2]) +>>> print(np.argsort(a)) +[1 2 0] +>>> +>>> b = np.array([[0, 3], [2, 2]]) +>>> print(np.argsort(b)) +[[0 1] + [0 1]] +>>> +>>> print(np.argsort(b, axis=0)) +[[0 1] + [1 0]] +>>> +>>> print(np.argsort(b, axis=1)) +[[0 1] + [0 1]] +``` + +### 【5x04】lexsort() + +`numpy.lexsort()` 函数使用键序列执行间接稳定排序,用于**对多个序列进行排序,返回其索引值**。 + +基本语法:`numpy.lexsort(keys, axis=-1)` + +| 参数 | 描述 | +| ------ | ------ | +| keys | 类似于 `(k, N)` 的要排序的数组 | +| axis | 指定要排序的轴,默认对最后一个轴进行排序 | + +举例:现有数组 `a = [1,5,1,4,3,4,4]`,`b = [9,4,0,4,0,2,1]`,利用 lexsort() 函数排序后的结果为:`[2,0,4,6,5,3,1]`,排序过程如下: + +假设数组 a1 为语文成绩:`a1 = [1,5,1,4,3,4,4]` +假设数组 b1 为数学成绩:`b1 = [9,4,0,4,0,2,1]` +数组索引值 c1 为同学姓名: `c1 = [0,1,2,3,4,5,6]` + +**1、首先按照语文成绩进行排名:** +语文成绩(数组 a)从小到大排名:`a2 = [1,1,3,4,4,4,5]`,对应的学生姓名(索引值)为:`c2 = [0,2,4,3,5,6,1]`,现在可以看到: +**0****2** 同学的语文成绩都一样,均为 **1** +**3****5****6** 同学的语文成绩都一样,均为 **4** + +**2、接下来,对于语文成绩相同的,按照他们的数学成绩再次进行排名:** +**0****2** 同学对应的数学成绩分别为:**9****0**,从小到大再次排序,即 **0** 排在 **2** 的后面,对应的学生姓名为 `c3 = [2,0,4,3,5,6,1]` +**3****5****6** 同学对应的数学成绩分别为:**4****2****1**,从小到大再次排序后,对应的学生姓名为 `c4 = [2,0,4,6,5,3,1]`,即最终结果。 + +简单来说,先对数组 a 从小到大排序,提取排序后元素对应的索引值,排序后元素有相同的,再根据数组 b 从小到大排序,得到最终的索引值。 + +以上步骤用 `numpy.lexsort()` 函数实现如下: + +```python +>>> import numpy as np +>>> a = [1,5,1,4,3,4,4] +>>> b = [9,4,0,4,0,2,1] +>>> +>>> c1 = np.lexsort((a,b)) # 先按 b 排序,再按照 a 排序 +>>> c2 = np.lexsort((b,a)) # 先按 a 排序,再按照 b 排序 +>>> +>>> print(c1) +[2 4 6 5 3 1 0] +>>> print(c2) +[2 0 4 6 5 3 1] +>>> +>>> print([(a[i],b[i]) for i in c1]) +[(1, 0), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4), (1, 9)] +>>> print([(a[i],b[i]) for i in c2]) +[(1, 0), (1, 9), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4)] +``` + +```python +>>> import numpy as np +>>> first_names = ('Hertz', 'Galilei', 'Hertz') +>>> second_names = ('Heinrich', 'Galileo', 'Gustav') +>>> +>>> print(np.lexsort((second_names, first_names))) # 按照字母对应的 ascii 码从小到大进行排序 +[1 2 0] +``` + +### 【5x05】sort_complex() + +`numpy.sort_complex()` 函数先使用实部,再使用虚部**对复数数组进行排序**。 + +复数:把形如 z=a+bi(a,b 均为实数)的数称为复数,其中 a 称为实部,b 称为虚部,i 称为虚数单位。 + +基本语法:`numpy.sort_complex(a)` + +应用举例: + +```python +>>> import numpy as np +>>> print(np.sort_complex([5, 3, 6, 2, 1])) +[1.+0.j 2.+0.j 3.+0.j 5.+0.j 6.+0.j] +>>> +>>> print(np.sort_complex([1 + 2j, 2 - 1j, 3 - 2j, 3 - 3j, 3 + 5j])) +[1.+2.j 2.-1.j 3.-3.j 3.-2.j 3.+5.j] +``` + +### 【5x06】partition() + +`numpy.partition()` 函数用于对数组进行**分区排序**,返回数组的分区副本。 + +基本语法:`numpy.partition(a, kth[, axis=-1, kind='introselect', order=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待排序数组 | +| kth | 整数或者整数序列,原数组元素中从小到大的第 k 个元素,在排序后的数组中,仍然处于第 k 位置
小于该元素的位于该元素的左边,大于该元素的位于该元素的右边,左右两边没有特别的排序要求 | +| axis | 指定要排序的轴,可选项,默认对最后一个轴进行排序 | +| kind | 排序算法,可选项,默认值为快速排序(quicksort) | +| order | 字符串或者字符串列表,可选项,若指定 order 值,将按照该字段进行排序 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([3, 4, 2, 1]) +>>> print(np.partition(a, 3)) # 原数组元素中从小到大的第 3 个元素,排序后仍然处于第 3 位置,小于 3 的在前面,大于 3 的在后面,前后无特别排序要求 +[2 1 3 4] +>>> +>>> print(np.partition(a, (1, 3))) # 小于 1 的在前面,大于 3 的在后面,1 和 3 之间的在中间 +[1 2 3 4] +``` + +### 【5x07】argpartition() + +`numpy.argpartition()` 函数用于对数组进行**分区排序**,返回重组后的**索引值数组**。 + +利用该函数可以很快地找出第 k 大的数的位置,以及大于 k(排在 k 后面)和小于 k(排在 k 前面)的数的位置。 + +基本语法:`numpy.argpartition(a[, kth, axis=-1, kind='introselect', order=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待排序数组 | +| kth | 整数或者整数序列,原数组元素中从小到大的第 k 个元素,在排序后的数组中,仍然处于第 k 位置
小于该元素的位于该元素的左边,大于该元素的位于该元素的右边,左右两边没有特别的排序要求 | +| axis | 指定要排序的轴,可选项,默认对最后一个轴进行排序 | +| kind | 排序算法,可选项,默认值为快速排序(quicksort) | +| order | 字符串或者字符串列表,可选项,若指定 order 值,将按照该字段进行排序 | + + +以下实例将找到数组的第 3 小(索引值 2)的值和第 2 大(索引值 -2)的值: + +```python +>>> import numpy as np +>>> a = np.array([46, 57, 23, 39, 1, 10, 0, 120]) +>>> print(a[np.argpartition(a, 2)[2]]) +10 +>>> print(a[np.argpartition(a, -2)[-2]]) +57 +``` + +### 【5x08】unique() + +`numpy.unique()` 函数**找到唯一值并返回从小到大的排序结果**,类似于 Python 的 set 集合。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.unique([1, 1, 2, 2, 3, 3])) +[1 2 3] +>>> +>>> a = np.array([[1, 0, 0], [1, 0, 0], [2, 3, 4]]) +>>> print(np.unique(a, axis=0)) +[[1 0 0] + [2 3 4]] +``` + +## 【6x00】NumPy 条件函数 + +### 【6x01】nonzero() + +`numpy.nonzero()` 函数将返回原数组中**非零元素的索引值**。 + +基本语法:`numpy.nonzero(a)` + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[3, 0, 0], [0, 4, 0], [5, 6, 0]]) +>>> print(np.nonzero(a)) +(array([0, 1, 2, 2], dtype=int32), + array([0, 1, 0, 1], dtype=int32)) +``` + +返回两个数组,其中的元素一一对应,比如数字 `3` 的索引值为 `(0,0)`,数字 `4` 的索引值为 `(1,1)` + +### 【6x02】where() + +`numpy.where()` 函数**返回数组中满足指定条件的元素的索引值**。 + +基本语法:`numpy.where(condition[, x, y])` + +| 参数 | 描述 | +| ------ | ------ | +| condition | 判断条件,如果满足该条件,则产生 x,否则产生 y,若未指定 x 与 y,则返回满足该条件元素的索引值 | +| x, y | 返回的值为数组对象,如果满足 condition,则产生 x,否则产生 y | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([12, 7, 9, 10, 21, 5, 11, 1]) +>>> +>>> print(np.where(a>8)) +(array([0, 2, 3, 4, 6], dtype=int32),) # 返回满足 a>8 的元素的索引值 +>>> +>>> print(np.where(a>8, a, 10*a)) # 如果原数组中的元素 a>8,则返回 a,否则返回 10*a +[12 70 9 10 21 50 11 10] +``` + +### 【6x03】extract() + +`numpy.extract()` 函数**返回数组中满足指定条件的元素**。 + +基本语法:`numpy.extract(condition, arr)` + +| 参数 | 描述 | +| ------ | ------ | +| condition | 判断条件 | +| arr | 原数组 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([12, 7, 9, 10, 21, 5, 11, 1]) +>>> print(np.extract(a>8, a)) +[12 9 10 21 11] +``` + +```python +>>> import numpy as np +>>> a = np.arange(9).reshape(3,3) +>>> print(a) +[[0 1 2] + [3 4 5] + [6 7 8]] +>>> +>>> condition = np.mod(a,2) == 0 # 定义筛选条件(余数为 0,即偶数) +>>> print(condition) +[[ True False True] + [False True False] + [ True False True]] +>>> +>>> print(np.extract(condition, a)) +[0 2 4 6 8] +``` + +## 【7x00】NumPy 判断函数 + +### 【7x01】any() / all() + +`numpy.any()`:如果**至少有一个**元素满足指定条件,则返回 True,否则返回 False。 + +`numpy.all()`:如果**所有**的元素满足指定条件,则返回 True,否则返回 False。 + +基本语法:`numpy.any(a[, axis=None, out=None, keepdims=])`;`numpy.all(a[, axis=None, out=None, keepdims=])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| axis | 指定轴,可选项,整数或者整数元组类型 | +| out | 可选项,放置结果的备用输出数组,必须具有与预期输出数组相同的形状和缓冲区长度 | +| keepdims | bool 类型,可选项,是否保持数组的二维特性 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.any([[True, False], [True, True]])) +True +>>> +>>> a = np.array([-3, -2, 4, 2, 8, 1]) +>>> print(np.any(a<0)) +True +``` + +```python +>>> import numpy as np +>>> print(np.all([[True, False], [True, True]])) +False +>>> +>>> a = np.array([-3, -2, 4, 2, 8, 1]) +>>> print(np.all(a<0)) +False +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105398131 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A67-NumPy-06.md b/source/_posts/A67-NumPy-06.md new file mode 100644 index 0000000000000000000000000000000000000000..817853658db349f9df15a0b3d7bec63ce2b47b61 --- /dev/null +++ b/source/_posts/A67-NumPy-06.md @@ -0,0 +1,975 @@ +--- +title: Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作 +tags: + - NumPy + - 矩阵 + - 线性代数 + - IO操作 +categories: + - Python 数据分析 + - NumPy +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/numpy.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 NumPy(六):矩阵、线性代数库与 IO 操作。 +--- + + +NumPy 系列文章: + +- [Python 数据分析三剑客之 NumPy(一):理解 NumPy / 数组基础](https://www.itrhx.com/2020/03/20/A62-NumPy-01/) +- [Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割](https://www.itrhx.com/2020/03/22/A63-NumPy-02/) +- [Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算](https://www.itrhx.com/2020/03/24/A64-NumPy-03/) +- [Python 数据分析三剑客之 NumPy(四):字符串函数总结与对比](https://www.itrhx.com/2020/03/26/A65-NumPy-04/) +- [Python 数据分析三剑客之 NumPy(五):数学 / 算术 / 统计 / 排序 / 条件 / 判断函数合集](https://www.itrhx.com/2020/03/28/A66-NumPy-05/) +- [Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作](https://www.itrhx.com/2020/03/30/A67-NumPy-06/) + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105511641 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】NumPy 矩阵库 + +`numpy.matlib` 模块是 NumPy 的矩阵库,该矩阵库包含多种函数,函数返回的是一个矩阵,而不是 Ndarray 对象。 + +官方文档介绍:[https://numpy.org/doc/1.18/reference/routines.matlib.html](https://numpy.org/doc/1.18/reference/routines.matlib.html) + +### 【1x01】numpy.mat() + +`numpy.mat()` 函数将输入数组转换为为矩阵。 + +基本语法:`numpy.mat(data[, dtype=None])` + +| 参数 | 描述 | +| ------ | ------ | +| data | 输入数据,如果 data 为字符串,则需要用逗号或空格分隔列,用分号分隔行 | +| dtype | 输出矩阵的数据类型,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.mat([1, 2, 3]) +>>> a +matrix([[1, 2, 3]]) +>>> a[0] +matrix([[1, 2, 3]]) +>>> a[0,1] +2 +``` + +```python +>>> import numpy as np +>>> a = np.array([[1, 2], [3, 4]]) +>>> a +array([[1, 2], + [3, 4]]) +>>> b = np.mat(a) +>>> b +matrix([[1, 2], + [3, 4]]) +``` + +### 【1x02】numpy.asmatrix() + +`numpy.asmatrix()` 函数将输入数组转换为为矩阵。 + +基本语法:`numpy.asmatrix(data[, dtype=None])` + +| 参数 | 描述 | +| ------ | ------ | +| data | 输入数据,如果 data 为字符串,则需要用逗号或空格分隔列,用分号分隔行 | +| dtype | 输出矩阵的数据类型,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2], [3, 4]]) +>>> np.asmatrix(a) +matrix([[1, 2], + [3, 4]]) +``` + +### 【1x03】numpy.matrix() + +`numpy.matrix()` 函数从类似数组的对象或数据字符串中返回一个矩阵。 + +**注意:此函数已经不建议再使用,在未来的版本当中可能会被删除。** + +基本语法:`class numpy.matrix(data[, dtype=None, copy=True])` + +| 参数 | 描述 | +| ------ | ------ | +| data | 数组或者字符串,如果 data 为字符串,则需要用逗号或空格分隔列,用分号分隔行 | +| dtype | 输出矩阵的数据类型,可选项 | +| copy | 是否复制数据到一个新矩阵,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.matrix('1 2; 3 4') +>>> a +matrix([[1, 2], + [3, 4]]) +>>> +>>> b = np.matrix([[1, 2], [3, 4]]) +>>> b +matrix([[1, 2], + [3, 4]]) +``` + +### 【1x04】mat() / asmatrix() / matrix() 的区别 + +如果输入已经是一个矩阵或一个数组,则 `mat()` 和 `asmatrix()` 函数不会执行复制操作,相当于 `matrix(data, copy=False)` + +对比举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2], [3, 4]]) +>>> b = np.mat(a) +>>> c = np.matrix(a) +>>> d = np.asmatrix(a) +>>> +>>> a +array([[1, 2], + [3, 4]]) +>>> b +matrix([[1, 2], + [3, 4]]) +>>> c +matrix([[1, 2], + [3, 4]]) +>>> d +matrix([[1, 2], + [3, 4]]) +>>> +>>> a[1][1] = 0 +>>> +>>> a +array([[1, 2], + [3, 0]]) +>>> b +matrix([[1, 2], + [3, 0]]) +>>> c # matrix() 函数默认执行 copy 操作,所以数据不变 +matrix([[1, 2], + [3, 4]]) +>>> d +matrix([[1, 2], + [3, 0]]) +``` + +### 【1x05】numpy.bmat() + +`numpy.bmat()` 函数用于从字符串、嵌套序列或数组生成矩阵对象,一般用于创建复合矩阵。 + +基本语法:`numpy.bmat(obj[, ldict=None, gdict=None])` + +| 参数 | 描述 | +| ------ | ------ | +| obj | 数组或者字符串,如果 data 为字符串,则需要用逗号或空格分隔列,用分号分隔行 | +| ldict | 字典,用于替换当前帧中的本地操作数。如果 obj 不是字符串或 gdict 为 None,则将被忽略 | +| gdict | 字典,用于替换当前帧中的全局操作数。如果 obj 不是字符串则忽略 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.mat('1 1; 1 1') +>>> b = np.mat('2 2; 2 2') +>>> c = np.mat('3 4; 5 6') +>>> d = np.mat('7 8; 9 0') +>>> +>>> np.bmat([[a, b], [c, d]]) +matrix([[1, 1, 2, 2], + [1, 1, 2, 2], + [3, 4, 7, 8], + [5, 6, 9, 0]]) +>>> np.bmat(np.r_[np.c_[a, b], np.c_[c, d]]) +matrix([[1, 1, 2, 2], + [1, 1, 2, 2], + [3, 4, 7, 8], + [5, 6, 9, 0]]) +>>> np.bmat('a,b; c,d') +matrix([[1, 1, 2, 2], + [1, 1, 2, 2], + [3, 4, 7, 8], + [5, 6, 9, 0]]) +``` + +### 【1x06】numpy.matlib.empty() + +`numpy.matlib.empty()` 函数用于创建一个给定形状和数据类型的新矩阵。 + +基本语法:`numpy.matlib.empty(shape[, dtype=None, order='C'])` + +| 参数 | 描述 | +| ------ | ------ | +| shape | 定义新矩阵的形状 | +| dtype | 数据类型,可选项 | +| order | 以行优先(C)或列优先(Fortran)的顺序存储多维数据在内存中,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.matlib.empty((2, 2))) +[[9.90263869e+067 8.01304531e+262] + [2.60799828e-310 0.00000000e+000]] +>>> print(np.matlib.empty((2, 2), dtype=int)) +[[ -793016358 -243407933] + [ -959331519 -2060787213]] +``` + +### 【1x07】numpy.matlib.zeros() + +`numpy.matlib.zeros()` 函数创建一个以 0 填充的给定形状和类数据型的矩阵。 + +基本语法:`numpy.matlib.zeros(shape[, dtype=None, order='C'])` + + | 参数 | 描述 | +| ------ | ------ | +| shape | 定义新矩阵的形状 | +| dtype | 数据类型,可选项 | +| order | 以行优先(C)或列优先(Fortran)的顺序存储多维数据在内存中,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> np.matlib.zeros((2, 3)) +matrix([[0., 0., 0.], + [0., 0., 0.]]) +``` + +### 【1x08】numpy.matlib.ones() + +`numpy.matlib.ones()` 函数创建一个以 1 填充的给定形状和类数据型的矩阵。 + +基本语法:`numpy.matlib.ones(shape[, dtype=None, order='C'])` + + | 参数 | 描述 | +| ------ | ------ | +| shape | 定义新矩阵的形状 | +| dtype | 数据类型,可选项 | +| order | 以行优先(C)或列优先(Fortran)的顺序存储多维数据在内存中,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> np.matlib.ones((2, 3)) +matrix([[1., 1., 1.], + [1., 1., 1.]]) +``` + +### 【1x09】numpy.matlib.eye() + +`numpy.matlib.eye()` 函数创建一个对角线元素为 1,其他位置为零的矩阵。 + +基本语法:`numpy.matlib.eye(n[, M=None, k=0, dtype=, order='C'])` + +| 参数 | 描述 | +| ------ | ------ | +| n | 返回的矩阵的行数,int 类型 | +| M | 返回的矩阵的列数,int 类型,可选项,默认为 n | +| k | 对角线索引,可选项,0 表示主对角线,正值表示上对角线,负值表示下对角线,该对角线上元素的值将会是 1 | +| dtype | 返回矩阵的数据类型,可选项 | +| order | 以行优先(C)或列优先(Fortran)的顺序存储多维数据在内存中,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.matlib.eye(n=3, k=1)) +[[0. 1. 0.] + [0. 0. 1.] + [0. 0. 0.]] +>>> print(np.matlib.eye(n=3, k=-1)) +[[0. 0. 0.] + [1. 0. 0.] + [0. 1. 0.]] +>>> print(np.matlib.eye(n=3, M=4, k=0, dtype=int)) +[[1 0 0 0] + [0 1 0 0] + [0 0 1 0]] +``` + +### 【1x10】numpy.matlib.identity() + +`numpy.matlib.identity()` 函数创建一个给定大小的单位矩阵。 + +单位矩阵:在矩阵的乘法中,有一种矩阵起着特殊的作用,如同数的乘法中的1,这种矩阵被称为单位矩阵。它是个方阵,从左上角到右下角的对角线(称为主对角线)上的元素均为1。除此以外全都为0。 + +基本语法:`numpy.matlib.identity(n[, dtype=None])` + +| 参数 | 描述 | +| ------ | ------ | +| n | 返回的单位矩阵的大小,int 类型 | +| dtype | 可选项,返回的单位矩阵的数据类型 | + +应用举例: + +```python +>>> import numpy as np +>>> print(np.matlib.identity(3, dtype=int)) +[[1 0 0] + [0 1 0] + [0 0 1]] +``` + +### 【1x11】numpy.matlib.repmat() + +`numpy.matlib.repmat()` 函数用于重复数组或矩阵 m*n 次。 + +基本语法:`numpy.matlib.repmat(a, m, n)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 待处理的数组对象 | +| m,n | 沿第一轴和第二轴重复的次数 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array(1) +>>> b = np.arange(4) +>>> a +array(1) +>>> b +array([0, 1, 2, 3]) +>>> +>>> print(np.matlib.repmat(a, 2, 3)) +[[1 1 1] + [1 1 1]] +>>> print(np.matlib.repmat(b, 2, 2)) +[[0 1 2 3 0 1 2 3] + [0 1 2 3 0 1 2 3]] +``` + +### 【1x12】numpy.matlib.rand() + +`numpy.matlib.rand()` 函数创建一个给定大小的矩阵,其中的数据在 `[0, 1)` 区间随机取值来填充。 + +基本语法:`numpy.matlib.rand(*args)` + +参数解释:`*args`:输出矩阵的形状,如果给定为 N 个整数,则每个整数指定一维的大小,如果以元组形式给出,则该元组表示输出矩阵完整的形状。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.matlib.rand(2, 3)) +[[0.27957871 0.48748368 0.0970184 ] + [0.71062224 0.92503824 0.72415015]] +>>> +>>> print(np.matlib.rand((2, 3))) +[[0.08814715 0.0307317 0.77775332] + [0.81158748 0.09173265 0.77497881]] +>>> +>>> print(np.matlib.rand(2, 3), 4) # 如果第一个参数是元组,则其他参数将被忽略 +[[0.53407924 0.56006372 0.63903716] + [0.56132381 0.90300814 0.44074964]] 4 +``` + +### 【1x13】numpy.matlib.randn() + +`numpy.matlib.randn()` 函数创建一个标准正态分布的随机矩阵。 + +标准正态分布,是一个在数学、物理及工程等领域都非常重要的概率分布,在统计学的许多方面有着重大的影响力。期望值`μ=0`,即曲线图象对称轴为Y轴,标准差 `σ=1` 条件下的正态分布,记为 `N(0,1)`。 + +标准正态分布又称为 u 分布,是以 0 为均数、以 1 为标准差的正态分布,记为 `N(0,1)` + +基本语法:`numpy.matlib.randn(*args)` + +参数解释:`*args`:输出矩阵的形状,如果给定为 N 个整数,则每个整数指定一维的大小,如果以元组形式给出,则该元组表示输出矩阵完整的形状。 + +应用举例: + +```python +>>> import numpy as np +>>> print(np.matlib.randn(2, 3)) +[[ 0.82976978 -0.9798698 0.71262414] + [ 2.31211127 -0.5090537 1.12357032]] +>>> +>>> print(2.5 * np.matlib.randn((2, 4)) + 3) # 2 x 4 矩阵 N(3, 6.25) +[[-0.66974538 4.9354863 2.46138048 7.05576713] + [ 0.80688217 1.79017491 3.78979646 -1.99071372]] +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105511641 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【2x00】NumPy 线性代数库 + +线性代数是数学的一个分支,它的研究对象是向量,向量空间(或称线性空间),线性变换和有限维的线性方程组。NumPy 中也提供了线性代数函数库 `numpy.linalg`。 + +官方文档介绍:[https://numpy.org/doc/1.18/reference/routines.linalg.html](https://numpy.org/doc/1.18/reference/routines.linalg.html) + +### 【2x01】numpy.dot() + +`numpy.dot()` 函数用于计算两个数组的点积。 + +基本语法:`numpy.dot(a, b[, out=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 第一个数组 | +| b | 第二个数组 | +| out | 可选项,放置结果的备用输出数组 | + +- 如果 a 和 b 均为一维数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积); +- 如果 a 和 b 均为二维数组,计算的是两个数组的矩阵乘积; +- 如果 a 和 b 均为多维数组,它的通用计算公式为:`dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])`,即结果数组中的每个元素都是数组 a 的最后一维上的所有元素与数组 b 的倒数第二维上的所有元素的乘积和。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4]]) +>>> b = np.array([[11,12],[13,14]]) +>>> print(np.dot(a,b)) # [[1*11+2*13, 1*12+2*14],[3*11+4*13, 3*12+4*14]] +[[37 40] + [85 92]] +>>> +>>> c = np.arange(3*4*5*6).reshape((3,4,5,6)) +>>> d = np.arange(3*4*5*6)[::-1].reshape((5,4,6,3)) +>>> print(np.dot(c, d)[2,3,2,1,2,2]) +499128 +>>> print(sum(c[2,3,2,:] * d[1,2,:,2])) +499128 +``` + +### 【2x02】numpy.vdot() + +`numpy.vdot()` 函数返回两个向量的点积,如果第一个参数是复数,那么它的共轭复数会用于计算。 如果参数是多维数组,它会被展开。 + +共轭复数:两个实部相等,虚部互为相反数的复数互为共轭复数。 + +基本语法:`numpy.vdot(a, b)` + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1+2j, 3+4j]) +>>> b = np.array([5+6j, 7+8j]) +>>> print(np.vdot(a, b)) # a 的共轭复数用于计算:(1-2j) * (5+6j) + (3-4j) * (7+8j) +(70-8j) +>>> print(np.vdot(b, a)) # b 的共轭复数用于计算:(1+2j) * (5-6j) + (3+4j) * (7-8j) +(70+8j) +>>> +>>> +>>> c = np.array([[1, 4], [5, 6]]) +>>> d = np.array([[4, 1], [2, 2]]) +>>> print(np.vdot(c, d)) # 1*4 + 4*1 + 5*2 + 6*2 +30 +``` + +### 【2x03】numpy.inner() + +`numpy.inner()` 函数计算一维数组的点积,对于其他维度,返回最后一个轴上的和的乘积。 + +基本语法:`numpy.inner(a, b)` + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2],[3,4]]) +>>> b = np.array([[11,12],[13,14]]) +>>> print(np.inner(a,b)) # [[1*11+2*12, 1*13+2*14], [3*11+4*12, 3*13+4*14]] +[[35 41] + [81 95]] +>>> +>>> +>>> c = np.array([1,2,3]) +>>> d = np.array([0,1,0]) +>>> print(np.inner(c,d)) # 1*0+2*1+3*0 +2 +``` + +### 【2x04】numpy.outer() + +`numpy.outer()` 函数计算两个向量的外积。 + +基本语法:`numpy.outer(a, b[, out=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a | 第一个向量,如果不是一维的则在计算前会将其展平 | +| b | 第一个向量,如果不是一维的则在计算前会将其展平 | +| out | 结果存储的位置,可选项,类似于 (M, N) 结构的 Ndarray 对象 | + +外积一般指两个向量的向量积,若两向量:`a = [a0, a1, ..., aM]` `b = [b0, b1, ..., bN]`,外积如下: + +``` +[[a0*b0 a0*b1 ... a0*bN ] + [a1*b0 . + [ ... . + [aM*b0 aM*bN ]] +``` + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1, 2, 3, 4]) +>>> b = np.array([5, 6, 7, 8]) +>>> print(np.outer(a, b)) +[[ 5 6 7 8] + [10 12 14 16] + [15 18 21 24] + [20 24 28 32]] +>>> +>>> c = np.array(['a', 'b', 'c'], dtype=object) +>>> print(np.outer(c, [1, 2, 3])) +[['a' 'aa' 'aaa'] + ['b' 'bb' 'bbb'] + ['c' 'cc' 'ccc']] +``` + +### 【2x05】numpy.matmul() + +`numpy.matmul()` 函数计算两个矩阵的乘积。 + +矩阵的乘积运算: + +设 A 为 `m x p` 的矩阵,B 为 `p x n` 的矩阵,那么称 `m x n` 的矩阵 C 为矩阵 A 与 B 的乘积,记作 C = AB,其中矩阵 C 中的第 i 行第 j 列元素可以表示为: + +$$ (AB)_{ij} = \sum_{k=1}^p a_{ik}b_{kj} = a_{i1}b_{1j} + a_{i2}b_{2j} + ... + a_{ip}b_{pj} $$ + +--- + +$$ +A = +\left[ +\begin{matrix} +a_{1,1} & a_{1,2} & a_{1,3} \\ +a_{2,1} & a_{2,2} & a_{2,3} +\end{matrix} +\right] +\qquad\qquad\qquad\qquad\qquad\qquad B = +\left[ +\begin{matrix} +b_{1,1} & b_{1,2} \\ +b_{2,1} & b_{2,2} \\ +b_{3,1} & b_{3,2} +\end{matrix} +\right] +$$ + +$$ +C = AB = +\left[ +\begin{matrix} +a_{1,1}b_{1,1} & a_{1,2}b_{2,1} & a_{1,3}b_{3,1}, & a_{1,1}b_{1,2} & a_{1,2}b_{2,2} & a_{1,3}b_{3,2} \\ +a_{2,1}b_{1,1} & a_{2,2}b_{2,1} & a_{2,3}b_{3,1}, & a_{2,1}b_{1,2} & a_{2,2}b_{2,2} & a_{2,3}b_{3,2} +\end{matrix} +\right] +$$ + +--- + +矩阵相乘的条件: + +- 当矩阵 A 的列数(column)等于矩阵 B 的行数(row)时,A 与 B 可以相乘; +- 矩阵 C 的行数等于矩阵 A 的行数,C 的列数等于 B 的列数; +- 乘积 C 的第 m 行第 n 列的元素等于矩阵 A 的第 m 行的元素与矩阵 B 的第 n 列对应元素乘积之和。 + +--- + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,0], [0,1]]) +>>> b = np.array([[4,1], [2,2]]) +>>> print(np.matmul(a, b)) +[[4 1] + [2 2]] +>>> +>>> c = np.array([[1,0], [0,1]]) +>>> d = np.array([1,2]) +>>> print(np.matmul(c, d)) +[1 2] +>>> print(np.matmul(d, c)) +[1 2] +>>> +>>> e = np.arange(8).reshape(2,2,2) +>>> f = np.arange(4).reshape(2,2) +>>> print(np.matmul(e, f)) +[[[ 2 3] + [ 6 11]] + + [[10 19] + [14 27]]] +``` + +### 【2x06】numpy.tensordot() + +`numpy.tensordot()` 函数计算两个不同维度矩阵的乘积。 + +基本语法:`numpy.tensordot(a, b, axes=2)` + +| 参数 | 描述 | +| ------ | ------ | +| a | 第一个矩阵 | +| b | 第二个矩阵 | +| axis | 指定收缩的轴
如果是一个整型 m,表示指定数组 a 的后 m 个轴和数组 b 的前 m 个轴分别进行内积,即对应位置元素相乘、再整体求和
如果是一个列表 [m, n],那么表示 a 的第 m+1 个 (索引为m) 轴和 b 的第 n+1 (索引为n) 个轴进行内积 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.random.randint(0, 9, (3, 4)) +>>> b = np.random.randint(0, 9, (4, 5)) +>>> a +array([[4, 0, 3, 6], + [1, 3, 2, 2], + [6, 1, 3, 4]]) +>>> b +array([[1, 0, 0, 7, 6], + [3, 8, 7, 5, 0], + [4, 7, 0, 8, 0], + [3, 8, 5, 0, 1]]) +>>> print(np.tensordot(a, b, 1)) +[[34 69 30 52 30] + [24 54 31 38 8] + [33 61 27 71 40]] +>>> +>>> c = np.array(range(1, 9)).reshape(2, 2, 2) +>>> d = np.array(('a', 'b', 'c', 'd'), dtype=object).reshape(2, 2) +>>> c +array([[[1, 2], + [3, 4]], + + [[5, 6], + [7, 8]]]) +>>> d +array([['a', 'b'], + ['c', 'd']], dtype=object) +>>> print(np.tensordot(c, d)) +['abbcccdddd' 'aaaaabbbbbbcccccccdddddddd'] +``` + +### 【2x07】numpy.linalg.det() + +`numpy.linalg.det()` 函数计算矩阵的行列式。 + +阵行列式是指矩阵的全部元素构成的行列式,设 A=(aij) 是数域 P 上的一个 n 阶矩阵,则所有 A=(aij) 中的元素组成的行列式称为矩阵 A 的行列式,记为 `|A|` 或 `det(A)` + +一个 2×2 矩阵的行列式可表示如下: + +$$ det = \left[ \begin{matrix} a & b \\ c & d \end{matrix} \right] = ad - bc $$ + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2], [3, 4]]) +>>> print(np.linalg.det(a)) +-2.0000000000000004 +``` + +### 【2x08】numpy.linalg.solve() + +`numpy.linalg.solve()` 函数求解线性矩阵方程或线性标量方程组。 + +--- + +$$ +\left \{ +\begin{aligned} +3x+y=9 \\ +x+2y=8 +\end{aligned} +\right. +\qquad用矩阵可表示为:\qquad +\left[ +\begin{matrix} +3 & 1 \\ +1 & 2 +\end{matrix} +\right] +\left[ +\begin{matrix} +x & y +\end{matrix} +\right] += \left[ +\begin{matrix} +9 & 8 +\end{matrix} +\right] +$$ + +--- + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[3,1], [1,2]]) +>>> b = np.array([9,8]) +>>> print(np.linalg.solve(a, b)) +[2. 3.] +``` + +### 【2x09】numpy.linalg.inv() + +`numpy.linalg.inv()` 函数计算矩阵的逆矩阵。 + +设 A 是数域上的一个 n 阶矩阵,若在相同数域上存在另一个 n 阶矩阵 B,使得:AB = BA = E,则我们称 B 是 A 的逆矩阵,而 A 则被称为可逆矩阵。注:E 为单位矩阵。 + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1, 2], [3, 4]]) +>>> b = np.linalg.inv(a) +>>> print(b) +[[-2. 1. ] + [ 1.5 -0.5]] +>>> +>>> a * b == b * a +array([[ True, True], + [ True, True]]) +``` + +## 【3x00】NumPy IO 操作 + +NumPy IO 操作即读写磁盘上的文本数据或二进制数据,在 NumPy 中有专门的 `.npy` / `npy` 文件,`.npy` 文件用于储存单个 Ndarray 对象;`.npz` 文件用于储存多个 Ndarray 对象。 + +### 【3x01】numpy.save() + +`numpy.save()` 函数将数组保存到二进制文件(`.npy` 文件)中。 + +基本语法:`numpy.save(file, arr[, allow_pickle=True, fix_imports=True])` + +| 参数 | 描述 | +| ------ | ------ | +| file | 要保存的文件名,可以带路径,文件后缀为 `.npy`,若路径末尾没有后缀,则会默认加上 `.npy` 后缀 | +| arr | 要保存的数组 | +| allow_pickle | bool 值,可选项,是否允许使用 Python pickle 保存数组对象
Python pickle 用于在保存到磁盘文件或从磁盘文件读取之前,对对象进行序列化和反序列化
pickle 序列化后的数据,可读性差,人一般无法识别 | +| fix_imports | bool 值,可选项,强制以 Python 2 兼容方式对 Python 3 上的数组对象进行处理
如果 fix_imports 为True,则 pickle 将尝试将新的 Python 3 名称映射到 Python 2 中使用的旧模块名称,以便 pickle 数据流可被 Python 2 读取 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2,3], [4,5,6]]) +>>> np.save('D:\\file\\outfile.npy', a) +``` + +### 【3x02】numpy.load() + +`numpy.load()` 函数用于读取 `.npy` / `npz` 文件里面的内容。 + +基本语法:`numpy.load(file[, mmap_mode=None, allow_pickle=False, fix_imports=True, encoding='ASCII'])` + +| 参数 | 描述 | +| ------ | ------ | +| file | 要读取的 `npy` 文件对象 | +| mmap_mode | 可选项,读取文件的模式,可选参数 `r+` `r` `w+` `c`,与 Python 读取文件模式类似,模式含义参见 [numpy.memmap](https://numpy.org/doc/1.18/reference/generated/numpy.memmap.html) | +| allow_pickle | bool 值,可选项,是否允许使用 Python pickle 保存数组对象
Python pickle 用于在保存到磁盘文件或从磁盘文件读取之前,对对象进行序列化和反序列化
pickle 序列化后的数据,可读性差,人一般无法识别 | +| fix_imports | bool 值,可选项,强制以 Python 2 兼容方式对 Python 3 上的数组对象进行处理
如果 fix_imports 为True,则 pickle 将尝试将新的 Python 3 名称映射到 Python 2 中使用的旧模块名称,以便 pickle 数据流可被 Python 2 读取 | +| encoding | str 类型,可选项,读取 Python2 字符串时使用什么编码
仅当在 Python3 中加载 Python 2 生成的 pickled 文件(包括包含对象数组的 npy/npz 文件)时才有用
不允许使用 `latin1`、`ASCII` 和 `bytes` 以外的值,因为它们可能损坏数字数据。默认值为 `ASCII` | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2,3], [4,5,6]]) +>>> np.save('D:\\file\\outfile.npy', a) +>>> np.load('D:\\file\\outfile.npy') +array([[1, 2, 3], + [4, 5, 6]]) +``` + +### 【3x03】numpy.savez() + +`numpy.savez()` 函数将多个数组保存到二进制文件(`.npz` 文件)中。 + +基本语法:`numpy.savez(file, *args[, **kwds])` + +| 参数 | 描述 | +| ------ | ------ | +| file | 要保存的文件名,可以带路径,文件后缀为 `.npz`,若路径末尾没有后缀,则会默认加上 `.npz` 后缀 | +| args | 保存的数组,由于 Python 不知道外面 savez 的数组的名称,因此将使用 `arr_0`,`arr_1` 等名称保存数组,这些参数可以是任何表达式 | +| kwds | 关键字参数,可选项,数组将与关键字名称一起保存在文件中 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([[1,2,3],[4,5,6]]) +>>> b = np.arange(0, 1.0, 0.1) +>>> c = np.sin(b) # c 使用关键字参数 sin_array +>>> np.savez('D:\\file\\outfile.npz', a, b, sin_array=c) +>>> r = np.load('D:\\file\\outfile.npz') +>>> print(r.files) # 查看各个数组名称 +['sin_array', 'arr_0', 'arr_1'] +>>> +>>> print(r['arr_0']) # 数组 a +[[1 2 3] + [4 5 6]] +>>> +>>> print(r['arr_1']) # 数组 b +[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9] +>>> +>>> print(r['sin_array']) # 数组 c +[0. 0.09983342 0.19866933 0.29552021 0.38941834 0.47942554 + 0.56464247 0.64421769 0.71735609 0.78332691] +``` + +### 【3x04】numpy.savetxt() + +`numpy.savetxt()` 函数将数组保存到文本文件中(txt)。 + +基本语法:`numpy.savetxt(fname, X[, fmt='%.18e', delimiter=' ', newline='n', header='', footer='', comments='# ', encoding=None])` + +| 参数 | 描述 | +| ------ | ------ | +| fname | 要保存的文件名,可以带路径,如果文件后缀为 `.gz`,则文件将自动以压缩格式 `gzip` 保存 | +| X | 要保存的数组 | +| fmt | 格式序列或多格式字符串,可选项 | +| delimiter | 指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等,可选项 | +| newline | 字符串或字符分隔线,可选项 | +| header | 写入文件开头的字符串,可选项 | +| footer | 写入文件末尾的字符串,可选项 | +| comments | 注释,在 header 和 footer 字符串之前添加的字符串,可选项 | +| encoding | 对输出文件进行编码,可选项 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1,2,3,4,5]) +>>> np.savetxt('D:\\file\\outfile.txt', a) +>>> np.loadtxt('D:\\file\\outfile.txt') +array([1., 2., 3., 4., 5.]) +>>> +>>> b = np.arange(0,10,0.5).reshape(4,-1) +>>> np.savetxt('D:\\file\\outfile2.txt', b, fmt="%d", delimiter=',') # 保存为整数,以逗号分隔 +>>> np.loadtxt('D:\\file\\outfile2.txt', delimiter=',') # 读取数据时也要指定相同的分隔符 +array([[0., 0., 1., 1., 2.], + [2., 3., 3., 4., 4.], + [5., 5., 6., 6., 7.], + [7., 8., 8., 9., 9.]]) +``` + +### 【3x05】numpy.loadtxt() + +`numpy.loadtxt()` 函数用于读取文本文件(txt)里面的内容。 + +基本语法:`numpy.loadtxt(fname[, dtype=, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0, encoding='bytes', max_rows=None])` + +重要参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| fname | 要读取的文件,文件名或生成器。如果文件扩展名是 `.gz` 或 `.bz2`,则首先将文件解压缩,注意,生成器应返回字节字符串 | +| dtype | 可选项,结果数组的数据类型 | +| comments | str 或 str 序列,可选项,用于指示注释开始的字符或字符列表 | +| delimiter | str 类型,可选项,指定分隔符 | +| skiprows | int 类型,可选项,跳过前 n 行,一般用于跳过第一行表头 | +| usecols | int 类型的索引值,读取指定的列 | +| unpack | bool 值,可选项,如果为True,则会对返回的数组进行转置 | +| ndmin | int 类型,可选项,返回的数组将至少具有 ndmin 维度,否则一维轴将被压缩 | +| encoding | str 类型,可选项,用于解码输入文件的编码 | +| max_rows | int 类型,可选项,读取 skiprows 行之后的最大行内容。默认值是读取所有行 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1,2,3,4,5]) +>>> np.savetxt('D:\\file\\outfile.txt', a) +>>> np.loadtxt('D:\\file\\outfile.txt') +array([1., 2., 3., 4., 5.]) +``` + +### 【3x06】numpy.genfromtxt() + +`numpy.genfromtxt()` 函数同样用于读取文本文件(txt)里面的内容。该函数比 `loadtxt()` 函数功能更加强大,`genfromtxt()` 主要面向结构数组和缺失数据处理。 + +官方文档介绍:[https://numpy.org/doc/1.18/reference/generated/numpy.genfromtxt.html](https://numpy.org/doc/1.18/reference/generated/numpy.genfromtxt.html) + +推荐文章:[https://www.cnblogs.com/Simplelee/p/8975763.html](https://www.cnblogs.com/Simplelee/p/8975763.html) + +主要语法:`numpy.genfromtxt(fname[, dtype=, comments='#', delimiter=None, skip_header=0, skip_footer=0, converters=None, missing_values=None, filling_values=None, usecols=None, encoding='bytes'])` + +主要参数解释: + +| 参数 | 描述 | +| ------ | ------ | +| fname | 要读取的文件,文件名或生成器。如果文件扩展名是 `.gz` 或 `.bz2`,则首先将文件解压缩,注意,生成器应返回字节字符串 | +| dtype | 可选项,结果数组的数据类型 | +| comments | str 或 str 序列,可选项,用于指示注释开始的字符或字符列表 | +| delimiter | str 类型,可选项,指定分隔符 | +| skip_header | int 类型,可选项,文件开头要跳过的行数 | +| skip_footer | int 类型,可选项,文件末尾要跳过的行数 | +| converters | 变量,可选项,将列的数据转换为值的一组函数
还可以为丢失的数据提供默认值:`converters = {3: lambda s: float(s or 0)}` | +| missing_values | 变量,可选项,与缺少的数据相对应的字符串集,默认情况下使用空格表示缺失 | +| filling_values | 变量,可选项,缺少数据时用作默认值的一组值 | +| usecols | 序列,可选项,读取指定的列 | +| encoding | str 类型,可选项,用于解码输入文件的编码 | + +应用举例: + +```python +>>> import numpy as np +>>> a = np.array([1,2,3,4,5]) +>>> np.savetxt('D:\\file\\outfile.txt', a) +>>> np.genfromtxt('D:\\file\\outfile.txt') +array([1., 2., 3., 4., 5.]) +>>> +>>> b = np.arange(0,10,0.5).reshape(4,-1) +>>> np.savetxt('D:\\file\\outfile2.txt', b, fmt="%d", delimiter=",") +>>> np.genfromtxt('D:\\file\\outfile2.txt', delimiter=',') +array([[0., 0., 1., 1., 2.], + [2., 3., 3., 4., 4.], + [5., 5., 6., 6., 7.], + [7., 8., 8., 9., 9.]]) +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105511641 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A68-Matplotlib-01.md b/source/_posts/A68-Matplotlib-01.md new file mode 100644 index 0000000000000000000000000000000000000000..1b8b696f0ac74a29796775eb069a6741d3df2595 --- /dev/null +++ b/source/_posts/A68-Matplotlib-01.md @@ -0,0 +1,347 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 +tags: + - Matplotlib + - matplotibrc +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(一):认识 Matplotlib 相关概念,了解其 matplotibrc 基本配置文件。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105638122 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】认识 Matplotlib + +Matplotlib 是建立在 NumPy 数组基础上的多平台数据可视化程序库,用于在 Python 中绘制数组的 2D 图形库,最初被设计用于完善 SciPy 的生态环境,虽然它起源于模仿 Matlab 图形命令,但它独立于 Matlab,可以以 Pythonic 和面向对象的方式使用。虽然 Matplotlib 主要是在纯 Python 中编写的,但它大量使用 NumPy 和其他扩展代码,即使对于大型数组也能提供良好的性能。它与 NumPy 一起使用,提供了一种有效的 Matlab 开源替代方案。 它也可以和图形工具包一起使用,如 PyQt 和 wxPython。Matplotlib 最重要的特性之一就是具有良好的操作系统兼容性和图形显示底层接口兼容性。 + +### 【1x01】简单示例 + +```python +>>> import matplotlib.pyplot as plt +>>> x = range(2, 26, 2) # 数据在 x 轴的位置,是一个可迭代对象 +>>> y = range(0, 12) # 数据在 y 轴的位置,是一个可迭代对象 +>>> plt.plot(x, y) # 绘制线形图 +[] +>>> plt.show() +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A68/01.png) + +### 【1x02】图像结构 + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A68/02.png) + +### 【1x03】三层结构 + +Matplotlib 三层结构:容器层、辅助显示层、图像层 + +
容器层
+ +容器层主要由 Canvas、Figure、Axes 组成。 +- Canvas 是位于最底层的系统层,在绘图的过程中充当画板的角色,即放置画布(Figure)的工具。 +- Figure 是 Canvas 上方的第一层,也是需要用户来操作的应用层的第一层,在绘图的过程中充当画布的角色,可以通过 plt.figure() 设置画布的大小和分辨率等 +- Axes 是应用层的第二层,在绘图的过程中相当于画布上的绘图区的角色,注意与 Axis 的区别,Axis 是坐标轴,包含大小限制、刻度和刻度标签。 + +注意点: + +- 一个figure(画布)可以包含多个axes(坐标系/绘图区),但是一个 axes 只能属于一个figure。 +- 一个axes(坐标系/绘图区)可以包含多个axis(坐标轴),包含两个即为 2d 坐标系,三个即为 3d 坐标系 。 + +
辅助显示层
+ +辅助显示层为 Axes(绘图区)内的除了根据数据绘制出的图像以外的内容,主要包括 Axes 外观(facecolor)、边框线(spines)、坐标轴(axis)、坐标轴名称(axis label)、坐标轴刻度(tick)、坐标轴刻度标签(tick label)、网格线(grid)、图例(legend)、标题(title)等内容。该层的设置可使图像显示更加直观更加容易被用户理解,但又不会对图像产生实质的影响。 + +
图像层
+ +图像层指 Axes 内通过 plot(线形图)、scatter(散点图)、bar(柱状图)、histogram(直方图)、pie(饼图) 等函数根据数据绘制出的图像。 + +
三者关系总结
+ +- Canvas(画板)位于最底层,用户一般接触不到; +- Figure(画布)建立在 Canvas 之上; +- Axes(绘图区)建立在Figure之上; +- 坐标轴(axis)、图例(legend)等辅助显示层以及图像层都是建立在 Axes 之上。 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105638122 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【2x00】了解 matplotlib.rcParams + +`matplotlib` 使用 `matplotlibrc` 配置文件来自定义图形的各种默认属性,称之为 `rc` 配置或 `rc` 参数。通过 `rc` 参数可以修改默认的属性,包括窗体大小、每英寸的点数、线条宽度、颜色、样式、坐标轴、坐标和网络属性、文本、字体等。`rc` 参数存储在字典变量中,通过字典的方式进行访问。 + +执行 `matplotlib.rcParams.keys()` 命令可以查看所有的 rc 参数及其默认值; +执行 `matplotlib.matplotlib_fname()` 命令可以查看 `matplotlibrc` 配置文件在本地的路径。 + +官网介绍:[https://matplotlib.org/tutorials/introductory/customizing.html](https://matplotlib.org/tutorials/introductory/customizing.html) + + +配置文件 matplotibrc 主要包括以下配置要素: + +- **axes**:坐标轴的背景颜色、坐标轴的边缘颜色、刻度线的大小、刻度标签的字体大小等; +- **figure**:画布标题大小、画布标题粗细、画布像素(dpi)、 画布背景颜色和边缘颜色等; +- **font**:字体类别、字体风格、字体粗细和字体大小等; +- **grid**:网格颜色、网格线条风格、网格线条宽度和网格透明度; +- **legend**:图例的文本大小、阴影、图例线框风格等; +- **lines**:设置线条属性,包括颜色、线条风格、线条宽度和标记风格等; +- **patch**:填充 2D 空间的图形对象,包括多边形和圆; +- **savefig**:保存画布图像的分辨率、背景颜色和边缘颜色等; +- **text**:文本颜色、LaTex 渲染文本等; +- **xtick / ytick**:x 轴和 y 轴的主次要刻度线的大小、宽度、刻度线颜色和刻度标签大小等。 + +--- + +**我们可以在 Python 项目中动态设置 `rc` 参数,所有 `rc` 参数设置都存储在名为 `matplotlib.rcParams` 的类似于字典的变量中,该变量对于 Matplotlib 软件包是全局的。`rcParams` 可以直接修改。通过这种方法的修改会对全局产生影响,在 Matplotlib 的其他方法中也可以单独对某个参数进行修改,后续介绍不同方法时会见到。** + +--- + +`rcParams` 修改示例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 定义全局字体 +plt.rcParams['xtick.color'] = 'red' # 定义 x 轴刻度颜色 +plt.rcParams['lines.marker'] = 'o' # 定义线条上点的形状 +plt.rcParams['legend.loc'] = 'upper left' # 定义图例在左上角 + +x = range(2, 26, 2) +y = range(0, 12) +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +plt.title('This is a title / 这是标题') +plt.xlabel('这是 x 轴标题') +plt.ylabel('这是 y 轴标题') +plt.grid(True) +plt.plot(x, y) +plt.plot(a, b) +plt.legend(['图例一', '图例二']) + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A68/03.png) + +--- + +### 【2x01】axes 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`axes.axisbelow`'] = 'line' | 网格线和刻度的位置 | `line`:在画板上方,在线条下方
`False`:在线条和画板的上方
`True`:在画板下方 | +| mpl.rcParams['`axes.edgecolor`'] = 'black' | 轴边缘颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`axes.facecolor`'] = 'white' | 轴背景色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`axes.labelcolor`'] = 'black' | 轴标题颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`axes.grid`'] = False | 是否显示网格 | `False`:不显示网格;`True`:显示网格 | +| mpl.rcParams['`axes.grid.axis`'] = 'both' | 网格应用于哪个轴 | `x`:x 轴;`y`:y 轴;`both`:同时应用于两个轴 | +| mpl.rcParams['`axes.grid.which`'] = 'major' | 网格应用于哪个刻度 | `major`:主(大)刻度;`minor`:次(小刻度);
`both`:同时应用于两个刻度 | +| mpl.rcParams['`axes.labelpad`'] = 4.0 | 轴标题和轴之间的间距 | float 类型间距值 | +| mpl.rcParams['`axes.labelsize`'] = 'medium' | x 轴和 y 轴标题的字体大小 | `xx-small`, `x-small`, `small`, `medium`
`large`, `x-large`, `xx-large`, `smaller`, `larger`
也可以使用数字来表示字体大小 | +| mpl.rcParams['`axes.labelweight`'] = 'normal' | x 轴和 y 轴标题的字体粗细 | `normal`:正常粗细;`bold`:粗体;`light`:细体
数字值 `400` 等价于 `normal`,`700` 等价于 `bold` | +| mpl.rcParams['`axes.linewidth`'] = 0.8 | 轴边线宽度 | float 类型宽度值 | +| mpl.rcParams['`axes.titlecolor`'] = 'auto' | 图表标题颜色 | 默认取 `text.color` 的值
其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`axes.titlelocation`'] = 'center' | 图表标题位置 | `left`:左;`right`:右;`center`:中间 | +| mpl.rcParams['`axes.titlepad`'] = 6.0 | 图表标题和轴之间的间距 | float 类型间距值 | +| mpl.rcParams['`axes.titlesize`'] = 'large' | 图表标题字体大小 | `xx-small`, `x-small`, `small`, `medium`
`large`, `x-large`, `xx-large`, `smaller`, `larger`
也可以使用数字来表示字体大小 | +| mpl.rcParams['`axes.titleweight`'] = 'normal' | 图表标题字体粗细 | `normal`:正常粗细;`bold`:粗体;`light`:细体
数字值 `400` 等价于 `normal`,`700` 等价于 `bold` | +| mpl.rcParams['`axes.xmargin`'] = 0.05 | x 轴边距 | 取值范围 `[0, 1]` | +| mpl.rcParams['`axes.ymargin`'] = 0.05 | y 轴边距 | 取值范围 `[0, 1]` | +| mpl.rcParams['`axes.unicode_minus`'] = True | 对负号使用 Unicode 而不是连字符 | `True`:是;`False`:否 | +| mpl.rcParams['`axes3d.grid`'] = True | 是否在三维轴上显示网格 | `True`:是;`False`:否 | + +### 【2x02】figure 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`figure.dpi`'] = 100 | 画布像素(dpi) | float 类型像素值 | +| mpl.rcParams['`figure.edgecolor`'] = 'white' | 画布边缘颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`figure.facecolor`'] = 'white' | 画布背景颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`figure.figsize`'] = [6.4, 4.8] | 画布尺寸 `[长, 宽]` | float 类型尺寸值(英寸) | +| mpl.rcParams['`figure.frameon`'] = True | 是否启用图框 | `True`:是;`False`:否 | +| mpl.rcParams['`figure.titlesize`'] = 'large' | 画布标题大小 | `xx-small`, `x-small`, `small`, `medium`
`large`, `x-large`, `xx-large`, `smaller`, `larger`
也可以使用数字来表示字体大小 | +| mpl.rcParams['`figure.titleweight`'] = 'normal' | 画布标题粗细 | `normal`:正常粗细;`bold`:粗体;`light`:细体
数字值 `400` 等价于 `normal`,`700` 等价于 `bold` | + +### 【2x03】font 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`font.family`'] = ['sans-serif'] | 规定字体系列 | 字体名称 | +| mpl.rcParams['`font.sans-serif`'] = ['DejaVu Sans, ......'] | 定义无衬线字体 | 默认是一些西文字体,可将其设置成其他字体来显示中文 | +| mpl.rcParams['`font.serif`'] = ['DejaVu Sans, ......'] | 定义有衬线字体 | 默认是一些西文字体,可将其设置成其他字体来显示中文 | +| mpl.rcParams['`font.size`'] = 10.0 | 定义字体大小 | float 数字类型字体大小 | +| mpl.rcParams['`font.weight`'] = 'normal' | 定义字体粗细 | `normal`:正常粗细;`bold`:粗体;`light`:细体
数字值 `400` 等价于 `normal`,`700` 等价于 `bold` | + +### 【2x04】grid 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`grid.alpha`'] = 1.0 | 网格透明度 | float 类型,取值范围:`[0, 1]` | +| mpl.rcParams['`grid.color`'] = '#b0b0b0' | 网格颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`grid.linestyle`'] = '-' | 网格线的样式 | `'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'`
`':'` or `'dotted'`, `'none'` or `' '` or `''` | +| mpl.rcParams['`grid.linewidth`'] = 0.8 | 网格宽度 | float 类型宽度值 | + +### 【2x05】legend 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`legend.borderaxespad`'] = 0.5 | 图例距离轴之间的距离 | float 类型距离值 | +| mpl.rcParams['`legend.borderpad`'] = 0.4 | 图例边框空白区域大小 | float 类型大小值 | +| mpl.rcParams['`legend.columnspacing`'] = 2.0 | 图例列间距 | float 类型距离值 | +| mpl.rcParams['`legend.edgecolor`'] = 0.8 | 图例边缘线颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`legend.facecolor`'] = 'inherit' | 图例背景颜色 | 默认继承自 `axes.facecolor`
其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`legend.fancybox`'] = True | 是否使用圆形框作为图例背景 | `True`:使用圆形框;`False`:使用矩形框 | +| mpl.rcParams['`legend.fontsize`'] = 'medium' | 图例字体大小 | `xx-small`, `x-small`, `small`, `medium`
`large`, `x-large`, `xx-large`, `smaller`, `larger`
也可以使用数字来表示字体大小 | +| mpl.rcParams['`legend.framealpha`'] = 0.8 | 图例透明度 | float 类型,取值范围:`[0, 1]` | +| mpl.rcParams['`legend.frameon`'] = True | 是否在画布之上绘制图例 | `True`:是;`False`:否 | +| mpl.rcParams['`legend.handleheight`'] = 0.7 | 图例的高度 | float 类型高度值 | +| mpl.rcParams['`legend.handlelength`'] = 2.0 | 图例的宽度 | float 类型宽度值 | +| mpl.rcParams['`legend.handletextpad`'] = 0.8 | 图例和图例文本之间的水平距离 | float 类型距离值 | +| mpl.rcParams['`legend.labelspacing`'] = 0.5 | 不同图例之间的垂直距离 | float 类型距离值 | +| mpl.rcParams['`legend.loc`'] = 'best' | 图例在画布中的位置 | `best`, `upper right`, `upper left`, `lower left`
`lower right`, `right`, `center left`, `center right`
`lower center`, `upper center`, `center` | +| mpl.rcParams['`legend.shadow`'] = False | 是否给图例添加阴影效果 | `True`:是;`False`:否 | + + +### 【2x06】lines 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`lines.antialiased`'] = True | 是否以抗锯齿方式渲染线条 | `True`:是;`False`:否 | +| mpl.rcParams['`lines.color`'] = 'C0' | 线条颜色(对 `plot()` 没有影响) | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`lines.linestyle`'] = '-' | 线条样式 | `'-'`, `'--'`, `'-.'`, `':'`, `'solid'`, `'dashed'`,
`'dashdot'`, `'dotted'`, `'none'`, `' '`, `''` | +| mpl.rcParams['`lines.linewidth`'] = 1.5 | 线条宽度 | float 类型宽度值 | +| mpl.rcParams['`lines.marker`'] = 'None' | 线条上点的形状 | `.`, `,`, `o`, `v`, `^` 等,具体常见 [matplotlib.markers](https://matplotlib.org/api/markers_api.html) | +| mpl.rcParams['`lines.markeredgecolor`'] = 'auto' | 线条上点边缘的颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`lines.markerfacecolor`'] = 'auto' | 线条上点的颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`lines.markeredgewidth`'] = 1.0 | 线条上点的粗细 | float 类型粗细值 | +| mpl.rcParams['`lines.markersize`'] = 6.0 | 线条上点的大小 | float 类型大小值 | + +### 【2x07】patch 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`patch.antialiased`'] = True | 以抗锯齿方式渲染补丁 | `True`:是;`False`:否 | +| mpl.rcParams['`patch.edgecolor`'] = 'black' | 补丁边缘颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`patch.facecolor`'] = 'C0' | 补丁颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`patch.linewidth`'] = 1.0 | 补丁边缘宽度(以磅为单位) | float 类型宽度值 | + +### 【2x08】savefig 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`savefig.bbox`'] = None | 是否以紧凑形式保存图片 | `standard`:标准形式;`tight`:紧凑形式
(去掉边上多余的空白) | +| mpl.rcParams['`savefig.pad_inches`'] = 0.1 | `savefig.bbox` 参数为 `tight` 时,
图片使用的填充值
(相当于 html 中的 Padding) | float 类型填充值 | +| mpl.rcParams['`savefig.dpi`'] = 'figure' | 保存图片的像素(dpi) | str 类型像素值 | +| mpl.rcParams['`savefig.edgecolor`'] = 'white' | 保存图片的边缘颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`savefig.facecolor`'] = 'white' | 保存图片的画布颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`savefig.format`'] = 'png' | 保存图片的格式 | `eps`, `pdf`, `pgf`, `png`, `ps`, `raw`, `rgba`, `svg`, `svgz` | +| mpl.rcParams['`savefig.transparent`'] = False | 保存图片的背景是否透明 | `True`:是;`False`:否 | + +### 【2x09】text 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`text.antialiased`'] = True | 是否以抗锯齿方式渲染文本 | `True`:是;`False`:否 | +| mpl.rcParams['`text.color`'] = 'red' | 文本颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`text.usetex`'] = False | 是否使用 [LaTeX](https://baike.baidu.com/item/LaTeX/1212106) 排版系统
(主要用于生成复杂表格和数学公式) | `True`:是;`False`:否 | + +### 【2x10】xtick 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`xtick.color`'] = 'black' | x 轴刻度的颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`xtick.direction`'] = 'out' | x 轴刻度的方向 | `in`:内部(x 轴上方);`out`:外部(x 轴下方)
`inout`:同时在内部和外部 | +| mpl.rcParams['`xtick.bottom`'] = True | 是否在画布底部显示 x 轴刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.top`'] = False | 是否在画布顶部显示 x 轴刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.labelbottom`'] = True | 是否在画布底部显示 x 轴刻度文字标签 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.labeltop`'] = False | 是否在画布顶部显示 x 轴刻度文字标签 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.labelsize`'] = 'medium' | x 轴刻度文字大小 | `xx-small`, `x-small`, `small`, `medium`
`large`, `x-large`, `xx-large`, `smaller`, `larger`
也可以使用数字来表示字体大小 | +| mpl.rcParams['`xtick.major.bottom`'] = True | 是否在画布底部显示 x 轴主(大)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.major.top`'] = True | 是否在画布顶部显示 x 轴主(大)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.major.pad`'] = 3.5 | x 轴主(大)刻度与文字标签的距离 | float 类型距离值 | +| mpl.rcParams['`xtick.major.size`'] = 3.5 | x 轴主(大)刻度的大小 | float 类型大小值 | +| mpl.rcParams['`xtick.major.width`'] = 0.8 | x 轴主(大)刻度的宽度 | float 类型宽度值 | +| mpl.rcParams['`xtick.minor.bottom`'] = True | 是否在画布底部显示 x 轴次(小)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.minor.top`'] = True | 是否在画布顶部显示 x 轴次(小)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`xtick.minor.pad`'] = 3.4 | x 轴次(小)刻度与文字标签的距离 | float 类型距离值 | +| mpl.rcParams['`xtick.minor.size`'] = 2.0 | x 轴次(小)刻度的大小 | float 类型大小值 | +| mpl.rcParams['`xtick.minor.width`'] = 0.6 | x 轴次(小)刻度的宽度 | float 类型宽度值 | +| mpl.rcParams['`xtick.minor.visible`'] = False | x 轴次(小)刻度的可见性 | `True`:是;`False`:否 | + +### 【2x11】ytick 部分属性 + +| 属性及其默认值 | 描述 | 其他取值 | +| ------ | ------ | ------ | +| mpl.rcParams['`ytick.color`'] = 'black' | y 轴刻度的颜色 | 其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| mpl.rcParams['`ytick.direction`'] = 'out' | y 轴刻度的方向 | `in`:内部(y 轴右方);`out`:外部(y 轴左方)
`inout`:同时在内部和外部 | +| mpl.rcParams['`ytick.left`'] = True | 是否在画布左边显示 y 轴刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.right`'] = False | 是否在画布右边显示 y 轴刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.labelleft`'] = True | 是否在画布左边显示 y 轴刻度文字标签 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.labelright`'] = False | 是否在画布右边显示 y 轴刻度文字标签 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.labelsize`'] = 'medium' | y 轴刻度文字大小 | `xx-small`, `x-small`, `small`, `medium`
`large`, `x-large`, `xx-large`, `smaller`, `larger`
也可以使用数字来表示字体大小 | +| mpl.rcParams['`ytick.major.left`'] = True | 是否在画布左边显示 y 轴主(大)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.major.right`'] = True | 是否在画布右边显示 y 轴主(大)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.major.pad`'] = 3.5 | y 轴主(大)刻度与文字标签的距离 | float 类型距离值 | +| mpl.rcParams['`ytick.major.size`'] = 3.5 | y 轴主(大)刻度的大小 | float 类型大小值 | +| mpl.rcParams['`ytick.major.width`'] = 0.8 | y 轴主(大)刻度的宽度 | float 类型宽度值 | +| mpl.rcParams['`ytick.minor.left`'] = True | 是否在画布左边显示 y 轴次(小)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.minor.right`'] = True | 是否在画布右边显示 y 轴次(小)刻度 | `True`:是;`False`:否 | +| mpl.rcParams['`ytick.minor.pad`'] = 3.4 | y 轴次(小)刻度与文字标签的距离 | float 类型距离值 | +| mpl.rcParams['`ytick.minor.size`'] = 2.0 | y 轴次(小)刻度的大小 | float 类型大小值 | +| mpl.rcParams['`ytick.minor.width`'] = 0.6 | y 轴次(小)刻度的宽度 | float 类型宽度值 | +| mpl.rcParams['`ytick.minor.visible`'] = False | y 轴次(小)刻度的可见性 | `True`:是;`False`:否 | + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105638122 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A69-Matplotlib-02.md b/source/_posts/A69-Matplotlib-02.md new file mode 100644 index 0000000000000000000000000000000000000000..10cff8d02fc78a5817789dc23feafb30b207ef63 --- /dev/null +++ b/source/_posts/A69-Matplotlib-02.md @@ -0,0 +1,533 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(二):文本描述/中文支持/画布/网格等基本图像属性 +tags: + - Matplotlib + - 画布 + - 网格 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(二):为图像添加文本描述、设置中文支持、了解画布、网格等基本图像属性。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105828049 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】添加文本描述 + +### 【1x01】添加标题:matplotlib.pyplot.title() + +`matplotlib.pyplot.title()` 方法可为图表添加标题。 + +基本语法:`matplotlib.pyplot.title(label[, fontdict=None, loc=None, pad=None])` + +| 参数 | 描述 | +| ------ | ------ | +| label | str 类型,标题文字 | +| fontdict | 字典类型,控制标题文本外观,可选项,默认值为:
`{'fontsize': rcParams['axes.titlesize'], `
`'fontweight' : rcParams['axes.titleweight'], `
`'color' : rcParams['axes.titlecolor'], `
`'verticalalignment': 'baseline', `
`'horizontalalignment': loc}` | +| loc | str 类型,可选项,三个可选值:center、left、right,默认为 `rcParams["axes.titlelocation"]`(默认为 `center`) | +| pad | float 类型,可选项,标题距轴顶部的偏移量(以磅为单位)。如果为 None,则默认为 `rcParams["axes.titlepad"]`(默认为:6.0) | + +应用举例: + +```python +import matplotlib.pyplot as plt + +x = range(2, 26, 2) +y = range(0, 12) +plt.title('This is a title') +plt.plot(x, y) +plt.show() +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/01.png) + +### 【1x02】为坐标轴添加标签:matplotlib.pyplot.xlabel() / ylabel() + +`matplotlib.pyplot.xlabel()`:为 x 轴添加标签; +`matplotlib.pyplot.ylabel()`:为 y 轴添加标签。 + +基本语法: +`matplotlib.pyplot.xlabel(xlabel[, fontdict=None, labelpad=None])` +`matplotlib.pyplot.ylabel(ylabel[, fontdict=None, labelpad=None])` + +| 参数 | 描述 | +| ------- | ------ | +| xlabel / ylabel | str 类型,要添加的文本信息 | +| fontdict | 字典类型,控制标题文本外观,可选项,默认值为:
`{'fontsize': rcParams['axes.titlesize'], `
`'fontweight' : rcParams['axes.titleweight'], `
`'color' : rcParams['axes.titlecolor'], `
`'verticalalignment': 'baseline', `
`'horizontalalignment': loc}` | +| labelpad | float 类型,可选项,x 轴标签距离 x 轴的距离 | + +应用举例: + +```python +import matplotlib.pyplot as plt + +x = range(2, 26, 2) +y = range(0, 12) +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +plt.title('This is a title') +plt.xlabel('This is x label', fontdict={'fontsize': 15, 'fontweight': 'bold', 'color': 'red'}, labelpad=15.0) +plt.ylabel('This is y label', fontsize=10, fontweight='light', color='blue', labelpad=15.0) + +plt.plot(x, y) +plt.plot(a, b) + +plt.show() +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/02.png) + +### 【1x03】任意位置添加文本:matplotlib.pyplot.text() + +`matplotlib.pyplot.text()` 方法可以在画布上任意位置添加文本描述。 + +基本语法:`matplotlib.pyplot.text(x, y, s[, fontdict=None, withdash=])` + +| 参数 | 描述 | +| ------ | ------ | +| x, y | 放置文本的坐标位置 | +| s | str 类型,要添加的文本信息 | +| fontdict | 字典类型,控制标题文本外观,可选项,默认值为:
`{'fontsize': rcParams['axes.titlesize'], `
`'fontweight' : rcParams['axes.titleweight'], `
`'color' : rcParams['axes.titlecolor'], `
`'verticalalignment': 'baseline', `
`'horizontalalignment': loc}` | +| ha | 注释点在注释文本的左边、右边或中间(`left`、`right`、`center`) | +| va | 注释点在注释文本的上边、下边、中间或基线 (`top`、`bottom`、`center`、`baseline`) | +| withdash | bool 类型,可选项,默认为 False,创建一个 [TextWithDash](https://matplotlib.org/api/text_api.html#matplotlib.text.TextWithDash) 实例而不是一个 [Text](https://matplotlib.org/api/text_api.html#matplotlib.text.Text) 实例 | + +应用举例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['lines.marker'] = 'o' # 设置线条上点的形状 +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +plt.title('This is a title') +plt.xlabel('This is x label') +plt.ylabel('This is y label') + +plt.text(4, 3.2, 'text1') +plt.text(9, 4.2, 'text2') +plt.text(14, 5.2, 'text3') +plt.text(19, 6.2, 'text4') +plt.text(24, 7.2, 'text5') +plt.text(27.5, 7.9, 'text6') + +plt.plot(a, b) + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/03.png) + +### 【1x03】任意位置添加文本:matplotlib.pyplot.annotate() + +`matplotlib.pyplot.annotate()` 方法可以在指定坐标点添加文本或 LaTeX 描述,也可以在其他位置添加描述后,使用箭头指向某个坐标点。比 `matplotlib.pyplot.text()` 更高级。 + +基本语法:`matplotlib.pyplot.annotate(text, xy, xytext, xycoords, textcoords, ha, va, arrowprops, \*\*kwargs)` + +| 参数 | 描述 | +| ------ | ------ | +| text | str 类型,注释的文本 | +| xy | 被注释的坐标点,格式:`(x, y)` | +| xytext | 注释文本的坐标点,格式:`(x, y)`,默认与 xy 相同 | +| xycoords | 被注释的坐标点的参考系,取值参见**表一**,默认为 'data' | +| textcoords | 注释文本的坐标点的参考系,取值参见**表二**,默认为 xycoords 的值 | +| ha | 注释点在注释文本的左边、右边或中间(`left`、`right`、`center`) | +| va | 注释点在注释文本的上边、下边、中间或基线 (`top`、`bottom`、`center`、`baseline`) | +| arrowprops | dict 字典类型,箭头的样式
如果 arrowprops 不包含键 arrowstyle,则允许的键参见**表三**
如果 arrowprops 包含键 arrowstyle,则允许的键参见**表四** | + +
表一:xycoords 取值类型
+ +| 取值 | 描述 | +| ------ | ------ | +| 'figure points' | 以画布左下角为参考,单位为点数 | +| 'figure pixels' | 以画布左下角为参考,单位为像素 | +| 'figure fraction' | 以画布左下角为参考,单位为百分比 | +| 'axes points' | 以绘图区左下角为参考,单位为点数 | +| 'axes pixels' | 以绘图区左下角为参考,单位为像素 | +| 'axes fraction' | 以绘图区左下角为参考,单位为百分比 | +| 'data' | 使用被注释对象的坐标系,即数据的 x, y 轴(默认) | +| 'polar' | 使用(θ,r)形式的极坐标系 | + +
表二:textcoords 取值类型
+ +| 取值 | 描述 | +| ------ | ------ | +| 'figure points' | 以画布左下角为参考,单位为点数 | +| 'figure pixels' | 以画布左下角为参考,单位为像素 | +| 'figure fraction' | 以画布左下角为参考,单位为百分比 | +| 'axes points' | 以绘图区左下角为参考,单位为点数 | +| 'axes pixels' | 以绘图区左下角为参考,单位为像素 | +| 'axes fraction' | 以绘图区左下角为参考,单位为百分比 | +| 'data' | 使用被注释对象的坐标系,即数据的 x, y 轴 | +| 'polar' | 使用(θ,r)形式的极坐标系 | +| 'offset points' | 相对于被注释点的坐标 xy 的偏移量,单位是点 | +| 'offset pixels' | 相对于被注释点的坐标 xy 的偏移量,单位是像素 | + +
表三:arrowprops 不包含键 arrowstyle 时的取值
+ +| 键 | 描述 | +| ------ | ------ | +| width | 箭头的宽度,以点为单位 | +| headwidth | 箭头底部的宽度,以点为单位 | +| headlength | 箭头的长度,以点为单位 | +| shrink | 箭头两端收缩占总长的百分比 | +| ? | 其他 [matplotlib.patches.FancyArrowPatch](https://matplotlib.org/api/_as_gen/matplotlib.patches.FancyArrowPatch.html#matplotlib.patches.FancyArrowPatch) 中的关键字,部分常用关键字参见**表五** | + +
表四:arrowprops 包含键 arrowstyle 时的取值
+ +| 取值 | 描述 | +| ------ | ------ | +| `'-'` | None | +| `'->'` | head_length=0.4,head_width=0.2 | +| `'-['` | widthB=1.0,lengthB=0.2,angleB=None | +| `']-'` | widthA=1.0, lengthA=0.2, angleA=None | +| `]-[` | widthA=1.0, lengthA=0.2, angleA=None, widthB=1.0, lengthB=0.2, angleB=None | +| `'|-|'` | widthA=1.0,widthB=1.0 | +| `'-|>'` | head_length=0.4,head_width=0.2 | +| `'<-'` | head_length=0.4,head_width=0.2 | +| `'<->'` | head_length=0.4,head_width=0.2 | +| `'<|-'` | head_length=0.4,head_width=0.2 | +| `'<|-|>'` | head_length=0.4,head_width=0.2 | +| `'fancy'` | head_length=0.4,head_width=0.4,tail_width=0.4 | +| `'simple'` | head_length=0.5,head_width=0.5,tail_width=0.2 | +| `'wedge'` | tail_width=0.3,shrink_factor=0.5 | + +
表五:matplotlib.patches.FancyArrowPatch 常用的键
+ +| 键 | 描述 | +| ------ | ------ | +| arrowstyle | 箭头样式,取值参见**表四** | +| connectionstyle | 连接方式,默认为 `arc3`,有以下五种取值:
`angle`:angleA=90, angleB=0, rad=0.0
`angle3`:angleA=90, angleB=0
`arc`:angleA=0, angleB=0, armA=None, armB=None, rad=0.0
`arc3`:rad=0.0
`bar`:armA=0.0, armB=0.0, fraction=0.3, angle=None
angle 为箭头旋转的角度,rad 为弧度 | +| relpos | 箭头起始点相对注释文本的位置,默认为 (0.5, 0.5),即文本的中心
(0,0)表示左下角,(1,1)表示右上角 | +| patchA | 箭头起点处的图形,默认为文本的边框 | +| patchB | 箭头终点处的图形,默认为空 | +| shrinkA | 箭头起点的缩进点数,默认为2 | +| shrinkB | 箭头终点的缩进点数,默认为2 | +| ? | 其他键值,参见官方文档 [matplotlib.patches.PathPatch](https://matplotlib.org/api/_as_gen/matplotlib.patches.PathPatch.html#matplotlib.patches.PathPatch) | + +
connectionstyle 样式举例
+ +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/04.png) + +应用举例: + +```python +import numpy as np +import matplotlib.pyplot as plt + +x = np.arange(-2*np.pi, 2*np.pi, 0.01) +y = np.sin(1*x)/x +plt.title('This is a title') +plt.xlabel('This is x label') +plt.ylabel('This is y label') + +plt.plot(x, y) + +plt.annotate(r'$\lim_{x\to 0}\frac{\sin(x)}{x}=1$', # 插入 LaTeX 表达式 + xy=[0, 1], # 被标记的坐标 + xycoords='data', # 被标记的坐标的参考系 + xytext=[50, -40], # 注释文本的坐标 + textcoords='offset points', # 注释文本的坐标的参考系 + fontsize=16, # 字体大小 + arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=.2")) # 箭头样式 + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/05.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105828049 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【2x00】设置中文显示 + +### 【2x01】常见系统自带文字及其英文名称 + +Windows 系统中常见自带字体: + +| 字体 | 英文名称 | +| ------ | ----------- | +| 黑体 | SimHei | +| 宋体 | SimSun | +| 新宋体 | NSimSun | +| 仿宋 | FangSong | +| 仿宋_GB2312 | FangSong_GB2312 | +| 楷体_GB2312 | KaiTi_GB2312 | +| 楷体 | KaiTi | +| 微软正黑 | Microsoft JhengHei | +| 微软雅黑 | Microsoft YaHei | +| 细明体 | MingLiU | +| 标楷体 | DFKai-SB | +| 新细明体 | PMingLiU | + +装有 office 后新添加的字体: + +| 字体 | 英文名称 | +| ------ | ----------- | +| 隶书 | LiSu | +| 幼圆 | YouYuan | +| 华文细黑 | STXihei | +| 华文楷体 | STKaiti | +| 华文宋体 | STSong | +| 华文中宋 | STZhongsong | +| 华文仿宋 | STFangsong | +| 方正舒体 | FZShuTi | +| 方正姚体 | FZYaoti | +| 华文彩云 | STCaiyun | +| 华文琥珀 | STHupo | +| 华文隶书 | STLiti | +| 华文行楷 | STXingkai | +| 华文新魏 | STXinwei | + +Mac OS 系统中常见自带字体: + +| 字体 | 英文名称 | +| ------ | ----------- | +| 华文细黑 | STHeiti Light / STXihei | +| 华文黑体 | STHeiti | +| 华文楷体 | STKaiti | +| 华文宋体 | STSong | +| 华文仿宋 | STFangsong | +| 丽黑 Pro | LiHei Pro Medium | +| 丽宋 Pro | LiSong Pro Light | +| 标楷体 | BiauKai | +| 苹果丽中黑 | Apple LiGothic Medium | +| 苹果丽细宋 | Apple LiSung Light | + + +### 【2x02】指定全局字体:rcParams + +通过 `rcParams['font.sans-serif']` 可以配置全局字体。 + +优点:只需设置一次即可显示所有中文;缺点:污染全局,无法对单个中文设置字体。 + +应用举例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 配置全局字体为微软雅黑 +plt.rcParams['axes.unicode_minus'] = False # 部分字体负号会显示乱码,可添加此参数进行配置 +a = [-15, -10, -5, 20, 25, 30] +b = [-5, -4, -3, 6, 7, 8] + +plt.title('这是中文标题') +plt.xlabel('这是 x 轴标签') +plt.ylabel('这是 y 轴标签') + +plt.plot(a, b) +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/06.png) + + +### 【2x03】指定单个字体:fontproperties + +`fontproperties` 参数可以加在要设置中文的地方 + +优点:不污染全局;缺点:中文太多了挨个设置比较繁琐。 + +应用举例: + +```python +import matplotlib.pyplot as plt + +a = [-15, -10, -5, 20, 25, 30] +b = [-5, -4, -3, 6, 7, 8] + +plt.title('这是中文标题', fontproperties='Microsoft JhengHei') # 微软正黑 +plt.xlabel('这是 x 轴标签', fontproperties='STLiti') # 华文隶书 +plt.ylabel('这是 y 轴标签', fontproperties='Microsoft YaHei') # 微软雅黑 + +plt.plot(a, b) +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/07.png) + + +### 【2x04】指定文字路径:FontProperties + +`matplotlib` 中 `font_manager` 模块的 `FontProperties` 方法可以通过指定文字路径来使用本地文字,在 Windows 中,文字路径一般是 `C:\Windows\Fonts\`,文字名称可以通过其属性来获取,部分用户自己安装的字体可能包含多个类型,可打开字体合集后通过其属性来获取。 + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/08.png) + +```python +import matplotlib.pyplot as plt +from matplotlib.font_manager import FontProperties + +font = FontProperties(fname=r"C:\Windows\Fonts\STXINGKA.TTF", size=14) +a = [-15, -10, -5, 20, 25, 30] +b = [-5, -4, -3, 6, 7, 8] + +plt.title('这是中文标题', fontproperties=font) +plt.xlabel('这是 x 轴标签', fontproperties=font) +plt.ylabel('这是 y 轴标签', fontproperties=font) + +plt.plot(a, b) +plt.show() +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/09.png) + +### 【2x05】文字更多属性:rc + +rc 参数支持文字的更多属性设置,如字体粗细、大小等,这种方法同样将影响全局。 + +官方参考:[https://matplotlib.org/api/matplotlib_configuration_api.html?highlight=rc#matplotlib.rc](https://matplotlib.org/api/matplotlib_configuration_api.html?highlight=rc#matplotlib.rc) + +应用举例: + +```python +import matplotlib.pyplot as plt + +font = {'family': 'SimHei', + 'weight': 'bold', + 'size': '10'} +plt.rc('font', **font) # 设置字体的更多属性 +plt.rc('axes', unicode_minus=False) # 显示负号 + +a = [-15, -10, -5, 20, 25, 30] +b = [-5, -4, -3, 6, 7, 8] + +plt.title('这是中文标题') +plt.xlabel('这是 x 轴标签') +plt.ylabel('这是 y 轴标签') + +plt.plot(a, b) +plt.show() +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/10.png) + +## 【3x00】设置画布大小 / 分辨率 / 颜色 + +`matplotlib.pyplot.figure()` 可以设置画布的大小、图片分辨率、颜色等。 + +基本语法:`matplotlib.pyplot.figure(figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True, \*\*kwargs)` + +| 参数 | 描述 | +| ------ | ------ | +| figsize | `(float, float)` 的格式,代表宽度和高度,单位为英寸
默认为 `rcParams["figure.figsize"] = [6.4, 4.8]`,即:640 x 480 | +| dpi | 图像分辨率,默认为 `rcParams["figure.figsize"] = 100` | +| facecolor | 图像背景颜色,默认为 `rcParams["figure.edgecolor"] = ‘white’` | +| edgecolor | 图像边缘颜色,默认为 `rcParams[’figure.edgecolor’] = ‘white’` | +| frameon | 是否启用图框 | + +应用举例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) + +plt.figure(figsize=(6.5, 5), dpi=120, facecolor='#BBFFFF') +plt.plot(x, y) + +plt.show() +``` + +![11](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/11.png) + +## 【4x00】设置网格 + +`matplotlib.pyplot.grid()` 方法可以为图表设置网格显示。 + +基本语法:`matplotlib.pyplot.grid([b=None, which='major', axis='both', \*\*kwargs])` + +| 参数 | 属性 | +| ------ | ------ | +| b | bool 值,可选项,是否显示网格,值为 `None` 或 `True` 则显示,`False` 不显示 | +| which | 可选项,在主/次刻度显示网格线,`major`:主(大)刻度;`minor`:次(小)刻度;`both`:两者同时显示 | +| axis | 可选项,在横/竖轴显示网格线,`x`:x 轴;`y`:y 轴;`both`:两者同时显示 | +| **kwargs | 其他 [Line2D](https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D) 属性,常见 [Line2D](https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D) 属性见下表 | + +Line2D 属性用法:`grid(color='r', linestyle='-', linewidth=2)`,部分常见 [Line2D](https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D) 属性如下: + +| 属性 | 描述 | +| ------ | ------ | +| alpha | 网格透明度,float 类型,取值范围:`[0, 1]`,默认为 1.0,即不透明 | +| antialiased / aa | 是否使用抗锯齿渲染,默认为 True | +| color / c | 网格颜色,支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 [Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| linestyle / ls | 网格线条样式:`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'`
`':'` or `'dotted'`, `'none'` or `' '` or `''` | +| linewidth / lw | 网格线条宽度,float 类型,默认 0.8 | + +应用举例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +a = [-15, -10, -5, 20, 25, 30] +b = [-5, -4, -3, 6, 7, 8] + +plt.title('这是中文标题') +plt.xlabel('这是 x 轴标签') +plt.ylabel('这是 y 轴标签') +plt.grid(axis='x', color='red', linestyle='-.', linewidth=2) +plt.plot(a, b) +plt.show() +``` + +![12](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A69/12.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105828049 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A70-Matplotlib-03.md b/source/_posts/A70-Matplotlib-03.md new file mode 100644 index 0000000000000000000000000000000000000000..40517736ca7c80013a170463f6f9ecda4686e4ef --- /dev/null +++ b/source/_posts/A70-Matplotlib-03.md @@ -0,0 +1,490 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(三):图例/LaTeX/刻度/子图/补丁等基本图像属性 +tags: + - Matplotlib + - 图例 + - LaTeX + - 子图 + - 补丁 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(三):了解图例、LaTeX、刻度、子图、补丁等基本图像属性。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105828143 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】设置图例 + +`matplotlib.pyplot.legend()` 方法可以为图表设置图例。 + +基本语法:`matplotlib.pyplot.legend(\*args, \*\*kwargs)` + +部分常见参数: + +| 参数 | 描述 | +| ------ | ------ | +| loc | 图例在画布中的位置,默认为 best,其他取值:
`best`, `upper right`, `upper left`, `lower left`
`lower right`, `right`, `center left`, `center right`
`lower center`, `upper center`, `center`
也可以用数字 0 - 10 来表示上述位置 | +| bbox_to_anchor | 调整图例在画布中的位置,当 loc 达不到我们想要的效果时,就可以使用该参数
该参数接收一个二元数组 (x, y),x 用于控制图例的左右移动,值越大越向右边移动
y 用于控制图例的上下移动,值越大,越向上移动 | +| borderaxespad | 图例距离轴之间的距离,float 类型,默认为 0.5 | +| borderpad | 图例边框空白区域大小,float 类型,默认为 0.4 | +| columnspacing | 图例列间距,float 类型,默认为 2.0 | +| edgecolor | 图例边缘线颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| facecolor | 图例背景颜色,默认继承自 `axes.facecolor`
其他颜色,支持英文颜色名称及其简写、十六进制颜色码等
更多颜色示例参见[官网 Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| fancybox | 是否使用圆形框作为图例背景, 默认为 True | +| fontsize | 图例字体大小,默认为 `medium`,`xx-small`, `x-small`, `small`, `medium`
`large`, `x-large`, `xx-large`, `smaller`, `larger`
也可以使用数字来表示字体大小 | +| framealpha | 图例透明度,float 类型,默认为 0.8,取值范围:`[0, 1]` | +| handleheight | 图例的高度 ,float 类型,默认为 0.7 | +| handlelength | 图例的宽度,float 类型,默认为 2.0 | +| handletextpad | 图例和图例文本之间的水平距离,float 类型,默认为 0.8 | +| labelspacing | 不同图例之间的垂直距离,float 类型,默认为 0.5 | +| shadow | 是否给图例添加阴影效果,默认为 False | + +### 【1x01】方法一:指定 label 参数 + +在画图的时候先指定 `label` 标签文本,再调用 `legend()` 方法即可。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +plt.plot(a, b, label='图例一') # 指定 a,b 数据的图例 +plt.plot(x, y, label='图例二') # 指定 x,y 数据的图例 + +plt.legend(loc=2, edgecolor='red', facecolor='#F5F5F5') # 指定图例位置、边缘线条颜色和背景色 +plt.show() +``` + +### 【1x02】方法二:使用 set_label 方法 + +在画图的时候先使用 `set_label()` 方法指定标签文本,再调用 `legend()` 方法即可。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +line1, = plt.plot(a, b) +line2, = plt.plot(x, y) +line1.set_label('图例一') # 指定 a,b 数据的图例 +line2.set_label('图例二') # 指定 x,y 数据的图例 + +plt.legend(loc=2, edgecolor='red', facecolor='#F5F5F5') # 指定图例位置、边缘线条颜色和背景色 +plt.show() +``` + +### 【1x03】方法三:直接使用 legend 方法 + +直接使用 `legend()` 方法来指定图例标签也可以达到同样效果,图例以列表或者元组形式储存,图例与绘制图形的顺序一一对应。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +plt.plot(a, b) +plt.plot(x, y) + +plt.legend(['图例一', '图例二'], loc=2, edgecolor='red', facecolor='#F5F5F5') +plt.show() +``` + +也可以使用两个元组,将绘制的图形和图例一一对应来储存: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +line1, = plt.plot(a, b) +line2, = plt.plot(x, y) + +plt.legend((line1, line2), ('图例一', '图例二'), loc=2, edgecolor='red', facecolor='#F5F5F5') +plt.show() +``` + +以上三种方法绘制的图形均一致: + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/01.png) + +## 【2x00】数学公式 LaTeX + +LaTeX(LATEX,音译“拉泰赫”)是一种基于 TeX 的排版系统,常用于生成复杂表格和数学公式,Matplotlib 提供了自己的 TeX 表达式解析器,布局引擎和字体,布局引擎基于 Donald Knuth 的 TeX 布局算法改编。使用数学公式时用 `$` 将其包围起来即可。具体的符号与其对应的英文表示参见官方文档:[https://matplotlib.org/tutorials/text/mathtext.html](https://matplotlib.org/tutorials/text/mathtext.html) + +应用举例: + +```python +import numpy as np +import matplotlib.pyplot as plt + +t = np.arange(0.0, 2.0, 0.01) +s = np.sin(2*np.pi*t) + +plt.title(r'$\alpha_i > \beta_i$', fontsize=20) +plt.text(1, -0.6, r'$\sum_{i=0}^\infty x_i$', fontsize=20) +plt.text(0.6, 0.6, r'$\mathcal{A}\mathrm{sin}(2 \omega t)$', fontsize=20) +plt.xlabel('time (s)') +plt.ylabel('volts (mV)') + +plt.plot(t, s) +plt.show() +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/02.png) + +## 【3x00】调整 x / y 轴刻度和范围 + +在生成图像时,默认会按照所给的数据均匀设置几个刻度,如果对默认的刻度不满意,则可以使用 `xticks()` 或 `yticks()` 方法指定刻度值。`xlim()` 与 `ylim()` 则可以设置刻度的范围。 + +基本语法: +`matplotlib.pyplot.xticks([ticks=None, labels=None, \*\*kwargs])` +`matplotlib.pyplot.yticks([ticks=None, labels=None, \*\*kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| ticks | 数组形式的位置列表,即显示第 n 个位置的刻度,可选项,若传递空列表将删除所有 xtick / ytick | +| labels | 数组形式的值,在对应刻度线显示的标签信息。仅当同时传递了刻度时,才能传递此参数 | +| **kwargs | 其他参数参见 [Text](https://matplotlib.org/api/text_api.html#matplotlib.text.Text) | + +其他参数里面有一个常用的 `rotation` 参数,次参数可以用于设置刻度标签的旋转角度,对于标签太长的可以将其旋转一个角度来显示。 + +应用举例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) + +plt.plot(x, y) +# x 轴每隔三个显示一次刻度,旋转45°显示标签 +plt.xticks(range(2, 26, 3), ('the {} ticks'.format(i) for i in range(2, 26, 3)), rotation=45) + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/03.png) + + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) + +plt.xlim((0, 30)) # 设置 x 轴刻度范围 +plt.plot(x, y) + +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/04.png) + +## 【4x00】画布边框与坐标轴的移动 + +Matplotlib 所绘制的图表中的每个绘图元素,例如线条 Line2D、文字 Text、刻度等在内存中都有一个对象与之对应。 + +`matplotlib.pyplot.gca()` 函数用于获取当前的绘图区 `Axes`(Get Current Axes) + +`matplotlib.pyplot.gcf()` 函数用于获取当前的画布 `Figure`(Get Current Figure) + +例如:`matplotlib.pyplot.plot()` 实际上会通过 `matplotlib.pyplot.gca()` 获得当前的 Axes对象 `ax`,然后再调用 `ax.plot()` 方法实现真正的绘图。我们可以通过这种方法来实现画布边框的隐藏和坐标轴的移动。 + +应用举例: + +```python +import matplotlib.pyplot as plt +import numpy as np + +x = np.arange(0, 2*np.pi, np.pi/100) +y = np.sin(x) +plt.plot(x, y) + +plt.xlabel('X axis') +plt.ylabel('Y axis') + +ticks = (0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi) +labels = ('0', r'$\frac{\pi} {2}$', r'$\pi$', r'$\frac{3\pi} {2}$', r'$2\pi$') +plt.xticks(ticks, labels) # 设置 x 坐标轴显示的数据 + +ax = plt.gca() # 获取当前的画布, gca = get current axes +ax.spines['right'].set_visible(False) # 设置右边框不显示 +ax.spines['top'].set_visible(False) # 设置上边框不显示 +# ax.spines['top'].set_color('none') # 设置颜色为无也可以 + +ax.xaxis.set_ticks_position('bottom') # 设置 x 坐标轴的标签位置 +ax.yaxis.set_ticks_position('left') # 设置 y 坐标轴的标签位置 +ax.spines['bottom'].set_position(('data', 0)) # 设置 x 轴在 (0, 0) 位置 +ax.spines['left'].set_position(('data', 0)) # 设置 y 轴在 (0, 0) 位置 + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/05.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105828143 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【5x00】创建子图 + +子图的概念:在同一张画布中创建多个图像,方便对数据进行对比。 + +### 【5x01】方法一:add_subplot() + +首先创建一个画布,然后利用 `add_subplot()` 方法填充子图,该方法接收三个参数,前两个参数表示子图有几行几列,最后一个参数表示第几个子图,如:`fig.add_subplot(221)` 表示总共有两行两列(2x2=4)一共4个子图,当前是第一个子图。若子图大于9个则用逗号隔开即可。 + +应用举例: + +```python +import numpy as np +import matplotlib.pyplot as plt + +x = np.arange(100) + +fig = plt.figure(figsize=(12, 6)) + +ax1 = fig.add_subplot(221) # 第 1 个子图 +ax1.plot(x, x) + +ax2 = fig.add_subplot(222) # 第 2 个子图 +ax2.plot(x, -x) + +ax3 = fig.add_subplot(223) # 第 3 个子图 +ax3.plot(x, x ** 2) + +ax4 = fig.add_subplot(224) # 第 4 个子图 +ax4.plot(-x, x ** 2) + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/06.png) + +### 【5x02】方法二:pyplot.subplot() + +`matplotlib.pyplot.subplot()` 方法和 `add_subplot()` 方法有点儿类似,同样接收三个参数,前两个参数表示子图有几行几列,最后一个参数表示第几个子图。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +x = np.arange(100) + +plt.figure(figsize=(12, 6)) + +plt.subplot(221) # 第 1 个子图 +plt.plot(x, x) + +plt.subplot(222) # 第 2 个子图 +plt.plot(x, x ** 2) + +plt.subplot(223) # 第 3 个子图 +plt.plot(x, x ** 3) + +plt.subplot(224) # 第 4 个子图 +plt.plot(x, x ** 4) + +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/07.png) + +### 【5x03】方法三:pyplot.subplots() + +`matplotlib.pyplot.subplots()` 函数会将画布分割成指定的列和行,分割后依次在各个区域画图即可。注意与 `matplotlib.pyplot.subplot()` 略有差别。 + +`fig, axes = plt.subplots` 的意思是:`plt.subplots` 方法会返回一个包含 figure(画布) 和 axes(绘图区) 对象的元组,fig 和 axes 参数分别接收这两个对象,后期对不同绘图区进行处理即可。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +x = np.arange(100) +fig, axes = plt.subplots(figsize=(12, 6), nrows=2, ncols=2) # 将画布分割为2行2列,起始值为0 + +axes[0][0].plot(x, x) # 绘制第1行第1列 +axes[0][1].plot(x, -x) # 绘制第1行第2列 +axes[1][0].plot(-x, x ** 2) # 绘制第2行第1列 +axes[1][1].plot(x, -x ** 2) # 绘制第2行第2列 + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/08.png) + +## 【6x00】填充补丁 + +`matplotlib.patches` 可用于在画布上填充圆形、长方形、椭圆形、多边形等多种图像补丁。 + +官方文档:[https://matplotlib.org/api/patches_api.html](https://matplotlib.org/api/patches_api.html) + + +| 类 | 描述 | +| ------ | ------ | +| matplotlib.patches.Arc(xy, width, height, angle=0.0, theta1=0.0, theta2=360.0, **kwargs) | 椭圆弧 | +| matplotlib.patches.Arrow(x, y, dx, dy, width=1.0, **kwargs) | 箭头 | +| matplotlib.patches.Circle(xy, radius=5, **kwargs) | 圆 | +| matplotlib.patches.Ellipse(xy, width, height, angle=0, **kwargs) | 椭圆 | +| matplotlib.patches.CirclePolygon(xy, radius=5, resolution=20, **kwargs) | 近似多边形的圆形面片 | +| matplotlib.patches.Polygon(xy, closed=True, **kwargs) | 不规则多边形 | +| matplotlib.patches.Rectangle(xy, width, height, angle=0.0, **kwargs) | 矩形 | +| matplotlib.patches.RegularPolygon(xy, numVertices, radius=5, orientation=0, **kwargs) | 正多边形 | +| matplotlib.patches.Shadow(patch, ox, oy, props=None, **kwargs) | 创建给定补丁的阴影 | +| matplotlib.patches.Wedge(center, r, theta1, theta2, width=None, **kwargs) | 楔形 | + +应用举例: + +```python +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.patches as mpathes + +x = np.arange(0.0, 2.0, 0.01) +y = np.sin(2*np.pi*x) + +# 获取当前绘图区(gca = Get Current Axes +ax = plt.gca() + +# 圆形:圆点(0.2, -0.25),半径0.2,红色 +circle = mpathes.Circle((0.2, -0.25), 0.2, color='r') + +# 长方形:左侧和底部坐标(0.25, 0.75),宽0.25,高0.15,透明度0.5 +rect = mpathes.Rectangle((0.25, 0.75), 0.25, 0.15, alpha=0.5) + +# 正多边形:中心点坐标(1.0, 0),顶点数6,中心到每个顶点的距离0.25 +regular_polygon = mpathes.RegularPolygon((1.0, 0), 6, 0.25, color='g') + +# 不规则多边形:polygon_point 为要连接的点的坐标 +polygon_point = [[1.5, -0.75], [1.75, -1], [2.0, 0], [1.5, -0.25]] +polygon = mpathes.Polygon(polygon_point, color='#FF69B4', alpha=0.3) + +# 椭圆形:中心点坐标(1.25, 0.75),横轴长度0.4,垂直轴长度0.2 +ellipse = mpathes.Ellipse((1.25, 0.75), 0.4, 0.2, color='y') + +# 将补丁添加到当前绘图区 +ax.add_patch(circle) +ax.add_patch(rect) +ax.add_patch(regular_polygon) +ax.add_patch(polygon) +ax.add_patch(ellipse) + +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.grid() +plt.plot(x, y) +plt.show() +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/09.png) + +## 【7x00】保存图像 + +`matplotlib.pyplot.savefig()` 方法可以将绘制的图像保存到本地,支持多种格式:eps, pdf, pgf, png, ps, raw, rgba, svg, svgz。 + + **注意:因为调用 `plt.show()` 函数后,会创建一个新的空白的图片,所以在保存图片时注意要在 `plt.show()` 前调用 `plt.savefig()`** + +基本语法:`matplotlib.pyplot.savefig(fname, dpi=None, facecolor='w', edgecolor='w', format=None, transparent=False)` + +| 参数 | 描述 | +| ------ | ------ | +| fname | str 类型 / 文件路径 / 类似文件的对象
如果未设置格式,则根据 fname 的扩展名(如果有)和 `rcParams[“savefig.format”] = ‘png’` 推断输出格式
如果设置了格式,则它将确定输出格式 | +| dpi | 保存图片的像素(dpi),以每英寸点数为单位。如果为 None,则默认取 `rcParams[’savefig.dpi’] = ‘figure’` | +| facecolor | 保存图片的画布颜色,默认为 white | +| edgecolor | 保存图片的边缘颜色,默认为 white | +| format | 保存图片的格式,未设置则取 fname 中的格式 | +| transparent | 保存图片的背景是否透明 | + +应用举例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +x = range(2, 26, 2) +y = range(0, 12) +a = [5, 10, 15, 20, 25, 30] +b = [3, 4, 5, 6, 7, 8] + +line1, = plt.plot(a, b) +line2, = plt.plot(x, y) + +plt.legend((line1, line2), ('图例一', '图例二'), loc=2, edgecolor='red', facecolor='#F5F5F5') +plt.savefig('D:\\data\\pic.png', transparent=True) # 保存为透明文件 +plt.show() +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A70/10.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105828143 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A71-Matplotlib-04.md b/source/_posts/A71-Matplotlib-04.md new file mode 100644 index 0000000000000000000000000000000000000000..d5927fcd74698a79dbb206f4791ba05683c3f6e4 --- /dev/null +++ b/source/_posts/A71-Matplotlib-04.md @@ -0,0 +1,497 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 +tags: + - Matplotlib + - 线性图 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(四):线性图的绘制。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105839855 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】方法描述 + +`matplotlib.pyplot.plot()` 函数可以用于绘制线性图。 + +本文用到的其他图像属性可参考前面的两篇文章: + +[《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) +[《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) + +基本语法:`matplotlib.pyplot.plot(x, y[, fmt, \*\*kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| x | x 轴数据,数组类型或者标量,x 值是可选的,默认为 `range(len(y))`,通常为一维数组 | +| y | y 轴数据,数组类型或者标量,通常为一维数组 | +| fmt | str 类型,格式字符串,由标记、线条和颜色部分组成
`fmt = '[marker][line][color]'`,例如 `ro` 表示红色圆圈,三个参数的取值见后表 | +| **kwargs | 可选项,其他 [Line2D](https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D) 属性,常用属性见下表 | + +部分常见 Line2D 属性如下表,完整属性参见[官方文档](https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D)。 + + +| 属性 | 描述 | +| ------ | ------ | +| alpha | 线条透明度,float 类型,取值范围:`[0, 1]`,默认为 1.0,即不透明 | +| antialiased / aa | 是否使用抗锯齿渲染,默认为 True | +| color / c | 线条颜色,支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 [Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| linestyle / ls | 线条样式:`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'`
`':'` or `'dotted'`, `'none'` or `' '` or `''` | +| linewidth / lw | 线条宽度,float 类型,默认 0.8 | +| markeredgecolor / mec | marker 标记的边缘颜色 | +| markeredgewidth / mew | marker 标记的边缘宽度 | +| markerfacecolor / mfc | marker 标记的颜色 | +| markerfacecoloralt / mfcalt | marker 标记的备用颜色 | +| markersize / ms | marker 标记的大小 | + +fmt 中 `marker`、`line`、`color` 三个参数的取值: + +
marker:线条标记样式(线条上每个数据点的样式)
+ +| 字符 | 描述 | +| ------ | ------ | +| `'.'` | 点标记(point marker) | +| `','` | 像素点标记(pixel marker) | +| `'o'` | 圆圈标记(circle marker) | +| `'v'` | 下三角标记(triangle_down marker) | +| `'^'` | 上三角标记(triangle_up marker) | +| `'<'` | 左三角标记(triangle_left marker) | +| `'>'` | 右三角标记(triangle_right marker) | +| `'1'` | 下三叉星标记(tri_down marker) | +| `'2'` | 上三叉星标记(tri_up marker) | +| `'3'` | 左三叉星标记(tri_left marker) | +| `'4'` | 右三叉星标记(tri_right marker) | +| `'s'` | 正方形标记(square marker) | +| `'p'` | 五角形标记(pentagon marker) | +| `'*'` | 星号标记(star marker) | +| `'h'` | 六边形标记(hexagon1 marker) | +| `'H'` | 六边形标记(hexagon2 marker) | +| `'+'` | 加号标记(plus marker) | +| `'x'` | X 号标记(x marker) | +| `'D'` | 菱形标记(diamond marker) | +| `'d'` | 细菱形标记(thin_diamond marker) | +| `'|'` | 垂直线标记(vline marker) | +| `'_'` | 水平线标记(hline marker) | + +
line:线条样式
+ +| 字符 | 描述 | +| ------ | ------ | +| `'-'` | 实线样式(solid line style) | +| `'--'` | 虚线样式(dashed line style) | +| `'-.'` | 点划线样式(dash-dot line style) | +| `':'` | 点样式(dotted line style) | + +
color:线条颜色,支持英文颜色名称及其简写、十六进制颜色码等 +
+ +| 字符 | 描述 | +| ------ | ------ | +| `'b'` | 蓝色(blue) | +| `'g'` | 绿色(green) | +| `'r'` | 红色(red) | +| `'c'` | 青色(cyan) | +| `'m'` | 品红(magenta) | +| `'y'` | 黄色(yellow) | +| `'k'` | 黑色(black) | +| `'w'` | 白色(white) | + +fmt 举例: + +```powershell +'b' # 默认形状的蓝色标记 +'or' # 红圈 +'-g' # 绿色实线 +'--' # 默认颜色的虚线 +'^k:' # 黑色三角形标记,由虚线连接 +``` + +## 【2x00】基本示例 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 设置显示中文 + +x = np.arange(-2*np.pi, 2*np.pi, 0.01) +y = np.sin(3*x)/x +plt.title('线性图示例') # 设置标题 +plt.xlabel('x 轴') # 设置 x 轴标签 +plt.ylabel('y 轴') # 设置 y 轴标签 + +plt.plot(x, y) +plt.show() +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/01.png) + +## 【3x00】多条数据 + +绘制多条数据,设置不同数据,然后多次调用 `plt.plot()` 函数即可,不同数据的线条颜色会不同,系统随机,可单独指定不同颜色。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x)/x +y2 = np.sin(2*x)/x +y3 = np.sin(1*x)/x +plt.title('多数据线性图示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x, y1) +plt.plot(x, y2) +plt.plot(x, y3) + +plt.show() +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/02.png) + +## 【4x00】设置颜色 / 样式 / 图例 + +设置线条颜色样式等属性直接在 `plot()` 函数里面添加相应参数即可,设置图例则需要调用 `legend()` 方法。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x1 = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x1)/x1 +y2 = np.sin(2*x1)/x1 + +x3 = np.arange(-2*np.pi, 2*np.pi, 2) +y3 = np.array([0, 2, 1.5, 1, 2.4, -0.2, 1.7]) + +plt.title('线性图自定义样式示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x1, y1, '--r', label='x1, y1') # 线条样式为 --,颜色为 r(红色) +plt.plot(x1, y2, color='green', label='x1, y2') # 样式默认,颜色为绿色 +plt.plot(x3, y3, marker='o', mfc='r', linestyle=':', label='x3, y3') # 标记样式为 o,颜色为 r(红色),线条样式为 : +plt.legend(edgecolor='#87A3CC', facecolor='#F5F5F5') # 图例 + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/03.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105839855 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【5x00】设置刻度 + +调用 `xticks()` 和 `yticks()` 函数可以对坐标刻度进行自定义,该函数接收两个参数,第一个参数表示要显示的刻度位置,第二个参数表示在对应刻度线上要显示的标签信息,标签信息支持 LeTeX 数学公式,使用时要用美元符号 `$` 包围起来。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x)/x +y2 = np.sin(2*x)/x +y3 = np.sin(1*x)/x +plt.title('线性图设置刻度示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x, y1, '--r', label='sin(3*x)/x') +plt.plot(x, y2, color='green', linestyle=':', label='sin(2*x)/x') +plt.plot(x, y3, label='sin(1*x)/x') +plt.legend(edgecolor='#87A3CC', facecolor='#F5F5F5') + +plt.xticks((-2*np.pi, -np.pi, 0, np.pi, 2*np.pi), (r'$-2\pi$', r'$-\pi$', '$0$', r'$\pi$', r'$2\pi$')) +plt.yticks((-1, 0, 1, 2, 3)) + +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/04.png) + +## 【6x00】隐藏画布边框 + +Matplotlib 所绘制的图表中的每个绘图元素,例如线条 Line2D、文字 Text、刻度等在内存中都有一个对象与之对应。 + +`matplotlib.pyplot.gca()` 函数用于获取当前的绘图区 `Axes`(Get Current Axes) + +`matplotlib.pyplot.gcf()` 函数用于获取当前的画布 `Figure`(Get Current Figure) + +例如:`matplotlib.pyplot.plot()` 实际上会通过 `matplotlib.pyplot.gca()` 获得当前的 `Axes` 对象 `ax`,然后再调用 `ax.plot()` 方法实现真正的绘图。我们可以通过这种方法来实现画布边框的隐藏和坐标轴的移动。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x)/x +y2 = np.sin(2*x)/x +y3 = np.sin(1*x)/x +plt.title('线性图隐藏画布边框示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x, y1, '--r', label='sin(3*x)/x') +plt.plot(x, y2, color='green', linestyle=':', label='sin(2*x)/x') +plt.plot(x, y3, label='sin(1*x)/x') +plt.legend(edgecolor='#87A3CC', facecolor='#F5F5F5') + +plt.xticks((-2*np.pi, -np.pi, 0, np.pi, 2*np.pi), (r'$-2\pi$', r'$-\pi$', '$0$', r'$\pi$', r'$2\pi$')) +plt.yticks((-1, 0, 1, 2, 3)) + +ax = plt.gca() # 获取当前的画布, gca = get current axes +ax.spines['right'].set_visible(False) # 获取绘图区的轴对象(spines),设置右边框不显示 +ax.spines['top'].set_visible(False) # 获取绘图区的轴对象(spines),设置上边框不显示 +# ax.spines['right'].set_color('none') # 设置颜色为 none,效果与上面的一致 +# ax.spines['top'].set_color('none') + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/05.png) + +## 【7x00】移动坐标轴 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x)/x +y2 = np.sin(2*x)/x +y3 = np.sin(1*x)/x +plt.title('线性图移动坐标轴示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x, y1, '--r', label='sin(3*x)/x') +plt.plot(x, y2, color='green', linestyle=':', label='sin(2*x)/x') +plt.plot(x, y3, label='sin(1*x)/x') +plt.legend(edgecolor='#87A3CC', facecolor='#F5F5F5') + +plt.xticks((-2*np.pi, -np.pi, 0, np.pi, 2*np.pi), (r'$-2\pi$', r'$-\pi$', '$0$', r'$\pi$', r'$2\pi$')) +plt.yticks((-1, 0, 1, 2, 3)) + +ax = plt.gca() # 获取当前的画布, gca = get current axes +ax.spines['right'].set_visible(False) # 获取绘图区的轴对象(spines),设置右边框不显示 +ax.spines['top'].set_visible(False) # 获取绘图区的轴对象(spines),设置上边框不显示 +# ax.spines['right'].set_color('none') # 设置颜色为 none,效果与上面的一致 +# ax.spines['top'].set_color('none') + +ax.spines['left'].set_position(('data', 0)) # 设置两个坐标轴在(0, 0)位置相交 +ax.spines['bottom'].set_position(('data', 0)) +ax.xaxis.set_ticks_position('bottom') # 设置 x 坐标轴标签的位置 +ax.yaxis.set_ticks_position('left') # 设置 y 坐标轴标签的位置 + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/06.png) + +## 【8x00】指定位置显示文本 + +`matplotlib.pyplot.annotate()` 方法可以在指定坐标点添加文本或 LaTeX 描述,也可以在其他位置添加描述后,使用箭头指向某个坐标点。 + +基本语法:`matplotlib.pyplot.annotate(text, xy, xytext, xycoords, textcoords, ha, va, arrowprops, \*\*kwargs)` + +| 参数 | 描述 | +| ------ | ------ | +| text | str 类型,注释的文本 | +| xy | 被注释的坐标点,格式:`(x, y)` | +| xytext | 注释文本的坐标点,格式:`(x, y)`,默认与 xy 相同 | +| xycoords | 被注释的坐标点的参考系,取值参见**表一**,默认为 'data' | +| textcoords | 注释文本的坐标点的参考系,取值参见**表二**,默认为 xycoords 的值 | +| ha | 注释点在注释文本的左边、右边或中间(`left`、`right`、`center`) | +| va | 注释点在注释文本的上边、下边、中间或基线 (`top`、`bottom`、`center`、`baseline`) | +| arrowprops | dict 字典类型,箭头的样式
如果 arrowprops 不包含键 arrowstyle,则允许的键参见**表三**
如果 arrowprops 包含键 arrowstyle,则允许的键参见**表四** | + +
表一:xycoords 取值类型
+ +| 取值 | 描述 | +| ------ | ------ | +| 'figure points' | 以画布左下角为参考,单位为点数 | +| 'figure pixels' | 以画布左下角为参考,单位为像素 | +| 'figure fraction' | 以画布左下角为参考,单位为百分比 | +| 'axes points' | 以绘图区左下角为参考,单位为点数 | +| 'axes pixels' | 以绘图区左下角为参考,单位为像素 | +| 'axes fraction' | 以绘图区左下角为参考,单位为百分比 | +| 'data' | 使用被注释对象的坐标系,即数据的 x, y 轴(默认) | +| 'polar' | 使用(θ,r)形式的极坐标系 | + +
表二:textcoords 取值类型
+ +| 取值 | 描述 | +| ------ | ------ | +| 'figure points' | 以画布左下角为参考,单位为点数 | +| 'figure pixels' | 以画布左下角为参考,单位为像素 | +| 'figure fraction' | 以画布左下角为参考,单位为百分比 | +| 'axes points' | 以绘图区左下角为参考,单位为点数 | +| 'axes pixels' | 以绘图区左下角为参考,单位为像素 | +| 'axes fraction' | 以绘图区左下角为参考,单位为百分比 | +| 'data' | 使用被注释对象的坐标系,即数据的 x, y 轴 | +| 'polar' | 使用(θ,r)形式的极坐标系 | +| 'offset points' | 相对于被注释点的坐标 xy 的偏移量,单位是点 | +| 'offset pixels' | 相对于被注释点的坐标 xy 的偏移量,单位是像素 | + +
表三:arrowprops 不包含键 arrowstyle 时的取值
+ +| 键 | 描述 | +| ------ | ------ | +| width | 箭头的宽度,以点为单位 | +| headwidth | 箭头底部的宽度,以点为单位 | +| headlength | 箭头的长度,以点为单位 | +| shrink | 箭头两端收缩占总长的百分比 | +| ? | 其他 [matplotlib.patches.FancyArrowPatch](https://matplotlib.org/api/_as_gen/matplotlib.patches.FancyArrowPatch.html#matplotlib.patches.FancyArrowPatch) 中的关键字,部分常用关键字参见**表五** | + +
表四:arrowprops 包含键 arrowstyle 时的取值
+ +| 取值 | 描述 | +| ------ | ------ | +| `'-'` | None | +| `'->'` | head_length=0.4,head_width=0.2 | +| `'-['` | widthB=1.0,lengthB=0.2,angleB=None | +| `']-'` | widthA=1.0, lengthA=0.2, angleA=None | +| `]-[` | widthA=1.0, lengthA=0.2, angleA=None, widthB=1.0, lengthB=0.2, angleB=None | +| `'|-|'` | widthA=1.0,widthB=1.0 | +| `'-|>'` | head_length=0.4,head_width=0.2 | +| `'<-'` | head_length=0.4,head_width=0.2 | +| `'<->'` | head_length=0.4,head_width=0.2 | +| `'<|-'` | head_length=0.4,head_width=0.2 | +| `'<|-|>'` | head_length=0.4,head_width=0.2 | +| `'fancy'` | head_length=0.4,head_width=0.4,tail_width=0.4 | +| `'simple'` | head_length=0.5,head_width=0.5,tail_width=0.2 | +| `'wedge'` | tail_width=0.3,shrink_factor=0.5 | + +
表五:matplotlib.patches.FancyArrowPatch 常用的键
+ +| 键 | 描述 | +| ------ | ------ | +| arrowstyle | 箭头样式,取值参见**表四** | +| connectionstyle | 连接方式,默认为 `arc3`,有以下五种取值:
`angle`:angleA=90, angleB=0, rad=0.0
`angle3`:angleA=90, angleB=0
`arc`:angleA=0, angleB=0, armA=None, armB=None, rad=0.0
`arc3`:rad=0.0
`bar`:armA=0.0, armB=0.0, fraction=0.3, angle=None
angle 为箭头旋转的角度,rad 为弧度 | +| relpos | 箭头起始点相对注释文本的位置,默认为 (0.5, 0.5),即文本的中心
(0,0)表示左下角,(1,1)表示右上角 | +| patchA | 箭头起点处的图形,默认为文本的边框 | +| patchB | 箭头终点处的图形,默认为空 | +| shrinkA | 箭头起点的缩进点数,默认为2 | +| shrinkB | 箭头终点的缩进点数,默认为2 | +| ? | 其他键值,参见官方文档 [matplotlib.patches.PathPatch](https://matplotlib.org/api/_as_gen/matplotlib.patches.PathPatch.html#matplotlib.patches.PathPatch) | + +
connectionstyle 样式举例
+ +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/07.png) + +应用举例: + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x)/x +y2 = np.sin(2*x)/x +y3 = np.sin(1*x)/x +plt.title('线性图显示文本注释示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x, y1, '--r', label='sin(3*x)/x') +plt.plot(x, y2, color='green', linestyle=':', label='sin(2*x)/x') +plt.plot(x, y3, label='sin(1*x)/x') +plt.legend(edgecolor='#87A3CC', facecolor='#F5F5F5') + +plt.xticks((-2*np.pi, -np.pi, 0, np.pi, 2*np.pi), (r'$-2\pi$', r'$-\pi$', '$0$', r'$\pi$', r'$2\pi$')) +plt.yticks((-1, 0, 1, 2, 3)) + +ax = plt.gca() # 获取当前的画布, gca = get current axes +ax.spines['right'].set_visible(False) # 获取绘图区的轴对象(spines),设置右边框不显示 +ax.spines['top'].set_visible(False) # 获取绘图区的轴对象(spines),设置上边框不显示 +# ax.spines['right'].set_color('none') # 设置颜色为 none,效果与上面的一致 +# ax.spines['top'].set_color('none') + +ax.spines['left'].set_position(('data', 0)) # 设置两个坐标轴在(0, 0)位置相交 +ax.spines['bottom'].set_position(('data', 0)) +ax.xaxis.set_ticks_position('bottom') # 设置 x 坐标轴标签的位置 +ax.yaxis.set_ticks_position('left') # 设置 y 坐标轴标签的位置 + +plt.annotate(r'$\lim_{x\to 0}\frac{\sin(x)}{x}=1$', # 插入 LaTeX 表达式 + xy=[0, 1], # 被标记的坐标 + xycoords='data', # 被标记的坐标的参考系 + xytext=[30, 30], # 注释文本的坐标 + textcoords='offset points', # 注释文本的坐标的参考系 + fontsize=16, # 字体大小 + arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=.2")) # 箭头样式 + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A71/08.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105839855 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A72-Matplotlib-05.md b/source/_posts/A72-Matplotlib-05.md new file mode 100644 index 0000000000000000000000000000000000000000..b0fb7bbb08ca1b66ecc3a782d1d26c52b5ab0425 --- /dev/null +++ b/source/_posts/A72-Matplotlib-05.md @@ -0,0 +1,434 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 +tags: + - Matplotlib + - 散点图 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(五):散点图的绘制。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105914929 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】方法描述 + +`matplotlib.pyplot.scatter()` 方法可用于绘制散点图。 + +本文用到的其他图像属性可参考前面的两篇文章: + +[《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) +[《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) + +基本语法:`matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None, alpha=None, linewidths=None, edgecolors=None, \*\*kwargs)` + +| 参数 | 描述 | +| ------ | ------ | +| x,y | 数据位置,标量或类似数组的形式 | +| s | 标记的大小,以磅为单位,默认 `rcParams['lines.markersize'] ** 2`,即 6**2=36 | +| color / c | 标记的颜色,可以是单个颜色或者一个颜色列表
支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 [Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| marker | 标记的样式,默认为 `rcParams["scatter.marker"] = 'o'`,更多样式参见**表一** | +| cmap | 将浮点数映射成颜色的颜色映射表,即一个 [Colormap](https://matplotlib.org/api/_as_gen/matplotlib.colors.Colormap.html#matplotlib.colors.Colormap) 实例或注册的颜色表名,仅当 c 是浮点数数组时才使用 cmap | +| alpha | 标记的透明度,float 类型,取值范围:[0, 1],默认为 1.0,即不透明 | +| linewidths | 标记边缘的线宽,默认为 `rcParams["lines.linewidth"] = 1.5` | +| edgecolors | 标记边缘的颜色,可以是单个颜色或者一个颜色列表
支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 [Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | + +
表一:marker 标记的样式
+ +| 标记 | 描述 | +| ------ | ------ | +| `"."` | 点 | +| `","` | 像素点 | +| `"o"` | 圆圈 | +| `"v"` | 倒三角 | +| `"^"` | 正三角 | +| `"<"` | 左三角 | +| `">"` | 右三角 | +| `"1"` | 倒三叉星 | +| `"2"` | 正三叉星(类似奔驰车标形状) | +| `"3"` | 左三叉星 | +| `"4"` | 右三叉星 | +| `"8"` | 八边形 | +| `"s"` | 正方形 | +| `"p"` | 五边形 | +| `"P"` | 填充的加号(粗加号) | +| `"+"` | 加号 | +| `"*"` | 星形 | +| `"h"` | 六边形(底部是角) | +| `"H"` | 六边形(底部是边) | +| `"x"` | x 号 | +| `"X"` | 填充的 x 号(粗 x 号) | +| `"D"` | 粗菱形(对角线相等) | +| `"d"` | 细菱形(对角线不等) | +| `"|"` | 垂直线 | +| `"_"` | 水平线 | +| `0` | 水平线靠左 | +| `1` | 水平线靠右 | +| `2` | 垂直线靠上 | +| `3` | 垂直线靠下 | +| `4` | 左三角(比 `"<"` 更细) | +| `5` | 右三角(比 `">"` 更细) | +| `6` | 正三角(比 `"^"` 更细) | +| `7` | 倒三角(比 `"v"` 更细) | +| `8` | 左三角(比 `"<"` 更细,靠左显示) | +| `9` | 右三角(比 `">"` 更细,靠右显示) | +| `10` | 正三角(比 `"^"` 更细,靠上显示) | +| `11` | 倒三角(比 `"v"` 更细,靠下显示) | +| `"None"` / `" "` / `""` | 无样式 | +| `'$...$'` | 支持 LaTeX 数学公式,表达式用美元符号包围起来 | + +## 【2x00】简单示例 + +```python +import numpy as np +import matplotlib.pyplot as plt + +x = np.arange(0, 10, 1) +y = np.array([3, 8, 1, 5, 7, 2, 3, 4, 5, 7]) +plt.scatter(x, y) + +plt.show() +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/01.png) + +## 【3x00】多条数据 + +绘制多条数据,设置不同数据,然后多次调用 `plt.scatter()` 函数即可,不同数据的线条颜色会不同,系统随机,可单独指定不同颜色。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2*np.pi, 2*np.pi, 1) +y1 = np.sin(3*x)/x +y2 = np.sin(2*x)/x +y3 = np.sin(1*x)/x +plt.title('多数据散点图示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.scatter(x, y1) +plt.scatter(x, y2) +plt.scatter(x, y3) + +plt.show() +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/02.png) + +## 【4x00】设置颜色 / 样式 / 图例 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2*np.pi, 2*np.pi, 1) +y1 = np.sin(3*x)/x +y2 = np.sin(2*x)/x +y3 = np.sin(1*x)/x +plt.title('散点图自定义样式示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.scatter(x, y1, color='g', s=30, label='(x, y1)') # 默认绿色样式 +plt.scatter(x, y2, color='r', s=40, marker='d', label='(x, y2)') # 红色菱形 +plt.scatter(x, y3, color='b', s=50, marker='2', label='(x, y3)') # 蓝色正三叉星 + +plt.legend(framealpha=0) # 显示图例,设置为全透明 + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/03.png) + +## 【5x00】指定位置显示文本注释 + +`matplotlib.pyplot.annotate()` 方法可以在指定位置显示文本注释,参数解释常见前文: +[《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) + +应用举例: + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [0.13, 0.22, 0.39, 0.59, 0.68, 0.74, 0.93] +y = [0.75, 0.34, 0.44, 0.52, 0.80, 0.25, 0.55] + +plt.title('散点图添加文本注释示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') +plt.xlim([0, 1]) # 设置 x 轴刻度的范围 +plt.ylim([0, 1]) # 设置 y 轴刻度的范围 + +plt.scatter(x, y, marker='o', s=50) +for m, n in zip(x, y): + plt.annotate('(%s,%s)' % (m, n), + xy=(m, n), + xytext=(0, -10), + textcoords='offset points', + ha='center', # 点在注释文本的中心 + va='top') # 点在注释文本的上方 + +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/04.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105914929 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【6x00】随机数据散点图 + +随机数据可以用 numpy 的 random 模块来实现。 + +`numpy.random.rand(d0, d1, …, dn)`:根据给定维度生成 [0,1) 之间的数据。 + +`numpy.random.randn(d0, d1, …, dn)` :返回一个或一组具有标准正态分布的样本。 + +`numpy.random.randint(low, high, size)`:返回随机整数,范围区间为 [low,high),size 为数组维度大小 + +应用举例: + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +N = 1000 +x = np.random.randn(N) +y = np.random.randn(N) + +plt.title('散点图随机数据示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') +plt.scatter(x, y, alpha=0.5) + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/05.png) + + +## 【7x00】随机颜色与色条 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +N = 1000 +x = np.random.randn(N) +y = np.random.randn(N) + +color = np.random.rand(N) +size = np.random.rand(N) * 1000 + +plt.figure(figsize=(8.4, 5.8)) # 设置画布大小 840x580 +plt.title('散点图随机大小颜色示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') +plt.scatter(x, y, c=color, s=size, alpha=0.5) + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/06.png) + +可以用 `pyplot.colorbar()` 方法绘制颜色对照条。 + +基本语法:`matplotlib.pyplot.colorbar([mappable=None, cax=None, ax=None, **kw])` + +部分参数解释如下表,其他参数,如长度,宽度等请参考[官方文档](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.colorbar.html)。 + +| 参数 | 描述 | +| ------ | ------ | +| mappable | 要设置色条的图像对象,该参数对于 `Figure.colorbar` 方法是必需的,但对于 `pyplot.colorbar` 函数是可选的 | +| cax | 可选项,要绘制色条的轴 | +| ax | 可选项,设置色条的显示位置,通常在一个画布上有多个子图时使用 | +| **kw | 可选项,其他关键字参数,参考[官方文档](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.colorbar.html) | + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +N = 1000 +x = np.random.randn(N) +y = np.random.randn(N) + +color = np.random.rand(N) +size = np.random.rand(N) * 1000 + +plt.figure(figsize=(8.4, 5.8)) +plt.title('散点图颜色对照条示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') +plt.scatter(x, y, c=color, s=size, alpha=0.5) +plt.colorbar() + +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/07.png) + +## 【8x00】不同图像之间的层级调整 + +`zorder` 参数用于设置不同图像之间的层级关系,数字越大,所处的层级越大,即显示越靠上。 + +未设置 `zorder` 参数前: + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x1 = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x1)/x1 +x2 = np.arange(-2*np.pi, 2*np.pi, 1) +y2 = np.sin(3*x2)/x2 + +plt.title('不同图像之间层级调整示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x1, y1, c='b', linewidth=3.5, label='线性图') +plt.scatter(x2, y2, c='r', s=40, label='散点图') +plt.legend() + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/08.png) + +设置 `zorder` 参数后: + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x1 = np.arange(-2*np.pi, 2*np.pi, 0.01) +y1 = np.sin(3*x1)/x1 +x2 = np.arange(-2*np.pi, 2*np.pi, 1) +y2 = np.sin(3*x2)/x2 + +plt.title('不同图像之间层级调整示例') +plt.xlabel('x 轴') +plt.ylabel('y 轴') + +plt.plot(x1, y1, zorder=1, c='b', linewidth=3.5, label='线性图') +plt.scatter(x2, y2, zorder=2, c='r', s=40, label='散点图') +plt.legend() + +plt.show() +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/09.png) + +## 【9x00】框选部分数据 + +有时候我们希望能够框选一部分数据来强调其重要性,`matplotlib.patches.Polygon()` 方法的作用是生成不规则的多边形补丁,`matplotlib.patches` 还有另外的方法可以生成矩形、圆形等其他图形,具体参见前面的文章[《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143),生成补丁之后,通过 `axes.add_patch()` 方法将其添加到绘图区(axes)即可。 + +```python +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.patches as mpathes + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +plt.figure(figsize=(8.4, 5.8)) + +x1 = np.arange(0, 1000, 10) +y1 = np.random.randint(0, 1000, 100) +x2 = np.arange(0, 500, 10) +y2 = np.random.randint(200, 800, 50) +x3 = np.random.randint(50, 800, 80) +y3 = np.random.randint(50, 800, 80) +x4 = np.array([0, 100, 300, 400, 350, 500, 450, 367, 420, 490]) +y4 = np.array([267, 800, 453, 500, 600, 420, 380, 503, 390, 600]) + +plt.title('散点图数据框选示例', fontsize=15) +plt.xlabel('x 轴', fontsize=15) +plt.ylabel('y 轴', fontsize=15) +plt.scatter(x1, y1, c='r', s=50, alpha=0.7, label='RED') +plt.scatter(x2, y2, c='b', s=100, alpha=0.7, label='BLUE') +plt.scatter(x3, y3, c='g', s=150, alpha=0.7, label='GREEN') +plt.scatter(x4, y4, c='y', s=250, alpha=0.7, label='YELLOW') +plt.legend(loc='upper right', borderpad=1, edgecolor='k', framealpha=1, labelspacing=1) + +Polygon_point = [[100, 800], [0, 267], [500, 420], [490, 600]] # 多边形补丁的顶点坐标 +polygon = mpathes.Polygon(Polygon_point, color='#FF69B4', alpha=0.3) # 绘制补丁,框选部分数据 +ax = plt.gca() # 获取当前绘图区(gca = Get Current Axes) +ax.add_patch(polygon) # 将补丁添加到当前绘图区 + +plt.show() +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A72/10.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105914929 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A73-Matplotlib-06.md b/source/_posts/A73-Matplotlib-06.md new file mode 100644 index 0000000000000000000000000000000000000000..ded1cb440229a015c5d60c62ce6a45d9074e690f --- /dev/null +++ b/source/_posts/A73-Matplotlib-06.md @@ -0,0 +1,673 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(六):直方图/柱状图/条形图的绘制 +tags: + - Matplotlib + - 直方图 + - 柱状图 + - 条形图 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(六):直方图、柱状图、条形图的绘制。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105952856 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】直方图 / 柱状图 / 条形图的区别 + +- 直方图:直方图(Histogram)又称质量分布图,是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况。**一般用于描述连续型数据的分布关系**,用横轴表示数据类型,纵轴表示分布情况。直方图是用面积表示各组频数的多少,矩形的高度表示每一组的频数或频率,宽度则表示各组的组距,因此其**高度与宽度均有意义**。其次,由于分组数据具有连续性,**直方图的各矩形通常是连续排列。** + +- 柱状图:柱状图(bar chart)又称条图、长条图、柱状统计图、条状图、棒形图,是一种以长方形的长度为变量的统计图表。**一般用于描述离散型分类数据的对比**,长条图用来比较两个或以上的价值(不同时间或者不同条件),只有一个变量,通常利用于较小的数据集分析。柱状图亦可横向排列,或用多维方式表达。**柱状图各矩形的宽度固定,矩形之间分开排列,会有间距。** + +- 条形图:通常情况下**条形图 = 柱状图**,也可以**将横向排列的柱状图称为条形图**。在本文中会将条形图视为后者。 + +![分割线](https://img-blog.csdnimg.cn/20200509010455973.png) + +## 【2x00】直方图的绘制 + +### 【2x01】函数介绍 matplotlib.pyplot.hist() + +`matplotlib.pyplot.hist()` 函数用于绘制直方图。 + +基本语法:`matplotlib.pyplot.hist(x[, bins=None, range=None, density=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, \*\*kwargs])` + +基本参数: + +| 参数 | 描述 | +| ------ | ------ | +| x | 数据集,数组或数组序列 | +| bins | 统计的分布区间、条形数,可以是整数、序列或字符串,默认 `rcParams["hist.bins"] =10`
如果 bins 是整数,则定义的是等宽的矩形的个数
如果 bins 是序列,则定义的是每个矩形的区间,如:`bins = [1, 2, 3, 4]`,则矩形分布区间为 `[1,2)`、`[2,3)`、`[3,4]`
如果 bins 是字符串,则它应该是 [numpy.histogram_bin_edges](https://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram_bin_edges.html#numpy.histogram_bin_edges) 所支持的策略之一 | +| range | 矩形分布的区间,在没有指定 bins 生效,元组类型 | +| density | 是否**显示频率统计结果**,`频率统计结果=区间数目/(总数*区间宽度)` | +| bottom | y 轴的起始位置,默认为 0 | +| histtype | 矩形的样式,有四种类型可选:
`'bar'`:默认值,传统的条形直方图,如果给出多个数据,则条形图并排排列
`'barstacked'`:当数据为 1 个时,和 bar 结果一样,当数据为多个时,则进行垂直堆叠
`'step'`:未填充的线条形式;`'stepfilled'`:填充的线条形式,效果与 bar 差不多 | +| align | 矩形的中心位于 bins(x 轴) 的位置,`'left'`:左;`'mid'`:中;`'right'`:右 | +| orientation | 矩形的方向,`vertical`:垂直;`horizontal`:水平 | +| rwidth | 矩形的相对宽度,如果未指定,则自动计算宽度 | +| log | y 坐标轴是否以指数刻度显示 | +| color | 矩形的颜色,默认蓝色,与 facecolor 作用相同,指定一个即可,如果两者都指定,则取 facecolor 的值 | +| label | 数据的标签,展示图例时使用 | +| stacked | 是否为堆积状图(当两个数据相似时,堆积在一起就会把第一个数据的显示相对缩小一点) | + +其他参数: + +| 参数 | 描述 | +| ------ | ------ | +| facecolor | 标量或数组类型,每个矩形的颜色,与 color 作用相同,指定一个即可,如果两者都指定,则取 facecolor 的值 | +| edgecolor | 标量或数组类型,直方图边缘线的颜色 | +| linewidth | 标量或数组类型,直方图边缘线的宽度,如果为 0,则不绘制边 | +| alpha | float 类型,矩形透明度 | +| label | 图例中显示的标签 | +| linestyle / ls | 线条样式,此处指矩形边缘线条样式
`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'` or `':'` or `'dotted'`, `'none'` or `' '` or `''` | +| linewidth / lw | 线条宽度,此处指矩形边缘线的宽度,float 类型,默认 0.8 | +| hatch | 矩形的填充图案,可以是组合形式,如果有相同的图案,则会增加填充的密度
取值可以是:`'/'`, `'\'`, `'|'`, `'-'`, `'+'`, `'x'`, `'o'`, `'O'`, `'.'`, `'*'` | + + +### 【2x02】简单直方图示例 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 设置中文显示 + +x = np.random.randint(0, 101, 100) # 数据集 +bins = np.arange(0, 101, 10) # 分布区间 [0,10)、[10,20)...[90,100] + +plt.hist(x, bins=bins, linewidth=0.5, edgecolor='k') # 边缘线宽0.5,颜色为黑色 +plt.xlim(0, 100) # x 轴刻度范围 +plt.title('简单直方图示例') # 标题 +plt.xlabel('x axis label') # x 轴标签 +plt.ylabel('y axis label') # y 轴标签 + +plt.show() +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/01.png) + +### 【2x03】堆积的直方图 + +参数 `stacked` 决定了将两份数据进行堆积显示。注意,有可能两个数据相似(y 轴的值相似),但是堆积在一起的时候,会把第一个数据的显示相对缩小一点。 + +```python +import matplotlib.pyplot as plt +import numpy as np + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +hist1 = np.random.randint(0, 100, 100) +hist2 = np.random.randint(0, 100, 100) +x = [hist1, hist2] +colors = ['orchid', 'deepskyblue'] +labels = ['hist1', 'hist2'] +bins = range(0, 101, 10) + +# 绘制两份数据的直方图,数据集等其他参数可以使用列表形式传递,也可以使用两次 hist 函数单独传递 +plt.hist(x, bins=bins, color=colors, stacked=True, label=labels) +plt.title('堆积的直方图示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend(loc="upper left") + +plt.show() +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/02.png) + +### 【2x04】填充其他样式 + +`hatch` 参数可以让直方图的矩形填充其他样式,可选值有:`'/'`, `'\'`, `'|'`, `'-'`, `'+'`, `'x'`, `'o'`, `'O'`, `'.'`, `'*'`。可以是不同图案的组合形式,如果有相同的图案,则会增加填充的密度。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 设置中文显示 + +x = np.random.randint(0, 101, 100) # 数据集 +bins = np.arange(0, 101, 10) # 分布区间 [0,10)、[10,20)...[90,100] + +# 矩形颜色为白色,使用 / 填充,边缘线宽0.5,颜色为黑色 +plt.hist(x, bins=bins, color='w', hatch='///', linewidth=0.5, edgecolor='k') +plt.xlim(0, 100) # x 轴刻度范围 +plt.title('直方图图案填充示例') # 标题 +plt.xlabel('x axis label') # x 轴标签 +plt.ylabel('y axis label') # y 轴标签 + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/03.png) + +![分割线](https://img-blog.csdnimg.cn/20200509010455973.png) + +## 【3x00】柱状图的绘制 + +### 【3x01】函数介绍 matplotlib.pyplot.bar() + +`matplotlib.pyplot.bar()` 函数用于绘制柱状图。 + +基本语法:`matplotlib.pyplot.bar(x, height[, width=0.8, bottom=None, align='center', \*\*kwargs])` + +基本参数: + +| 参数 | 描述 | +| ------ | ------ | +| x | 标量序列,每个矩形对应的 x 轴刻度 | +| height | 标量或标量序列,每个矩形对应的高度,即 y 轴刻度 | +| width | 标量或数组类型,每个矩形的宽度,默认为 0.8 | +| bottom | 标量或数组类型,y 轴的起始位置,默认为 0 | +| align | 矩形与 x 轴刻度对齐的位置,`'center'`:中;`'edge'`:左边缘 | + +其他参数: + +| 参数 | 描述 | +| ------ | ------ | +| color | 标量或数组类型,每个矩形的颜色,与 facecolor 作用相同,指定一个即可,如果两者都指定,则取 facecolor 的值 | +| edgecolor | 标量或数组类型,柱状图边缘线的颜色 | +| linewidth | 标量或数组类型,柱状图边缘线的宽度,如果为0,则不绘制边 | +| tick_label | 标量或数组类型,柱状图 x 轴的刻度标签,默认使用数字标签 | +| xerr / yerr | 标量,指定对应标准差(添加误差线时会用到) | +| ecolor | 标量或数组类型,误差线的线条颜色,默认值为 black | +| capsize | 标量,误差线两头横线的宽度,默认为 `rcParams["errorbar.capsize"] = 0.0` | +| error_kw | 字典类型,可以此字典中定义 ecolor 和 capsize,比单独指定的优先级要高 | +| log | bool 值,y 坐标轴是否以指数刻度显示 | +| alpha | float 类型,矩形透明度 | +| label | 图例中显示的标签 | +| linestyle / ls | 线条样式,此处指矩形边缘线条样式
`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'` or `':'` or `'dotted'`, `'none'` or `' '` or `''` | +| linewidth / lw | 线条宽度,此处指矩形边缘线的宽度,float 类型,默认 0.8 | +| hatch | 矩形的填充图案,可以是组合形式,如果有相同的图案,则会增加填充的密度
取值可以是:`'/'`, `'\'`, `'|'`, `'-'`, `'+'`, `'x'`, `'o'`, `'O'`, `'.'`, `'*'` | + +### 【3x02】简单柱状图示例 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [1, 2, 3, 4, 5] +height = [5, 7, 4, 3, 1] + +# 设置 x 轴的标签,也可以用 plt.xticks 方法来设置 +tick_label = ['A', 'B', 'C', 'D', 'E'] +# 设置颜色序列 +color = ['red', 'yellow', 'peru', 'orchid', 'deepskyblue'] +# 绘制柱状图,边缘线宽度为1,颜色为黑色,样式为 -- +plt.bar(x, height, tick_label=tick_label, color=color, edgecolor='k', linewidth=1, linestyle='--') + +plt.title('简单柱状图示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/04.png) + +### 【3x03】添加与标准差的误差线 + +首先定义一个列表,其中的元素是与每个值对应的标准差,`ecolor` 和 `capsize` 参数分别指定误差线的颜色和两头横线的宽度。这两个参数可以通过 `error_kw` 字典形式组合起来。以字典形式的组合优先级别要比单独指定高。另外,柱状图指定标准差时要用 `yerr`,条形图(横向排列的柱状图)指定标准差时要用 `xerr`。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [1, 2, 3, 4, 5] +height = [5, 7, 4, 3, 2] +std = [0.5, 0.1, 1.2, 0.3, 1.0] # 标准差 + +tick_label = ['A', 'B', 'C', 'D', 'E'] # 设置 x 轴的标签,也可以用 plt.xticks 方法来设置 +color = ['red', 'yellow', 'peru', 'orchid', 'deepskyblue'] # 设置颜色序列 +plt.bar( + x, + height, + tick_label=tick_label, + color=color, + yerr=std, # 指定对应标准差 + # error_kw={ + # 'ecolor': 'k', # 指定误差线的颜色 + # 'capsize': 6 # 指定误差线两头横线的宽度 + # }, + ecolor='k', + capsize=6, + edgecolor='k', # 指定边缘线颜色 + linewidth=1 # 指定边缘线宽度 +) + +plt.title('柱状图添加误差线示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/05.png) + +### 【3x04】多序列柱状图 + +在绘制多序列的柱状图时,只需要多次调用 `matplotlib.pyplot.bar()` 函数即可,指定一个较小的宽度值(偏移量),绘制不同数据时设置不同的 x 位置刻度即可。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(5) +height1 = np.array([5, 7, 4, 3, 2]) +height2 = np.array([2, 4, 6, 7, 3]) +height3 = np.array([3, 1, 7, 5, 2]) + +# 设置宽度值(偏移量) +width = 0.3 +# 绘制不同数据时,x 轴依次增加一个偏移量 +plt.bar(x, height1, width, label='bar1') +plt.bar(x + width, height2, width, label='bar2') +plt.bar(x + width * 2, height3, width, label='bar3') + +# 设置 x 轴刻度的标签 +plt.xticks(x + width, ['A', 'B', 'C', 'D', 'E']) +plt.title('多序列柱状图示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/06.png) + +### 【3x05】堆积的柱状图 + +所谓堆积图,就是将多序列数据堆积到一个矩形上显示,在柱状图中要实现堆积图,只需要改变 `bottom` 参数即可,`bottom` 参数用于设置 y 轴基线,即柱状图的底边在 y 轴上的起始刻度,第一条数据 `data1` 的基线可以设置为 0,即默认值,第二条数据 `data2` 的基线可以设置在 `data1` 的上方,即 `bottom=data1`,第三条数据 `data3` 的基线可以设置在 `data1 + data2` 的上方,即 `bottom=data1+data2`,以此类推。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(5) +height1 = np.array([5, 7, 4, 3, 2]) +height2 = np.array([2, 4, 6, 7, 3]) +height3 = np.array([3, 1, 7, 5, 2]) + +plt.bar(x, height1, label='bar1') +plt.bar(x, height2, label='bar2', bottom=height1) +plt.bar(x, height3, label='bar3', bottom=(height2+height1)) + +plt.xticks(x, ['A', 'B', 'C', 'D', 'E']) +plt.title('堆积的柱状图示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/07.png) + +### 【3x06】填充其他样式 + +`hatch` 参数可以让柱状图的矩形填充其他样式,可选值有:`'/'`, `'\'`, `'|'`, `'-'`, `'+'`, `'x'`, `'o'`, `'O'`, `'.'`, `'*'`。可以是不同图案的组合形式,如果有相同的图案,则会增加填充的密度。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(5) +height1 = np.array([5, 7, 4, 3, 2]) +height2 = np.array([2, 4, 6, 7, 3]) +height3 = np.array([3, 1, 7, 5, 2]) + +plt.bar(x, height1, label='bar1', color='w', hatch='///') +plt.bar(x, height2, label='bar2', bottom=height1, color='w', hatch='xxx') +plt.bar(x, height3, label='bar3', bottom=(height2+height1), color='w', hatch='|||') + +plt.xticks(x, ['A', 'B', 'C', 'D', 'E']) +plt.title('柱状图图案填充示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/08.png) + +### 【3x07】添加文字描述 + +利用 `matplotlib.pyplot.text()` 方法可以在柱状图每个矩形上方添加文字描述。具体参数解释可参考前面的文章:[《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(5) +height1 = np.array([5, 7, 4, 3, 2]) +height2 = np.array([2, 4, 6, 7, 3]) +height3 = np.array([3, 1, 7, 5, 2]) + +width = 0.3 +# 绘制不同数据时,x 轴依次增加一个偏移量 +plt.bar(x, height1, width, label='bar1') +plt.bar(x + width, height2, width, label='bar2') +plt.bar(x + width * 2, height3, width, label='bar3') + +# 依次添加每条数据的标签 +for a, b in zip(x, height1): + plt.text(a, b, b, ha='center', va='bottom') +for c, d in zip(x, height2): + plt.text(c + width, d, d, ha='center', va='bottom') +for e, f in zip(x, height3): + plt.text(e + width * 2, f, f, ha='center', va='bottom') + +# 设置 x 轴刻度的标签 +plt.xticks(x + width, ['A', 'B', 'C', 'D', 'E']) +plt.title('柱状图添加文字描述示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/09.png) + +![分割线](https://img-blog.csdnimg.cn/20200509010455973.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105952856 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【4x00】条形图的绘制 + +### 【4x01】函数介绍 matplotlib.pyplot.barh() + +`matplotlib.pyplot.barh()` 函数用于绘制条形图(水平排列的柱状图)。 + +基本语法:`matplotlib.pyplot.barh(y, width[, height=0.8, left=None, align='center', color, \*\*kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| y | 标量或数组类型,每个矩形对应的 y 轴刻度 | +| width | 标量或数组类型,每个矩形的宽度,即 x 轴刻度 | +| height | 标量序列,每个矩形的高度,默认 0.8 | +| left | 标量序列,每个矩形的左侧 x 坐标的起始位置,默认值为 0 | +| align | 矩形的底边与 y 轴刻度对齐的位置,`'center'`:中;`'edge'`:底边 | + +其他参数: + +| 参数 | 描述 | +| ------ | ------ | +| color | 标量或数组类型,每个矩形的颜色,与 facecolor 作用相同,指定一个即可,如果两者都指定,则取 facecolor 的值 | +| edgecolor | 标量或数组类型,条形图边缘线的颜色 | +| linewidth | 标量或数组类型,条形图边缘线的宽度,如果为0,则不绘制边 | +| tick_label | 标量或数组类型,条形图 y 轴的刻度标签,默认使用数字标签 | +| xerr / yerr | 标量,指定对应标准差(添加误差线时会用到) | +| ecolor | 标量或数组类型,误差线的线条颜色,默认值为 black | +| capsize | 标量,误差线两头横线的宽度,默认为 `rcParams["errorbar.capsize"] = 0.0` | +| error_kw | 字典类型,可以此字典中定义 ecolor 和 capsize,比单独指定的优先级要高 | +| log | bool 值,y 坐标轴是否以指数刻度显示 | +| alpha | float 类型,矩形透明度 | +| label | 图例中显示的标签 | +| linestyle / ls | 线条样式,此处指矩形边缘线条样式
`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'` or `':'` or `'dotted'`, `'none'` or `' '` or `''` | +| linewidth / lw | 线条宽度,此处指矩形边缘线的宽度,float 类型,默认 0.8 | +| hatch | 矩形的填充图案,可以是组合形式,如果有相同的图案,则会增加填充的密度
取值可以是:`'/'`, `'\'`, `'|'`, `'-'`, `'+'`, `'x'`, `'o'`, `'O'`, `'.'`, `'*'` | + +### 【4x02】简单条形图示例 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +y = [1, 2, 3, 4, 5] +width = [5, 7, 4, 3, 1] + +tick_label = ['A', 'B', 'C', 'D', 'E'] +color = ['red', 'yellow', 'peru', 'orchid', 'deepskyblue'] +plt.barh(y, width, tick_label=tick_label, color=color, edgecolor='k', linewidth=1, linestyle='--') + +plt.title('简单条形图示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/10.png) + +### 【4x03】添加与标准差的误差线 + +与柱状图一样,首先定义一个列表,其中的元素是与每个值对应的标准差,`ecolor` 和 `capsize` 参数分别指定误差线的颜色和两头横线的宽度。这两个参数可以通过 `error_kw` 字典形式组合起来。以字典形式的组合优先级别要比单独指定高。另外,柱状图指定标准差时要用 `yerr`,条形图(横向排列的柱状图)指定标准差时要用 `xerr`。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +y = [1, 2, 3, 4, 5] +width = [5, 7, 4, 3, 2] +std = [0.5, 0.1, 1.2, 0.3, 1.0] # 标准差 + +tick_label = ['A', 'B', 'C', 'D', 'E'] # 设置 x 轴的标签,也可以用 plt.xticks 方法来设置 +color = ['red', 'yellow', 'peru', 'orchid', 'deepskyblue'] # 颜色序列 +plt.barh( + y, + width, + tick_label=tick_label, + color=color, + xerr=std, # 指定对应标准差 + # error_kw={ + # 'ecolor': 'k', # 指定误差线的颜色 + # 'capsize': 6 # 指定误差线两头横线的宽度 + # }, + ecolor='k', + capsize=6, + edgecolor='k', # 指定边缘线颜色 + linewidth=1 # 指定边缘线宽度 +) + +plt.title('条形图添加误差线示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![11](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/11.png) + +### 【4x04】多序列条形图 + +与多序列柱状图类似,在绘制多序列的条形图时,只需要多次调用 `matplotlib.pyplot.barh()` 函数即可,指定一个较小的高度值(偏移量),绘制不同数据时设置不同的 y 位置刻度即可。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +y = np.arange(5) +width1 = np.array([5, 7, 4, 3, 2]) +width2 = np.array([2, 4, 6, 7, 3]) +width3 = np.array([3, 1, 7, 5, 2]) + +# 设置高度值(偏移量) +height = 0.3 +# 绘制不同数据时,y 轴依次增加一个偏移量 +plt.barh(y, width1, height, label='bar1') +plt.barh(y + height, width2, height, label='bar2') +plt.barh(y + height * 2, width3, height, label='bar3') + +# 设置 y 轴刻度的标签 +plt.yticks(y + height, ['A', 'B', 'C', 'D', 'E']) +plt.title('多序列条形图示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![12](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/12.png) + +### 【4x05】堆积的条形图 + +堆积图就是将多序列数据堆积到一个矩形上显示,和堆积的柱状图类似,在条形图中要实现堆积图,只需要改变 `left` 参数即可,`left` 参数用于设置 x 轴基线,即柱状图的底边在 x 轴上的起始刻度,第一条数据 `data1` 的基线可以设置为 0,即默认值,第二条数据 `data2` 的基线可以设置在 `data1` 的上方,即 `left=data1`,第三条数据 `data3` 的基线可以设置在 `data1 + data2` 的上方,即 `left=data1+data2`,以此类推。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +y = np.arange(5) +width1 = np.array([5, 7, 4, 3, 2]) +width2 = np.array([2, 4, 6, 7, 3]) +width3 = np.array([3, 1, 7, 5, 2]) + +plt.barh(y, width1, label='bar1') +plt.barh(y, width2, label='bar2', left=width1) +plt.barh(y, width3, label='bar3', left=(width1+width2)) + +plt.yticks(y, ['A', 'B', 'C', 'D', 'E']) +plt.title('堆积的条形图示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![13](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/13.png) + +### 【4x06】填充其他样式 + +`hatch` 参数可以让柱状图的矩形填充其他样式,可选值有:`'/'`, `'\'`, `'|'`, `'-'`, `'+'`, `'x'`, `'o'`, `'O'`, `'.'`, `'*'`。可以是不同图案的组合形式,如果有相同的图案,则会增加填充的密度。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +y = np.arange(5) +width1 = np.array([5, 7, 4, 3, 2]) +width2 = np.array([2, 4, 6, 7, 3]) +width3 = np.array([3, 1, 7, 5, 2]) + +plt.barh(y, width1, label='bar1', color='w', hatch='///') +plt.barh(y, width2, label='bar2', left=width1, color='w', hatch='xxx') +plt.barh(y, width3, label='bar3', left=(width1+width2), color='w', hatch='|||') + +plt.yticks(y, ['A', 'B', 'C', 'D', 'E']) +plt.title('条形图图案填充示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![14](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/14.png) + +### 【4x07】添加文字描述 + +利用 `matplotlib.pyplot.text()` 方法可以在条形图每个矩形上方添加文字描述。具体参数解释可参考前面的文章:[《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +y = np.arange(5) +width1 = np.array([5, 7, 4, 3, 2]) +width2 = np.array([2, 4, 6, 7, 3]) +width3 = np.array([3, 1, 7, 5, 2]) + +height = 0.3 +# 绘制不同数据时,y 轴依次增加一个偏移量 +plt.barh(y, width1, height, label='bar1') +plt.barh(y + height, width2, height, label='bar2') +plt.barh(y + height * 2, width3, height, label='bar3') + +# 依次添加每条数据的标签 +for a, b in zip(width1, y): + plt.text(a, b-0.05, a) +for c, d in zip(width2, y): + plt.text(c, d+0.20, c) +for e, f in zip(width3, y): + plt.text(e, f+0.50, e) + +# 设置 y 轴刻度的标签 +plt.yticks(y + height, ['A', 'B', 'C', 'D', 'E']) +plt.title('条形图添加文字描述示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') +plt.legend() + +plt.show() +``` + +![15](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A73/15.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/105952856 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A74-Matplotlib-07.md b/source/_posts/A74-Matplotlib-07.md new file mode 100644 index 0000000000000000000000000000000000000000..c342ca598f0407df7af3c992f98027db6be62910 --- /dev/null +++ b/source/_posts/A74-Matplotlib-07.md @@ -0,0 +1,296 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 +tags: + - Matplotlib + - 饼状图 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106025845 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】方法描述 + +`matplotlib.pyplot.pie()` 方法用于绘制饼状图。 + +基本语法: + +```python +matplotlib.pyplot.pie( + x[, explode=None, labels=None, colors=None, + autopct=None, pctdistance=0.6, shadow=False, + labeldistance=1.1, startangle=None, radius=None, + counterclock=True, wedgeprops=None, textprops=None, + center=(0, 0), frame=False, rotatelabels=False, \*, data=None] + ) +``` + +| 参数 | 描述 | +| ------ | ------ | +| x | 每个扇形块的大小,数组形式,大小单位是比例 | +| explode | 指定对应扇形块脱离饼图的半径大小,数组形式,其中元素个数应该是 len(x) | +| labels | 每个扇形块上的文本标签,列表形式 | +| labeldistance | 每个扇形块上的文本标签与扇形中心的距离,float 类型,默认 1.1 | +| colors | 每个扇形块对应的颜色,数组形式 | +| autopct | 用于计算每个扇形块所占比例,字符串或者函数类型
例如:`autopct='%1.1f%%'` 表示浮点数,保留一位小数,并添加百分比符号 | +| pctdistance | 每个扇形块的中心与 autopct 生成的文本之间的距离,float 类型,默认 0.6 | +| shadow | 是否为扇形添加阴影效果 | +| startangle | 将饼图按照逆时针旋转指定的角度,float 类型 | +| radius | 饼图的半径,如果是 None,则将被设置为 1,float 类型 | +| counterclock | 是否按照逆时针对扇形图进行排列,bool 类型,默认 True | +| wedgeprops | 传递给绘制每个扇形图对象的参数,字典形式,参数值参见 [Wedge](https://matplotlib.org/api/_as_gen/matplotlib.patches.Wedge.html#matplotlib.patches.Wedge)
例如:`wedgeprops = {'linewidth': 3}` 设置扇形边框线宽度为 3 | +| textprops | 传递给文本对象的参数,字典形式
例如:`textprops={'color': 'r', 'fontsize': 15}` 设置文字为红色,大小为15 | +| center | 饼图圆心在画布上是坐标,默认 (0, 0) | +| frame | 是否显示 x, y 坐标轴外框,默认 False | +| rotatelabels | 是否按照角度进行调整每块饼的 label 文本标签,默认 False | + +## 【2x00】简单示例 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [10, 30, 45, 15] +labels = ['Java', 'Golang', 'Python', 'C++'] +colors = ['red', 'yellow', 'blue', 'green'] + +# 指定4个扇区所占比例以及扇区的颜色,扇区文本标签距离扇区中心1.1 +plt.pie(x, labels=labels, colors=colors, labeldistance=1.1) +plt.title('饼状图简单示例') + +plt.show() +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A74/01.png) + +## 【3x00】按角度调整扇形标签 + +`rotatelabels` 属性可以设置是否按照角度调整每块饼的 label(标签)显示方式。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [10, 30, 45, 15] +labels = ['Java', 'Go', 'Python', 'C++'] +colors = ['red', 'yellow', 'blue', 'green'] + +# 指定4个扇区所占比例以及扇区的颜色,扇区文本标签距离扇区中心1.1,按角度调整 labels +plt.pie(x, labels=labels, colors=colors, labeldistance=1.1, rotatelabels=True) +plt.title('饼状图按角度调整 labels 示例') + +plt.show() +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A74/02.png) + +## 【4x00】显示图例 + +与前面文章中绘制线性图、散点图、条形图一样,调用 `matplotlib.pyplot.legend()` 方法可绘制图例,该方法的参数解释参见前文[《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [10, 30, 45, 15] +labels = ['Java', 'Go', 'Python', 'C++'] +colors = ['red', 'yellow', 'blue', 'green'] + +plt.pie(x, labels=labels, colors=colors, labeldistance=1.1) +plt.title('饼状图显示图例示例') +plt.legend(bbox_to_anchor=(1, 1)) + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A74/03.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106025845 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【5x00】突出显示扇形块 + +`explode` 参数可以实现突出显示某一块扇区,接收数组形式的参数,这个数组中的元素个数应该是 len(x),即和扇区块的数量相同。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [10, 30, 45, 15] +labels = ['Java', 'Golang', 'Python', 'C++'] +colors = ['red', 'yellow', 'blue', 'green'] + +# 指定第一个扇区块脱离饼图的半径大小为0.3,其它扇区不脱离 +plt.pie(x, labels=labels, colors=colors, labeldistance=1.1, explode=[0.3, 0, 0, 0]) +plt.title('饼状图突出显示扇形块示例') +plt.legend(bbox_to_anchor=(1, 1)) + +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A74/04.png) + +## 【6x00】显示各扇区所占百分比 + +`autopct` 参数可用于计算每个扇形块所占比例,接收字符串或者函数类型,例如:`autopct='%1.1f%%'` 表示浮点数,保留一位小数,并添加百分比符号。`pctdistance` 参数用于调整每个扇形块的中心与 `autopct` 生成的文本之间的距离,float 类型,默认 0.6。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [10, 30, 45, 15] +labels = ['Java', 'Golang', 'Python', 'C++'] +colors = ['red', 'yellow', 'blue', 'green'] + +plt.pie( + x, # 每个扇形块所占比例 + labels=labels, # 扇形块文本标签 + colors=colors, # 扇形块颜色 + labeldistance=1.1, # 扇形块标签距离中心的距离 + explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 + autopct='%1.1f%%', # 显示百分比,保留一位小数 + pctdistance=0.5 # 百分比文本距离饼状图中心的距离 +) +plt.title('饼状图显示各扇区所占百分比示例') +plt.legend(bbox_to_anchor=(1, 1)) # 显示图例 + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A74/05.png) + +## 【7x00】旋转饼状图 + +`startangle` 参数可以选择饼状图,改变饼状图放置的角度。注意是按照逆时针旋转。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [10, 30, 45, 15] +labels = ['Java', 'Golang', 'Python', 'C++'] +colors = ['red', 'yellow', 'blue', 'green'] + +plt.pie( + x, # 每个扇形块所占比例 + labels=labels, # 扇形块文本标签 + colors=colors, # 扇形块颜色 + labeldistance=1.1, # 扇形块标签距离中心的距离 + explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 + autopct='%1.1f%%', # 显示百分比,保留一位小数 + pctdistance=0.5, # 百分比文本距离饼状图中心的距离 + startangle=-90 # 逆时针旋转-90°,即顺时针旋转90° +) +plt.title('饼状图旋转角度示例') +plt.legend(bbox_to_anchor=(1, 1)) # 显示图例 + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A74/06.png) + +## 【8x00】自定义每个扇形和文字属性 + +`wedgeprops` 参数以字典形式为每个扇形添加自定义属性,例如:`wedgeprops = {'linewidth': 3}` 设置扇形边框线宽度为 3,更多其他参数值参见 [Wedge](https://matplotlib.org/api/_as_gen/matplotlib.patches.Wedge.html#matplotlib.patches.Wedge); + +`textprops` 参数同样以字典形式为文本对象添加自定义属性,例如:`textprops={'color': 'r', 'fontsize': 15}` 设置文字为红色,大小为15,更多其他参数值参见 [Text](https://matplotlib.org/api/text_api.html?highlight=text#matplotlib.text.Text)。 + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = [10, 30, 45, 15] +labels = ['Java', 'Golang', 'Python', 'C++'] +colors = ['red', 'yellow', 'blue', 'green'] + +plt.pie( + x, # 每个扇形块所占比例 + labels=labels, # 扇形块文本标签 + colors=colors, # 扇形块颜色 + labeldistance=1.1, # 扇形块标签距离中心的距离 + explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 + autopct='%1.1f%%', # 显示百分比,保留一位小数 + pctdistance=0.6, # 百分比文本距离饼状图中心的距离 + shadow=True, # 显示阴影效果 + wedgeprops={ # 为每个扇形添加属性 + 'width': 0.7, # 扇形宽度0.7 + 'edgecolor': '#98F5FF', # 扇形边缘线颜色 + 'linewidth': 3 # 扇形边缘线宽度 + }, + textprops={ # 为文字添加属性 + 'fontsize': 13, # 文字大小 + 'fontweight': 'bold', # 文字粗细 + 'color': 'k' # 文字颜色,黑色 + } +) +plt.title('饼状图自定义每个扇形和文字属性示例', fontweight='bold') +plt.legend(bbox_to_anchor=(1, 1), borderpad=0.6) # 显示图例 + +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A74/07.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106025845 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A75-Matplotlib-08.md b/source/_posts/A75-Matplotlib-08.md new file mode 100644 index 0000000000000000000000000000000000000000..1a7bd1b82b6adba59a8135bf74d0de9a1f32098e --- /dev/null +++ b/source/_posts/A75-Matplotlib-08.md @@ -0,0 +1,378 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(八):等高线/等值线图的绘制 +tags: + - Matplotlib + - 等高线图 + - 等值线图 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(八):等高线、等值线图的绘制。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106066852 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】等高线概念 + +参考百度百科,等高线概念总结如下:等高线指的是地形图上高程相等的相邻各点所连成的闭合曲线。把地面上海拔高度相同的点连成的闭合曲线,并垂直投影到一个水平面上,并按比例缩绘在图纸上,就得到等高线。等高线也可以看作是不同海拔高度的水平面与实际地面的交线,所以等高线是闭合曲线。在等高线上标注的数字为该等高线的海拔。 + +- 位于同一等高线上的地面点,海拔高度相同。但海拔高度相同的点不一定位于同一条等高线上; +- 在同一幅图内,除了陡崖以外,不同高程的等高线不能相交; +- 在图廓内相邻等高线的高差一般是相同的,因此地面坡度与等高线之间的等高线平距成反比,等高线平距愈小,等高线排列越密,说明地面坡度越大;等高线平距愈大,等高线排列越稀,则说明地面坡度愈小; +- 等高线是一条闭合的曲线,如果不能在同一幅内闭合,则必在相邻或者其他图幅内闭合。 +- 等高线经过山脊或山谷时改变方向,因此,山脊线或者山谷线应垂直于等高线转折点处的切线,即等高线与山脊线或者山谷线正交。 + +**在 Matplotlib 等高线的绘制中,需要传递三个基本参数:某个点的 x、y 轴坐标以及其高度。** + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/01.png) + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/02.png) + + + +## 【2x00】理解 numpy.meshgrid() + +`numpy.meshgrid()` 方法用于生成网格点坐标矩阵。 + +```python +import numpy as np + +a = np.array([1, 2, 3]) +b = np.array([7, 8, 9]) +res = np.meshgrid(a, b) +print(res) +``` + +输出结果: + +```python +[array([[1, 2, 3], + [1, 2, 3], + [1, 2, 3]]), + array([[7, 7, 7], + [8, 8, 8], + [9, 9, 9]])] +``` + +给定两个数组,`a[1, 2, 3]` 和 `b[7, 8, 9]`,a 作为 x 轴数据,b 作为 y 轴数据,那么一共可以绘制出 9 个点: (1,7)、(1,8)、(1,9)、(2,7)、(2,8)、(2,9)、(3,7)、(3,8)、(3,9),而 `numpy.meshgrid()` 方法就是起这样的作用,返回的两个二维数组,横坐标矩阵 a 中的每个元素,与纵坐标矩阵 b 中对应位置元素,共同构成一个点的完整坐标。 + +**因为在 `matplotlib.pyplot.contour()` 等高线绘制函数中接收的是二维坐标信息,所以在绘制等高线图之前要将原数据经过 `numpy.meshgrid()` 方法处理,也可以自己构建类似于上述的二维数组。** + +![分割线](https://img-blog.csdnimg.cn/20200512112427932.png) + +## 【3x00】绘制方法 matplotlib.pyplot.contour() + +`matplotlib.pyplot.contour()` 方法可用于绘制等高线图。 + +基本语法:`matplotlib.pyplot.contour(\*args, data=None, \*\*kwargs)` + +通用格式:`matplotlib.pyplot.contour([X, Y,] Z, [levels], **kwargs)` + +基本参数: + +| 参数 | 描述 | +| ------ | ------ | +| X, Y | 数组形式的点的 x 和 y 轴坐标,两者都必须是二维的,形状与 Z 相同 | +| Z | 绘制轮廓的高度值,二维数组,每个元素是其对应点的高度 | +| levels | 确定等高线的数目和位置,如果是整数 N,则使用 N 个数据间隔,即绘制 N+1 条等高线
如果是数组形式,则绘制指定的等高线。值必须按递增顺序排列 | + +其他参数: + +| 参数 | 描述 | +| ------ | ------ | +| colors | 等高线的颜色,颜色字符串或颜色序列 | +| cmap | 等高线的颜色,字符串或者 [Colormap](https://matplotlib.org/tutorials/colors/colormaps.html)
通常包含一系列的渐变色或其他颜色组合,取值参见**【6x00】Colormap 取值** | +| alpha | 透明度,介于0(透明)和1(不透明)之间 | +| origin | 通过指定 Z[0,0] 的位置来确定 Z 的方向和确切位置,仅当未指定 X, Y 时才有意义
`None`:Z[0,0] 位于左下角的 X=0, Y=0 处
`'lower'`:Z [0, 0] 位于左下角的 X = 0.5, Y = 0.5 处
`'upper'`:Z[0,0] 位于左上角的 X=N+0.5, Y=0.5 处
`'image'`:使用 `rcParams[“image.origin”] = 'upper'`的值 | +| antialiased | 是否启用抗锯齿渲染,默认 True | +| linewidths | 等高线的线宽,如果是数字,则所有等高线都将使用此线宽
如果是序列,则将按指定的顺序以升序打印线宽
默认为 `rcParams[“lines.linewidth”] = 1.5` | +| linestyles | 等高线的样式,如果线条颜色为单色,则负等高线默认为虚线
`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'` `':'` or `'dotted'`, `'none'` or `' '` or `''` | + +![分割线](https://img-blog.csdnimg.cn/20200512112427932.png) + +## 【4x00】填充方法 matplotlib.pyplot.contourf() + +`matplotlib.pyplot.contourf()` 方法与 `matplotlib.pyplot.contour()` 的区别在于:`contourf()` 会对等高线间的区域进行颜色填充(filled contours)。除此之外两者的函数签名和返回值都相同。 + +基本语法:`matplotlib.pyplot.contourf(\*args, data=None, \*\*kwargs)` + +通用格式:`matplotlib.pyplot.contour([X, Y,] Z, [levels], **kwargs)` + +基本参数: + +| 参数 | 描述 | +| ------ | ------ | +| X, Y | 数组形式的点的 x 和 y 轴坐标,两者都必须是二维的,形状与 Z 相同 | +| Z | 绘制轮廓的高度值,二维数组,每个元素是其对应点的高度 | +| levels | 确定等高线的数目和位置,如果是整数 N,则使用 N 个数据间隔,即绘制 N+1 条等高线
如果是数组形式,则绘制指定的等高线。值必须按递增顺序排列 | + +其他参数: + +| 参数 | 描述 | +| ------ | ------ | +| colors | 等高线的填充颜色,颜色字符串或颜色序列 | +| cmap | 等高线的填充颜色,字符串或者 [Colormap](https://matplotlib.org/tutorials/colors/colormaps.html)
通常包含一系列的渐变色或其他颜色组合,取值参见**【6x00】Colormap 取值** | +| alpha | 透明度,介于0(透明)和1(不透明)之间 | +| origin | 通过指定 Z[0,0] 的位置来确定 Z 的方向和确切位置,仅当未指定 X, Y 时才有意义
`None`:Z[0,0] 位于左下角的 X=0, Y=0 处
`'lower'`:Z [0, 0] 位于左下角的 X = 0.5, Y = 0.5 处
`'upper'`:Z[0,0] 位于左上角的 X=N+0.5, Y=0.5 处
`'image'`:使用 `rcParams[“image.origin”] = 'upper'`的值 | +| antialiased | 是否启用抗锯齿渲染,默认 True | +| linewidths | 等高线的线宽,如果是数字,则所有等高线都将使用此线宽
如果是序列,则将按指定的顺序以升序打印线宽
默认为 `rcParams[“lines.linewidth”] = 1.5` | +| linestyles | 等高线的样式,如果线条颜色为单色,则负等高线默认为虚线
`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'` `':'` or `'dotted'`, `'none'` or `' '` or `''` | + +![分割线](https://img-blog.csdnimg.cn/20200512180336350.png) + +## 【5x00】标记方法 matplotlib.pyplot.clabel() + +`matplotlib.pyplot.clabel(CS, \*args, \*\*kwargs)` 方法可用于标记等高线图。 + +| 参数 | 描述 | +| ------ | ------ | +| CS | ContourSet(等高线集)对象,即 `pyplot.contour()` 返回的对象 | +| levels | 需要标记的等高线集,数组类型,如果未指定则默认标记所有等高线 | +| fontsize | 标记的字体大小,可选项:
`'xx-small'`, `'x-small'`, `'small'`, `'medium'`, `'large'`, `'x-large'`, `'xx-large'` | +| colors | 标记的颜色,颜色字符串或颜色序列 | +| inline | 是否在标签位置移除轮廓显示,bool 类型,默认 True | +| inline_spacing | 标签位置移除轮廓的宽度,float 类型,默认为 5 | +| fmt | 标签的格式字符串。str 或 dict 类型,默认值为 `%1.3f` | +| rightside_up | 是否将标签旋转始终与水平面成正负90度,bool 类型,默认 True | +| use_clabeltext | 默认为 False,如果为 True,则使用 [ClabelText](https://matplotlib.org/api/contour_api.html#matplotlib.contour.ClabelText) 类(而不是 [Text](https://matplotlib.org/api/text_api.html#matplotlib.text.Text))创建标签
ClabelText 在绘图期间重新计算文本的旋转角度,如果轴的角度发生变化,则可以使用此功能 | + +![分割线](https://img-blog.csdnimg.cn/20200512112427932.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106066852 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【6x00】Colormap 取值 + +`matplotlib.pyplot.contour()` 和 `matplotlib.pyplot.contourf()` 中 `cmap` 参数用于设置等高线的颜色,取值通常为 Colormap 中的值,通常包含一系列的渐变色或其他颜色组合。具体参加下图。 + +官方文档:[https://matplotlib.org/tutorials/colors/colormaps.html](https://matplotlib.org/tutorials/colors/colormaps.html) + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/03.png) + +![分割线](https://img-blog.csdnimg.cn/20200512112427932.png) + +## 【7x00】简单示例 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2.0, 2.0, 0.01) +y = np.arange(-2.0, 2.0, 0.01) +m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵 + + +# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度 +def f(a, b): + return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2) + + +# 绘制等高线图,8 个数据间隔,颜色为黑色 +plt.contour(m, n, f(m, n), 8, colors='k') +plt.title('等高线图简单示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/04.png) + +![分割线](https://img-blog.csdnimg.cn/20200512112427932.png) + +## 【8x00】添加标记 + +`matplotlib.pyplot.clabel()` 方法用于给等高线添加标记。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2.0, 2.0, 0.01) +y = np.arange(-2.0, 2.0, 0.01) +m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵 + + +# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度 +def f(a, b): + return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2) + + +# 绘制等高线图,8 个数据间隔,颜色为黑色 +C = plt.contour(m, n, f(m, n), 8, colors='k') +# 添加标记,标记处不显示轮廓线,颜色为黑红绿蓝四种,保留两位小数 +plt.clabel(C, inline=True, colors=['k', 'r', 'g', 'b'], fmt='%1.2f') +plt.title('等高线图添加标记示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/05.png) + +![分割线](https://img-blog.csdnimg.cn/20200512112427932.png) + +## 【9x00】轮廓线颜色和样式 + +`matplotlib.pyplot.contour()` 方法中,`colors` 参数即可为等高线轮廓设置颜色,可以是单色,也可以是一个颜色列表,`linestyles` 参数可以设置轮廓线样式,注意,如果线条颜色为单色,则负等高线(高度值为负)默认为虚线。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2.0, 2.0, 0.01) +y = np.arange(-2.0, 2.0, 0.01) +m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵 + + +# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度 +def f(a, b): + return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2) + + +colors = ['k', 'r', 'g', 'b'] +# 绘制等高线图,8 个数据间隔,颜色为黑色,线条样式为 -- +C = plt.contour(m, n, f(m, n), 8, colors=colors, linestyles='--') +# 添加标记,标记处不显示轮廓线,颜色为黑红绿蓝四种,保留两位小数 +plt.clabel(C, inline=True, colors=colors, fmt='%1.2f') +plt.title('等高线图设置颜色/样式示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/06.png) + +如果想启用渐变色,则可以设置 `cmap`,取值参见**【6x00】Colormap 取值**,`colorbar()` 方法可以显示颜色对照条。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2.0, 2.0, 0.01) +y = np.arange(-2.0, 2.0, 0.01) +m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵 + + +# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度 +def f(a, b): + return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2) + + +# 绘制等高线图,8 个数据间隔,颜色为 plasma +C = plt.contour(m, n, f(m, n), 8, cmap='plasma') +# 添加标记,标记处不显示轮廓线,颜色为黑色,保留两位小数 +plt.clabel(C, inline=True, colors='k', fmt='%1.2f') +# 显示颜色条 +plt.colorbar() +plt.title('等高线图设置渐变色示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/07.png) + +![分割线](https://img-blog.csdnimg.cn/20200512112427932.png) + +## 【10x00】颜色填充 + +`matplotlib.pyplot.contourf()` 方法用于对等高线之间的地方进行颜色填充。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +x = np.arange(-2.0, 2.0, 0.01) +y = np.arange(-2.0, 2.0, 0.01) +m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵 + + +# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度 +def f(a, b): + return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2) + + +# 绘制等高线图,8 个数据间隔,颜色为 plasma +plt.contourf(m, n, f(m, n), 8, cmap='plasma') +C = plt.contour(m, n, f(m, n), 8, cmap='plasma') +# 添加标记,标记处不显示轮廓线,颜色为黑色,保留两位小数 +plt.clabel(C, inline=True, colors='k', fmt='%1.2f') +# 显示颜色条 +plt.colorbar() +plt.title('等高线图颜色填充示例') +plt.xlabel('x axis label') +plt.ylabel('y axis label') + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A75/08.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106066852 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A76-Matplotlib-09.md b/source/_posts/A76-Matplotlib-09.md new file mode 100644 index 0000000000000000000000000000000000000000..098578d3cdca2fd6f1d5823f753bf91cd53dc424 --- /dev/null +++ b/source/_posts/A76-Matplotlib-09.md @@ -0,0 +1,531 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(九):极区图/极坐标图/雷达图的绘制 +tags: + - Matplotlib + - 极区图 + - 极坐标图 + - 雷达图 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(九):极区图、极坐标图、雷达图的绘制。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106162412 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】了解极坐标 + +参考百度百科:极坐标,属于二维坐标系统,创始人是牛顿,主要应用于数学领域。极坐标是指在平面内取一个定点 O,叫极点,引一条射线 Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。对于平面内任何一点 M,用 ρ 表示线段 OM 的长度(有时也用 r 表示),θ 表示从 OxOM 的角度,ρ 叫做点 M 的极径,θ 叫做点 M 的极角,有序数对 (ρ,θ) 就叫点 M 的极坐标,这样建立的坐标系叫做极坐标系。通常情况下,M 的极径坐标单位为 1(长度单位),极角坐标单位为 rad(或°)。 + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/01.png) + +## 【2x00】基本方法 matplotlib.pyplot.polar() + +`matplotlib.pyplot.polar()` 方法可用于绘制极坐标图。 + +基本语法:`polar(theta, r, **kwargs)` + +- **theta**:点的角坐标,以弧度单位传入参数; +- **r**:点的半径坐标; +- ****kwargs**:可选项,其他 Line2D 属性,常用属性见**表一**。 + +拓展:数学上通常是用弧度而非角度,弧度单位缩写为 rad,2π rad = 360°,1° ≈ 0.0174533 rad,1 rad ≈ 57.29578°。 + +- 角度转换为弧度公式:弧度 = 角度 ÷ 180 × π +- 弧度转换为角度公式:角度 = 弧度 × 180 ÷ π + +
表一:Line2D 部分属性,完整属性参见官方文档:
https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html
+ +| 属性 | 描述 | +| ------ | ------ | +| alpha | 线条透明度,float 类型,取值范围:`[0, 1]`,默认为 1.0,即不透明 | +| antialiased / aa | 是否使用抗锯齿渲染,默认为 True | +| color / c | 线条颜色,支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 [Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| fillstyle | 点的填充样式,`'full'`、`'left'`、`'right'`、`'bottom'`、`'top'`、`'none'` | +| label | 图例,具体参数参见:
[《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) | +| linestyle / ls | 连接的线条样式:`'-'` or `'solid'`, `'--'` or `'dashed'`, `'-.'` or `'dashdot'`
`':'` or `'dotted'`, `'none'` or `' '` or `''` | +| linewidth / lw | 连接的线条宽度,float 类型,默认 0.8 | +| marker | 标记样式,具体样式参见**表二** | +| markeredgecolor / mec | marker 标记的边缘颜色 | +| markeredgewidth / mew | marker 标记的边缘宽度 | +| markerfacecolor / mfc | marker 标记的颜色 | +| markerfacecoloralt / mfcalt | marker 标记的备用颜色 | +| markersize / ms | marker 标记的大小 | + +
表二:marker 标记的样式,官方文档:
https://matplotlib.org/api/markers_api.html
+ +| 标记 | 描述 | +| ------ | ------ | +| `"."` | 点 | +| `","` | 像素点 | +| `"o"` | 圆圈 | +| `"v"` | 倒三角 | +| `"^"` | 正三角 | +| `"<"` | 左三角 | +| `">"` | 右三角 | +| `"1"` | 倒三叉星 | +| `"2"` | 正三叉星(类似奔驰车标形状) | +| `"3"` | 左三叉星 | +| `"4"` | 右三叉星 | +| `"8"` | 八边形 | +| `"s"` | 正方形 | +| `"p"` | 五边形 | +| `"P"` | 填充的加号(粗加号) | +| `"+"` | 加号 | +| `"*"` | 星形 | +| `"h"` | 六边形(底部是角) | +| `"H"` | 六边形(底部是边) | +| `"x"` | x 号 | +| `"X"` | 填充的 x 号(粗 x 号) | +| `"D"` | 粗菱形(对角线相等) | +| `"d"` | 细菱形(对角线不等) | +| `"|"` | 垂直线 | +| `"_"` | 水平线 | +| `0` | 水平线靠左 | +| `1` | 水平线靠右 | +| `2` | 垂直线靠上 | +| `3` | 垂直线靠下 | +| `4` | 左三角(比 `"<"` 更细) | +| `5` | 右三角(比 `">"` 更细) | +| `6` | 正三角(比 `"^"` 更细) | +| `7` | 倒三角(比 `"v"` 更细) | +| `8` | 左三角(比 `"<"` 更细,靠左显示) | +| `9` | 右三角(比 `">"` 更细,靠右显示) | +| `10` | 正三角(比 `"^"` 更细,靠上显示) | +| `11` | 倒三角(比 `"v"` 更细,靠下显示) | +| `"None"` / `" "` / `""` | 无样式 | +| `'$...$'` | 支持 LaTeX 数学公式,表达式用美元符号包围起来 | + +## 【3x00】绘制极坐标 + +```python +import numpy as np +import matplotlib.pyplot as plt + +# 设置中文显示 +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +# 设置画布大小 +plt.figure(figsize=(8.0, 6.0)) + +# 设置三个数据,theta 为点位置的弧度参数,r 为点的半径坐标 +theta1 = np.array([1.25*np.pi, np.pi/2, 0]) +theta2 = np.array([-np.pi/6, -np.pi/2, 0, np.pi/2, np.pi]) +theta3 = np.arange(0., 2*np.pi, 0.5) +r1 = np.array([4, 2, 3]) +r2 = np.array([5, 2, 4, 5, 3]) +r3 = np.random.randint(0, 5, 13) + +# 绘制第一个极坐标图,点的标记样式为细菱形,大小为8,点之间的连接线条样式为: +plt.polar(theta1, r1, marker='d', ms=8, ls=':', label='数据一') +# 填充第一个极坐标图,填充颜色为蓝色,透明度0.3 +plt.fill(theta1, r1, color='b', alpha=0.3) +# 绘制第二个极坐标图,marker、linestyle、color 三个参数可以组合以字符串形式传入 +plt.polar(theta2, r2, '*-g', ms=10, label='数据二') +# 绘制第三个极坐标图,设置 linestyle 为 none,即点与点之间不相连 +plt.polar(theta3, r3, marker='o', ls='none', ms=8, color='r', label='数据三') + +plt.title('matplotlib.pyplot.polar 用法示例', pad=25, fontsize=15) +plt.legend(bbox_to_anchor=(1.3, 1)) + +plt.show() +``` + +示例中 figure、title、legend 等其他方法的解释可参见我的系列文章: + +- [《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》](https://itrhx.blog.csdn.net/article/details/105638122) +- [《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) +- [《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) + +绘制结果如下图: + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/02.png) + +## 【4x00】绘制雷达图 + +雷达图是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多变量数据的图形方法。轴的相对位置和角度通常是无信息的。 雷达图也称为网络图,蜘蛛图,星图,蜘蛛网图,不规则多边形,极坐标图或 Kiviat 图。它相当于平行坐标图,轴径向排列。 + +在前面的示例中,使用了 `matplotlib.pyplot.fill()` 方法对三个极坐标点围成的图形进行了填充,这就有点儿接近于雷达图了,仔细观察前面的示例,在填充时第一个点和最后一个点之间没有连线,即没有闭合,而更精确的雷达图应该是闭合的,且外围应该是文字描述而不是度数。 + +在绘制雷达图之前需要提前了解一些函数。这些函数可以帮助我们实现闭合、自定义文字标签等。 + +--- + +### 【4x01】理解 numpy.concatenate() + +`numpy.concatenate()` 方法用于沿现有轴连接一系列数组,我们可以利用此方法来实现闭合操作。 + +基本语法:`numpy.concatenate((a1, a2, ...)[, axis=0, out=None])` + +| 参数 | 描述 | +| ------ | ------ | +| a1, a2, … | 要连接的数组,必须拥有相同的维度 | +| axis | 沿指定轴连接数组,可选项,如果 axis 为 None,则数组在使用前被展平,默认值为 0 | +| out | 用于接收连接后的数组,可选项 | + +用法示例: + +```python +import numpy as np + +a = np.array([1, 2, 3, 4]) +b = np.array(['a', 'b', 'c', 'd']) +print(np.concatenate((a, b))) +``` + +输出结果如下: + +```python +['1' '2' '3' '4' 'a' 'b' 'c' 'd'] +``` + +如果要实现数组的闭合,则可以传入原数组和一个新数组,其中新数组中的元素为原数组中的第一个元素,示例如下: + +```python +import numpy as np + +a = np.array([1, 2, 3, 4]) +print(np.concatenate((a, [a[0]]))) +``` + +输出结果如下: + +```python +[1 2 3 4 1] +``` + +--- + +### 【4x02】理解 pyplot.thetagrids() + +`matplotlib.pyplot.thetagrids()` 方法用于获取并设置当前极区图上的极轴。 + +基本语法:`matplotlib.pyplot.thetagrids(angles, labels=None, fmt=None, **kwargs)` + +| 参数 | 描述 | +| ------ | ------ | +| angles | 网格线的角度,浮点数、度数组成的元组 | +| labels | 每个极轴要使用的文本标签,字符串组成的元组 | +| fmt | 格式化 angles 参数,如 `'%1.2f'` 保留两位小数,注意,将使用以弧度为单位的角度 | +| **kwargs | 其他关键字参数,参见[官方文档](https://matplotlib.org/api/text_api.html?highlight=text#matplotlib.text.Text) | + +应用举例: + +```python + import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +plt.polar() +angles = range(0, 360, 45) +labels = ('东', '东北', '北', '西北', '西', '西南', '南', '东南') +plt.thetagrids(angles, labels) +plt.title('matplotlib.pyplot.thetagrids() 用法示例', pad=15) + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/03.png) + +--- + +### 【4x03】绘制雷达图 + +`numpy.concatenate()` 方法能够解决闭合问题,`matplotlib.pyplot.thetagrids()` 能够解决自定义极轴和极轴的文本标记问题,因此就可以绘制一个标准的雷达图了。示例如下: + +```python +import numpy as np +import matplotlib.pyplot as plt + +# 设置中文显示、画布大小 +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +plt.figure(figsize=(8.0, 6.0)) + +# 分割圆并执行闭合操作(0-2π之间返回间隔均匀的6个弧度:π/3、2π/3、π、4π/3、5π/3、2π) +theta = np.linspace(0, 2*np.pi, 6, endpoint=False) +theta = np.concatenate((theta, [theta[0]])) + +# 设置两组数据并执行闭合操作 +data1 = np.array([9, 4, 3, 5, 2, 8]) +data2 = np.array([3, 6, 9, 6, 3, 2]) +data1 = np.concatenate((data1, [data1[0]])) +data2 = np.concatenate((data2, [data2[0]])) + +# 绘制并填充两组数据 +plt.polar(theta, data1, 'bo-', label='小王') +plt.polar(theta, data2, 'ro:', label='小张') +plt.fill(theta, data1, color='b', alpha=0.3) +plt.fill(theta, data2, color='r', alpha=0.3) + +# 将六个弧度(π/3、2π/3、π、4π/3、5π/3、2π)转换成角度,并分别设置标签 +labels = np.array(['Python', 'Golang', 'Java', 'C++', 'PHP', 'JavaScript']) +plt.thetagrids(theta * 180/np.pi, labels) + +# 设置刻度范围、标题、图例 +plt.ylim(0, 10) +plt.title('编程语言掌握程度') +plt.legend(bbox_to_anchor=(1.3, 1)) +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/04.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106162412 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【5x00】高级用法:绘制极坐标散点图 + +`matplotlib.pyplot.polar()` 方法可以实现极坐标散点图,但仅用这一个函数的话实现的样式效果并不多,以下介绍另外三种绘制极坐标散点图的方法: + +- `matplotlib.pyplot.polar()` 和 `matplotlib.pyplot.scatter()` 结合,前者绘制极坐标图,后者在极坐标图上绘制散点图; + +- `matplotlib.pyplot.subplot()` 和 `matplotlib.pyplot.scatter()` 结合,前者添加子图,其中指定 `projection='polar'` 即为极坐标图, 后者在极坐标图上绘制散点图; + +- `matplotlib.pyplot.axes()` 与 `matplotlib.pyplot.scatter()` 结合,前者设置绘图区参数,其中指定 `projection='polar'` 或 `polar=True` 即为极坐标图, 后者在极坐标图上绘制散点图。 + +--- + +### 【5x01】方法一:pyplot.scatter() 与 pyplot.polar() + +以下用到的 `matplotlib.pyplot.scatter()` 函数,各参数含义以及支持的其他参数可以参见前文: + +- [《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) + +- [《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》](https://itrhx.blog.csdn.net/article/details/105914929) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +N = 50 +r = 2 * np.random.rand(N) +theta = 2 * np.pi * np.random.rand(N) +size = 200 * r ** 2 +colors = N * np.random.rand(N) + +plt.polar() +plt.scatter(theta, r, s=size, c=colors, alpha=0.8) +plt.title('极坐标散点图示例一', pad=15) + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/05.png) + +--- + +### 【5x02】方法二:pyplot.scatter() 与 pyplot.subplot() + +`matplotlib.pyplot.subplot()` 方法用于添加子图,如果想要子图为极坐标图,则需要指定 `projection` 参数为 `polar`,有关此函数的具体介绍可参见[官方文档](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot.html)。其他函数的参数解释可参考前文: + +- [《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) + +- [《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》](https://itrhx.blog.csdn.net/article/details/105914929) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +N = 50 +r = 2 * np.random.rand(N) +theta = 2 * np.pi * np.random.rand(N) +size = 200 * r ** 2 +colors = N * np.random.rand(N) + +# 一行一列第一个子图 +plt.subplot(111, projection='polar') +plt.scatter(theta, r, s=size, c=colors, alpha=0.8) +plt.title('极坐标散点图示例二', pad=15) + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/06.png) + +--- + +### 【5x03】方法三:pyplot.scatter() 与 pyplot.axes() + +axes 为 Matplotlib 图像中的绘图区,`matplotlib.pyplot.axes()` 方法可以对绘图区进行设置,同样的也可以设置 `projection` 参数为 `polar` 来实现极坐标图,设置 `polar=True` 也行。示例中其他函数的参数解释可参考前文: + +- [《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》](https://itrhx.blog.csdn.net/article/details/105638122) + +- [《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》](https://itrhx.blog.csdn.net/article/details/105914929) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +N = 50 +r = 2 * np.random.rand(N) +theta = 2 * np.pi * np.random.rand(N) +size = 200 * r ** 2 +colors = N * np.random.rand(N) + +# plt.axes(polar=True) +plt.axes(projection='polar') +plt.scatter(theta, r, s=size, c=colors, alpha=0.8) +plt.title('极坐标散点图示例三', pad=15) + +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/07.png) + +## 【6x00】高级用法:绘制极坐标柱状图 + +和极坐标散点图的绘制类似,`matplotlib.pyplot.polar()` 方法可以实现极坐标图,但仅用这一个函数的话实现的样式效果并不多,以下介绍另外三种绘制极坐标柱状图的方法: + +- `matplotlib.pyplot.polar()` 和 `matplotlib.pyplot.bar()` 结合,前者绘制极坐标图,后者在极坐标图上绘制柱状图; + +- `matplotlib.pyplot.subplot()` 和 `matplotlib.pyplot.bar()` 结合,前者添加子图,其中指定 `projection='polar'` 即为极坐标图, 后者在极坐标图上绘制柱状图; + +- `matplotlib.pyplot.axes()` 与 `matplotlib.pyplot.bar()` 结合,前者设置绘图区参数,其中指定 `projection='polar'` 或 `polar=True` 即为极坐标图, 后者在极坐标图上绘制柱状图。 + +--- + +### 【6x01】方法一:pyplot.bar() 与 pyplot.polar() + +以下用到的 `matplotlib.pyplot.bar()` 函数,各参数含义以及支持的其他参数可以参见前文: + +- [《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) + +- [《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》](https://itrhx.blog.csdn.net/article/details/105952856) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +r = np.random.rand(8) +theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8) +colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4']) + +plt.polar() +plt.bar(theta, r, color=colors, alpha=0.8) +plt.title('极坐标柱状图示例一', pad=15) + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/08.png) + +--- + +### 【6x02】方法二:pyplot.bar() 与 pyplot.subplot() + +`matplotlib.pyplot.subplot()` 方法用于添加子图,如果想要子图为极坐标图,则需要指定 `projection` 参数为 `polar`,有关此函数的具体介绍可参见[官方文档](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot.html)。其他函数的参数解释可参考前文: + +- [《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) + +- [《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》](https://itrhx.blog.csdn.net/article/details/105952856) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +r = np.random.rand(8) +theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8) +colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4']) + +plt.subplot(111, projection='polar') +plt.bar(theta, r, color=colors, alpha=0.8) +plt.title('极坐标柱状图示例二', pad=15) + +plt.show() +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/09.png) + +--- + +### 【6x03】方法三:pyplot.bar() 与 pyplot.axes() + +axes 为 Matplotlib 图像中的绘图区,`matplotlib.pyplot.axes()` 方法可以对绘图区进行设置,同样的也可以设置 `projection` 参数为 `polar` 来实现极坐标图,设置 `polar=True` 也行。示例中其他函数的参数解释可参考前文: + +- [《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》](https://itrhx.blog.csdn.net/article/details/105638122) + +- [《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》](https://itrhx.blog.csdn.net/article/details/105952856) + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +r = np.random.rand(8) +theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8) +colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4']) + +# plt.axes(polar=True) +plt.axes(projection='polar') +plt.bar(theta, r, color=colors, alpha=0.8) +plt.title('极坐标柱状图示例三', pad=15) + +plt.show() +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A76/10.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106162412 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A77-Matplotlib-10.md b/source/_posts/A77-Matplotlib-10.md new file mode 100644 index 0000000000000000000000000000000000000000..a622d39ca70cd0b2a5cc2af90edada254f31715c --- /dev/null +++ b/source/_posts/A77-Matplotlib-10.md @@ -0,0 +1,844 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 +tags: + - Matplotlib + - 3D图 +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106558131 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】了解 mplot3d Toolkit + +mplot3d Toolkit 即 mplot3d 工具包,在 matplotlib 中使用 mplot3d 工具包可以绘制 3D 图。 + +mplot3d 官方文档:[https://matplotlib.org/tutorials/toolkits/mplot3d.html](https://matplotlib.org/tutorials/toolkits/mplot3d.html) + +在 matplotlib 中,figure 为画布,axes 为绘图区,`fig.add_subplot()`、`plt.subplot()` 方法均可以创建子图,在绘制 3D 图时,某些 2D 图的参数也适用于 3D 图,在本文的示例中,可能会用到的一些没有具体解释的函数或者参数,其用法均可在前面的系列文章中找到: + +- [《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》](https://itrhx.blog.csdn.net/article/details/105638122) + +- [《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828049) + +- [《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》](https://itrhx.blog.csdn.net/article/details/105828143) + +**绘制 3D 图的步骤:创建 Axes3D 对象,然后调用 Axes3D 的不同方法来绘制不同类型的 3D 图。以下介绍三种 Axes3D 对象创建的方法。** + +### 【01x01】Axes3D 对象创建方法一:Axes3D(fig) + +在 Matplotlib 1.0.0 版本中,绘制 3D 图需要先导入 Axes3D 包,获取 figure 画布对象 fig 后,通过 Axes3D(fig) 方法来创建 Axes3D 对象,具体方法如下: + +```python +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D + +# 获取 figure 画布并创建 Axes3D 对象 +fig = plt.figure() +ax = Axes3D(fig) + +# 数据坐标 +z = np.linspace(0, 15, 1000) +x = np.sin(z) +y = np.cos(z) + +# 绘制线性图 +ax.plot(x, y, z) +plt.show() +``` + +### 【01x02】Axes3D 对象创建方法二:add_subplot + +在 Matplotlib 3.2.0 版本中,绘制 3D 图可以通过创建子图,然后指定 projection 参数 为 3d 即可,返回的 ax 为 Axes3D 对象,以下两种方法均可: + +```python +import numpy as np +import matplotlib.pyplot as plt + +# 获取 figure 画布并通过子图创建 Axes3D 对象 +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +# 数据坐标 +z = np.linspace(0, 15, 1000) +x = np.sin(z) +y = np.cos(z) + +# 绘制线性图 +ax.plot(x, y, z) +plt.show() +``` + +```python +import numpy as np +import matplotlib.pyplot as plt + +# 通过子图创建 Axes3D 对象 +ax = plt.subplot(111, projection='3d') + +# 数据坐标 +z = np.linspace(0, 15, 1000) +x = np.sin(z) +y = np.cos(z) + +# 绘制线性图 +ax.plot(x, y, z) +plt.show() +``` + +### 【01x03】Axes3D 对象创建方法三:gca + +除了以上两种方法以外,还可以先获取画布对象 fig,再通过 `fig.gca()` 方法获取当前绘图区(gca = Get Current Axes),然后指定 projection 参数 为 3d 即可,返回的 ax 为 Axes3D 对象。 + +```python +import numpy as np +import matplotlib.pyplot as plt + +# 依次获取画布和绘图区并创建 Axes3D 对象 +fig = plt.figure() +ax = fig.gca(projection='3d') + +# 数据坐标 +z = np.linspace(0, 15, 1000) +x = np.sin(z) +y = np.cos(z) + +# 绘制线性图 +ax.plot(x, y, z) +plt.show() +``` + +以上三种方法运行结果均为下图: + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/01.png) + +## 【02x00】cmap 与 colorbar + +默认情况下,散点图、线性图、曲面图等将以纯色着色,但可以通过提供 cmap 参数支持颜色映射。cmap 参数用于设置一些特殊的颜色组合,如渐变色等,参数取值通常为 Colormap 中的值,具体取值可参见下图: + +官方文档:[https://matplotlib.org/tutorials/colors/colormaps.html](https://matplotlib.org/tutorials/colors/colormaps.html) + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/02.png) + +如果使用了 cmap 参数,则可以使用 `pyplot.colorbar()` 函数来绘制一个色条,即颜色对照条。 + +基本语法:`matplotlib.pyplot.colorbar([mappable=None, cax=None, ax=None, **kw])` + +部分参数解释如下表,其他参数,如长度,宽度等请参考[官方文档](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.colorbar.html)。 + +| 参数 | 描述 | +| ------ | ------ | +| mappable | 要设置色条的图像对象,该参数对于 `Figure.colorbar` 方法是必需的,但对于 `pyplot.colorbar` 函数是可选的 | +| cax | 可选项,要绘制色条的轴 | +| ax | 可选项,设置色条的显示位置,通常在一个画布上有多个子图时使用 | +| **kw | 可选项,其他关键字参数,参考[官方文档](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.colorbar.html) | + +## 【03x00】3D 线性图:Axes3D.plot + +基本方法:`Axes3D.plot(xs, ys[, zs, zdir='z', *args, **kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| xs | 一维数组,点的 x 轴坐标 | +| ys | 一维数组,点的 y 轴坐标 | +| zs | 一维数组,可选项,点的 z 轴坐标 | +| zdir | 可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递,
若此时将 zdir 设置为 'y',数据将会被绘制到 x-z 轴平面上,默认为 'z' | +| **kwargs | 其他关键字参数,可选项,可参见 [matplotlib.axes.Axes.plot](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html) | + +```python +import numpy as np +import matplotlib.pyplot as plt + +# 设置中文显示 +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 依次获取画布和绘图区并创建 Axes3D 对象 +fig = plt.figure() +ax = fig.gca(projection='3d') + +# 第一条3D线性图数据 +theta = np.linspace(-4 * np.pi, 4 * np.pi, 100) +z1 = np.linspace(-2, 2, 100) +r = z1**2 + 1 +x1 = r * np.sin(theta) +y1 = r * np.cos(theta) + +# 第二条3D线性图数据 +z2 = np.linspace(-3, 3, 100) +x2 = np.sin(z2) +y2 = np.cos(z2) + +# 绘制3D线性图 +ax.plot(x1, y1, z1, color='b', label='3D 线性图一') +ax.plot(x2, y2, z2, color='r', label='3D 线性图二') + +# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel、plt.legend... +ax.set_title('绘制 3D 线性图示例', pad=15, fontsize='12') +ax.set_xlabel('x 轴', color='r', fontsize='12') +ax.set_ylabel('y 轴', color='g', fontsize='12') +ax.set_zlabel('z 轴', color='b', fontsize='12') +ax.legend() + +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/03.png) + +## 【04x00】3D 散点图:Axes3D.scatter + +基本方法:`Axes3D.scatter(xs, ys[, zs=0, zdir='z', s=20, c=None, depthshade=True, *args, **kwargs])` + +| 参数 | 描述 | +| ------ | ----- | +| xs | 一维数组,点的 x 轴坐标 | +| ys | 一维数组,点的 y 轴坐标 | +| zs | 一维数组,可选项,点的 z 轴坐标 | +| zdir | 可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递,
若此时将 zdir 设置为 'y',数据将会被绘制到 x-z 轴平面上,默认为 'z' | +| s | 标量或数组类型,可选项,标记的大小,默认 20 | +| c | 标记的颜色,可选项,可以是单个颜色或者一个颜色列表
支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 [Color Demo](https://matplotlib.org/gallery/color/color_demo.html) | +| depthshade | bool 值,可选项,默认 True,是否为散点标记着色以提供深度外观 | +| **kwargs | 其他关键字参数,可选项,可参见 [scatter](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.scatter.html) | + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 依次获取画布和绘图区并创建 Axes3D 对象 +fig = plt.figure() +ax = fig.gca(projection='3d') +n = 100 + + +def randrange(n, vmin, vmax): + return (vmax - vmin)*np.random.rand(n) + vmin + + +''' +定义绘制 n 个随机点,设置每一组数据点的样式和范围 +x轴数据位于[23,32]区间,y轴数据位于[0,100]区间,z轴数据位于[zlow,zhigh]区间 +''' +for m, zlow, zhigh in [('o', -50, -25), ('^', -30, -5)]: + xs = randrange(n, 23, 32) + ys = randrange(n, 0, 100) + zs = randrange(n, zlow, zhigh) + ax.scatter(xs, ys, zs, marker=m) + +# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel... +ax.set_title('绘制 3D 散点图示例', pad=15, fontsize='12') +ax.set_xlabel('x 轴', color='b') +ax.set_ylabel('y 轴', color='b') +ax.set_zlabel('z 轴', color='b') + +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/04.png) + +## 【05x00】3D 线框图:Axes3D.plot_wireframe + +基本方法:`Axes3D.plot_wireframe(X, Y, Z[, *args, **kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| X | 二维数组,x 轴数据 | +| Y | 二维数组,y 轴数据 | +| Z | 二维数组,z 轴数据 | +| **kwargs | 其他关键字参数,可选项,如线条样式颜色等,可参见 [Line3DCollection](https://matplotlib.org/api/_as_gen/mpl_toolkits.mplot3d.art3d.Line3DCollection.html) | + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 获取 figure 画布并通过子图创建 Axes3D 对象 +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + + +# 定义Z轴坐标的生成方法 +def f(m, n): + return np.sin(np.sqrt(m ** 2 + n ** 2)) + + +# 设置3D线框图数据 +x = np.linspace(-6, 6, 30) +y = np.linspace(-6, 6, 30) +# 生成网格点坐标矩阵,该方法在系列文章八中有具体介绍 +X, Y = np.meshgrid(x, y) +Z = f(X, Y) + +# 绘制3D线框图 +ax.plot_wireframe(X, Y, Z, color='c') + +# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel... +ax.set_title('绘制 3D 线框图示例', pad=15, fontsize='12') +ax.set_xlabel('x 轴') +ax.set_ylabel('y 轴') +ax.set_zlabel('z 轴') + +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/05.png) + +## 【06x00】3D 曲面图:Axes3D.plot_surface + +基本方法:`Axes3D.plot_surface(X, Y, Z[, *args, vmin=None, vmax=None, **kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| X | 二维数组,x 轴数据 | +| Y | 二维数组,y 轴数据 | +| Z | 二维数组,z 轴数据 | +| vmin / vmax | 规定数据界限 | +| **kwargs | 其他关键字参数,可选项,如线条样式颜色等,可参见 [Line3DCollection](https://matplotlib.org/api/_as_gen/mpl_toolkits.mplot3d.art3d.Line3DCollection.html) | + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 获取 figure 画布并通过子图创建 Axes3D 对象 +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +# 设置3D曲面图数据 +X = np.arange(-5, 5, 0.25) +Y = np.arange(-5, 5, 0.25) +# 生成网格点坐标矩阵,该方法在系列文章八中有具体介绍 +X, Y = np.meshgrid(X, Y) +R = np.sqrt(X**2 + Y**2) +Z = np.sin(R) + +# 绘制3D曲面图并添加色条(长度0.8) +surface = ax.plot_surface(X, Y, Z, cmap='rainbow', antialiased=False) +fig.colorbar(surface, shrink=0.8) + +# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel... +ax.set_title('绘制 3D 曲面图示例', pad=15, fontsize='12') +ax.set_xlabel('x 轴') +ax.set_ylabel('y 轴') +ax.set_zlabel('z 轴') +# 调整观察角度和方位角,俯仰角25度,方位角40度 +ax.view_init(25, 40) +# 设置Z轴刻度界限 +ax.set_zlim(-2, 2) + +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/06.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106558131 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【07x00】3D 柱状图:Axes3D.bar + +基本方法:`Axes3D.bar(left, height, zs=0, zdir='z', *args, **kwargs)` + +| 参数 | 描述 | +| ------ | ------ | +| left | 一维数组,柱状图最左侧位置的 x 坐标 | +| height | 一维数组,柱状图的高度(y 坐标) | +| zs | 第 i 个多边形将出现在平面 y=zs[i] 上 +| zdir | 可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递,
若此时将 zdir 设置为 'y',数据将会被绘制到 x-z 轴平面上,默认为 'z' | +| **kwargs | 其他关键字参数,参见 [matplotlib.axes.Axes.bar](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.bar.html) | + +```python +import matplotlib.pyplot as plt +import numpy as np + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 获取 figure 画布并通过子图创建 Axes3D 对象 +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +colors = ['r', 'g', 'b', 'y'] +yticks = [3, 2, 1, 0] + +# 设置3D柱状图数据并绘制图像 +for c, k in zip(colors, yticks): + xs = np.arange(20) + ys = np.random.rand(20) + cs = [c] * len(xs) + ax.bar(xs, ys, zs=k, zdir='y', color=cs, alpha=0.8) + +# 设置图像标题、坐标标签以及范围 +ax.set_title('绘制 3D 柱状图示例', pad=15, fontsize='12') +ax.set_xlabel('X 轴') +ax.set_ylabel('Y 轴') +ax.set_zlabel('Z 轴') +ax.set_yticks(yticks) + +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/07.png) + +## 【08x00】3D 箭头图:Axes3D.quiver + +基本方法:`Axes3D.quiver(X, Y, Z, U, V, W, length=1, arrow_length_ratio=0.3, pivot='tail', normalize=False, **kwargs)` + +| 参数 | 描述 | +| ------ | ------ | +| X, Y, Z | 数组形式,箭头位置的 x、y 和 z 轴坐标(默认为箭头尾部) | +| U, V, W | 数组形式,箭头向量的 x、y 和 z 轴分量 | +| length | float 类型,每个箭筒的长度,默认为 1.0 | +| arrow_length_ratio | float 类型,箭头相对于箭身的比率,默认为 0.3 | +| pivot | 箭头在网格点上的位置;箭头围绕该点旋转,因此命名为 pivot,默认为 'tail'
可选项:`'tail'`:尾部;`'middle'`:中间;`'tip'`:尖端 | +| normalize | bool 类型,如果为 True,则所有箭头的长度都将相同
默认为 False,即箭头的长度取决于 U、V、W 的值 | +| **kwargs | 其他关键字参数,参见 [LineCollection](https://matplotlib.org/api/collections_api.html#matplotlib.collections.LineCollection) | + +```python +import matplotlib.pyplot as plt +import numpy as np + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 依次获取画布和绘图区并创建 Axes3D 对象 +fig = plt.figure() +ax = fig.gca(projection='3d') + +# 设置箭头位置 +x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2), + np.arange(-0.8, 1, 0.2), + np.arange(-0.8, 1, 0.8)) + +# 设置箭头数据 +u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z) +v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z) +w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)) + +# 绘制 3D 箭头图 +ax.quiver(x, y, z, u, v, w, length=0.1, normalize=True) + +# 设置图像标题、坐标标签 +ax.set_title('绘制 3D 箭头图示例', pad=15, fontsize='12') +ax.set_xlabel('X 轴') +ax.set_ylabel('Y 轴') +ax.set_zlabel('Z 轴') + +# 调整观察角度,俯仰角20度 +ax.view_init(20) + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/08.png) + +## 【09x00】3D 等高线图:Axes3D.contour + +基本方法:`Axes3D.contour(X, Y, Z[, *args, extend3d=False, stride=5, zdir='z', offset=None, **kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| X | 一维数组,x 轴数据 | +| Y | 一维数组,y 轴数据 | +| Z | 一维数组,z 轴数据 | +| extend3d | bool 值,可选项,是否以 3D 延伸轮廓,默认 False | +| stride | int 类型,可选项,用于延伸轮廓的步长 | +| zdir | 可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递,
若此时将 zdir 设置为 'y',数据将会被绘制到 x-z 轴平面上,默认为 'z' | +| offset | 标量,可选项,如果指定,则在垂直于 zdir 的平面上的位置绘制轮廓线的投影 | +| **kwargs | 其他关键字参数,可选项,可参见 [matplotlib.axes.Axes.contour](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.contour.html) | + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 获取 figure 画布并通过子图创建 Axes3D 对象 +fig = plt.figure(figsize=(8, 4.8)) +ax = fig.add_subplot(111, projection='3d') + +# 设置等高线数据 +X = np.arange(-2.0, 2.0, 0.01) +Y = np.arange(-2.0, 2.0, 0.01) +# 生成网格点坐标矩阵 +m, n = np.meshgrid(X, Y) + + +# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度 +def f(a, b): + return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2) + + +# 绘制3D等高线图并添加色条图(长度0.8) +contour = ax.contour(X, Y, f(m, n), cmap='rainbow') +fig.colorbar(contour, shrink=0.8) + +# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel... +ax.set_title('绘制 3D 等高线图示例', pad=15, fontsize='12') +ax.set_xlabel('x 轴') +ax.set_ylabel('y 轴') +ax.set_zlabel('z 轴') + +plt.show() +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/09.png) + +## 【10x00】3D 等高线填充图:Axes3D.contourf + +基本语法:`Axes3D.contourf(X, Y, Z[, *args, zdir='z', offset=None, **kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| X | 一维数组,x 轴数据 | +| Y | 一维数组,y 轴数据 | +| Z | 一维数组,z 轴数据 | +| zdir | 可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递,
若此时将 zdir 设置为 'y',数据将会被绘制到 x-z 轴平面上,默认为 'z' | +| offset | 标量,可选项,如果指定,则在垂直于 zdir 的平面上的位置绘制轮廓线的投影 | +| **kwargs | 其他关键字参数,可选项,可参见 [matplotlib.axes.Axes.contourf](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.contourf.html) | + +```python +import numpy as np +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 获取 figure 画布并通过子图创建 Axes3D 对象 +fig = plt.figure(figsize=(8, 4.8)) +ax = fig.add_subplot(111, projection='3d') + +# 设置等高线数据 +X = np.arange(-2.0, 2.0, 0.01) +Y = np.arange(-2.0, 2.0, 0.01) +# 生成网格点坐标矩阵 +m, n = np.meshgrid(X, Y) + + +# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度 +def f(a, b): + return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2) + + +# 绘制3D等高线图并添加色条图(长度0.8) +contourf = ax.contourf(X, Y, f(m, n), cmap='rainbow') +fig.colorbar(contourf, shrink=0.8) + +# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel... +ax.set_title('绘制 3D 等高线填充图示例', pad=15, fontsize='12') +ax.set_xlabel('x 轴') +ax.set_ylabel('y 轴') +ax.set_zlabel('z 轴') + +plt.show() +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/10.png) + +## 【11x00】3D 三角曲面图:Axes3D.plot_trisurf + +基本方法:`Axes3D.plot_trisurf(X, Y, Z[, *args, color=None, vmin=None, vmax=None, **kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| X | 一维数组,x 轴数据 | +| Y | 一维数组,y 轴数据 | +| Z | 一维数组,z 轴数据 | +| color | 曲面表面的颜色 | +| vmin / vmax | 规定数据界限 | +| **kwargs | 可选项,其他关键字参数,可参见 [Poly3DCollection](https://matplotlib.org/api/_as_gen/mpl_toolkits.mplot3d.art3d.Poly3DCollection.html) | + +```python +import matplotlib.pyplot as plt +import numpy as np + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 获取 figure 画布并通过子图创建 Axes3D 对象 +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +n_radii = 8 +n_angles = 36 + +radii = np.linspace(0.125, 1.0, n_radii) +angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)[..., np.newaxis] +x = np.append(0, (radii*np.cos(angles)).flatten()) +y = np.append(0, (radii*np.sin(angles)).flatten()) +z = np.sin(-x*y) + +# 绘制3D三角曲面图并添加色条(长度0.8) +trisurf = ax.plot_trisurf(x, y, z, cmap='rainbow') +fig.colorbar(trisurf, shrink=0.8) + +# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel... +ax.set_title('绘制 3D 三角曲面图示例', pad=15, fontsize='12') +ax.set_xlabel('x 轴') +ax.set_ylabel('y 轴') +ax.set_zlabel('z 轴') + +plt.show() +``` + +![11](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/11.png) + +```python +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.tri as mtri + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +fig = plt.figure(figsize=(15, 6)) + +# ============ 第一个示例图 ============ # + +ax = fig.add_subplot(1, 2, 1, projection='3d') + +u = np.linspace(0, 2.0 * np.pi, endpoint=True, num=50) +v = np.linspace(-0.5, 0.5, endpoint=True, num=10) +u, v = np.meshgrid(u, v) +u, v = u.flatten(), v.flatten() + +x = (1 + 0.5 * v * np.cos(u / 2.0)) * np.cos(u) +y = (1 + 0.5 * v * np.cos(u / 2.0)) * np.sin(u) +z = 0.5 * v * np.sin(u / 2.0) + +tri = mtri.Triangulation(u, v) + +trisurf_1 = ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap='cool') +fig.colorbar(trisurf_1, shrink=0.8) +ax.set_zlim(-1, 1) + +ax.set_title('绘制 3D 三角曲面图示例一', pad=15, fontsize='12') +ax.set_xlabel('x 轴') +ax.set_ylabel('y 轴') +ax.set_zlabel('z 轴') + +# ============ 第二个示例图 ============ # + +ax = fig.add_subplot(1, 2, 2, projection='3d') + +n_angles = 36 +n_radii = 8 +min_radius = 0.25 +radii = np.linspace(min_radius, 0.95, n_radii) + +angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False) +angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1) +angles[:, 1::2] += np.pi/n_angles + +x = (radii*np.cos(angles)).flatten() +y = (radii*np.sin(angles)).flatten() +z = (np.cos(radii)*np.cos(3*angles)).flatten() + +triang = mtri.Triangulation(x, y) + +xmid = x[triang.triangles].mean(axis=1) +ymid = y[triang.triangles].mean(axis=1) +mask = xmid**2 + ymid**2 < min_radius**2 +triang.set_mask(mask) + +trisurf_2 = ax.plot_trisurf(triang, z, cmap='hsv') +fig.colorbar(trisurf_2, shrink=0.8) + +ax.set_title('绘制 3D 三角曲面图示例二', pad=15, fontsize='12') +ax.set_xlabel('x 轴') +ax.set_ylabel('y 轴') +ax.set_zlabel('z 轴') + +plt.show() +``` + +![12](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/12.png) + +## 【12x00】将 2D 图像聚合到 3D 图像中:Axes3D.add_collection3d + +基本方法:`Axes3D.add_collection3d(col, zs=0, zdir='z')` + +| 参数 | 描述 | +| ------ | ------ | +| col | [PolyCollection](https://matplotlib.org/api/collections_api.html?highlight=polycollection#matplotlib.collections.PolyCollection) / [LineCollection](https://matplotlib.org/api/collections_api.html?highlight=linecollection#matplotlib.collections.LineCollection) / [PatchCollection](https://matplotlib.org/api/collections_api.html?highlight=patchcollection#matplotlib.collections.PatchCollection) 对象 | +| zs | 第 i 个多边形将出现在平面 y=zs[i] 上 +| zdir | 可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递,
若此时将 zdir 设置为 'y',数据将会被绘制到 x-z 轴平面上,默认为 'z' | + +该函数一般用来向图形中添加 3D 集合对象,以下用一个示例来展示某个地区在不同年份和不同月份的降水量: + +```python +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.collections import PolyCollection + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +fig = plt.figure() +ax = fig.gca(projection='3d') + +np.random.seed(59) +month = np.arange(0, 13) +years = [2017, 2018, 2019, 2020] + +precipitation = [] +for year in years: + value = np.random.rand(len(month)) * 300 + value[0], value[-1] = 0, 0 + precipitation.append(list(zip(month, value))) + +poly = PolyCollection(precipitation, facecolors=['r', 'g', 'b', 'y'], alpha=.6) +ax.add_collection3d(poly, zs=years, zdir='y') + +ax.set_title('2D 图像聚合到 3D 图像示例', pad=15, fontsize='12') +ax.set_xlabel('月份') +ax.set_ylabel('年份') +ax.set_zlabel('降水量') +ax.set_xlim3d(0, 12) +ax.set_ylim3d(2016, 2021) +ax.set_zlim3d(0, 300) + +plt.show() +``` + +![13](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/13.png) + +此外,该方法也常被用于绘制 3D 多边形图,即多边体,示例如下: + +```python +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +fig = plt.figure() +ax = fig.gca(projection='3d') + +# 六面体顶点和面 +verts = [(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1), (1, 0, 1)] +faces = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [0, 3, 7, 4]] + +# 获取每个面的顶点 +poly3d = [[verts[vert_id] for vert_id in face] for face in faces] + +# 绘制顶点 +x, y, z = zip(*verts) +ax.scatter(x, y, z) +# 绘制多边形面 +ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w', linewidths=1, alpha=0.5)) +# 绘制多边形的边 +ax.add_collection3d(Line3DCollection(poly3d, colors='k', linewidths=0.5, linestyles=':')) + +# 设置图像标题、坐标标签以及范围 +ax.set_title('绘制多边体示例', pad=15, fontsize='12') +ax.set_xlabel('X 轴') +ax.set_ylabel('Y 轴') +ax.set_zlabel('Z 轴') +ax.set_xlim3d(-0.5, 1.5) +ax.set_ylim3d(-0.5, 1.5) +ax.set_zlim3d(-0.5, 1.5) +plt.show() +``` + +![14](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/14.png) + +## 【13x00】3D 图添加文本描述:Axes3D.text + +基本方法:`Axes3D.text(x, y, z, s[, zdir=None, **kwargs])` + +| 参数 | 描述 | +| ------ | ------ | +| x, y, z | 文本位置的 x、y、z 轴坐标 | +| s | 要添加的文本 | +| zdir | 可选项,若将 zdir 设置为 'y',文本将会被投影到 x-z 轴平面上,默认为 None | +| **kwargs | 其他关键字参数,参见 [matplotlib.text](https://matplotlib.org/api/text_api.html) | + +```python +import matplotlib.pyplot as plt + +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + +# 依次获取画布和绘图区并创建 Axes3D 对象 +fig = plt.figure() +ax = fig.gca(projection='3d') + +# Demo 1: zdir 参数用法 +zdirs = (None, 'x', 'y', 'z', (1, 1, 0), (1, 1, 1)) +xs = (1, 4, 4, 9, 4, 1) +ys = (2, 5, 8, 10, 1, 2) +zs = (10, 3, 8, 9, 1, 8) + +for zdir, x, y, z in zip(zdirs, xs, ys, zs): + label = '(%d, %d, %d), dir=%s' % (x, y, z, zdir) + ax.text(x, y, z, label, zdir) + +# Demo 2:设置颜色 +ax.text(9, 0, 0, "red", color='red') + +# Demo 3: text2D,位置(0,0)为左下角,(1,1)为右上角。 +ax.text2D(0.05, 0.95, "2D Text", transform=ax.transAxes) + +# 设置坐标轴界限和标签 +ax.set_xlim(0, 10) +ax.set_ylim(0, 10) +ax.set_zlim(0, 10) +ax.set_xlabel('X 轴') +ax.set_ylabel('Y 轴') +ax.set_zlabel('Z 轴') + +plt.show() +``` + +![15](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A77/15.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106558131 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A78-Matplotlib-11.md b/source/_posts/A78-Matplotlib-11.md new file mode 100644 index 0000000000000000000000000000000000000000..ebaa484697906d38320d6705a6e763ee7f01ff3f --- /dev/null +++ b/source/_posts/A78-Matplotlib-11.md @@ -0,0 +1,2024 @@ +--- +title: Python 数据分析三剑客之 Matplotlib(十一):最常用最有价值的 50 个图表【译文】 +tags: + - Matplotlib +categories: + - Python 数据分析 + - Matplotlib +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/matplotlib.png +avatar: https://c.disquscdn.com/uploads/users/7256/9757/avatar92.jpg +author: Selva Prabhakaran +author_url: https://www.machinelearningplus.com/author/selva86/ +description: Python 数据分析三剑客之 Matplotlib(十一):最常用的、最有价值的 50 个图表【译文】。 +--- + +Matplotlib 系列文章: + +- [Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件](https://www.itrhx.com/2020/04/10/A68-Matplotlib-01/) +- [Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性](https://www.itrhx.com/2020/04/12/A69-Matplotlib-02/) +- [Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性](https://www.itrhx.com/2020/04/14/A70-Matplotlib-03/) +- [Python 数据分析三剑客之 Matplotlib(四):线性图的绘制](https://www.itrhx.com/2020/04/16/A71-Matplotlib-04/) +- [Python 数据分析三剑客之 Matplotlib(五):散点图的绘制](https://www.itrhx.com/2020/04/18/A72-Matplotlib-05/) +- [Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制](https://www.itrhx.com/2020/04/21/A73-Matplotlib-06/) +- [Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制](https://www.itrhx.com/2020/04/24/A74-Matplotlib-07/) +- [Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制](https://www.itrhx.com/2020/04/30/A75-Matplotlib-08/) +- [Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制](https://www.itrhx.com/2020/06/03/A76-Matplotlib-09/) +- [Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制](https://www.itrhx.com/2020/06/08/A77-Matplotlib-10/) +- [Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表](https://www.itrhx.com/2020/06/09/A78-Matplotlib-11/)【译文】 + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +> 翻译丨[TRHX](https://itrhx.blog.csdn.net/) +> 作者丨[Selva Prabhakaran](https://www.machinelearningplus.com/author/selva86/) +> 原文丨[《Top 50 matplotlib Visualizations – The Master Plots (with full python code)》](https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/) + +--- + +> ★ 本文中的示例原作者使用的编辑器为 Jupyter Notebook; +> ★ 译者使用 PyCharm 测试原文中有部分代码不太准确,部分已进行修改,对应有注释说明; +> ★ 运行本文代码,需要安装 Matplotlib 和 Seaborn 等可视化库,其他的一些辅助可视化库已在代码部分作标注; +> ★ 示例中用到的数据均储存在作者的 GitHub:[https://github.com/selva86/datasets](https://github.com/selva86/datasets),因此运行程序可能需要FQ; +> ★ 译者英文水平有限,若遇到翻译模糊的词建议参考原文来理解。 +> ★ 本文50个示例代码已打包为 .py 文件,可直接下载:[https://download.csdn.net/download/qq_36759224/12507219](https://download.csdn.net/download/qq_36759224/12507219) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本译文首发于 CSDN,作者 Selva Prabhakaran,译者 TRHX。 +本文链接:https://itrhx.blog.csdn.net/article/details/106558131 +原文链接:https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/ +``` + +--- + +## 【1x00】介绍(Introduction) + +在数据分析和可视化中最常用的、最有价值的前 50 个 Matplotlib 图表。这些图表会让你懂得在不同情况下合理使用 Python 的 Matplotlib 和 Seaborn 库来达到数据可视化效果。 + +这些图表根据可视化目标的 7 个不同情景进行分组。 例如,如果要想象两个变量之间的关系,请查看“关联”部分下的图表。 或者,如果您想要显示值如何随时间变化,请查看“变化”部分,依此类推。 + +有效图表的重要特征: + +- 在不歪曲事实的情况下传达正确和必要的信息; +- 设计简单,不必太费力就能理解它; +- 从审美角度支持信息而不是掩盖信息; +- 信息没有超负荷。 + +## 【2x00】准备工作(Setup) + +在代码运行前先引入下面的基本设置,当然,个别图表可能会重新定义显示要素。 + +```python +# !pip install brewer2mpl +import numpy as np +import pandas as pd +import matplotlib as mpl +import matplotlib.pyplot as plt +import seaborn as sns +import warnings; warnings.filterwarnings(action='once') + +large = 22; med = 16; small = 12 +params = {'axes.titlesize': large, + 'legend.fontsize': med, + 'figure.figsize': (16, 10), + 'axes.labelsize': med, + 'axes.titlesize': med, + 'xtick.labelsize': med, + 'ytick.labelsize': med, + 'figure.titlesize': large} +plt.rcParams.update(params) +plt.style.use('seaborn-whitegrid') +sns.set_style("white") +%matplotlib inline + +# Version +print(mpl.__version__) #> 3.0.0 +print(sns.__version__) #> 0.9.0 +``` + +## 【3x00】关联(Correlation) + +关联图用于可视化两个或多个变量之间的关系。也就是说,一个变量相对于另一个变量如何变化。 + +### 【01】散点图(Scatter plot) + +散点图是研究两个变量之间关系的经典和基本的绘图。如果数据中有多个组,则可能需要以不同的颜色显示每个组。在 Matplotlib 中,您可以使用 `plt.scatterplot()` 方便地执行此操作。 + +```python +# Import dataset +midwest = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv") + +# Prepare Data +# Create as many colors as there are unique midwest['category'] +categories = np.unique(midwest['category']) +colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))] + +# Draw Plot for Each Category +plt.figure(figsize=(16, 10), dpi= 80, facecolor='w', edgecolor='k') + +for i, category in enumerate(categories): + plt.scatter('area', 'poptotal', + data=midwest.loc[midwest.category==category, :], + s=20, cmap=colors[i], label=str(category)) +# 原文 c=colors[i] 已修改为 cmap=colors[i] + +# Decorations +plt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000), + xlabel='Area', ylabel='Population') + +plt.xticks(fontsize=12); plt.yticks(fontsize=12) +plt.title("Scatterplot of Midwest Area vs Population", fontsize=22) +plt.legend(fontsize=12) +plt.show() +``` + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/01.png) + +### 【02】带边界的气泡图(Bubble plot with Encircling) + +有时候您想在一个边界内显示一组点来强调它们的重要性。在本例中,您将从被包围的数据中获取记录,并将其传递给下面的代码中描述的 `encircle()`。 + +```python +from matplotlib import patches +from scipy.spatial import ConvexHull +import warnings; warnings.simplefilter('ignore') +sns.set_style("white") + +# Step 1: Prepare Data +midwest = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv") + +# As many colors as there are unique midwest['category'] +categories = np.unique(midwest['category']) +colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))] + +# Step 2: Draw Scatterplot with unique color for each category +fig = plt.figure(figsize=(16, 10), dpi=80, facecolor='w', edgecolor='k') + +for i, category in enumerate(categories): + plt.scatter('area', 'poptotal', data=midwest.loc[midwest.category == category, :], s='dot_size', cmap=colors[i], label=str(category), edgecolors='black', linewidths=.5) +# 原文 c=colors[i] 已修改为 cmap=colors[i] + +# Step 3: Encircling +# https://stackoverflow.com/questions/44575681/how-do-i-encircle-different-data-sets-in-scatter-plot +def encircle(x,y, ax=None, **kw): + if not ax: ax = plt.gca() + p = np.c_[x, y] + hull = ConvexHull(p) + poly = plt.Polygon(p[hull.vertices, :], **kw) + ax.add_patch(poly) + +# Select data to be encircled +midwest_encircle_data = midwest.loc[midwest.state=='IN', :] + +# Draw polygon surrounding vertices +encircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec="k", fc="gold", alpha=0.1) +encircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec="firebrick", fc="none", linewidth=1.5) + +# Step 4: Decorations +plt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000), + xlabel='Area', ylabel='Population') + +plt.xticks(fontsize=12); plt.yticks(fontsize=12) +plt.title("Bubble Plot with Encircling", fontsize=22) +plt.legend(fontsize=12) +plt.show() +``` + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/02.png) + +### 【03】带线性回归最佳拟合线的散点图(Scatter plot with linear regression line of best fit) + +如果你想了解两个变量之间是如何变化的,那么最佳拟合线就是常用的方法。下图显示了数据中不同组之间的最佳拟合线的差异。若要禁用分组并只为整个数据集绘制一条最佳拟合线,请从 `sns.lmplot()` 方法中删除 `hue ='cyl'` 参数。 + +```python +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv") +df_select = df.loc[df.cyl.isin([4, 8]), :] + +# Plot +sns.set_style("white") +gridobj = sns.lmplot(x="displ", y="hwy", hue="cyl", data=df_select, + height=7, aspect=1.6, robust=True, palette='tab10', + scatter_kws=dict(s=60, linewidths=.7, edgecolors='black')) + +# Decorations +gridobj.set(xlim=(0.5, 7.5), ylim=(0, 50)) +plt.title("Scatterplot with line of best fit grouped by number of cylinders", fontsize=20) +plt.show() +``` + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/03.png) + +针对每一组数据绘制线性回归线(Each regression line in its own column),可以通过在 `sns.lmplot()` 中设置 `col=groupingcolumn` 参数来实现,如下: + +```python +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv") +df_select = df.loc[df.cyl.isin([4, 8]), :] + +# Each line in its own column +sns.set_style("white") +gridobj = sns.lmplot(x="displ", y="hwy", + data=df_select, + height=7, + robust=True, + palette='Set1', + col="cyl", + scatter_kws=dict(s=60, linewidths=.7, edgecolors='black')) + +# Decorations +gridobj.set(xlim=(0.5, 7.5), ylim=(0, 50)) +plt.show() +``` + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/04.png) + +### 【04】抖动图(Jittering with stripplot) + +通常,多个数据点具有完全相同的 X 和 Y 值。 此时多个点绘制会重叠并隐藏。为避免这种情况,可以将数据点稍微抖动,以便可以直观地看到它们。 使用 `seaborn` 库的 `stripplot()` 方法可以很方便的实现这个功能。 + +```python +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv") + +# Draw Stripplot +fig, ax = plt.subplots(figsize=(16,10), dpi= 80) +sns.stripplot(df.cty, df.hwy, jitter=0.25, size=8, ax=ax, linewidth=.5) + +# Decorations +plt.title('Use jittered plots to avoid overlapping of points', fontsize=22) +plt.show() +``` + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/05.png) + +### 【05】计数图(Counts Plot) + +避免点重叠问题的另一个选择是根据点的位置增加点的大小。所以,点的大小越大,它周围的点就越集中。 + +```python +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv") +df_counts = df.groupby(['hwy', 'cty']).size().reset_index(name='counts') + +# Draw Stripplot +fig, ax = plt.subplots(figsize=(16,10), dpi= 80) +sns.stripplot(df_counts.cty, df_counts.hwy, size=df_counts.counts*2, ax=ax) + +# Decorations +plt.title('Counts Plot - Size of circle is bigger as more points overlap', fontsize=22) +plt.show() +``` + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/06.png) + + +### 【06】边缘直方图(Marginal Histogram) + +边缘直方图是具有沿 X 和 Y 轴变量的直方图。 这用于可视化 X 和 Y 之间的关系以及单独的 X 和 Y 的单变量分布。 这种图经常用于探索性数据分析(EDA)。 + +```python +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv") + +# Create Fig and gridspec +fig = plt.figure(figsize=(16, 10), dpi= 80) +grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2) + +# Define the axes +ax_main = fig.add_subplot(grid[:-1, :-1]) +ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[]) +ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[]) + +# Scatterplot on main ax +ax_main.scatter('displ', 'hwy', s=df.cty*4, c=df.manufacturer.astype('category').cat.codes, alpha=.9, data=df, cmap="tab10", edgecolors='gray', linewidths=.5) + +# histogram on the right +ax_bottom.hist(df.displ, 40, histtype='stepfilled', orientation='vertical', color='deeppink') +ax_bottom.invert_yaxis() + +# histogram in the bottom +ax_right.hist(df.hwy, 40, histtype='stepfilled', orientation='horizontal', color='deeppink') + +# Decorations +ax_main.set(title='Scatterplot with Histograms \n displ vs hwy', xlabel='displ', ylabel='hwy') +ax_main.title.set_fontsize(20) +for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()): + item.set_fontsize(14) + +xlabels = ax_main.get_xticks().tolist() +ax_main.set_xticklabels(xlabels) +plt.show() +``` + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/07.png) + +### 【07】边缘箱形图(Marginal Boxplot) + +边缘箱形图与边缘直方图具有相似的用途。 然而,箱线图有助于精确定位 X 和 Y 的中位数、第25和第75百分位数。 + +```python +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv") + +# Create Fig and gridspec +fig = plt.figure(figsize=(16, 10), dpi= 80) +grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2) + +# Define the axes +ax_main = fig.add_subplot(grid[:-1, :-1]) +ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[]) +ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[]) + +# Scatterplot on main ax +ax_main.scatter('displ', 'hwy', s=df.cty*5, c=df.manufacturer.astype('category').cat.codes, alpha=.9, data=df, cmap="Set1", edgecolors='black', linewidths=.5) + +# Add a graph in each part +sns.boxplot(df.hwy, ax=ax_right, orient="v") +sns.boxplot(df.displ, ax=ax_bottom, orient="h") + +# Decorations ------------------ +# Remove x axis name for the boxplot +ax_bottom.set(xlabel='') +ax_right.set(ylabel='') + +# Main Title, Xlabel and YLabel +ax_main.set(title='Scatterplot with Histograms \n displ vs hwy', xlabel='displ', ylabel='hwy') + +# Set font size of different components +ax_main.title.set_fontsize(20) +for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()): + item.set_fontsize(14) + +plt.show() +``` + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/08.png) + +### 【08】相关图(Correllogram) + +相关图用于直观地查看给定数据帧(或二维数组)中所有可能的数值变量对之间的相关性度量。 + +```python +# Import Dataset +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv") + +# Plot +plt.figure(figsize=(12, 10), dpi=80) +sns.heatmap(df.corr(), xticklabels=df.corr().columns, yticklabels=df.corr().columns, cmap='RdYlGn', center=0, annot=True) + +# Decorations +plt.title('Correlogram of mtcars', fontsize=22) +plt.xticks(fontsize=12) +plt.yticks(fontsize=12) +plt.show() +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/09.png) + +### 【09】成对图(Pairwise Plot) + +成对图是探索性分析中最受欢迎的一种方法,用来理解所有可能的数值变量对之间的关系。它是二元分析的必备工具。 + +```python +# Load Dataset +df = sns.load_dataset('iris') + +# Plot +plt.figure(figsize=(10, 8), dpi=80) +sns.pairplot(df, kind="scatter", hue="species", plot_kws=dict(s=80, edgecolor="white", linewidth=2.5)) +plt.show() +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/10.png) + +```python +# Load Dataset +df = sns.load_dataset('iris') + +# Plot +plt.figure(figsize=(10, 8), dpi=80) +sns.pairplot(df, kind="reg", hue="species") +plt.show() +``` + +![11](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/11.png) + +## 【4x00】偏差(Deviation) + +### 【10】发散型条形图(Diverging Bars) + +如果您想根据单个指标查看项目的变化情况,并可视化此差异的顺序和数量,那么散型条形图是一个很好的工具。 它有助于快速区分数据组的性能,并且非常直观,并且可以立即传达这一点。 + +```python +# Prepare Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv") +x = df.loc[:, ['mpg']] +df['mpg_z'] = (x - x.mean())/x.std() +df['colors'] = ['red' if x < 0 else 'green' for x in df['mpg_z']] +df.sort_values('mpg_z', inplace=True) +df.reset_index(inplace=True) + +# Draw plot +plt.figure(figsize=(14,10), dpi= 80) +plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=5) + +# Decorations +plt.gca().set(ylabel='$Model$', xlabel='$Mileage$') +plt.yticks(df.index, df.cars, fontsize=12) +plt.title('Diverging Bars of Car Mileage', fontdict={'size':20}) +plt.grid(linestyle='--', alpha=0.5) +plt.show() +``` + +![12](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/12.png) + +### 【11】发散型文本图(Diverging Texts) + +发散型文本图与发散型条形图相似,如果你希望以一种美观的方式显示图表中每个项目的值,就可以使用这种方法。 + +```python +# Prepare Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv") +x = df.loc[:, ['mpg']] +df['mpg_z'] = (x - x.mean())/x.std() +df['colors'] = ['red' if x < 0 else 'green' for x in df['mpg_z']] +df.sort_values('mpg_z', inplace=True) +df.reset_index(inplace=True) + +# Draw plot +plt.figure(figsize=(14, 14), dpi=80) +plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z) +for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z): + t = plt.text(x, y, round(tex, 2), horizontalalignment='right' if x < 0 else 'left', + verticalalignment='center', fontdict={'color':'red' if x < 0 else 'green', 'size':14}) + +# Decorations +plt.yticks(df.index, df.cars, fontsize=12) +plt.title('Diverging Text Bars of Car Mileage', fontdict={'size':20}) +plt.grid(linestyle='--', alpha=0.5) +plt.xlim(-2.5, 2.5) +plt.show() +``` + +![13](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/13.png) + +### 【12】发散型散点图(Diverging Dot Plot) + +发散型散点图类似于发散型条形图。 但是,与发散型条形图相比,没有条形会减少组之间的对比度和差异。 + +```python +# Prepare Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv") +x = df.loc[:, ['mpg']] +df['mpg_z'] = (x - x.mean())/x.std() +df['colors'] = ['red' if x < 0 else 'darkgreen' for x in df['mpg_z']] +df.sort_values('mpg_z', inplace=True) +df.reset_index(inplace=True) + +# Draw plot +plt.figure(figsize=(14, 16), dpi=80) +plt.scatter(df.mpg_z, df.index, s=450, alpha=.6, color=df.colors) +for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z): + t = plt.text(x, y, round(tex, 1), horizontalalignment='center', + verticalalignment='center', fontdict={'color': 'white'}) + +# Decorations +# Lighten borders +plt.gca().spines["top"].set_alpha(.3) +plt.gca().spines["bottom"].set_alpha(.3) +plt.gca().spines["right"].set_alpha(.3) +plt.gca().spines["left"].set_alpha(.3) + +plt.yticks(df.index, df.cars) +plt.title('Diverging Dotplot of Car Mileage', fontdict={'size': 20}) +plt.xlabel('$Mileage$') +plt.grid(linestyle='--', alpha=0.5) +plt.xlim(-2.5, 2.5) +plt.show() +``` + +![14](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/14.png) + +### 【13】带标记的发散型棒棒糖图(Diverging Lollipop Chart with Markers) + +带有标记的棒棒糖提供了一种灵活的方式,强调您想要引起注意的任何重要数据点并在图表中适当地给出推理。 + +```python +# Prepare Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv") +x = df.loc[:, ['mpg']] +df['mpg_z'] = (x - x.mean())/x.std() +df['colors'] = 'black' + +# color fiat differently +df.loc[df.cars == 'Fiat X1-9', 'colors'] = 'darkorange' +df.sort_values('mpg_z', inplace=True) +df.reset_index(inplace=True) + + +# Draw plot +import matplotlib.patches as patches + +plt.figure(figsize=(14, 16), dpi=80) +plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=1) +plt.scatter(df.mpg_z, df.index, color=df.colors, s=[600 if x == 'Fiat X1-9' else 300 for x in df.cars], alpha=0.6) +plt.yticks(df.index, df.cars) +plt.xticks(fontsize=12) + +# Annotate +plt.annotate('Mercedes Models', xy=(0.0, 11.0), xytext=(1.0, 11), xycoords='data', + fontsize=15, ha='center', va='center', + bbox=dict(boxstyle='square', fc='firebrick'), + arrowprops=dict(arrowstyle='-[, widthB=2.0, lengthB=1.5', lw=2.0, color='steelblue'), color='white') + +# Add Patches +p1 = patches.Rectangle((-2.0, -1), width=.3, height=3, alpha=.2, facecolor='red') +p2 = patches.Rectangle((1.5, 27), width=.8, height=5, alpha=.2, facecolor='green') +plt.gca().add_patch(p1) +plt.gca().add_patch(p2) + +# Decorate +plt.title('Diverging Bars of Car Mileage', fontdict={'size': 20}) +plt.grid(linestyle='--', alpha=0.5) +plt.show() +``` + +![15](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/15.png) + +### 【14】面积图(Area Chart) + +通过对轴和线之间的区域进行着色,面积图不仅强调波峰和波谷,还强调波峰和波谷的持续时间。 高点持续时间越长,线下面积越大。 + +```python +import numpy as np +import pandas as pd + +# Prepare Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv", parse_dates=['date']).head(100) +x = np.arange(df.shape[0]) +y_returns = (df.psavert.diff().fillna(0)/df.psavert.shift(1)).fillna(0) * 100 + +# Plot +plt.figure(figsize=(16, 10), dpi=80) +plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] >= 0, facecolor='green', interpolate=True, alpha=0.7) +plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] <= 0, facecolor='red', interpolate=True, alpha=0.7) + +# Annotate +plt.annotate('Peak \n1975', xy=(94.0, 21.0), xytext=(88.0, 28), + bbox=dict(boxstyle='square', fc='firebrick'), + arrowprops=dict(facecolor='steelblue', shrink=0.05), fontsize=15, color='white') + + +# Decorations +xtickvals = [str(m)[:3].upper()+"-"+str(y) for y, m in zip(df.date.dt.year, df.date.dt.month_name())] +plt.gca().set_xticks(x[::6]) +plt.gca().set_xticklabels(xtickvals[::6], rotation=90, fontdict={'horizontalalignment': 'center', 'verticalalignment': 'center_baseline'}) +plt.ylim(-35, 35) +plt.xlim(1, 100) +plt.title("Month Economics Return %", fontsize=22) +plt.ylabel('Monthly returns %') +plt.grid(alpha=0.5) +plt.show() +``` + +![16](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/16.png) + +## 【5x00】排序(Ranking) + +### 【15】有序条形图(Ordered Bar Chart) + +有序条形图有效地传达了项目的排序顺序。在图表上方添加度量标准的值,用户就可以从图表本身获得精确的信息。 + +```python +# Prepare Data +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") +df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean()) +df.sort_values('cty', inplace=True) +df.reset_index(inplace=True) + +# Draw plot +import matplotlib.patches as patches + +fig, ax = plt.subplots(figsize=(16,10), facecolor='white', dpi= 80) +ax.vlines(x=df.index, ymin=0, ymax=df.cty, color='firebrick', alpha=0.7, linewidth=20) + +# Annotate Text +for i, cty in enumerate(df.cty): + ax.text(i, cty+0.5, round(cty, 1), horizontalalignment='center') + + +# Title, Label, Ticks and Ylim +ax.set_title('Bar Chart for Highway Mileage', fontdict={'size':22}) +ax.set(ylabel='Miles Per Gallon', ylim=(0, 30)) +plt.xticks(df.index, df.manufacturer.str.upper(), rotation=60, horizontalalignment='right', fontsize=12) + +# Add patches to color the X axis labels +p1 = patches.Rectangle((.57, -0.005), width=.33, height=.13, alpha=.1, facecolor='green', transform=fig.transFigure) +p2 = patches.Rectangle((.124, -0.005), width=.446, height=.13, alpha=.1, facecolor='red', transform=fig.transFigure) +fig.add_artist(p1) +fig.add_artist(p2) +plt.show() +``` + +![17](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/17.png) + +### 【16】棒棒糖图(Lollipop Chart) + +棒棒糖图表以一种视觉上令人愉悦的方式提供与有序条形图类似的目的。 + +```python +# Prepare Data +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") +df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean()) +df.sort_values('cty', inplace=True) +df.reset_index(inplace=True) + +# Draw plot +fig, ax = plt.subplots(figsize=(16, 10), dpi=80) +ax.vlines(x=df.index, ymin=0, ymax=df.cty, color='firebrick', alpha=0.7, linewidth=2) +ax.scatter(x=df.index, y=df.cty, s=75, color='firebrick', alpha=0.7) + +# Title, Label, Ticks and Ylim +ax.set_title('Lollipop Chart for Highway Mileage', fontdict={'size': 22}) +ax.set_ylabel('Miles Per Gallon') +ax.set_xticks(df.index) +ax.set_xticklabels(df.manufacturer.str.upper(), rotation=60, fontdict={'horizontalalignment': 'right', 'size': 12}) +ax.set_ylim(0, 30) + +# Annotate +for row in df.itertuples(): + ax.text(row.Index, row.cty+.5, s=round(row.cty, 2), horizontalalignment='center', verticalalignment='bottom', fontsize=14) + +plt.show() +``` + +![18](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/18.png) + +### 【17】点图(Dot Plot) + +点图可以表示项目的排名顺序。由于它是沿水平轴对齐的,所以可以更容易地看到点之间的距离。 + +```python +# Prepare Data +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") +df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean()) +df.sort_values('cty', inplace=True) +df.reset_index(inplace=True) + +# Draw plot +fig, ax = plt.subplots(figsize=(16, 10), dpi=80) +ax.hlines(y=df.index, xmin=11, xmax=26, color='gray', alpha=0.7, linewidth=1, linestyles='dashdot') +ax.scatter(y=df.index, x=df.cty, s=75, color='firebrick', alpha=0.7) + +# Title, Label, Ticks and Ylim +ax.set_title('Dot Plot for Highway Mileage', fontdict={'size': 22}) +ax.set_xlabel('Miles Per Gallon') +ax.set_yticks(df.index) +ax.set_yticklabels(df.manufacturer.str.title(), fontdict={'horizontalalignment': 'right'}) +ax.set_xlim(10, 27) +plt.show() +``` + +![19](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/19.png) + +### 【18】坡度图(Slope Chart) + +坡度图最适合比较给定人员/项目的“前”和“后”位置。 + +```python +import matplotlib.lines as mlines + +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/gdppercap.csv") + +left_label = [str(c) + ', ' + str(round(y)) for c, y in zip(df.continent, df['1952'])] +right_label = [str(c) + ', ' + str(round(y)) for c, y in zip(df.continent, df['1957'])] +klass = ['red' if (y1 - y2) < 0 else 'green' for y1, y2 in zip(df['1952'], df['1957'])] + + +# draw line +# https://stackoverflow.com/questions/36470343/how-to-draw-a-line-with-matplotlib/36479941 +def newline(p1, p2, color='black'): + ax = plt.gca() + l = mlines.Line2D([p1[0], p2[0]], [p1[1], p2[1]], color='red' if p1[1] - p2[1] > 0 else 'green', marker='o', + markersize=6) + ax.add_line(l) + return l + + +fig, ax = plt.subplots(1, 1, figsize=(14, 14), dpi=80) + +# Vertical Lines +ax.vlines(x=1, ymin=500, ymax=13000, color='black', alpha=0.7, linewidth=1, linestyles='dotted') +ax.vlines(x=3, ymin=500, ymax=13000, color='black', alpha=0.7, linewidth=1, linestyles='dotted') + +# Points +ax.scatter(y=df['1952'], x=np.repeat(1, df.shape[0]), s=10, color='black', alpha=0.7) +ax.scatter(y=df['1957'], x=np.repeat(3, df.shape[0]), s=10, color='black', alpha=0.7) + +# Line Segmentsand Annotation +for p1, p2, c in zip(df['1952'], df['1957'], df['continent']): + newline([1, p1], [3, p2]) + ax.text(1 - 0.05, p1, c + ', ' + str(round(p1)), horizontalalignment='right', verticalalignment='center', + fontdict={'size': 14}) + ax.text(3 + 0.05, p2, c + ', ' + str(round(p2)), horizontalalignment='left', verticalalignment='center', + fontdict={'size': 14}) + +# 'Before' and 'After' Annotations +ax.text(1 - 0.05, 13000, 'BEFORE', horizontalalignment='right', verticalalignment='center', + fontdict={'size': 18, 'weight': 700}) +ax.text(3 + 0.05, 13000, 'AFTER', horizontalalignment='left', verticalalignment='center', + fontdict={'size': 18, 'weight': 700}) + +# Decoration +ax.set_title("Slopechart: Comparing GDP Per Capita between 1952 vs 1957", fontdict={'size': 22}) +ax.set(xlim=(0, 4), ylim=(0, 14000), ylabel='Mean GDP Per Capita') +ax.set_xticks([1, 3]) +ax.set_xticklabels(["1952", "1957"]) +plt.yticks(np.arange(500, 13000, 2000), fontsize=12) + +# Lighten borders +plt.gca().spines["top"].set_alpha(.0) +plt.gca().spines["bottom"].set_alpha(.0) +plt.gca().spines["right"].set_alpha(.0) +plt.gca().spines["left"].set_alpha(.0) +plt.show() +``` + +![20](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/20.png) + +### 【19】哑铃图(Dumbbell Plot) + +哑铃图传达了各种项目的“前”和“后”位置以及项目的等级顺序。如果您希望可视化特定项目/计划对不同对象的影响,那么它非常有用。 + +```python +import matplotlib.lines as mlines + +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/health.csv") +df.sort_values('pct_2014', inplace=True) +df.reset_index(inplace=True) + + +# Func to draw line segment +def newline(p1, p2, color='black'): + ax = plt.gca() + l = mlines.Line2D([p1[0], p2[0]], [p1[1], p2[1]], color='skyblue') + ax.add_line(l) + return l + + +# Figure and Axes +fig, ax = plt.subplots(1, 1, figsize=(14, 14), facecolor='#f7f7f7', dpi=80) + +# Vertical Lines +ax.vlines(x=.05, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted') +ax.vlines(x=.10, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted') +ax.vlines(x=.15, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted') +ax.vlines(x=.20, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted') + +# Points +ax.scatter(y=df['index'], x=df['pct_2013'], s=50, color='#0e668b', alpha=0.7) +ax.scatter(y=df['index'], x=df['pct_2014'], s=50, color='#a3c4dc', alpha=0.7) + +# Line Segments +for i, p1, p2 in zip(df['index'], df['pct_2013'], df['pct_2014']): + newline([p1, i], [p2, i]) + +# Decoration +ax.set_facecolor('#f7f7f7') +ax.set_title("Dumbell Chart: Pct Change - 2013 vs 2014", fontdict={'size': 22}) +ax.set(xlim=(0, .25), ylim=(-1, 27), ylabel='Mean GDP Per Capita') +ax.set_xticks([.05, .1, .15, .20]) +ax.set_xticklabels(['5%', '15%', '20%', '25%']) +ax.set_xticklabels(['5%', '15%', '20%', '25%']) +plt.show() +``` + +![21](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/21.png) + +## 【6x00】分布(Distribution) + +### 【20】连续变量的直方图(Histogram for Continuous Variable) + +连续变量的直方图显示给定变量的频率分布。下面的图表基于分类变量对频率条进行分组,从而更深入地了解连续变量和分类变量。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare data +x_var = 'displ' +groupby_var = 'class' +df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var) +vals = [df[x_var].values.tolist() for i, df in df_agg] + +# Draw +plt.figure(figsize=(16, 9), dpi=80) +colors = [plt.cm.Spectral(i / float(len(vals) - 1)) for i in range(len(vals))] +n, bins, patches = plt.hist(vals, 30, stacked=True, density=False, color=colors[:len(vals)]) + +# Decoration +plt.legend({group: col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])}) +plt.title(f"Stacked Histogram of ${x_var}$ colored by ${groupby_var}$", fontsize=22) +plt.xlabel(x_var) +plt.ylabel("Frequency") +plt.ylim(0, 25) +plt.xticks(ticks=bins[::3], labels=[round(b, 1) for b in bins[::3]]) +plt.show() +``` + +![22](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/22.png) + +### 【21】分类变量的直方图(Histogram for Categorical Variable) + +分类变量的直方图显示该变量的频率分布。通过给条形图上色,您可以将分布与表示颜色的另一个类型变量相关联。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare data +x_var = 'manufacturer' +groupby_var = 'class' +df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var) +vals = [df[x_var].values.tolist() for i, df in df_agg] + +# Draw +plt.figure(figsize=(16, 9), dpi=80) +colors = [plt.cm.Spectral(i / float(len(vals) - 1)) for i in range(len(vals))] +n, bins, patches = plt.hist(vals, df[x_var].unique().__len__(), stacked=True, density=False, color=colors[:len(vals)]) + +# Decoration +plt.legend({group: col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])}) +plt.title(f"Stacked Histogram of ${x_var}$ colored by ${groupby_var}$", fontsize=22) +plt.xlabel(x_var) +plt.ylabel("Frequency") +plt.ylim(0, 40) +plt.xticks(ticks=bins, labels=np.unique(df[x_var]).tolist(), rotation=90, horizontalalignment='left') +plt.show() +``` + +![23](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/23.png) + +### 【22】密度图(Density Plot) + +密度图是连续变量分布可视化的常用工具。通过按“response”变量对它们进行分组,您可以检查 X 和 Y 之间的关系。如果出于代表性目的来描述城市里程分布如何随气缸数而变化,请参见下面的情况。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Draw Plot +plt.figure(figsize=(16, 10), dpi=80) +sns.kdeplot(df.loc[df['cyl'] == 4, "cty"], shade=True, color="g", label="Cyl=4", alpha=.7) +sns.kdeplot(df.loc[df['cyl'] == 5, "cty"], shade=True, color="deeppink", label="Cyl=5", alpha=.7) +sns.kdeplot(df.loc[df['cyl'] == 6, "cty"], shade=True, color="dodgerblue", label="Cyl=6", alpha=.7) +sns.kdeplot(df.loc[df['cyl'] == 8, "cty"], shade=True, color="orange", label="Cyl=8", alpha=.7) + +# Decoration +plt.title('Density Plot of City Mileage by n_Cylinders', fontsize=22) +plt.legend() +plt.show() +``` + +![24](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/24.png) + +### 【23】直方图密度曲线(Density Curves with Histogram) + +具有直方图的密度曲线将两个图所传达的信息集合在一起,因此您可以将它们都放在一个图形中,而不是放在两个图形中。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Draw Plot +plt.figure(figsize=(13, 10), dpi=80) +sns.distplot(df.loc[df['class'] == 'compact', "cty"], color="dodgerblue", label="Compact", hist_kws={'alpha': .7}, + kde_kws={'linewidth': 3}) +sns.distplot(df.loc[df['class'] == 'suv', "cty"], color="orange", label="SUV", hist_kws={'alpha': .7}, + kde_kws={'linewidth': 3}) +sns.distplot(df.loc[df['class'] == 'minivan', "cty"], color="g", label="minivan", hist_kws={'alpha': .7}, + kde_kws={'linewidth': 3}) +plt.ylim(0, 0.35) + +# Decoration +plt.title('Density Plot of City Mileage by Vehicle Type', fontsize=22) +plt.legend() +plt.show() +``` + +![25](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/25.png) + +### 【24】山峰叠峦图 / 欢乐图(Joy Plot) + +Joy Plot 允许不同组的密度曲线重叠,这是一种很好的可视化方法,可以直观地显示大量分组之间的关系。它看起来赏心悦目,清楚地传达了正确的信息。它可以使用基于 `matplotlib` 的 `joypy` 包轻松构建。 + +【译者 TRHX 注:Joy Plot 看起来就像是山峰叠峦,山峦起伏,层次分明,但取名为 Joy,欢乐的意思,所以不太好翻译,在使用该方法时要先安装 joypy 库】 + +```python +# !pip install joypy +# Import Data +import joypy +# 原文没有 import joypy,译者 TRHX 添加 + +mpg = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Draw Plot +plt.figure(figsize=(16, 10), dpi=80) +fig, axes = joypy.joyplot(mpg, column=['hwy', 'cty'], by="class", ylim='own', figsize=(14, 10)) + +# Decoration +plt.title('Joy Plot of City and Highway Mileage by Class', fontsize=22) +plt.show() +``` + +![26](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/26.png) + +### 【25】分布式点图(Distributed Dot Plot) + +分布点图显示按组分割的点的单变量分布。点越暗,数据点在该区域的集中程度就越高。通过对中值进行不同的着色,这些组的真实位置立即变得明显。 + +```python +import matplotlib.patches as mpatches + +# Prepare Data +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") +cyl_colors = {4: 'tab:red', 5: 'tab:green', 6: 'tab:blue', 8: 'tab:orange'} +df_raw['cyl_color'] = df_raw.cyl.map(cyl_colors) + +# Mean and Median city mileage by make +df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean()) +df.sort_values('cty', ascending=False, inplace=True) +df.reset_index(inplace=True) +df_median = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.median()) + +# Draw horizontal lines +fig, ax = plt.subplots(figsize=(16, 10), dpi=80) +ax.hlines(y=df.index, xmin=0, xmax=40, color='gray', alpha=0.5, linewidth=.5, linestyles='dashdot') + +# Draw the Dots +for i, make in enumerate(df.manufacturer): + df_make = df_raw.loc[df_raw.manufacturer == make, :] + ax.scatter(y=np.repeat(i, df_make.shape[0]), x='cty', data=df_make, s=75, edgecolors='gray', c='w', alpha=0.5) + ax.scatter(y=i, x='cty', data=df_median.loc[df_median.index == make, :], s=75, c='firebrick') + +# Annotate +ax.text(33, 13, "$red \; dots \; are \; the \: median$", fontdict={'size': 12}, color='firebrick') + +# Decorations +red_patch = plt.plot([], [], marker="o", ms=10, ls="", mec=None, color='firebrick', label="Median") +plt.legend(handles=red_patch) +ax.set_title('Distribution of City Mileage by Make', fontdict={'size': 22}) +ax.set_xlabel('Miles Per Gallon (City)', alpha=0.7) +ax.set_yticks(df.index) +ax.set_yticklabels(df.manufacturer.str.title(), fontdict={'horizontalalignment': 'right'}, alpha=0.7) +ax.set_xlim(1, 40) +plt.xticks(alpha=0.7) +plt.gca().spines["top"].set_visible(False) +plt.gca().spines["bottom"].set_visible(False) +plt.gca().spines["right"].set_visible(False) +plt.gca().spines["left"].set_visible(False) +plt.grid(axis='both', alpha=.4, linewidth=.1) +plt.show() +``` + +![27](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/27.png) + +### 【26】箱形图(Box Plot) + +箱形图是可视化分布的一种好方法,同时牢记中位数,第 25 个第 75 个四分位数和离群值。 但是,在解释方框的大小时需要小心,这可能会扭曲该组中包含的点数。 因此,手动提供每个框中的观察次数可以帮助克服此缺点。 + +例如,左侧的前两个框,尽管它们分别具有 5 和 47 个 obs,但是却具有相同大小, 因此,有必要写下该组中的观察数。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Draw Plot +plt.figure(figsize=(13, 10), dpi=80) +sns.boxplot(x='class', y='hwy', data=df, notch=False) + + +# Add N Obs inside boxplot (optional) +def add_n_obs(df, group_col, y): + medians_dict = {grp[0]: grp[1][y].median() for grp in df.groupby(group_col)} + xticklabels = [x.get_text() for x in plt.gca().get_xticklabels()] + n_obs = df.groupby(group_col)[y].size().values + for (x, xticklabel), n_ob in zip(enumerate(xticklabels), n_obs): + plt.text(x, medians_dict[xticklabel] * 1.01, "#obs : " + str(n_ob), horizontalalignment='center', + fontdict={'size': 14}, color='white') + + +add_n_obs(df, group_col='class', y='hwy') + +# Decoration +plt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22) +plt.ylim(10, 40) +plt.show() +``` + +![28](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/28.png) + +### 【27】点 + 箱形图(Dot + Box Plot) + +点 + 箱形图传达类似于分组的箱形图信息。此外,这些点还提供了每组中有多少数据点的含义。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Draw Plot +plt.figure(figsize=(13,10), dpi= 80) +sns.boxplot(x='class', y='hwy', data=df, hue='cyl') +sns.stripplot(x='class', y='hwy', data=df, color='black', size=3, jitter=1) + +for i in range(len(df['class'].unique())-1): + plt.vlines(i+.5, 10, 45, linestyles='solid', colors='gray', alpha=0.2) + +# Decoration +plt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22) +plt.legend(title='Cylinders') +plt.show() +``` + +![29](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/29.png) + +### 【28】小提琴图(Violin Plot) + +小提琴图是箱形图在视觉上令人愉悦的替代品。 小提琴的形状或面积取决于它所持有的观察次数。 但是,小提琴图可能更难以阅读,并且在专业设置中不常用。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Draw Plot +plt.figure(figsize=(13, 10), dpi=80) +sns.violinplot(x='class', y='hwy', data=df, scale='width', inner='quartile') + +# Decoration +plt.title('Violin Plot of Highway Mileage by Vehicle Class', fontsize=22) +plt.show() +``` + +![30](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/30.png) + +### 【29】人口金字塔图(Population Pyramid) + +人口金字塔可用于显示按体积排序的组的分布。或者它也可以用于显示人口的逐级过滤,因为它是用来显示有多少人通过一个营销漏斗(Marketing Funnel)的每个阶段。 + +```python +# Read data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/email_campaign_funnel.csv") + +# Draw Plot +plt.figure(figsize=(13, 10), dpi=80) +group_col = 'Gender' +order_of_bars = df.Stage.unique()[::-1] +colors = [plt.cm.Spectral(i / float(len(df[group_col].unique()) - 1)) for i in range(len(df[group_col].unique()))] + +for c, group in zip(colors, df[group_col].unique()): + sns.barplot(x='Users', y='Stage', data=df.loc[df[group_col] == group, :], order=order_of_bars, color=c, label=group) + +# Decorations +plt.xlabel("$Users$") +plt.ylabel("Stage of Purchase") +plt.yticks(fontsize=12) +plt.title("Population Pyramid of the Marketing Funnel", fontsize=22) +plt.legend() +plt.show() +``` + +![31](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/31.png) + +### 【30】分类图(Categorical Plots) + +由 `seaborn` 库提供的分类图可用于可视化彼此相关的两个或更多分类变量的计数分布。 + +```python +# Load Dataset +titanic = sns.load_dataset("titanic") + +# Plot +g = sns.catplot("alive", col="deck", col_wrap=4, + data=titanic[titanic.deck.notnull()], + kind="count", height=3.5, aspect=.8, + palette='tab20') + +# 译者 TRHX 注释掉了这一行代码 +# fig.suptitle('sf') +plt.show() +``` + +![32](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/32.png) + +```python +# Load Dataset +titanic = sns.load_dataset("titanic") + +# Plot +sns.catplot(x="age", y="embark_town", + hue="sex", col="class", + data=titanic[titanic.embark_town.notnull()], + orient="h", height=5, aspect=1, palette="tab10", + kind="violin", dodge=True, cut=0, bw=.2) + +# 译者 TRHX 添加了这行代码 +plt.show() +``` + +![33](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/33.png) + +## 【7x00】组成(Composition) + +### 【31】华夫饼图(Waffle Chart) + +华夫饼图可以使用 `pywaffle` 包创建,用于显示较大群体中的组的组成。 + +【译者 TRHX 注:在使用该方法时要先安装 pywaffle 库】 + +```python +# ! pip install pywaffle +# Reference: https://stackoverflow.com/questions/41400136/how-to-do-waffle-charts-in-python-square-piechart +from pywaffle import Waffle + +# Import +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare Data +df = df_raw.groupby('class').size().reset_index(name='counts') +n_categories = df.shape[0] +colors = [plt.cm.inferno_r(i / float(n_categories)) for i in range(n_categories)] + +# Draw Plot and Decorate +fig = plt.figure( + FigureClass=Waffle, + plots={ + '111': { + 'values': df['counts'], + 'labels': ["{0} ({1})".format(n[0], n[1]) for n in df[['class', 'counts']].itertuples()], + 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12}, + 'title': {'label': '# Vehicles by Class', 'loc': 'center', 'fontsize': 18} + }, + }, + rows=7, + colors=colors, + figsize=(16, 9) +) + +# 译者 TRHX 添加了这行代码 +plt.show() +``` + +![34](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/34.png) + +```python +# ! pip install pywaffle +from pywaffle import Waffle + +# Import +# 译者 TRHX 取消注释了这行代码 +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare Data +# By Class Data +df_class = df_raw.groupby('class').size().reset_index(name='counts_class') +n_categories = df_class.shape[0] +colors_class = [plt.cm.Set3(i / float(n_categories)) for i in range(n_categories)] + +# By Cylinders Data +df_cyl = df_raw.groupby('cyl').size().reset_index(name='counts_cyl') +n_categories = df_cyl.shape[0] +colors_cyl = [plt.cm.Spectral(i / float(n_categories)) for i in range(n_categories)] + +# By Make Data +df_make = df_raw.groupby('manufacturer').size().reset_index(name='counts_make') +n_categories = df_make.shape[0] +colors_make = [plt.cm.tab20b(i / float(n_categories)) for i in range(n_categories)] + +# Draw Plot and Decorate +fig = plt.figure( + FigureClass=Waffle, + plots={ + '311': { + 'values': df_class['counts_class'], + 'labels': ["{1}".format(n[0], n[1]) for n in df_class[['class', 'counts_class']].itertuples()], + 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Class'}, + 'title': {'label': '# Vehicles by Class', 'loc': 'center', 'fontsize': 18}, + 'colors': colors_class + }, + '312': { + 'values': df_cyl['counts_cyl'], + 'labels': ["{1}".format(n[0], n[1]) for n in df_cyl[['cyl', 'counts_cyl']].itertuples()], + 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Cyl'}, + 'title': {'label': '# Vehicles by Cyl', 'loc': 'center', 'fontsize': 18}, + 'colors': colors_cyl + }, + '313': { + 'values': df_make['counts_make'], + 'labels': ["{1}".format(n[0], n[1]) for n in df_make[['manufacturer', 'counts_make']].itertuples()], + 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Manufacturer'}, + 'title': {'label': '# Vehicles by Make', 'loc': 'center', 'fontsize': 18}, + 'colors': colors_make + } + }, + rows=9, + figsize=(16, 14) +) + +# 译者 TRHX 添加了这行代码 +plt.show() +``` + +![35](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/35.png) + +### 【32】饼图(Pie Chart) + +饼图是显示组成的经典方法。然而,现在一般不宜使用,因为馅饼部分的面积有时会产生误导。因此,如果要使用饼图,强烈建议您显式地记下饼图每个部分的百分比或数字。 + +```python +# Import +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare Data +df = df_raw.groupby('class').size() + +# Make the plot with pandas +''' +原代码:df.plot(kind='pie', subplots=True, figsize=(8, 8), dpi=80) +译者 TRHX 删除了 dpi= 80 +''' +df.plot(kind='pie', subplots=True, figsize=(8, 8)) +plt.title("Pie Chart of Vehicle Class - Bad") +plt.ylabel("") +plt.show() +``` + +![36](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/36.png) + +```python +# Import +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare Data +df = df_raw.groupby('class').size().reset_index(name='counts') + +# Draw Plot +fig, ax = plt.subplots(figsize=(12, 7), subplot_kw=dict(aspect="equal"), dpi=80) + +data = df['counts'] +categories = df['class'] +explode = [0, 0, 0, 0, 0, 0.1, 0] + + +def func(pct, allvals): + absolute = int(pct / 100. * np.sum(allvals)) + return "{:.1f}% ({:d} )".format(pct, absolute) + + +wedges, texts, autotexts = ax.pie(data, + autopct=lambda pct: func(pct, data), + textprops=dict(color="w"), + colors=plt.cm.Dark2.colors, + startangle=140, + explode=explode) + +# Decoration +ax.legend(wedges, categories, title="Vehicle Class", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1)) +plt.setp(autotexts, size=10, weight=700) +ax.set_title("Class of Vehicles: Pie Chart") +plt.show() +``` + +![37](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/37.png) + +### 【33】矩阵树形图(Treemap) + +矩阵树形图类似于饼图,它可以更好地完成工作而不会误导每个组的贡献。 + +【译者 TRHX 注:在使用该方法时要先安装 squarify 库】 + +```python +# pip install squarify +import squarify + +# Import Data +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare Data +df = df_raw.groupby('class').size().reset_index(name='counts') +labels = df.apply(lambda x: str(x[0]) + "\n (" + str(x[1]) + ")", axis=1) +sizes = df['counts'].values.tolist() +colors = [plt.cm.Spectral(i / float(len(labels))) for i in range(len(labels))] + +# Draw Plot +plt.figure(figsize=(12, 8), dpi=80) +squarify.plot(sizes=sizes, label=labels, color=colors, alpha=.8) + +# Decorate +plt.title('Treemap of Vechile Class') +plt.axis('off') +plt.show() +``` + +![38](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/38.png) + +### 【34】条形图(Bar Chart) + +条形图是一种基于计数或任何给定度量的可视化项的经典方法。在下面的图表中,我为每个项目使用了不同的颜色,但您通常可能希望为所有项目选择一种颜色,除非您按组对它们进行着色。颜色名称存储在下面代码中的 `all_colors` 中。您可以通过在 `plt.plot()` 中设置 `color` 参数来更改条形的颜色。 + +```python +import random + +# Import Data +df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv") + +# Prepare Data +df = df_raw.groupby('manufacturer').size().reset_index(name='counts') +n = df['manufacturer'].unique().__len__()+1 +all_colors = list(plt.cm.colors.cnames.keys()) +random.seed(100) +c = random.choices(all_colors, k=n) + +# Plot Bars +plt.figure(figsize=(16,10), dpi= 80) +plt.bar(df['manufacturer'], df['counts'], color=c, width=.5) +for i, val in enumerate(df['counts'].values): + plt.text(i, val, float(val), horizontalalignment='center', verticalalignment='bottom', fontdict={'fontweight':500, 'size':12}) + +# Decoration +plt.gca().set_xticklabels(df['manufacturer'], rotation=60, horizontalalignment= 'right') +plt.title("Number of Vehicles by Manaufacturers", fontsize=22) +plt.ylabel('# Vehicles') +plt.ylim(0, 45) +plt.show() +``` + +![39](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/39.png) + +## 【8x00】变化(Change) + +### 【35】时间序列图(Time Series Plot) + +时间序列图用于可视化给定指标随时间的变化。在这里你可以看到 1949 年到 1969 年间的航空客运量是如何变化的。 + +```python +# Import Data +df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv') + +# Draw Plot +plt.figure(figsize=(16, 10), dpi=80) +plt.plot('date', 'traffic', data=df, color='tab:red') + +# Decoration +plt.ylim(50, 750) +xtick_location = df.index.tolist()[::12] +xtick_labels = [x[-4:] for x in df.date.tolist()[::12]] +plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=0, fontsize=12, horizontalalignment='center', alpha=.7) +plt.yticks(fontsize=12, alpha=.7) +plt.title("Air Passengers Traffic (1949 - 1969)", fontsize=22) +plt.grid(axis='both', alpha=.3) + +# Remove borders +plt.gca().spines["top"].set_alpha(0.0) +plt.gca().spines["bottom"].set_alpha(0.3) +plt.gca().spines["right"].set_alpha(0.0) +plt.gca().spines["left"].set_alpha(0.3) +plt.show() +``` + +![40](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/40.png) + +### 【36】带波峰和波谷注释的时间序列图(Time Series with Peaks and Troughs Annotated) + +下面的时间序列绘制了所有的波峰和波谷,并注释了所选特殊事件的发生。 + +```python +# Import Data +df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv') + +# Get the Peaks and Troughs +data = df['traffic'].values +doublediff = np.diff(np.sign(np.diff(data))) +peak_locations = np.where(doublediff == -2)[0] + 1 + +doublediff2 = np.diff(np.sign(np.diff(-1 * data))) +trough_locations = np.where(doublediff2 == -2)[0] + 1 + +# Draw Plot +plt.figure(figsize=(16, 10), dpi=80) +plt.plot('date', 'traffic', data=df, color='tab:blue', label='Air Traffic') +plt.scatter(df.date[peak_locations], df.traffic[peak_locations], marker=mpl.markers.CARETUPBASE, color='tab:green', + s=100, label='Peaks') +plt.scatter(df.date[trough_locations], df.traffic[trough_locations], marker=mpl.markers.CARETDOWNBASE, color='tab:red', + s=100, label='Troughs') + +# Annotate +for t, p in zip(trough_locations[1::5], peak_locations[::3]): + plt.text(df.date[p], df.traffic[p] + 15, df.date[p], horizontalalignment='center', color='darkgreen') + plt.text(df.date[t], df.traffic[t] - 35, df.date[t], horizontalalignment='center', color='darkred') + +# Decoration +plt.ylim(50, 750) +xtick_location = df.index.tolist()[::6] +xtick_labels = df.date.tolist()[::6] +plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=90, fontsize=12, alpha=.7) +plt.title("Peak and Troughs of Air Passengers Traffic (1949 - 1969)", fontsize=22) +plt.yticks(fontsize=12, alpha=.7) + +# Lighten borders +plt.gca().spines["top"].set_alpha(.0) +plt.gca().spines["bottom"].set_alpha(.3) +plt.gca().spines["right"].set_alpha(.0) +plt.gca().spines["left"].set_alpha(.3) + +plt.legend(loc='upper left') +plt.grid(axis='y', alpha=.3) +plt.show() +``` + +![41](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/41.png) + +### 【37】自相关 (ACF) 和部分自相关 (PACF) 图(Autocorrelation (ACF) and Partial Autocorrelation (PACF) Plot) + +自相关图(ACF图)显示了时间序列与其自身滞后的相关性。 每条垂直线(在自相关图上)表示系列与滞后 0 之间的滞后的相关性。图中的蓝色阴影区域是显著性级别。 那些位于蓝线之上的滞后是显著的滞后。 + +那么如何解释呢? + +对于航空乘客来说,我们看到超过 14 个滞后已经越过蓝线,因此意义重大。这意味着,14 年前的航空客运量对今天的交通量产生了影响。 + +另一方面,部分自相关图(PACF)显示了任何给定滞后(时间序列)相对于当前序列的自相关,但消除了中间滞后的贡献。 + +```python +from statsmodels.graphics.tsaplots import plot_acf, plot_pacf + +# Import Data +df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv') + +# Draw Plot +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6), dpi=80) +plot_acf(df.traffic.tolist(), ax=ax1, lags=50) +plot_pacf(df.traffic.tolist(), ax=ax2, lags=20) + +# Decorate +# lighten the borders +ax1.spines["top"].set_alpha(.3); ax2.spines["top"].set_alpha(.3) +ax1.spines["bottom"].set_alpha(.3); ax2.spines["bottom"].set_alpha(.3) +ax1.spines["right"].set_alpha(.3); ax2.spines["right"].set_alpha(.3) +ax1.spines["left"].set_alpha(.3); ax2.spines["left"].set_alpha(.3) + +# font size of tick labels +ax1.tick_params(axis='both', labelsize=12) +ax2.tick_params(axis='both', labelsize=12) +plt.show() +``` + +![42](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/42.png) + +### 【38】交叉相关图(Cross Correlation plot) + +交叉相关图显示了两个时间序列相互之间的滞后。 + +```python +import statsmodels.tsa.stattools as stattools + +# Import Data +df = pd.read_csv('https://github.com/selva86/datasets/raw/master/mortality.csv') +x = df['mdeaths'] +y = df['fdeaths'] + +# Compute Cross Correlations +ccs = stattools.ccf(x, y)[:100] +nlags = len(ccs) + +# Compute the Significance level +# ref: https://stats.stackexchange.com/questions/3115/cross-correlation-significance-in-r/3128#3128 +conf_level = 2 / np.sqrt(nlags) + +# Draw Plot +plt.figure(figsize=(12, 7), dpi=80) + +plt.hlines(0, xmin=0, xmax=100, color='gray') # 0 axis +plt.hlines(conf_level, xmin=0, xmax=100, color='gray') +plt.hlines(-conf_level, xmin=0, xmax=100, color='gray') + +plt.bar(x=np.arange(len(ccs)), height=ccs, width=.3) + +# Decoration +plt.title('$Cross\; Correlation\; Plot:\; mdeaths\; vs\; fdeaths$', fontsize=22) +plt.xlim(0, len(ccs)) +plt.show() +``` + +![43](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/43.png) + +### 【39】时间序列分解图(Time Series Decomposition Plot) + +时间序列分解图将时间序列分解为趋势、季节和残差分量。 + +```python +from statsmodels.tsa.seasonal import seasonal_decompose +from dateutil.parser import parse + +# Import Data +df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv') +dates = pd.DatetimeIndex([parse(d).strftime('%Y-%m-01') for d in df['date']]) +df.set_index(dates, inplace=True) + +# Decompose +result = seasonal_decompose(df['traffic'], model='multiplicative') + +# Plot +plt.rcParams.update({'figure.figsize': (10, 10)}) +result.plot().suptitle('Time Series Decomposition of Air Passengers') +plt.show() +``` + +![44](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/44.png) + +### 【40】多重时间序列(Multiple Time Series) + +您可以在同一图表上绘制多个测量相同值的时间序列,如下所示。 + +```python +# Import Data +df = pd.read_csv('https://github.com/selva86/datasets/raw/master/mortality.csv') + +# Define the upper limit, lower limit, interval of Y axis and colors +y_LL = 100 +y_UL = int(df.iloc[:, 1:].max().max() * 1.1) +y_interval = 400 +mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange'] + +# Draw Plot and Annotate +fig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80) + +columns = df.columns[1:] +for i, column in enumerate(columns): + plt.plot(df.date.values, df[column].values, lw=1.5, color=mycolors[i]) + plt.text(df.shape[0] + 1, df[column].values[-1], column, fontsize=14, color=mycolors[i]) + +# Draw Tick lines +for y in range(y_LL, y_UL, y_interval): + plt.hlines(y, xmin=0, xmax=71, colors='black', alpha=0.3, linestyles="--", lw=0.5) + +# Decorations +plt.tick_params(axis="both", which="both", bottom=False, top=False, + labelbottom=True, left=False, right=False, labelleft=True) + +# Lighten borders +plt.gca().spines["top"].set_alpha(.3) +plt.gca().spines["bottom"].set_alpha(.3) +plt.gca().spines["right"].set_alpha(.3) +plt.gca().spines["left"].set_alpha(.3) + +plt.title('Number of Deaths from Lung Diseases in the UK (1974-1979)', fontsize=22) +plt.yticks(range(y_LL, y_UL, y_interval), [str(y) for y in range(y_LL, y_UL, y_interval)], fontsize=12) +plt.xticks(range(0, df.shape[0], 12), df.date.values[::12], horizontalalignment='left', fontsize=12) +plt.ylim(y_LL, y_UL) +plt.xlim(-2, 80) +plt.show() +``` + +![45](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/45.png) + +### 【41】使用次要的 Y 轴来绘制不同范围的图形(Plotting with different scales using secondary Y axis) + +如果要显示在同一时间点测量两个不同数量的两个时间序列,则可以在右侧的次要 Y 轴上再绘制第二个系列。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv") + +x = df['date'] +y1 = df['psavert'] +y2 = df['unemploy'] + +# Plot Line1 (Left Y Axis) +fig, ax1 = plt.subplots(1, 1, figsize=(16, 9), dpi=80) +ax1.plot(x, y1, color='tab:red') + +# Plot Line2 (Right Y Axis) +ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis +ax2.plot(x, y2, color='tab:blue') + +# Decorations +# ax1 (left Y axis) +ax1.set_xlabel('Year', fontsize=20) +ax1.tick_params(axis='x', rotation=0, labelsize=12) +ax1.set_ylabel('Personal Savings Rate', color='tab:red', fontsize=20) +ax1.tick_params(axis='y', rotation=0, labelcolor='tab:red') +ax1.grid(alpha=.4) + +# ax2 (right Y axis) +ax2.set_ylabel("# Unemployed (1000's)", color='tab:blue', fontsize=20) +ax2.tick_params(axis='y', labelcolor='tab:blue') +ax2.set_xticks(np.arange(0, len(x), 60)) +ax2.set_xticklabels(x[::60], rotation=90, fontdict={'fontsize': 10}) +ax2.set_title("Personal Savings Rate vs Unemployed: Plotting in Secondary Y Axis", fontsize=22) +fig.tight_layout() +plt.show() +``` + +![46](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/46.png) + +### 【42】带误差带的时间序列(Time Series with Error Bands) + +如果您有一个时间序列数据集,其中每个时间点(日期/时间戳)有多个观测值,则可以构造具有误差带的时间序列。下面您可以看到一些基于一天中不同时间的订单的示例。还有一个关于45天内到达的订单数量的例子。 + +在这种方法中,订单数量的平均值用白线表示。并计算95%的置信区间,并围绕平均值绘制。 + +```python +from scipy.stats import sem + +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/user_orders_hourofday.csv") +df_mean = df.groupby('order_hour_of_day').quantity.mean() +df_se = df.groupby('order_hour_of_day').quantity.apply(sem).mul(1.96) + +# Plot +plt.figure(figsize=(16, 10), dpi=80) +plt.ylabel("# Orders", fontsize=16) +x = df_mean.index +plt.plot(x, df_mean, color="white", lw=2) +plt.fill_between(x, df_mean - df_se, df_mean + df_se, color="#3F5D7D") + +# Decorations +# Lighten borders +plt.gca().spines["top"].set_alpha(0) +plt.gca().spines["bottom"].set_alpha(1) +plt.gca().spines["right"].set_alpha(0) +plt.gca().spines["left"].set_alpha(1) +plt.xticks(x[::2], [str(d) for d in x[::2]], fontsize=12) +plt.title("User Orders by Hour of Day (95% confidence)", fontsize=22) +plt.xlabel("Hour of Day") + +s, e = plt.gca().get_xlim() +plt.xlim(s, e) + +# Draw Horizontal Tick lines +for y in range(8, 20, 2): + plt.hlines(y, xmin=s, xmax=e, colors='black', alpha=0.5, linestyles="--", lw=0.5) + +plt.show() +``` + +![47](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/47.png) + +```python +"Data Source: https://www.kaggle.com/olistbr/brazilian-ecommerce#olist_orders_dataset.csv" +from dateutil.parser import parse +from scipy.stats import sem + +# Import Data +df_raw = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/orders_45d.csv', + parse_dates=['purchase_time', 'purchase_date']) + +# Prepare Data: Daily Mean and SE Bands +df_mean = df_raw.groupby('purchase_date').quantity.mean() +df_se = df_raw.groupby('purchase_date').quantity.apply(sem).mul(1.96) + +# Plot +plt.figure(figsize=(16, 10), dpi=80) +plt.ylabel("# Daily Orders", fontsize=16) +x = [d.date().strftime('%Y-%m-%d') for d in df_mean.index] +plt.plot(x, df_mean, color="white", lw=2) +plt.fill_between(x, df_mean - df_se, df_mean + df_se, color="#3F5D7D") + +# Decorations +# Lighten borders +plt.gca().spines["top"].set_alpha(0) +plt.gca().spines["bottom"].set_alpha(1) +plt.gca().spines["right"].set_alpha(0) +plt.gca().spines["left"].set_alpha(1) +plt.xticks(x[::6], [str(d) for d in x[::6]], fontsize=12) +plt.title("Daily Order Quantity of Brazilian Retail with Error Bands (95% confidence)", fontsize=20) + +# Axis limits +s, e = plt.gca().get_xlim() +plt.xlim(s, e - 2) +plt.ylim(4, 10) + +# Draw Horizontal Tick lines +for y in range(5, 10, 1): + plt.hlines(y, xmin=s, xmax=e, colors='black', alpha=0.5, linestyles="--", lw=0.5) + +plt.show() +``` + +![48](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/48.png) + +### 【43】堆积面积图(Stacked Area Chart) + +堆积面积图提供了多个时间序列的贡献程度的可视化表示,以便相互比较。 + +```python +# Import Data +df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/nightvisitors.csv') + +# Decide Colors +mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive'] + +# Draw Plot and Annotate +fig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80) +columns = df.columns[1:] +labs = columns.values.tolist() + +# Prepare data +x = df['yearmon'].values.tolist() +y0 = df[columns[0]].values.tolist() +y1 = df[columns[1]].values.tolist() +y2 = df[columns[2]].values.tolist() +y3 = df[columns[3]].values.tolist() +y4 = df[columns[4]].values.tolist() +y5 = df[columns[5]].values.tolist() +y6 = df[columns[6]].values.tolist() +y7 = df[columns[7]].values.tolist() +y = np.vstack([y0, y2, y4, y6, y7, y5, y1, y3]) + +# Plot for each column +labs = columns.values.tolist() +ax = plt.gca() +ax.stackplot(x, y, labels=labs, colors=mycolors, alpha=0.8) + +# Decorations +ax.set_title('Night Visitors in Australian Regions', fontsize=18) +ax.set(ylim=[0, 100000]) +ax.legend(fontsize=10, ncol=4) +plt.xticks(x[::5], fontsize=10, horizontalalignment='center') +plt.yticks(np.arange(10000, 100000, 20000), fontsize=10) +plt.xlim(x[0], x[-1]) + +# Lighten borders +plt.gca().spines["top"].set_alpha(0) +plt.gca().spines["bottom"].set_alpha(.3) +plt.gca().spines["right"].set_alpha(0) +plt.gca().spines["left"].set_alpha(.3) + +plt.show() +``` + +![49](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/49.png) + +### 【44】未堆积面积图(Area Chart UnStacked) + +未堆积的面积图用于可视化两个或多个序列彼此之间的进度(起伏)。在下面的图表中,你可以清楚地看到,随着失业持续时间的中位数增加,个人储蓄率是如何下降的。未堆积面积图很好地展示了这一现象。 + +```python +# Import Data +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv") + +# Prepare Data +x = df['date'].values.tolist() +y1 = df['psavert'].values.tolist() +y2 = df['uempmed'].values.tolist() +mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive'] +columns = ['psavert', 'uempmed'] + +# Draw Plot +fig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80) +ax.fill_between(x, y1=y1, y2=0, label=columns[1], alpha=0.5, color=mycolors[1], linewidth=2) +ax.fill_between(x, y1=y2, y2=0, label=columns[0], alpha=0.5, color=mycolors[0], linewidth=2) + +# Decorations +ax.set_title('Personal Savings Rate vs Median Duration of Unemployment', fontsize=18) +ax.set(ylim=[0, 30]) +ax.legend(loc='best', fontsize=12) +plt.xticks(x[::50], fontsize=10, horizontalalignment='center') +plt.yticks(np.arange(2.5, 30.0, 2.5), fontsize=10) +plt.xlim(-10, x[-1]) + +# Draw Tick lines +for y in np.arange(2.5, 30.0, 2.5): + plt.hlines(y, xmin=0, xmax=len(x), colors='black', alpha=0.3, linestyles="--", lw=0.5) + +# Lighten borders +plt.gca().spines["top"].set_alpha(0) +plt.gca().spines["bottom"].set_alpha(.3) +plt.gca().spines["right"].set_alpha(0) +plt.gca().spines["left"].set_alpha(.3) +plt.show() +``` + +![50](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/50.png) + +### 【45】日历热力图(Calendar Heat Map) + +与时间序列相比,日历地图是另一种基于时间的数据可视化的不太受欢迎的方法。虽然在视觉上很吸引人,但数值并不十分明显。然而,它能很好地描绘极端值和假日效果。 + +【译者 TRHX 注:在使用该方法时要先安装 calmap 库】 + +```python +import matplotlib as mpl +import calmap + +# Import Data +df = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/yahoo.csv", parse_dates=['date']) +df.set_index('date', inplace=True) + +# Plot +plt.figure(figsize=(16, 10), dpi=80) +calmap.calendarplot(df['2014']['VIX.Close'], fig_kws={'figsize': (16, 10)}, + yearlabel_kws={'color': 'black', 'fontsize': 14}, subplot_kws={'title': 'Yahoo Stock Prices'}) +plt.show() +``` + +![51](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/51.png) + + +### 【46】季节图(Seasonal Plot) + +季节图可用于比较上一季度同一天(年/月/周等)时间序列的表现。 + +```python +from dateutil.parser import parse + +# Import Data +df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv') + +# Prepare data +df['year'] = [parse(d).year for d in df.date] +df['month'] = [parse(d).strftime('%b') for d in df.date] +years = df['year'].unique() + +# 译者 TRHX 添加了该行代码 +df.rename(columns={'value': 'traffic'}, inplace=True) + +# Draw Plot +mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive', + 'deeppink', 'steelblue', 'firebrick', 'mediumseagreen'] +plt.figure(figsize=(16, 10), dpi=80) + +for i, y in enumerate(years): + plt.plot('month', 'traffic', data=df.loc[df.year == y, :], color=mycolors[i], label=y) + plt.text(df.loc[df.year == y, :].shape[0] - .9, df.loc[df.year == y, 'traffic'][-1:].values[0], y, fontsize=12, + color=mycolors[i]) + +# Decoration +plt.ylim(50, 750) +plt.xlim(-0.3, 11) +plt.ylabel('$Air Traffic$') +plt.yticks(fontsize=12, alpha=.7) +plt.title("Monthly Seasonal Plot: Air Passengers Traffic (1949 - 1969)", fontsize=22) +plt.grid(axis='y', alpha=.3) + +# Remove borders +plt.gca().spines["top"].set_alpha(0.0) +plt.gca().spines["bottom"].set_alpha(0.5) +plt.gca().spines["right"].set_alpha(0.0) +plt.gca().spines["left"].set_alpha(0.5) +# plt.legend(loc='upper right', ncol=2, fontsize=12) +plt.show() +``` + +![52](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/52.png) + +## 【9x00】分组( Groups) + +### 【47】树状图(Dendrogram) + +树状图根据给定的距离度量将相似的点组合在一起,并根据点的相似性将它们组织成树状链接。 + +```python +import scipy.cluster.hierarchy as shc + +# Import Data +df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv') + +# Plot +plt.figure(figsize=(16, 10), dpi=80) +plt.title("USArrests Dendograms", fontsize=22) +dend = shc.dendrogram(shc.linkage(df[['Murder', 'Assault', 'UrbanPop', 'Rape']], method='ward'), labels=df.State.values, + color_threshold=100) +plt.xticks(fontsize=12) +plt.show() +``` + +![53](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/53.png) + +### 【48】聚类图(Cluster Plot) + +聚类图可以用来划分属于同一个聚类的点。下面是一个基于 USArrests 数据集将美国各州分成 5 组的代表性示例。这个聚类图使用 'murder' 和 'assault' 作为 X 轴和 Y 轴。或者,您可以将第一个主元件用作 X 轴和 Y 轴。 + +【译者 TRHX 注:在使用该方法时要先安装 sklearn 库】 + +```python +from sklearn.cluster import AgglomerativeClustering +from scipy.spatial import ConvexHull + +# Import Data +df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv') + +# Agglomerative Clustering +cluster = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward') +cluster.fit_predict(df[['Murder', 'Assault', 'UrbanPop', 'Rape']]) + +# Plot +plt.figure(figsize=(14, 10), dpi=80) +plt.scatter(df.iloc[:, 0], df.iloc[:, 1], c=cluster.labels_, cmap='tab10') + + +# Encircle +def encircle(x, y, ax=None, **kw): + if not ax: ax = plt.gca() + p = np.c_[x, y] + hull = ConvexHull(p) + poly = plt.Polygon(p[hull.vertices,:], **kw) + ax.add_patch(poly) + +# Draw polygon surrounding vertices +encircle(df.loc[cluster.labels_ == 0, 'Murder'], df.loc[cluster.labels_ == 0, 'Assault'], ec="k", fc="gold", alpha=0.2, linewidth=0) +encircle(df.loc[cluster.labels_ == 1, 'Murder'], df.loc[cluster.labels_ == 1, 'Assault'], ec="k", fc="tab:blue", alpha=0.2, linewidth=0) +encircle(df.loc[cluster.labels_ == 2, 'Murder'], df.loc[cluster.labels_ == 2, 'Assault'], ec="k", fc="tab:red", alpha=0.2, linewidth=0) +encircle(df.loc[cluster.labels_ == 3, 'Murder'], df.loc[cluster.labels_ == 3, 'Assault'], ec="k", fc="tab:green", alpha=0.2, linewidth=0) +encircle(df.loc[cluster.labels_ == 4, 'Murder'], df.loc[cluster.labels_ == 4, 'Assault'], ec="k", fc="tab:orange", alpha=0.2, linewidth=0) + +# Decorations +plt.xlabel('Murder'); plt.xticks(fontsize=12) +plt.ylabel('Assault'); plt.yticks(fontsize=12) +plt.title('Agglomerative Clustering of USArrests (5 Groups)', fontsize=22) +plt.show() +``` + +![54](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/54.png) + +### 【49】安德鲁斯曲线(Andrews Curve) + +安德鲁斯曲线有助于可视化是否存在基于给定分组的数值特征的固有分组。如果特征(数据集中的列)不能帮助区分组(cyl),则行将不会像下图所示被很好地分隔开。 + +```python +from pandas.plotting import andrews_curves + +# Import +df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv") +df.drop(['cars', 'carname'], axis=1, inplace=True) + +# Plot +plt.figure(figsize=(12, 9), dpi=80) +andrews_curves(df, 'cyl', colormap='Set1') + +# Lighten borders +plt.gca().spines["top"].set_alpha(0) +plt.gca().spines["bottom"].set_alpha(.3) +plt.gca().spines["right"].set_alpha(0) +plt.gca().spines["left"].set_alpha(.3) + +plt.title('Andrews Curves of mtcars', fontsize=22) +plt.xlim(-3, 3) +plt.grid(alpha=0.3) +plt.xticks(fontsize=12) +plt.yticks(fontsize=12) +plt.show() +``` + +![55](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/55.png) + +### 【50】平行坐标图(Parallel Coordinates) + +平行坐标有助于可视化功能是否有助于有效地隔离组。如果一个分离受到影响,则该特征可能在预测该组时非常有用。 + +```python +from pandas.plotting import parallel_coordinates + +# Import Data +df_final = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/diamonds_filter.csv") + +# Plot +plt.figure(figsize=(12, 9), dpi=80) +parallel_coordinates(df_final, 'cut', colormap='Dark2') + +# Lighten borders +plt.gca().spines["top"].set_alpha(0) +plt.gca().spines["bottom"].set_alpha(.3) +plt.gca().spines["right"].set_alpha(0) +plt.gca().spines["left"].set_alpha(.3) + +plt.title('Parallel Coordinated of Diamonds', fontsize=22) +plt.grid(alpha=0.3) +plt.xticks(fontsize=12) +plt.yticks(fontsize=12) +plt.show() +``` + +![56](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A78/56.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本译文首发于 CSDN,作者 Selva Prabhakaran,译者 TRHX。 +本文链接:https://itrhx.blog.csdn.net/article/details/106558131 +原文链接:https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/ +``` + +--- diff --git a/source/_posts/A79-Pandas-01.md b/source/_posts/A79-Pandas-01.md new file mode 100644 index 0000000000000000000000000000000000000000..4a3bae95ba6ad73940ffd6b53cc0049420d2c3b4 --- /dev/null +++ b/source/_posts/A79-Pandas-01.md @@ -0,0 +1,734 @@ +--- +title: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 +tags: + - Pandas + - Series + - DataFrame +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 基本对象。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106676693 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】了解 Pandas + +[Pandas](https://pandas.pydata.org/) 是 [Python](https://www.python.org/) 的一个数据分析包,是基于 [NumPy](https://numpy.org/) 构建的,最初由 [AQR Capital Management](https://www.aqr.com/) 于 2008 年 4 月开发,并于 2009 年底开源出来,目前由专注于 [Python](https://www.python.org/) 数据包开发的 [PyData](https://pydata.org/) 开发团队继续开发和维护,属于 [PyData](https://pydata.org/) 项目的一部分。 + +[Pandas](https://pandas.pydata.org/) 最初被作为金融数据分析工具而开发出来,因此,[Pandas](https://pandas.pydata.org/) 为时间序列分析提供了很好的支持。**Pandas 的名称来自于面板数据(panel data)和 Python 数据分析(data analysis)**。panel data 是经济学中关于多维数据集的一个术语,在 [Pandas](https://pandas.pydata.org/) 中也提供了 panel 的数据类型。 + +[Pandas](https://pandas.pydata.org/) 经常和其它工具一同使用,如数值计算工具 [NumPy](https://numpy.org/) 和 [SciPy](https://www.scipy.org/),分析库 [statsmodels](https://www.statsmodels.org/) 和 [scikit-learn](https://scikit-learn.org/),数据可视化库 [Matplotlib](https://matplotlib.org/) 等,虽然 [Pandas](https://pandas.pydata.org/) 采用了大量的 NumPy 编码风格,但二者最大的不同是 **Pandas 是专门为处理表格和混杂数据设计的。而 NumPy 更适合处理统一的数值数组数据。** + +--- + +【以下对 Pandas 的解释翻译自官方文档:[https://pandas.pydata.org/docs/getting_started/overview.html#package-overview](https://pandas.pydata.org/docs/getting_started/overview.html#package-overview)】 + +--- + +Pandas 是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。Pandas 的目标是成为 Python 数据分析实践与实战的必备高级工具,其长远目标是成为**最强大、最灵活、可以支持任何语言的开源数据分析工具**。经过多年不懈的努力,Pandas 离这个目标已经越来越近了。 + +Pandas 适用于处理以下类型的数据: + +- 与 SQL 或 Excel 表类似的,含异构列的表格数据; +- 有序和无序(非固定频率)的时间序列数据; +- 带行列标签的矩阵数据,包括同构或异构型数据; +- 任意其它形式的观测、统计数据集, 数据转入 Pandas 数据结构时不必事先标记。 + +Pandas 的主要数据结构是 [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.html#pandas.Series)(一维数据)与 [DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html#pandas.DataFrame)(二维数据),这两种数据结构足以处理- 金融、统计、社会科学、工程等领域里的大多数典型用例。对于 R 语言用户,[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html#pandas.DataFrame) 提供了比 R 语言 `data.frame` 更丰富的功能。Pandas 基于 [NumPy](https://www.numpy.org/) 开发,可以与其它第三方科学计算支持库完美集成。 + +Pandas 就像一把万能瑞士军刀,下面仅列出了它的部分优势 : + +- 处理浮点与非浮点数据里的**缺失数据**,表示为 NaN; +- 大小可变:**插入或删除** DataFrame 等多维对象的列; +- 自动、显式**数据对齐**:显式地将对象与一组标签对齐,也可以忽略标签,在 Series、DataFrame 计算时自动与数据对齐; +- 强大、灵活的**分组**(group by)功能:**拆分-应用-组合**数据集,聚合、转换数据; +- 把 Python 和 NumPy 数据结构里不规则、不同索引的数据**轻松地转换**为 DataFrame 对象; +- 基于智能标签,对大型数据集进行**切片、花式索引、子集分解**等操作; +- 直观地**合并**和**连接**数据集; +- 灵活地**重塑**和**旋转**数据集; +- 轴支持**分层**标签(每个刻度可能有多个标签); +- 强大的 IO 工具,读取平面文件(CSV 等支持分隔符的文件)、Excel 文件、数据库等来源的数据,以及从超快 **HDF5 格式**保存 / 加载数据; +- **时间序列**:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。 + +这些功能主要是为了解决其它编程语言、科研环境的痛点。处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化与制表,Pandas 是处理数据的理想工具。 + +其它说明: + +- Pandas 速度很快。Pandas 的很多底层算法都用 [Cython](https://cython.org/) 优化过。然而,为了保持通用性,必然要牺牲一些性能,如果专注某一功能,完全可以开发出比 Pandas 更快的专用工具。 +- Pandas 是 [statsmodels](https://www.statsmodels.org/stable/index.html) 的依赖项,因此,Pandas 也是 Python 中统计计算生态系统的重要组成部分。 +- Pandas 已广泛应用于金融领域。 + +## 【02x00】Pandas 数据结构 + +Pandas 的主要数据结构是 [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.html#pandas.Series)(带标签的一维同构数组)与 [DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html#pandas.DataFrame)(带标签的,大小可变的二维异构表格)。 + +Pandas 数据结构就像是低维数据的容器。比如,DataFrame 是 Series 的容器,Series 则是标量的容器。使用这种方式,可以在容器中以字典的形式插入或删除对象。 + +此外,通用 API 函数的默认操作要顾及时间序列与截面数据集的方向。当使用 Ndarray 存储二维或三维数据时,编写函数要注意数据集的方向,这对用户来说是一种负担;如果不考虑 C 或 Fortran 中连续性对性能的影响,一般情况下,不同的轴在程序里其实没有什么区别。Pandas 里,轴的概念主要是为了给数据赋予更直观的语义,即用更恰当的方式表示数据集的方向。这样做可以让用户编写数据转换函数时,少费点脑子。 + +处理 DataFrame 等表格数据时,对比 Numpy,**index**(行)或 **columns**(列)比 **axis 0** 和 **axis 1** 更直观。用这种方式迭代 DataFrame 的列,代码更易读易懂: + +```python +for col in df.columns: + series = df[col] + # do something with series +``` + +## 【03x00】Series 对象 + +Series 是带标签的一维数组,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引。调用 pandas.Series 函数即可创建 Series,基本语法如下: + +`pandas.Series(data=None[, index=None, dtype=None, name=None, copy=False, fastpath=False])` + +| 参数 | 描述 | +| ------ | ------ | +| data | 数组类型,可迭代的,字典或标量值,存储在序列中的数据 | +| index | 索引(数据标签),值必须是可哈希的,并且具有与数据相同的长度,
允许使用非唯一索引值。如果未提供,将默认为RangeIndex(0,1,2,…,n) | +| dtype | 输出系列的数据类型。可选项,如果未指定,则将从数据中推断,具体参考官网 [dtypes](https://pandas.pydata.org/docs/getting_started/basics.html#dtypes) 介绍 | +| name | str 类型,可选项,给 Series 命名 | +| copy | bool 类型,可选项,默认 False,是否复制输入数据 | + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A79/01.png) + +### 【03x01】通过 list 构建 Series + +一般情况下我们只会用到 data 和 index 参数,可以通过 list(列表) 构建 Series,示例如下: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2]) +>>> obj +0 1 +1 5 +2 -8 +3 2 +dtype: int64 +``` + +由于我们没有为数据指定索引,于是会自动创建一个 0 到 N-1(N 为数据的长度)的整数型索引,左边一列是自动创建的索引(index),右边一列是数据(data)。 + +此外,还可以自定义索引(index): + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +``` + +索引(index)也可以通过赋值的方式就地修改: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +>>> obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] +>>> obj +Bob 1 +Steve 5 +Jeff -8 +Ryan 2 +dtype: int64 +``` + +### 【03x02】通过 dict 构建 Series + +通过 字典(dict) 构建 Series,字典的键(key)会作为索引(index),字典的值(value)会作为数据(data),示例如下: + +```python +>>> import pandas as pd +>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000} +>>> obj = pd.Series(data) +>>> obj +Beijing 21530000 +Shanghai 24280000 +Wuhan 11210000 +Zhejiang 58500000 +dtype: int64 +``` + +如果你想按照某个特定的顺序输出结果,可以传入排好序的字典的键以改变顺序: + +```python + +>>> import pandas as pd +>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000} +>>> cities = ['Guangzhou', 'Wuhan', 'Zhejiang', 'Shanghai'] +>>> obj = pd.Series(data, index=cities) +>>> obj +Guangzhou NaN +Wuhan 11210000.0 +Zhejiang 58500000.0 +Shanghai 24280000.0 +dtype: float64 +``` + +**注意:data 为字典,且未设置 index 参数时:** + +- **如果 Python >= 3.6 且 Pandas >= 0.23,Series 按字典的插入顺序排序索引。** +- **如果 Python < 3.6 或 Pandas < 0.23,Series 按字母顺序排序索引。** + +### 【03x03】获取其数据和索引 + +我们可以通过 Series 的 values 和 index 属性获取其数据和索引对象: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj.values +array([ 1, 5, -8, 2], dtype=int64) +>>> obj.index +Index(['a', 'b', 'c', 'd'], dtype='object') +``` + +### 【03x04】通过索引获取数据 + +与普通 NumPy 数组相比,Pandas 可以通过索引的方式选取 Series 中的单个或一组值,获取一组值时,传入的是一个列表,列表中的元素是索引值,另外还可以通过索引来修改其对应的值: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +>>> obj['a'] +1 +>>> obj['a'] = 3 +>>> obj[['a', 'b', 'c']] +a 3 +b 5 +c -8 +dtype: int64 +``` + +### 【03x05】使用函数运算 + +在 Pandas 中可以使用 NumPy 函数或类似 NumPy 的运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等): + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj[obj > 0] +a 1 +b 5 +d 2 +dtype: int64 +>>> obj * 2 +a 2 +b 10 +c -16 +d 4 +dtype: int64 +>>> np.exp(obj) +a 2.718282 +b 148.413159 +c 0.000335 +d 7.389056 +dtype: float64 +``` + +除了这些运算函数以外,还可以将 Series 看成是一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> 'a' in obj +True +>>> 'e' in obj +False +``` + +和 NumPy 类似,Pandas 中也有 NaN(即非数字,not a number),在 Pandas 中,它用于表示缺失值,Pandas 的 isnull 和 notnull 函数可用于检测缺失数据: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series([np.NaN, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a NaN +b 5.0 +c -8.0 +d 2.0 +dtype: float64 +>>> pd.isnull(obj) +a True +b False +c False +d False +dtype: bool +>>> pd.notnull(obj) +a False +b True +c True +d True +dtype: bool +>>> obj.isnull() +a True +b False +c False +d False +dtype: bool +>>> obj.notnull() +a False +b True +c True +d True +dtype: bool +``` + +### 【03x06】name 属性 + +可以在 `pandas.Series` 方法中为 Series 对象指定一个 name: + +```python +>>> import pandas as pd +>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000} +>>> obj = pd.Series(data, name='population') +>>> obj +Beijing 21530000 +Shanghai 24280000 +Wuhan 11210000 +Zhejiang 58500000 +Name: population, dtype: int64 +``` + +也可以通过 name 和 index.name 属性为 Series 对象和其索引指定 name: + +```python +>>> import pandas as pd +>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000} +>>> obj = pd.Series(data) +>>> obj.name = 'population' +>>> obj.index.name = 'cities' +>>> obj +cities +Beijing 21530000 +Shanghai 24280000 +Wuhan 11210000 +Zhejiang 58500000 +Name: population, dtype: int64 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106676693 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【04x00】DataFrame 对象 + +DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共用同一个索引)。DataFrame 中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。 + +- 类似多维数组/表格数据 (如Excel、R 语言中的 data.frame); +- 每列数据可以是不同的类型; +- 索引包括列索引和行索引 + +基本语法如下: + +`pandas.DataFrame(data=None, index: Optional[Collection] = None, columns: Optional[Collection] = None, dtype: Union[str, numpy.dtype, ExtensionDtype, None] = None, copy: bool = False)` + +| 参数 | 描述 | +| ------ | ------ | +| data | ndarray 对象(结构化或同类的)、可迭代的或者字典形式,存储在序列中的数据 | +| index | 数组类型,索引(数据标签),如果未提供,将默认为 RangeIndex(0,1,2,…,n) | +| columns | 列标签。如果未提供,则将默认为 RangeIndex(0、1、2、…、n) | +| dtype | 输出系列的数据类型。可选项,如果未指定,则将从数据中推断,具体参考官网 [dtypes](https://pandas.pydata.org/docs/getting_started/basics.html#dtypes) 介绍 | +| copy | bool 类型,可选项,默认 False,是否复制输入数据,仅影响 DataFrame/2d ndarray 输入 | + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A79/02.png) + +### 【03x01】通过 ndarray 构建 DataFrame + +```python +>>> import numpy as np +>>> import pandas as pd +>>> data = np.random.randn(5,3) +>>> data +array([[-2.16231157, 0.44967198, -0.73131523], + [ 1.18982913, 0.94670798, 0.82973421], + [-1.57680831, -0.99732066, 0.96432 ], + [-0.77483149, -1.23802881, 0.44061227], + [ 1.77666419, 0.24931983, -1.12960153]]) +>>> obj = pd.DataFrame(data) +>>> obj + 0 1 2 +0 -2.162312 0.449672 -0.731315 +1 1.189829 0.946708 0.829734 +2 -1.576808 -0.997321 0.964320 +3 -0.774831 -1.238029 0.440612 +4 1.776664 0.249320 -1.129602 +``` + +指定索引(index)和列标签(columns),和 Series 对象类似,可以在构建的时候添加索引和标签,也可以直接通过赋值的方式就地修改: + +```python +>>> import numpy as np +>>> import pandas as pd +>>> data = np.random.randn(5,3) +>>> index = ['a', 'b', 'c', 'd', 'e'] +>>> columns = ['A', 'B', 'C'] +>>> obj = pd.DataFrame(data, index, columns) +>>> obj + A B C +a -1.042909 -0.238236 -1.050308 +b 0.587079 0.739683 -0.233624 +c -0.451254 -0.638496 1.708807 +d -0.620158 -1.875929 -0.432382 +e -1.093815 0.396965 -0.759479 +>>> +>>> obj.index = ['A1', 'A2', 'A3', 'A4', 'A5'] +>>> obj.columns = ['B1', 'B2', 'B3'] +>>> obj + B1 B2 B3 +A1 -1.042909 -0.238236 -1.050308 +A2 0.587079 0.739683 -0.233624 +A3 -0.451254 -0.638496 1.708807 +A4 -0.620158 -1.875929 -0.432382 +A5 -1.093815 0.396965 -0.759479 +``` + +### 【03x02】通过 dict 构建 DataFrame + +通过 字典(dict) 构建 DataFrame,字典的键(key)会作为列标签(columns),字典的值(value)会作为数据(data),示例如下: + +```python +>>> import pandas as pd +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]} +>>> obj = pd.DataFrame(data) +>>> obj + city year people +0 Wuhan 2017 10892900 +1 Wuhan 2018 11081000 +2 Wuhan 2019 11212000 +3 Beijing 2017 21707000 +4 Beijing 2018 21542000 +5 Beijing 2019 21536000 +``` + +如果指定了列序列,则 DataFrame 的列就会按照指定顺序进行排列,如果传入的列在数据中找不到,就会在结果中产生缺失值(NaN): + +```python +>>> import pandas as pd +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]} +>>> pd.DataFrame(data) + city year people +0 Wuhan 2017 10892900 +1 Wuhan 2018 11081000 +2 Wuhan 2019 11212000 +3 Beijing 2017 21707000 +4 Beijing 2018 21542000 +5 Beijing 2019 21536000 +>>> pd.DataFrame(data, columns=['year', 'city', 'people']) + year city people +0 2017 Wuhan 10892900 +1 2018 Wuhan 11081000 +2 2019 Wuhan 11212000 +3 2017 Beijing 21707000 +4 2018 Beijing 21542000 +5 2019 Beijing 21536000 +>>> pd.DataFrame(data, columns=['year', 'city', 'people', 'money']) + year city people money +0 2017 Wuhan 10892900 NaN +1 2018 Wuhan 11081000 NaN +2 2019 Wuhan 11212000 NaN +3 2017 Beijing 21707000 NaN +4 2018 Beijing 21542000 NaN +5 2019 Beijing 21536000 NaN +``` + +**注意:data 为字典,且未设置 columns 参数时:** + +- **Python > = 3.6 且 Pandas > = 0.23,DataFrame 的列按字典的插入顺序排序。** + +- **Python < 3.6 或 Pandas < 0.23,DataFrame 的列按字典键的字母排序。** + +### 【03x03】获取其数据和索引 + +和 Series 一样,DataFrame 也可以通过其 values 和 index 属性获取其数据和索引对象: + +```python +>>> import numpy as np +>>> import pandas as pd +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]} +>>> obj = pd.DataFrame(data) +>>> obj.index +RangeIndex(start=0, stop=6, step=1) +>>> obj.values +array([['Wuhan', 2017, 10892900], + ['Wuhan', 2018, 11081000], + ['Wuhan', 2019, 11212000], + ['Beijing', 2017, 21707000], + ['Beijing', 2018, 21542000], + ['Beijing', 2019, 21536000]], dtype=object) +``` + +### 【03x04】通过索引获取数据 + +通过类似字典标记的方式或属性的方式,可以将 DataFrame 的列获取为一个 Series 对象; + +行也可以通过位置或名称的方式进行获取,比如用 loc 属性; + +对于特别大的 DataFrame,有一个 head 方法可以选取前五行数据。 + +用法示例: + +```python +>>> import numpy as np +>>> import pandas as pd +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]} +>>> obj = pd.DataFrame(data) +>>> obj + city year people +0 Wuhan 2017 10892900 +1 Wuhan 2018 11081000 +2 Wuhan 2019 11212000 +3 Beijing 2017 21707000 +4 Beijing 2018 21542000 +5 Beijing 2019 21536000 +>>> +>>> obj['city'] +0 Wuhan +1 Wuhan +2 Wuhan +3 Beijing +4 Beijing +5 Beijing +Name: city, dtype: object +>>> +>>> obj.year +0 2017 +1 2018 +2 2019 +3 2017 +4 2018 +5 2019 +Name: year, dtype: int64 +>>> +>>> type(obj.year) + +>>> +>>> obj.loc[2] +city Wuhan +year 2019 +people 11212000 +Name: 2, dtype: object +>>> +>>> obj.head() + city year people +0 Wuhan 2017 10892900 +1 Wuhan 2018 11081000 +2 Wuhan 2019 11212000 +3 Beijing 2017 21707000 +4 Beijing 2018 21542000 +``` + +### 【03x05】修改列的值 + +列可以通过赋值的方式进行修改。在下面示例中,分别给"money"列赋上一个标量值和一组值: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000], + 'money':[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN]} +>>> obj = pd.DataFrame(data, index=['A', 'B', 'C', 'D', 'E', 'F']) +>>> obj + city year people money +A Wuhan 2017 10892900 NaN +B Wuhan 2018 11081000 NaN +C Wuhan 2019 11212000 NaN +D Beijing 2017 21707000 NaN +E Beijing 2018 21542000 NaN +F Beijing 2019 21536000 NaN +>>> +>>> obj['money'] = 6666666666 +>>> obj + city year people money +A Wuhan 2017 10892900 6666666666 +B Wuhan 2018 11081000 6666666666 +C Wuhan 2019 11212000 6666666666 +D Beijing 2017 21707000 6666666666 +E Beijing 2018 21542000 6666666666 +F Beijing 2019 21536000 6666666666 +>>> +>>> obj['money'] = np.arange(100000000, 700000000, 100000000) +>>> obj + city year people money +A Wuhan 2017 10892900 100000000 +B Wuhan 2018 11081000 200000000 +C Wuhan 2019 11212000 300000000 +D Beijing 2017 21707000 400000000 +E Beijing 2018 21542000 500000000 +F Beijing 2019 21536000 600000000 +``` + +将列表或数组赋值给某个列时,其长度必须跟 DataFrame 的长度相匹配。如果赋值的是一个 Series,就会精确匹配 DataFrame 的索引: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000], + 'money':[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN]} +>>> obj = pd.DataFrame(data, index=['A', 'B', 'C', 'D', 'E', 'F']) +>>> obj + city year people money +A Wuhan 2017 10892900 NaN +B Wuhan 2018 11081000 NaN +C Wuhan 2019 11212000 NaN +D Beijing 2017 21707000 NaN +E Beijing 2018 21542000 NaN +F Beijing 2019 21536000 NaN +>>> +>>> new_data = pd.Series([5670000000, 6890000000, 7890000000], index=['A', 'C', 'E']) +>>> obj['money'] = new_data +>>> obj + city year people money +A Wuhan 2017 10892900 5.670000e+09 +B Wuhan 2018 11081000 NaN +C Wuhan 2019 11212000 6.890000e+09 +D Beijing 2017 21707000 NaN +E Beijing 2018 21542000 7.890000e+09 +F Beijing 2019 21536000 NaN +``` + +### 【03x06】增加 / 删除列 + +为不存在的列赋值会创建出一个新列,关键字 del 用于删除列: + +```python +>>> import pandas as pd +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]} +>>> obj = pd.DataFrame(data) +>>> obj + city year people +0 Wuhan 2017 10892900 +1 Wuhan 2018 11081000 +2 Wuhan 2019 11212000 +3 Beijing 2017 21707000 +4 Beijing 2018 21542000 +5 Beijing 2019 21536000 +>>> +>>> obj['northern'] = obj['city'] == 'Beijing' +>>> obj + city year people northern +0 Wuhan 2017 10892900 False +1 Wuhan 2018 11081000 False +2 Wuhan 2019 11212000 False +3 Beijing 2017 21707000 True +4 Beijing 2018 21542000 True +5 Beijing 2019 21536000 True +>>> +>>> del obj['northern'] +>>> obj + city year people +0 Wuhan 2017 10892900 +1 Wuhan 2018 11081000 +2 Wuhan 2019 11212000 +3 Beijing 2017 21707000 +4 Beijing 2018 21542000 +5 Beijing 2019 21536000 +``` + +### 【03x07】name 属性 + +可以通过 index.name 和 columns.name 属性设置索引(index)和列标签(columns)的 name,注意 DataFrame 对象是没有 name 属性的: + +```python +>>> import pandas as pd +>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], + 'year': [2017, 2018, 2019, 2017, 2018, 2019], + 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]} +>>> obj = pd.DataFrame(data) +>>> obj.index.name = 'index' +>>> obj.columns.name = 'columns' +>>> obj +columns city year people +index +0 Wuhan 2017 10892900 +1 Wuhan 2018 11081000 +2 Wuhan 2019 11212000 +3 Beijing 2017 21707000 +4 Beijing 2018 21542000 +5 Beijing 2019 21536000 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106676693 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A80-Pandas-02.md b/source/_posts/A80-Pandas-02.md new file mode 100644 index 0000000000000000000000000000000000000000..e22861b901abc2531b28301ca9d79c70c1b3c003 --- /dev/null +++ b/source/_posts/A80-Pandas-02.md @@ -0,0 +1,1024 @@ +--- +title: Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 +tags: + - Pandas + - Index + - 索引 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106698307 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +# 【1】Index 索引对象 + + Series 和 DataFrame 中的索引都是 Index 对象,为了保证数据的安全,索引对象是不可变的,如果尝试更改索引就会报错;常见的 Index 种类有:索引(Index),整数索引(Int64Index),层级索引(MultiIndex),时间戳类型(DatetimeIndex)。 + +一下代码演示了 Index 索引对象和其不可变的性质: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj.index +Index(['a', 'b', 'c', 'd'], dtype='object') +>>> type(obj.index) + +>>> obj.index[0] = 'e' +Traceback (most recent call last): + File "", line 1, in + obj.index[0] = 'e' + File "C:\Users\...\base.py", line 3909, in __setitem__ + raise TypeError("Index does not support mutable operations") +TypeError: Index does not support mutable operations +``` + +
index 索引对象常用属性
+ +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Index.html](https://pandas.pydata.org/docs/reference/api/pandas.Index.html) + +| 属性 | 描述 | +| ------ | ------ | +| T | 转置 | +| array | index 的数组形式,常见[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.array.html) | +| dtype | 返回基础数据的 dtype 对象 | +| hasnans | 是否有 NaN(缺失值) | +| inferred_type | 返回一个字符串,表示 index 的类型 | +| is_monotonic | 判断 index 是否是递增的 | +| is_monotonic_decreasing | 判断 index 是否单调递减 | +| is_monotonic_increasing | 判断 index 是否单调递增 | +| is_unique | index 是否没有重复值 | +| nbytes | 返回 index 中的字节数 | +| ndim | index 的维度 | +| nlevels | Number of levels. | +| shape | 返回一个元组,表示 index 的形状 | +| size | index 的大小 | +| values | 返回 index 中的值 / 数组 | + + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj.index +Index(['a', 'b', 'c', 'd'], dtype='object') +>>> +>>> obj.index.array + +['a', 'b', 'c', 'd'] +Length: 4, dtype: object +>>> +>>> obj.index.dtype +dtype('O') +>>> +>>> obj.index.hasnans +False +>>> +>>> obj.index.inferred_type +'string' +>>> +>>> obj.index.is_monotonic +True +>>> +>>> obj.index.is_monotonic_decreasing +False +>>> +>>> obj.index.is_monotonic_increasing +True +>>> +>>> obj.index.is_unique +True +>>> +>>> obj.index.nbytes +16 +>>> +>>> obj.index.ndim +1 +>>> +>>> obj.index.nlevels +1 +>>> +>>> obj.index.shape +(4,) +>>> +>>> obj.index.size +4 +>>> +>>> obj.index.values +array(['a', 'b', 'c', 'd'], dtype=object) +``` + +
index 索引对象常用方法
+ +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Index.html](https://pandas.pydata.org/docs/reference/api/pandas.Index.html) + +| 方法 | 描述 | +| ------ | ------ | +| all(self, *args, **kwargs) | 判断所有元素是否为真,有 0 会被视为 False | +| any(self, *args, **kwargs) | 判断是否至少有一个元素为真,均为 0 会被视为 False | +| append(self, other) | 连接另一个 index,产生一个新的 index | +| argmax(self[, axis, skipna]) | 返回 index 中最大值的索引值 | +| argmin(self[, axis, skipna]) | 返回 index 中最小值的索引值 | +| argsort(self, *args, **kwargs) | 对 index 从小到大排序,返回排序后的元素在原 index 中的索引值 | +| delete(self, loc) | 删除指定索引位置的元素,返回删除后的新 index | +| difference(self, other[, sort]) | 在第一个 index 中删除第二个 index 中的元素,即差集 | +| drop(self, labels[, errors]) | 在原 index 中删除传入的值 | +| drop_duplicates(self[, keep]) | 删除重复值,keep 参数可选值如下:
`‘first’`:保留第一次出现的重复项;
`‘last’`:保留最后一次出现的重复项;
`False`:不保留重复项 | +| duplicated(self[, keep]) | 判断是否为重复值,keep 参数可选值如下:
`‘first’`:第一次重复的为 False,其他为 True;
`‘last’`:最后一次重复的为 False,其他为 True;
`False`:所有重复的均为 True | +| dropna(self[, how]) | 删除缺失值,即 NaN | +| fillna(self[, value, downcast]) | 用指定值填充缺失值,即 NaN | +| equals(self, other) | 判断两个 index 是否相同 | +| insert(self, loc, item) | 将元素插入到指定索引处,返回新的 index | +| intersection(self, other[, sort]) | 返回两个 index 的交集 | +| isna(self) | 检测 index 元素是否为缺失值,即 NaN | +| isnull(self) | 检测 index 元素是否为缺失值,即 NaN | +| max(self[, axis, skipna]) | 返回 index 的最大值 | +| min(self[, axis, skipna]) | 返回 index 的最小值 | +| union(self, other[, sort]) | 返回两个 index 的并集 | +| unique(self[, level]) | 返回 index 中的唯一值,相当于去除重复值 | + + +- `all(self, *args, **kwargs)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.all.html)】 +```python +>>> import pandas as pd +>>> pd.Index([1, 2, 3]).all() +True +>>> +>>> pd.Index([0, 1, 2]).all() +False +``` + +- `any(self, *args, **kwargs)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.any.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([0, 0, 1]).any() +True +>>> +>>> pd.Index([0, 0, 0]).any() +False +``` + +- `append(self, other)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.append.html)】 + +```python +>>> import pandas as pd +>>> pd.Index(['a', 'b', 'c']).append(pd.Index([1, 2, 3])) +Index(['a', 'b', 'c', 1, 2, 3], dtype='object') +``` + +- `argmax(self[, axis, skipna])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.argmax.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 2, 3, 9, 1]).argmax() +3 +``` + +- `argmin(self[, axis, skipna])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.argmin.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 2, 3, 9, 1]).argmin() +4 +``` + +- `argsort(self, *args, **kwargs)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.argsort.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 2, 3, 9, 1]).argsort() +array([4, 1, 2, 0, 3], dtype=int32) +``` + +- `delete(self, loc)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.delete.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 2, 3, 9, 1]).delete(0) +Int64Index([2, 3, 9, 1], dtype='int64') +``` + +- `difference(self, other[, sort])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.difference.html)】 + +```python +>>> import pandas as pd +>>> idx1 = pd.Index([2, 1, 3, 4]) +>>> idx2 = pd.Index([3, 4, 5, 6]) +>>> idx1.difference(idx2) +Int64Index([1, 2], dtype='int64') +>>> idx1.difference(idx2, sort=False) +Int64Index([2, 1], dtype='int64') +``` + +- `drop(self, labels[, errors])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.drop.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 2, 3, 9, 1]).drop([2, 1]) +Int64Index([5, 3, 9], dtype='int64') +``` + +- `drop_duplicates(self[, keep])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.drop_duplicates.html)】 + +```python +>>> import pandas as pd +>>> idx = pd.Index(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo']) +>>> idx.drop_duplicates(keep='first') +Index(['lama', 'cow', 'beetle', 'hippo'], dtype='object') +>>> idx.drop_duplicates(keep='last') +Index(['cow', 'beetle', 'lama', 'hippo'], dtype='object') +>>> idx.drop_duplicates(keep=False) +Index(['cow', 'beetle', 'hippo'], dtype='object') +``` + +- duplicated(self[, keep]) 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.duplicated.html)】 + +```python +>>> import pandas as pd +>>> idx = pd.Index(['lama', 'cow', 'lama', 'beetle', 'lama']) +>>> idx.duplicated() +array([False, False, True, False, True]) +>>> idx.duplicated(keep='first') +array([False, False, True, False, True]) +>>> idx.duplicated(keep='last') +array([ True, False, True, False, False]) +>>> idx.duplicated(keep=False) +array([ True, False, True, False, True]) +``` + +- `dropna(self[, how])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.dropna.html)】 + +```python +>>> import numpy as np +>>> import pandas as pd +>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).dropna() +Float64Index([2.0, 5.0, 6.0], dtype='float64') +``` + +- `fillna(self[, value, downcast])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.fillna.html)】 + +```python +>>> import numpy as np +>>> import pandas as pd +>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).fillna(5) +Float64Index([2.0, 5.0, 5.0, 6.0, 5.0, 5.0], dtype='float64') +``` + +- `equals(self, other)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.equals.html)】 + +```python +>>> import pandas as pd +>>> idx1 = pd.Index([5, 2, 3, 9, 1]) +>>> idx2 = pd.Index([5, 2, 3, 9, 1]) +>>> idx1.equals(idx2) +True +>>> +>>> idx1 = pd.Index([5, 2, 3, 9, 1]) +>>> idx2 = pd.Index([5, 2, 4, 9, 1]) +>>> idx1.equals(idx2) +False +``` + +- `intersection(self, other[, sort])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.intersection.html)】 + +```python +>>> import pandas as pd +>>> idx1 = pd.Index([1, 2, 3, 4]) +>>> idx2 = pd.Index([3, 4, 5, 6]) +>>> idx1.intersection(idx2) +Int64Index([3, 4], dtype='int64') +``` + +- `insert(self, loc, item)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.insert.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 2, 3, 9, 1]).insert(2, 'A') +Index([5, 2, 'A', 3, 9, 1], dtype='object') +``` + +- `isna(self)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.isna.html)】、`isnull(self)` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.isnull.html)】 + +```python +>>> import numpy as np +>>> import pandas as pd +>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).isna() +array([False, False, True, False, True, True]) +>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).isnull() +array([False, False, True, False, True, True]) +``` + +- `max(self[, axis, skipna])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.max.html)】、`min(self[, axis, skipna])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.min.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 2, 3, 9, 1]).max() +9 +>>> pd.Index([5, 2, 3, 9, 1]).min() +1 +``` + +- `union(self, other[, sort])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.union.html)】 + +```python +>>> import pandas as pd +>>> idx1 = pd.Index([1, 2, 3, 4]) +>>> idx2 = pd.Index([3, 4, 5, 6]) +>>> idx1.union(idx2) +Int64Index([1, 2, 3, 4, 5, 6], dtype='int64') +``` + +- `unique(self[, level])` 【[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.Index.unique.html)】 + +```python +>>> import pandas as pd +>>> pd.Index([5, 1, 3, 5, 1]).unique() +Int64Index([5, 1, 3], dtype='int64') +``` + +# 【2】Pandas 一般索引 + +由于在 Pandas 中,由于有一些更高级的索引操作,比如重新索引,层级索引等,因此将一般的切片索引、花式索引、布尔索引等归纳为一般索引。 + +## 【2.1】Series 索引 + +### 【2.1.1】head() / tail() + +`Series.head()` 和 `Series.tail()` 方法可以获取的前五行和后五行数据,如果向 head() / tail() 里面传入参数,则会获取指定行: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(8)) +>>> obj +0 -0.643437 +1 -0.365652 +2 -0.966554 +3 -0.036127 +4 1.046095 +5 -2.048362 +6 -1.865551 +7 1.344728 +dtype: float64 +>>> +>>> obj.head() +0 -0.643437 +1 -0.365652 +2 -0.966554 +3 -0.036127 +4 1.046095 +dtype: float64 +>>> +>>> obj.head(3) +0 -0.643437 +1 -0.365652 +2 -0.966554 +dtype: float64 +>>> +>>> obj.tail() +3 1.221221 +4 -1.373496 +5 1.032843 +6 0.029734 +7 -1.861485 +dtype: float64 +>>> +>>> obj.tail(3) +5 1.032843 +6 0.029734 +7 -1.861485 +dtype: float64 +``` + +### 【2.1.2】行索引 + +Pandas 中可以按照位置进行索引,也可以按照索引名(index)进行索引,也可以用 Python 字典的表达式和方法来获取值: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +>>> obj['c'] +-8 +>>> obj[2] +-8 +>>> 'b' in obj +True +>>> obj.keys() +Index(['a', 'b', 'c', 'd'], dtype='object') +>>> list(obj.items()) +[('a', 1), ('b', 5), ('c', -8), ('d', 2)] +``` + +### 【2.1.3】切片索引 + +切片的方法有两种:按位置切片和按索引名(index)切片,注意:按位置切片时,**不包含**终止索引;按索引名(index)切片时,**包含**终止索引。 + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +>>> +>>> obj[1:3] +b 5 +c -8 +dtype: int64 +>>> +>>> obj[0:3:2] +a 1 +c -8 +dtype: int64 +>>> +>>> obj['b':'d'] +b 5 +c -8 +d 2 +dtype: int64 +``` + +### 【2.1.4】花式索引 + +所谓的花式索引,就是间隔索引、不连续的索引,传递一个由索引名(index)或者位置参数组成的**列表**来一次性获得多个元素: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +>>> +>>> obj[[0, 2]] +a 1 +c -8 +dtype: int64 +>>> +>>> obj[['a', 'c', 'd']] +a 1 +c -8 +d 2 +dtype: int64 +``` + +### 【2.1.5】布尔索引 + +可以通过一个布尔数组来索引目标数组,即通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。 + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 5, -8, 2, -3], index=['a', 'b', 'c', 'd', 'e']) +>>> obj +a 1 +b 5 +c -8 +d 2 +e -3 +dtype: int64 +>>> +>>> obj[obj > 0] +a 1 +b 5 +d 2 +dtype: int64 +>>> +>>> obj > 0 +a True +b True +c False +d True +e False +dtype: bool +``` + +## 【2.2】DataFrame 索引 + +### 【2.2.1】head() / tail() + +和 Series 一样,`DataFrame.head()` 和 `DataFrame.tail()` 方法同样可以获取 DataFrame 的前五行和后五行数据,如果向 head() / tail() 里面传入参数,则会获取指定行: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.random.randn(8,4), columns = ['a', 'b', 'c', 'd']) +>>> obj + a b c d +0 -1.399390 0.521596 -0.869613 0.506621 +1 -0.748562 -0.364952 0.188399 -1.402566 +2 1.378776 -1.476480 0.361635 0.451134 +3 -0.206405 -1.188609 3.002599 0.563650 +4 0.993289 1.133748 1.177549 -2.562286 +5 -0.482157 1.069293 1.143983 -1.303079 +6 -1.199154 0.220360 0.801838 -0.104533 +7 -1.359816 -2.092035 2.003530 -0.151812 +>>> +>>> obj.head() + a b c d +0 -1.399390 0.521596 -0.869613 0.506621 +1 -0.748562 -0.364952 0.188399 -1.402566 +2 1.378776 -1.476480 0.361635 0.451134 +3 -0.206405 -1.188609 3.002599 0.563650 +4 0.993289 1.133748 1.177549 -2.562286 +>>> +>>> obj.head(3) + a b c d +0 -1.399390 0.521596 -0.869613 0.506621 +1 -0.748562 -0.364952 0.188399 -1.402566 +2 1.378776 -1.476480 0.361635 0.451134 +>>> +>>> obj.tail() + a b c d +3 -0.206405 -1.188609 3.002599 0.563650 +4 0.993289 1.133748 1.177549 -2.562286 +5 -0.482157 1.069293 1.143983 -1.303079 +6 -1.199154 0.220360 0.801838 -0.104533 +7 -1.359816 -2.092035 2.003530 -0.151812 +>>> +>>> obj.tail(3) + a b c d +5 -0.482157 1.069293 1.143983 -1.303079 +6 -1.199154 0.220360 0.801838 -0.104533 +7 -1.359816 -2.092035 2.003530 -0.151812 +``` + +### 【2.2.2】列索引 + +DataFrame 可以按照列标签(columns)来进行列索引: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.random.randn(7,2), columns = ['a', 'b']) +>>> obj + a b +0 -1.198795 0.928378 +1 -2.878230 0.014650 +2 2.267475 0.370952 +3 0.639340 -1.301041 +4 -1.953444 0.148934 +5 -0.445225 0.459632 +6 0.097109 -2.592833 +>>> +>>> obj['a'] +0 -1.198795 +1 -2.878230 +2 2.267475 +3 0.639340 +4 -1.953444 +5 -0.445225 +6 0.097109 +Name: a, dtype: float64 +>>> +>>> obj[['a']] + a +0 -1.198795 +1 -2.878230 +2 2.267475 +3 0.639340 +4 -1.953444 +5 -0.445225 +6 0.097109 +>>> +>>> type(obj['a']) + +>>> type(obj[['a']]) + +``` + +### 【2.2.3】切片索引 + +DataFrame 中的切片索引是针对行来操作的,切片的方法有两种:按位置切片和按索引名(index)切片,注意:按位置切片时,不包含终止索引;按索引名(index)切片时,包含终止索引。 + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = np.random.randn(5,4) +>>> index = ['I1', 'I2', 'I3', 'I4', 'I5'] +>>> columns = ['a', 'b', 'c', 'd'] +>>> obj = pd.DataFrame(data, index, columns) +>>> obj + a b c d +I1 0.828676 -1.663337 1.753632 1.432487 +I2 0.368138 0.222166 0.902764 -1.436186 +I3 2.285615 -2.415175 -1.344456 -0.502214 +I4 3.224288 -0.500268 1.293596 -1.235549 +I5 -0.938833 -0.804433 -0.170047 -0.566766 +>>> +>>> obj[0:3] + a b c d +I1 0.828676 -1.663337 1.753632 1.432487 +I2 0.368138 0.222166 0.902764 -1.436186 +I3 2.285615 -2.415175 -1.344456 -0.502214 +>>> +>>> obj[0:4:2] + a b c d +I1 -0.042168 1.437354 -1.114545 0.830790 +I3 0.241506 0.018984 -0.499151 -1.190143 +>>> +>>> obj['I2':'I4'] + a b c d +I2 0.368138 0.222166 0.902764 -1.436186 +I3 2.285615 -2.415175 -1.344456 -0.502214 +I4 3.224288 -0.500268 1.293596 -1.235549 +``` + +### 【2.2.4】花式索引 + +和 Series 一样,所谓的花式索引,就是间隔索引、不连续的索引,传递一个由列名(columns)组成的**列表**来一次性获得多列元素: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = np.random.randn(5,4) +>>> index = ['I1', 'I2', 'I3', 'I4', 'I5'] +>>> columns = ['a', 'b', 'c', 'd'] +>>> obj = pd.DataFrame(data, index, columns) +>>> obj + a b c d +I1 -1.083223 -0.182874 -0.348460 -1.572120 +I2 -0.205206 -0.251931 1.180131 0.847720 +I3 -0.980379 0.325553 -0.847566 -0.882343 +I4 -0.638228 -0.282882 -0.624997 -0.245980 +I5 -0.229769 1.002930 -0.226715 -0.916591 +>>> +>>> obj[['a', 'd']] + a d +I1 -1.083223 -1.572120 +I2 -0.205206 0.847720 +I3 -0.980379 -0.882343 +I4 -0.638228 -0.245980 +I5 -0.229769 -0.916591 +``` + +### 【2.2.5】布尔索引 + +可以通过一个布尔数组来索引目标数组,即通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。 + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = np.random.randn(5,4) +>>> index = ['I1', 'I2', 'I3', 'I4', 'I5'] +>>> columns = ['a', 'b', 'c', 'd'] +>>> obj = pd.DataFrame(data, index, columns) +>>> obj + a b c d +I1 -0.602984 -0.135716 0.999689 -0.339786 +I2 0.911130 -0.092485 -0.914074 -0.279588 +I3 0.849606 -0.420055 -1.240389 -0.179297 +I4 0.249986 -1.250668 0.329416 -1.105774 +I5 -0.743816 0.430647 -0.058126 -0.337319 +>>> +>>> obj[obj > 0] + a b c d +I1 NaN NaN 0.999689 NaN +I2 0.911130 NaN NaN NaN +I3 0.849606 NaN NaN NaN +I4 0.249986 NaN 0.329416 NaN +I5 NaN 0.430647 NaN NaN +>>> +>>> obj > 0 + a b c d +I1 False False True False +I2 True False False False +I3 True False False False +I4 True False True False +I5 False True False False +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106698307 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +# 【3】索引器:loc 和 iloc + +loc 是标签索引、iloc 是位置索引,注意:在 Pandas1.0.0 之前还有 ix 方法(即可按标签也可按位置索引),在 Pandas1.0.0 之后已被移除。 + +## 【3.1】loc 标签索引 + +loc 标签索引,即根据 index 和 columns 来选择数据。 + +### 【3.1.1】Series.loc + +在 Series 中,允许输入: + +- 单个标签,例如 `5` 或 `'a'`,(注意,`5` 是 index 的名称,而不是位置索引); +- 标签列表或数组,例如 `['a', 'b', 'c']`; +- 带有标签的切片对象,例如 `'a':'f'`。 + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Series.loc.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.loc.html) + +```python +>>> import pandas as np +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +>>> +>>> obj.loc['a'] +1 +>>> +>>> obj.loc['a':'c'] +a 1 +b 5 +c -8 +dtype: int64 +>>> +>>> obj.loc[['a', 'd']] +a 1 +d 2 +dtype: int64 +``` + +### 【3.1.2】DataFrame.loc + +在 DataFrame 中,第一个参数索引**行**,第二个参数是索引**列**,允许输入的格式和 Series 大同小异。 + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html) + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['a', 'b', 'c'], columns=['A', 'B', 'C']) +>>> obj + A B C +a 1 2 3 +b 4 5 6 +c 7 8 9 +>>> +>>> obj.loc['a'] +A 1 +B 2 +C 3 +Name: a, dtype: int64 +>>> +>>> obj.loc['a':'c'] + A B C +a 1 2 3 +b 4 5 6 +c 7 8 9 +>>> +>>> obj.loc[['a', 'c']] + A B C +a 1 2 3 +c 7 8 9 +>>> +>>> obj.loc['b', 'B'] +5 +>>> obj.loc['b', 'A':'C'] +A 4 +B 5 +C 6 +Name: b, dtype: int64 +``` + +## 【3.2】iloc 位置索引 + +作用和 loc 一样,不过是基于索引的编号来索引,即根据 index 和 columns 的位置编号来选择数据。 + +### 【3.2.1】Series.iloc + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Series.iloc.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.iloc.html) + +在 Series 中,允许输入: + +- 整数,例如 `5`; +- 整数列表或数组,例如 `[4, 3, 0]`; +- 具有整数的切片对象,例如 `1:7`。 + +```python +>>> import pandas as np +>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd']) +>>> obj +a 1 +b 5 +c -8 +d 2 +dtype: int64 +>>> +>>> obj.iloc[1] +5 +>>> +>>> obj.iloc[0:2] +a 1 +b 5 +dtype: int64 +>>> +>>> obj.iloc[[0, 1, 3]] +a 1 +b 5 +d 2 +dtype: int64 +``` + +### 【3.2.2】DataFrame.iloc + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html) + +在 DataFrame 中,第一个参数索引**行**,第二个参数是索引**列**,允许输入的格式和 Series 大同小异: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['a', 'b', 'c'], columns=['A', 'B', 'C']) +>>> obj + A B C +a 1 2 3 +b 4 5 6 +c 7 8 9 +>>> +>>> obj.iloc[1] +A 4 +B 5 +C 6 +Name: b, dtype: int64 +>>> +>>> obj.iloc[0:2] + A B C +a 1 2 3 +b 4 5 6 +>>> +>>> obj.iloc[[0, 2]] + A B C +a 1 2 3 +c 7 8 9 +>>> +>>> obj.iloc[1, 2] +6 +>>> +>>> obj.iloc[1, 0:2] +A 4 +B 5 +Name: b, dtype: int64 +``` + +# 【4】Pandas 重新索引 + +Pandas 对象的一个重要方法是 reindex,其作用是创建一个新对象,它的数据符合新的索引。以 `DataFrame.reindex` 为例(Series 类似),基本语法如下: + +`DataFrame.reindex(self, labels=None, index=None, columns=None, axis=None, method=None, copy=True, level=None, fill_value=nan, limit=None, tolerance=None)` + +部分参数描述如下:(完整参数解释参见[官方文档](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.reindex.html)) + +| 参数 | 描述 | +| ------ | ------ | +| index | 用作索引的新序列,既可以是 index 实例,也可以是其他序列型的 Python 数据结构 | +| method | 插值(填充)方式,取值如下:
`None`:不填补空白;
`pad / ffill`:将上一个有效的观测值向前传播到下一个有效的观测值;
`backfill / bfill`:使用下一个有效观察值来填补空白;
`nearest`:使用最近的有效观测值来填补空白。 | +| fill_value | 在重新索引的过程中,需要引入缺失值时使用的替代值 | +| limit | 前向或后向填充时的最大填充量 | +| tolerance | 向前或向后填充时,填充不准确匹配项的最大间距(绝对值距离) | +| level | 在 Multilndex 的指定级别上匹配简单索引,否则选其子集 | +| copy | 默认为 True,无论如何都复制;如果为 False,则新旧相等就不复制 | + +reindex 将会根据新索引进行重排。如果某个索引值当前不存在,就引入缺失值: + +```python +>>> import pandas as pd +>>> obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) +>>> obj +d 4.5 +b 7.2 +a -5.3 +c 3.6 +dtype: float64 +>>> +>>> obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e']) +>>> obj2 +a -5.3 +b 7.2 +c 3.6 +d 4.5 +e NaN +dtype: float64 +``` + +对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理。method 选项即可达到此目的,例如,使用 ffill 可以实现前向值填充: + +```python +>>> import pandas as pd +>>> obj = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) +>>> obj +0 blue +2 purple +4 yellow +dtype: object +>>> +>>> obj2 = obj.reindex(range(6), method='ffill') +>>> obj2 +0 blue +1 blue +2 purple +3 purple +4 yellow +5 yellow +dtype: object +``` + +借助 DataFrame,reindex可以修改(行)索引和列。只传递一个序列时,会重新索引结果的行: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California']) +>>> obj + Ohio Texas California +a 0 1 2 +c 3 4 5 +d 6 7 8 +>>> +>>> obj2 = obj.reindex(['a', 'b', 'c', 'd']) +>>> obj2 + Ohio Texas California +a 0.0 1.0 2.0 +b NaN NaN NaN +c 3.0 4.0 5.0 +d 6.0 7.0 8.0 +``` + +列可以用 columns 关键字重新索引: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California']) +>>> obj + Ohio Texas California +a 0 1 2 +c 3 4 5 +d 6 7 8 +>>> +>>> states = ['Texas', 'Utah', 'California'] +>>> obj.reindex(columns=states) + Texas Utah California +a 1 NaN 2 +c 4 NaN 5 +d 7 NaN 8 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106698307 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A81-Pandas-03.md b/source/_posts/A81-Pandas-03.md new file mode 100644 index 0000000000000000000000000000000000000000..5e1c67f7e688161b063c3fb159ac917c546d8bde --- /dev/null +++ b/source/_posts/A81-Pandas-03.md @@ -0,0 +1,649 @@ +--- +title: Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 +tags: + - Pandas + - 算术运算 + - 缺失值 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(三):各种算术运算与缺失值的处理。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106743778 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】Pandas 算术运算 + +Pandas 继承了 NumPy 的功能,NumPy 的基本能力之一是快速对每个元素进行运算,既包括基本算术运算(加、减、乘、除),也包括更复杂的运算(三角函数、指数函数和对数函数等)。具体可以参考 NumPy 系列文章。 + +### 【01x01】使用 NumPy 通用函数 + +因为 Pandas 是建立在 NumPy 基础之上的,所以 NumPy 的通用函数同样适用于 Pandas 的 Series 和 DataFrame 对象,如下所示: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> rng = np.random.RandomState(42) +>>> ser = pd.Series(rng.randint(0, 10, 4)) +>>> ser +0 6 +1 3 +2 7 +3 4 +dtype: int32 +>>> +>>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D']) +>>> obj + A B C D +0 6 9 2 6 +1 7 4 3 7 +2 7 2 5 4 +``` + +使用 NumPy 通用函数,生成的结果是另一个保留索引的 Pandas 对象: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> rng = np.random.RandomState(42) +>>> ser = pd.Series(rng.randint(0, 10, 4)) +>>> ser +0 6 +1 3 +2 7 +3 4 +dtype: int32 +>>> +>>> np.exp(ser) +0 403.428793 +1 20.085537 +2 1096.633158 +3 54.598150 +dtype: float64 +``` + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D']) +>>> np.sin(obj * np.pi / 4) + A B C D +0 -1.000000 7.071068e-01 1.000000 -1.000000e+00 +1 -0.707107 1.224647e-16 0.707107 -7.071068e-01 +2 -0.707107 1.000000e+00 -0.707107 1.224647e-16 +``` + +### 【01x02】数据对齐 + +Pandas 最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。自动的数据对齐操作会在不重叠的索引处引入缺失值,即 NaN,缺失值会在算术运算过程中传播。 + +Series 对象的数据对齐操作: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e']) +>>> obj2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g']) +>>> obj1 +a 7.3 +c -2.5 +d 3.4 +e 1.5 +dtype: float64 +>>> +>>> obj2 +a -2.1 +c 3.6 +e -1.5 +f 4.0 +g 3.1 +dtype: float64 +>>> +>>> obj1 + obj2 +a 5.2 +c 1.1 +d NaN +e 0.0 +f NaN +g NaN +dtype: float64 +``` + +DataFrame 对象的数据对齐操作会同时发生在行和列上: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado']) +>>> obj2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon']) +>>> obj1 + b c d +Ohio 0.0 1.0 2.0 +Texas 3.0 4.0 5.0 +Colorado 6.0 7.0 8.0 +>>> +>>> obj2 + b d e +Utah 0.0 1.0 2.0 +Ohio 3.0 4.0 5.0 +Texas 6.0 7.0 8.0 +Oregon 9.0 10.0 11.0 +>>> +>>> obj1 + obj2 + b c d e +Colorado NaN NaN NaN NaN +Ohio 3.0 NaN 6.0 NaN +Oregon NaN NaN NaN NaN +Texas 9.0 NaN 12.0 NaN +Utah NaN NaN NaN NaN +``` + +### 【01x03】DataFrame 与 Series 之间的运算 + +首先回忆 NumPy 中的广播(参见:[《Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割》](https://itrhx.blog.csdn.net/article/details/104988137)),跟不同维度的 NumPy 数组一样,DataFrame 和 Series 之间算术运算也是有明确规定的。首先回忆一下 NumPy 中不同维度的数组之间的运算: + +```python +>>> import numpy as np +>>> arr = np.arange(12.).reshape((3, 4)) +>>> arr +array([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.]]) +>>> +>>> arr[0] +array([0., 1., 2., 3.]) +>>> +>>> arr - arr[0] +array([[0., 0., 0., 0.], + [4., 4., 4., 4.], + [8., 8., 8., 8.]]) +``` + +可以看到每一行都进行了减法运算,这正是 NumPy 中的广播,而 DataFrame 与 Series 之间的运算也类似,默认情况下,DataFrame 和 Series 之间的算术运算会将 Series 的索引匹配到 DataFrame 的列,然后沿着行一直向下广播: + +```python +>>> import numpy as np +>>> import pandas as pd +>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD']) +>>> frame + b d e +AA 0.0 1.0 2.0 +BB 3.0 4.0 5.0 +CC 6.0 7.0 8.0 +DD 9.0 10.0 11.0 +>>> +>>> series = frame.iloc[0] +>>> series +b 0.0 +d 1.0 +e 2.0 +Name: AA, dtype: float64 +>>> +>>> frame - series + b d e +AA 0.0 0.0 0.0 +BB 3.0 3.0 3.0 +CC 6.0 6.0 6.0 +DD 9.0 9.0 9.0 +``` + +如果某个索引值在 DataFrame 的列或 Series 的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集: + +```python +>>> import numpy as np +>>> import pandas as pd +>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD']) +>>> frame + b d e +AA 0.0 1.0 2.0 +BB 3.0 4.0 5.0 +CC 6.0 7.0 8.0 +DD 9.0 10.0 11.0 +>>> +>>> series = pd.Series(range(3), index=['b', 'e', 'f']) +>>> series +b 0 +e 1 +f 2 +dtype: int64 +>>> +>>> frame + series + b d e f +AA 0.0 NaN 3.0 NaN +BB 3.0 NaN 6.0 NaN +CC 6.0 NaN 9.0 NaN +DD 9.0 NaN 12.0 NaN +``` + +如果希望匹配行且在列上广播,则必须使用算术运算方法,在方法中传入的轴(axis)就是希望匹配的轴。在下例中,我们的目的是匹配 DataFrame 的行索引(axis='index' or axis=0)并进行广播: + +```python +>>> import numpy as np +>>> import pandas as pd +>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD']) +>>> frame + b d e +AA 0.0 1.0 2.0 +BB 3.0 4.0 5.0 +CC 6.0 7.0 8.0 +DD 9.0 10.0 11.0 +>>> +>>> series = frame['d'] +>>> series +AA 1.0 +BB 4.0 +CC 7.0 +DD 10.0 +Name: d, dtype: float64 +>>> +>>> frame.sub(series, axis='index') + b d e +AA -1.0 0.0 1.0 +BB -1.0 0.0 1.0 +CC -1.0 0.0 1.0 +DD -1.0 0.0 1.0 +``` + +### 【01x04】Pandas 算术方法 + +完整的 Pandas 算术方法见下表: + +| 方法 | 副本 | 描述 | +| ------ | ----- | ------ | +| add() | radd() | 加法(+) | +| sub()、subtract() | rsub() | 减法(-) | +| mul()、multiply() | rmul() | 乘法(*) | +| pow() | rpow() | 指数(**) +| truediv()、div()、divide() | rdiv() | 除法(/) +| floordiv() | rfloordiv() | 底除(//) +| mod() | rmod() | 求余(%) + +副本均为原方法前加了个 `r`,它会翻转参数: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd')) +>>> obj + a b c d +0 0.0 1.0 2.0 3.0 +1 4.0 5.0 6.0 7.0 +2 8.0 9.0 10.0 11.0 +>>> +>>> 1 / obj + a b c d +0 inf 1.000000 0.500000 0.333333 +1 0.250 0.200000 0.166667 0.142857 +2 0.125 0.111111 0.100000 0.090909 +>>> +>>> obj.rdiv(1) + a b c d +0 inf 1.000000 0.500000 0.333333 +1 0.250 0.200000 0.166667 0.142857 +2 0.125 0.111111 0.100000 0.090909 +``` + + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106743778 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【02x00】处理缺失值 + +在现实中遇到的数据很少是干净整齐的,许多数据集都会有数据缺失的现象,缺失值主要有三种形式:null、NaN(NAN,nan) 或 NA。 + +### 【02x01】fill_value() 指定值与缺失值进行运算 + +使用 `add`, `sub`, `div`, `mul` 等算术方法时,通过 `fill_value` 指定填充值,未对齐的数据将和填充值做运算。 + +Series 中的应用: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series([1, 2, 3, 4, 5]) +>>> obj2 = pd.Series([6, 7]) +>>> +>>> obj1 +0 1 +1 2 +2 3 +3 4 +4 5 +dtype: int64 +>>> +>>> obj2 +0 6 +1 7 +dtype: int64 +>>> +>>> obj1.add(obj2) +0 7.0 +1 9.0 +2 NaN +3 NaN +4 NaN +dtype: float64 +>>> +>>> obj1.add(obj2, fill_value=-1) +0 7.0 +1 9.0 +2 2.0 +3 3.0 +4 4.0 +dtype: float64 +``` + +DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd')) +>>> obj2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde')) +>>> +>>> obj2.loc[1, 'b'] = np.nan +>>> +>>> obj1 + a b c d +0 0.0 1.0 2.0 3.0 +1 4.0 5.0 6.0 7.0 +2 8.0 9.0 10.0 11.0 +>>> +>>> obj2 + a b c d e +0 0.0 1.0 2.0 3.0 4.0 +1 5.0 NaN 7.0 8.0 9.0 +2 10.0 11.0 12.0 13.0 14.0 +3 15.0 16.0 17.0 18.0 19.0 +>>> +>>> obj1 + obj2 + a b c d e +0 0.0 2.0 4.0 6.0 NaN +1 9.0 NaN 13.0 15.0 NaN +2 18.0 20.0 22.0 24.0 NaN +3 NaN NaN NaN NaN NaN +>>> +>>> obj1.add(obj2, fill_value=10) + a b c d e +0 0.0 2.0 4.0 6.0 14.0 +1 9.0 15.0 13.0 15.0 19.0 +2 18.0 20.0 22.0 24.0 24.0 +3 25.0 26.0 27.0 28.0 29.0 +``` + +### 【02x02】isnull() / notnull() 判断缺失值 + +`isnull()`:为缺失值时为 `True`,否则为 `False`; + +`notnull()` 为缺失值时为 `False`,否则为 `True`。 + +```python +>>> import numpy as np +>>> import pandas as pd +>>> obj = pd.Series([1, np.nan, 'hello', None]) +>>> obj +0 1 +1 NaN +2 hello +3 None +dtype: object +>>> +>>> obj.isnull() +0 False +1 True +2 False +3 True +dtype: bool +>>> +>>> obj.notnull() +0 True +1 False +2 True +3 False +dtype: bool +``` + +### 【02x03】dropna() 删除缺失值 + +`dropna()` 方法用于返回一个删除了缺失值的新 Series 或 DataFrame 对象。 + +在 Series 对象当中,`dropna()` 方法的语法如下(其他参数用法可参考在 DataFrame 中的应用): + +`Series.dropna(self, axis=0, inplace=False, how=None)` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Series.dropna.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.dropna.html) + +```python +>>> import numpy as np +>>> import pandas as pd +>>> obj = pd.Series([1, np.nan, 'hello', None]) +>>> obj +0 1 +1 NaN +2 hello +3 None +dtype: object +>>> +>>> obj.dropna() +0 1 +2 hello +dtype: object +``` + +在 DataFrame 对象中,`dropna()` 方法的语法如下: + +`DataFrame.dropna(self, axis=0, how='any', thresh=None, subset=None, inplace=False)` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html) + +| 参数 | 描述 | +| ------ | ------ | +| axis | 确定是否删除包含缺失值的行或列
`0` 或 `'index'`:删除包含缺失值的行。`1` 或 `'columns'`:删除包含缺失值的列 | +| how | `'any'`:如果存在任何NA值,则删除该行或列。`'all'`:如果所有值都是NA,则删除该行或列 | +| thresh | 设置行或列中**非缺失值**的最小数量 | + +不传递任何参数,将会删除任何包含缺失值的整行数据: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]]) +>>> obj + 0 1 2 +0 1.0 NaN 2 +1 2.0 3.0 5 +2 NaN 4.0 6 +>>> +>>> obj.dropna() + 0 1 2 +1 2.0 3.0 5 +``` + +指定 axis 参数,删除包含缺失值的行或列: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]]) +>>> obj + 0 1 2 +0 1.0 NaN 2 +1 2.0 3.0 5 +2 NaN 4.0 6 +>>> +>>> obj.dropna(axis='columns') + 2 +0 2 +1 5 +2 6 +``` + +指定 how 参数,`'any'`:如果存在任何NA值,则删除该行或列。`'all'`:如果所有值都是NA,则删除该行或列: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]]) +>>> obj + 0 1 2 3 +0 1.0 NaN 2 NaN +1 2.0 3.0 5 NaN +2 NaN 4.0 6 NaN +>>> obj.dropna(axis='columns', how='all') + 0 1 2 +0 1.0 NaN 2 +1 2.0 3.0 5 +2 NaN 4.0 6 +``` + +指定 thresh 参数,设置行或列中**非缺失值**的最小数量,以下示例中,第一行和第三行只有两个非缺失值,所以会被删除: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]]) +>>> obj + 0 1 2 3 +0 1.0 NaN 2 NaN +1 2.0 3.0 5 NaN +2 NaN 4.0 6 NaN +>>> +>>> obj.dropna(axis='rows', thresh=3) + 0 1 2 3 +1 2.0 3.0 5 NaN +``` + +### 【02x04】fillna() 填充缺失值 + +`fillna()` 方法可以将缺失值替换成有效的数值。 + +在 Series 对象中,`fillna()` 方法的语法如下: + +`Series.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Series.fillna.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.fillna.html) + +| 参数 | 描述 | +| ------ | ------ | +| value | 用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值
指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值
不在dict / Series / DataFrame中的值将不被填充。此值不能是列表 | +| method | 填充方法:`None`
`‘pad’` / `‘ffill’`:将上一个有效观测值向前传播到下一个有效观测值
`‘backfill’` / `‘bfill’`:使用下一个有效观察值来填补空白 | +| axis | `0` or `‘index’`,要填充缺失值的轴 | + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, np.nan, 2, None, 3], index=list('abcde')) +>>> obj +a 1.0 +b NaN +c 2.0 +d NaN +e 3.0 +dtype: float64 +>>> +>>> obj.fillna(0) +a 1.0 +b 0.0 +c 2.0 +d 0.0 +e 3.0 +dtype: float64 +>>> +>>> obj.fillna(method='ffill') +a 1.0 +b 1.0 +c 2.0 +d 2.0 +e 3.0 +dtype: float64 +>>> +>>> obj.fillna(method='bfill') +a 1.0 +b 2.0 +c 2.0 +d 3.0 +e 3.0 +dtype: float64 +``` + +在 DataFrame 对象中,`fillna()` 方法的语法如下: + +`DataFrame.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.fillna.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.fillna.html) + +| 参数 | 描述 | +| ------ | ------ | +| value | 用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值
指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值
不在dict / Series / DataFrame中的值将不被填充。此值不能是列表 | +| method | 填充方法:`None`
`‘pad’` / `‘ffill’`:将上一个有效观测值向前传播到下一个有效观测值
`‘backfill’` / `‘bfill’`:使用下一个有效观察值来填补空白 | +| axis | `0` or `‘index’`,`1` or `‘columns’`,要填充缺失值的轴 | + +在 DataFrame 对象中的用法和在 Series 对象中的用法大同小异,只不过 axis 参数多了一个选择: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]]) +>>> obj + 0 1 2 3 +0 1.0 NaN 2 NaN +1 2.0 3.0 5 NaN +2 NaN 4.0 6 NaN +>>> +>>> obj.fillna(method='ffill', axis=1) + 0 1 2 3 +0 1.0 1.0 2.0 2.0 +1 2.0 3.0 5.0 5.0 +2 NaN 4.0 6.0 6.0 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106743778 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A82-Pandas-04.md b/source/_posts/A82-Pandas-04.md new file mode 100644 index 0000000000000000000000000000000000000000..0600e35b6d0bef79f0e70f686f5ca4cc50660515 --- /dev/null +++ b/source/_posts/A82-Pandas-04.md @@ -0,0 +1,693 @@ +--- +title: Python 数据分析三剑客之 Pandas(四):函数应用/映射/排序和层级索引 +tags: + - Pandas + - 函数应用 + - 映射 + - 排序 + - 层级索引 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106758103 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】函数应用和映射 + +Pandas 可直接使用 NumPy 的 ufunc(元素级数组方法) 函数: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.random.randn(5,4) - 1) +>>> obj + 0 1 2 3 +0 -0.228107 1.377709 -1.096528 -2.051001 +1 -2.477144 -0.500013 -0.040695 -0.267452 +2 -0.485999 -1.232930 -0.390701 -1.947984 +3 -0.839161 -0.702802 -1.756359 -1.873149 +4 0.853121 -1.540105 0.621614 -0.583360 +>>> +>>> np.abs(obj) + 0 1 2 3 +0 0.228107 1.377709 1.096528 2.051001 +1 2.477144 0.500013 0.040695 0.267452 +2 0.485999 1.232930 0.390701 1.947984 +3 0.839161 0.702802 1.756359 1.873149 +4 0.853121 1.540105 0.621614 0.583360 +``` + +函数映射:在 Pandas 中 `apply` 方法可以将函数应用到列或行上,可以通过设置 axis 参数来指定行或列,默认 axis = 0,即按列映射: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.random.randn(5,4) - 1) +>>> obj + 0 1 2 3 +0 -0.707028 -0.755552 -2.196480 -0.529676 +1 -0.772668 0.127485 -2.015699 -0.283654 +2 0.248200 -1.940189 -1.068028 -1.751737 +3 -0.872904 -0.465371 -1.327951 -2.883160 +4 -0.092664 0.258351 -1.010747 -2.313039 +>>> +>>> obj.apply(lambda x : x.max()) +0 0.248200 +1 0.258351 +2 -1.010747 +3 -0.283654 +dtype: float64 +>>> +>>> obj.apply(lambda x : x.max(), axis=1) +0 -0.529676 +1 0.127485 +2 0.248200 +3 -0.465371 +4 0.258351 +dtype: float64 +``` + +另外还可以通过 `applymap` 将函数映射到每个数据上: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.random.randn(5,4) - 1) +>>> obj + 0 1 2 3 +0 -0.772463 -1.597008 -3.196100 -1.948486 +1 -1.765108 -1.646421 -0.687175 -0.401782 +2 0.275699 -3.115184 -1.429063 -1.075610 +3 -0.251734 -0.448399 -3.077677 -0.294674 +4 -1.495896 -1.689729 -0.560376 -1.808794 +>>> +>>> obj.applymap(lambda x : '%.2f' % x) + 0 1 2 3 +0 -0.77 -1.60 -3.20 -1.95 +1 -1.77 -1.65 -0.69 -0.40 +2 0.28 -3.12 -1.43 -1.08 +3 -0.25 -0.45 -3.08 -0.29 +4 -1.50 -1.69 -0.56 -1.81 +``` + +## 【02x00】排序 + +### 【02x01】sort_index() 索引排序 + +根据条件对数据集排序(sorting)也是一种重要的内置运算。要对行或列索引进行排序(按字典顺序),可使用 `sort_index` 方法,它将返回一个已排序的新对象。 + +在 Series 和 DataFrame 中的基本语法如下: + +```python +Series.sort_index(self, + axis=0, + level=None, + ascending=True, + inplace=False, + kind='quicksort', + na_position='last', + sort_remaining=True, + ignore_index: bool = False) +``` + +```python +DataFrame.sort_index(self, + axis=0, + level=None, + ascending=True, + inplace=False, + kind='quicksort', + na_position='last', + sort_remaining=True, + ignore_index: bool = False) +``` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_index.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_index.html) +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_index.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_index.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴排序,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| ascending | 为 `True`时升序排序(默认),为 `False`时降序排序 | +| kind | 排序方法,`quicksort`:快速排序(默认);`'mergesort’`:归并排序;`'heapsort'`:堆排序;具体可参见 [numpy.sort()](https://numpy.org/doc/stable/reference/generated/numpy.sort.html) | + +在 Series 中的应用(按照索引 index 排序): + +```python +>>> import pandas as pd +>>> obj = pd.Series(range(4), index=['d', 'a', 'b', 'c']) +>>> obj +d 0 +a 1 +b 2 +c 3 +dtype: int64 +>>> +>>> obj.sort_index() +a 1 +b 2 +c 3 +d 0 +dtype: int64 +``` + +在 DataFrame 中的应用(可按照索引 index 或列标签 columns 排序): + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c']) +>>> obj + d a b c +three 0 1 2 3 +one 4 5 6 7 +>>> +>>> obj.sort_index() + d a b c +one 4 5 6 7 +three 0 1 2 3 +>>> +>>> obj.sort_index(axis=1) + a b c d +three 1 2 3 0 +one 5 6 7 4 +>>> +>>> obj.sort_index(axis=1, ascending=False) + d c b a +three 0 3 2 1 +one 4 7 6 5 +``` + +### 【02x02】sort_values() 按值排序 + +在 Series 和 DataFrame 中的基本语法如下: + +```python +Series.sort_values(self, + axis=0, + ascending=True, + inplace=False, + kind='quicksort', + na_position='last', + ignore_index=False) +``` + +```python +DataFrame.sort_values(self, + by, + axis=0, + ascending=True, + inplace=False, + kind='quicksort', + na_position='last', + ignore_index=False) +``` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_values.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_values.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| by | DataFrame 中的必须参数,指定列的值进行排序,Series 中没有此参数 | +| axis | 指定轴排序,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| ascending | 为 `True`时升序排序(默认),为 `False`时降序排序 | +| kind | 排序方法,`quicksort`:快速排序(默认);`'mergesort’`:归并排序;`'heapsort'`:堆排序;具体可参见 [numpy.sort()](https://numpy.org/doc/stable/reference/generated/numpy.sort.html) | + + +在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾: + +```python +>>> import pandas as pd +>>> obj = pd.Series([4, 7, -3, 2]) +>>> obj +0 4 +1 7 +2 -3 +3 2 +dtype: int64 +>>> +>>> obj.sort_values() +2 -3 +3 2 +0 4 +1 7 +dtype: int64 +>>> +>>> obj = pd.Series([4, np.nan, 7, np.nan, -3, 2]) +>>> obj +0 4.0 +1 NaN +2 7.0 +3 NaN +4 -3.0 +5 2.0 +dtype: float64 +>>> +>>> obj.sort_values() +4 -3.0 +5 2.0 +0 4.0 +2 7.0 +1 NaN +3 NaN +dtype: float64 +``` + +在 DataFrame 中的应用,有时候可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给 `sort_values()` 的 `by` 参数即可达到该目的,当传递多个列时,首先会对第一列进行排序,若第一列有相同的值,再根据第二列进行排序,依次类推: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]}) +>>> obj + a b c +0 4 0 6 +1 4 1 4 +2 -3 0 1 +3 2 1 3 +>>> +>>> obj.sort_values(by='c') + a b c +2 -3 0 1 +3 2 1 3 +1 4 1 4 +0 4 0 6 +>>> +>>> obj.sort_values(by='c', ascending=False) + a b c +0 4 0 6 +1 4 1 4 +3 2 1 3 +2 -3 0 1 +>>> +>>> obj.sort_values(by=['a', 'b']) + a b c +2 -3 0 1 +3 2 1 3 +0 4 0 6 +1 4 1 4 +``` + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]}, index=['A', 'B', 'C', 'D']) +>>> obj + a b c +A 4 0 6 +B 4 1 4 +C -3 0 1 +D 2 1 3 +>>> +>>> obj.sort_values(by='B', axis=1) + b a c +A 0 4 6 +B 1 4 4 +C 0 -3 1 +D 1 2 3 +``` + +### 【02x03】rank() 返回排序后元素索引 + +rank() 函数会返回一个对象,对象的值是原对象经过排序后的索引值,即下标。 + +在 Series 和 DataFrame 中的基本语法如下: + +```python +Series.rank(self: ~ FrameOrSeries, + axis=0, + method: str = 'average', + numeric_only: Union[bool, NoneType] = None, + na_option: str = 'keep', + ascending: bool = True, + pct: bool = False) +``` + +```python +DataFrame.rank(self: ~ FrameOrSeries, + axis=0, + method: str = 'average', + numeric_only: Union[bool, NoneType] = None, + na_option: str = 'keep', + ascending: bool = True, + pct: bool = False) +``` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.rank.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.rank.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rank.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rank.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴排序,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| method | 有相同值时,如何处理:
`‘average’`:默认值,去两个相同索引的平均值;`‘min’`:取两个相同索引的最小值;
`‘max’`:取两个相同索引的最大值;`‘first’`:按照出现的先后顺序;
`‘dense’`:和 `'min'` 差不多,但是各组之间总是+1的,不太好解释,可以看后面的示例 | +| ascending | 为 `True`时升序排序(默认),为 `False`时降序排序 | + +在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾: + +```python +>>> import pandas as pd +>>> obj = pd.Series([7, -5, 7, 4, 2, 0, 4]) +>>> obj +0 7 +1 -5 +2 7 +3 4 +4 2 +5 0 +6 4 +dtype: int64 +>>> +>>> obj.rank() +0 6.5 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,默认取平均值,即 6.5 +1 1.0 +2 6.5 +3 4.5 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,默认取平均值,即 4.5 +4 3.0 +5 2.0 +6 4.5 +dtype: float64 +>>> +>>> obj.rank(method='first') +0 6.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照第一次出现排序,分别为 6 和 7 +1 1.0 +2 7.0 +3 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照第一次出现排序,分别为 4 和 5 +4 3.0 +5 2.0 +6 5.0 +dtype: float64 +>>> +>>> obj.rank(method='dense') +0 5.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,但 dense 规定间隔为 1 所以为 5 +1 1.0 +2 5.0 +3 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 4 +4 3.0 +5 2.0 +6 4.0 +dtype: float64 +>>> +>>> obj.rank(method='min') +0 6.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,即 6 +1 1.0 +2 6.0 +3 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 4 +4 3.0 +5 2.0 +6 4.0 +dtype: float64 +``` + +在 DataFrame 中可以使用 axis 参数来指定轴: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2.5]}) +>>> obj + b a c +0 4.3 0 -2.0 +1 7.0 1 5.0 +2 -3.0 0 8.0 +3 2.0 1 -2.5 +>>> +>>> obj.rank() + b a c +0 3.0 1.5 2.0 +1 4.0 3.5 3.0 +2 1.0 1.5 4.0 +3 2.0 3.5 1.0 +>>> +>>> obj.rank(axis='columns') + b a c +0 3.0 2.0 1.0 +1 3.0 1.0 2.0 +2 1.0 2.0 3.0 +3 3.0 2.0 1.0 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106758103 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【03x00】层级索引 + +### 【03x01】认识层级索引 + +以下示例将创建一个 Series 对象, 索引 Index 由两个子 list 组成,第一个子 list 是外层索引,第二个 list 是内层索引: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]]) +>>> obj +a 0 -0.201536 + 1 -0.629058 + 2 0.766716 +b 0 -1.255831 + 1 -0.483727 + 2 -0.018653 +c 0 0.788787 + 1 1.010097 + 2 -0.187258 +d 0 1.242363 + 1 -0.822011 + 2 -0.085682 +dtype: float64 +``` + +### 【03x02】MultiIndex 索引对象 + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.html](https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.html) + +尝试打印上面示例中 Series 的索引类型,会得到一个 MultiIndex 对象,MultiIndex 对象的 levels 属性表示两个层级中分别有那些标签,codes 属性表示每个位置分别是什么标签,如下所示: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]]) +>>> obj +a 0 0.035946 + 1 -0.867215 + 2 -0.053355 +b 0 -0.986616 + 1 0.026071 + 2 -0.048394 +c 0 0.251274 + 1 0.217790 + 2 1.137674 +d 0 -1.245178 + 1 1.234972 + 2 -0.035624 +dtype: float64 +>>> +>>> type(obj.index) + +>>> +>>> obj.index +MultiIndex([('a', 0), + ('a', 1), + ('a', 2), + ('b', 0), + ('b', 1), + ('b', 2), + ('c', 0), + ('c', 1), + ('c', 2), + ('d', 0), + ('d', 1), + ('d', 2)], + ) +>>> obj.index.levels +FrozenList([['a', 'b', 'c', 'd'], [0, 1, 2]]) +>>> +>>> obj.index.codes +FrozenList([[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]]) +``` + +通常可以使用 `from_arrays()` 方法来将数组对象转换为 MultiIndex 索引对象: + +```python +>>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']] +>>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color')) +MultiIndex([(1, 'red'), + (1, 'blue'), + (2, 'red'), + (2, 'blue')], + names=['number', 'color']) +``` + +其他常用方法见下表(更多方法参见官方文档): + +| 方法 | 描述 | +| ------ | ------ | +| from_arrays(arrays[, sortorder, names]) | 将数组转换为 MultiIndex | +| from_tuples(tuples[, sortorder, names]) | 将元组列表转换为 MultiIndex | +| from_product(iterables[, sortorder, names]) | 将多个可迭代的笛卡尔积转换成 MultiIndex | +| from_frame(df[, sortorder, names]) | 将 DataFrame 对象转换为 MultiIndex | +| set_levels(self, levels[, level, inplace, …]) | 为 MultiIndex 设置新的 levels | +| set_codes(self, codes[, level, inplace, …]) | 为 MultiIndex 设置新的 codes | +| sortlevel(self[, level, ascending, …]) | 根据 level 进行排序 | +| droplevel(self[, level]) | 删除指定的 level | +| swaplevel(self[, i, j]) | 交换 level i 与 level i,即交换外层索引与内层索引 | + +### 【03x03】提取值 + +对于这种有多层索引的对象,如果只传入一个参数,则会对外层索引进行提取,其中包含对应所有的内层索引,如果传入两个参数,则第一个参数表示外层索引,第二个参数表示内层索引,示例如下: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]]) +>>> obj +a 0 0.550202 + 1 0.328784 + 2 1.422690 +b 0 -1.333477 + 1 -0.933809 + 2 -0.326541 +c 0 0.663686 + 1 0.943393 + 2 0.273106 +d 0 1.354037 + 1 -2.312847 + 2 -2.343777 +dtype: float64 +>>> +>>> obj['b'] +0 -1.333477 +1 -0.933809 +2 -0.326541 +dtype: float64 +>>> +>>> obj['b', 1] +-0.9338094811708413 +>>> +>>> obj[:, 2] +a 1.422690 +b -0.326541 +c 0.273106 +d -2.343777 +dtype: float64 +``` + +### 【03x04】交换分层与排序 + +MultiIndex 对象的 `swaplevel()` 方法可以交换外层与内层索引,`sortlevel()` 方法会先对外层索引进行排序,再对内层索引进行排序,默认是升序,如果设置 `ascending` 参数为 False 则会降序排列,示例如下: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]]) +>>> obj +a 0 -0.110215 + 1 0.193075 + 2 -1.101706 +b 0 -1.325743 + 1 0.528418 + 2 -0.127081 +c 0 -0.733822 + 1 1.665262 + 2 0.127073 +d 0 1.262022 + 1 -1.170518 + 2 0.966334 +dtype: float64 +>>> +>>> obj.swaplevel() +0 a -0.110215 +1 a 0.193075 +2 a -1.101706 +0 b -1.325743 +1 b 0.528418 +2 b -0.127081 +0 c -0.733822 +1 c 1.665262 +2 c 0.127073 +0 d 1.262022 +1 d -1.170518 +2 d 0.966334 +dtype: float64 +>>> +>>> obj.swaplevel().index.sortlevel() +(MultiIndex([(0, 'a'), + (0, 'b'), + (0, 'c'), + (0, 'd'), + (1, 'a'), + (1, 'b'), + (1, 'c'), + (1, 'd'), + (2, 'a'), + (2, 'b'), + (2, 'c'), + (2, 'd')], + ), array([ 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11], dtype=int32)) +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106758103 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A83-Pandas-05.md b/source/_posts/A83-Pandas-05.md new file mode 100644 index 0000000000000000000000000000000000000000..2bc765dcda89d00f38975f4db3d35f603a9fd886 --- /dev/null +++ b/source/_posts/A83-Pandas-05.md @@ -0,0 +1,737 @@ +--- +title: Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 +tags: + - Pandas + - 统计计算 + - 统计描述 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(五):统计计算与统计描述。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106788501 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】统计计算 + +Pandas 对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从 Series 中提取单个值(如 sum 或 mean)或从 DataFrame 的行或列中提取一个 Series。跟对应的 NumPy 数组方法相比,它们都是基于没有缺失数据的假设而构建的。 + +### 【01x01】sum() 求和 + +`sum()` 方法用于返回指定轴的和,相当于 `numpy.sum()`。 + +在 Series 和 DataFrame 中的基本语法如下: + +- `Series.sum(self, axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs)` + +- `DataFrame.sum(self, axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.sum.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.sum.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sum.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sum.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴求和,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| skipna | bool 类型,求和时是否排除缺失值(NA/null),默认 True | +| level | 如果轴是 MultiIndex(层次结构),则沿指定层次求和 | + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> idx = pd.MultiIndex.from_arrays([ + ['warm', 'warm', 'cold', 'cold'], + ['dog', 'falcon', 'fish', 'spider']], + names=['blooded', 'animal']) +>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx) +>>> obj +blooded animal +warm dog 4 + falcon 2 +cold fish 0 + spider 8 +Name: legs, dtype: int64 +>>> +>>> obj.sum() +14 +>>> +>>> obj.sum(level='blooded') +blooded +warm 6 +cold 8 +Name: legs, dtype: int64 +>>> +>>> obj.sum(level=0) +blooded +warm 6 +cold 8 +Name: legs, dtype: int64 +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = 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']) +>>> obj + one two +a 1.40 NaN +b 7.10 -4.5 +c NaN NaN +d 0.75 -1.3 +>>> +>>> obj.sum() +one 9.25 +two -5.80 +dtype: float64 +>>> +>>> obj.sum(axis=1) +a 1.40 +b 2.60 +c 0.00 +d -0.55 +dtype: float64 +``` + +### 【01x02】min() 最小值 + +`min()` 方法用于返回指定轴的最小值。 + +在 Series 和 DataFrame 中的基本语法如下: + +- `Series.min(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs)` + +- `DataFrame.min(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.min.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.min.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.min.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.min.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴求最小值,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| skipna | bool 类型,求最小值时是否排除缺失值(NA/null),默认 True | +| level | 如果轴是 MultiIndex(层次结构),则沿指定层次求最小值 | + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> idx = pd.MultiIndex.from_arrays([ + ['warm', 'warm', 'cold', 'cold'], + ['dog', 'falcon', 'fish', 'spider']], + names=['blooded', 'animal']) +>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx) +>>> obj +blooded animal +warm dog 4 + falcon 2 +cold fish 0 + spider 8 +Name: legs, dtype: int64 +>>> +>>> obj.min() +0 +>>> +>>> obj.min(level='blooded') +blooded +warm 2 +cold 0 +Name: legs, dtype: int64 +>>> +>>> obj.min(level=0) +blooded +warm 2 +cold 0 +Name: legs, dtype: int64 +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = 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']) +>>> obj + one two +a 1.40 NaN +b 7.10 -4.5 +c NaN NaN +d 0.75 -1.3 +>>> +>>> obj.min() +one 0.75 +two -4.50 +dtype: float64 +>>> +>>> obj.min(axis=1) +a 1.4 +b -4.5 +c NaN +d -1.3 +dtype: float64 +>>> +>>> obj.min(axis='columns', skipna=False) +a NaN +b -4.5 +c NaN +d -1.3 +dtype: float64 +``` + +### 【01x03】max() 最大值 + +`max()` 方法用于返回指定轴的最大值。 + +在 Series 和 DataFrame 中的基本语法如下: + +- `Series.max(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs)` + +- `DataFrame.max(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.max.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.max.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.max.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.max.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴求最大值,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| skipna | bool 类型,求最大值时是否排除缺失值(NA/null),默认 True | +| level | 如果轴是 MultiIndex(层次结构),则沿指定层次求最大值 | + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> idx = pd.MultiIndex.from_arrays([ + ['warm', 'warm', 'cold', 'cold'], + ['dog', 'falcon', 'fish', 'spider']], + names=['blooded', 'animal']) +>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx) +>>> obj +blooded animal +warm dog 4 + falcon 2 +cold fish 0 + spider 8 +Name: legs, dtype: int64 +>>> +>>> obj.max() +8 +>>> +>>> obj.max(level='blooded') +blooded +warm 4 +cold 8 +Name: legs, dtype: int64 +>>> +>>> obj.max(level=0) +blooded +warm 4 +cold 8 +Name: legs, dtype: int64 +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = 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']) +>>> obj + one two +a 1.40 NaN +b 7.10 -4.5 +c NaN NaN +d 0.75 -1.3 +>>> +>>> obj.max() +one 7.1 +two -1.3 +dtype: float64 +>>> +>>> obj.max(axis=1) +a 1.40 +b 7.10 +c NaN +d 0.75 +dtype: float64 +>>> +>>> obj.max(axis='columns', skipna=False) +a NaN +b 7.10 +c NaN +d 0.75 +dtype: float64 +``` + +### 【01x04】mean() 平均值 + +`mean()` 方法用于返回指定轴的平均值。 + +在 Series 和 DataFrame 中的基本语法如下: + +- `Series.mean(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs)` + +- `DataFrame.mean(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.mean.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.mean.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴求平均值,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| skipna | bool 类型,求平均值时是否排除缺失值(NA/null),默认 True | +| level | 如果轴是 MultiIndex(层次结构),则沿指定层次求平均值 | + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> idx = pd.MultiIndex.from_arrays([ + ['warm', 'warm', 'cold', 'cold'], + ['dog', 'falcon', 'fish', 'spider']], + names=['blooded', 'animal']) +>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx) +>>> obj +blooded animal +warm dog 4 + falcon 2 +cold fish 0 + spider 8 +Name: legs, dtype: int64 +>>> +>>> obj.mean() +3.5 +>>> +>>> obj.mean(level='blooded') +blooded +warm 3 +cold 4 +Name: legs, dtype: int64 +>>> +>>> obj.mean(level=0) +blooded +warm 3 +cold 4 +Name: legs, dtype: int64 +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = 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']) +>>> obj + one two +a 1.40 NaN +b 7.10 -4.5 +c NaN NaN +d 0.75 -1.3 +>>> +>>> obj.mean() +one 3.083333 +two -2.900000 +dtype: float64 +>>> +>>> obj.mean(axis=1) +a 1.400 +b 1.300 +c NaN +d -0.275 +dtype: float64 +>>> +>>> obj.mean(axis='columns', skipna=False) +a NaN +b 1.300 +c NaN +d -0.275 +dtype: float64 +``` + +### 【01x05】idxmin() 最小值索引 + +`idxmin()` 方法用于返回最小值的索引。 + +在 Series 和 DataFrame 中的基本语法如下: + +- `Series.idxmin(self, axis=0, skipna=True, *args, **kwargs)` + +- `DataFrame.idxmin(self, axis=0, skipna=True)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmin.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmin.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmin.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmin.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| skipna | bool 类型,是否排除缺失值(NA/null),默认 True | + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> idx = pd.MultiIndex.from_arrays([ + ['warm', 'warm', 'cold', 'cold'], + ['dog', 'falcon', 'fish', 'spider']], + names=['blooded', 'animal']) +>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx) +>>> obj +blooded animal +warm dog 4 + falcon 2 +cold fish 0 + spider 8 +Name: legs, dtype: int64 +>>> +>>> obj.idxmin() +('cold', 'fish') +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = 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']) +>>> obj + one two +a 1.40 NaN +b 7.10 -4.5 +c NaN NaN +d 0.75 -1.3 +>>> +>>> obj.idxmin() +one d +two b +dtype: object +``` + + +### 【01x06】idxmax() 最大值索引 + +`idxmax()` 方法用于返回最大值的索引。 + +在 Series 和 DataFrame 中的基本语法如下: + +- `Series.idxmax(self, axis=0, skipna=True, *args, **kwargs)` + +- `DataFrame.idxmax(self, axis=0, skipna=True)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmax.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmax.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmax.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmax.html) + +常用参数描述如下: + +| 参数 | 描述 | +| ------ | ------ | +| axis | 指定轴,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| skipna | bool 类型,是否排除缺失值(NA/null),默认 True | + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> idx = pd.MultiIndex.from_arrays([ + ['warm', 'warm', 'cold', 'cold'], + ['dog', 'falcon', 'fish', 'spider']], + names=['blooded', 'animal']) +>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx) +>>> obj +blooded animal +warm dog 4 + falcon 2 +cold fish 0 + spider 8 +Name: legs, dtype: int64 +>>> +>>> obj.idxmax() +('cold', 'spider') +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = 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']) +>>> obj + one two +a 1.40 NaN +b 7.10 -4.5 +c NaN NaN +d 0.75 -1.3 +>>> +>>> obj.idxmax() +one b +two d +dtype: object +``` + +## 【02x00】统计描述 + +`describe()` 方法用于快速综合统计结果:计数、均值、标准差、最大最小值、四分位数等。还可以通过参数来设置需要忽略或者包含的统计选项。 + +在 Series 和 DataFrame 中的基本语法如下: + +- `Series.describe(self: ~ FrameOrSeries, percentiles=None, include=None, exclude=None)` + +- `DataFrame.describe(self: ~ FrameOrSeries, percentiles=None, include=None, exclude=None) ` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.describe.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.describe.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html) + +| 参数 | 描述 | +| ------ | ------ | +| percentiles | 数字列表,可选项,要包含在输出中的百分比。所有值都应介于 0 和 1 之间。默认值为 [.25、.5、.75],即返回第 25、50 和 75 个百分点 | +| include | 要包含在结果中的数据类型,数据类型列表,默认 None,具体取值类型参见官方文档 | +| exclude | 要从结果中忽略的数据类型,数据类型列表,默认 None,具体取值类型参见官方文档 | + +描述数字形式的 Series 对象: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 2, 3]) +>>> obj +0 1 +1 2 +2 3 +dtype: int64 +>>> +>>> obj.describe() +count 3.0 +mean 2.0 +std 1.0 +min 1.0 +25% 1.5 +50% 2.0 +75% 2.5 +max 3.0 +dtype: float64 +``` + +分类描述: + +```python +>>> import pandas as pd +>>> obj = pd.Series(['a', 'a', 'b', 'c']) +>>> obj +0 a +1 a +2 b +3 c +dtype: object +>>> +>>> obj.describe() +count 4 +unique 3 +top a +freq 2 +dtype: object +``` + +描述时间戳: + +```python +>>> import pandas as pd +>>> obj = pd.Series([ + np.datetime64("2000-01-01"), + np.datetime64("2010-01-01"), + np.datetime64("2010-01-01") + ]) +>>> obj +0 2000-01-01 +1 2010-01-01 +2 2010-01-01 +dtype: datetime64[ns] +>>> +>>> obj.describe() +count 3 +unique 2 +top 2010-01-01 00:00:00 +freq 2 +first 2000-01-01 00:00:00 +last 2010-01-01 00:00:00 +dtype: object +``` + +描述 DataFrame 对象: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']}) +>>> obj + categorical numeric object +0 d 1 a +1 e 2 b +2 f 3 c +>>> +>>> obj.describe() + numeric +count 3.0 +mean 2.0 +std 1.0 +min 1.0 +25% 1.5 +50% 2.0 +75% 2.5 +max 3.0 +``` + +不考虑数据类型,显示所有描述: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']}) +>>> obj + categorical numeric object +0 d 1 a +1 e 2 b +2 f 3 c +>>> +>>> obj.describe(include='all') + categorical numeric object +count 3 3.0 3 +unique 3 NaN 3 +top f NaN c +freq 1 NaN 1 +mean NaN 2.0 NaN +std NaN 1.0 NaN +min NaN 1.0 NaN +25% NaN 1.5 NaN +50% NaN 2.0 NaN +75% NaN 2.5 NaN +max NaN 3.0 NaN +``` + +仅包含 category 列: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']}) +>>> obj + categorical numeric object +0 d 1 a +1 e 2 b +2 f 3 c +>>> +>>> obj.describe(include=['category']) + categorical +count 3 +unique 3 +top f +freq 1 +``` + +## 【03x00】常用统计方法 + +其他常用统计方法参见下表: + +| 方法 | 描述 | 官方文档 | +| ------ | ------ | ------------ | +| count | 非NA值的数量 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.count.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.count.html) | +| describe | 针对Series或各DataFrame列计算汇总统计 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.describe.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html) | +| min | 计算最小值 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.min.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.min.html) | +| max | 计算最大值 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.max.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.max.html) | +| argmin | 计算能够获取到最小值的索引位置(整数) | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.argmin.html) | +| argmax | 计算能够获取到最大值的索引位置(整数) | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.argmax.html) | +| idxmin | 计算能够获取到最小值的索引值 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmin.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmin.html) | +| idxmax | 计算能够获取到最大值的索引值 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmax.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmax.html) | +| quantile | 计算样本的分位数(0到1) | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.quantile.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.quantile.html) | +| sum | 值的总和 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.sum.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sum.html) | +| mean | 值的平均数 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.mean.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html) | +| median | 值的算术中位数(50%分位数) | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.median.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.median.html) | +| mad | 根据平均值计算平均绝对离差 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.mad.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mad.html) | +| var | 样本值的方差 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.var.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.var.html) | +| std | 样本值的标准差 | [Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.std.html)丨[DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.std.html) | + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106788501 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A84-Pandas-06.md b/source/_posts/A84-Pandas-06.md new file mode 100644 index 0000000000000000000000000000000000000000..af6705897df52b52bf081742aa6ae14828b590e7 --- /dev/null +++ b/source/_posts/A84-Pandas-06.md @@ -0,0 +1,812 @@ +--- +title: Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂/应用/合并 +tags: + - Pandas + - GroupBy + - 数据分裂 + - 数据合并 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106804881 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】GroupBy 机制 + +对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节。在将数据集加载、融合、准备好之后,通常就是计算分组统计或生成透视表。Pandas 提供了一个灵活高效的 GroupBy 功能,虽然“分组”(group by)这个名字是借用 SQL 数据库语言的命令,但其理念引用发明 R 语言 frame 的 Hadley Wickham 的观点可能更合适:分裂(Split)、应用(Apply)和组合(Combine)。 + +分组运算过程:Split —> Apply —> Combine + +- 分裂(Split):根据某些标准将数据分组; +- 应用(Apply):对每个组独立应用一个函数; +- 合并(Combine):把每个分组的计算结果合并起来。 + +官方介绍:[https://pandas.pydata.org/docs/user_guide/groupby.html](https://pandas.pydata.org/docs/user_guide/groupby.html) + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A84/01.png) + +## 【02x00】GroupBy 对象 + +常见的 GroupBy 对象:Series.groupby、DataFrame.groupby,基本语法如下: + +```python +Series.groupby(self, + by=None, + axis=0, + level=None, + as_index: bool = True, + sort: bool = True, + group_keys: bool = True, + squeeze: bool = False, + observed: bool = False) → ’groupby_generic.SeriesGroupBy’ +``` + +```python +DataFrame.groupby(self, + by=None, + axis=0, + level=None, + as_index: bool = True, + sort: bool = True, + group_keys: bool = True, + squeeze: bool = False, + observed: bool = False) → ’groupby_generic.DataFrameGroupBy’ +``` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.groupby.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.groupby.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html) + +常用参数解释如下: + +| 参数 | 描述 | +| ------ | ------ | +| by | 映射、函数、标签或标签列表,用于确定分组依据的分组。如果 by 是函数,则会在对象索引的每个值上调用它。
如果传递了 dict 或 Series,则将使用 Series 或 dict 的值来确定组(将 Series 的值首先对齐;请参见.align() 方法)。
如果传递了 ndarray,则按原样使用这些值来确定组。标签或标签列表可以按自身中的列传递给分组。 注意,元组被解释为(单个)键 | +| axis | 沿指定轴拆分,默认 `0`,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| level | 如果轴是 MultiIndex(层次结构),则按特定层级进行分组,默认 None | +| as_index | bool 类型,默认 True,对于聚合输出,返回以组标签为索引的对象。仅与 DataFrame 输入相关。
`as_index=False` 实际上是“SQL样式”分组输出 | +| sort | bool 类型,默认 True,对组键排序。关闭此选项可获得更好的性能。注:这不影响每组的观察顺序。Groupby 保留每个组中行的顺序 | +| group_keys | bool 类型,默认 True,调用 apply 方法时,是否将组键(keys)添加到索引( index)以标识块 | +| squeeze | bool 类型,默认 False,如果可能,减少返回类型的维度,否则返回一致的类型 | + +groupby() 进行分组,GroupBy 对象没有进行实际运算,只是包含分组的中间数据,示例如下: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randn(8), + 'data2': np.random.randn(8)} +>>> +>>> obj = pd.DataFrame(data) +>>> obj + key1 key2 data1 data2 +0 a one -0.804160 -0.868905 +1 b one -0.086990 0.325741 +2 a two 0.757992 0.541101 +3 b three -0.281435 0.097841 +4 a two 0.817757 -0.643699 +5 b two -0.462760 -0.321196 +6 a one -0.403699 0.602138 +7 a three 0.883940 -0.850526 +>>> +>>> obj.groupby('key1') + +>>> +>>> obj['data1'].groupby(obj['key1']) + +``` + +## 【03x00】GroupBy Split 数据分裂 + +### 【03x01】分组运算 + +前面通过 `groupby()` 方法获得了一个 GroupBy 对象,它实际上还没有进行任何计算,只是含有一些有关分组键 `obj['key1']` 的中间数据而已。换句话说,该对象已经有了接下来对各分组执行运算所需的一切信息。例如,我们可以调用 GroupBy 的 `mean()` 方法来计算分组平均值,`size()` 方法返回每个分组的元素个数: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randn(8), + 'data2': np.random.randn(8)} +>>> +>>> obj = pd.DataFrame(data) +>>> obj + key1 key2 data1 data2 +0 a one -0.544099 -0.614079 +1 b one 2.193712 0.101005 +2 a two -0.004683 0.882770 +3 b three 0.312858 1.732105 +4 a two 0.011089 0.089587 +5 b two 0.292165 1.327638 +6 a one -1.433291 -0.238971 +7 a three -0.004724 -2.117326 +>>> +>>> grouped1 = obj.groupby('key1') +>>> grouped2 = obj['data1'].groupby(obj['key1']) +>>> +>>> grouped1.mean() + data1 data2 +key1 +a -0.395142 -0.399604 +b 0.932912 1.053583 +>>> +>>> grouped2.mean() +key1 +a -0.395142 +b 0.932912 +Name: data1, dtype: float64 +>>> +>>> grouped1.size() +key1 +a 5 +b 3 +dtype: int64 +>>> +>>> grouped2.size() +key1 +a 5 +b 3 +Name: data1, dtype: int64 +``` + +### 【03x02】按类型按列分组 + +`groupby()` 方法 `axis` 参数默认是 0,通过设置也可以在其他任何轴上进行分组,也支持按照类型(dtype)进行分组: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randn(8), + 'data2': np.random.randn(8)} +>>> obj = pd.DataFrame(data) +>>> obj + key1 key2 data1 data2 +0 a one -0.607009 1.948301 +1 b one 0.150818 -0.025095 +2 a two -2.086024 0.358164 +3 b three 0.446061 1.708797 +4 a two 0.745457 -0.980948 +5 b two 0.981877 2.159327 +6 a one 0.804480 -0.499661 +7 a three 0.112884 0.004367 +>>> +>>> obj.dtypes +key1 object +key2 object +data1 float64 +data2 float64 +dtype: object +>>> +>>> obj.groupby(obj.dtypes, axis=1).size() +float64 2 +object 2 +dtype: int64 +>>> +>>> obj.groupby(obj.dtypes, axis=1).sum() + float64 object +0 1.341291 aone +1 0.125723 bone +2 -1.727860 atwo +3 2.154858 bthree +4 -0.235491 atwo +5 3.141203 btwo +6 0.304819 aone +7 0.117251 athree +``` + +### 【03x03】自定义分组 + +`groupby()` 方法中可以一次传入多个数组的列表,也可以自定义一组分组键。也可以通过一个字典、一个函数,或者按照索引层级进行分组。 + +传入多个数组的列表: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randn(8), + 'data2': np.random.randn(8)} +>>> obj = pd.DataFrame(data) +>>> obj + key1 key2 data1 data2 +0 a one -0.841652 0.688055 +1 b one 0.510042 -0.561171 +2 a two -0.418862 -0.145983 +3 b three -1.104698 0.563158 +4 a two 0.329527 -0.893108 +5 b two 0.753653 -0.342520 +6 a one -0.882527 -1.121329 +7 a three 1.726794 0.160244 +>>> +>>> means = obj['data1'].groupby([obj['key1'], obj['key2']]).mean() +>>> means +key1 key2 +a one -0.862090 + three 1.726794 + two -0.044667 +b one 0.510042 + three -1.104698 + two 0.753653 +Name: data1, dtype: float64 +>>> +>>> means.unstack() +key2 one three two +key1 +a -0.862090 1.726794 -0.044667 +b 0.510042 -1.104698 0.753653 +``` + +自定义分组键: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'], + 'key2' : ['one', 'two', 'one', 'two', 'one'], + 'data1' : np.random.randn(5), + 'data2' : np.random.randn(5)}) +>>> obj + key1 key2 data1 data2 +0 a one -0.024003 0.350480 +1 a two -0.767534 -0.100426 +2 b one -0.594983 -1.945580 +3 b two -0.374482 0.817592 +4 a one 0.755452 -0.137759 +>>> +>>> states = np.array(['Wuhan', 'Beijing', 'Beijing', 'Wuhan', 'Wuhan']) +>>> years = np.array([2005, 2005, 2006, 2005, 2006]) +>>> +>>> obj['data1'].groupby([states, years]).mean() +Beijing 2005 -0.767534 + 2006 -0.594983 +Wuhan 2005 -0.199242 + 2006 0.755452 +Name: data1, dtype: float64 +``` + +#### 【03x03x01】字典分组 + +通过字典进行分组: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.random.randint(1, 10, (5,5)), + columns=['a', 'b', 'c', 'd', 'e'], + index=['A', 'B', 'C', 'D', 'E']) +>>> obj + a b c d e +A 1 4 7 1 9 +B 8 2 4 7 8 +C 9 8 2 5 1 +D 2 4 2 8 3 +E 7 5 7 2 3 +>>> +>>> obj_dict = {'a':'Python', 'b':'Python', 'c':'Java', 'd':'C++', 'e':'Java'} +>>> obj.groupby(obj_dict, axis=1).size() +C++ 1 +Java 2 +Python 2 +dtype: int64 +>>> +>>> obj.groupby(obj_dict, axis=1).count() + C++ Java Python +A 1 2 2 +B 1 2 2 +C 1 2 2 +D 1 2 2 +E 1 2 2 +>>> +>>> obj.groupby(obj_dict, axis=1).sum() + C++ Java Python +A 1 16 5 +B 7 12 10 +C 5 3 17 +D 8 5 6 +E 2 10 12 +``` + +#### 【03x03x02】函数分组 + +通过函数进行分组: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.random.randint(1, 10, (5,5)), + columns=['a', 'b', 'c', 'd', 'e'], + index=['AA', 'BBB', 'CC', 'D', 'EE']) +>>> obj + a b c d e +AA 3 9 5 8 2 +BBB 1 4 2 2 6 +CC 9 2 4 7 6 +D 2 5 5 7 1 +EE 8 8 8 2 2 +>>> +>>> def group_key(idx): + """ + idx 为列索引或行索引 + """ + return len(idx) + +>>> obj.groupby(group_key).size() # 等价于 obj.groupby(len).size() +1 1 +2 3 +3 1 +dtype: int64 +``` + +#### 【03x03x03】索引层级分组 + +通过不同索引层级进行分组: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> columns = pd.MultiIndex.from_arrays([['Python', 'Java', 'Python', 'Java', 'Python'], + ['A', 'A', 'B', 'C', 'B']], names=['language', 'index']) +>>> obj = pd.DataFrame(np.random.randint(1, 10, (5, 5)), columns=columns) +>>> obj +language Python Java Python Java Python +index A A B C B +0 7 1 9 8 5 +1 4 5 4 5 6 +2 4 3 1 9 5 +3 6 6 3 8 1 +4 7 9 2 8 2 +>>> +>>> obj.groupby(level='language', axis=1).sum() +language Java Python +0 9 21 +1 10 14 +2 12 10 +3 14 10 +4 17 11 +>>> +>>> obj.groupby(level='index', axis=1).sum() +index A B C +0 8 14 8 +1 9 10 5 +2 7 6 9 +3 12 4 8 +4 16 4 8 +``` + +### 【03x04】分组迭代 + +GroupBy 对象支持迭代,对于单层分组,可以产生一组二元元组,由分组名和数据块组成: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randn(8), + 'data2': np.random.randn(8)} +>>> obj = pd.DataFrame(data) +>>> obj + key1 key2 data1 data2 +0 a one -1.088762 0.668504 +1 b one 0.275500 0.787844 +2 a two -0.108417 -0.491296 +3 b three 0.019524 -0.363390 +4 a two 0.453612 0.796999 +5 b two 1.982858 1.501877 +6 a one 1.101132 -1.928362 +7 a three 0.524775 -1.205842 +>>> +>>> for group_name, group_data in obj.groupby('key1'): + print(group_name) + print(group_data) + + +a + key1 key2 data1 data2 +0 a one -1.088762 0.668504 +2 a two -0.108417 -0.491296 +4 a two 0.453612 0.796999 +6 a one 1.101132 -1.928362 +7 a three 0.524775 -1.205842 +b + key1 key2 data1 data2 +1 b one 0.275500 0.787844 +3 b three 0.019524 -0.363390 +5 b two 1.982858 1.501877 +``` + +对于多层分组,元组的第一个元素将会是由键值组成的元组,第二个元素为数据块: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randn(8), + 'data2': np.random.randn(8)} +>>> obj = pd.DataFrame(data) +>>> obj + key1 key2 data1 data2 +0 a one -1.088762 0.668504 +1 b one 0.275500 0.787844 +2 a two -0.108417 -0.491296 +3 b three 0.019524 -0.363390 +4 a two 0.453612 0.796999 +5 b two 1.982858 1.501877 +6 a one 1.101132 -1.928362 +7 a three 0.524775 -1.205842 +>>> +>>> for group_name, group_data in obj.groupby(['key1', 'key2']): + print(group_name) + print(group_data) + + +('a', 'one') + key1 key2 data1 data2 +0 a one -1.088762 0.668504 +6 a one 1.101132 -1.928362 +('a', 'three') + key1 key2 data1 data2 +7 a three 0.524775 -1.205842 +('a', 'two') + key1 key2 data1 data2 +2 a two -0.108417 -0.491296 +4 a two 0.453612 0.796999 +('b', 'one') + key1 key2 data1 data2 +1 b one 0.2755 0.787844 +('b', 'three') + key1 key2 data1 data2 +3 b three 0.019524 -0.36339 +('b', 'two') + key1 key2 data1 data2 +5 b two 1.982858 1.501877 +``` + +### 【03x05】对象转换 + +GroupBy 对象支持转换成列表或字典: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randn(8), + 'data2': np.random.randn(8)} +>>> obj = pd.DataFrame(data) +>>> obj + key1 key2 data1 data2 +0 a one -0.607009 1.948301 +1 b one 0.150818 -0.025095 +2 a two -2.086024 0.358164 +3 b three 0.446061 1.708797 +4 a two 0.745457 -0.980948 +5 b two 0.981877 2.159327 +6 a one 0.804480 -0.499661 +7 a three 0.112884 0.004367 +>>> +>>> grouped = obj.groupby('key1') +>>> list(grouped1) +[('a', key1 key2 data1 data2 +0 a one -0.607009 1.948301 +2 a two -2.086024 0.358164 +4 a two 0.745457 -0.980948 +6 a one 0.804480 -0.499661 +7 a three 0.112884 0.004367), +('b', key1 key2 data1 data2 +1 b one 0.150818 -0.025095 +3 b three 0.446061 1.708797 +5 b two 0.981877 2.159327)] +>>> +>>> dict(list(grouped1)) +{'a': key1 key2 data1 data2 +0 a one -0.607009 1.948301 +2 a two -2.086024 0.358164 +4 a two 0.745457 -0.980948 +6 a one 0.804480 -0.499661 +7 a three 0.112884 0.004367, +'b': key1 key2 data1 data2 +1 b one 0.150818 -0.025095 +3 b three 0.446061 1.708797 +5 b two 0.981877 2.159327} +``` + +## 【04x00】GroupBy Apply 数据应用 + +聚合指的是任何能够从数组产生标量值的数据转换过程,常用于对分组后的数据进行计算 + +### 【04x01】聚合函数 + +之前的例子已经用过一些内置的聚合函数,比如 mean、count、min 以及 sum 等。常见的聚合运算如下表所示: + +官方文档:[https://pandas.pydata.org/docs/reference/groupby.html](https://pandas.pydata.org/docs/reference/groupby.html) + +| 方法 | 描述 | +| ------ | ------ | +| count | 非NA值的数量 | +| describe | 针对Series或各DataFrame列计算汇总统计 | +| min | 计算最小值 | +| max | 计算最大值 | +| argmin | 计算能够获取到最小值的索引位置(整数) | +| argmax | 计算能够获取到最大值的索引位置(整数) | +| idxmin | 计算能够获取到最小值的索引值 | +| idxmax | 计算能够获取到最大值的索引值 | +| quantile | 计算样本的分位数(0到1) | +| sum | 值的总和 | +| mean | 值的平均数 | +| median | 值的算术中位数(50%分位数) | +| mad | 根据平均值计算平均绝对离差 | +| var | 样本值的方差 | +| std | 样本值的标准差 | + +应用示例: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randint(1,10, 8), + 'data2': np.random.randint(1,10, 8)} +>>> obj = pd.DataFrame(obj) +>>> obj + key1 key2 data1 data2 +0 a one 9 7 +1 b one 5 9 +2 a two 2 4 +3 b three 3 4 +4 a two 5 1 +5 b two 5 9 +6 a one 1 8 +7 a three 2 4 +>>> +>>> obj.groupby('key1').sum() + data1 data2 +key1 +a 19 24 +b 13 22 +>>> +>>> obj.groupby('key1').max() + key2 data1 data2 +key1 +a two 9 8 +b two 5 9 +>>> +>>> obj.groupby('key1').min() + key2 data1 data2 +key1 +a one 1 1 +b one 3 4 +>>> +>>> obj.groupby('key1').mean() + data1 data2 +key1 +a 3.800000 4.800000 +b 4.333333 7.333333 +>>> +>>> obj.groupby('key1').size() +key1 +a 5 +b 3 +dtype: int64 +>>> +>>> obj.groupby('key1').count() + key2 data1 data2 +key1 +a 5 5 5 +b 3 3 3 +>>> +>>> obj.groupby('key1').describe() + data1 ... data2 + count mean std min 25% ... min 25% 50% 75% max +key1 ... +a 5.0 3.800000 3.271085 1.0 2.0 ... 1.0 4.0 4.0 7.0 8.0 +b 3.0 4.333333 1.154701 3.0 4.0 ... 4.0 6.5 9.0 9.0 9.0 + +[2 rows x 16 columns] +``` + +### 【04x02】自定义函数 + +如果自带的内置函数满足不了我们的要求,则可以自定义一个聚合函数,然后传入 `GroupBy.agg(func)` 或 `GroupBy.aggregate(func) ` 方法中即可。func 的参数为 groupby 索引对应的记录。 + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randint(1,10, 8), + 'data2': np.random.randint(1,10, 8)} +>>> obj = pd.DataFrame(obj) +>>> obj + key1 key2 data1 data2 +0 a one 9 7 +1 b one 5 9 +2 a two 2 4 +3 b three 3 4 +4 a two 5 1 +5 b two 5 9 +6 a one 1 8 +7 a three 2 4 +>>> +>>> def peak_range(df): + return df.max() - df.min() + +>>> +>>> obj.groupby('key1').agg(peak_range) + data1 data2 +key1 +a 8 7 +b 2 5 +>>> +>>> obj.groupby('key1').agg(lambda df : df.max() - df.min()) + data1 data2 +key1 +a 8 7 +b 2 5 +``` + +### 【04x03】对不同列作用不同函数 + +使用字典可以对不同列作用不同的聚合函数: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], + 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], + 'data1': np.random.randint(1,10, 8), + 'data2': np.random.randint(1,10, 8)} +>>> obj = pd.DataFrame(obj) +>>> obj + key1 key2 data1 data2 +0 a one 9 7 +1 b one 5 9 +2 a two 2 4 +3 b three 3 4 +4 a two 5 1 +5 b two 5 9 +6 a one 1 8 +7 a three 2 4 +>>> +>>> dict1 = {'data1':'mean', 'data2':'sum'} +>>> dict2 = {'data1':['mean','max'], 'data2':'sum'} +>>> +>>> obj.groupby('key1').agg(dict1) + data1 data2 +key1 +a 3.800000 24 +b 4.333333 22 +>>> +>>> obj.groupby('key1').agg(dict2) + data1 data2 + mean max sum +key1 +a 3.800000 9 24 +b 4.333333 5 22 +``` + +### 【04x04】GroupBy.apply() + +`apply()` 方法会将待处理的对象拆分成多个片段,然后对各片段调用传入的函数,最后尝试将各片段组合到一起。 + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'A':['bob','sos','bob','sos','bob','sos','bob','bob'], + 'B':['one','one','two','three','two','two','one','three'], + 'C':[3,1,4,1,5,9,2,6], + 'D':[1,2,3,4,5,6,7,8]}) +>>> obj + A B C D +0 bob one 3 1 +1 sos one 1 2 +2 bob two 4 3 +3 sos three 1 4 +4 bob two 5 5 +5 sos two 9 6 +6 bob one 2 7 +7 bob three 6 8 +>>> +>>> grouped = obj.groupby('A') +>>> for name, group in grouped: + print(name) + print(group) + + +bob + A B C D +0 bob one 3 1 +2 bob two 4 3 +4 bob two 5 5 +6 bob one 2 7 +7 bob three 6 8 +sos + A B C D +1 sos one 1 2 +3 sos three 1 4 +5 sos two 9 6 +>>> +>>> grouped.apply(lambda x:x.describe()) # 对 bob 和 sos 两组数据使用 describe 方法 + C D +A +bob count 5.000000 5.000000 + mean 4.000000 4.800000 + std 1.581139 2.863564 + min 2.000000 1.000000 + 25% 3.000000 3.000000 + 50% 4.000000 5.000000 + 75% 5.000000 7.000000 + max 6.000000 8.000000 +sos count 3.000000 3.000000 + mean 3.666667 4.000000 + std 4.618802 2.000000 + min 1.000000 2.000000 + 25% 1.000000 3.000000 + 50% 1.000000 4.000000 + 75% 5.000000 5.000000 + max 9.000000 6.000000 +>>> +>>> grouped.apply(lambda x:x.min()) # # 对 bob 和 sos 两组数据使用 min 方法 + A B C D +A +bob bob one 2 1 +sos sos one 1 2 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106804881 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A85-Pandas-07.md b/source/_posts/A85-Pandas-07.md new file mode 100644 index 0000000000000000000000000000000000000000..aaba8517fd5e18aea3370fda64d49244ec9ca1f5 --- /dev/null +++ b/source/_posts/A85-Pandas-07.md @@ -0,0 +1,928 @@ +--- +title: Python 数据分析三剑客之 Pandas(七):合并数据集 +tags: + - Pandas + - 合并数据集 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(七):数据集的合并。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106830112 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】concat + +`pandas.concat` 可以沿着指定轴将多个对象堆叠到一起。 + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.concat.html](https://pandas.pydata.org/docs/reference/api/pandas.concat.html) + +基本语法: + +```python +pandas.concat(objs: Union[Iterable[‘DataFrame’], Mapping[Optional[Hashable], ‘DataFrame’]], + axis='0', + join: str = "'outer'", + ignore_index: bool = 'False', + keys='None', + levels='None', + names='None', + verify_integrity: bool = 'False', + sort: bool = 'False', + copy: bool = 'True') → ’DataFrame’ +``` + +```python +pandas.concat(objs: Union[Iterable[FrameOrSeriesUnion], Mapping[Optional[Hashable], FrameOrSeriesUnion]], + axis='0', + join: str = "'outer'", + ignore_index: bool = 'False', + keys='None', + levels='None', + names='None', + verify_integrity: bool = 'False', + sort: bool = 'False', + copy: bool = 'True') → FrameOrSeriesUnion +``` + +常用参数描述: + +| 参数 | 描述 | +| ------ | ------ | +| objs | Series 或 DataFrame 对象的序列或映射,要合并的对象 | +| axis | 沿指定轴合并,`0` or `‘index’`,`1` or `‘columns’`,只有在 DataFrame 中才有 `1` or `'columns’` | +| join | 如何处理其他轴(或多个轴)上的索引,可取值:`‘inner’`,`‘outer’`(默认值)
`‘outer’`:当 axis = 0 时,列名相同的列会合并,其余列都保留(并集),空值填充;
`‘inner’`:当 axis = 0 时,列名相同的列会合并,其余列都舍弃(交集) | +| ignore_index | bool 类型,连接后的值是否使用原索引值,如果为 True,则索引将会是 0, 1, ..., n-1 | +| keys | 序列形式,默认 None,传递 keys 后,会构造一个层次索引,即 MultiIndex 对象,keys 为最外层索引 | +| levels | 用于构造 MultiIndex 的特定级别(唯一值)。未指定则将从键中推断出来 | +| names | 列表类型,为索引添加标签 | +| verify_integrity | bool 类型,是否检查合并后的索引有无重复项,设置为 `True` 若有重复项则会报错 | +| sort | 当 `join='outer'` 时对列索引进行排序。当 `join='inner'` 时此操作无效 | + +合并两个 Series 对象: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series(['a', 'b']) +>>> obj2 = pd.Series(['c', 'd']) +>>> pd.concat([obj1, obj2]) +0 a +1 b +0 c +1 d +dtype: object +``` + +设置 `ignore_index=True`,放弃原有的索引值: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series(['a', 'b']) +>>> obj2 = pd.Series(['c', 'd']) +>>> pd.concat([obj1, obj2], ignore_index=True) +0 a +1 b +2 c +3 d +dtype: object +``` + +设置 `keys` 参数,添加最外层的索引: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series(['a', 'b']) +>>> obj2 = pd.Series(['c', 'd']) +>>> pd.concat([obj1, obj2], keys=['s1', 's2']) +s1 0 a + 1 b +s2 0 c + 1 d +dtype: object +``` + +设置 `names` 参数,为索引添加标签: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series(['a', 'b']) +>>> obj2 = pd.Series(['c', 'd']) +>>> pd.concat([obj1, obj2], keys=['s1', 's2'], names=['Series name', 'Row ID']) +Series name Row ID +s1 0 a + 1 b +s2 0 c + 1 d +dtype: object +``` + +合并 `DataFrame` 对象: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number']) +>>> obj2 = pd.DataFrame([['c', 3], ['d', 4]], columns=['letter', 'number']) +>>> obj1 + letter number +0 a 1 +1 b 2 +>>> +>>> obj2 + letter number +0 c 3 +1 d 4 +>>> +>>> pd.concat([obj1, obj2]) + letter number +0 a 1 +1 b 2 +0 c 3 +1 d 4 +``` + +合并 `DataFrame` 对象,不存在的值将会被 NaN 填充: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number']) +>>> obj2 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']], columns=['letter', 'number', 'animal']) +>>> obj1 + letter number +0 a 1 +1 b 2 +>>> +>>> obj2 + letter number animal +0 c 3 cat +1 d 4 dog +>>> +>>> pd.concat([obj1, obj2]) + letter number animal +0 a 1 NaN +1 b 2 NaN +0 c 3 cat +1 d 4 dog +``` + +合并 `DataFrame` 对象,设置 `join="inner"` 不存在的列将会舍弃: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number']) +>>> obj2 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']], columns=['letter', 'number', 'animal']) +>>> obj1 + letter number +0 a 1 +1 b 2 +>>> +>>> obj2 + letter number animal +0 c 3 cat +1 d 4 dog +>>> +>>> pd.concat([obj1, obj2], join="inner") + letter number +0 a 1 +1 b 2 +0 c 3 +1 d 4 +``` + +合并 `DataFrame` 对象,设置 `axis=1` 沿 y 轴合并(增加列): + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number']) +>>> obj2 = pd.DataFrame([['bird', 'polly'], ['monkey', 'george']], columns=['animal', 'name']) +>>> obj1 + letter number +0 a 1 +1 b 2 +>>> +>>> obj2 + animal name +0 bird polly +1 monkey george +>>> +>>> pd.concat([obj1, obj2], axis=1) + letter number animal name +0 a 1 bird polly +1 b 2 monkey george +``` + +设置 `verify_integrity=True` ,检查新的索引是否有重复项,有重复项会报错: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame([1], index=['a']) +>>> obj2 = pd.DataFrame([2], index=['a']) +>>> obj1 + 0 +a 1 +>>> +>>> obj2 + 0 +a 2 +>>> +>>> pd.concat([obj1, obj2], verify_integrity=True) +Traceback (most recent call last): + ... +ValueError: Indexes have overlapping values: ['a'] +``` + +设置 `sort=True`,会对列索引进行排序输出: + +```python +>>> obj1 = pd.DataFrame([['a', 3], ['d', 2]], columns=['letter', 'number']) +>>> obj2 = pd.DataFrame([['c', 1, 'cat'], ['b', 4, 'dog']], columns=['letter', 'number', 'animal']) +>>> obj1 + letter number +0 a 3 +1 d 2 +>>> +>>> obj2 + letter number animal +0 c 1 cat +1 b 4 dog +>>> +>>> pd.concat([obj1, obj2], sort=True) + animal letter number +0 NaN a 3 +1 NaN d 2 +0 cat c 1 +1 dog b 4 +``` + +## 【02x00】append + +Append 方法事实上是在一个 Series / DataFrame 对象后最追加另一个 Series / DataFrame 对象并返回一个新对象,不改变原对象的值。 + +基本语法: + +- `Series.append(self, to_append, ignore_index=False, verify_integrity=False)` + +- `DataFrame.append(self, other, ignore_index=False, verify_integrity=False, sort=False)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.append.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.append.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.append.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.append.html) + +参数描述: + +| 参数 | 描述 | +| ------ | ------ | +| to_append / other | 要追加的数据 | +| ignore_index | bool 类型,连接后的值是否使用原索引值,如果为 True,则索引将会是 0, 1, ..., n-1 | +| verify_integrity | bool 类型,是否检查合并后的索引有无重复项,设置为 `True` 若有重复项则会报错 | +| sort | bool 类型,是否对列索引(columns)进行排序,默认 False | + +合并 Series 对象: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series([1, 2, 3]) +>>> obj2 = pd.Series([4, 5, 6]) +>>> obj3 = pd.Series([4, 5, 6], index=[3, 4, 5]) +>>> obj1 +0 1 +1 2 +2 3 +dtype: int64 +>>> +>>> obj2 +0 4 +1 5 +2 6 +dtype: int64 +>>> +>>> obj3 +3 4 +4 5 +5 6 +dtype: int64 +>>> +>>> obj1.append(obj2) +0 1 +1 2 +2 3 +0 4 +1 5 +2 6 +dtype: int64 +>>> +>>> obj1.append(obj3) +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +dtype: int64 +>>> +>>> obj1.append(obj2, ignore_index=True) +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +dtype: int64 +>>> +>>> obj1.append(obj2, verify_integrity=True) +Traceback (most recent call last): +... +ValueError: Indexes have overlapping values: Int64Index([0, 1, 2], dtype='int64') +``` + +合并 DataFrame 对象: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB')) +>>> obj2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB')) +>>> +>>> obj1 + A B +0 1 2 +1 3 4 +>>> +>>> obj2 + A B +0 5 6 +1 7 8 +>>> +>>> obj1.append(obj2) + A B +0 1 2 +1 3 4 +0 5 6 +1 7 8 +>>> +>>> obj1.append(obj2, ignore_index=True) + A B +0 1 2 +1 3 4 +2 5 6 +3 7 8 +``` + +以下虽然不是生成 DataFrames 的推荐方法,但演示了从多个数据源生成 DataFrames 的两种方法: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame(columns=['A']) +>>> for i in range(5): + obj = obj.append({'A': i}, ignore_index=True) + + +>>> obj + A +0 0 +1 1 +2 2 +3 3 +4 4 +``` + +```python +>>> import pandas as pd +>>> pd.concat([pd.DataFrame([i], columns=['A']) for i in range(5)], ignore_index=True) + A +0 0 +1 1 +2 2 +3 3 +4 4 +``` + +## 【03x00】merge + +将不同的数据源进行合并是数据科学中常见的操作,这既包括将两个不同的数据集非常简单地拼接在一起,也包括用数据库那样的连接(join)与合并(merge)操作处理有重叠字段的数据集。Series 与DataFrame 都具备这类操作,Pandas 的函数与方法让数据合并变得快速简单。 + +数据集的合并(merge)或连接(join)运算是通过一个或多个键将行连接起来的。这些运算是关系型数据库(基于SQL)的核心。Pandas 的 merge 函数是对数据应用这些算法的主要切入点。 + + **`pandas.merge` 可根据一个或多个连接键将不同 DataFrame 中的行连接起来。** + +基本语法: + +```python +pandas.merge(left, + right, + how: str = 'inner', + on=None, + left_on=None, + right_on=None, + left_index: bool = False, + right_index: bool = False, + sort: bool = False, + suffixes='_x', '_y', + copy: bool = True, + indicator: bool = False, + validate=None) → ’DataFrame’ +``` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.merge.html](https://pandas.pydata.org/docs/reference/api/pandas.merge.html) + +常见参数描述: + +| 参数 | 描述 | +| ------ | ------ | +| left | 参与合并的左侧 DataFrame 对象 | +| right | 参与合并的右侧 DataFrame 对象 | +| how | 合并方式,默认 `'inner'`
`'inner'`:内连接,即使用两个对象中**都有**的键(交集);
`'outer'`:外连接,即使用两个对象中**所有**的键(并集);
`'left'`:左连接,即使用**左**对象中所有的键;
`'right'`:右连接,即使用**右**对象中所有的键; | +| on | 用于连接的列名。必须存在于左右两个 Dataframe对象中
如果未指定,且其他连接键也未指定,则以 left 和 right 列名的交集作为连接键 | +| left_on | 左侧 DataFrame 对象中用作连接键的列 | +| right_on | 右侧 DataFrame 对象中用作连接键的列 | +| left_index | bool 类型,是否使用左侧 DataFrame 对象中的索引(index)作为连接键,默认 False | +| right_index | bool 类型,是否使用右侧 DataFrame 对象中的索引(index)作为连接键,默认 False | +| sort | bool 类型,是否在结果中按顺序对连接键排序,默认 False。
如果为 False,则连接键的顺序取决于联接类型(how 关键字) | +| suffixes | 字符串值元组,用于追加到重叠列名的末尾,默认为 `('_x', '_y')`。
例如,如果左右两个 DataFrame 对象都有 `data` 列时,则结果中就会出现 `data_x` 和 `data_y` | + +### 【03x01】一对一连接 + +**一对一连接是指两个 DataFrame 对象的列的值没有重复值。** + +如果不指定任何参数,调用 `merge` 方法,`merge` 就会将重叠的列的列名当做键来合并。 + +在下面的示例中,两个 DataFrame 对象都有一个列名为 `key` 的列,未指定按照哪一列来合并,`merge` 就会默认按照 `key` 来合并: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame({'key': ['b', 'a', 'c'], 'data1': range(3)}) +>>> obj2 = pd.DataFrame({'key': ['a', 'c', 'b'], 'data2': range(3)}) +>>> obj1 + key data1 +0 b 0 +1 a 1 +2 c 2 +>>> +>>> obj2 + key data2 +0 a 0 +1 c 1 +2 b 2 +>>> +>>> pd.merge(obj1, obj2) + key data1 data2 +0 b 0 2 +1 a 1 0 +2 c 2 1 +``` + +### 【03x02】多对一连接 + +**多对一连接是指两个 DataFrame 对象中,有一个的列的值有重复值。**通过多对一连接获得的结果,DataFrame 将会保留重复值。 + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)}) +>>> obj2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)}) +>>> +>>> obj1 + key data1 +0 b 0 +1 b 1 +2 a 2 +3 c 3 +4 a 4 +5 a 5 +6 b 6 +>>> +>>> obj2 + key data2 +0 a 0 +1 b 1 +2 d 2 +>>> +>>> pd.merge(obj1, obj2) + key data1 data2 +0 b 0 1 +1 b 1 1 +2 b 6 1 +3 a 2 0 +4 a 4 0 +5 a 5 0 +``` + +### 【03x03】多对多连接 + +**多对多连接是指两个 DataFrame 对象中的列的值都有重复值。** + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame({'key': ['a', 'b', 'b', 'c'], 'data1': range(4)}) +>>> obj2 = pd.DataFrame({'key': ['a', 'a', 'b', 'b', 'c', 'c'], 'data2': range(6)}) +>>> obj1 + key data1 +0 a 0 +1 b 1 +2 b 2 +3 c 3 +>>> +>>> obj2 + key data2 +0 a 0 +1 a 1 +2 b 2 +3 b 3 +4 c 4 +5 c 5 +>>> +>>> pd.merge(obj1, obj2) + key data1 data2 +0 a 0 0 +1 a 0 1 +2 b 1 2 +3 b 1 3 +4 b 2 2 +5 b 2 3 +6 c 3 4 +7 c 3 5 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106830112 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +### 【03x04】参数 on / left_on / right_on + +参数 `on` 用于指定按照某一列来进行合并,若不指定该参数,则会默认按照重叠的列的列名当做键来合并: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame({'key': ['b', 'a', 'c'], 'data1': range(3)}) +>>> obj2 = pd.DataFrame({'key': ['a', 'c', 'b'], 'data2': range(3)}) +>>> obj1 + key data1 +0 b 0 +1 a 1 +2 c 2 +>>> +>>> obj2 + key data2 +0 a 0 +1 c 1 +2 b 2 +>>> +>>> pd.merge(obj1, obj2, on='key') + key data1 data2 +0 b 0 2 +1 a 1 0 +2 c 2 1 +``` + +如果要根据多个键进行合并,传入一个由列名组成的列表即可: + +```python +>>> import pandas as pd +>>> left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], + 'key2': ['one', 'two', 'one'], + 'lval': [1, 2, 3]}) +>>> right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], + 'key2': ['one', 'one', 'one', 'two'], + 'rval': [4, 5, 6, 7]}) +>>> left + key1 key2 lval +0 foo one 1 +1 foo two 2 +2 bar one 3 +>>> +>>> right + key1 key2 rval +0 foo one 4 +1 foo one 5 +2 bar one 6 +3 bar two 7 +>>> +>>> pd.merge(left, right, on=['key1', 'key2']) + key1 key2 lval rval +0 foo one 1 4 +1 foo one 1 5 +2 bar one 3 6 +``` + + +如果两个对象的列名不同,就可以使用 `left_on`、`right_on` 参数分别进行指定: + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)}) +>>> obj2 = pd.DataFrame({'rkey': ['a', 'b', 'd'], 'data2': range(3)}) +>>> obj1 + lkey data1 +0 b 0 +1 b 1 +2 a 2 +3 c 3 +4 a 4 +5 a 5 +6 b 6 +>>> +>>> obj2 + rkey data2 +0 a 0 +1 b 1 +2 d 2 +>>> +>>> pd.merge(obj1, obj2, left_on='lkey', right_on='rkey') + lkey data1 rkey data2 +0 b 0 b 1 +1 b 1 b 1 +2 b 6 b 1 +3 a 2 a 0 +4 a 4 a 0 +5 a 5 a 0 +``` + +### 【03x05】参数 how + +在前面的示例中,结果里面 c 和 d 以及与之相关的数据消失了。默认情况下,`merge` 做的是内连接(`'inner'`),结果中的键是交集。其他方式还有:`'left'`、`'right'`、`'outer'`,含义如下: + +- `'inner'`:内连接,即使用两个对象中**都有**的键(交集); +- `'outer'`:外连接,即使用两个对象中**所有**的键(并集); +- `'left'`:左连接,即使用**左**对象中所有的键; +- `'right'`:右连接,即使用**右**对象中所有的键; + +```python +>>> import pandas as pd +>>> obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)}) +>>> obj2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)}) +>>> obj1 + key data1 +0 b 0 +1 b 1 +2 a 2 +3 c 3 +4 a 4 +5 a 5 +6 b 6 +>>> +>>> obj2 + key data2 +0 a 0 +1 b 1 +2 d 2 +>>> +>>> pd.merge(obj1, obj2, on='key', how='inner') + key data1 data2 +0 b 0 1 +1 b 1 1 +2 b 6 1 +3 a 2 0 +4 a 4 0 +5 a 5 0 +>>> +>>> pd.merge(obj1, obj2, on='key', how='outer') + key data1 data2 +0 b 0.0 1.0 +1 b 1.0 1.0 +2 b 6.0 1.0 +3 a 2.0 0.0 +4 a 4.0 0.0 +5 a 5.0 0.0 +6 c 3.0 NaN +7 d NaN 2.0 +>>> +>>> pd.merge(obj1, obj2, on='key', how='left') + key data1 data2 +0 b 0 1.0 +1 b 1 1.0 +2 a 2 0.0 +3 c 3 NaN +4 a 4 0.0 +5 a 5 0.0 +6 b 6 1.0 +>>> +>>> pd.merge(obj1, obj2, on='key', how='right') + key data1 data2 +0 b 0.0 1 +1 b 1.0 1 +2 b 6.0 1 +3 a 2.0 0 +4 a 4.0 0 +5 a 5.0 0 +6 d NaN 2 +``` + +### 【03x06】参数 suffixes + +`suffixes` 参数用于指定附加到左右两个 DataFrame 对象的重叠列名上的字符串: + +在以下示例中,选择按照 `key1` 进行合并,而两个 DataFrame 对象都包含 `key2` 列,如果未指定 `suffixes` 参数,则默认会为两个对象的 `key2` 加上 `_x` 和 `_y`,以便区分它们,如果指定了 `suffixes` 参数,就会按照添加指定的后缀: + + +```python +>>> import pandas as pd +>>> left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], + 'key2': ['one', 'two', 'one'], + 'lval': [1, 2, 3]}) +>>> right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], + 'key2': ['one', 'one', 'one', 'two'], + 'rval': [4, 5, 6, 7]}) +>>> left + key1 key2 lval +0 foo one 1 +1 foo two 2 +2 bar one 3 +>>> +>>> right + key1 key2 rval +0 foo one 4 +1 foo one 5 +2 bar one 6 +3 bar two 7 +>>> +>>> pd.merge(left, right, on='key1') + key1 key2_x lval key2_y rval +0 foo one 1 one 4 +1 foo one 1 one 5 +2 foo two 2 one 4 +3 foo two 2 one 5 +4 bar one 3 one 6 +5 bar one 3 two 7 +>>> +>>> pd.merge(left, right, on='key1', suffixes=('_left', '_right')) + key1 key2_left lval key2_right rval +0 foo one 1 one 4 +1 foo one 1 one 5 +2 foo two 2 one 4 +3 foo two 2 one 5 +4 bar one 3 one 6 +5 bar one 3 two 7 +``` + +### 【03x07】参数 left_index / right_index + +有时候,DataFrame 中的连接键位于其索引中。在这种情况下,可以使用 `left_index=True` 或`right_index=True`(或两个都传)以说明索引应该被用作连接键。这种方法称为按索引连接,在 Pandas 中还有个 `join` 方法可以实现这个功能。 + +在以下示例中,按照 left 的 key 列进行连接,而 right 对象的连接键位于其索引中,因此要指定 `right_index=True`: + +```python +>>> import pandas as pd +>>> left = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], 'value': range(6)}) +>>> right = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b']) +>>> left + key value +0 a 0 +1 b 1 +2 a 2 +3 a 3 +4 b 4 +5 c 5 +>>> +>>> right + group_val +a 3.5 +b 7.0 +>>> +>>> pd.merge(left, right, left_on='key', right_index=True) + key value group_val +0 a 0 3.5 +2 a 2 3.5 +3 a 3 3.5 +1 b 1 7.0 +4 b 4 7.0 +``` + +## 【04x00】join + +join 方法只适用于 DataFrame 对象,Series 对象没有该方法,该方法用于连接另一个 DataFrame 对象的列(columns)。 + +基本语法:`DataFrame.join(self, other, on=None, how='left', lsuffix='', rsuffix='', sort=False) → ’DataFrame’` + +参数描述: + +| 参数 | 描述 | +| ------ | ------ | +| other | 另一个 DataFrame、Series 或 DataFrame 列表对象 | +| on | 列名称,或者列名称组成的列表、元组,连接的列 | +| how | 合并方式,默认 `'left'`
`'inner'`:内连接,即使用两个对象中**都有**的键(交集);
`'outer'`:外连接,即使用两个对象中**所有**的键(并集);
`'left'`:左连接,即使用**左**对象中所有的键;
`'right'`:右连接,即使用**右**对象中所有的键; | +| lsuffix | 当两个对象有相同的列名时,合并后左边数据列名的后缀 | +| rsuffix | 当两个对象有相同的列名时,合并后右边数据列名的后缀 | +| sort | bool 类型,是否在结果中按顺序对连接键排序,默认 False。
如果为 False,则连接键的顺序取决于联接类型(how 关键字) | + +使用 `lsuffix` 和 `rsuffix` 参数: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'], + 'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']}) +>>> other = pd.DataFrame({'key': ['K0', 'K1', 'K2'], + 'B': ['B0', 'B1', 'B2']}) +>>> obj + key A +0 K0 A0 +1 K1 A1 +2 K2 A2 +3 K3 A3 +4 K4 A4 +5 K5 A5 +>>> +>>> other + key B +0 K0 B0 +1 K1 B1 +2 K2 B2 +>>> +>>> obj.join(other, lsuffix='_1', rsuffix='_2') + key_1 A key_2 B +0 K0 A0 K0 B0 +1 K1 A1 K1 B1 +2 K2 A2 K2 B2 +3 K3 A3 NaN NaN +4 K4 A4 NaN NaN +5 K5 A5 NaN NaN +``` + +如果右表的索引是左表的某一列的值,这时可以将右表的索引和左表的列对齐合并这样的灵活方式进行合并: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'],'key': ['K0', 'K1', 'K0', 'K1']}) +>>> other = pd.DataFrame({'C': ['C0', 'C1'],'D': ['D0', 'D1']},index=['K0', 'K1']) +>>> obj + A B key +0 A0 B0 K0 +1 A1 B1 K1 +2 A2 B2 K0 +3 A3 B3 K1 +>>> +>>> other + C D +K0 C0 D0 +K1 C1 D1 +>>> +>>> obj.join(other, on='key') + A B key C D +0 A0 B0 K0 C0 D0 +1 A1 B1 K1 C1 D1 +2 A2 B2 K0 C0 D0 +3 A3 B3 K1 C1 D1 +``` + +## 【05x00】四种方法的区别 + +- `concat`:可用于两个或多个 Series 或 DataFrame 对象间,通过 `axis` 参数指定按照行方向(增加行)或列方向(增加列)进合并操作,默认行合并(增加行),取并集; + +- `append`:在一个 Series 或 DataFrame 对象后最追加另一个 Series 或 DataFrame 对象并返回一个新对象,不改变原对象的值。只能按行合并(增加行)。 + +- `merge`:只能对两个 DataFrame 对象进行合并,一般按照列方向(增加列)进行合并操作,按照行方向合并一般用 join 方法代替,默认列合并(增加列),取交集; + +- `join`:只能对两个 DataFrame 对象进行合并,按照列方向(增加列)进行合并操作,默认左连接。 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106830112 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A86-Pandas-08.md b/source/_posts/A86-Pandas-08.md new file mode 100644 index 0000000000000000000000000000000000000000..0707b54f2b28555e963ec371efe72aeb46d15659 --- /dev/null +++ b/source/_posts/A86-Pandas-08.md @@ -0,0 +1,969 @@ +--- +title: Python 数据分析三剑客之 Pandas(八):数据重塑/重复数据处理/数据替换 +tags: + - Pandas + - 数据重塑 + - 数据替换 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106900748 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】数据重塑 + +有许多用于重新排列表格型数据的基础运算。这些函数也称作重塑(reshape)或轴向旋转(pivot)运算。重塑层次化索引主要有以下两个方法: + +- `stack`:将数据的列转换成行; + +- `unstack`:将数据的行转换成列。 + +### 【01x01】stack + +`stack` 方法用于将数据的列转换成为行; + +基本语法:`DataFrame.stack(self, level=-1, dropna=True)` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.stack.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.stack.html) + +| 参数 | 描述 | +| ------ | ------ | +| level | 从列转换到行,指定不同层级的列索引或列标签、由列索引或列标签组成的数组,默认-1 | +| dropna | bool 类型,是否删除重塑后数据中所有值为 NaN 的行,默认 True | + +单层列(Single level columns): + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame([[0, 1], [2, 3]], index=['cat', 'dog'], columns=['weight', 'height']) +>>> obj + weight height +cat 0 1 +dog 2 3 +>>> +>>> obj.stack() +cat weight 0 + height 1 +dog weight 2 + height 3 +dtype: int64 +``` + +多层列(Multi level columns): + +```python +>>> import pandas as pd +>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('weight', 'pounds')]) +>>> obj = pd.DataFrame([[1, 2], [2, 4]], index=['cat', 'dog'], columns=multicol) +>>> obj + weight + kg pounds +cat 1 2 +dog 2 4 +>>> +>>> obj.stack() + weight +cat kg 1 + pounds 2 +dog kg 2 + pounds 4 +``` + +缺失值填充: + +```python +>>> import pandas as pd +>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')]) +>>> obj = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['cat', 'dog'], columns=multicol) +>>> obj + weight height + kg m +cat 1.0 2.0 +dog 3.0 4.0 +>>> +>>> obj.stack() + height weight +cat kg NaN 1.0 + m 2.0 NaN +dog kg NaN 3.0 + m 4.0 NaN +``` + +通过 `level` 参数指定不同层级的轴进行重塑: + +```python +>>> import pandas as pd +>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')]) +>>> obj = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['cat', 'dog'], columns=multicol) +>>> obj + weight height + kg m +cat 1.0 2.0 +dog 3.0 4.0 +>>> +>>> obj.stack(level=0) + kg m +cat height NaN 2.0 + weight 1.0 NaN +dog height NaN 4.0 + weight 3.0 NaN +>>> +>>> obj.stack(level=1) + height weight +cat kg NaN 1.0 + m 2.0 NaN +dog kg NaN 3.0 + m 4.0 NaN +>>> +>>> obj.stack(level=[0, 1]) +cat height m 2.0 + weight kg 1.0 +dog height m 4.0 + weight kg 3.0 +dtype: float64 +``` + +对于重塑后的数据,若有一行的值均为 NaN,则默认会被删除,可以设置 `dropna=False` 来保留缺失值: + +```python +>>> import pandas as pd +>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')]) +>>> obj = pd.DataFrame([[None, 1.0], [2.0, 3.0]], index=['cat', 'dog'], columns=multicol) +>>> obj + weight height + kg m +cat NaN 1.0 +dog 2.0 3.0 +>>> +>>> obj.stack(dropna=False) + height weight +cat kg NaN NaN + m 1.0 NaN +dog kg NaN 2.0 + m 3.0 NaN +>>> +>>> obj.stack(dropna=True) + height weight +cat m 1.0 NaN +dog kg NaN 2.0 + m 3.0 NaN +``` + +### 【01x02】unstack + +`unstack`:将数据的行转换成列。 + +基本语法: + +- `Series.unstack(self, level=-1, fill_value=None)` + +- `DataFrame.unstack(self, level=-1, fill_value=None)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.unstack.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.unstack.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.unstack.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.unstack.html) + +| 参数 | 描述 | +| ------ | ------ | +| level | 从行转换到列,指定不同层级的行索引,默认-1 | +| fill_value | 用于替换 NaN 的值 | + +在 Series 对象中的应用: + +```python +>>> import pandas as pd +>>> obj = pd.Series([1, 2, 3, 4], index=pd.MultiIndex.from_product([['one', 'two'], ['a', 'b']])) +>>> obj +one a 1 + b 2 +two a 3 + b 4 +dtype: int64 +>>> +>>> obj.unstack() + a b +one 1 2 +two 3 4 +>>> +>>> obj.unstack(level=0) + one two +a 1 3 +b 2 4 +``` + +和 `stack` 方法类似,如果值不存在将会引入缺失值(NaN): + +```python +>>> import pandas as pd +>>> obj1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) +>>> obj2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) +>>> obj3 = pd.concat([obj1, obj2], keys=['one', 'two']) +>>> obj3 +one a 0 + b 1 + c 2 + d 3 +two c 4 + d 5 + e 6 +dtype: int64 +>>> +>>> obj3.unstack() + a b c d e +one 0.0 1.0 2.0 3.0 NaN +two NaN NaN 4.0 5.0 6.0 +``` + +在 DataFrame 对象中的应用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame(np.arange(6).reshape((2, 3)), + index=pd.Index(['Ohio','Colorado'], name='state'), + columns=pd.Index(['one', 'two', 'three'], + name='number')) +>>> obj +number one two three +state +Ohio 0 1 2 +Colorado 3 4 5 +>>> +>>> obj2 = obj.stack() +>>> obj2 +state number +Ohio one 0 + two 1 + three 2 +Colorado one 3 + two 4 + three 5 +dtype: int32 +>>> +>>> obj3 = pd.DataFrame({'left': obj2, 'right': obj2 + 5}, + columns=pd.Index(['left', 'right'], name='side')) +>>> obj3 +side left right +state number +Ohio one 0 5 + two 1 6 + three 2 7 +Colorado one 3 8 + two 4 9 + three 5 10 +>>> +>>> obj3.unstack('state') +side left right +state Ohio Colorado Ohio Colorado +number +one 0 3 5 8 +two 1 4 6 9 +three 2 5 7 10 +>>> +>>> obj3.unstack('state').stack('side') +state Colorado Ohio +number side +one left 3 0 + right 8 5 +two left 4 1 + right 9 6 +three left 5 2 + right 10 7 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106900748 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【02x00】重复数据处理 + +- `duplicated`:判断是否为重复值; + +- `drop_duplicates`:删除重复值。 + +### 【02x01】duplicated + +`duplicated` 方法可以判断值是否为重复数据。 + +基本语法: + +- `Series.duplicated(self, keep='first')` + +- `DataFrame.duplicated(self, subset: Union[Hashable, Sequence[Hashable], NoneType] = None, keep: Union[str, bool] = 'first') → ’Series’` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.duplicated.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.duplicated.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.duplicated.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.duplicated.html) + +| 参数 | 描述 | +| ------ | ------ | +| keep | 标记重复项的方法,默认 `'first'`
`'first'`:将非重复项和第一个重复项标记为 False,其他重复项标记为 True
`'last'`:将非重复项和最后一个重复项标记为 False,其他重复项标记为 True
`False`:将所有重复项标记为 True,非重复项标记为 False | +| subset | 列标签或标签序列,在 DataFrame 对象中才有此参数,
用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列 | + +默认情况下,对于每组重复的值,第一个出现的重复值标记为 False,其他重复项标记为 True,非重复项标记为 False,相当于 `keep='first'`: + +```python +>>> import pandas as pd +>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama']) +>>> obj +0 lama +1 cow +2 lama +3 beetle +4 lama +dtype: object +>>> +>>> obj.duplicated() +0 False +1 False +2 True +3 False +4 True +dtype: bool +>>> +>>> obj.duplicated(keep='first') +0 False +1 False +2 True +3 False +4 True +dtype: bool +``` + +设置 `keep='last'`,将每组非重复项和最后一次出现的重复项标记为 False,其他重复项标记为 True,设置 `keep=False`,则所有重复项均为 True,其他值为 False: + +```python +>>> import pandas as pd +>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama']) +>>> obj +0 lama +1 cow +2 lama +3 beetle +4 lama +dtype: object +>>> +>>> obj.duplicated(keep='last') +0 True +1 False +2 True +3 False +4 False +dtype: bool +>>> +>>> obj.duplicated(keep=False) +0 True +1 False +2 True +3 False +4 True +dtype: bool +``` + +在 DataFrame 对象中,subset 参数用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4, + 'data2' : np.random.randint(0, 4, 8)}) +>>> obj + data1 data2 +0 a 0 +1 a 0 +2 a 0 +3 a 3 +4 b 3 +5 b 3 +6 b 0 +7 b 2 +>>> +>>> obj.duplicated() +0 False +1 True +2 True +3 False +4 False +5 True +6 False +7 False +dtype: bool +>>> +>>> obj.duplicated(subset='data1') +0 False +1 True +2 True +3 True +4 False +5 True +6 True +7 True +dtype: bool +>>> +>>> obj.duplicated(subset='data2', keep='last') +0 True +1 True +2 True +3 True +4 True +5 False +6 False +7 False +dtype: bool +``` + +### 【02x02】drop_duplicates + +`drop_duplicates` 方法会返回一个删除了重复值的序列。 + +基本语法: + +```python +Series.drop_duplicates(self, keep='first', inplace=False) +``` + +```python +DataFrame.drop_duplicates(self, + subset: Union[Hashable, Sequence[Hashable], NoneType] = None, + keep: Union[str, bool] = 'first', + inplace: bool = False, + ignore_index: bool = False) → Union[ForwardRef(‘DataFrame’), NoneType] +``` + + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.drop_duplicates.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.drop_duplicates.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.drop_duplicates.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.drop_duplicates.html) + +| 参数 | 描述 | +| ------ | ------ | +| keep | 删除重复项的方法,默认 `'first'`
`'first'`:保留非重复项和第一个重复项,其他重复项标记均删除
`'last'`:保留非重复项和最后一个重复项,其他重复项删除
`False`:将所有重复项删除,非重复项保留 | +| inplace | 是否返回删除重复项后的值,默认 False,若设置为 True,则不返回值,直接改变原数据 | +| subset | 列标签或标签序列,在 DataFrame 对象中才有此参数,
用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列 | +| ignore_index | bool 类型,在 DataFrame 对象中才有此参数,是否忽略原对象的轴标记,
默认 False,如果为 True,则新对象的索引将是 0, 1, 2, ..., n-1 | + +keep 参数的使用: + +```python +>>> import pandas as pd +>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'], name='animal') +>>> obj +0 lama +1 cow +2 lama +3 beetle +4 lama +5 hippo +Name: animal, dtype: object +>>> +>>> obj.drop_duplicates() +0 lama +1 cow +3 beetle +5 hippo +Name: animal, dtype: object +>>> +>>> obj.drop_duplicates(keep='last') +1 cow +3 beetle +4 lama +5 hippo +Name: animal, dtype: object +>>> +>>> obj.drop_duplicates(keep=False) +1 cow +3 beetle +5 hippo +Name: animal, dtype: object +``` + +如果设置 `inplace=True`,则不会返回任何值,但原对象的值已被改变: + +```python +>>> import pandas as pd +>>> obj1 = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'], name='animal') +>>> obj1 +0 lama +1 cow +2 lama +3 beetle +4 lama +5 hippo +Name: animal, dtype: object +>>> +>>> obj2 = obj1.drop_duplicates() +>>> obj2 # 有返回值 +0 lama +1 cow +3 beetle +5 hippo +Name: animal, dtype: object +>>> +>>> obj3 = obj1.drop_duplicates(inplace=True) +>>> obj3 # 无返回值 +>>> +>>> obj1 # 原对象的值已改变 +0 lama +1 cow +3 beetle +5 hippo +Name: animal, dtype: object +``` + +在 DataFrame 对象中的使用: + +```python +>>> import numpy as np +>>> import pandas as pd +>>> obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4, + 'data2' : np.random.randint(0, 4, 8)}) +>>> obj + data1 data2 +0 a 2 +1 a 1 +2 a 1 +3 a 2 +4 b 1 +5 b 2 +6 b 0 +7 b 0 +>>> +>>> obj.drop_duplicates() + data1 data2 +0 a 2 +1 a 1 +4 b 1 +5 b 2 +6 b 0 +>>> +>>> obj.drop_duplicates(subset='data2') + data1 data2 +0 a 2 +1 a 1 +6 b 0 +>>> +>>> obj.drop_duplicates(subset='data2', ignore_index=True) + data1 data2 +0 a 2 +1 a 1 +2 b 0 +``` + +## 【03x00】数据替换 + +### 【03x01】replace + +`replace` 方法可以根据值的内容进行替换。 + +基本语法: + +- `Series.replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad')` + +- `DataFrame.replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad')` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.replace.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.replace.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.replace.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.replace.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| to_replace | 找到要替换值的方法,可以是:字符串、正则表达式、列表、字典、整数、浮点数、Series 对象或者 None
使用不同参数的区别参见官方文档 | +| value | 用于替换匹配项的值, 对于 DataFrame,可以使用字典的值来指定每列要使用的值,
还允许使用此类对象的正则表达式,字符串和列表或字典 | +| inplace | bool 类型,是否直接改变原数据且不返回值,默认 False | +| regex | bool 类型或者与 to_replace 相同的类型,
当 to_replace 参数为正则表达式时,regex 应为 True,或者直接使用该参数代替 to_replace | + +`to_replace` 和 `value` 参数只传入一个值,单个值替换单个值: + +```python +>>> import pandas as pd +>>> obj = pd.Series([0, 1, 2, 3, 4]) +>>> obj +0 0 +1 1 +2 2 +3 3 +4 4 +dtype: int64 +>>> +>>> obj.replace(0, 5) +0 5 +1 1 +2 2 +3 3 +4 4 +dtype: int64 +``` + +`to_replace` 传入多个值,`value` 传入一个值,多个值替换一个值: + +```python +>>> import pandas as pd +>>> obj = pd.Series([0, 1, 2, 3, 4]) +>>> obj +0 0 +1 1 +2 2 +3 3 +4 4 +dtype: int64 +>>> +>>> obj.replace([0, 1, 2, 3], 4) +0 4 +1 4 +2 4 +3 4 +4 4 +dtype: int64 +``` + +`to_replace` 和 `value` 参数都传入多个值,多个值替换多个值: + +```python +>>> import pandas as pd +>>> obj = pd.Series([0, 1, 2, 3, 4]) +>>> obj +0 0 +1 1 +2 2 +3 3 +4 4 +dtype: int64 +>>> +>>> obj.replace([0, 1, 2, 3], [4, 3, 2, 1]) +0 4 +1 3 +2 2 +3 1 +4 4 +dtype: int64 +``` + +`to_replace` 传入字典: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'A': [0, 1, 2, 3, 4], + 'B': [5, 6, 7, 8, 9], + 'C': ['a', 'b', 'c', 'd', 'e']}) +>>> obj + A B C +0 0 5 a +1 1 6 b +2 2 7 c +3 3 8 d +4 4 9 e +>>> +>>> obj.replace(0, 5) + A B C +0 5 5 a +1 1 6 b +2 2 7 c +3 3 8 d +4 4 9 e +>>> +>>> obj.replace({0: 10, 1: 100}) + A B C +0 10 5 a +1 100 6 b +2 2 7 c +3 3 8 d +4 4 9 e +>>> +>>> obj.replace({'A': 0, 'B': 5}, 100) + A B C +0 100 100 a +1 1 6 b +2 2 7 c +3 3 8 d +4 4 9 e +>>> obj.replace({'A': {0: 100, 4: 400}}) + A B C +0 100 5 a +1 1 6 b +2 2 7 c +3 3 8 d +4 400 9 e +``` + +`to_replace` 传入正则表达式: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'A': ['bat', 'foo', 'bait'], + 'B': ['abc', 'bar', 'xyz']}) +>>> obj + A B +0 bat abc +1 foo bar +2 bait xyz +>>> +>>> obj.replace(to_replace=r'^ba.$', value='new', regex=True) + A B +0 new abc +1 foo new +2 bait xyz +>>> +>>> obj.replace({'A': r'^ba.$'}, {'A': 'new'}, regex=True) + A B +0 new abc +1 foo bar +2 bait xyz +>>> +>>> obj.replace(regex=r'^ba.$', value='new') + A B +0 new abc +1 foo new +2 bait xyz +>>> +>>> obj.replace(regex={r'^ba.$': 'new', 'foo': 'xyz'}) + A B +0 new abc +1 xyz new +2 bait xyz +>>> +>>> obj.replace(regex=[r'^ba.$', 'foo'], value='new') + A B +0 new abc +1 new new +2 bait xyz +``` + +### 【03x02】where + +`where` 方法用于替换条件为 False 的值。 + +基本语法: + +- `Series.where(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False)` + +- `DataFrame.where(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.where.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.where.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.where.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.where.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| cond | 替换条件,如果 cond 为 True,则保留原始值。如果为 False,则替换为来自 other 的相应值 | +| other | 替换值,如果 cond 为 False,则替换为来自该参数的相应值 | +| inplace | bool 类型,是否直接改变原数据且不返回值,默认 False | + + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> obj = pd.Series(range(5)) +>>> obj +0 0 +1 1 +2 2 +3 3 +4 4 +dtype: int64 +>>> +>>> obj.where(obj > 0) +0 NaN +1 1.0 +2 2.0 +3 3.0 +4 4.0 +dtype: float64 +>>> +>>> obj.where(obj > 1, 10) +0 10 +1 10 +2 2 +3 3 +4 4 +dtype: int64 +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=['A', 'B']) +>>> obj + A B +0 0 1 +1 2 3 +2 4 5 +3 6 7 +4 8 9 +>>> +>>> m = obj % 3 == 0 +>>> obj.where(m, -obj) + A B +0 0 -1 +1 -2 3 +2 -4 -5 +3 6 -7 +4 -8 9 +>>> +>>> obj.where(m, -obj) == np.where(m, obj, -obj) + A B +0 True True +1 True True +2 True True +3 True True +4 True True +``` + +### 【03x03】mask + +`mask` 方法与 `where` 方法相反,`mask` 用于替换条件为 False 的值。 + +基本语法: + +- `Series.mask(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False)` + +- `DataFrame.mask(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False)` + +官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.mask.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.mask.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mask.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mask.html) + + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| cond | 替换条件,如果 cond 为 False,则保留原始值。如果为 True,则替换为来自 other 的相应值 | +| other | 替换值,如果 cond 为 False,则替换为来自该参数的相应值 | +| inplace | bool 类型,是否直接改变原数据且不返回值,默认 False | + +在 Series 中的应用: + +```python +>>> import pandas as pd +>>> obj = pd.Series(range(5)) +>>> obj +0 0 +1 1 +2 2 +3 3 +4 4 +dtype: int64 +>>> +>>> obj.mask(obj > 0) +0 0.0 +1 NaN +2 NaN +3 NaN +4 NaN +dtype: float64 +>>> +>>> obj.mask(obj > 1, 10) +0 0 +1 1 +2 10 +3 10 +4 10 +dtype: int64 +``` + +在 DataFrame 中的应用: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=['A', 'B']) +>>> obj + A B +0 0 1 +1 2 3 +2 4 5 +3 6 7 +4 8 9 +>>> +>>> m = obj % 3 == 0 +>>> +>>> obj.mask(m, -obj) + A B +0 0 1 +1 2 -3 +2 4 5 +3 -6 7 +4 8 -9 +>>> +>>> obj.where(m, -obj) == obj.mask(~m, -obj) + A B +0 True True +1 True True +2 True True +3 True True +4 True True +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106900748 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A87-Pandas-09.md b/source/_posts/A87-Pandas-09.md new file mode 100644 index 0000000000000000000000000000000000000000..0bcae2199ec70ba373055a020b811df1e93e0ee8 --- /dev/null +++ b/source/_posts/A87-Pandas-09.md @@ -0,0 +1,1441 @@ +--- +title: Python 数据分析三剑客之 Pandas(九):时间序列 +tags: + - Pandas + - 时间序列 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(九):时间序列。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106947061 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】时间序列 + +官网对于时间序列的介绍:[https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html) + +时间序列(time series)是一种重要的结构化数据形式,应用于多个领域,包括金融学、经济学、生态学、神经科学、物理学等。在多个时间点观察或测量到的任何事物都可以形成一段时间序列。很多时间序列是固定频率的,也就是说,数据点是根据某种规律定期出现的(比如每15秒、每5分钟、每月出现一次)。时间序列也可以是不定期的,没有固定的时间单位或单位之间的偏移量。时间序列数据的意义取决于具体的应用场景,主要有以下几种: + +- **时间戳(timestamp),表示某个具体的时间点,例如 2020-6-24 15:30;** +- **固定周期(period),表示某个时间周期,例如 2020-01;** +- **时间间隔(timedelta),持续时间,即两个日期或时间之间的差异。** + +- **针对时间戳数据,Pandas 提供了 Timestamp 类型。它本质上是 Python 的原生 datetime 类型的替代品,但是在性能更好的 numpy.datetime64 类型的基础上创建。对应的索引数据结构是 DatetimeIndex。** + +- **针对时间周期数据,Pandas 提供了 Period 类型。这是利用 numpy.datetime64 类型将固定频率的时间间隔进行编码。对应的索引数据结构是 PeriodIndex。** + +- **针对时间增量或持续时间,Pandas 提供了 Timedelta 类型。Timedelta 是一种代替 Python 原生datetime.timedelta 类型的高性能数据结构,同样是基于 numpy.timedelta64 类型。对应的索引数据结构是 TimedeltaIndex。** + +## 【02x00】Timestamp 时间戳 + +### 【02x01】pandas.Timestamp + +在 pandas 中,`pandas.Timestamp` 方法用来代替 Python 中的 `datetime.datetime` 方法。 + +Timestamp 与 Python 的 Datetime 等效,在大多数情况下都可以互换。 此类型用于组成 DatetimeIndex 以及 Pandas 中其他面向时间序列的数据结构。 + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Timestamp.html](https://pandas.pydata.org/docs/reference/api/pandas.Timestamp.html) + +基本语法: + +```python +class pandas.Timestamp(ts_input=, + freq=None, tz=None, unit=None, + year=None, month=None, day=None, + hour=None, minute=None, second=None, + microsecond=None, nanosecond=None, tzinfo=None) +``` + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| ts_input | 要转换为时间戳的对象,可以是 datetime-like,str,int,float 类型 | +| freq | 时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见[【02x02】freq 频率部分取值](#t4) | +| tz | 时间戳将具有的时区 | +| unit | 如果 ts_input 是整数或浮点数,该参数用于设置其单位(D、s、ms、us、ns) | + +简单示例: + +```python +>>> import pandas as pd +>>> pd.Timestamp('2017-01-01T12') +Timestamp('2017-01-01 12:00:00') +``` + +设置 `unit='s'`,即待转换对象单位为秒: + +```python +>>> import pandas as pd +>>> pd.Timestamp(1513393355.5, unit='s') +Timestamp('2017-12-16 03:02:35.500000') +``` + +使用 `tz` 参数设置时区: + +```python +>>> import pandas as pd +>>> pd.Timestamp(1513393355, unit='s', tz='US/Pacific') +Timestamp('2017-12-15 19:02:35-0800', tz='US/Pacific') +``` + +单独设置年月日: + +```python +>>> import pandas as pd +>>> pd.Timestamp(year=2020, month=6, day=24, hour=12) +Timestamp('2020-06-24 12:00:00') +``` + +### 【02x02】freq 频率部分取值 + +完整取值参见官方文档:[https://pandas.pydata.org/docs/user_guide/timeseries.html#timeseries-offset-aliases](https://pandas.pydata.org/docs/user_guide/timeseries.html#timeseries-offset-aliases) + +| 参数 | 类型 | 描述 | +| ------------ | ------------------------- | ----------- | +| D | Day | 每日历日 | +| B | BusinessDay | 每工作日 | +| H | Hour | 每小时 | +| T 或 min | Minute | 每分 | +| S | Second | 每秒 | +| L 或 ms | Milli | 每毫秒(即每千分之一秒) | +| U | Micro | 每微秒(即每百万分之一秒) | +| M | MonthEnd | 每月最后一个日历日 | +| BM | BusinessMonthEnd | 每月最后一个工作日 | +| MS | MonthBegin | 每月第一个日历日 | +| BMS | BusinessMonthBegin | 每月第一个工作日 | +| W-MON、W-TUE… | Week | 从指定的星期几(MON、TUE、 WED、THU、FR、SAT、SUN)开始算起,每周 | +| WoM-1MON、WOM-2MON… | WeekOfMonth | 产生每月第一、第二、第三或第四周的星期几。例如,WoM-3FRI 表示每月第3个星期五 | +| Q-JAN、Q-FEB... | QuarterEnd | 对于以指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、OCT、NOV、DEC)结束的年度,每季度最后一月的最后个日历日 | +| BQ-JAN、BQ-FEB... | BusinessQuarterEnd | 对于以指定月份结束的年度,每季度最后一月的最后一个工作日 | +| QS-JAN、QS-FEB... | QuarterBegin | 对于以指定月份结束的年度,每季度最后一月的第一个日历日 | +| BQS-JAN、 BQS-FEB... | BusinessQuarterBegin | 对于以指定月份结束的年度,每季度最后一月的第一个工作日 | +| A-JAN、A-FEB... | YearEnd | 每年指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、 OCT、NOV、DEC)的最后一个日历日 | +| BA-JAN、BA-FEB… | BusinessYearEnd | 每年指定月份的最后一个工作日 | +| AS-JAN、AS-FEB… | YearBegin | 每年指定月份的第一个历日日 | +| BAS-JAN、BAS-FEB... | BusinessYearBegin | 每年指定月份的第一个工作日 | + +### 【02x03】to_datetime + +在 Python 中,datetime 库提供了日期和时间处理方法,利用 `str` 或 `strftime` 方法可以将 datetime 对象转化成字符串,具体用法可参见[【Python 标准库学习】日期和时间处理库 — datetime](https://blog.csdn.net/qq_36759224/article/details/104427220)。 + +```python +>>> from datetime import datetime +>>> stamp = datetime(2020, 6, 24) +>>> stamp +datetime.datetime(2020, 6, 24, 0, 0) +>>> +>>> str(stamp) +'2020-06-24 00:00:00' +>>> +>>> stamp.strftime('%Y-%m-%d') +'2020-06-24' +``` + +**在 pandas 中 to_datetime 方法可以将字符串解析成多种不同的 Timestamp(时间戳) 对象:** + +```python +>>> import pandas as pd +>>> datestrs = '2011-07-06 12:00:00' +>>> type(datestrs) + +>>> +>>> pd.to_datetime(datestrs) +Timestamp('2011-07-06 12:00:00') +``` + +基本语法: + +```python +pandas.to_datetime(arg, errors='raise', dayfirst=False, + yearfirst=False, utc=None, format=None, + exact=True, unit=None, infer_datetime_format=False, + origin='unix', cache=True) +``` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html](https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| arg | 要转换为日期时间的对象,可以接受 int, float, str, datetime, list, tuple, 1-d array, Series DataFrame/dict-like 类型 | +| errors | 如果字符串不满足时间戳的形式,是否会发生异常
`ignore`:不引发异常,返回原始输入;`raise`:无效解析将引发异常(默认);`coerce`:无效解析将被设置为NaT | +| dayfirst | bool 类型,默认 False,如果 arg 是 str 或列表,是否首先解析为日期
例如 dayfirst 为 True,`10/11/12` 被解析为 `2012-11-10`,为 False 则解析为 `2012-10-11` | +| yearfirst | bool 类型,默认 False,如果 arg 是 str 或列表,是否首先解析为年份
例如 dayfirst 为 True,`10/11/12` 被解析为 `2010-11-12`,为 False 则解析为 `2012-10-11`
如果 dayfirst 和 yearfirst 都为 True,则优先 yearfirst | +| utc | bool 类型,是否转换为协调世界时,默认 None | +| format | 格式化时间,如 `21/2/20 16:10` 使用 `%d/%m/%y %H:%M` 会被解析为 `2020-02-21 16:10:00`
符号含义常见文章:[【Python 标准库学习】日期和时间处理库 — datetime](https://blog.csdn.net/qq_36759224/article/details/104427220) 或者[官方文档](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior) | +| exact | 如果为 True,则需要精确的格式匹配。如果为 False,则允许格式与目标字符串中的任何位置匹配 | +| unit | 如果 arg 是整数或浮点数,该参数用于设置其单位(D、s、ms、us、ns) | + +简单应用: + +```python +>>> import pandas as pd +>>> obj = pd.DataFrame({'year': [2015, 2016], 'month': [2, 3], 'day': [4, 5]}) +>>> obj + year month day +0 2015 2 4 +1 2016 3 5 +>>> +>>> pd.to_datetime(obj) +0 2015-02-04 +1 2016-03-05 +dtype: datetime64[ns] +``` + +设置 `format` 和 `errors` 参数: + +```python +>>> import pandas as pd +>>> pd.to_datetime('13000101', format='%Y%m%d', errors='ignore') +datetime.datetime(1300, 1, 1, 0, 0) +>>> +>>> pd.to_datetime('13000101', format='%Y%m%d', errors='coerce') +NaT +>>> +>>> pd.to_datetime('13000101', format='%Y%m%d', errors='raise') +Traceback (most recent call last): +... +pandas._libs.tslibs.np_datetime.OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1300-01-01 00:00:00 +``` + +设置 `unit` 参数: + +```python +>>> import pandas as pd +>>> pd.to_datetime(1490195805, unit='s') +Timestamp('2017-03-22 15:16:45') +>>> +>>> pd.to_datetime(1490195805433502912, unit='ns') +Timestamp('2017-03-22 15:16:45.433502912') +``` + +### 【02x04】date_range + +`pandas.date_range` 方法可用于根据指定的频率生成指定长度的 DatetimeIndex。 + +基本语法: + +```python +pandas.date_range(start=None, end=None, periods=None, freq=None, + tz=None, normalize=False, name=None, closed=None, + **kwargs) → pandas.core.indexes.datetimes.DatetimeIndex +``` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.date_range.html](https://pandas.pydata.org/docs/reference/api/pandas.date_range.html) + +| 参数 | 描述 | +| ------ | ------ | +| start | 开始日期 | +| end | 结束日期 | +| periods | int 类型,要生成的时段数(天) | +| freq | 频率字符串,即按照某种特定的频率来生成日期,取值参见[【02x02】freq 频率部分取值](#t4) | +| tz | 设置时区,例如 “Asia/Hong_Kong” | +| normalize | bool 类型,默认 False,是否在生成日期之前对其进行规范化(仅保留年月日) | +| name | 结果 DatetimeIndex 的名称 | +| closed | `None`:默认值,同时保留开始日期和结束日期
`'left'`:保留开始日期,不保留结束日期
`'right'`:保留结束日期,不保留开始日期 | + +简单示例: + +```python +>>> import pandas as pd +>>> pd.date_range(start='1/1/2018', end='1/08/2018') +DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', + '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'], + dtype='datetime64[ns]', freq='D') +``` + +指定 `periods` 参数: + +```python +>>> import pandas as pd +>>> pd.date_range(start='2012-04-01', periods=20) +DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04', + '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08', + '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12', + '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16', + '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'], + dtype='datetime64[ns]', freq='D') +>>> +>>> pd.date_range(end='2012-06-01', periods=20) +DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16', + '2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20', + '2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24', + '2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28', + '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'], + dtype='datetime64[ns]', freq='D') +>>> +>>> pd.date_range(start='2018-04-24', end='2018-04-27', periods=3) +DatetimeIndex(['2018-04-24 00:00:00', '2018-04-25 12:00:00', '2018-04-27 00:00:00'], + dtype='datetime64[ns]', freq=None) +>>> +>>> pd.date_range(start='2018-04-24', end='2018-04-28', periods=3) +DatetimeIndex(['2018-04-24', '2018-04-26', '2018-04-28'], dtype='datetime64[ns]', freq=None) +``` + +指定 `freq='M'` 会按照每月最后一个日历日的频率生成日期,指定 `freq='3M'` 会每隔3个月按照每月最后一个日历日的频率生成日期: + +```python +>>> import pandas as pd +>>> pd.date_range(start='1/1/2018', periods=5, freq='M') +DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30', + '2018-05-31'], + dtype='datetime64[ns]', freq='M') +>>> +>>> pd.date_range(start='1/1/2018', periods=5, freq='3M') +DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31', + '2019-01-31'], + dtype='datetime64[ns]', freq='3M') +>>> +``` + +使用 `tz` 参数设置时区: + +```python +>>> import pandas as pd +>>> pd.date_range(start='1/1/2018', periods=5, tz='Asia/Tokyo') +DatetimeIndex(['2018-01-01 00:00:00+09:00', '2018-01-02 00:00:00+09:00', + '2018-01-03 00:00:00+09:00', '2018-01-04 00:00:00+09:00', + '2018-01-05 00:00:00+09:00'], + dtype='datetime64[ns, Asia/Tokyo]', freq='D') +>>> +>>> pd.date_range(start='6/24/2020', periods=5, tz='Asia/Hong_Kong') +DatetimeIndex(['2020-06-24 00:00:00+08:00', '2020-06-25 00:00:00+08:00', + '2020-06-26 00:00:00+08:00', '2020-06-27 00:00:00+08:00', + '2020-06-28 00:00:00+08:00'], + dtype='datetime64[ns, Asia/Hong_Kong]', freq='D') +``` + +设置 `normalize` 参数,在生成时间戳之前对其进行格式化操作: + +```python +>>> import pandas as pd +>>> pd.date_range('2020-06-24 12:56:31', periods=5, normalize=True) +DatetimeIndex(['2020-06-24', '2020-06-25', '2020-06-26', '2020-06-27', + '2020-06-28'], + dtype='datetime64[ns]', freq='D') +``` + +设置 `closed` 参数: + +```python +>>> import pandas as pd +>>> pd.date_range(start='2020-06-20', end='2020-06-24', closed=None) +DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23', + '2020-06-24'], + dtype='datetime64[ns]', freq='D') +>>> +>>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='left') +DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23'], dtype='datetime64[ns]', freq='D') +>>> +>>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='right') +DatetimeIndex(['2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24'], dtype='datetime64[ns]', freq='D') +``` + +### 【02x05】索引与切片 + +Pandas 最基本的时间序列类型就是以时间戳(通常以 Python 字符串或 datatime 对象表示)为索引的Series,这些 datetime 对象实际上是被放在 DatetimeIndex 中的,可以使用类似 pandas.Series 对象的切片方法对其进行索引: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> dates = [datetime(2011, 1, 2), datetime(2011, 1, 5), + datetime(2011, 1, 7), datetime(2011, 1, 8), + datetime(2011, 1, 10), datetime(2011, 1, 12)] +>>> obj = pd.Series(np.random.randn(6), index=dates) +>>> +>>> obj +2011-01-02 -0.407110 +2011-01-05 -0.186661 +2011-01-07 -0.731080 +2011-01-08 0.860970 +2011-01-10 1.929973 +2011-01-12 -0.168599 +dtype: float64 +>>> +>>> obj.index +DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08', + '2011-01-10', '2011-01-12'], + dtype='datetime64[ns]', freq=None) +>>> +>>> obj.index[0] +Timestamp('2011-01-02 00:00:00') +>>> +>>> obj.index[0:3] +DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07'], dtype='datetime64[ns]', freq=None) +``` + +另外还可以传入一个可以被解释为日期的字符串,或者只需传入“年”或“年月”即可轻松选取数据的切片: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000)) +>>> obj +2000-01-01 -1.142284 +2000-01-02 1.198785 +2000-01-03 2.466909 +2000-01-04 -0.086728 +2000-01-05 -0.978437 + ... +2002-09-22 -0.252240 +2002-09-23 0.148561 +2002-09-24 -1.330409 +2002-09-25 -0.673471 +2002-09-26 -0.253271 +Freq: D, Length: 1000, dtype: float64 +>>> +>>> obj['26/9/2002'] +-0.25327100684233356 +>>> +>>> obj['2002'] +2002-01-01 1.058715 +2002-01-02 0.900859 +2002-01-03 1.993508 +2002-01-04 -0.103211 +2002-01-05 -0.950090 + ... +2002-09-22 -0.252240 +2002-09-23 0.148561 +2002-09-24 -1.330409 +2002-09-25 -0.673471 +2002-09-26 -0.253271 +Freq: D, Length: 269, dtype: float64 +>>> +>>> obj['2002-09'] +2002-09-01 -0.995528 +2002-09-02 0.501528 +2002-09-03 -0.486753 +2002-09-04 -1.083906 +2002-09-05 1.458975 +2002-09-06 -1.331685 +2002-09-07 0.195338 +2002-09-08 -0.429613 +2002-09-09 1.125823 +2002-09-10 1.607051 +2002-09-11 0.530387 +2002-09-12 -0.015938 +2002-09-13 1.781043 +2002-09-14 -0.277123 +2002-09-15 0.344569 +2002-09-16 -1.010810 +2002-09-17 0.463001 +2002-09-18 1.883636 +2002-09-19 0.274520 +2002-09-20 0.624184 +2002-09-21 -1.203057 +2002-09-22 -0.252240 +2002-09-23 0.148561 +2002-09-24 -1.330409 +2002-09-25 -0.673471 +2002-09-26 -0.253271 +Freq: D, dtype: float64 +>>> +>>> obj['20/9/2002':'26/9/2002'] +2002-09-20 0.624184 +2002-09-21 -1.203057 +2002-09-22 -0.252240 +2002-09-23 0.148561 +2002-09-24 -1.330409 +2002-09-25 -0.673471 +2002-09-26 -0.253271 +Freq: D, dtype: float64 +``` + +### 【02x06】移动数据与数据偏移 + +移动(shifting)指的是沿着时间轴将数据前移或后移。Series 和 DataFrame 都有一个 shift 方法用于执行单纯的前移或后移操作,保持索引不变: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(4), + index=pd.date_range('1/1/2000', periods=4, freq='M')) +>>> obj +2000-01-31 -0.100217 +2000-02-29 1.177834 +2000-03-31 -0.644353 +2000-04-30 -1.954679 +Freq: M, dtype: float64 +>>> +>>> obj.shift(2) +2000-01-31 NaN +2000-02-29 NaN +2000-03-31 -0.100217 +2000-04-30 1.177834 +Freq: M, dtype: float64 +>>> +>>> obj.shift(-2) +2000-01-31 -0.644353 +2000-02-29 -1.954679 +2000-03-31 NaN +2000-04-30 NaN +Freq: M, dtype: float64 +``` + +因为简单的移位操作不会修改索引,所以部分数据会被丢弃并引入 NaN(缺失值)。因此,如果频率已知,则可以将其传给 shift 以便实现对时间戳进行位移而不是对数据进行简单位移: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> obj = pd.Series(np.random.randn(4), + index=pd.date_range('1/1/2000', periods=4, freq='M')) +>>> obj +2000-01-31 -0.100217 +2000-02-29 1.177834 +2000-03-31 -0.644353 +2000-04-30 -1.954679 +Freq: M, dtype: float64 +>>> +>>> obj.shift(2, freq='M') +2000-03-31 -0.100217 +2000-04-30 1.177834 +2000-05-31 -0.644353 +2000-06-30 -1.954679 +Freq: M, dtype: float64 +``` + +Pandas 中的频率是由一个基础频率(base frequency)和一个乘数组成的。基础频率通常以一个字符串别名表示,比如 `"M"` 表示每月,`"H"` 表示每小时。对于每个基础频率,都有一个被称为日期偏移量(date offset)的对象与之对应。例如,按小时计算的频率可以用 `Hour` 类表示: + +```python +>>> from pandas.tseries.offsets import Hour, Minute +>>> hour = Hour() +>>> hour + +>>> +>>> four_hours = Hour(4) +>>> four_hours +<4 * Hours> +``` + +一般来说,无需明确创建这样的对象,只需使用诸如 `"H"` 或 `"4H"` 这样的字符串别名即可。在基础频率前面放上一个整数即可创建倍数: + +```python +>>> import pandas as pd +>>> pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h') +DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00', + '2000-01-01 08:00:00', '2000-01-01 12:00:00', + '2000-01-01 16:00:00', '2000-01-01 20:00:00', + '2000-01-02 00:00:00', '2000-01-02 04:00:00', + '2000-01-02 08:00:00', '2000-01-02 12:00:00', + '2000-01-02 16:00:00', '2000-01-02 20:00:00', + '2000-01-03 00:00:00', '2000-01-03 04:00:00', + '2000-01-03 08:00:00', '2000-01-03 12:00:00', + '2000-01-03 16:00:00', '2000-01-03 20:00:00'], + dtype='datetime64[ns]', freq='4H') +``` + +大部分偏移量对象都可通过加法进行连接: + +```python +>>> from pandas.tseries.offsets import Hour, Minute +>>> Hour(2) + Minute(30) +<150 * Minutes> +``` + +对于 `freq` 参数也可以传入频率字符串(如 `"2h30min"`),这种字符串可以被高效地解析为等效的表达式: + +```python +>>> import pandas as pd +>>> pd.date_range('2000-01-01', periods=10, freq='1h30min') +DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00', + '2000-01-01 03:00:00', '2000-01-01 04:30:00', + '2000-01-01 06:00:00', '2000-01-01 07:30:00', + '2000-01-01 09:00:00', '2000-01-01 10:30:00', + '2000-01-01 12:00:00', '2000-01-01 13:30:00'], + dtype='datetime64[ns]', freq='90T') +``` + +这种偏移量还可以用在 datetime 或 Timestamp 对象上: + +```python +>>> from pandas.tseries.offsets import Day, MonthEnd +>>> now = datetime(2011, 11, 17) +>>> now + 3 * Day() +Timestamp('2011-11-20 00:00:00') +``` + +如果加的是锚点偏移量,比如 MonthEnd,第一次增量会将原日期向前滚动到符合频率规则的下一个日期: + +```python +>>> from pandas.tseries.offsets import Day, MonthEnd +>>> now = datetime(2011, 11, 17) +>>> now + MonthEnd() +Timestamp('2011-11-30 00:00:00') +>>> now + MonthEnd(2) +Timestamp('2011-12-31 00:00:00') +``` + +通过锚点偏移量的 rollforward 和 rollback 方法,可明确地将日期向前或向后滚动: + +```python +>>> from pandas.tseries.offsets import Day, MonthEnd +>>> now = datetime(2011, 11, 17) +>>> offset = MonthEnd() +>>> offset.rollforward(now) +Timestamp('2011-11-30 00:00:00') +>>> offset.rollback(now) +Timestamp('2011-10-31 00:00:00') +``` + +与 `groupby` 方法结合使用: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> from pandas.tseries.offsets import Day, MonthEnd +>>> obj = pd.Series(np.random.randn(20), + index=pd.date_range('1/15/2000', periods=20, freq='4d')) +>>> obj +2000-01-15 -0.591729 +2000-01-19 -0.775844 +2000-01-23 -0.745603 +2000-01-27 -0.076439 +2000-01-31 1.796417 +2000-02-04 -0.500349 +2000-02-08 0.515851 +2000-02-12 -0.344171 +2000-02-16 0.419657 +2000-02-20 0.307288 +2000-02-24 0.115113 +2000-02-28 -0.362585 +2000-03-03 1.074892 +2000-03-07 1.111366 +2000-03-11 0.949910 +2000-03-15 -1.535727 +2000-03-19 0.545944 +2000-03-23 -0.810139 +2000-03-27 -1.260627 +2000-03-31 -0.128403 +Freq: 4D, dtype: float64 +>>> +>>> offset = MonthEnd() +>>> obj.groupby(offset.rollforward).mean() +2000-01-31 -0.078640 +2000-02-29 0.021543 +2000-03-31 -0.006598 +dtype: float64 +``` + +### 【02x07】时区处理 + +在 Python 中,时区信息来自第三方库 pytz,使用 `pytz.common_timezones` 方法可以查看所有的时区名称,使用 `pytz.timezone` 方法从 pytz 中获取时区对象: + +```python +>>> import pytz +>>> pytz.common_timezones +['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', ..., 'UTC'] +>>> +>>> tz = pytz.timezone('Asia/Shanghai') +>>> tz + # 表示与 UTC 时间相差8小时6分 +``` + +在 `date_range` 方法中,`tz` 参数用于指定时区,默认为 None,可以使用 `tz_localize` 方法将其进行本地化时区转换,如下示例中,将无时区转本地化 UTC 时区: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D') +>>> ts = pd.Series(np.random.randn(len(rng)), index=rng) +>>> ts +2012-03-09 09:30:00 -1.527913 +2012-03-10 09:30:00 -1.116101 +2012-03-11 09:30:00 0.359358 +2012-03-12 09:30:00 -0.475920 +2012-03-13 09:30:00 -0.336570 +2012-03-14 09:30:00 -1.075952 +Freq: D, dtype: float64 +>>> +>>> print(ts.index.tz) +None +>>> +>>> ts_utc = ts.tz_localize('UTC') +>>> ts_utc +2012-03-09 09:30:00+00:00 -1.527913 +2012-03-10 09:30:00+00:00 -1.116101 +2012-03-11 09:30:00+00:00 0.359358 +2012-03-12 09:30:00+00:00 -0.475920 +2012-03-13 09:30:00+00:00 -0.336570 +2012-03-14 09:30:00+00:00 -1.075952 +Freq: D, dtype: float64 +>>> +>>> ts_utc.index +DatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00', + '2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00', + '2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00'], + dtype='datetime64[ns, UTC]', freq='D') +``` + +时间序列被本地化到某个特定时区后,就可以用 `tz_convert` 方法将其转换到别的时区了: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D') +>>> ts = pd.Series(np.random.randn(len(rng)), index=rng) +>>> ts +2012-03-09 09:30:00 0.480303 +2012-03-10 09:30:00 -1.461039 +2012-03-11 09:30:00 -1.512749 +2012-03-12 09:30:00 -2.185421 +2012-03-13 09:30:00 1.657845 +2012-03-14 09:30:00 0.175633 +Freq: D, dtype: float64 +>>> +>>> ts.tz_localize('UTC').tz_convert('Asia/Shanghai') +2012-03-09 17:30:00+08:00 0.480303 +2012-03-10 17:30:00+08:00 -1.461039 +2012-03-11 17:30:00+08:00 -1.512749 +2012-03-12 17:30:00+08:00 -2.185421 +2012-03-13 17:30:00+08:00 1.657845 +2012-03-14 17:30:00+08:00 0.175633 +Freq: D, dtype: float64 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106947061 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【03x00】period 固定时期 + +### 【03x01】pandas.Period + +固定时期(period)表示的是时间区间,比如数日、数月、数季、数年等。Period 类所表示的就是这种数据类型,其构造函数需要用到一个字符串或整数。 + +基本语法: + +```python +class pandas.Period(value=None, freq=None, ordinal=None, + year=None, month=None, quarter=None, + day=None, hour=None, minute=None, second=None) +``` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Period.html](https://pandas.pydata.org/docs/reference/api/pandas.Period.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| value | 时间段 | +| freq | 时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见[【02x02】freq 频率部分取值](#t4) | + +以下示例中,Period 对象表示的是从2020年1月1日到2020年12月31日之间的整段时间 + +```python +>>> import pandas as pd +>>> pd.Period(2020, freq='A-DEC') +Period('2020', 'A-DEC') +``` + +利用加减法对其按照频率进行位移: + +```python +>>> import pandas as pd +>>> obj = pd.Period(2020, freq='A-DEC') +>>> obj +Period('2020', 'A-DEC') +>>> +>>> obj + 5 +Period('2025', 'A-DEC') +>>> +>>> obj - 5 +Period('2015', 'A-DEC') +``` + +PeriodIndex 类保存了一组 Period,它可以在任何 pandas 数据结构中被用作轴索引: + +```python +>>> import pandas as pd +>>> import numpy as np +>>> rng = [pd.Period('2000-01'), pd.Period('2000-02'), pd.Period('2000-03'), + pd.Period('2000-04'), pd.Period('2000-05'), pd.Period('2000-06')] +>>> obj = pd.Series(np.random.randn(6), index=rng) +>>> obj +2000-01 0.229092 +2000-02 1.515498 +2000-03 -0.334401 +2000-04 -0.492681 +2000-05 -2.012818 +2000-06 0.338804 +Freq: M, dtype: float64 +>>> +>>> obj.index +PeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M') +``` + +```python +>>> import pandas as pd +>>> values = ['2001Q3', '2002Q2', '2003Q1'] +>>> index = pd.PeriodIndex(values, freq='Q-DEC') +>>> index +PeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC') +>>> +``` + +### 【03x02】period_range + +`pandas.period_range` 方法可根据指定的频率生成指定长度的 PeriodIndex。 + +基本语法: + +`pandas.period_range(start=None, end=None, periods=None, freq=None, name=None) → pandas.core.indexes.period.PeriodIndex` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.period_range.html](https://pandas.pydata.org/docs/reference/api/pandas.period_range.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| start | 起始日期 | +| end | 结束日期 | +| periods | 要生成的时段数 | +| freq | 时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见[【02x02】freq 频率部分取值](#t4) | +| name | 结果 PeriodIndex 对象名称 | + +简单应用: + +```python +>>> import pandas as pd +>>> pd.period_range(start='2019-01-01', end='2020-01-01', freq='M') +PeriodIndex(['2019-01', '2019-02', '2019-03', '2019-04', '2019-05', '2019-06', + '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', + '2020-01'], + dtype='period[M]', freq='M') +>>> +>>> pd.period_range(start=pd.Period('2017Q1', freq='Q'), + end=pd.Period('2017Q2', freq='Q'), freq='M') +PeriodIndex(['2017-03', '2017-04', '2017-05', '2017-06'], dtype='period[M]', freq='M') +``` + +### 【03x03】asfreq 时期频率转换 + +Period 和 PeriodIndex 对象都可以通过 asfreq 方法被转换成别的频率。 + +基本语法:`PeriodIndex.asfreq(self, *args, **kwargs)` + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| freq | 新的频率(偏移量),取值参见[【02x02】freq 频率部分取值](#t4) | +| how | 按照开始或者结束对齐,`'E'` or `'END'` or `'FINISH'`;`'S'` or `'START'` or `'BEGIN'` | + +应用示例: + +```python +>>> import pandas as pd +>>> pidx = pd.period_range('2010-01-01', '2015-01-01', freq='A') +>>> pidx +PeriodIndex(['2010', '2011', '2012', '2013', '2014', '2015'], dtype='period[A-DEC]', freq='A-DEC') +>>> +>>> pidx.asfreq('M') +PeriodIndex(['2010-12', '2011-12', '2012-12', '2013-12', '2014-12', '2015-12'], dtype='period[M]', freq='M') +>>> +>>> pidx.asfreq('M', how='S') +PeriodIndex(['2010-01', '2011-01', '2012-01', '2013-01', '2014-01', '2015-01'], dtype='period[M]', freq='M') +``` + +### 【03x04】to_period 与 to_timestamp() + +`to_period` 方法可以将 Timestamp(时间戳) 转换为 Period(固定时期); + +`to_timestamp` 方法可以将 Period(固定时期)转换为 Timestamp(时间戳) 。 + + +```python +>>> import pandas as pd +>>> rng = pd.date_range('2000-01-01', periods=3, freq='M') +>>> ts = pd.Series(np.random.randn(3), index=rng) +>>> ts +2000-01-31 0.220759 +2000-02-29 -0.108221 +2000-03-31 0.819433 +Freq: M, dtype: float64 +>>> +>>> pts = ts.to_period() +>>> pts +2000-01 0.220759 +2000-02 -0.108221 +2000-03 0.819433 +Freq: M, dtype: float64 +>>> +>>> pts2 = pts.to_timestamp() +>>> pts2 +2000-01-01 0.220759 +2000-02-01 -0.108221 +2000-03-01 0.819433 +Freq: MS, dtype: float64 +>>> +>>> ts.index +DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31'], dtype='datetime64[ns]', freq='M') +>>> +>>> pts.index +PeriodIndex(['2000-01', '2000-02', '2000-03'], dtype='period[M]', freq='M') +>>> +>>> pts2.index +DatetimeIndex(['2000-01-01', '2000-02-01', '2000-03-01'], dtype='datetime64[ns]', freq='MS') +``` + +## 【04x00】timedelta 时间间隔 + +### 【04x01】pandas.Timedelta + +Timedelta 表示持续时间,即两个日期或时间之间的差。 + +Timedelta 相当于 Python 的 datetime.timedelta,在大多数情况下两者可以互换。 + +基本语法:`class pandas.Timedelta(value=, unit=None, **kwargs)` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html](https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| value | 传入的值,可以是 Timedelta,timedelta,np.timedelta64,string 或 integer 对象 | +| unit | 用于设置 value 的单位,具体取值参见官方文档 | + +表示两个 datetime 对象之间的时间差: + +```python +>>> import pandas as pd +>>> pd.to_datetime('2020-6-24') - pd.to_datetime('2016-1-1') +Timedelta('1636 days 00:00:00') +``` + +通过字符串传递参数: + +```python +>>> import pandas as pd +>>> pd.Timedelta('3 days 3 hours 3 minutes 30 seconds') +Timedelta('3 days 03:03:30') +``` + +通过整数传递参数: + +```python +>>> import pandas as pd +>>> pd.Timedelta(5,unit='h') +Timedelta('0 days 05:00:00') +``` + +获取属性: + +```python +>>> import pandas as pd +>>> obj = pd.Timedelta('3 days 3 hours 3 minutes 30 seconds') +>>> obj +Timedelta('3 days 03:03:30') +>>> +>>> obj.days +3 +>>> obj.seconds +11010 +``` + +### 【04x02】to_timedelta + +to_timedelta 方法可以将传入的对象转换成 timedelta 对象。 + +基本语法:`pandas.to_timedelta(arg, unit='ns', errors='raise')` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.to_timedelta.html](https://pandas.pydata.org/docs/reference/api/pandas.to_timedelta.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| arg | 要转换为 timedelta 的对象,可以是 str,timedelta,list-like 或 Series 对象 +| unit | 用于设置 arg 的单位,具体取值参见官方文档 | +| errors | 如果 arg 不满足时间戳的形式,是否会发生异常
`ignore`:不引发异常,返回原始输入;`raise`:无效解析将引发异常(默认);`coerce`:无效解析将被设置为NaT | + +将单个字符串解析为 timedelta 对象: + +```python +>>> import pandas as pd +>>> pd.to_timedelta('1 days 06:05:01.00003') +Timedelta('1 days 06:05:01.000030') +>>> +>>> pd.to_timedelta('15.5us') +Timedelta('0 days 00:00:00.000015') +``` + +将字符串列表或数组解析为 timedelta 对象: + +```python +>>> import pandas as pd +>>> pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan']) +TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015', NaT], dtype='timedelta64[ns]', freq=None) +``` + +指定 `unit` 参数: + +```python +>>> import pandas as pd +>>> pd.to_timedelta(np.arange(5), unit='s') +TimedeltaIndex(['00:00:00', '00:00:01', '00:00:02', '00:00:03', '00:00:04'], dtype='timedelta64[ns]', freq=None) +>>> +>>> pd.to_timedelta(np.arange(5), unit='d') +TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq=None) +``` + +### 【04x03】timedelta_range + +`timedelta_range` 方法可根据指定的频率生成指定长度的 TimedeltaIndex。 + + +基本语法: + +```python +pandas.timedelta_range(start=None, end=None, periods=None, + freq=None, name=None, closed=None) → pandas.core.indexes.timedeltas.TimedeltaIndex +``` + +官方文档:[https://pandas.pydata.org/docs/reference/api/pandas.timedelta_range.html](https://pandas.pydata.org/docs/reference/api/pandas.timedelta_range.html) + +常用参数: + +| 参数 | 描述 | +| ------ | -------- | +| start | 开始日期 | +| end | 结束日期 | +| periods | int 类型,要生成的时段数 | +| freq | 频率字符串,即按照某种特定的频率来生成日期,取值参见[【02x02】freq 频率部分取值](#t4) | +| name | 结果 TimedeltaIndex 的名称 | +| closed | `None`:默认值,同时保留开始日期和结束日期
`'left'`:保留开始日期,不保留结束日期
`'right'`:保留结束日期,不保留开始日期 | + +应用示例: + +```python +>>> import pandas as pd +>>> pd.timedelta_range(start='1 day', periods=4) +TimedeltaIndex(['1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D') +``` + +closed 参数指定保留哪个端点。默认保留两个端点: + +```python +>>> import pandas as pd +>>> pd.timedelta_range(start='1 day', periods=4, closed='right') +TimedeltaIndex(['2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D') +``` + +freq 参数指定 TimedeltaIndex 的频率。只接受固定频率,非固定频率如 `'M'` 将会报错: + +```python +>>> import pandas as pd +>>> pd.timedelta_range(start='1 day', end='2 days', freq='6H') +TimedeltaIndex(['1 days 00:00:00', '1 days 06:00:00', '1 days 12:00:00', + '1 days 18:00:00', '2 days 00:00:00'], + dtype='timedelta64[ns]', freq='6H') +>>> +>>> pd.timedelta_range(start='1 day', end='2 days', freq='M') +Traceback (most recent call last): +... +ValueError: is a non-fixed frequency +``` + +## 【05x00】重采样及频率转换 + +重采样(resampling)指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据聚合到低频率称为降采样(downsampling),而将低频率数据转换到高频率则称为升采样(upsampling)。并不是所有的重采样都能被划分到这两个大类中。例如,将 W-WED(每周三)转换为 W-FRI 既不是降采样也不是升采样。 + +Pandas 中提供了 resample 方法来帮助我们实现重采样。Pandas 对象都带有一个 resample 方法,它是各种频率转换工作的主力函数。 + +基本语法: + +```python +Series.resample(self, rule, axis=0, + closed: Union[str, NoneType] = None, + label: Union[str, NoneType] = None, + convention: str = 'start', + kind: Union[str, NoneType] = None, + loffset=None, base: int = 0, + on=None, level=None) +``` + +```python +DataFrame.resample(self, rule, axis=0, + closed: Union[str, NoneType] = None, + label: Union[str, NoneType] = None, + convention: str = 'start', + kind: Union[str, NoneType] = None, + loffset=None, base: int = 0, + on=None, level=None) +``` + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| rule | +| axis | 重采样的轴,默认 0 | +| closed | 在重采样中,各时间段的哪一端是闭合(即包含)的,
除 `'M'`、`'A'`、`'Q'`、`'BM'`、`'BA'`、`'BQ'` 和 `'W'` 默认值为 ‘right’ 外,其他默认值为 'left‘ | +| label | 在重采样中,如何设置聚合值的标签, right 或 left,默认为 None,
例如,9:30 到 9:35 之间的这 5 分钟会被标记为 9:30 或 9:35 | +| convention | 仅用于 PeriodIndex(固定时期),对周期进行重采样,`'start'` or `'s'`,`'end'` or `'e'` | +| on | 对于 DataFrame 对象,可用该参数指定重采样后的数据的 index(行索引) 为原数据中的某列 | +| level | 对于具有层级索引(MultiIndex)的 DataFrame 对象,可以使用该参数来指定需要在哪个级别上进行重新采样 | + +将序列重采样到三分钟的频率,并将每个频率的值相加: + +```python +>>> import pandas as pd +>>> index = pd.date_range('1/1/2000', periods=9, freq='T') +>>> series = pd.Series(range(9), index=index) +>>> series +2000-01-01 00:00:00 0 +2000-01-01 00:01:00 1 +2000-01-01 00:02:00 2 +2000-01-01 00:03:00 3 +2000-01-01 00:04:00 4 +2000-01-01 00:05:00 5 +2000-01-01 00:06:00 6 +2000-01-01 00:07:00 7 +2000-01-01 00:08:00 8 +Freq: T, dtype: int64 +>>> +>>> series.resample('3T').sum() +2000-01-01 00:00:00 3 +2000-01-01 00:03:00 12 +2000-01-01 00:06:00 21 +Freq: 3T, dtype: int64 +``` + +设置 `label='right'`,即每个索引 index 会使用靠右侧(较大值)的标签: + +```python +>>> import pandas as pd +>>> index = pd.date_range('1/1/2000', periods=9, freq='T') +>>> series = pd.Series(range(9), index=index) +>>> series +2000-01-01 00:00:00 0 +2000-01-01 00:01:00 1 +2000-01-01 00:02:00 2 +2000-01-01 00:03:00 3 +2000-01-01 00:04:00 4 +2000-01-01 00:05:00 5 +2000-01-01 00:06:00 6 +2000-01-01 00:07:00 7 +2000-01-01 00:08:00 8 +Freq: T, dtype: int64 +>>> +>>> series.resample('3T', label='right').sum() +2000-01-01 00:03:00 3 +2000-01-01 00:06:00 12 +2000-01-01 00:09:00 21 +Freq: 3T, dtype: int64 +``` + +设置 `closed='right'`,即结果中会包含原数据中最右侧(较大)的值: + +```python +>>> import pandas as pd +>>> index = pd.date_range('1/1/2000', periods=9, freq='T') +>>> series = pd.Series(range(9), index=index) +>>> series +2000-01-01 00:00:00 0 +2000-01-01 00:01:00 1 +2000-01-01 00:02:00 2 +2000-01-01 00:03:00 3 +2000-01-01 00:04:00 4 +2000-01-01 00:05:00 5 +2000-01-01 00:06:00 6 +2000-01-01 00:07:00 7 +2000-01-01 00:08:00 8 +Freq: T, dtype: int64 +>>> +>>> series.resample('3T', label='right', closed='right').sum() +2000-01-01 00:00:00 0 +2000-01-01 00:03:00 6 +2000-01-01 00:06:00 15 +2000-01-01 00:09:00 15 +Freq: 3T, dtype: int64 +``` + +以下示例将序列重采样到30秒的频率,`asfreq()[0:5]` 用于选择前5行数据: + +```python +>>> import pandas as pd +>>> index = pd.date_range('1/1/2000', periods=9, freq='T') +>>> series = pd.Series(range(9), index=index) +>>> series +2000-01-01 00:00:00 0 +2000-01-01 00:01:00 1 +2000-01-01 00:02:00 2 +2000-01-01 00:03:00 3 +2000-01-01 00:04:00 4 +2000-01-01 00:05:00 5 +2000-01-01 00:06:00 6 +2000-01-01 00:07:00 7 +2000-01-01 00:08:00 8 +Freq: T, dtype: int64 +>>> +>>> series.resample('30S').asfreq()[0:5] +2000-01-01 00:00:00 0.0 +2000-01-01 00:00:30 NaN +2000-01-01 00:01:00 1.0 +2000-01-01 00:01:30 NaN +2000-01-01 00:02:00 2.0 +Freq: 30S, dtype: float64 +``` + +使用 `pad` 方法向后填充缺失值(NaN): + +```python +>>> import pandas as pd +>>> index = pd.date_range('1/1/2000', periods=9, freq='T') +>>> series = pd.Series(range(9), index=index) +>>> series +2000-01-01 00:00:00 0 +2000-01-01 00:01:00 1 +2000-01-01 00:02:00 2 +2000-01-01 00:03:00 3 +2000-01-01 00:04:00 4 +2000-01-01 00:05:00 5 +2000-01-01 00:06:00 6 +2000-01-01 00:07:00 7 +2000-01-01 00:08:00 8 +Freq: T, dtype: int64 +>>> +>>> series.resample('30S').pad()[0:5] +2000-01-01 00:00:00 0 +2000-01-01 00:00:30 0 +2000-01-01 00:01:00 1 +2000-01-01 00:01:30 1 +2000-01-01 00:02:00 2 +Freq: 30S, dtype: int64 +``` + +使用 `bfill` 方法向前填充缺失值(NaN): + +```python +>>> import pandas as pd +>>> index = pd.date_range('1/1/2000', periods=9, freq='T') +>>> series = pd.Series(range(9), index=index) +>>> series +2000-01-01 00:00:00 0 +2000-01-01 00:01:00 1 +2000-01-01 00:02:00 2 +2000-01-01 00:03:00 3 +2000-01-01 00:04:00 4 +2000-01-01 00:05:00 5 +2000-01-01 00:06:00 6 +2000-01-01 00:07:00 7 +2000-01-01 00:08:00 8 +Freq: T, dtype: int64 +>>> +>>> series.resample('30S').bfill()[0:5] +2000-01-01 00:00:00 0 +2000-01-01 00:00:30 1 +2000-01-01 00:01:00 1 +2000-01-01 00:01:30 2 +2000-01-01 00:02:00 2 +Freq: 30S, dtype: int64 +``` + +通过 `apply` 方法传递自定义函数: + +```python +>>> import pandas as pd +>>> index = pd.date_range('1/1/2000', periods=9, freq='T') +>>> series = pd.Series(range(9), index=index) +>>> series +2000-01-01 00:00:00 0 +2000-01-01 00:01:00 1 +2000-01-01 00:02:00 2 +2000-01-01 00:03:00 3 +2000-01-01 00:04:00 4 +2000-01-01 00:05:00 5 +2000-01-01 00:06:00 6 +2000-01-01 00:07:00 7 +2000-01-01 00:08:00 8 +Freq: T, dtype: int64 +>>> +>>> def custom_resampler(array_like): + return np.sum(array_like) + 5 + +>>> series.resample('3T').apply(custom_resampler) +2000-01-01 00:00:00 8 +2000-01-01 00:03:00 17 +2000-01-01 00:06:00 26 +Freq: 3T, dtype: int64 +``` + +convention 参数的应用: + +```python +>>> import pandas as pd +>>> s = pd.Series([1, 2], index=pd.period_range('2012-01-01', freq='A', periods=2)) +>>> s +2012 1 +2013 2 +Freq: A-DEC, dtype: int64 +>>> +>>> s.resample('Q', convention='start').asfreq() +2012Q1 1.0 +2012Q2 NaN +2012Q3 NaN +2012Q4 NaN +2013Q1 2.0 +2013Q2 NaN +2013Q3 NaN +2013Q4 NaN +Freq: Q-DEC, dtype: float64 +>>> +>>> s.resample('Q', convention='end').asfreq() +2012Q4 1.0 +2013Q1 NaN +2013Q2 NaN +2013Q3 NaN +2013Q4 2.0 +Freq: Q-DEC, dtype: float64 +``` + +```python +>>> import pandas as pd +>>> q = pd.Series([1, 2, 3, 4], index=pd.period_range('2018-01-01', freq='Q', periods=4)) +>>> q +2018Q1 1 +2018Q2 2 +2018Q3 3 +2018Q4 4 +Freq: Q-DEC, dtype: int64 +>>> +>>> q.resample('M', convention='end').asfreq() +2018-03 1.0 +2018-04 NaN +2018-05 NaN +2018-06 2.0 +2018-07 NaN +2018-08 NaN +2018-09 3.0 +2018-10 NaN +2018-11 NaN +2018-12 4.0 +Freq: M, dtype: float64 +>>> +>>> q.resample('M', convention='start').asfreq() +2018-01 1.0 +2018-02 NaN +2018-03 NaN +2018-04 2.0 +2018-05 NaN +2018-06 NaN +2018-07 3.0 +2018-08 NaN +2018-09 NaN +2018-10 4.0 +2018-11 NaN +2018-12 NaN +Freq: M, dtype: float64 +``` + +对于 DataFrame 对象,可以使用关键字 on 来指定原数据中的某列为重采样后数据的行索引: + +```python +>>> import pandas as pd +>>> d = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19], + 'volume': [50, 60, 40, 100, 50, 100, 40, 50]}) +>>> df = pd.DataFrame(d) +>>> df['week_starting'] = pd.date_range('01/01/2018', periods=8, freq='W') +>>> df + price volume week_starting +0 10 50 2018-01-07 +1 11 60 2018-01-14 +2 9 40 2018-01-21 +3 13 100 2018-01-28 +4 14 50 2018-02-04 +5 18 100 2018-02-11 +6 17 40 2018-02-18 +7 19 50 2018-02-25 +>>> +>>> df.resample('M', on='week_starting').mean() + price volume +week_starting +2018-01-31 10.75 62.5 +2018-02-28 17.00 60.0 +``` + +对于具有层级索引(MultiIndex)的 DataFrame 对象,可以使用关键字 `level` 来指定需要在哪个级别上进行重新采样: + +```python +>>> import pandas as pd +>>> days = pd.date_range('1/1/2000', periods=4, freq='D') +>>> d2 = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19], + 'volume': [50, 60, 40, 100, 50, 100, 40, 50]}) +>>> df2 = pd.DataFrame(d2, index=pd.MultiIndex.from_product([days, ['morning', 'afternoon']])) +>>> df2 + price volume +2000-01-01 morning 10 50 + afternoon 11 60 +2000-01-02 morning 9 40 + afternoon 13 100 +2000-01-03 morning 14 50 + afternoon 18 100 +2000-01-04 morning 17 40 + afternoon 19 50 +>>> +>>> df2.resample('D', level=0).sum() + price volume +2000-01-01 21 110 +2000-01-02 22 140 +2000-01-03 32 150 +2000-01-04 36 90 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106947061 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A88-Pandas-10.md b/source/_posts/A88-Pandas-10.md new file mode 100644 index 0000000000000000000000000000000000000000..89c4a7368b8f8f33c1c177264cb14e571688f5d9 --- /dev/null +++ b/source/_posts/A88-Pandas-10.md @@ -0,0 +1,518 @@ +--- +title: Python 数据分析三剑客之 Pandas(十):数据读写 +tags: + - Pandas + - 数据读写 + - IO操作 +categories: + - Python 数据分析 + - Pandas +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/pandas.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: Python 数据分析三剑客之 Pandas(十):数据读写操作。 +--- + +Pandas 系列文章: + +- [Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象](https://www.itrhx.com/2020/06/11/A79-Pandas-01/) +- [Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作](https://www.itrhx.com/2020/06/13/A80-Pandas-02/) +- [Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理](https://www.itrhx.com/2020/06/14/A81-Pandas-03/) +- [Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引](https://www.itrhx.com/2020/06/15/A82-Pandas-04/) +- [Python 数据分析三剑客之 Pandas(五):统计计算与统计描述](https://www.itrhx.com/2020/06/16/A83-Pandas-05/) +- [Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并](https://www.itrhx.com/2020/06/17/A84-Pandas-06/) +- [Python 数据分析三剑客之 Pandas(七):合并数据集](https://www.itrhx.com/2020/06/21/A85-Pandas-07/) +- [Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换](https://www.itrhx.com/2020/06/22/A86-Pandas-08/) +- [Python 数据分析三剑客之 Pandas(九):时间序列](https://www.itrhx.com/2020/06/25/A87-Pandas-09/) +- [Python 数据分析三剑客之 Pandas(十):数据读写](https://www.itrhx.com/2020/06/26/A88-Pandas-10/) + +--- + +专栏: + +【[NumPy 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/NumPy/)】【[Pandas 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Pandas/)】【[Matplotlib 专栏](https://www.itrhx.com/categories/Python-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/Matplotlib/)】 + +推荐学习资料与网站: + +【[NumPy 中文网](https://www.numpy.org.cn/)】【[Pandas 中文网](https://www.pypandas.cn/)】【[Matplotlib 中文网](https://www.matplotlib.org.cn/)】【[NumPy、Matplotlib、Pandas 速查表](https://github.com/TRHX/Python-quick-reference-table)】 + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106963135 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【01x00】读取数据 + +Pandas 提供了一些用于将表格型数据读取为 DataFrame 对象的函数。常见方法如下: + +Pandas 官方对 IO 工具的介绍:[https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html](https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html) + +| 函数 | 描述 | +| ------ | ------ | +| read_csv | 从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为逗号 | +| read_table | 从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为制表符(`'\t'`) | +| read_fwf | 读取定宽列格式数据(没有分隔符) | +| read_clipboard | 读取剪贴板中的数据,可以看做 read_table 的剪贴板版本。在将网页转换为表格时很有用 | +| read_excel | 从 Excel XLS 或 XLSX file 读取表格数据 | +| read_hdf | 读取 pandas写的 HDF5 文件 | +| read_html | 读取 HTML 文档中的所有表格 | +| read_json | 读取 JSON( JavaScript Object Notation)字符串中的数据 | +| read_msgpack | 读取二进制格式编码的 pandas 数据(Pandas v1.0.0 中已删除对 msgpack 的支持,建议使用 [pyarrow](https://pandas.pydata.org/docs/user_guide/io.html#io-msgpack)) | +| read_pickle | 读取 Python pickle 格式中存储的任意对象 | +| read_sas | 读取存储于 SAS 系统自定义存储格式的 SAS 数据集 | +| read_sql | (使用 SQLAlchemy)读取 SQL 查询结果为 pandas 的 DataFrame | +| read_stata | 读取 Stata 文件格式的数据集 | +| read_feather | 读取 Feather 二进制格式文件 | + +以下以 read_csv 和 read_table 为例,它们的参数多达 50 多个,具体可参见官方文档: + +read_csv:[https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html) + +read_table:[https://pandas.pydata.org/docs/reference/api/pandas.read_table.html](https://pandas.pydata.org/docs/reference/api/pandas.read_table.html) + +常用参数: + +| 参数 | 描述 | +| ------ | ------ | +| path | 表示文件系统位置、URL、文件型对象的字符串 | +| sep / delimiter | 用于对行中各字段进行拆分的字符序列或正则表达式 | +| header | 用作列名的行号,默认为 0(第一行),如果没有 header 行就应该设置为 None | +| index_col | 用作行索引的列编号或列名。可以是单个名称、数字或由多个名称、数字组成的列表(层次化索引) | +| names | 用于结果的列名列表,结合 header=None | +| skiprows | 需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始) | +| na_values | 指定一组值,将该组值设置为 NaN(缺失值) | +| comment | 用于将注释信息从行尾拆分出去的字符(一个或多个) | +| parse_dates | 尝试将数据解析为日期,默认为 False。如果为 True,则尝试解析所有列。此外,还可以指定需要解析的一组列号或列名。
如果列表的元素为列表或元组,就会将多个列组合到一起再进行日期解析工作(例如,日期、时间分别位于两个列中) | +| keep_date_col | 如果连接多列解析日期,则保持参与连接的列。默认为 False | +| converters | 由列号 / 列名跟函数之间的映射关系组成的字典。例如,`{'foo': f}` 会对 foo 列的所有值应用函数 f | +| dayfirst | 当解析有歧义的日期时,将其看做国际格式(例如,7/6/2012 —> June 7,2012),默认为 Fase | +| date_parser | 用于解析日期的函数 | +| nrows | 需要读取的行数(从文件开始处算起) | +| iterator | 返回一个 TextParser 以便逐块读取文件 | +| chunksize | 文件块的大小(用于迭代) | +| skip_footer | 需要忽略的行数(从文件末尾处算起) | +| verbose | 打印各种解析器输出信息,比如“非数值列中缺失值的数量”等 | +| encoding | 用于 unicode 的文本编码格式。例如,“utf-8” 表示用 UTF-8 编码的文本 | +| squeeze | 如果数据经解析后仅含一列,则返回 Series | +| thousands | 千分位分隔符,如 `,` 或 `.` | + +### 【01x01】简单示例 + +首先创建一个 test1.csv 文件: + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/01.png) + +使用 read_csv 方法将其读出为一个 DataFrame 对象: + +```python +>>> import pandas as pd +>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test1.csv') +>>> obj + a b c d message +0 1 2 3 4 hello +1 5 6 7 8 world +2 9 10 11 12 python +>>> +>>> type(obj) + +``` + +前面的 csv 文件是以逗号分隔的,可以使用 read_table 方法并指定分隔符来读取: + +```python +>>> import pandas as pd +>>> obj = pd.read_table(r'C:\Users\TanRe\Desktop\test1.csv', sep=',') +>>> obj + a b c d message +0 1 2 3 4 hello +1 5 6 7 8 world +2 9 10 11 12 python +``` + +### 【01x02】header / names 定制列标签 + +以上示例中第一行为列标签,如果没有单独定义列标签,使用 read_csv 方法也会默认将第一行当作列标签: + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/02.png) + +```python +>>> import pandas as pd +>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv') +>>> obj + 1 2 3 4 hello +0 5 6 7 8 world +1 9 10 11 12 python +``` + +避免以上情况,可以设置 `header=None`,Pandas 会为其自动分配列标签: + +```python +>>> import pandas as pd +>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', header=None) + 0 1 2 3 4 +0 1 2 3 4 hello +1 5 6 7 8 world +2 9 10 11 12 python +``` + +也可以使用 `names` 参数自定义列标签,传递的是一个列表: + +```python +>>> import pandas as pd +>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', names=['a', 'b', 'c', 'd', 'message']) + a b c d message +0 1 2 3 4 hello +1 5 6 7 8 world +2 9 10 11 12 python +``` + +### 【01x03】index_col 指定列为行索引 + +`index_col` 参数可以指定某一列作为 DataFrame 的行索引,传递的参数是列名称,在以下示例中,会将列名为 `message` 的列作为 DataFrame 的行索引: + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/03.png) + +```python +>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', + names=['a', 'b', 'c', 'd', 'message'], + index_col='message') + a b c d +message +hello 1 2 3 4 +world 5 6 7 8 +python 9 10 11 12 +``` + +如果需要构造多层索引的 DataFrame 对象,则只需传入由列编号或列名组成的列表即可: + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/04.png) + +```python +>>> import pandas as pd +>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test3.csv', index_col=['key1', 'key2']) + value1 value2 +key1 key2 +one a 1 2 + b 3 4 + c 5 6 + d 7 8 +two a 9 10 + b 11 12 + c 13 14 + d 15 16 +``` + +### 【01x04】sep 指定分隔符 + +在 read_table 中,sep 参数用于接收分隔符,如果遇到不是用固定的分隔符去分隔字段的,也可以传递一个正则表达式作为 read_table 的分隔符,如下面的 txt 文件数据之间是由不同的空白字符间隔开的: + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/05.png) + +```python +>>> import pandas as pd +>>> pd.read_table(r'C:\Users\TanRe\Desktop\test1.txt', sep='\s+') + A B C +aaa -0.264438 -1.026059 -0.619500 +bbb 0.927272 0.302904 -0.032399 +ccc -0.264273 -0.386314 -0.217601 +ddd -0.871858 -0.348382 1.100491 +``` + +### 【01x05】skiprows 忽略行 + +skiprows 参数可用于设置需要忽略的行数,或需要跳过的行号列表,在下面的示例中,读取文件时选择跳过第1、3、4行(索引值分别为0、2、3): + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/06.png) + +```python +>>> import pandas as pd +>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test4.csv', skiprows=[0, 2, 3]) + a b c d message +0 1 2 3 4 hello +1 5 6 7 8 world +2 9 10 11 12 python +``` + +### 【01x06】na_values 设置缺失值 + +当文件中出现了空字符串或者 NA 值,Pandas 会将其标记成 NaN(缺失值),同样也可以使用 `isnull` 方法来判断结果值是否为缺失值: + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/07.png) + +```python +>>> import pandas as pd +>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> obj + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> pd.isnull(obj) + something a b c d message +0 False False False False False True +1 False False False True False False +2 False False False False False False +``` + +`na_values` 方法可以传递一组值,将这组值设置为缺失值,如果传递的为字典对象,则字典的各值将被设置为 NaN: + +```python +>>> import pandas as pd +>>> obj1 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> obj1 + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> obj2 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv', na_values=['1', '12']) +>>> obj2 + something a b c d message +0 one NaN 2 3.0 4.0 NaN +1 two 5.0 6 NaN 8.0 world +2 three 9.0 10 11.0 NaN python +>>> +>>> sentinels = {'message': ['python', 'world'], 'something': ['two']} +>>> obj3 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv', na_values=sentinels) +>>> obj3 + something a b c d message +0 one 1 2 3.0 4 NaN +1 NaN 5 6 NaN 8 NaN +2 three 9 10 11.0 12 NaN +``` + +### 【01x07】nrows / chunksize 行与块 + +以下 test6.csv 文件中包含 50 行数据: + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/08.png) + +可以设置 `pd.options.display.max_rows` 来紧凑地显示指定行数的数据: + +```python +>>> import pandas as pd +>>> pd.options.display.max_rows = 10 +>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv') + one two three four key +0 0.467976 -0.038649 -0.295344 -1.824726 L +1 -0.358893 1.404453 0.704965 -0.200638 B +2 -0.501840 0.659254 -0.421691 -0.057688 G +3 0.204886 1.074134 1.388361 -0.982404 R +4 0.354628 -0.133116 0.283763 -0.837063 Q +.. ... ... ... ... .. +45 2.311896 -0.417070 -1.409599 -0.515821 L +46 -0.479893 -0.633419 0.745152 -0.646038 E +47 0.523331 0.787112 0.486066 1.093156 K +48 -0.362559 0.598894 -1.843201 0.887292 G +49 -0.096376 -1.012999 -0.657431 -0.573315 0 + +[50 rows x 5 columns] +``` + +通过 nrows 参数可以读取指定行数: + +```python +>>> import pandas as pd +>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', nrows=5) + one two three four key +0 0.467976 -0.038649 -0.295344 -1.824726 L +1 -0.358893 1.404453 0.704965 -0.200638 B +2 -0.501840 0.659254 -0.421691 -0.057688 G +3 0.204886 1.074134 1.388361 -0.982404 R +4 0.354628 -0.133116 0.283763 -0.837063 Q +``` + +要逐块读取文件,可以指定 chunksize(行数): + +```python +>>> import pandas as pd +>>> chunker = pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', chunksize=50) +>>> chunker + +``` + +返回的 TextParser 对象,可以根据 chunksize 对文件进行逐块迭代。以下示例中,对 test6.csv 文件数据进行迭代处理,将值计数聚合到 "key" 列中: + +```python +>>> import pandas as pd +>>> chunker = pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', chunksize=50) +>>> tot = pd.Series([], dtype='float64') +>>> for piece in chunker: + tot = tot.add(piece['key'].value_counts(), fill_value=0) + + +>>> tot = tot.sort_values(ascending=False) +>>> tot[:10] +G 6.0 +E 5.0 +B 5.0 +L 5.0 +0 5.0 +K 4.0 +A 4.0 +R 4.0 +C 2.0 +Q 2.0 +dtype: float64 +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106963135 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【02x00】写入数据 + +Pandas 提供了一些用于将表格型数据读取为 DataFrame 对象的函数。常见方法如下: + +| 函数 | 描述 | +| ------ | ------ | +| to_csv | 将对象写入逗号分隔值(csv)文件 | +| to_clipboard | 将对象复制到系统剪贴板 | +| to_excel | 将对象写入 Excel 工作表 | +| to_hdf | 使用 HDFStore 将包含的数据写入 HDF5 文件 | +| to_html | 将 DataFrame 呈现为 HTML 表格 | +| to_json | 将对象转换为 JSON( JavaScript Object Notation)字符串 | +| to_msgpack | 将对象写入二进制格式编码的文件(Pandas v1.0.0 中已删除对 msgpack 的支持,建议使用 [pyarrow](https://pandas.pydata.org/docs/user_guide/io.html#io-msgpack)) | +| to_pickle | Pickle(序列化)对象到文件 | +| to_sql | 将存储在 DataFrame 中的数据写入 SQL 数据库 | +| to_stata | 将 DataFrame 对象导出为 Stata 格式 | +| to_feather | 将 DataFrames 写入 Feather 二进制格式文件 | + +以下以 to_csv 为例,它的参数同样多达 50 多个,具体可参见官方文档: + +- [https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html) + +- [https://pandas.pydata.org/docs/reference/api/pandas.Series.to_csv.html](https://pandas.pydata.org/docs/reference/api/pandas.Series.to_csv.html) + +### 【02x01】简单示例 + +以之前的 test5.csv 文件为例,先读出数据,再将数据写入另外的文件: + +```python +>>> import pandas as pd +>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> data + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> data.to_csv(r'C:\Users\TanRe\Desktop\out1.csv') +``` + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/09.png) + +### 【02x02】sep 指定分隔符 + +sep 参数可用于其他分隔符: + +```python +>>> import pandas as pd +>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> data + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> data.to_csv(r'C:\Users\TanRe\Desktop\out2.csv', sep='|') +``` + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/10.png) + +### 【02x03】na_rep 替换缺失值 + +na_rep 参数可将缺失值(NaN)替换成其他字符串: + +```python +>>> import pandas as pd +>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> data + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> data.to_csv(r'C:\Users\TanRe\Desktop\out3.csv', na_rep='X') +``` + +![11](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/11.png) + +### 【02x04】index / header 行与列标签 + +设置 `index=False`, `header=False`,可以禁用行标签与列标签: + +```python +>>> import pandas as pd +>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> data + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> data.to_csv(r'C:\Users\TanRe\Desktop\out4.csv', index=False, header=False) +``` + +![12](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/12.png) + +还可以传入列表来重新设置列标签: + +```python +>>> import pandas as pd +>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> data + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> data.to_csv(r'C:\Users\TanRe\Desktop\out5.csv', header=['a', 'b', 'c', 'd', 'e', 'f']) +``` + +![13](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/13.png) + +### 【02x05】columns 指定列 + +可以通过设置 columns 参数,只写入部分列,并按照指定顺序排序: + +```python +>>> import pandas as pd +>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv') +>>> data + something a b c d message +0 one 1 2 3.0 4 NaN +1 two 5 6 NaN 8 world +2 three 9 10 11.0 12 python +>>> +>>> data.to_csv(r'C:\Users\TanRe\Desktop\out6.csv', columns=['c', 'b', 'a']) +``` + +![14](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A88/14.png) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/106963135 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A89-COVID-19.md b/source/_posts/A89-COVID-19.md new file mode 100644 index 0000000000000000000000000000000000000000..2368e1e0c9e43444ef348130f3e721c885dc1518 --- /dev/null +++ b/source/_posts/A89-COVID-19.md @@ -0,0 +1,1075 @@ +--- +title: COVID-19 肺炎疫情数据实时监控(python 爬虫 + pyecharts 数据可视化 + wordcloud 词云图) +tags: + - 爬虫 + - 肺炎疫情 +categories: + - Python3 学习笔记 + - 爬虫实战 +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/virus.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: COVID-19 肺炎疫情数据实时监控,基于 python 爬虫 + pyecharts 数据可视化 + wordcloud 词云图实现。 +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/107140534 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【1x00】前言 + +本来两三个月之前就想搞个疫情数据实时数据展示的,由于各种不可抗拒因素一而再再而三的鸽了,最近终于抽空写了一个,数据是用 Python 爬取的[百度疫情实时大数据报告](https://voice.baidu.com/act/newpneumonia/newpneumonia/),请求库用的 requests,解析用的 Xpath 语法,词云用的 wordcloud 库,数据可视化用 pyecharts 绘制的地图和折线图,数据储存在 Excel 表格里面,使用 openpyxl 对表格进行处理。 + +本程序实现了累计确诊地图展示和每日数据变化折线图展示,其他更多数据的获取和展示均可在程序中进行拓展,可以将程序部署在服务器上,设置定时运行,即可实时展示数据,pyecharts 绘图模块也可以整合到 Web 框架(Django、Flask等)中使用。 + +在获取数据时有**全球****境外**两个概念,全球包含中国,境外不包含中国,后期绘制的四个图:中国累计确诊地图、全球累计确诊地图(包含中国)、中国每日数据折线图、境外每日数据折线图(不包含中国)。 + +**注意项:直接向该网页发送请求获取的响应中,没有每个国家的每日数据,该数据获取的地址是:[https://voice.baidu.com/newpneumonia/get?target=trend&isCaseIn=1&stage=publish](https://voice.baidu.com/newpneumonia/get?target=trend&isCaseIn=1&stage=publish)** + + +- **预览地址**:[http://cov.itrhx.com/](http://cov.itrhx.com/) + +- **数据来源**:[https://voice.baidu.com/act/newpneumonia/newpneumonia/](https://voice.baidu.com/act/newpneumonia/newpneumonia/) + +- **pyecharts 文档**:[https://pyecharts.org/](https://pyecharts.org/) + +- **openpyxl 文档**:[https://openpyxl.readthedocs.io/](https://openpyxl.readthedocs.io/) + +- **wordcloud 文档**:[http://amueller.github.io/word_cloud/](http://amueller.github.io/word_cloud/) + +## 【2x00】思维导图 + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A89/01.png) + +## 【3x00】数据结构分析 + +通过查看百度的疫情数据页面,可以看到很多整齐的数据,猜测就是疫情相关的数据,保存该页面,对其进行格式化,很容易可以分析出所有的数据都在 `` 里面,其中 title 里面是一些 Unicode 编码,将其转为中文后更容易得到不同的分类数据。 + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A89/02.png) + +由于数据繁多,可以将数据主体部分提取出来,删除一些重复项和其他杂项,留下数据大体位置并分析数据结构,便于后期的数据提取,经过处理后的数据大致结构如下: + +```json + +``` + +## 【4x00】主函数 main() + +分别将数据获取、词云图绘制、地图绘制写入三个文件:`data_get()`、`data_wordcloud()`、`data_map()`,然后使用一个主函数文件 main.py 来调用这三个文件里面的函数。 + +```python +import data_get +import data_wordcloud +import data_map + +data_dict = data_get.init() +data_get.china_total_data(data_dict) +data_get.global_total_data(data_dict) +data_get.china_daily_data(data_dict) +data_get.foreign_daily_data(data_dict) + +data_wordcloud.china_wordcloud() +data_wordcloud.global_wordcloud() + +data_map.all_map() +``` + +## 【5x00】数据获取模块 data_get + +### 【5x01】初始化函数 init() + +使用 xpath 语法 `//script[@id="captain-config"]/text()` 提取里面的值,利用 `json.loads` 方法将其转换为字典对象,以便后续的其他函数调用。 + +```python +def init(): + headers = { + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.13 Safari/537.36' + } + url = 'https://voice.baidu.com/act/newpneumonia/newpneumonia/' + response = requests.get(url=url, headers=headers) + tree = etree.HTML(response.text) + dict1 = tree.xpath('//script[@id="captain-config"]/text()') + print(type(dict1[0])) + dict2 = json.loads(dict1[0]) + return dict2 +``` + +### 【5x02】中国总数据 china_total_data() + +```python +def china_total_data(data): + + """ + 1、中国省/直辖市/自治区/行政区疫情数据 + 省/直辖市/自治区/行政区:area + 现有确诊: curConfirm + 累计确诊: confirmed + 累计治愈: crued + 累计死亡: died + 现有确诊增量: curConfirmRelative + 累计确诊增量: confirmedRelative + 累计治愈增量: curedRelative + 累计死亡增量: diedRelative + """ + + wb = openpyxl.Workbook() # 创建工作簿 + ws_china = wb.active # 获取工作表 + ws_china.title = "中国省份疫情数据" # 命名工作表 + ws_china.append(['省/直辖市/自治区/行政区', '现有确诊', '累计确诊', '累计治愈', + '累计死亡', '现有确诊增量', '累计确诊增量', + '累计治愈增量', '累计死亡增量']) + china = data['component'][0]['caseList'] + for province in china: + ws_china.append([province['area'], + province['curConfirm'], + province['confirmed'], + province['crued'], + province['died'], + province['curConfirmRelative'], + province['confirmedRelative'], + province['curedRelative'], + province['diedRelative']]) + + """ + 2、中国城市疫情数据 + 城市:city + 现有确诊:curConfirm + 累计确诊:confirmed + 累计治愈:crued + 累计死亡:died + 累计确诊增量:confirmedRelative + """ + + ws_city = wb.create_sheet('中国城市疫情数据') + ws_city.append(['城市', '现有确诊', '累计确诊', + '累计治愈', '累计死亡', '累计确诊增量']) + for province in china: + for city in province['subList']: + # 某些城市没有 curConfirm 数据,则将其设置为 0,crued 和 died 为空时,替换成 0 + if 'curConfirm' not in city: + city['curConfirm'] = '0' + if city['crued'] == '': + city['crued'] = '0' + if city['died'] == '': + city['died'] = '0' + ws_city.append([city['city'], '0', city['confirmed'], + city['crued'], city['died'], city['confirmedRelative']]) + + """ + 3、中国疫情数据更新时间:mapLastUpdatedTime + """ + + time_domestic = data['component'][0]['mapLastUpdatedTime'] + ws_time = wb.create_sheet('中国疫情数据更新时间') + ws_time.column_dimensions['A'].width = 22 # 调整列宽 + ws_time.append(['中国疫情数据更新时间']) + ws_time.append([time_domestic]) + + wb.save('COVID-19-China.xlsx') + print('中国疫情数据已保存至 COVID-19-China.xlsx!') +``` + +### 【5x03】全球总数据 global_total_data() + +全球总数据在提取完成后,进行地图绘制时发现并没有中国的数据,因此在写入全球数据时注意要单独将中国的数据插入 Excel 中。 + +```python +def global_total_data(data): + + """ + 1、全球各国疫情数据 + 国家:country + 现有确诊:curConfirm + 累计确诊:confirmed + 累计治愈:crued + 累计死亡:died + 累计确诊增量:confirmedRelative + """ + + wb = openpyxl.Workbook() + ws_global = wb.active + ws_global.title = "全球各国疫情数据" + + # 按照国家保存数据 + countries = data['component'][0]['caseOutsideList'] + ws_global.append(['国家', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) + for country in countries: + ws_global.append([country['area'], + country['curConfirm'], + country['confirmed'], + country['crued'], + country['died'], + country['confirmedRelative']]) + + # 按照洲保存数据 + continent = data['component'][0]['globalList'] + for area in continent: + ws_foreign = wb.create_sheet(area['area'] + '疫情数据') + ws_foreign.append(['国家', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) + for country in area['subList']: + ws_foreign.append([country['country'], + country['curConfirm'], + country['confirmed'], + country['crued'], + country['died'], + country['confirmedRelative']]) + + # 在“全球各国疫情数据”和“亚洲疫情数据”两张表中写入中国疫情数据 + ws1, ws2 = wb['全球各国疫情数据'], wb['亚洲疫情数据'] + original_data = data['component'][0]['summaryDataIn'] + add_china_data = ['中国', + original_data['curConfirm'], + original_data['confirmed'], + original_data['cured'], + original_data['died'], + original_data['confirmedRelative']] + ws1.append(add_china_data) + ws2.append(add_china_data) + + """ + 2、全球疫情数据更新时间:foreignLastUpdatedTime + """ + + time_foreign = data['component'][0]['foreignLastUpdatedTime'] + ws_time = wb.create_sheet('全球疫情数据更新时间') + ws_time.column_dimensions['A'].width = 22 # 调整列宽 + ws_time.append(['全球疫情数据更新时间']) + ws_time.append([time_foreign]) + + wb.save('COVID-19-Global.xlsx') + print('全球疫情数据已保存至 COVID-19-Global.xlsx!') +``` + +### 【5x04】中国每日数据 china_daily_data() + +```python +def china_daily_data(data): + + """ + i_dict = data['component'][0]['trend'] + i_dict['updateDate']:日期 + i_dict['list'][0]:确诊 + i_dict['list'][1]:疑似 + i_dict['list'][2]:治愈 + i_dict['list'][3]:死亡 + i_dict['list'][4]:新增确诊 + i_dict['list'][5]:新增疑似 + i_dict['list'][6]:新增治愈 + i_dict['list'][7]:新增死亡 + i_dict['list'][8]:累计境外输入 + i_dict['list'][9]:新增境外输入 + """ + + ccd_dict = data['component'][0]['trend'] + update_date = ccd_dict['updateDate'] # 日期 + china_confirmed = ccd_dict['list'][0]['data'] # 每日累计确诊数据 + china_crued = ccd_dict['list'][2]['data'] # 每日累计治愈数据 + china_died = ccd_dict['list'][3]['data'] # 每日累计死亡数据 + wb = openpyxl.load_workbook('COVID-19-China.xlsx') + + # 写入每日累计确诊数据 + ws_china_confirmed = wb.create_sheet('中国每日累计确诊数据') + ws_china_confirmed.append(['日期', '数据']) + for data in zip(update_date, china_confirmed): + ws_china_confirmed.append(data) + + # 写入每日累计治愈数据 + ws_china_crued = wb.create_sheet('中国每日累计治愈数据') + ws_china_crued.append(['日期', '数据']) + for data in zip(update_date, china_crued): + ws_china_crued.append(data) + + # 写入每日累计死亡数据 + ws_china_died = wb.create_sheet('中国每日累计死亡数据') + ws_china_died.append(['日期', '数据']) + for data in zip(update_date, china_died): + ws_china_died.append(data) + + wb.save('COVID-19-China.xlsx') + print('中国每日累计确诊/治愈/死亡数据已保存至 COVID-19-China.xlsx!') +``` + +### 【5x05】境外每日数据 foreign_daily_data() + +```python +def foreign_daily_data(data): + + """ + te_dict = data['component'][0]['allForeignTrend'] + te_dict['updateDate']:日期 + te_dict['list'][0]:累计确诊 + te_dict['list'][1]:治愈 + te_dict['list'][2]:死亡 + te_dict['list'][3]:现有确诊 + te_dict['list'][4]:新增确诊 + """ + + te_dict = data['component'][0]['allForeignTrend'] + update_date = te_dict['updateDate'] # 日期 + foreign_confirmed = te_dict['list'][0]['data'] # 每日累计确诊数据 + foreign_crued = te_dict['list'][1]['data'] # 每日累计治愈数据 + foreign_died = te_dict['list'][2]['data'] # 每日累计死亡数据 + wb = openpyxl.load_workbook('COVID-19-Global.xlsx') + + # 写入每日累计确诊数据 + ws_foreign_confirmed = wb.create_sheet('境外每日累计确诊数据') + ws_foreign_confirmed.append(['日期', '数据']) + for data in zip(update_date, foreign_confirmed): + ws_foreign_confirmed.append(data) + + # 写入累计治愈数据 + ws_foreign_crued = wb.create_sheet('境外每日累计治愈数据') + ws_foreign_crued.append(['日期', '数据']) + for data in zip(update_date, foreign_crued): + ws_foreign_crued.append(data) + + # 写入累计死亡数据 + ws_foreign_died = wb.create_sheet('境外每日累计死亡数据') + ws_foreign_died.append(['日期', '数据']) + for data in zip(update_date, foreign_died): + ws_foreign_died.append(data) + + wb.save('COVID-19-Global.xlsx') + print('境外每日累计确诊/治愈/死亡数据已保存至 COVID-19-Global.xlsx!') +``` + +## 【6x00】词云图绘制模块 data_wordcloud + +### 【6x01】中国累计确诊词云图 foreign_daily_data() + +```python +def china_wordcloud(): + wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 获取已有的xlsx文件 + ws_china = wb['中国省份疫情数据'] # 获取中国省份疫情数据表 + ws_china.delete_rows(1) # 删除第一行 + china_dict = {} # 将省份及其累计确诊按照键值对形式储存在字典中 + for data in ws_china.values: + china_dict[data[0]] = int(data[2]) + word_cloud = wordcloud.WordCloud(font_path='C:/Windows/Fonts/simsun.ttc', + background_color='#CDC9C9', + min_font_size=15, + width=900, height=500) + word_cloud.generate_from_frequencies(china_dict) + word_cloud.to_file('WordCloud-China.png') + print('中国省份疫情词云图绘制完毕!') +``` + +### 【6x02】全球累计确诊词云图 foreign_daily_data() + +```python +def global_wordcloud(): + wb = openpyxl.load_workbook('COVID-19-Global.xlsx') + ws_global = wb['全球各国疫情数据'] + ws_global.delete_rows(1) + global_dict = {} + for data in ws_global.values: + global_dict[data[0]] = int(data[2]) + word_cloud = wordcloud.WordCloud(font_path='C:/Windows/Fonts/simsun.ttc', + background_color='#CDC9C9', + width=900, height=500) + word_cloud.generate_from_frequencies(global_dict) + word_cloud.to_file('WordCloud-Global.png') + print('全球各国疫情词云图绘制完毕!') +``` + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/107140534 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- + +## 【7x00】地图绘制模块 data_map + +### 【7x01】中国累计确诊地图 china_total_map() + +```python +def china_total_map(): + wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 获取已有的xlsx文件 + ws_time = wb['中国疫情数据更新时间'] # 获取文件中中国疫情数据更新时间表 + ws_data = wb['中国省份疫情数据'] # 获取文件中中国省份疫情数据表 + ws_data.delete_rows(1) # 删除第一行 + province = [] # 省份 + curconfirm = [] # 累计确诊 + for data in ws_data.values: + province.append(data[0]) + curconfirm.append(data[2]) + time_china = ws_time['A2'].value # 更新时间 + + # 设置分级颜色 + pieces = [ + {'max': 0, 'min': 0, 'label': '0', 'color': '#FFFFFF'}, + {'max': 9, 'min': 1, 'label': '1-9', 'color': '#FFE5DB'}, + {'max': 99, 'min': 10, 'label': '10-99', 'color': '#FF9985'}, + {'max': 999, 'min': 100, 'label': '100-999', 'color': '#F57567'}, + {'max': 9999, 'min': 1000, 'label': '1000-9999', 'color': '#E64546'}, + {'max': 99999, 'min': 10000, 'label': '≧10000', 'color': '#B80909'} + ] + + # 绘制地图 + ct_map = ( + Map() + .add(series_name='累计确诊人数', data_pair=[list(z) for z in zip(province, curconfirm)], maptype="china") + .set_global_opts( + title_opts=opts.TitleOpts(title="中国疫情数据(累计确诊)", + subtitle='数据更新至:' + time_china + '\n\n来源:百度疫情实时大数据报告'), + visualmap_opts=opts.VisualMapOpts(max_=300, is_piecewise=True, pieces=pieces) + ) + ) + return ct_map +``` + +### 【7x02】全球累计确诊地图 global_total_map() + +```python +def global_total_map(): + wb = openpyxl.load_workbook('COVID-19-Global.xlsx') + ws_time = wb['全球疫情数据更新时间'] + ws_data = wb['全球各国疫情数据'] + ws_data.delete_rows(1) + country = [] # 国家 + curconfirm = [] # 累计确诊 + for data in ws_data.values: + country.append(data[0]) + curconfirm.append(data[2]) + time_global = ws_time['A2'].value # 更新时间 + + # 国家名称中英文映射表 + name_map = { + "Somalia": "索马里", + "Liechtenstein": "列支敦士登", + "Morocco": "摩洛哥", + "W. Sahara": "西撒哈拉", + "Serbia": "塞尔维亚", + "Afghanistan": "阿富汗", + "Angola": "安哥拉", + "Albania": "阿尔巴尼亚", + "Andorra": "安道尔共和国", + "United Arab Emirates": "阿拉伯联合酋长国", + "Argentina": "阿根廷", + "Armenia": "亚美尼亚", + "Australia": "澳大利亚", + "Austria": "奥地利", + "Azerbaijan": "阿塞拜疆", + "Burundi": "布隆迪", + "Belgium": "比利时", + "Benin": "贝宁", + "Burkina Faso": "布基纳法索", + "Bangladesh": "孟加拉国", + "Bulgaria": "保加利亚", + "Bahrain": "巴林", + "Bahamas": "巴哈马", + "Bosnia and Herz.": "波斯尼亚和黑塞哥维那", + "Belarus": "白俄罗斯", + "Belize": "伯利兹", + "Bermuda": "百慕大", + "Bolivia": "玻利维亚", + "Brazil": "巴西", + "Barbados": "巴巴多斯", + "Brunei": "文莱", + "Bhutan": "不丹", + "Botswana": "博茨瓦纳", + "Central African Rep.": "中非共和国", + "Canada": "加拿大", + "Switzerland": "瑞士", + "Chile": "智利", + "China": "中国", + "Côte d'Ivoire": "科特迪瓦", + "Cameroon": "喀麦隆", + "Dem. Rep. Congo": "刚果(布)", + "Congo": "刚果(金)", + "Colombia": "哥伦比亚", + "Cape Verde": "佛得角", + "Costa Rica": "哥斯达黎加", + "Cuba": "古巴", + "N. Cyprus": "北塞浦路斯", + "Cyprus": "塞浦路斯", + "Czech Rep.": "捷克", + "Germany": "德国", + "Djibouti": "吉布提", + "Denmark": "丹麦", + "Dominican Rep.": "多米尼加", + "Algeria": "阿尔及利亚", + "Ecuador": "厄瓜多尔", + "Egypt": "埃及", + "Eritrea": "厄立特里亚", + "Spain": "西班牙", + "Estonia": "爱沙尼亚", + "Ethiopia": "埃塞俄比亚", + "Finland": "芬兰", + "Fiji": "斐济", + "France": "法国", + "Gabon": "加蓬", + "United Kingdom": "英国", + "Georgia": "格鲁吉亚", + "Ghana": "加纳", + "Guinea": "几内亚", + "Gambia": "冈比亚", + "Guinea-Bissau": "几内亚比绍", + "Eq. Guinea": "赤道几内亚", + "Greece": "希腊", + "Grenada": "格林纳达", + "Greenland": "格陵兰岛", + "Guatemala": "危地马拉", + "Guam": "关岛", + "Guyana": "圭亚那合作共和国", + "Honduras": "洪都拉斯", + "Croatia": "克罗地亚", + "Haiti": "海地", + "Hungary": "匈牙利", + "Indonesia": "印度尼西亚", + "India": "印度", + "Br. Indian Ocean Ter.": "英属印度洋领土", + "Ireland": "爱尔兰", + "Iran": "伊朗", + "Iraq": "伊拉克", + "Iceland": "冰岛", + "Israel": "以色列", + "Italy": "意大利", + "Jamaica": "牙买加", + "Jordan": "约旦", + "Japan": "日本", + "Siachen Glacier": "锡亚琴冰川", + "Kazakhstan": "哈萨克斯坦", + "Kenya": "肯尼亚", + "Kyrgyzstan": "吉尔吉斯斯坦", + "Cambodia": "柬埔寨", + "Korea": "韩国", + "Kuwait": "科威特", + "Lao PDR": "老挝", + "Lebanon": "黎巴嫩", + "Liberia": "利比里亚", + "Libya": "利比亚", + "Sri Lanka": "斯里兰卡", + "Lesotho": "莱索托", + "Lithuania": "立陶宛", + "Luxembourg": "卢森堡", + "Latvia": "拉脱维亚", + "Moldova": "摩尔多瓦", + "Madagascar": "马达加斯加", + "Mexico": "墨西哥", + "Macedonia": "马其顿", + "Mali": "马里", + "Malta": "马耳他", + "Myanmar": "缅甸", + "Montenegro": "黑山", + "Mongolia": "蒙古国", + "Mozambique": "莫桑比克", + "Mauritania": "毛里塔尼亚", + "Mauritius": "毛里求斯", + "Malawi": "马拉维", + "Malaysia": "马来西亚", + "Namibia": "纳米比亚", + "New Caledonia": "新喀里多尼亚", + "Niger": "尼日尔", + "Nigeria": "尼日利亚", + "Nicaragua": "尼加拉瓜", + "Netherlands": "荷兰", + "Norway": "挪威", + "Nepal": "尼泊尔", + "New Zealand": "新西兰", + "Oman": "阿曼", + "Pakistan": "巴基斯坦", + "Panama": "巴拿马", + "Peru": "秘鲁", + "Philippines": "菲律宾", + "Papua New Guinea": "巴布亚新几内亚", + "Poland": "波兰", + "Puerto Rico": "波多黎各", + "Dem. Rep. Korea": "朝鲜", + "Portugal": "葡萄牙", + "Paraguay": "巴拉圭", + "Palestine": "巴勒斯坦", + "Qatar": "卡塔尔", + "Romania": "罗马尼亚", + "Russia": "俄罗斯", + "Rwanda": "卢旺达", + "Saudi Arabia": "沙特阿拉伯", + "Sudan": "苏丹", + "S. Sudan": "南苏丹", + "Senegal": "塞内加尔", + "Singapore": "新加坡", + "Solomon Is.": "所罗门群岛", + "Sierra Leone": "塞拉利昂", + "El Salvador": "萨尔瓦多", + "Suriname": "苏里南", + "Slovakia": "斯洛伐克", + "Slovenia": "斯洛文尼亚", + "Sweden": "瑞典", + "Swaziland": "斯威士兰", + "Seychelles": "塞舌尔", + "Syria": "叙利亚", + "Chad": "乍得", + "Togo": "多哥", + "Thailand": "泰国", + "Tajikistan": "塔吉克斯坦", + "Turkmenistan": "土库曼斯坦", + "Timor-Leste": "东帝汶", + "Tonga": "汤加", + "Trinidad and Tobago": "特立尼达和多巴哥", + "Tunisia": "突尼斯", + "Turkey": "土耳其", + "Tanzania": "坦桑尼亚", + "Uganda": "乌干达", + "Ukraine": "乌克兰", + "Uruguay": "乌拉圭", + "United States": "美国", + "Uzbekistan": "乌兹别克斯坦", + "Venezuela": "委内瑞拉", + "Vietnam": "越南", + "Vanuatu": "瓦努阿图", + "Yemen": "也门", + "South Africa": "南非", + "Zambia": "赞比亚", + "Zimbabwe": "津巴布韦", + "Aland": "奥兰群岛", + "American Samoa": "美属萨摩亚", + "Fr. S. Antarctic Lands": "南极洲", + "Antigua and Barb.": "安提瓜和巴布达", + "Comoros": "科摩罗", + "Curaçao": "库拉索岛", + "Cayman Is.": "开曼群岛", + "Dominica": "多米尼加", + "Falkland Is.": "福克兰群岛马尔维纳斯", + "Faeroe Is.": "法罗群岛", + "Micronesia": "密克罗尼西亚", + "Heard I. and McDonald Is.": "赫德岛和麦克唐纳群岛", + "Isle of Man": "曼岛", + "Jersey": "泽西岛", + "Kiribati": "基里巴斯", + "Saint Lucia": "圣卢西亚", + "N. Mariana Is.": "北马里亚纳群岛", + "Montserrat": "蒙特塞拉特", + "Niue": "纽埃", + "Palau": "帕劳", + "Fr. Polynesia": "法属波利尼西亚", + "S. Geo. and S. Sandw. Is.": "南乔治亚岛和南桑威奇群岛", + "Saint Helena": "圣赫勒拿", + "St. Pierre and Miquelon": "圣皮埃尔和密克隆群岛", + "São Tomé and Principe": "圣多美和普林西比", + "Turks and Caicos Is.": "特克斯和凯科斯群岛", + "St. Vin. and Gren.": "圣文森特和格林纳丁斯", + "U.S. Virgin Is.": "美属维尔京群岛", + "Samoa": "萨摩亚" + } + + pieces = [ + {'max': 0, 'min': 0, 'label': '0', 'color': '#FFFFFF'}, + {'max': 49, 'min': 1, 'label': '1-49', 'color': '#FFE5DB'}, + {'max': 99, 'min': 50, 'label': '50-99', 'color': '#FFC4B3'}, + {'max': 999, 'min': 100, 'label': '100-999', 'color': '#FF9985'}, + {'max': 9999, 'min': 1000, 'label': '1000-9999', 'color': '#F57567'}, + {'max': 99999, 'min': 10000, 'label': '10000-99999', 'color': '#E64546'}, + {'max': 999999, 'min': 100000, 'label': '100000-999999', 'color': '#B80909'}, + {'max': 9999999, 'min': 1000000, 'label': '≧1000000', 'color': '#8A0808'} + ] + + gt_map = ( + Map() + .add(series_name='累计确诊人数', data_pair=[list(z) for z in zip(country, curconfirm)], maptype="world", name_map=name_map, is_map_symbol_show=False) + .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) + .set_global_opts( + title_opts=opts.TitleOpts(title="全球疫情数据(累计确诊)", + subtitle='数据更新至:' + time_global + '\n\n来源:百度疫情实时大数据报告'), + visualmap_opts=opts.VisualMapOpts(max_=300, is_piecewise=True, pieces=pieces), + ) + ) + return gt_map +``` + +### 【7x03】中国每日数据折线图 china_daily_map() + +```python +def china_daily_map(): + wb = openpyxl.load_workbook('COVID-19-China.xlsx') + ws_china_confirmed = wb['中国每日累计确诊数据'] + ws_china_crued = wb['中国每日累计治愈数据'] + ws_china_died = wb['中国每日累计死亡数据'] + + ws_china_confirmed.delete_rows(1) + ws_china_crued.delete_rows(1) + ws_china_died.delete_rows(1) + + x_date = [] # 日期 + y_china_confirmed = [] # 每日累计确诊 + y_china_crued = [] # 每日累计治愈 + y_china_died = [] # 每日累计死亡 + + for china_confirmed in ws_china_confirmed.values: + y_china_confirmed.append(china_confirmed[1]) + for china_crued in ws_china_crued.values: + x_date.append(china_crued[0]) + y_china_crued.append(china_crued[1]) + for china_died in ws_china_died.values: + y_china_died.append(china_died[1]) + + fi_map = ( + Line(init_opts=opts.InitOpts(height='420px')) + .add_xaxis(xaxis_data=x_date) + .add_yaxis( + series_name="中国累计确诊数据", + y_axis=y_china_confirmed, + label_opts=opts.LabelOpts(is_show=False), + ) + .add_yaxis( + series_name="中国累计治愈趋势", + y_axis=y_china_crued, + label_opts=opts.LabelOpts(is_show=False), + ) + .add_yaxis( + series_name="中国累计死亡趋势", + y_axis=y_china_died, + label_opts=opts.LabelOpts(is_show=False), + ) + .set_global_opts( + title_opts=opts.TitleOpts(title="中国每日累计确诊/治愈/死亡趋势"), + legend_opts=opts.LegendOpts(pos_bottom="bottom", orient='horizontal'), + tooltip_opts=opts.TooltipOpts(trigger="axis"), + yaxis_opts=opts.AxisOpts( + type_="value", + axistick_opts=opts.AxisTickOpts(is_show=True), + splitline_opts=opts.SplitLineOpts(is_show=True), + ), + xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False), + ) + ) + return fi_map +``` + +### 【7x04】境外每日数据折线图 foreign_daily_map() + +```python +def foreign_daily_map(): + wb = openpyxl.load_workbook('COVID-19-Global.xlsx') + ws_foreign_confirmed = wb['境外每日累计确诊数据'] + ws_foreign_crued = wb['境外每日累计治愈数据'] + ws_foreign_died = wb['境外每日累计死亡数据'] + + ws_foreign_confirmed.delete_rows(1) + ws_foreign_crued.delete_rows(1) + ws_foreign_died.delete_rows(1) + + x_date = [] # 日期 + y_foreign_confirmed = [] # 累计确诊 + y_foreign_crued = [] # 累计治愈 + y_foreign_died = [] # 累计死亡 + + for foreign_confirmed in ws_foreign_confirmed.values: + y_foreign_confirmed.append(foreign_confirmed[1]) + for foreign_crued in ws_foreign_crued.values: + x_date.append(foreign_crued[0]) + y_foreign_crued.append(foreign_crued[1]) + for foreign_died in ws_foreign_died.values: + y_foreign_died.append(foreign_died[1]) + + fte_map = ( + Line(init_opts=opts.InitOpts(height='420px')) + .add_xaxis(xaxis_data=x_date) + .add_yaxis( + series_name="境外累计确诊趋势", + y_axis=y_foreign_confirmed, + label_opts=opts.LabelOpts(is_show=False), + ) + .add_yaxis( + series_name="境外累计治愈趋势", + y_axis=y_foreign_crued, + label_opts=opts.LabelOpts(is_show=False), + ) + .add_yaxis( + series_name="境外累计死亡趋势", + y_axis=y_foreign_died, + label_opts=opts.LabelOpts(is_show=False), + ) + .set_global_opts( + title_opts=opts.TitleOpts(title="境外每日累计确诊/治愈/死亡趋势"), + legend_opts=opts.LegendOpts(pos_bottom="bottom", orient='horizontal'), + tooltip_opts=opts.TooltipOpts(trigger="axis"), + yaxis_opts=opts.AxisOpts( + type_="value", + axistick_opts=opts.AxisTickOpts(is_show=True), + splitline_opts=opts.SplitLineOpts(is_show=True), + ), + xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False), + ) + ) + return fte_map +``` + +## 【8x00】结果截图 + +### 【8x01】数据储存 Excel + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A89/03.png) + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A89/04.png) + +### 【8x02】词云图 + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A89/05.png) + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A89/06.png) + +### 【8x03】地图 + 折线图 + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A89/07.png) + +## 【9x00】完整代码 + +预览地址:[http://cov.itrhx.com/](http://cov.itrhx.com/) + +完整代码地址(点亮 star 有 buff 加成):[https://github.com/TRHX/Python3-Spider-Practice/tree/master/COVID-19](https://github.com/TRHX/Python3-Spider-Practice/tree/master/COVID-19) + +其他爬虫实战代码合集(持续更新):[https://github.com/TRHX/Python3-Spider-Practice](https://github.com/TRHX/Python3-Spider-Practice) + +爬虫实战专栏(持续更新):[https://itrhx.blog.csdn.net/article/category/9351278](https://itrhx.blog.csdn.net/article/category/9351278) + +--- + +```yaml +这里是一段防爬虫文本,请读者忽略。 +本文原创首发于 CSDN,作者 TRHX。 +博客首页:https://itrhx.blog.csdn.net/ +本文链接:https://itrhx.blog.csdn.net/article/details/107140534 +未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! +``` + +--- diff --git a/source/_posts/A90-pyspider-51job.md b/source/_posts/A90-pyspider-51job.md new file mode 100644 index 0000000000000000000000000000000000000000..753437c60e68d53b4116fe522db64d0c3a083173 --- /dev/null +++ b/source/_posts/A90-pyspider-51job.md @@ -0,0 +1,377 @@ +--- +title: 前程无忧招聘信息爬取 + 数据可视化 +tags: + - 爬虫 + - 前程无忧 + - 数据可视化 +categories: + - Python3 学习笔记 + - 爬虫实战 +thumbnail: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/thumbnail/51job.png +avatar: https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.1.9/images/trhx.png +description: 利用 Python 根据用户输入的关键字爬取相关职位信息并存入 MongoDB,对数据进行清洗并可视化展示。 +--- + +- 爬取时间:2020-07-11 +- 实现目标:根据用户输入的关键字爬取相关职位信息存入 MongoDB,读取数据进行可视化展示。 +- 涉及知识:请求库 requests、Xpath 语法、数据库 MongoDB、数据处理与可视化 Numpy、Pandas、Matplotlib。 +- 完整代码:[https://github.com/TRHX/Python3-Spider-Practice/tree/master/51job](https://github.com/TRHX/Python3-Spider-Practice/tree/master/51job) +- 其他爬虫实战代码合集(持续更新):[https://github.com/TRHX/Python3-Spider-Practice](https://github.com/TRHX/Python3-Spider-Practice) +- 爬虫实战专栏(持续更新):[https://itrhx.blog.csdn.net/article/category/9351278](https://itrhx.blog.csdn.net/article/category/9351278) + +--- + +## 【1x00】获取数据 get_51job_data.py + +### 【01x01】构建请求地址 + +以 Python 职位为例,请求地址如下: + +第一页:https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,1.html + +第二页:https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,2.html + +第三页:https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,3.html + +初始化函数: + +```python + def __init__(self): + self.base_url = 'https://search.51job.com/list/000000,000000,0000,00,9,99,%s,2,%s.html' + self.headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.13 Safari/537.36'} + self.keyword = input('请输入关键字:') +``` + +### 【01x02】获取总页数 + +在页面的下方给出了该职位一共有多少页,使用 Xpath 和正则表达式提取里面的数字,方便后面翻页爬取使用,注意页面编码为 `gbk`。 + +![01](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/01.png) + +```python + def tatal_url(self): + url = self.base_url % (self.keyword, str(1)) + response = requests.get(url=url, headers=self.headers) + tree = etree.HTML(response.content.decode('gbk')) + # 提取一共有多少页 + text = tree.xpath("//div[@class='p_in']/span[1]/text()")[0] + number = re.findall('[0-9]', text) + number = int(''.join(number)) + print('%s职位共有%d页' % (self.keyword, number)) + return number +``` + +### 【01x03】提取详情页 URL + +定义一个 `detail_url()` 方法,传入总页数,循环提取每一页职位详情页的 URL,将每一个详情页 URL 传递给 `parse_data()` 方法,用于解析详情页内的具体职位信息。 + +提取详情页时有以下几种特殊情况: + +**特殊情况一:**如果有前程无忧自己公司的职位招聘信息掺杂在里面,他的详情页结构和普通的不一样,页面编码也有差别。 + + 页面示例:[https://51rz.51job.com/job.html?jobid=115980776](https://51rz.51job.com/job.html?jobid=115980776) + + 页面真实数据请求地址类似于:https://coapi.51job.com/job_detail.php?jsoncallback=&key=&sign=params={"jobid":""} + + 请求地址中的各参数值通过 js 加密:[https://js.51jobcdn.com/in/js/2018/coapi/coapi.min.js](https://js.51jobcdn.com/in/js/2018/coapi/coapi.min.js) + +![02](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/02.png) + +![03](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/03.png) + +**特殊情况二:**部分公司有自己的专属页面,此类页面的结构也不同于普通页面 + + 页面示例:[http://dali.51ideal.com/jobdetail.html?jobid=121746338](http://dali.51ideal.com/jobdetail.html?jobid=121746338) + +![04](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/04.png) + +![05](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/05.png) + +为了规范化,本次爬取将去掉这部分特殊页面,仅爬取 URL 带有 `jobs.51job.com` 的数据 + +```python + def detail_url(self, number): + for num in range(1, number+1): + url = self.base_url % (self.keyword, str(num)) + response = requests.get(url=url, headers=self.headers) + tree = etree.HTML(response.content.decode('gbk')) + detail_url1 = tree.xpath("//div[@class='dw_table']/div[@class='el']/p/span/a/@href") + + """ + 深拷贝一个 url 列表,如果有连续的不满足要求的链接,若直接在原列表里面删除, + 则会漏掉一些链接,因为每次删除后的索引已改变,因此在原列表中提取不符合元素 + 后,在深拷贝的列表里面进行删除。最后深拷贝的列表里面的元素均符合要求。 + """ + + detail_url2 = copy.deepcopy(detail_url1) + for url in detail_url1: + if 'jobs.51job.com' not in url: + detail_url2.remove(url) + self.parse_data(detail_url2) + print('第%d页数据爬取完毕!' % num) + time.sleep(2) + print('所有数据爬取完毕!') +``` + +### 【01x04】提取职位信息 + +解析详情页时页面编码是 `gbk`,但是某些页面在解析时仍然会报编码错误,因此使用 `try-except` 语句捕捉编码错误(UnicodeDecodeError),如果该页面有编码错误则直接 return 结束函数。 + +```python + def parse_data(self, urls): + + """ + position: 职位 + wages: 工资 + region: 地区 + experience: 经验 + education: 学历 + need_people: 招聘人数 + publish_date: 发布时间 + english: 英语要求 + welfare_tags: 福利标签 + job_information: 职位信息 + work_address: 上班地址 + company_name: 公司名称 + company_nature: 公司性质 + company_scale: 公司规模 + company_industry: 公司行业 + company_information: 公司信息 + """ + + for url in urls: + response = requests.get(url=url, headers=self.headers) + try: + text = response.content.decode('gbk') + except UnicodeDecodeError: + return + tree = etree.HTML(text) + + """ + 提取内容时使用 join 方法将列表转为字符串,而不是直接使用索引取值, + 这样做的好处是遇到某些没有的信息直接留空而不会报错 + """ + + position = ''.join(tree.xpath("//div[@class='cn']/h1/text()")) + wages = ''.join(tree.xpath("//div[@class='cn']/strong/text()")) + + # 经验、学历、招聘人数、发布时间等信息都在一个标签里面,逐一使用列表解析式提取 + content = tree.xpath("//div[@class='cn']/p[2]/text()") + content = [i.strip() for i in content] + if content: + region = content[0] + else: + region = '' + experience = ''.join([i for i in content if '经验' in i]) + education = ''.join([i for i in content if i in '本科大专应届生在校生硕士']) + need_people = ''.join([i for i in content if '招' in i]) + publish_date = ''.join([i for i in content if '发布' in i]) + english = ''.join([i for i in content if '英语' in i]) + + welfare_tags = ','.join(tree.xpath("//div[@class='jtag']/div//text()")[1:-2]) + job_information = ''.join(tree.xpath("//div[@class='bmsg job_msg inbox']/p//text()")).replace(' ', '') + work_address = ''.join(tree.xpath("//div[@class='bmsg inbox']/p//text()")) + company_name = ''.join(tree.xpath("//div[@class='tCompany_sidebar']/div[1]/div[1]/a/p/text()")) + company_nature = ''.join(tree.xpath("//div[@class='tCompany_sidebar']/div[1]/div[2]/p[1]//text()")) + company_scale = ''.join(tree.xpath("//div[@class='tCompany_sidebar']/div[1]/div[2]/p[2]//text()")) + company_industry = ''.join(tree.xpath("//div[@class='tCompany_sidebar']/div[1]/div[2]/p[3]/@title")) + company_information = ''.join(tree.xpath("//div[@class='tmsg inbox']/text()")) + + job_data = [position, wages, region, experience, education, need_people, publish_date, + english, welfare_tags, job_information, work_address, company_name, + company_nature, company_scale, company_industry, company_information] + + save_mongodb(job_data) +``` + +### 【01x05】保存数据到 MongoDB + +指定一个名为 `job51_spider` 的数据库和一个名为 `data` 的集合,依次将信息保存至 MongoDB。 + +```python +def save_mongodb(data): + client = pymongo.MongoClient(host='localhost', port=27017) + db = client.job51_spider + collection = db.data + save_data = { + '职位': data[0], + '工资': data[1], + '地区': data[2], + '经验': data[3], + '学历': data[4], + '招聘人数': data[5], + '发布时间': data[6], + '英语要求': data[7], + '福利标签': data[8], + '职位信息': data[9], + '上班地址': data[10], + '公司名称': data[11], + '公司性质': data[12], + '公司规模': data[13], + '公司行业': data[14], + '公司信息': data[15] + } + collection.insert_one(save_data) +``` + +## 【2x00】数据可视化 draw_bar_chart.py + +### 【02x01】数据初处理 + +从 MongoDB 里面读取数据为 DataFrame 对象,本次可视化只分析工资与经验、学历的关系,所以只取这三项,由于获取的数据有些是空白值,因此使用 replace 方法将空白值替换成缺失值(NaN),然后使用 DataFrame 对象的 `dropna()` 方法删除带有缺失值(NaN)的行。将工资使用 `apply` 方法,将每个值应用于 `wish_data` 方法,即对每个值进行清洗。 + +```python +def processing_data(): + # 连接数据库,从数据库读取数据(也可以导出后从文件中读取) + client = pymongo.MongoClient(host='localhost', port=27017) + db = client.job51_spider + collection = db.data + + # 读取数据并转换为 DataFrame 对象 + data = pd.DataFrame(list(collection.find())) + data = data[['工资', '经验', '学历']] + + # 使用正则表达式选择空白的字段并填充为缺失值,然后删除带有缺失值的所有行 + data.replace(to_replace=r'^\s*$', value=np.nan, regex=True, inplace=True) + data = data.dropna() + + # 对工资数据进行清洗,处理后的工作单位:元/月 + data['工资'] = data['工资'].apply(wish_data) + return data +``` + +### 【02x02】数据清洗 + +```python +def wish_data(wages_old): + + """ + 数据清洗规则: + 分为元/天,千(以上/下)/月,万(以上/下)/月,万(以上/下)/年 + 若数据是一个区间的,则求其平均值,最后的值统一单位为元/月 + """ + + if '元/天' in wages_old: + if '-' in wages_old.split('元')[0]: + wages1 = wages_old.split('元')[0].split('-')[0] + wages2 = wages_old.split('元')[0].split('-')[1] + wages_new = (float(wages2) + float(wages1)) / 2 * 30 + else: + wages_new = float(wages_old.split('元')[0]) * 30 + return wages_new + + elif '千/月' in wages_old or '千以下/月' in wages_old or '千以上/月' in wages_old: + if '-' in wages_old.split('千')[0]: + wages1 = wages_old.split('千')[0].split('-')[0] + wages2 = wages_old.split('千')[0].split('-')[1] + wages_new = (float(wages2) + float(wages1)) / 2 * 1000 + else: + wages_new = float(wages_old.split('千')[0]) * 1000 + return wages_new + + elif '万/月' in wages_old or '万以下/月' in wages_old or '万以上/月' in wages_old: + if '-' in wages_old.split('万')[0]: + wages1 = wages_old.split('万')[0].split('-')[0] + wages2 = wages_old.split('万')[0].split('-')[1] + wages_new = (float(wages2) + float(wages1)) / 2 * 10000 + else: + wages_new = float(wages_old.split('万')[0]) * 10000 + return wages_new + + elif '万/年' in wages_old or '万以下/年' in wages_old or '万以上/年' in wages_old: + if '-' in wages_old.split('万')[0]: + wages1 = wages_old.split('万')[0].split('-')[0] + wages2 = wages_old.split('万')[0].split('-')[1] + wages_new = (float(wages2) + float(wages1)) / 2 * 10000 / 12 + else: + wages_new = float(wages_old.split('万')[0]) * 10000 / 12 + return wages_new +``` + +### 【02x03】绘制经验与平均薪资关系图 + +```python +def wages_experience_chart(data): + # 根据经验分类,求不同经验对应的平均薪资 + wages_experience = data.groupby('经验').mean() + + # 获取经验和薪资的值,将其作为画图的 x 和 y 数据 + w = wages_experience['工资'].index.values + e = wages_experience['工资'].values + + # 按照经验对数据重新进行排序,薪资转为 int 类型(也可以直接在前面对 DataFrame 按照薪资大小排序) + wages = [w[6], w[1], w[2], w[3], w[4], w[5], w[0]] + experience = [int(e[6]), int(e[1]), int(e[2]), int(e[3]), int(e[4]), int(e[5]), int(e[0])] + + # 绘制柱状图 + plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + plt.figure(figsize=(9, 6)) + x = wages + y = experience + color = ['#E41A1C', '#377EB8', '#4DAF4A', '#984EA3', '#FF7F00', '#FFFF33', '#A65628'] + plt.bar(x, y, color=color) + for a, b in zip(x, y): + plt.text(a, b, b, ha='center', va='bottom') + plt.title('Python 相关职位经验与平均薪资关系', fontsize=13) + plt.xlabel('经验', fontsize=13) + plt.ylabel('平均薪资(元 / 月)', fontsize=13) + plt.savefig('wages_experience_chart.png') + plt.show() +``` + +### 【02x04】绘制学历与平均薪资关系图 + +```python +def wages_education_chart(data): + # 根据学历分类,求不同学历对应的平均薪资 + wages_education = data.groupby('学历').mean() + + # 获取学历和薪资的值,将其作为画图的 x 和 y 数据 + wages = wages_education['工资'].index.values + education = [int(i) for i in wages_education['工资'].values] + + # 绘制柱状图 + plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] + plt.figure(figsize=(9, 6)) + x = wages + y = education + color = ['#E41A1C', '#377EB8', '#4DAF4A'] + plt.bar(x, y, color=color) + for a, b in zip(x, y): + plt.text(a, b, b, ha='center', va='bottom') + plt.title('Python 相关职位学历与平均薪资关系', fontsize=13) + plt.xlabel('学历', fontsize=13) + plt.ylabel('平均薪资(元 / 月)', fontsize=13) + plt.savefig('wages_education_chart.png') + plt.show() +``` + +## 【3x00】数据截图 + +一共有 34009 条数据,完整数据已放在 github,可自行下载。 + +MongoDB: + +![06](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/06.png) + +CSV 文件: + +![07](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/07.png) + +JSON 文件: + +![08](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/08.png) + +关系图: + +![09](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/09.png) + +![10](https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-PIC/A90/10.png) + +## 【4x00】完整代码 + +完整代码地址(点亮 star 有 buff 加成):[https://github.com/TRHX/Python3-Spider-Practice/tree/master/51job](https://github.com/TRHX/Python3-Spider-Practice/tree/master/51job) + +其他爬虫实战代码合集(持续更新):[https://github.com/TRHX/Python3-Spider-Practice](https://github.com/TRHX/Python3-Spider-Practice) + +爬虫实战专栏(持续更新):[https://itrhx.blog.csdn.net/article/category/9351278](https://itrhx.blog.csdn.net/article/category/9351278) diff --git a/source/friends/index.md b/source/friends/index.md index aa93976beebb65384a24c7048d2cbda0521a1285..19d22ab2e4f074f88edd305310f24e5f70990f6f 100644 --- a/source/friends/index.md +++ b/source/friends/index.md @@ -33,12 +33,40 @@ links: - name: shansan avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/shansan.jpeg url: https://shan333.cn/ - backgroundColor: '#A47366' + backgroundColor: '#E94335' textColor: '#fff' tags: - C++ - Python + - name: Yinux's Blog + avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/yinuxy.jpg + url: https://www.yinuxy.com/ + backgroundColor: '#7C5246' + textColor: '#fff' + tags: + - Python + - 算法 + - 大数据 + + - name: TUFZ + avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/TUFZ.jpg + url: http://www.itufz.com/ + backgroundColor: '#967ADC' + textColor: '#fff' + tags: + - Java + - 算法 + + - name: DAYUANSHUAI + avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/dayuanshuai.jpg + url: http://idayuanshuai.com/ + backgroundColor: '#708090' + textColor: '#fff' + tags: + - 网络工程师 + - 运维大佬 + - name: 番茄酱の萌化小屋 avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/kurumi.jpg url: https://i.kurumi.ink/ @@ -52,7 +80,7 @@ links: - name: attack204 avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/attack204.jpg url: http://attack204.com/ - backgroundColor: '#967ADC' + backgroundColor: '#34A853' textColor: '#fff' tags: - OIer @@ -201,16 +229,6 @@ links: - C++ - 蒟蒻 - - name: Yinux's Blog - avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/yinuxy.jpg - url: https://www.yinuxy.com/ - backgroundColor: '#7C5246' - textColor: '#fff' - tags: - - Python - - 算法 - - 大数据 - - name: Steven_MengのBlog avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/stevenmhy.jpg url: https://stevenmhy.tk/ @@ -379,7 +397,7 @@ links: - name: 高高编程小屋 avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/frogfrog.jpg - url: http://frogfrog.cn/ + url: http://littlewhale.xyz/ backgroundColor: '#967ADC' textColor: '#fff' tags: @@ -437,6 +455,14 @@ links: - Java - Spring + - name: Alex Kyle + avatar: https://cdn.jsdelivr.net/gh/TRHX/ImageHosting/ITRHX-LINKS/congjinyebaiya.jpg + url: https://congjinyebaiya.wang/ + backgroundColor: '#967ADC' + textColor: '#fff' + tags: + - 前端 + - group: 虐狗博主 icon: fas fa-heartbeat items: diff --git a/themes/material-x-1.2.1/_config.yml b/themes/material-x-1.2.1/_config.yml index 7e5c2dda6ac997a3c5b3fded67256d94d8476287..81a4bdb5436a66a1a394e0a9a6a8bd916d5df8b1 100644 --- a/themes/material-x-1.2.1/_config.yml +++ b/themes/material-x-1.2.1/_config.yml @@ -121,8 +121,12 @@ menu_desktop: target: _blank - name: 肺炎疫情图 icon: fas fa-heart - url: 2019-nCoV/ + url: http://cov.itrhx.com/ target: _blank + # - name: 肺炎疫情图 + # icon: fas fa-heart + # url: 2019-nCoV/ + # target: _blank # 手机端导航菜单(从右上角的按钮点击展开) menu_mobile: @@ -149,7 +153,7 @@ menu_mobile: url: https://itrhx.blog.csdn.net/ - name: 肺炎疫情图 icon: fas fa-heart - url: 2019-nCoV/ + url: http://cov.itrhx.com/ # 默认的meta信息,文章中没有配置则按照这里的配置来显示,设置为false则不显示 # 其中,title只在header中有效,music和thumbnail无需在这里设置,文章中有则显示 @@ -193,22 +197,38 @@ sidebar: # icon: fas fa-info-circle # url: about/ # rel: nofollow +# - widget: plain +# icon: fas fa-handshake +# title: 欢迎光临 +# body: '
Hexo QQ 交流群Telegram 交流群' +# more: +# icon: fas fa-info-circle +# url: https://www.revolvermaps.com/ +# target: _blank - widget: plain icon: fas fa-handshake title: 欢迎光临 - body: '
QQ 交流群Telegram 交流群' + body: 'Hexo QQ 交流群Telegram 交流群' more: icon: fas fa-info-circle url: https://www.revolvermaps.com/ target: _blank - widget: plain - icon: fas fa-map-marked-alt - title: 家乡产业 - 恩施富硒茶 - body: 恩施硒茶、利川红•冷后浑,源自北纬30°的功夫红茶,产于世界硒都 — 湖北恩施,2018年4月28日,国家主席习近平在武汉东湖同印度总理莫迪一同品尝了利川红,富硒茶具有降脂减肥、防癌抗毒、提神醒脑等功能,传统炒青工艺,正宗产地,色泽翠绿,茶香浓郁,爱茶养生人士的不二选择!恩施富硒茶恩施富硒茶恩施富硒茶恩施富硒茶恩施富硒茶恩施富硒茶进店逛逛 + icon: fas fa-blog + title: CSDN 内容合伙人 + body: '' more: - icon: fas fa-shopping-cart - url: https://shop144988343.taobao.com/ + icon: fas fa-info-circle + url: https://itrhx.blog.csdn.net/ target: _blank +# - widget: plain +# icon: fas fa-map-marked-alt +# title: 家乡产业 - 恩施富硒茶 +# body: 恩施硒茶、利川红•冷后浑,源自北纬30°的功夫红茶,产于世界硒都 — 湖北恩施,2018年4月28日,国家主席习近平在武汉东湖同印度总理莫迪一同品尝了利川红,富硒茶具有降脂减肥、防癌抗毒、提神醒脑等功能,传统炒青工艺,正宗产地,色泽翠绿,茶香浓郁,爱茶养生人士的不二选择!恩施富硒茶恩施富硒茶恩施富硒茶恩施富硒茶恩施富硒茶恩施富硒茶进店逛逛 +# more: +# icon: fas fa-shopping-cart +# url: https://shop144988343.taobao.com/ +# target: _blank # - widget: plain # icon: fas fa-comments # title: 交流群组 diff --git a/themes/material-x-1.2.1/layout/_partial/article.ejs b/themes/material-x-1.2.1/layout/_partial/article.ejs index 1a5b59e314223437634d267d461280d595561c04..fb869a3796e072c2ce1c531c6a26e611a89bd34e 100644 --- a/themes/material-x-1.2.1/layout/_partial/article.ejs +++ b/themes/material-x-1.2.1/layout/_partial/article.ejs @@ -7,10 +7,7 @@
<%- post.content %>
-

- <% if (post.layout == 'post'){ %> -
CourseDuck Python Banner
- <% } %> +
<% if (theme.reward.enable && post.layout == 'post' && post.reward != false){ %> <%- partial('reward') %> <% } %>