近期開始學習python機器學習的相關知識,為了使后續學習中避免編程遇到的基礎問題,對python數組以及矩陣庫numpy的使用進行總結,以此來加深和鞏固自己以前所學的知識。
Section One:Python數組的使用
在python中,數組這個概念其實已經被淡化了,取之的是元組和列表,下面就列表和元組進行相關的總結和使用。
Subsection One: List
list列表本質是一種序列類型的數據結構,有點類似於C/C++中所學的數組,但又不同。他們的相同之處在於,二者中的每個元素都分配有一個索引值來進行訪問,如:

1 #python list 2 list1 = ['physics', 'chemistry', 1997, 2000] 3 print(list1[0])
而在C/C++中我們知道,數組也可以通過這種數組名加索引值的方式來訪問,在此不做贅述。
但是,細心的話,我們會發現,python中的列表與C/C++中有所不同,它可以包含不同的數據類型,而C/C++中則不可以。此外,在上面的代碼中,我們可以看到,二者有着相同的創建方式。
但在python中,對於list列表類型的訪問,有着不同的方式,下面就列表的訪問進行總結:

1 """List: 2 -------------------------------- 3 """ 4 # create a list 5 list1 = ['physics', 'chemistry', 1997, 2000] 6 7 # two methods to access a list as follows: 8 print "list1[0]", list1[0] 9 print "list1[1:4]", list1[1:4] 10 11 print "list1[-1]", list1[-1] 12 print "list1[-2]", list1[-2] 13 14 print "list1[1:]", list1[1:]
從上面兩種方式,其實可以看到,python中的列表可以通過"起始索引:終止索引(可選)"的方式,來直接訪問列表中的一串數據,這在C/C++中是無法做到的,這給我們帶來極大的便利性,加上終止索引,表示訪問從起始索引到終止索引之間的全部數據,不加則意味着要訪問從起始索引到該列表末尾的全部數據。
此外,在列表中,索引值為負代表着從列表末尾來訪問這個列表,圖上圖三、四例子可以看到。
此外,python中對於列表,引入了以下幾種方法來更新和刪除列表,並賦予幾種訪問列表屬性的方法。
# update and delete list1.append('Google') print list1
列表可以通過append方法,往列表的末尾添加新的元素,在list1列表的基礎上,這里添加了一個叫做google的字符串元素。

del list1[2] print "after deleting value at index 2", list1
可以看到,使用del函數將索引為2的數據刪除了,此外,del函數還能結合之前提到的訪問數組的方式來刪除相關元素,如:

del list1[1:] print "after deleting value by list1[1:]", list1
同理,采用起始index:終止index的方式,也是能夠實現刪除列表中一段數據的。
此外,python中提供了一個len函數,來獲取一個列表的長度,使用"+"操作符能夠實現不同數組之間的合並,使用"*"操作符實現創建包含n個相同元素的列表,以及一些循環和遍歷方式來確定數據是否在列表中,下面給出相關的操作:

"""List: -------------------------------- """ # create a list list1 = ['physics', 'chemistry', 1997, 2000] list2 = [1, 2, 3 , 4] l = len(list1) print "access len function to get the length of list1" print l # + operator print list1 + list2 list3 = list1 + list2 print "list3:", list3 # * operator list4 = ['hhhh'] * 4 print list4 #traverse print "traverse list1:" for x in list1: print x #confirm x in list print "confirm x in list" print 2 in list1 print 1997 in list1
此外,還可以通過min和max函數來獲取列表的最大最小值,count函數用以計算某元素在列表中的出現次數,remove來移除匹配到的數據,sort函數進行排序,reverse函數進行逆序,這些可以在list的官方文檔中查詢到。
Subsection Two: 元組
元組的創建根列表的很類似,但是它用括號進行創建:

""" Tuples ------------------------------ """ tup1 = (1, 2, 3, "Google") print tup1 tup2 = ('flesh',) print tup2
細心的小伙伴們可能會看到,我在創建第二個tuples的時候,里面雖然只有一個元素,但是,我還是用了一個逗號,其實,這是很有必要的,雖然不加也不會有編譯錯誤,在這部分代碼中。但是,在其他情況則不一定了,比如,我們使用元組作為返回參數,如果不加逗號,但是返回的元組中只有一個數據,比如26,那么,計算機就會因為無法識別該元素是數字26還是元組26。因此,加上是必要的,也有助於我們養成良好的編程習慣。
元組的訪問呢與列表是一樣的,因為它們倆都是python中最為常見的序列結構,在這里不做贅述,有興趣的小伙伴可以自己去嘗試一下下,值得注意的是,訪問時的形式與列表的相同,不是L(index)的方式,而是L[index]。
此外,在元組中,對相關數據的修改是非法的,如下所示:

print "modify the data at index 2" tup1[2] = 100 print tup1
所以給位小伙伴們在使用元組時一定要注意呀!
但是元組中,可以使用"+"以及"*"兩個操作符來進行對元組的修改。
其余的相關方法如len等,而這類似,可以通過查閱文檔來了解。
Section Two: Numpy庫的使用(后續補充,要吃飯了23333)
補充:
Numpy是python中的矩陣庫,可以方便的讓我們學習。
可以使用cmd命令行來安裝該庫,命令如下:

pip install Numpy
安裝完成后,即可使用。python提供了一個pydoc命令,可以用於查看本地所安裝的python庫,也是在cmd命令行中輸入。
python -m pydoc -p 1234
-p指定啟動的服務的端口號,可以隨意指定不沖突的端口號
-m則是py中的一種工作模式了
1234就是-p下指定的一個端口號。運行后cmd會出現這樣的結果:
然后根據所給的url直接在瀏覽器中輸入,就可以訪問到本地的庫文檔,個人比較喜歡直接查文檔的方式進行學習。
該界面中包含numpy庫下轄的多個類以及各個類中所包含的函數模塊,並在每個接口部分,給出了相應的使用案例。
下面給出numpy的使用:
numpy的調用,與其他庫文件的調用一樣,采用import方式進行調用:
import numpy as np
通過這種方式,可以將本地的numpy庫,導入當前的py文件中進行使用。此外,numpy給python的學習者以極大的便利來使用矩陣,尤其是其所提供的help函數,能夠在使用者不知道或者忘記怎么使用其內部函數的時候,給予幫助。
調用方式如下:
help(function name)
在這里我以下面這個例子為例:

1 """ 2 Numpy Learning 3 ------------------------------------------------------ 4 """ 5 6 import numpy as np 7 8 help(np.sort)
sort函數是numpy中自帶的一個排序函數,當運行help方法進行獲取他的使用后,就可以在console框中得到相應的調用案例:
這種方式能夠在一定程度上提高我們查詢文檔的速度。
對於矩陣的使用,可以自行生成,也可以借助numpy中所帶的相關類進行獲取,如Datasource,該類可以通過如下方式導入進行使用
from numpy import DataSource
導入后,就可以直接進行調用,以鳶尾花數據庫中的數據為例:
實例化DataSource對象以后,該對象包含相對應的方法,可以在上文中提到的本地庫函數界面中查詢到,典型的就有exists方法,用以判斷訪問的數據是否存在。

1 """ 2 Numpy Learning 3 ------------------------------------------------------ 4 """ 5 6 import numpy as np 7 from numpy import DataSource 8 9 # method to get data 10 url_name = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data' 11 repos = DataSource() 12 print repos.exists(url_name)
運行后輸出為True,說明存在,我們可以直接通過url_name來訪問相應的數據。

1 """ 2 Numpy Learning 3 ------------------------------------------------------ 4 """ 5 6 import numpy as np 7 from numpy import DataSource 8 9 # method to get data 10 # url name to access 11 url_name = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data' 12 ds = DataSource() 13 dataset = ds.open(url_name, mode='r') 14 15 for key in dataset: 16 print key
數據的訪問這里選擇只讀形式,然后通過for循環對獲取的數據進行解析輸出:
這種方式獲取的數據存在一定的局限性,因為每個key其實是一個list對象,其中數據全部為字符串型數據。進一步的使用則需要對數據進行解析,可以簡單的通過pandas數據庫來獲取整理數據,這個庫是python中的一個數據分析庫,事倍功半,pandas的使用,將會在后續另一篇blog中進行敘述。本文采用一些線性代數中的簡單實例,來使用numpy矩陣庫。
ex1:求解下列線性方程:
通常,線性方程可以表示成Ax = b的形式,A即為線性方程組的系數矩陣,b即為右側的值構成的列向量。則可以通過在方程兩邊同乘以系數矩陣的逆矩陣來求得x的解。在這里給出我手解得到的值x1=1;x2=x3=0。
下面借助numpy進行求解,代碼如下:

1 #coding:utf-8 2 """ 3 Numpy Learning 4 ------------------------------------------------------ 5 """ 6 7 import numpy as np 8 import numpy.linalg as lg 9 10 # create an matrix 11 """ 12 np.array(parameter matrix) 13 the matrix can be one-dimensional or multi-dimensional 14 It's worth noting that if matrix is one-dimensional, the fellow method 15 can be used: 16 np.array([1,2,3,4]) 17 else like the given sample 18 """ 19 # A = np.array([1, 2, 3, 4]) 20 # print "onr-dimensional matrix: " 21 # print A 22 # A = np.array([1, 2, 3, 4]) 23 A = np.array([[1, 2, 3], [2, 2, 5], [3, 5, 1]]) 24 b = np.array([[1], [2], [3]]) 25 26 A_inv = lg.inv(A) 27 28 # x = np.dot(A_inv, b) 29 x = A_inv.dot(b) 30 print "x is calculated by dot function:" 31 print x 32 # print "x is calculated by * operation: " 33 # print A_inv * b 34 35 print("The inverse of A is :") 36 print A_inv 37 print("Column vector b is :") 38 print b 39 print("The result of A_inv * b is :") 40 print A_inv * b 41 42 print "The examples of * operator :" 43 a = np.array([[1, 2, 3], [2, 2, 5], [3, 5, 1]]) 44 b = np.array([[1], [2], [3]]) 45 print a * b 46 47 # error 48 # a = np.array([[1, 2, 3], [2, 2, 5], [3, 5, 1]]) 49 # b = np.array([[1], [2]]) 50 # print a * b 51 52 # error 53 # a = np.array([[1, 2, 3], [2, 2, 5], [3, 5, 1]]) 54 # b = np.array([[1, 2], [2, 2], [3, 2]]) 55 # print a * b
代碼中給出了使用numpy創建矩陣的兩種方式,一種是創建多維矩陣另一種則是創建一維的矩陣,即行向量。可以看到,當創建行向量的時候,只需要傳入一個list類型的對象即可,而創建多維矩陣的時候,需要以行向量作為一個list的元素構成一含有多個子list的一個list作為參數傳遞進去,以此來創建矩陣。
在這里用到了numpy底下linalg中的一個方法即inv方法,用於求矩陣的逆矩陣。需要注意的是,numpy中,對" * "、" / "、" - "、" + "進行了重載,以此來滿足矩陣的運算需要,但是,在這些運算符中," * "運算符不同於其他工具中的功能,它實現的不是矩陣的點乘,而是對矩陣的元素進行操作,即,當兩個矩陣a、b的行相同,且當矩陣a或b的列滿足矩陣a的列數等於矩陣b的列數,或者矩陣a或者b的列數等於1時,兩個矩陣中的元素進行操作,上述代碼的運行結果可以很直觀的看到這一點。
上述代碼的運行結果如下所示:
從上述代碼可以看到,矩陣的點乘是每個numpy矩陣對象自帶的方法,可以通過np.dot(parameter A, parameter B)的方式,也可以直接A.dot(B)。而求逆運算則包含在linalg模塊中。
此外,在每個numpy對象中包含以下幾種屬性:ndim、shape、size、dtype、itemsize以及data,下面以ex1線性方程組的系數矩陣A為例來輸出這些屬性。

1 A = np.array([[1, 2, 3], [2, 2, 5], [3, 5, 1]]) 2 print "The metrix A" 3 print A 4 print "A.ndim: " 5 print A.ndim 6 print "A.shape: " 7 print A.shape 8 print "A.size: " 9 print A.size 10 print "A.dtype: " 11 print A.dtype 12 print "A.itemsize" 13 print A.itemsize 14 print "A.data" 15 print A.data
運行上述代碼可以得到如下結果:
從上述結果可知,indim屬性表征的是一個矩陣的維度,即一個矩陣中的元素最多能用多少個矩陣下標來表示,在這里,由於是二維矩陣,因此,該值為2。如果是三維矩陣,那么一個元素需要3個索引值來表示,那么indim屬性值也就為3。shape屬性表示的是n*m矩陣的尺寸,在這里是個3*3矩陣,因此該值為(3, 3),則該值的長度即為indim值。size表示的是這個矩陣中包含的元素的個數,該屬性與shape屬性有着相同的表征含義。dtype則表示的是矩陣中元素的數據類型。itemsize則表示的是一個元素的字節數,在這里由於是32位整型,因此,該值為32/8 = 4。data屬性表示的是矩陣所對應的緩存中的實際數據,一般來說是用不到這個屬性的。
除了以上內容,我們在學習線性代數的過程中,通常會遇到一些計算的小技巧,比如借助單位矩陣來求一些矩陣等,下面還是以線代中的一些例子為例。
ex2:
上題中需要用到一個單位矩陣E,在numpy中,提供了相應的方法來生成一定要求的矩陣,下面結合例子來調用輸出這些方法。
首先,給出numpy中自帶的一些創建特殊矩陣的方法:

1 # Create an array full of zeros, the type of parameter likes np.shape. 2 Zero = np.zeros((3, 3)) 3 print "Zero array: " 4 print Zero 5 6 # The function ones creates an array full of ones 7 ones = np.ones((4, 4)) 8 print "Ones array: " 9 print ones 10 11 # The function empty creates an array whose initial content is 12 # random and depends on the state of the memory. By default, 13 # the dtype of the created array is float64. 14 15 Empty = np.empty((3, 3)) 16 print "Empty array: " 17 print Empty 18 19 # To creates sequences of numbers, this function 20 # analogous to range that returns arrays instead of lists. 21 Sequences = np.arange(10, 30, 2) 22 print "Sequences array: " 23 print Sequences 24 25 # The function creates a sequences array by predicting the 26 # number of elements obtained. 27 Linspace = np.linspace(10, 30, 25) 28 print "Linspace array: " 29 print Linspace 30 31 # The function creates a N-th order identity matrix. 32 E = np.eye(4) 33 print "E array: " 34 print E
運行以上代碼可以得到如下輸出結果:
從上圖可以看到:
- np.zeros(parameter A)的方式,可以創建一個n*m型的零矩陣。這個A類似之前輸出的屬性shape,一個元組形式的參數,當然,n*m只是舉例說明,實際可以是多維的,如(i, j, k)。
- np.ones(parameter A)與zeros()函數相同,所傳參數也是一個元組類型數據,只是結果有所不同,生成的是一個全1的矩陣。
- np.empty(parameter A)創建的是一個隨機數矩陣,所傳參數與zeros和ones相同,只是生成的結果是一個隨機數構成的矩陣,內部元素的數據與內存有關,數據類型默認是64位浮點型。
- np.arange(parameter A)創建的是一個等差序列list,參數A是一個包含三個數據的元組,(a,b,c),[a,b)為這個arange的范圍,左閉右開區間,即不包括b的,步長為c的一個序列。
- np.linspace(parameter A)則是創建一個等差序列list,與arange不同的是,這里參數A依舊是(a, b, c),但是,這個元組中的c變量表示的不是步長,而是從a到b這個左開右閉區間內,所包含的數的個數。
- np.eye(parameter A)創建的一個N階的單位矩陣,參數A為一個整型數據,表示的是單位矩陣的階數。
此外,numpy中創建的矩陣也是可以對其進行python中的切片和迭代操作的。
結合以上的內容,可以非常方便的創建一個單位矩陣E,進而求解所給出的那道題。代碼如下所示:

1 A = np.array([[1, 0, 0, 0], [-2, 3, 0, 0], 2 [0, -4, 5, 0], [0, 0, -6, 7]]) 3 4 E = np.eye(4) 5 6 C = lg.inv((E + A)) 7 B = C.dot((E - A)) 8 E_add_B_inv = lg.inv((E + B)) 9 print E_add_B_inv
運行上述代碼,即可求得:
可以看到,所求結果與手算結果相一致,第四行第二列的那個數值直接視為0。
補充:
在numpy中,每個np對象還包含轉置操作:

1 A = np.array([[1, 0, 0, 0], [-2, 3, 0, 0], 2 [0, -4, 5, 0], [0, 0, -6, 7]]) 3 print "The transposition of A: " 4 print A.T
得到結果如下所示:
以上是目前的我本人所需要用到的一些numpy的知識點,后續隨着學習的深入會繼續補充該文。還有更多的內容,中文版的入門教程可以參考這篇博客https://www.cnblogs.com/qflyue/p/8244331.html
英文版的可以直接查官方的文檔了
https://docs.scipy.org/doc/numpy-dev/user/quickstart.html