Numy基礎知識分享
數據分析最常用的第三方包為:Numpy、Pandas
Numpy主要用於數學計算,例如矩陣積計算。
Pandas是基於Numpy的數據分析工具,提供了一套名為數據框的數據結構,能方便的對錶結構的數據進行分析。
matplotlib是一個圖形繪製庫,專門用於數據可視化。
本文主要介紹基本的數據結構知識和Numpy的基礎知識。
一、數據的維度
數據維度是數據的組織形式。
一維數據是線性的,對應數組、列表、集合等概念
數組不同於列表,聊表中的元素數據類型可以不同,而數組中元素的數據類型必須相同。
二維數據由多個一維數據構成,是一維數據的組合形式,表格就是最典型的二維數據。
多維數據由一維或二維數據在新維度上擴展形成,例如五年間同種格式的出納單表格,增加了時間的維度。
高維數據僅利用最基本的二元關係,利用鍵值對將數據組織起來,這裡我們很快想到了Python中的字典類型。
二、NumPy簡介
NumPy是一個開源的Python科學計算基礎庫,是SciPy、Pandas等數據處理或科學計算庫的基礎,包含一個強大的N維數組對象 ndarray。
我們使用:
import numpy as np
來引入模塊。
基於NumPy的演算法要比純Python快10到100倍(甚至更快),並且使用的內存更少。
import numpy as npmy_arr=np.arange(100000)my_list=list(range(100000))%time for _ in range(10):my_arr2=my_arr*2%time for _ in range(10):my_list2=my_list*2
同樣是100000的數組,Numpy數組計算十次的時間遠遠少於Python列表的計算時間。
三、N維數組對象:ndarray
我們使用np.array()生成一個ndarray數組
此外還有很多其他創建方法
介紹一下秩和軸的概念:
軸(axis): 保存數據的維度
秩(rank):軸的數量
下面是一些ndarray對象的屬性:
ndarray數組可以由非同質對象構成,例如:
我們可以用astype轉換數據類型:
注意:當浮點數用np.int64轉換為實數時,小數部分會被截除(而非四捨五入)
如果某個由字元串組成的數組中全部字元串都是數字,可以用astype將其轉為數值:
dtype還可以這樣玩:
四、基本的索引和切片
當我們修改切片數組裡的數值時,原數組也會改變,這點和python中的列表類似。
所以如果你想得到ndarray切片的一份副本(其改變不改變原數組),則需要用copy進行複製,例如:
a[1,3].copy()
對於高維數組的切片訪問要注意其維度:
注意:高維數組賦值時在維度較高層面上的切片會影響整個較低維度:
數組也可以被用於切片賦值(但必須同質,也就是數據的數量相同):
我們來看圖理解:(注意,左邊的是豎軸右邊的是橫軸,只有冒號」表示選取整個軸,切片同Python,帶左邊的數不到右邊的數。)
布爾型索引在實際應用處理數據時非常有用。
我們先來設置一些數組(實際應用時可直接用Python爬取)
name=np.array([亞索,艾希,趙信,蓋倫,亞索,艾希,艾希])attackdata=np.random.randn(7,4)#對應name隨機生成一個7*4的二維數組
對name和字元串『艾希』的比較會生成一個布爾型數組
這個布爾型數組可以用於索引:
~操作符表示否定
Python中的and、or在布爾型數組中是無效的
可以使用&(和)、|(或)之類的布爾算術運算符進行組合操作:
我們常用布爾型數組設置值,例如將負值歸零,將除了某人的資料外全部設為固定值等:
花式索引:
花式索引跟切片不一樣,它總是將數據複製到新數組中。
數組轉置和軸對換:
轉T法行列互換:
軸對換:
五、通用函數
有些ufunc可以返回多個數組。例如modf,它是Python內置函數divmod的矢量化版本,它會返回浮點數數組的小數和整數部分:
六、利用數組進行數據處理
矢量化:用數組表達式代替循環的做法,一般來說,矢量化數組運算要比等價的純Python方式快上更多。
import numpy as nppoints = np.arange(-5, 5, 0.01)xs, ys = np.meshgrid(points, points)z = np.sqrt(xs ** 2 + ys ** 2)
對該函數的求值把這兩個數組當做兩個浮點數那樣編寫表達式即可。
x if condition else y的矢量化版本是numpy.where函數
先設三個數組:
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])cond = np.array([True, False, True, True, False])
假設我們想要根據cond中的值選取xarr和yarr的值(True從xarr選,False從yarr中選),我們就可以用numpy.where函數,非常簡便。
In [170]: result = np.where(cond, xarr, yarr)In [171]: resultOut[171]: array([ 1.1, 2.2, 1.3, 1.4, 2.5])
np.where的第二個和第三個參數不必是數組,它們都可以是標量值。假設有一個由隨機數據組成的矩陣,你希望將所有正值替換為2,所有負值替換為-2,利用np.where會非常簡單:
In [172]: arr = np.random.randn(4, 4)In [173]: arrOut[173]: array([[-0.5031, -0.6223, -0.9212, -0.7262], [ 0.2229, 0.0513, -1.1577, 0.8167], [ 0.4336, 1.0107, 1.8249, -0.9975], [ 0.8506, -0.1316, 0.9124, 0.1882]])In [175]: np.where(arr > 0, 2, -2)Out[175]: array([[-2, -2, -2, -2], [ 2, 2, -2, 2], [ 2, 2, 2, -2], [ 2, -2, 2, 2]])In [176]: np.where(arr > 0, 2, arr) # set only positive values to 2Out[176]: array([[-0.5031, -0.6223, -0.9212, -0.7262], [ 2. , 2. , -1.1577, 2. ], [ 2. , 2. , 2. , -0.9975], [ 2. , -0.1316, 2. , 2. ]])
mean和sum這類的函數可以接受一個axis選項參數,用於計算該軸向上的統計值,最終結果是一個少一維的數組:
對於布爾型數組,上述函數會強制將布爾值轉換為1(True)和0(False)
any和all對布爾型數組非常有用。any用於測試數組中是否存在一個或多個True,而all則檢查數組中所有值是否都是True(用於非布爾型數組時,所有非0元素將會被當做True。):
In [192]: bools = np.array([False, False, True, False])In [193]: bools.any()Out[193]: TrueIn [194]: bools.all()Out[194]: False
NumPy數組也可以通過sort方法就地排序,多維數組可以在任何一個軸向上進行排序,只需將軸編號傳給sort即可。
對於一維ndarray的基本集合運算,np.unique可以找出數組中的唯一值並返回已排序的結果:
In [206]: names = np.array([Bob, Joe, Will, Bob, Will, Joe, Joe])In [207]: np.unique(names)Out[207]: array([Bob, Joe, Will], dtype=<U4)In [208]: ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])In [209]: np.unique(ints)Out[209]: array([1, 2, 3, 4])
np.in1d用於測試一個數組中的值在另一個數組中的成員資格,返回一個布爾型數組:
In [211]: values = np.array([6, 0, 0, 3, 2, 5, 6])In [212]: np.in1d(values, [2, 3, 6])Out[212]: array([ True, False, False, True, True, False, True], dtype=bool)
七、文件是輸入和輸出
np.save和np.load是讀寫磁碟數組數據的兩個主要函數(如果文件路徑末尾沒有擴展名.npy,則該擴展名會被自動加上):
In [213]: arr = np.arange(10)In [214]: np.save(some_array, arr)In [215]: np.load(some_array.npy)Out[215]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
通過np.savez可以將多個數組保存到一個未壓縮文件中,載入.npz文件時,你會得到一個類似字典的對象,該對象會對各個數組進行延遲載入:
In [216]: np.savez(array_archive.npz, a=arr, b=arr)In [217]: arch = np.load(array_archive.npz)In [218]: arch[b]Out[218]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
八、線性代數相關
NumPy提供了一個用於矩陣乘法的dot函數
(tips:理解下矩陣積的概念)
In [223]: x = np.array([[1., 2., 3.], [4., 5., 6.]])In [224]: y = np.array([[6., 23.], [-1, 7], [8, 9]])In [225]: xOut[225]: array([[ 1., 2., 3.], [ 4., 5., 6.]])In [226]: yOut[226]: array([[ 6., 23.], [ -1., 7.], [ 8., 9.]])In [227]: x.dot(y)Out[227]: array([[ 28., 64.], [ 67., 181.]])
x.dot(y)等價於np.dot(x, y):
In [228]: np.dot(x, y)Out[228]: array([[ 28., 64.], [ 67., 181.]])
@符也可以用作中綴運算符,進行矩陣乘法:
In [229]: np.dot(x, np.ones(3))Out[229]: array([ 6., 15.])In [230]: x @ np.ones(3)Out[230]: array([ 6., 15.])
九、偽隨機數生成
偽隨機數是用確定性的演算法計算出來的似來自[0,1]均勻分布的隨機數序列(例如正態分布)。並不真正的隨機,但具有類似於隨機數的統計特徵,如均勻性、獨立性等。
numpy.random模塊對Python內置的random進行了補充,你可以用normal來得到一個標準正態分布的樣本數組:
可以用NumPy的np.random.seed更改隨機數生成種子(相同的seed( )值使每次生成的隨機數都相同):
輸出為:
numpy.random的數據生成函數使用了全局的隨機種子。要避免全局狀態,你可以使用numpy.random.RandomState,創建一個與其它隔離的隨機數生成器
示例:隨機漫步
從0開始,步長1和-1出現的概率相等,根據前100個隨機漫步值生成的折線圖:
In [247]: import random .....: position = 0 .....: walk = [position] .....: steps = 100 .....: for i in range(steps): .....: step = 1 if random.randint(0, 1) else -1 .....: position += step .....: walk.append(position)In [249]: plt.plot(walk[:100])
用np.random模塊一次性隨機產生100個「擲硬幣」結果(即兩個數中任選一個),將其分別設置為1或-1,然後計算累計和:
In [251]: nsteps = 100In [252]: draws = np.random.randint(0, 2, size=nsteps)In [253]: steps = np.where(draws > 0, 1, -1)In [254]: walk = steps.cumsum()
有了這些數據之後,我們就可以沿著漫步路徑做一些統計工作了,比如求取最大值和最小值:
In [255]: walk.min()Out[255]: -3In [256]: walk.max()Out[256]: 31
假設我們想要知道本次隨機漫步需要多久才能距離初始0點至少10步遠(任一方向均可)。np.abs(walk)>=10可以得到一個布爾型數組,它表示的是距離是否達到或超過10,而我們想要知道的是第一個10或-10的索引。可以用argmax來解決這個問題,它返回的是該布爾型數組第一個最大值的索引(True就是最大值):
In [257]: (np.abs(walk) >= 10).argmax()Out[257]: 37
如果你希望模擬多個隨機漫步過程(比如5000個),只需對上面的代碼做一點點修改即可生成所有的隨機漫步過程。只要給numpy.random的函數傳入一個二元元組就可以產生一個二維數組,然後我們就可以一次性計算5000個隨機漫步過程(一行一個)的累計和了:
In [258]: nwalks = 5000In [259]: nsteps = 1000In [260]: draws = np.random.randint(0, 2, size=(nwalks, nsteps)) # 0 or 1In [261]: steps = np.where(draws > 0, 1, -1)In [262]: walks = steps.cumsum(1)In [263]: walksOut[263]: array([[ 1, 0, 1, ..., 8, 7, 8], [ 1, 0, -1, ..., 34, 33, 32], [ 1, 0, -1, ..., 4, 5, 4], ..., [ 1, 2, 1, ..., 24, 25, 26], [ 1, 2, 3, ..., 14, 13, 14], [ -1, -2, -3, ..., -24, -23, -22]])In [264]: walks.max()Out[264]: 138In [265]: walks.min()Out[265]: -133
得到這些數據之後,我們來計算30或-30的最小穿越時間(不是5000個過程都到達了30。我們可以用any方法來對此進行檢查)。
In [266]: hits30 = (np.abs(walks) >= 30).any(1)In [267]: hits30Out[267]: array([False, True, False, ..., False, True, False], dtype=bool)In [268]: hits30.sum() # Number that hit 30 or -30Out[268]: 3410In [269]: crossing_times = (np.abs(walks[hits30]) >= 30).argmax(1)In [270]: crossing_times.mean()Out[270]: 498.88973607038122
然後我們利用這個布爾型數組選出那些穿越了30(絕對值)的隨機漫步(行),並調用argmax在軸1上獲取穿越時間即可。
推薦閱讀:
※利用數組進行數據進行處理
※python numpy的樣本標準差怎麼寫?
※NumPy基礎:矢量計算
※ImagePy教程 —— 主界面