中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
第79天:數(shù)據(jù)分析之 Numpy 初步

NumPy 是 Python 中一個(gè)基本的科學(xué)計(jì)算庫(kù),包含以下特性:

  • 強(qiáng)大的 N 維數(shù)組對(duì)象;
  • 精巧的廣播(broadcasting)功能;
  • C/C++ 和 Fortran 代碼集成工具;
  • 實(shí)用的線性代數(shù)、傅里葉變換、隨機(jī)數(shù)生成等功能。

其中,N 維數(shù)組是 NumPy 最為核心的特性。

除了顯而易見的科學(xué)計(jì)算用途,NumPy 還可以用作一般數(shù)據(jù)類型的多維容器,并且是任何數(shù)據(jù)類型均可;但有一點(diǎn):一個(gè)數(shù)組中必須是同種數(shù)據(jù)類型。這一特性使得 NumPy 可以高效、無(wú)縫地與各種數(shù)據(jù)庫(kù)進(jìn)行集成。

NumPy 基于開源許可協(xié)議  BSD license 發(fā)布,對(duì)于二次分發(fā)使用幾乎沒有限制。

1. 安裝 NumPy

由于 NumPy 并非 Python 的內(nèi)置模塊,因此我們直接從 Python 官網(wǎng)下載安裝的發(fā)行版是不包含 NumPy 這個(gè)模塊的。這個(gè)時(shí)候你要是想import numpy,顯然是會(huì)無(wú)功而返的。因此我們需要額外安裝 NumPy 模塊。

安裝 NumPy 有好幾種方式,我們這里推薦的是:1)使用pip進(jìn)行安裝;2)安裝Anaconda。

1.1 使用pip安裝

這種方式推薦給已經(jīng)從 Python 官網(wǎng)下載了某個(gè) Python 發(fā)行版的讀者,或是已經(jīng)通過其它方式獲得了 Python 環(huán)境,但卻沒有 NumPy 這個(gè)模塊的讀者。

安裝命令:


pip install numpy

或:


python -m pip install numpy

均可。

當(dāng)然,實(shí)際上 NumPy 模塊本身也有很多依賴,也需要其他一些模塊才能夠真正發(fā)揮出它強(qiáng)大的功能,因此我們推薦一次安裝多個(gè)模塊:


python -m pip install --user numpy scipy matplotlib ipython jupyter pandas sympy nose

1.2 安裝 Anaconda

這種方式適合還沒有安裝 Python 的讀者,或是已經(jīng)安裝了 Python 但是想一勞永逸擁有大多數(shù)科學(xué)計(jì)算庫(kù)的讀者。

訪問 Anaconda 官網(wǎng)找到下載鏈接進(jìn)行安裝即可。

或者如果你覺得 Anaconda 過于臃腫,也可以安裝其簡(jiǎn)化版本 Miniconda 。

2. N 維數(shù)組

N 維數(shù)組,也稱“多維數(shù)組”,這里的“N”代表的就是數(shù)組的維數(shù)。

我們?cè)谥耙呀?jīng)學(xué)過了 Python 中的內(nèi)置數(shù)據(jù)類型,其中有一種在表現(xiàn)形式上跟多維數(shù)組很像——就是序列(sequence)型的列表(list)數(shù)據(jù):二者都是由中括號(hào)括起來(lái)的數(shù)據(jù)類型。

但實(shí)際上,多維數(shù)組和列表是完全不同的兩種數(shù)據(jù)類型,我們?cè)谑褂玫臅r(shí)候一定要嚴(yán)格地將二者區(qū)分開來(lái)。具體地講,二者有以下不同點(diǎn):

  • NumPy 的多維數(shù)組在創(chuàng)建之初形狀大小就已經(jīng)固定;而列表的大小則是動(dòng)態(tài)變化的。改變一個(gè)多維數(shù)組的大小,實(shí)際上會(huì)導(dǎo)致一個(gè)新的數(shù)值被創(chuàng)建,舊的數(shù)組的刪除。
  • NumPy 多維數(shù)組中的元素要求是同種數(shù)據(jù)類型,因此在內(nèi)存中實(shí)際的大小也是相同的。只有一個(gè)例外:數(shù)組由 Python 的各種對(duì)象組成,這樣數(shù)組中元素的大小才會(huì)不同。
  • NumPy 的多維數(shù)組使得對(duì)大量數(shù)據(jù)進(jìn)行高級(jí)的數(shù)學(xué)運(yùn)算或其他操作變得更加方便快捷。對(duì)同樣一個(gè)運(yùn)算來(lái)說(shuō),使用多維數(shù)組會(huì)比使用 Python 內(nèi)置的序列類型更加高效,代碼量也更少
  • 許許多多的基于 Python 的科學(xué)計(jì)算庫(kù)、數(shù)學(xué)應(yīng)用庫(kù)都使用 NumPy 的多維數(shù)組進(jìn)行實(shí)現(xiàn),并且這些庫(kù)的數(shù)量還在日漸增多。就算有些庫(kù)也同樣支持 Python 的序列作為輸入,它們也會(huì)優(yōu)先將序列轉(zhuǎn)換為多維數(shù)組,再進(jìn)行處理;此外,這些庫(kù)的輸出一般也是多維數(shù)組。換而言之,要無(wú)障礙地使用當(dāng)今大多數(shù)基于 Python 的科學(xué)/數(shù)學(xué)計(jì)算軟件,僅僅掌握 Python 內(nèi)置的序列數(shù)據(jù)類型是不夠的,還應(yīng)當(dāng)學(xué)會(huì)如何使用 NumPy 的多維數(shù)組。

2.1 比較

本小節(jié)代碼示例來(lái)自《何為 NumPy》

讓我們來(lái)看一個(gè)例子(暫時(shí)忽略對(duì)變量的定義,假定存在 a、b、result 這三個(gè)數(shù)組)。

假設(shè)我們現(xiàn)在有 a、b 兩個(gè)一維數(shù)組(類似于一維列表),要對(duì)它們進(jìn)行“對(duì)應(yīng)元素相乘”的運(yùn)算,如果使用 Python 內(nèi)置的列表,應(yīng)該寫成什么樣呢?




result = []for i in range(len(a)): result.append(a[i]*b[i])

顯然結(jié)果是正確無(wú)誤的。但是我們考慮一個(gè)情形:如果 a、b 兩個(gè)一維數(shù)組中每個(gè)都包含數(shù)百萬(wàn)甚至更多的元素,會(huì)發(fā)生什么呢?眾所周知,Python 作為一門解釋型語(yǔ)言,其代碼的執(zhí)行速度本就遠(yuǎn)低于眾多的編譯型語(yǔ)言,并且之前我們也講到過,Python 中的for循環(huán)實(shí)際上是一個(gè)迭代計(jì)算的過程,這樣就會(huì)導(dǎo)致性能上成本很高;大多數(shù)時(shí)間都被浪費(fèi)在了對(duì)代碼的解釋和對(duì)對(duì)象的操作上。

講到性能問題,我們一下就想到了日常被拉出來(lái)和 Python 比較的 C 語(yǔ)言。那么我們用 C 語(yǔ)言來(lái)實(shí)現(xiàn)上面這個(gè)運(yùn)算又如何呢?




for (i = 0; i < rows; i++): { result[i] = a[i]*b[i];}

較之之前的 Python 代碼,顯然這段 C 代碼節(jié)省了解釋代碼和操作對(duì)象的性能開銷,但凡事有利有弊,提升了性能的同時(shí)也犧牲了 Python 代碼的簡(jiǎn)潔明了。如果是二維數(shù)組呢?






for (i = 0; i < rows; i++): { for (j = 0; j < columns; j++): { result[i][j] = a[i][j]*b[i][j]; }}

好了,不用再往上加了。我們完全可以想見,隨著數(shù)組維數(shù)越來(lái)越多,這段代碼嵌套的循環(huán)也將越來(lái)越多,代碼越來(lái)越龐雜——總之直觀性越來(lái)越差。

如果用上 NumPy 呢?同樣是計(jì)算兩個(gè)數(shù)組的逐元素乘積,NumPy 對(duì)于包含多維數(shù)組的運(yùn)算默認(rèn)模式就是“逐元素運(yùn)算”,同時(shí)又通過預(yù)編譯好的 C 代碼來(lái)實(shí)現(xiàn)高性能的計(jì)算。使用示例如下:


result = a * b

啊哈!是不是有點(diǎn)眼熟?這不就是一個(gè)很自然的數(shù)學(xué)表達(dá)式嗎?當(dāng)然跟矩陣的點(diǎn)乘還是不一樣的,但是只要了解 NumPy 的這個(gè)運(yùn)算規(guī)則的人,看到這行代碼就有一種一目了然之感。管你三七二十,兩維、十維還是八十、八百維,我都用這一個(gè)表達(dá)式全部搞定。既保留了 Python 代碼簡(jiǎn)潔明了的風(fēng)格,也獲得了較高的執(zhí)行速度。

2.2 兩個(gè)重要的特性

在上面的例子中,支撐起 NumPy 強(qiáng)大功能的主要有兩個(gè)很重要的特性:矢量化(vectorization)和廣播(broadcasting)。

2.2.1 矢量化

其中,矢量化描述的是這么個(gè)情形:凡是在遇到需要顯式循環(huán)、索引的地方,都可以省略掉這些細(xì)枝末節(jié),由預(yù)編譯好的、優(yōu)化過的 C 代碼在后臺(tái)默默耕耘。這么一來(lái)就帶來(lái)了幾個(gè)好處:

  • 矢量化的代碼更加簡(jiǎn)潔易讀;
  • 代碼行的減少也意味著更少的 bug;
  • 代碼中表達(dá)式更加接近數(shù)學(xué)公式的本來(lái)面目;
  • 矢量化也使得代碼更加 Pythonic。沒有“矢量化”,我們的代碼將會(huì)充斥著低效、難懂的for循環(huán)。

2.2.2 廣播

“廣播”這個(gè)特性對(duì)于掌握 NumPy 非常重要,文章后面會(huì)單獨(dú)講解一下,希望讀者能夠用心理解

“廣播”是一個(gè) NumPy 的術(shù)語(yǔ),描述的則是這么一個(gè)情況:NumPy 中的運(yùn)算都是默認(rèn)逐元素進(jìn)行的。這些運(yùn)算不僅限于常見的算術(shù)運(yùn)算,也包括不那么常見的邏輯運(yùn)算、位運(yùn)算,以及函數(shù),等等,凡是用到這些運(yùn)算,或者說(shuō)操作,NumPy 都默認(rèn)是逐元素進(jìn)行的;這就叫“廣播”。

從前面的例子來(lái)看,進(jìn)行逐元素乘法的 a、b 兩個(gè)數(shù)組,既可以是大小相同的多維數(shù)組,也可以其中一個(gè)是標(biāo)量、另一個(gè)是數(shù)組,甚至可以是兩個(gè)大小不同的數(shù)組,為了使得“廣播”的語(yǔ)意明確、結(jié)果清晰,其中較小的那個(gè)數(shù)組就可以被擴(kuò)展為較大數(shù)組的大小。

3. 認(rèn)識(shí)數(shù)組

3.1 創(chuàng)建數(shù)組

本小節(jié)代碼來(lái)自《NumPy 快速入門》

創(chuàng)建數(shù)組(array)的方式有不少,其中最自然的一種方式就是通過列表來(lái)生成數(shù)組。

要使用 NumPy 模塊,首先我們要在當(dāng)前的 Python 環(huán)境中導(dǎo)入 NumPy,同時(shí)為了便于之后的引用,我們將其重命名為np


>>> import numpy as np

3.1.1 通過列表創(chuàng)建數(shù)組

文章前面我們提到過,NumPy 的多維數(shù)組和 Python 內(nèi)置的列表長(zhǎng)得很像,估計(jì)是表親還是啥的。并且嵌套的列表在一定程度上也能夠?qū)崿F(xiàn)多維數(shù)組的功能,因此 NumPy 也很人性化的提供了接口,可以將現(xiàn)成的列表轉(zhuǎn)換為我們要的多維數(shù)組。






>>> first_array = np.array([2,3,4])>>> first_arrayarray([2, 3, 4])>>> first_array.dtypedtype('int32')

其中,多維數(shù)組的dtype屬性指明了多維數(shù)組中元素的類型。當(dāng)然也可以將列表變量作為參數(shù):







>>> example_list = [2.0,3.0,4.0]>>> second_array = np.array(example_list)>>> second_arrayarray([2., 3., 4.])>>> second_array.dtypedtype('float64')

要注意的是,通過這種方式創(chuàng)建數(shù)組,經(jīng)常犯的一個(gè)錯(cuò)誤是缺少了列表的方括號(hào),這樣參數(shù)就不再是一個(gè)列表,而是好幾個(gè)獨(dú)立的參數(shù)了:



>>> a = np.array(1,2,3,4) # 這是錯(cuò)的>>> a = np.array([1,2,3,4]) # 這樣才是對(duì)的

實(shí)際上不僅是列表,同為 Python 中的序列類型,列表的親兄弟元組也可以起到相同的作用:




>>> a = np.array((2,3,4))>>> aarray([2, 3, 4])

同時(shí),使用array創(chuàng)建數(shù)組時(shí),如果提供的序列對(duì)象是嵌套的,NumPy 還可以直接據(jù)此生成二維、三維甚至更高維的多維數(shù)組:










>>> a = np.array(((2,3,4,5),(4,5,6,7)))>>> aarray([[2, 3, 4, 5], [4, 5, 6, 7]])>>> >>> a = np.array([(2,3,4,5),(4,5,6,7)])>>> aarray([[2, 3, 4, 5], [4, 5, 6, 7]])

還能在創(chuàng)建數(shù)組的同時(shí)顯式指定數(shù)據(jù)類型:










>>> complex_array = np.array([[1,2],[3,4]], dtype='complex')>>> complex_arrayarray([[1.+0.j, 2.+0.j], [3.+0.j, 4.+0.j]])>>> >>> float_array = np.array([[1,2],[3,4]], dtype='float64')>>> float_arrayarray([[1., 2.], [3., 4.]])

3.1.2 元素未知的創(chuàng)建方式

一般來(lái)說(shuō),很多時(shí)候我們都是知道多維數(shù)組的大小,但不知道其元素具體的值,因此 NumPy 提供了一些函數(shù),可以創(chuàng)建以占位符初始化的固定大小的多維數(shù)組。其中,zeros創(chuàng)建的是全為 0 的多維數(shù)組,ones創(chuàng)建的時(shí)候全為 1 的多維數(shù)組,而empty創(chuàng)建的則是隨機(jī)初始值的多維數(shù)組,數(shù)組大小由一個(gè)序列(即列表或元組,建議使用元組)參數(shù)給定。并且這幾種方式的默認(rèn)類型都是flloat64。























>>> np.zeros((3,4))array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]])>>> >>> np.ones((3,4))array([[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]])>>>>>> np.empty((3,4)) # empty 的結(jié)果就是一塊沒有初始化的內(nèi)存。這里由于形狀相同,是直接取了上一個(gè)數(shù)組的值array([[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]])>>> >>> np.empty((3,5)) # 增大數(shù)組的大小就可以得到預(yù)期的隨機(jī)結(jié)果了array([[1.40546330e-311, 1.40546113e-311, 1.37961302e-306, 6.23053614e-307, 8.45593934e-307], [7.56593017e-307, 8.01097889e-307, 1.78020169e-306, 7.56601165e-307, 1.02359984e-306], [2.04719290e-306, 1.00132653e-307, 1.78021527e-306, 1.66889876e-307, 3.49694131e-317]])

3.1.3 等差序列的數(shù)組

NumPy 還提供了一個(gè)類似于 Python 內(nèi)置的range的函數(shù)arange,用以創(chuàng)建一個(gè)由等差序列組成的數(shù)組:









>>> np.arange(10,30,5)array([10, 15, 20, 25])>>> >>> np.arange( 0, 2, 0.3 )array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])>>> >>> np.arange(0.2,0.3,0.01)array([0.2 , 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29])

可以看到,arange的參數(shù)還可以是浮點(diǎn)數(shù),與range略有不同。其他的特性都差不多,不再贅述。

3.1.4 元素?cái)?shù)量固定的浮點(diǎn)數(shù)組

由于浮點(diǎn)精度的原因,使用arange創(chuàng)建浮點(diǎn)數(shù)組時(shí),我們不能保證得到我們預(yù)期大小的數(shù)組,因此這個(gè)時(shí)候就建議使用linspace這個(gè)函數(shù)。linspacearange的區(qū)別就在于它們的第三個(gè)參數(shù):前者指定的是最終得到的元素個(gè)數(shù),而后者指定的則是元素間的步長(zhǎng)。




>>> np.linspace(0.2,0.3,9)array([0.2 , 0.2125, 0.225 , 0.2375, 0.25 , 0.2625, 0.275 , 0.2875, 0.3 ])

3.2 多維數(shù)組的基本屬性

多維數(shù)組是 NumPy 中最主要的對(duì)象。其實(shí)就是一個(gè)由同種元素組成的元素表,可以由元組進(jìn)行索引。在 NumPy 中,維度又被稱作“軸(axe)”。

注意,在繼續(xù)介紹數(shù)組的各種屬性之前,我們要區(qū)別開“數(shù)組的維度”和“數(shù)組某個(gè)軸上的維度”。

“數(shù)組的維度”指的是數(shù)組的“軸”數(shù),用維度空間的概念來(lái)理解,也就是數(shù)組能夠在多少個(gè)方向上具有坐標(biāo)。比如一維的線性空間中,數(shù)組就只能在 x 方向上具有坐標(biāo);對(duì)于二維的平面空間,數(shù)組就在 x 和 y 兩個(gè)方向上具有坐標(biāo)。

而“數(shù)組軸的維度”則是指的在某個(gè)特定的方向上,數(shù)組可以有幾個(gè)刻度,或者說(shuō)“層次”。比如一維數(shù)組[0,1,2]就是在 x 方向上具有 3 個(gè)層次;二維數(shù)組[[0,1,2],[2,3,4]]則是在 x 方向上具有 2 個(gè)層次,每個(gè)層次都是一個(gè)在 y 方向上的三個(gè)層次的一維數(shù)組,在 y 方向上具有 3 個(gè)層次,每個(gè)層次都是一個(gè)在 x 方向上具有兩個(gè)層次的一維數(shù)組。

下面介紹 NumPy 多維數(shù)組的基本屬性:

  1. ndim

ndim即“n dimension”的簡(jiǎn)寫。該屬性指示的是多維數(shù)組的維數(shù),或者說(shuō)是“軸數(shù)”。

  1. shape

字面意思。這個(gè)屬性指示的是多維數(shù)組整體的維度,或者說(shuō)是多維數(shù)組的“形狀”。是一個(gè)整型元組,每一個(gè)元素都對(duì)應(yīng)與相應(yīng)軸上的維數(shù)。對(duì) n 行 m 列的矩陣而言,它的shape就是(n,m)。shape的元素個(gè)數(shù)等于多維數(shù)組的軸數(shù)。

  1. size

多維數(shù)組中元素的總個(gè)數(shù)。等于shape中各元素之積。

  1. dtype

dtype實(shí)際上是“data type”的簡(jiǎn)寫,意味著它指示的是多維數(shù)組中元素的數(shù)據(jù)類型。

  1. itemsize

多維數(shù)組中,每個(gè)元素的字節(jié)大小。等效于dtype.itemsize。

  1. data

指示的是包含多維數(shù)組中元素實(shí)際內(nèi)存的緩沖區(qū)。通常用不到。

3.3 數(shù)組的打印形式

數(shù)組在打印的時(shí)候長(zhǎng)得跟嵌套列表差不多,但其排布都要遵循以下規(guī)律:

  • 最后一個(gè)軸從左往右打印;
  • 次后軸從上往下打印;
  • 剩下的軸都從上往下打印,每部分由一個(gè)空行隔開。

也就是說(shuō),一維數(shù)組按行打印,二維數(shù)組按矩陣形式打印,三維及更高維數(shù)組會(huì)打印成矩陣列表。
















































>>> print(np.zeros((2,))) # 一維數(shù)組[0. 0.]>>>>>> print(np.zeros((2,3))) # 二維數(shù)組[[0. 0. 0.] [0. 0. 0.]]>>>>>> print(np.zeros((2,3,4))) # 三維數(shù)組[[[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(np.zeros((2,3,4,5))) # 四維數(shù)組[[[[0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.]]]

[[[0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.]]]]

3.4 重整多維數(shù)組的大小

另外,為了更靈活地使用多維數(shù)組,NumPy 還提供了reshape方法,可以將多維數(shù)組重整為某個(gè)大小。

比如在圖像識(shí)別領(lǐng)域,就需要圖像作為機(jī)器學(xué)習(xí)輸入數(shù)據(jù),而實(shí)用的機(jī)器學(xué)習(xí)應(yīng)用圖像來(lái)源又是不確定的,因此圖像的像素陣列大小不一定一致。

使用reshape要求參數(shù)乘積與被重整的數(shù)組元素個(gè)數(shù)相同:















>>> np.arange(12)array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])>>> >>> np.arange(12).reshape(2,6)array([[ 0, 1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])>>> >>> np.arange(12).reshape(6,2)array([[ 0, 1], [ 2, 3], [ 4, 5], [ 6, 7], [ 8, 9], [10, 11]])

并且reshape還允許缺省 1 個(gè)參數(shù)(用-1占位),它會(huì)根據(jù)數(shù)組元素的總數(shù)和提供的其他參數(shù)自動(dòng)求出一個(gè)合適的值,從而得到新的大小的數(shù)組:


















>>> np.arange(12).reshape(2,3,2)array([[[ 0, 1], [ 2, 3], [ 4, 5]],
[[ 6, 7], [ 8, 9], [10, 11]]])>>> >>> np.arange(12).reshape(2,-1,2)array([[[ 0, 1], [ 2, 3], [ 4, 5]],
[[ 6, 7], [ 8, 9], [10, 11]]])

4. 多維數(shù)組的索引

本節(jié)參考自《NumPy 索引》。示例代碼多來(lái)自《NumPy 索引》。

所謂索引,在 NumPy 中指的是任何用中括號(hào)來(lái)獲取數(shù)組元素值的行為。

NumPy 中,索引的方式有很多,這既使得 NumPy 更加強(qiáng)大靈活,也帶來(lái)了難于辨析的問題。

4.1 常用方式

最簡(jiǎn)單的一種索引方式就是單個(gè)索引。對(duì)于一維數(shù)組,我們可以像對(duì) Python 中的序列一樣進(jìn)行索引:






>>> x = np.arange(10)>>> x[2]2>>> x[-2]8

對(duì)于二維和更高維的數(shù)組,我們可以在同一個(gè)中括號(hào)內(nèi)直接索引:






>>> x.shape = (2,5) # 等同于 x = x.reshape(2,5)>>> x[1,3]8>>> x[1,-1]9

而不必像對(duì)嵌套序列一樣,用多個(gè)中括號(hào)分別索引:






>>> y = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]] # 這是一個(gè)列表,不是 NumPy 多維數(shù)組!>>> y[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]>>> y[1][3]8

當(dāng)給出的索引少于數(shù)組維數(shù)(軸數(shù))時(shí),得到的會(huì)是一個(gè)數(shù)組對(duì)象:



>>> x[0]array([0, 1, 2, 3, 4])

而對(duì)于返回的這個(gè)數(shù)組,我們又可以繼續(xù)索引,因此對(duì)于多維數(shù)組而言,也可以使用嵌套序列的索引方式,即使用多個(gè)中括號(hào)(但這種方式比一次索引要更低效,因此不推薦):



>>> x[0][2]2

此外,NumPy 多維數(shù)組又可以像列表一樣,進(jìn)行切片(用冒號(hào)“:”):








>>> x = np.arange(10)>>> xarray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>>> x[2:5]array([2, 3, 4])>>> x[1:7:2]array([1, 3, 5])

數(shù)組也可以用另一個(gè)數(shù)組來(lái)索引:






>>> x = np.arange(10,1,-1)>>> xarray([10, 9, 8, 7, 6, 5, 4, 3, 2])>>> x[np.array([3, 3, 1, 8])]array([7, 7, 9, 2])

4.2 不常用方式

也可以用多個(gè)數(shù)組來(lái)進(jìn)行索引:













>>> y = np.arange(35).reshape(5,7)>>> yarray([[ 0, 1, 2, 3, 4, 5, 6], [ 7, 8, 9, 10, 11, 12, 13], [14, 15, 16, 17, 18, 19, 20], [21, 22, 23, 24, 25, 26, 27], [28, 29, 30, 31, 32, 33, 34]])>>> y[np.array([0,2,4]), np.array([0,1,2])]array([ 0, 15, 30])>>> >>> y[np.array([0,2,4]), 1]array([ 1, 15, 29])

還可以用布爾數(shù)組作為掩碼,篩選數(shù)組元素:










>>> b = y>20>>> barray([[False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [ True, True, True, True, True, True, True], [ True, True, True, True, True, True, True]])>>> y[b]array([21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34])

對(duì)應(yīng)于布爾數(shù)組中為“真”的元素就被篩選出來(lái)了。

5. NumPy 中的廣播

本小節(jié)參考自《NumPy 廣播》和《NumPy 廣播機(jī)制詳解》。圖片來(lái)自《NumPy 廣播機(jī)制詳解》。

NumPy 中,各種運(yùn)算默認(rèn)都是“逐元素”進(jìn)行的。最簡(jiǎn)單的例子就是兩個(gè)明顯大小相同的數(shù)組運(yùn)算:





>>> a = np.array([1.0, 2.0, 3.0])>>> b = np.array([2.0, 2.0, 2.0])>>> a * barray([ 2., 4., 6.])

但是逐元素計(jì)算有一個(gè)問題:對(duì)于形狀不太像的數(shù)組怎么辦呢?比如下面這個(gè)數(shù)組和標(biāo)量的乘法運(yùn)算:




>>> multi_array = np.array([1.0,2.0,3.0])>>> scalar = 2.0>>> multi_array * scalar # array([2., 4., 6.])

按“逐元素”運(yùn)算的預(yù)期,顯然我們是期望把這個(gè)標(biāo)量與數(shù)組的每一個(gè)元素相乘,來(lái)得到一個(gè)新的數(shù)組。但是 NumPy 懂得這其中的邏輯嗎?誒?好像還真的懂。

既然我們號(hào)稱 NumPy 可以用自然的方式來(lái)表達(dá)數(shù)學(xué)公式,肯定不能把一個(gè)簡(jiǎn)單的標(biāo)量乘向量弄得太復(fù)雜,同樣是直接乘就可以了,得到的結(jié)果與之前兩個(gè)大小相同的數(shù)組直接相乘是一樣的:



>>> multi_array * scalararray([2., 4., 6.])

在這里邊,標(biāo)量scalar就好像被擴(kuò)展為了一個(gè)跟multi_array大小相當(dāng)?shù)臄?shù)組一樣。

NumPy 標(biāo)量廣播圖示

5.1 廣播的前提:相容的形狀

在 NumPy 的廣播機(jī)制中,有一個(gè)很重要的概念叫做“相容的形狀”。只有當(dāng)兩個(gè)數(shù)組具有“相容的形狀”時(shí),“廣播”才能起作用;否則拋出異常ValueError: operands could not be broadcast together with shapes xx yy。

所謂“相容的形狀”,指的是參與運(yùn)算的這兩個(gè)數(shù)組各個(gè)維度要么 1)相等;要么 2)其中一個(gè)數(shù)組的對(duì)應(yīng)維度為 1(不存在的維度也是 1)。

而 NumPy 比較各個(gè)維度的順序是從后往前,一次比較,就相當(dāng)于把參與運(yùn)算的數(shù)組形狀右對(duì)齊,然后若相等就再往前看,若其中一個(gè)為 1 就將其在這個(gè)維度上擴(kuò)展到更高的維度,直到第一個(gè)維度。

下面是對(duì)于上述規(guī)則一個(gè)更清晰的表述描述:








Image (3d array): 256 x 256 x 3Scale (1d array): 3Result (3d array): 256 x 256 x 3
A (4d array): 8 x 1 x 6 x 1B (3d array): 7 x 1 x 5Result (4d array): 8 x 7 x 6 x 5

但是像這樣的兩個(gè)數(shù)組就無(wú)法通過“廣播”實(shí)現(xiàn)逐元素運(yùn)算了:






A (1d array): 3B (1d array): 4 # 最后一個(gè)維度無(wú)法匹配
A (2d array): 2 x 1B (3d array): 8 x 4 x 3 # 倒數(shù)第二個(gè)維度無(wú)法匹配

5.2 廣播的實(shí)例

對(duì)于一個(gè)多維數(shù)組和一個(gè)一維數(shù)組的運(yùn)算,實(shí)例如下:















>>> a = np.array([[ 0.0, 0.0, 0.0],... [10.0, 10.0, 10.0],... [20.0, 20.0, 20.0],... [30.0, 30.0, 30.0]])>>> b = np.array([1.0, 2.0, 3.0])>>> a.shape(4, 3)>>> b.shape(3,)>>> a + barray([[ 1., 2., 3.], [11., 12., 13.], [21., 22., 23.], [31., 32., 33.]])

廣播圖示如下:

NumPy 向量廣播圖示

對(duì)齊之后,維度不相容是萬(wàn)萬(wàn)不行的:














>>> a = np.array([[ 0.0, 0.0, 0.0],... [10.0, 10.0, 10.0],... [20.0, 20.0, 20.0],... [30.0, 30.0, 30.0]])>>> b = np.array([1.0, 2.0, 3.0])>>> a.shape(4, 3)>>> b.shape(4,)>>> a + bTraceback (most recent call last): File "<stdin>", line 1, in <module>ValueError: operands could not be broadcast together with shapes (4,3) (4,)

圖示如下:

NumPy 向量無(wú)法廣播的圖示

當(dāng)然我們也可以通過reshape重整b數(shù)組的形狀,以適應(yīng)廣播的要求:
















>>> b.shape(4,)>>> b = b.reshape(4,1)>>> b.shape(4, 1)>>> barray([[1.], [2.], [3.], [4.]])>>> a + barray([[ 1., 1., 1.], [12., 12., 12.], [23., 23., 23.], [34., 34., 34.]])

這樣就沒問題了。

6. 多維數(shù)組切片之圖像裁剪

看了那么多枯燥的原理,我們接下來(lái)輕松一下,看看 NumPy 還能干什么。

喜歡拍照的同學(xué)都知道,圖片是由“像素(pixel)”構(gòu)成的。所謂“像素”,英文 pixel 就是“picture element”的簡(jiǎn)寫,指的是“構(gòu)成圖像的元素”。

實(shí)際上我們可以把一張圖片縱橫切分成很多小塊,這些最基本的小方格就是構(gòu)成多姿多彩的數(shù)字圖像世界的一磚一瓦。作為二維的圖像,它們像素的排布是不是跟二維數(shù)組很像?誒~ 對(duì)了,我們可以用一個(gè)很常用的圖形庫(kù)matplotlib來(lái)讀取圖像,得到的實(shí)際上就是一個(gè) NumPy 二維數(shù)組:





>>> import matplotlib.pyplot as plt>>> image = plt.imread("python-logo.png")>>> image.shape(600, 800, 3)
Python Logo

取下一半圖像:





>>> image_crop = image[300:,::,::]>>> plt.imshow(image_crop)<matplotlib.image.AxesImage object at 0x0000019C783EA2B0>>>> plt.show()
Python Logo 裁剪圖

取右邊一半的圖像:





>>> image_crop = image[:,400:,:]>>> plt.imshow(image_crop)<matplotlib.image.AxesImage object at 0x0000019C78BC0BE0>>>> plt.show()
Python Logo 裁剪圖

7. 總結(jié)

本文對(duì)我們以后經(jīng)常會(huì)用到的 NumPy 模塊進(jìn)行了簡(jiǎn)要的介紹。雖然本文篇幅已經(jīng)很長(zhǎng),但對(duì)于 NumPy 相關(guān)知識(shí)的講解依然只是滄海一粟。

本文的目的在于給讀者提供一個(gè)粗略的印象,記不住沒關(guān)系,希望在以后的使用中讀者能夠熟練掌握 NumPy 的使用。

8. 參考資料

[1]https://numpy.org/

[2]https://numpy.org/devdocs/user/whatisnumpy.html

[3]https://numpy.org/devdocs/user/quickstart.html

[4]https://numpy.org/devdocs/user/basics.indexing.html

[5]https://numpy.org/devdocs/user/basics.broadcasting.html

[6]https://numpy.org/devdocs/user/theory.broadcasting.html

示例代碼:https://github.com/JustDoPython/python-100-day

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Python數(shù)據(jù)分析之numpy學(xué)習(xí)(一)
Python之Numpy庫(kù)常用函數(shù)大全(含注釋)
入門numpy(上)【解讀numpy官方文檔】
Python 數(shù)據(jù)分析基礎(chǔ)包:Numpy
Python 數(shù)據(jù)操作教程:NUMPY 教程與練習(xí)
python創(chuàng)建數(shù)組的12種方式
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服