Numpy基礎筆記
Basic Numpy
ndarray物件基礎
什麼是ndarray物件?即是N-dimentional array,也就是n維陣列物件。
指定ndarray型別的物件——dtype(data type,就是n維陣列物件內的基本元素型別)
numpy陣列的基本知識
陣列的基本屬性
- shape屬性,即是陣列的形狀,用元組來描述(儲存著幾行幾列的資訊)
- axis屬性,即是陣列的軸,有0、1、2……軸(在引數列表中的axis代表著以哪個軸作為基準)
- ndim屬性,即是陣列的維數,用元組來表示(其實就是反映陣列有幾個軸)
- size屬性,返回陣列的長度(就是看數組裡面一共有多少基本元素,不要與len()函式返回值混淆,len與ndim返回值一致)
- dtype屬性,即是陣列元素的型別(也可以在外面直接創造複雜dtype型別,並把它與一個變數繫結,可以節省程式碼量)
- itemsize屬性,即是陣列中每個元素的長度(以位元組形式表示)
資料型別(主要在結構化陣列中應用)
全部資料型別
見 Python Data Analysis P34,不過一般很少使用
結構化陣列中的資料型別
bytes | b1 |
---|---|
int | i1, i2, i4, i8 |
usigned ints | u1, u2, u4, u8 |
floats | f2, f4, f8 |
complex | c8, c16 |
fixed length strings | a |
可以通過type函式來檢視元素型別
建立陣列(包含特殊陣列建立)
-
arr = np.array([1, 2, 3]) //array接收序列引數,通常用list, tuple(且他們地位等價,即互相巢狀可以換位)
-
np.arange(1, 100, 2) //arange在給定範圍內生成一個一維陣列,為閉開區間,為比較常用的方法。 //接收一個引數時預設從0開始,數字型引數-初始,結束,步長(步長可以為小數,與range不同,這十分特殊!!!!!) // 記住reshape函式!!!即可接收元組也可直接接受元組內的引數,通常使用 c = np.arange(0, 16).reshape((4, 4)) //reshape方法可以返回一個按引數指定形狀的多維陣列 np.arange(0, 16).resize((4, 4)) //resize方法與reshape方法的不同之處在於resize直接修改原物件,但是resize並不常用,我們希望物件更安全 //但是reshape產生的新檢視,其實是一個引用,即使兩者形狀不一樣,但是他們指向記憶體的同一塊區域,如果要更改其中之一,請使用copy函式來避免這種事情發生
-
arr = np.linspace(0, 10, 5) //linspace函式接收:起始,結束,份數。它與arange相對應,只不過第三個引數從步長變為了份數 //其餘像與shape, reshape方法的配合與arange一直(本質是對物件應用,只不過它們通常成對出現) // 其實linspace與arange是一樣的,只不過使用的方式略有區別而已 // linspace中的重要引數,restep(導致linspace返回一個元組,前半部分是生成的array,後部分是步長),linspace與arange的不同之處在於 linspace預設包括右端而arange並不是,可以通過將endpoint設定為False,就可不取右端點
-
//快速建立特殊陣列 // 注意!zeros、ones、random只能接收元組類引數!注意與reshape、shape區別! // 零陣列 np.zeros((3, 3)) array([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]) //zeros_like函式!跟ones_like一模一樣 //一陣列 np.ones((3, 3)) array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) arr = np.array([1, 2, 3]) // one_like函式!可以根據已有陣列的形狀建立一陣列 np.ones_like(arr) //隨機陣列 np.random.random((3, 3)) array([[0.23159009, 0.63306642, 0.63343724], [0.2765953 , 0.57742195, 0.3329211 ], [0.02730095, 0.86618645, 0.98329664]]) // 建立一個空陣列(隨機分配的垃圾值) np.empty((2, 3)) np.empty_like(arr) // 最一般的特殊陣列建立函式!full函式 np.full(((2, 3), 7.1)) // 建立一個2x3的7.1充滿的陣列 np.full_like(arr, 7.1) //請注意,full_like函式在填充時會根據arr內型別進行型別轉換,比如arr的資料型別原來為int型,會將7.1變為7 //建立diagnal(一般是主對角線) np.eye(5) [[1. 0. 0. 0. 0.] [0. 1. 0. 0. 0.] [0. 0. 1. 0. 0.] [0. 0. 0. 1. 0.] [0. 0. 0. 0. 1.]] eye的k引數,正數代表向右平移,負數代表向左平移(是指主對角線漂移) // 通過已有陣列建立元素型別不同的陣列 arr = arr.astype(np.float)
-
//建立結構化陣列示例 // 我可能想複雜了,其實往往不需要在後面寫生dtype,除非有特殊需求 structured = np.array([(1, 'First', 0.5, 1+2j), (2, 'Second', 1.3, 2-2j), (3, 'Third', 0.8, 1+3j)], dtype=[('id', 'i2'), ('position', 'a6'), ('value', 'f4'), ('complexs', 'c8')]) //這樣就可以通過像字典一樣的形式來操作結構化陣列 array([(1, b'First', 0.5, 1.+2.j), (2, b'Second', 1.3, 2.-2.j), (3, b'Third', 0.8, 1.+3.j)], dtype=[('id', '<i2'), ('position', 'S6'), ('value', '<f4'), ('complexs', '<c8')]) // 另一種方法來制定各欄位名稱 structured = np.array([(1, 'First', 0.5, 1+2j), (2, 'Second', 1.3, 2-2j), (3, 'Third', 0.8, 1+3j)], dtype=['i2', 'a6', 'f4', 'c8']) structured.dtype.names = ['id', 'position', 'value', 'complexs'] //改變dtype屬性的names欄位,這是給列取名字!!! //這樣就可以像字典一樣使用了, //結構化陣列呼叫示例 structured['id']
陣列的基本操作
運算的前提——廣播與廣播機制(umm……不太熟)
numpy可以實現元素級操作,同時numpy實現了對不同形狀物件的運算,這種機制稱為廣播
廣播機制:將兩種不同形狀的陣列物件進行元素級運算的預處理機制(也就是升維),分為兩個階段。
[1]. 判斷兩個陣列的各個維度是否相容,如果相容直接進行[2]。如果不相容,再判斷其中一個數組是否為一維,如果為一維也進行[2],否則不能進行.
[2]. 用已有的元素生成其他的元素
算數基本操作
算數運算子
+, -, *, /, %, **, //等所有算數運算子都是元素級運算子,結果返回新陣列
注意:python中的*指的是元素級乘法,採用dot方法計算矩陣積
特殊的運算子:+=,-=(自增、自減最常用)等某等運算子可以直接更改物件
通用函式與運算(Universal function)
通用函式是指元素級操作函式,可以抽象為f(arr)
其中較常用的為dot(矩陣積),等。讓人感動的是numpy重複實現了math庫中絕大多數函式,以靜態方法方式呼叫。
arr.T //陣列轉置
arr.flatten() //將陣列將為1維,返回新的副本(意味著直接返回全新的陣列物件,可以直接修改,注意這是與reshape不同的地方)
np.flat() //將陣列將為1維,返回一個1維迭代器,可以用for迴圈遍歷
arr.ravel() //將陣列將為1維,返回檢視(記憶體的位置是不變的!!!)
arr.astype(np.float) // 返回一個新陣列,將原陣列的資料經過float()處理
arr.swapaxes(ax1, ax2) // 將兩個維度互換(換軸)
arr.transpose() // 不帶引數時,效果相當於轉置
arr.transpose(2, 1, 0) // 相當於將arr的三個軸轉換到新位置
arr.tolist() //將ndarray轉換為列表,如果使用哦那個list()函式轉換,其實是相當於向量函式作用在ndarray上,是向量操作,打不傲tolist()的的效果
arr.tostring() // 將ndarray轉換為字串
// arr形狀轉換等其他實現參照建立陣列章節
聚合函式(Group function)
聚合函式是指對一組值(往往是一個數組)進行操作,返回單一值。
其中常用的有:sum, min, max, mean, std(標準差)
索引與切片(花式索引、布林索引)—— 需要更多的練習
索引的操作與標準庫中的list相同,一起回憶一下:
操作相同但是返回值型別有區別:list的切片得到副本,而陣列的切片得到檢視
副本可以理解為原物件變化不對副本產生影響(當然有深淺copy之分,這裡不贅述了),檢視就像是SQL資料庫中的檢視,原物件變化會導致檢視物件發生變化,倘若陣列想要得到副本可以使用例項方法copy來得到
//一維陣列索引示例 (在python中切片與索引(花式索引除外)返回的是副本,但在numpy中只返回檢視!!!需要用copy與deep copy來建立副本)
a = np.arange(10)
a[2] = 2
a[-1] = 9 //反向索引也很常見,相當於從第一個元素反著查
//陣列切片示例(結果很顯然,不寫了)
a[:]
a[1:2] //閉開區間
a[1:]
a[:8]
a[1:9:2] //帶步長的切片
a[::-1] // 逆序地去除所有資料
//二維陣列切片示例(多維陣列以此類推)
A = np.array([range(10), range(10, 20)])
A[1, 2] // 選出第一行、第三列元素
A[1] //相當於選取第二行,當然還有更標準的寫法,見下一個
A[1,:] //選取第2行,這相當於是省略了1軸的操作,這個逗號甚至可以省掉
A[:,1] //選取第2列 切記!零軸空操作,就是指前面的那個冒號,是不能被省略的!
// 注意!!!A[1]這種索引式返回結果是降維後的結果!!!而切片式返回的陣列與原陣列位數相同
// 分別在0軸和1軸上切分,輸出為兩個軸切出的交集
A[0:2, 0:2] //選取一個子矩陣
// 索引與切片相結合,因為有索引所以降了一個維度哦!
A[1, :2]
// 花式索引!!!
// 還是索引產生的副本!!!這與其他的取法不同!!!
A[[1, 9]:2] //列表(序列均可)可選取我們要拿出來的單列,是花式索引!!!(花式索引甚至可以重複放並且支援負數)
// 花式索引的另一種情況,將有高維數陣列作為索引傳入一維陣列,會得到與高維陣列相同形狀的切片!!!
arr = np.arange(9)
b = np.arange(4).reshape(2, 2)
arr[b]
// 花式索引應用在二維陣列(不熟)
arr = np.arange(15).reshape(4, 4)
// 布林索引,也就是布林陣列作為索引,只取出值為True對應的值(不熟)
// 不同種索引相互配合
陣列迭代
最初級的方法是使用foreach迴圈
更pythonic的方法是使用apply_along_axis()函式——直接對行、列整體進行操作
np.apply_along_axis(function, axis, arr)
//下面是對行求平均值的示例
np.apply_along_axis(np.mean, axis=1, arr=A)
//非常值得注意的地方!axis是along which axis的含義!尤其是之後的split都是這樣!
//被我們操作的函式可以是自己定義的
陣列篩選與bool陣列
A = np.arange(-8, 8).reshape((4, 4))
//array([[-8, -7, -6, -5],
// [-4, -3, -2, -1],
// [ 0, 1, 2, 3],
// [ 4, 5, 6, 7]])
A[A > 0] //篩選出陣列中符合要求的元素,以一位陣列返回
A > 0 //相當於一個元素級操作,返回bool陣列
陣列的形狀變換
包括前面提到過的reshape, shape。
ravel方法可以得到二維陣列對應的一維陣列(返回新陣列)
transpose方法可以實現轉置以及換軸(返回新陣列)swapaxes也可以實現換軸
陣列切分
陣列的切分靠split族函式來實現:vsplit,hsplit,split
其實split完全可以代替vsplit與hsplit
//vertival split
[B, C] = np.vsplit(A, 2) //將A切為兩部分,預設沿著列
[B, C] = np.hsplit(A, 2) //將A切為兩部分,預設沿著行
//更為複雜但更靈活的split函式
[A1, A2, A3] = np.split(A, [1, 3], axis=1) //沿著1軸(就是沿著columns切)將A抽取[1, 3]後分成三部分
陣列拷貝
在numpy中唯一為ndarray建立副本的方法是使用copy方法
淺拷貝就是指直接的賦值 a = b
這與python不同,python的copy函式是淺拷貝,deepcopy函式才是深拷貝
陣列資料檔案的讀寫
numpy提供 save, load函式來儲存與讀取二進位制檔案,getfromtxt從文字檔案中讀取
data = np.random.random((3, 3))
np.save('sava_data', data) //將data存在save_data.npy檔案中,npy是預設儲存拓展名
dataget = np.load('save_data.npy') //讀取資料
//讀取文字檔案資料示例
data = getfromtxt('data.csv', delimiter=',', names=True) //delimiter是分隔符,由於為CSV檔案,分隔符自然為逗號
//names代表資料中是否含有標題
//缺失的資料會被補成nan
事實上這些讀取的工作常常由pandas來操作