Python-科學計算NumPy模塊(1)
1.前言
我們都知道在Python中有一個list的數據類型,list擁有強大的功能,它是元素的集合併且它裡面的元素可以是任何Python數據類型,list可以很方便的對它裡面的元素進行增刪改查的操作。但是我們如果需要進行科學計算的話需要滿足下面兩點:
- 能直接對集合進行數學操作;
- 運算速度要快,對於機器學習來說需要進行科學計算的數據量可能很大;
heigh = [1.74,1.68,1.71]weight = [65.4,59.2,63.6]ibm = heigh/weight**2print(ibm)Traceback (most recent call last): File "G:/Python源碼/numpy_test/numpy_test.py", line 58, in <module> ibm = heigh/weight**2TypeError: unsupported operand type(s) for ** or pow(): list and int
從上面的代碼可以看出:
1.list並不能直接對整個集合進行數學的相關操作,因為list中的元素可以是任意類型,如果進行數學運算的話不知道是什麼類型。
我們的解決方案就是我們的NumPy模塊。NumPy(Numerical Python的簡稱)是高性能科學計算和數據分析的基礎包。由於NumPy提供了一個簡單易用的C API,因此很容易將數據傳遞給低級語言編寫的外部庫,外部庫也能以NumPy數組的形式將數據返回給Python。這個功能使Python稱為一種包裝C/C++/Fortran歷史代碼庫的選擇,並使被包裝庫擁有一個動態的、易用的介面。numpy數組是Python中list數據類型的一個替代品,它能夠對整個數組(集合)進行數學的操作。
import numpy as npnp_heigh = np.array([1.74,1.68,1.71])np_weight = np.array([65.4,59.2,63.6])ibm = np_heigh/np_weight**2print(ibm)[ 0.00040681 0.00047936 0.00042275]
從上面代碼可以看出:
1.我們可以很輕鬆的對numpy ndarray進行集合的數學操作。
我們說完了對於科學計算很重要的能直接對集合進行數學操作。那速度是如何體現出來的呢?
#在list中list = [1.0,is,True]print(list)[1.0, is, True]#在numpy中import numpy as npnp_a = np.array([1.0,is,True])print(np_a)[1.0 is True]
從上面代碼可以看出:
1.對於list來說裡面的元素可以是任意Python數據類型,而numpy array中的元素必須是一致的,如果我們定義的數據類型不一致的話,就會自動幫我們轉換成一致的數據類型。2.如果對NumPy中的元素進行操作的話,因為他裡面都是相同類型的數據類型,速度一定比對list操作要快的很多。
2.NumPy的ndarray:一種多維數組對象
- 我們從上面了解到,我們使用array函數創建的對象都是ndarray,其實這也是NumPy的最重要的一個特點N維數組對象,這個對象是一個快速而靈活的大數據集容器。我們通過上面對集合進行數學運算時候也看到了,我們可以利用ndarray這種數組對整塊的數據執行一些數學運算。當然他的語法和標量元素之間的運算是一樣的。
- 還有一點我們上面也提到了,就是ndarray是一個通用的同構數據多維容器,也就是說,其中所有元素必須是相同類型的(與Python中的list很明顯的區別)
3.NumPy數組可以表示的類型
你肯定會說這裡又是數組有是ndarray對象的,他們有什麼區別呢?其實我們可以認為他們是等同的。我們從上面知道了對於list數據類型的替代品numpy ndarray。其實ndarray就是n維的一個array,我們可以通過numpy的array函數來創建一個ndarray對象。ndarray可以有任意數量的維度。由於他可以存儲任意數量的維度,所以我們可以使用ndarray來表示我們所熟知的任意數據的類型。下面我就詳細的介紹用numpy ndarray來表示標量、向量、矩陣以及張量。
當然在介紹能表示的數據之前,我們需要先了解ndarray對象的shape屬性以及說明數組數據類型的dtype對象(說白了就是數組中元素的類型)。shape他返回的是一個表示各個維度大小的元組,當然如果想要改變形狀,可以使用ndarray.shape = 元組進行更改。dtype說明數組數據類型的對象,由於我們上面說過,我們的數組是一個通用的數據多維容器,所以他裡面的元素的類型都是一樣的,也就是說對於我們每個數組來說,他的dtype只有一個。
import numpy as nparray = np.array([1,2,3])print(array)print(array.shape)print(array.dtype)print(type(array))[1,2,3](3,)int32<class numpy.ndarray>
2.1標量
我們都知道在Python中有int、float、string...這些基本的數據類型,所以能表示的標量可以是整數、浮點數以及字元...類型。但在NumPy中他能表示的標量的類型比Python所能表示的還要多。NumPy 可以讓你指定有符號和無符號的類型以及不同的大小。因此,你可以使用 uint8、int8、uint16、int16、uint32、int32、uint64、int64、float8、float16、float32、float64等類型,後面的8、16、32以及64是代表位數。後面講dtype時候在詳細的講解他們的類型。
位數越大,精確度就越高,但是佔用的空間就會越大
位數越小,精確度就越低,但是佔用的空間就會越小
import numpy as npscalar = np.array(5)print(scalar)print(scalar.dtype)print(scalar.shape)print(type(scalar))print("---------------")scalar = scalar + 15print(scalar)print(scalar.dtype)print(scalar.shape)print(type(scalar))5int32()<class numpy.ndarray>---------------20int32()<class numpy.int32>
從上面的代碼可以看出:
1.NumPy中的標量不論是與Python中的標量還是Python中的標量都是可以直接進行運算的。2.使用array函數創建ndarray對象,但是他如果和標量(無論是Python中還是numpy中的標量)運算。他的結果都會是numpy.變數數據類型的對象。而不會再是ndarray對象。3.我們列印標量的形狀,列印輸出一個()。我們從上面知道,調用shape屬性,返回的是一個表示維度的一個元組。那麼在標量中調用shape我們可以看出他返回的是一個()。這個()在Python中表示的是一個tuple對象。()這表示它的維度為零,是標量。
2.2向量(Vectors)
import numpy as npvector = np.array([1,2,3,4,5])print(vector)print(vector.dtype)print(type(vector))print(vector.shape)[1 2 3 4 5]int32<class numpy.ndarray>(5,)
從上面的代碼可以看出:
1.我們可以看出返回的結果是(5,)元組,因為向量只有一個維度,所以元組中僅僅包含了一個數字和一個逗號。2.我們看標量的形狀為(),為什麼不是(5)這樣表示呢?我們的shape總是返回元組。因為在Python中如果(5)他並不能理解成僅有一項的元組,所以有了逗號,就能識別他是一個元組了。
a = (5)print(a)print(type(a))print("----------")b = (5,)print(b)print(type(b))5<class int>----------(5,)<class tuple>
2.3矩陣(Matrices)
import numpy as npmatrices = np.array([[1,2,3], [4,5,6], [7,8,9]])print(matrices)print(matrices.dtype)print(matrices.shape)print(type(matrices))[[1 2 3] [4 5 6] [7 8 9]]int32(3,3)<class numpy.ndarray>
4.創建數組(ndarray)
上面的代碼使用了創建數組最簡單的函數array。他接受一切的序列型的對象(序列型的對象可以是list,tuple...其他序列類型,當然這個函數參數也可以是另一個ndarray)。我們使用list序列對象作為array函數的參數為例:
import numpy as nparray = np.array([1,2,3])print(array)print(array.dtype)[1 2 3]int32
從上面代碼可以看出:
1.我這裡並沒有給數組中的元素指定一個類型值,但是我的np.array會嘗試為新建的這個數組推斷出一個較為合適的數據類型本例中是int32。數據類型保存在一個特殊的dtype對象中。
當然也就是說數組中的元素類型不一致,並且我們沒有進行顯示的給dtype參數賦值的話(當然我們可以在創建ndarray對象的時候給dtype賦值指定數據類型),np.array就會嘗試為新建的這個數組推斷出一個較為合適的數據類型。數據類型保存在一個特殊dtype對象。一會我們會單獨拿出一個部分來說這個dtype對象。
#使用array函數,參數為序列類型#這裡尤為要說明的是他的參數可以是另一個數組(ndarray)import numpy as nparray = np.array([1,2,3])array2 = np.array(array)#這裡我的array函數參數是ndarrayprint(array)print(array2)print("----------")print(type(array))print(type(array2))print("----------")#is判斷的是a對象是否就是b對象,是通過id來判斷的print(array is array2)[1 2 3][1 2 3]----------<class numpy.ndarray><class numpy.ndarray>----------False
從上面代碼可以看出:
1.我們使用is關鍵字來查看是否為同一個對象,我們可以看出array和array2是不同的對象,也就是說,當我們使用一個ndarray對象作為array函數的參數的時候得到的另一個ndarray對象的時候,這另一個數組是對參數中數組的一個copy。直白點說就是他們佔用不同的內存相互之間沒有任何關係。
#使用asarray,其實這個函數和array函數的功能一樣#但是有一點不一樣:如果參數是另一個數組(ndarray)# 1.array函數,創建的另一個對象不是同一個# 2.asarray函數,創建的另一個對象是同一個import numpy as nparray = np.asarray([1,2,3])array2 = np.asarray(array)print(array)print(array2)print("----------")print(type(array))print(type(array2))print("----------")#is判斷的是a對象是否就是b對象,是通過id來判斷的print(array is array2)[1 2 3][1 2 3]----------<class numpy.ndarray><class numpy.ndarray>----------True
從上面代碼可以看出:
1.我們可以看出如果對於asarray函數來說參數不是ndarray的話,與array函數沒有什麼區別,但是如果是ndarray的話,通過asarray不進行複製,也就是他返回的是同一個對象。也就是通過is關鍵字,返回的結果是True。直白點說就是他們共享同一塊內存空間。
import numpy as np#這裡arange函數用的還是比較多的,所以單拿出來#np.arange(start,end,step)array = np.arange(4)print(array)[0 1 2 3]array2 = np.arange(1,10,2)print(array2)[1 3 5 7 9]#如果我想通過arange生成矩陣,怎麼辦呢?#注意這裡生成的行*列一定要等於生成元素的個數#如果不滿足行*列等於元素個數#會拋出ValueError: total size of new array must be unchangedarray3 = np.arange(1,10,2).reshape((5,1))print(array3)[[1] [3] [5] [7] [9]]#這裡因為函數中的參數start>end,並且沒有指定步長step#所以輸出結果為[]array4 = np.arange(14,2)print(array4)[]#這裡雖然指定了步長,但是步長為>0的一個正數,#所以這裡輸出結果也會是[]array5 = np.arange(14,2,2)#這裡的步長>0(用於測試)print(array5)[]array6 = np.arange(14,2,-1)#這裡的步長<0(用於測試)print(array6)[14 13 12 11 10 9 8 7 6 5 4 3]
import numpy as nparray = np.ones(4)array2 = np.ones((4,))#array3 = np.ones((4,4))#參數是數組或者序列類型,#返回的根據參數的形狀和dtype創建一個為1的數組array4 = np.ones_like([1,2,3])array5 = np.ones_like([[1,2,3], [4,5,6]])print(array)print(array2)print(array3)print("----------")print(array4)print(array5)print("----------")print(array.dtype)print(array2.dtype)print(array3.dtype)[ 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] [1 1 1]]----------float64float64float64
import numpy as nparray = np.zeros(4)array2 = np.zeros((4,))#array3 = np.zeros((4,4))#參數是數組或者序列類型,#返回的根據參數的形狀和dtype創建一個為1的數組array4 = np.zeros_like([1,2,3])array5 = np.zeros_like([[1,2,3], [4,5,6]])print(array)print(array2)print(array3)print("----------")print(array4)print(array5)print("----------")print(array.dtype)print(array2.dtype)print(array3.dtype)[ 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]]----------float64float64float64
import numpy as nparray = np.empty(4)array2 = np.empty((4,))#array3 = np.empty((4,4))#參數是數組或者序列類型,#返回的根據參數的形狀和dtype創建一個為1的數組array4 = np.empty_like([1,2,3])array5 = np.empty_like([[1,2,3], [4,5,6]])print(array)print(array2)print(array3)print("----------")print(array4)print(array5)print("----------")print(array.dtype)print(array2.dtype)print(array3.dtype)[ 9.90263869e+067 8.01304531e+262 2.60799828e-310 9.48818959e+077][ 9.90263869e+067 8.01304531e+262 2.60799828e-310 1.57027689e-312][[ 6.23042070e-307 1.89146896e-307 1.37961302e-306 1.05699242e-307] [ 8.01097889e-307 1.78020169e-306 7.56601165e-307 1.02359984e-306] [ 1.33510679e-306 2.22522597e-306 1.24611674e-306 1.29061821e-306] [ 6.23057349e-307 1.86920193e-306 9.34608432e-307 2.56765117e-312]]----------[0 0 0][[0 0 0] [0 0 0]]----------float64float64float64
從上面代碼可以看出:
1.np.empty會返回全0數組的想法是不安全的。很多情況下他返回的都是一些未初始化的垃圾值。2.我們從上面可以看出我們創建數組的時候,調用dtype的時候返回的都是float64,這是因為NumPy關注的是數值的計算,所以在NumPy中如果沒有特別的指定,數據類型基本上都是float64(浮點數)。
import numpy as nparray = np.eye(4)array2 = np.identity(4)print(array)print(array2)[[ 1. 0. 0. 0.] [ 0. 1. 0. 0.] [ 0. 0. 1. 0.] [ 0. 0. 0. 1.]][[ 1. 0. 0. 0.] [ 0. 1. 0. 0.] [ 0. 0. 1. 0.] [ 0. 0. 0. 1.]]
從上面代碼可以看出:
1.就目前來看他們的效果都是一樣的,參數都是一個整數,然後創建的是一個方陣;
linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
在指定的間隔內返回均勻間隔的數字。返回num均勻分布的樣本,在[start, stop]。Parament: start:序列的起點 stop:序列的結束點,除非endpoint被設置為False,stop被排除 num:int, optional(可選)生成的樣本數,默認是50。必須是非負。
endpoint:如果是真,則一定包括stop,如果為False,一定不會有stop retstep : bool, optional If True, return (samples, step), where step is the spacing between samples.(array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]), 1.0) dtype : dtype, optional 輸出數組的類型。如果沒有給出,從其他輸入參數的數據類型推斷
logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None):
在指定的間隔內返回等比數列。Parament: start:序列的起點 stop:序列的結束點,除非endpoint被設置為False,stop被排除num:int, optional(可選)
生成的樣本數,默認是50。必須是非負。 endpoint:如果是真,則一定包括stop,如果為False,一定不會有stop base:這裡是指數的底數,默認是10,也就是說是 ,可以改成2 dtype : dtype, optional 輸出數組的類型。如果沒有給出,從其他輸入參數的數據類型推斷
5.ndarray的數據類型
其實如果直白的說,ndarray的數據類型就是我們創建數組時候的各個元素的數據類型,由於ndarray是一個通用的同構數據多維容器,所以每個ndarray對象有唯一的一個dtype值。當然這裡的數據類型都是NumPy中的類型。
dtype(數據類型)是一個特殊的對象,他含有ndarray將一塊內存解釋為特定數據類型所需的信息。dtype是NumPy如此強大和靈活的原因之一。多數情況下,他們直接映射到相應的機器表示,這使得"讀寫磁碟上的二進位數據流"以及"集成低級語言代碼(如C)"等工作變得更加的簡單。標準的雙精度浮點值(即Python中的float對象)需要佔用8個位元組(即64位)。因此,該類型在NumPy中就記作float64。
我們在創建數組的時候可以顯式的指定dtype,同時我們也可以不進行指定,他會為新的數組推斷出一個合適的數據類型。那麼如果我們後期需要再對數組中的數據類型進行轉換的話,那怎麼辦呢?這個時候我們可以通過ndarray數組對象的astype方法顯示的轉換為其他的dtype。
import numpy as np#顯示的指定dtypearray = np.array([1,2,3],dtype = np.float64)#隱式的指定dtypearray2 = np.array([1,2,3])print(array.dtype)print(array2.dtype)print("----------")array3 = array2.astype(np.float64)print(array2.dtype)print(array3.dtype)float64<U1----------<U1float64
我們從上面的(NumPy的數據類型)表格看到了有一個列叫做類型代碼,我們其實可以不使用np.數據類型來指定類型,也可以使用對應參數的類型代碼來簡潔的表示。但是對於數據類型這麼多的NumPy,個人建議還是不要使用類型代碼這種方式。
import numpy as nparray = np.array([1,2,3],dtype= S)print(array)print(array.dtype)[b1 b2 b3]|S1
這裡需要進行三點說明的是:
- 如果轉換失敗的話,比如說某一個字元串類型的數據不能轉換成整數類型,就會拋出ValueError的異常;
- 如果不指定np.float64,直接將參數寫成float,也是可以的,因為NumPy很聰明,他會將Python類型映射到等價的dtype中去;
- 其實我們調用astype方法,返回的是一個新的數組,也就是對原始數據的一個完整拷貝,(當然即使astype中的類型與原始數組中的dtype相同,也會返回一個新的數組)。
import numpy as nparray = np.array([h,1,2],dtype = np.float64)print(array)Traceback (most recent call last): File "G:/Python源碼/numpy_test/numpy_test.py", line 639, in <module> array = np.array([h,1,2],dtype = np.float64)ValueError: could not convert string to float: h
import numpy as nparray = np.array([1,2,3])array2 = array.astype(float)print(array.dtype)print(array2.dtype)int32float64
import numpy as nparray = np.array([1.1,2.3,4,7.8],dtype = np.float64)array2 = array.astype(np.int64)print(array)print(array2)print("-----列印類型-----")print(array.dtype)print(array2.dtype)print("-----判斷是否為同一個對象-----")array2[0] = 10000print(array)print(array2)[ 1.1 2.3 4. 7.8][1 2 4 7]-----列印類型-----float64int64-----判斷是否為同一個對象-----[ 1.1 2.3 4. 7.8][10000 2 4 7]
總結(是否是對源數據的拷貝):
6.NumPy數組索引
6.1基本的索引和切片
NumPy數組的索引是一個內容豐富的主題,因為選取數據子集或者是單個元素的方式有很多。對於一維數組來說,他和Python中的list的功能差不太多。
#對於一維數組來說import numpy as nparray = np.arange(8)print(array)print("-----選取單個元素-----")print(array[3])print(array[-1])print("-----選取數據子集-----")print(array[0:5])print(array[1:-2])[0 1 2 3 4 5 6 7]-----選取單個元素-----37-----選取數據子集-----[0 1 2 3 4][1 2 3 4 5]
這裡要多說幾句:
- 對於一維數組來說,我們可以認為是與list操作相一致的。我們可以直接通過正負索引來獲取單個元素,也可以通過切片來獲取一維數組的一個片段,切片的時候都是包左不包右的。
- 數組的切片是原始數組的視圖,也就是說數據沒有被複制,視圖上的任何修改都會直接反應到源數組上。(當然這個時候不能使用is關鍵字來判斷是否為同一個對象了),這是 因為NumPy的設計目的是處理大數據,所以你可以想像一下,如果NumPy堅持要將數據複製來複制去的話會產生何等性能和內存問題。當然如果想要拷貝副本的話可以顯式的調用copy方法。
- 切片也是有步長的你可以指定[1:5:2],這裡面的2就是切片的步長。如果特殊點步長為-1也就是[::-1],即我的數組就會反轉。
- 這裡的切片都是從0位置開始的。
- 我們從上面可以看出,無論是索引單個元素還是進行切片,我們都可以為其傳入一個負值,從數組的後面進行索引。
import numpy as nparray = np.array([1,2,3,4,5,6,7])array2 = array[1:]print("-----原始的數據-----")print(array)print(array2)print("-----更改後的數據-----")array2[0] = 10000print(array)print(array2)-----原始的數據-----[1 2 3 4 5 6 7][2 3 4 5 6 7]-----更改後的數據-----[ 1 10000 3 4 5 6 7][10000 3 4 5 6 7]
那對於高維數組來說,能做的事情就更多了。在一個二維數組中,各索引位置上的元素不再是標量而是一維數組。
import numpy as nparray = np.arange(1,13).reshape((4,3))print(array)print("-----獲取單個元素的兩種方式-----")print(array[0][1])print(array[0,1])print(array[-1][2])print(array[-1,2])print("-----對多維數組進行切片-----")#因為這裡只是一個矩陣,所以有兩個軸,也就是說能指定兩個位置print(array[:2])#只有一個值,也就是只有第一個軸的方向,也就是axis=0print(array[:2,:1])[[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12]]-----獲取單個元素的兩種方式-----221212-----對多維數組進行切片-----[[1 2 3] [4 5 6]][[1] [4]]
6.2布爾型索引
布爾型索引是NumPy特有的功能,他的功能非常的強大。並且應用的場景也非常的多。比如:下表是幾個學生的一年中期末期中的語數英三科的考試成績:
先初始化我們的數據:
import numpy as npnames_array = np.array([KC,XC,XC,LC,LC,KC],dtype = np.string_)grades_array = np.array([[80,98,78], [66,80,77], [68,88,90], [77,61,70], [70,65,80], [82,70,80]],dtype = np.int32)
我們要選出"KC"這名學生的期中期末的成績:
names_array2 = (names_array == KC)print("-----篩選滿足條件的行-----")print(names_array is names_array2)print(names_array2)print("-----進行篩選-----")print(grades_array[names_array2])-----篩選滿足條件的行-----False[ True False False False False True]-----進行篩選-----[[80 98 78] [82 70 80]]
這裡注意:
- 布爾型數組的長度必須和被索引的軸長度一致,就本例而言,是一個二維數組,所以他有兩個軸,所以我們默認傳入的是一個默認會是第一個軸,也就是行數,所以就本例而言我們的布爾型數組要和我們數據數組的行數相同才可以。
那如果我們要獲取除了KC這位同學的其他同學的成績:
print(names_array == KC)print("-----方式一-----")print(names_array != KC)print("-----方式二-----")print(-(names_array == KC))[ True False False False False True]-----方式一-----[False True True True True False]-----方式二-----[False True True True True False]
當然我們操作還不僅僅是這些,我們還可以組合應用多個布爾條件,使用&(和)、|(或)之類的布爾算術運算符即可(當然這裡要注意了,我們不能使用Python中的and和or關鍵字):
print("-----獲取KC或者LC同學的成績-----")print((names_array == KC) | (names_array == LC))print(grades_array[(names_array == KC) | (names_array == LC)])-----獲取KC或者LC同學的成績-----[ True False False True True True][[80 98 78] [77 61 70] [70 65 80] [82 70 80]]
當然因為我們是二維的一個數組,所以我們對應的是兩個軸,那我們還可以對列進行篩選,這裡其實很靈活的,我們可以使用一個標量來獲取整個列,也可以傳入一個分片來獲取部分列,當然我們對於列的篩選也可以布爾型的索引:
print("-----獲取KC同學的數學成績-----")print(grades_array[(names_array == KC),1])print(grades_array[names_array == KC][grades_array[names_array == KC] >= 80])-----獲取KC同學的數學成績-----[98 70][80 98 82 80]
6.3花式索引
花式索引(Fancy indexing)是一個NumPy術語,他指的是利用整數數組進行索引。下面是對於二維數組的例子:
import numpy as nparray = np.arange(32).reshape((8,4))print(array)print("-----獲取第一行和第三行-----")print(array[[0,2]])print("-----獲取最後兩行-----")print(array[[-1,-2]])print("-----獲取元素值-----")print(array[[0,2],[0,1]])print(array[[0,2]][:,[0,1]])print(array[np.ix_([0,2],[0,1])])[[ 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]]-----獲取第一行和第三行-----[[ 0 1 2 3] [ 8 9 10 11]]-----獲取最後兩行-----[[28 29 30 31] [24 25 26 27]]-----獲取元素值-----[0 9][[0 1] [8 9]][[0 1] [8 9]]
這裡要注意的是:
- 其實這傳入的是一個用於指定順序的整數列表或者是ndarray就行。這裡其實要注意的是花式索引和切片索引還是與很大的區別的:切片索引得到的是同一個源數組的視圖,所以無論修改哪個數組其實都是對同一個數組進行操作。但是花式索引就不一樣了,他是複製一個源數組。
- array[[0,2]][:,[0,1]]這裡可能不好理解,但是我們把他拆開來看,array[[0,2]]來獲取第1行和第3行的返回的是一個兩行的數組,然後在去[:,[0,1]]這裡我們的行是:全選,而列只選了第一列和第二列兩列。
- 使用np.ix_函數,他可以將兩個一維整數數組轉換為一個用於選取正方形區域的索引器。
總結(是否是對源數據的拷貝):
這裡所說的源數據的視圖說的就是如果我們修改其中一個數組,另一個源數組也會發生變化,他們操作的對象是同一個。當然如果不是的話就是說明我們在操作的時候又重新創建了一個新的數組,這個數組是對源數組的一個拷貝,這個時候去任何一個數組都不會對另一個數組產生影響。
推薦閱讀:
※Python中對位元組流/二進位流的操作:struct模塊簡易使用教程
※python資源全匯總—中文版
※PyQt5GUI應用程序工具包入門(一)——環境搭建
※Python將list連續元素和非連續元素分開轉換為指定字元串
※抓取1400篇Python文章後的故事(內附高質量Python文章推薦)