第4章 Numpy基礎(chǔ)(2)

以下內(nèi)容主要學(xué)習(xí)自《利用Python進(jìn)行數(shù)據(jù)分析》

第4章 NumPy基礎(chǔ)(2)

NumPy是Numerical Python的簡(jiǎn)稱(chēng),它是目前Python數(shù)值計(jì)算中最為重要的基礎(chǔ)包。大多數(shù)計(jì)算包都提供了基于Numpy的科學(xué)函數(shù)功能,將NumPy的數(shù)組對(duì)象作為數(shù)據(jù)交換的通用語(yǔ)言。

本章將介紹NumPy數(shù)組的基礎(chǔ)操作。雖然深入理解NumPy對(duì)于大部分?jǐn)?shù)據(jù)分析應(yīng)用并不是必需的,但是精通基于數(shù)組的編程和思維是成為Python科學(xué)計(jì)算專(zhuān)家的第一步。

NumPy-2

ndarray索引與切片

Numpy.ndarray的索引與切片是一個(gè)值得學(xué)習(xí)的話(huà)題。有很多方式可以讓你選中數(shù)據(jù)的子集或某個(gè)單一元素。

所謂“索引”,就是通過(guò)單一的索引號(hào),得到ndarray的部分?jǐn)?shù)據(jù);所謂“切片”,就是通過(guò)索引號(hào)段,得到ndarray的部分?jǐn)?shù)據(jù)。索引可以取得原數(shù)組降維的部分?jǐn)?shù)據(jù),而切片不會(huì)降低維度,而是得到一個(gè)維度相同的子集

如果熟悉Python的列表操作,那么很容易掌握ndarray的索引與切片,因?yàn)檎Z(yǔ)法是相似的。

索引

通過(guò)索引獲得單一的元素

NumPy的索引語(yǔ)法與Python列表的索引語(yǔ)法是一樣的。如下是對(duì)一維數(shù)組進(jìn)行索引:

In[1]: arr = np.arange(10)

In[2]: arr
Out[2]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In[3]: arr[5]  #一維數(shù)組的索引
Out[3]: 5

如果要從二維數(shù)組(或多維數(shù)組)中取得單一元素,那么就要提供多個(gè)索引值。如下是對(duì)二維數(shù)組進(jìn)行索引:

In [4]: arr = arr.reshape(2, 5)

In [5]: arr
Out[5]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

In [6]: arr[1][3]  # 二維數(shù)組的索引
Out[6]: 8

In [7]: arr[1, 3]  # 盡管索引語(yǔ)法不同,但索引效果一樣
Out[7]: 8
通過(guò)索引獲得ndarray的子集

可以從二維(或多維)數(shù)組中,獲得ndarray的自己,方法是在多維數(shù)組中,如果省略后續(xù)索引值,返回的對(duì)象將是降低一個(gè)維度的數(shù)組。

# 生成一個(gè)維度為(2,3,4)的三維數(shù)組
In [1]: arr = np.arange(24).reshape(2, 3, 4)

In [2]: arr
Out[2]:
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

In [3]: arr[0]  # 返回第1維、索引號(hào)為0的子集,返回的將是二維數(shù)組
Out[3]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [4]: arr[0][1]  # 返回一維數(shù)組
Out[4]: array([4, 5, 6, 7])

切片

一維數(shù)組的切片

與Python列表類(lèi)似,NumPy數(shù)組可以通過(guò)相似的語(yǔ)法對(duì)數(shù)組進(jìn)行切片。

In[1]: arr = np.arange(10)

In[2]: arr
Out[2]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In[3]: sub = arr[5:8]  # 通過(guò)切片獲取部分?jǐn)?shù)據(jù)

In[4]: sub
Out[4]: array([5, 6, 7])

In [5]: sub.shape  # sub是一個(gè)有三個(gè)元素的一維數(shù)組
Out[5]: (3,)

In[6]: sub[0:2] = 12  # 對(duì)切片賦值,就是對(duì)切片中的每一個(gè)元素賦值

In[7]: arr
Out[7]: array([ 0,  1,  2,  3,  4, 12, 12, 7,  8,  9])

注意,區(qū)別于Python的內(nèi)建列表,ndarray的切片是原數(shù)組的視圖,這意味著數(shù)據(jù)并不是被復(fù)制了,任何對(duì)于視圖的修改都會(huì)反映到原數(shù)組上。這是因?yàn)镹umPy被設(shè)計(jì)成適合處理非常大的數(shù)組,你可以想象如果NumPy持續(xù)復(fù)制數(shù)據(jù)會(huì)引起內(nèi)存和性能問(wèn)題。

如果你是NumPy新手,你可能對(duì)此感到驚訝,因?yàn)槠渌木幊陶Z(yǔ)言都是急切地復(fù)制數(shù)據(jù)。如果你堅(jiān)持要得到一份數(shù)組切片的拷貝,而不是一份視圖的話(huà),可以試用ndarray.copy()方法顯式地復(fù)制數(shù)據(jù)。

In [8]: sub = arr[0:3].copy()  # 顯式地復(fù)制數(shù)據(jù)

In [9]: sub
Out[9]: array([0, 1, 2])

In [10]: sub[0:3] = 99

In [11]: sub
Out[11]: array([99, 99, 99])

# 通過(guò)復(fù)制的子集,不會(huì)影響原數(shù)組
In [12]: arr
Out[12]: array([ 0,  1,  2,  3,  4, 13, 13, 12,  8,  9])
多維數(shù)組的切片
In [1]: arr = np.arange(12).reshape(3,4)

In [2]: arr  # 一個(gè)3X4的二維數(shù)組
Out[2]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

# 對(duì)二維數(shù)組進(jìn)行切片,得到一個(gè)子集
# 1:3表示從第2行開(kāi)始,取3-1=2行
# 2:4表示從第3列開(kāi)始,取4-2=2列
In [3]: arr[1:3, 2:4]
Out[3]:
array([[ 6,  7],
       [10, 11]])

注意:索引可以取得原數(shù)組降維的部分?jǐn)?shù)據(jù),而切片不會(huì)降低維度,而是得到一個(gè)維度相同的子集。妥善地混合索引和切片,就可以得到低維度的切片。

In [4]: arr[1, 1:3]  # 獲取第2行,2、3列數(shù)據(jù)
Out[4]: array([5, 6])

單獨(dú)一個(gè)冒號(hào)表示選擇整個(gè)軸上的數(shù)組,并且對(duì)原數(shù)組的切片賦值,那么原數(shù)組也會(huì)被賦值。這也是因?yàn)镹umPy被設(shè)計(jì)成適合處理非常大的數(shù)組,因此缺省是按地址引用。

In [1]: arr = np.arange(12).reshape(3,4)

In [2: arr
Out[2]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

# 獲取所有行、第1列的切片
In [3]: sub = arr[:, :1]

In [4]: sub
Out[4]:
array([[0],
       [4],
       [8]])

# 把切片中的所有元素賦值為0
In [5]: sub[:,:] = 0

# 對(duì)切片的賦值,會(huì)影響到原數(shù)組
In [6]: arr
Out[6]:
array([[ 0,  1,  2,  3],
       [ 0,  5,  6,  7],
       [ 0,  9, 10, 11]])

神奇索引

神奇索引這個(gè)詞很容易讓人誤解,它是NumPy的一個(gè)術(shù)語(yǔ)。簡(jiǎn)單來(lái)講,神奇索引的目的是用整數(shù)數(shù)組對(duì)ndarray數(shù)據(jù)進(jìn)行索引。

假設(shè)我們有一個(gè)8X4的數(shù)組:

In [1]: arr = np.empty((8,4))

In [2]: for i in range(8):
    ...:     arr[i] = i+1

In [3]: arr
Out[3]:
array([[1., 1., 1., 1.],
       [2., 2., 2., 2.],
       [3., 3., 3., 3.],
       [4., 4., 4., 4.],
       [5., 5., 5., 5.],
       [6., 6., 6., 6.],
       [7., 7., 7., 7.],
       [8., 8., 8., 8.]])

如果我們要從如上的數(shù)組中,選擇第5、4、1、7行組成的子集,那么可以傳遞[4,3,0,6]來(lái)得到(注意數(shù)組下標(biāo)從0開(kāi)始)

In [4]: arr[[4, 3, 0, 6]]
Out[4]:
array([[5., 5., 5., 5.],
       [4., 4., 4., 4.],
       [1., 1., 1., 1.],
       [7., 7., 7., 7.]])

如果使用負(fù)數(shù)索引,將從尾部進(jìn)行選擇:

In [5]: arr[[-3, -5, -7]]
Out[5]:
array([[6., 6., 6., 6.],
       [4., 4., 4., 4.],
       [2., 2., 2., 2.]])

注意上面的例子,原數(shù)組是二維的,但傳入了一個(gè)索引維度,所以是得到了降維后的子集。如果傳入兩個(gè)索引,將得到一維數(shù)組。

In [1]: arr = np.arange(12).reshape(3,4)

In [2]: arr
Out[2]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

# 選去第1行第2個(gè)元素、以及第3行第4個(gè)元素。
In [3]: arr[[0,2], [1, 3]]
Out[3]: array([ 1, 11])

請(qǐng)牢記:神奇索引與切片不同,它總是將數(shù)據(jù)復(fù)制到一個(gè)新的數(shù)組中。

布爾索引

假設(shè)我們有7X3的數(shù)據(jù),這7行數(shù)據(jù)數(shù)據(jù)屬于3個(gè)人,如下示例:

In [1]: names = np.array(['張三', '王五', '李四', '張三', '王五', '王五', '李四'])

# 生成一個(gè)7X3的數(shù)組,數(shù)組中的每個(gè)元素是0~10的隨機(jī)數(shù)
In [2]: data = np.random.randint(low=0, high=10, size=(7,3))

In [3]: data
Out[3]:
array([[4, 0, 2],
       [8, 1, 5],
       [3, 3, 1],
       [4, 9, 3],
       [3, 7, 3],
       [7, 8, 4],
       [5, 4, 7]])

用names數(shù)組與字符串'張三'比較會(huì)產(chǎn)生一個(gè)布爾值數(shù)組:

In [4]: names == '張三'
Out[4]: array([ True, False, False,  True, False, False, False])

如果把這個(gè)布爾值數(shù)組當(dāng)作“神奇索引”,傳遞給data數(shù)組,會(huì)得到如下結(jié)果

In [5]: data[names == '張三']
Out[5]:
array([[4, 0, 2],
       [4, 9, 3]])

如上,其效果等同于選擇出了所有“張三”的行數(shù)據(jù)。

ndarray排序

一維數(shù)組的排序

數(shù)組實(shí)例可以使用sort方法進(jìn)行排序。

In [1]: arr = np.random.randn(6)

In [2]: arr
Out[2]:
array([-1.51683294,  0.71207739, -1.91733282, -1.07901923, -0.35628366,
       -0.52888226])

In [3]: arr.sort()

In [4]: arr
Out[4]:
array([-1.91733282, -1.51683294, -1.07901923, -0.52888226, -0.35628366,
        0.71207739])

多維數(shù)組的排序

對(duì)于多維數(shù)組的排序,可以使用NumPy的頂層sort函數(shù),該函數(shù)可以接送axis參數(shù),以便按照某一個(gè)維度排序。

In [1]: arr = np.random.randint(-5, 5, (3,4))

In [2]: arr
Out[2]:
array([[ 2,  4, -4, -3],
       [-1, -5,  2,  0],
       [-3, -4, -3, -3]])

In [3]: np.sort(arr, axis=0)
Out[3]:
array([[-3, -5, -4, -3],
       [-1, -4, -3, -3],
       [ 2,  4,  2,  0]])

In [4]: np.sort(arr, axis=1)
Out[4]:
array([[-4, -3,  2,  4],
       [-5, -1,  0,  2],
       [-4, -3, -3, -3]])
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容