浅入浅出数据分析之Hello NumPy系列(四)
2020,努力做一个无可替代的人!
作者 | 小一
全文共2833字,阅读全文需10分钟
写在前面的话
没想到吧,NumPy 还有一小节,请珍惜 NumPy 最后的美好时光。
这一节的内容源自于一个朋友的提问,我在交流群里也分享过,具体问题会在正文中复现,知道你们好奇,往下看就好。
害,差点忘了,先回顾下前三节的内容,同学们自行复习:
听说抬起头看天眼眶才不会湿?
我想试试
正文
先来复现一下朋友当时问我的问题:
有一个数据a(DataFrame类型、3行4列的数据),数据b(Series类型、[0,1,2]),比较a和b后输出布尔型数组
看一下代码演示
# 创建 DataFrame
import pandas as pd
df_a = pd.DataFrame(np.arange(12).reshape(3, 4))
# 输出
0 1 2 3
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
# 创建 Series
import numpy as np
series_b = pd.Series(np.arange(3))
# 输出
0 0
1 1
2 2
dtype: int32
就这样两个数据类型,我刚开始一听第一反应是:这咋比较?数据类型都不一样,维度也不一样。
直到我翻开书看了一下才想起这个概念:广播
。
先看一下比较的结果是什么
df_a > series_b
# 输出
0 1 2 3
0 False False False False
1 True True True False
2 True True True False
如果你知道为什么会出现上面这个结果,那恭喜你,这一小节你可以直接跳过,相信我,你是最NB的
不知道的同学我们还是要继续的,看完今天的文章想必你会明白。
广播
上面问题提到的一个概念,也是今天唯一的一个知识点:广播
广播指的是不同形状的数组之间的算术运算的执行方式。
首先,将标量数组和数组合并时就会发生简单的广播。
# 创建数组
data_arr1 = np.arange(5)
# 输出
[0 1 2 3 4]
data_arr1 * 5
# 输出
[ 0 5 10 15 20]
在上面的乘法运算中,标量值4你也可以看做是一个一行一列的数组,被广播到其他所有的元素上。
这是最简单的标量的广播,那如果是数组的广播呢?
看例子:
# 创建4行3列的二维数组
data_arr2 = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]])
# 输出
[[0 0 0]
[1 1 1]
[2 2 2]
[3 3 3]]
# 创建一维数组
data_arr3 = np.array([1, 2, 3])
# 输出
[1 2 3]
# A + B
data_arr2 + data_arr3
# 输出
[[1 2 3]
[2 3 4]
[3 4 5]
[4 5 6]]
没想到吧,竟然可以计算而没有报错。
这是因为数组 data_arr3 在0轴上做的广播(灰色数字),将原本1行3列的数组广播成4行3列,从而可以与 data_arr2 进行计算
ok,想必你应该清楚广播是什么作用了吧
当然,广播也不是说所有情况都会广播,人家也是有原则的。
何为广播?
如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为它们是广播兼容的
。
广播会在缺失和(或)长度为1 的维度上进行。
这句话是理解广播的核心,老实说,看懂了吗?
不懂往下看,抬起头看天是看不到答案的,只会不让眼泪流下来!
广播主要发生在三种情况下:
一种是两个数组的维度不相等,但是它们的后缘维度的轴长相符
另一种是两个数组的维度相同,对应维度的轴长要么相等要么任意一个为1
上面两种的结合体
第一种情况
两个数组的维度不相等,但是它们的后缘维度的轴长相符
以上面的例子为例
# 输出数组形状/维度
data_arr2.shape
data_arr3.shape
# 输出
(4, 3)
(3,)
可以看到,data_arr2 (4, 3)是二维的,data_arr3 (3,)是一维的,两个数组的维度不相等。同时,它们的后缘维度都是3,后缘维度的轴长相等。
完美符合我们的第一种情况,所以可以进行相加运算。
同样的道理,多维数组也遵循广播原则。
举个图例:
以此类推:
(2,4,2,4) 和 (2,3,4) 是兼容的
(2,4,2,4) 和 (2,4) 是兼容的
(2,4,2,4) 和 (4) 是兼容的
第二种情况
两个数组的维度相同,对应维度的轴长要么相等要么任意一个为1
这个就比较容易理解了,两个维度相同的数组,对应的维度长度有两种情况:
要么长度相同,要么有一个长度为1
# 创建4行1列的二维数组
data_arr4 = np.array([[1, 2, 3, 4]]).reshape(4, 1)
# 输出
[[1]
[2]
[3]
[4]]
# 创建1行3列的二维数组
data_arr5 = np.array([[1, 2, 3]])
# 输出
[[1 2 3]]
这两个数组都是二维数组分别是(4, 1)、(1, 3)
与我们的 data_arr2 (4, 3) 相比,根据第二种情况:
(4, 3) 与 (4, 1) 维度相同,第一维长度相同,第二维存在长度为1;
(4, 3) 与 (1, 3) 维度相同,第一维存在长度为1,第二维长度相同;
(4, 1) 与 (1, 3) 维度相同,第一维存在长度为1,第二维存在长度为1。
所以,以上三个数组之间互相兼容。
稍微画个图例:
这个时候,第二个二维数组会在1轴上进行广播(灰色数字)
第三种情况
明白了第一种和第二种形式的广播,第三种就是两者的结合体。
举几个简单的例子你就明白了:
(4, 2, 5) 和 (1, 5) 是兼容的。但是不满足第一、第二种情况
(4, 2, 5) 和 (2, 1) 是兼容的。同样不满足第一、第二种情况
看完这三种情况,是不是清楚了一些?
再来细品一下广播的定义
如果两个数组的后缘维度的轴长度相符或其中一方的长度为1,则认为它们是广播兼容的
。
所以,当我们拿到两个数组,需要判断是否兼容时,先从后缘维度开始,依次往前。
要么对应维度的长度相等,要么对应维度存在某一方的长度为1。
若两个数组的每一个维度都符合这个要求,那这两个数组一定是兼容的。
总结一下:
今天主要讲到一个概念:广播。
正文最后的总结我觉得很到位了,不妨多读几遍理解一下。
看到广播概念的时候,我猜大部分人刚开始也会很懵逼,字都认识,说了个啥?
所以我列举了三种情况去分解这个概念,还记得是哪三种吗?
两个数组的维度不相等,但是它们的后缘维度的轴长相符
两个数组的维度相同,对应维度的轴长要么相等要么任意一个为1
上面两种的结合体
看完这三种情况后,我们回过头再来看概念,是不是就清晰多了?
ok,《Hello NumPy》系列就完结了,一共四小节,希望对你们有用!
写在后面的话
静下心来写技术文真的也太舒服了吧,希望你们也能静下心舒服的看文章。
我一直以为这几天做的最认真的事就是洗手,结果发现我写文章也可以这么认真。
都怪文章名字没起好,对不起自己。说到这,我的眼眶又湿了。
最近不能去外面吃好的,下班一有空就窝家里写文章,都饿瘦了。
之前买的一箱泡面差不多都吃完了,和我爸妈视频的时候他们都说我饿瘦了
不说了,眼眶全湿了…
下个系列见
碎碎念一下
我发现了自己文章起名字的能力真的太差了,还挺影响阅读量的 就像这个系列的名字一样,贼差劲! 知错就改,下个系列一定好好起名
不过名字没起好不妨碍你们点在看吧?
入门:
准备工作 运算符 数据类型① 数据类型② 流程控制 函数 文件 模块 异常进阶:
面向对象 正则表达式 多线程与多进程 JSON操作 时间序列 数据库操作 邮件发送高阶:
事半功倍的高阶函数 NumPy系列① NumPy系列② NumPy系列③技巧:
学习技巧① 学习技巧② 学习技巧③爬虫系列基础:
准备工作 爬虫实现方式 Requests详解 BeautifulSoup详解
其他系列
学排版:
Markdown排版教程
领资料:
数据分析干货礼包
讲故事:
小一的故事 和二三四们的故事听故事:
投稿故事①投故事:
看故事之前先看我好巧啊,你也读到这了!
点个
在看
让我看到你