《Hello NumPy》系列 | Numpy廣播的終極奧義



2020,努力做一個無可替代的人!



寫在前面的話

沒想到吧,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(34))
# 輸出
   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([[000], [111], [222], [333]])
# 輸出
[[0 0 0]
 [1 1 1]
 [2 2 2]
 [3 3 3]]

# 創建一維數組
data_arr3 = np.array([123])
# 輸出
[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

# 輸出
(43)
(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([[1234]]).reshape(41)
# 輸出
[[1]
 [2]
 [3]
 [4]]

# 創建1行3列的二維數組
data_arr5 = np.array([[123]])
# 輸出
[[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》 系列就完結了,一共四小節,希望對你們有用!

寫在後面的話

靜下心來寫技術文真的也太舒服了吧,希望你們也能靜下心舒服的看文章。

我一直以爲這幾天做的最認真的事就是洗手,結果發現我寫文章也可以這麼認真。

最近不能去外面喫好的,下班一有空就窩家裏寫文章,都餓瘦了。

之前買的一箱泡麪差不多都喫完了,和我爸媽視頻的時候他們都說我餓瘦了

不說了,眼眶全溼了…

下個系列見


原創不易,歡迎點贊噢

文章首發:公衆號【知秋小夢】

文章同步:掘金,簡書


原文鏈接:《Hello NumPy》系列-廣播操作就看這一篇


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章