python:numpy陣列運算、排序、統計、隨機數生成

LY_ysys629發表於2017-06-24

主要內容

1) 利用陣列進行資料處理

2) 將條件邏輯表述為陣列運算

3) 數學與統計方法

4) 用於布林型陣列的方法

5) 排序

6) 唯一化以及其他的集合邏輯

7) 用於陣列的檔案輸入輸出

8) 線性代數

1) 利用陣列進行資料處理

import numpy as np
points = np.arange(-5,5,1)

print points
xs,ys  = np.meshgrid(points,points)

ys
[-5 -4 -3 -2 -1  0  1  2  3  4]

array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
       [-4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
       [-3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
       [-2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
       [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1],
       [ 2,  2,  2,  2,  2,  2,  2,  2,  2,  2],
       [ 3,  3,  3,  3,  3,  3,  3,  3,  3,  3],
       [ 4,  4,  4,  4,  4,  4,  4,  4,  4,  4]])
xs
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4]])

2) 將條件邏輯表述維陣列運算

np.where()函式是三元表示式:x if condition else y 的向量化版本,假設,我們有一個布林陣列和兩個陣列

xarr = np.array([1,2,3,4,5])

yarr = np.array([6,7,8,9,10])

cond = np.array([True,False,True,True,False,])

加入我們想根據cond陣列的情況來選取xarr或yarr陣列中的值,有兩種方法,一種是列表推導式,另外一種是向量化

##列表推導式
%timeit  result = [(x if c else y) for x,y,c in zip(xarr,yarr,cond)]
The slowest run took 14.83 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.77 µs per loop
result
[1, 7, 3, 4, 10]
##  向量化
%timeit result = np.where(cond,xarr,yarr)
The slowest run took 13.14 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 827 ns per loop
result
array([ 1,  7,  3,  4, 10])

從上述結果真可以看出,向量化的計算速度大概是列表計算的三倍,注意返回結果型別的不一致!np.where函式的引數還可以是標量

arr = np.random.randn(4,4)
arr
array([[ 0.81362115, -0.59091357,  0.04834518,  0.31279457],
       [ 0.14034937, -0.495634  , -1.65939013, -0.06717819],
       [ 1.27779012,  1.00333966, -1.89590419,  0.06417592],
       [-0.39706132, -0.55924097,  0.19493047, -2.09199616]])
np.where(arr>0,2,-2)
array([[ 2, -2,  2,  2],
       [ 2, -2, -2, -2],
       [ 2,  2, -2,  2],
       [-2, -2,  2, -2]])
arr
array([[ 0.81362115, -0.59091357,  0.04834518,  0.31279457],
       [ 0.14034937, -0.495634  , -1.65939013, -0.06717819],
       [ 1.27779012,  1.00333966, -1.89590419,  0.06417592],
       [-0.39706132, -0.55924097,  0.19493047, -2.09199616]])

注意,條件邏輯表示式不改變原陣列

np.where(arr>0,2,arr)#只在條件為真是做出改變
array([[-1.05581125, -0.33226037,  2.        , -0.35399731],
       [ 2.        , -0.85778503,  2.        , -0.63576095],
       [ 2.        ,  2.        , -0.76836718,  2.        ],
       [-0.04934349, -0.95880935,  2.        , -1.00340544]])

還可以巢狀

cond1 = np.array([True,False,True,True,True,])

np.where(cond & cond1,0,np.where(cond1,1,2))
array([0, 2, 0, 0, 1])

另外,布林型資料還可以在計算過程中被當做0或1處理

result = 1*(cond - cond1) + 2*(cond+cond1)
C:\Program Files\anaconda\lib\site-packages\ipykernel\__main__.py:1: DeprecationWarning: numpy boolean subtract, the `-` operator, is deprecated, use the bitwise_xor, the `^` operator, or the logical_xor function instead.
  if __name__ == '__main__':
result
array([2, 0, 2, 2, 3])

3)數學和統計方法

比如sum、mean、std等聚合計算(aggregation,通常叫做約減(reduction)),既可以當做陣列的例項方法呼叫(array.sum()),還可以當做頂級Numpy函式使用sum(array)。

arr = np.ones((4,5))
arr
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.]])
arr.mean()
1.0
np.mean(arr)
1.0
arr.sum()
20.0
arr
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.]])

注意,聚合函式不改變原陣列

np.sum(arr)
20.0
arr[:,2] = 2
arr
array([[ 1.,  1.,  2.,  1.,  1.],
       [ 1.,  1.,  2.,  1.,  1.],
       [ 1.,  1.,  2.,  1.,  1.],
       [ 1.,  1.,  2.,  1.,  1.]])
arr.sum(0)#縱軸方向\
13
arr
array([0, 1, 3, 4, 5])
arr.sum(1)#橫軸方向
array([ 6.,  6.,  6.,  6.])
arr.cumsum(0)#縱軸方向的累計和,放回新陣列
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 4.,  4.,  4.,  4.,  4.]])

基本陣列統計方法

方法 說明
sum 對陣列中全部或某軸向的元素求和,0長度的陣列的sum為0
mean 算數平均數,0長度的陣列的mean為NaN
std、var 標準差、方差,自由度可調(預設為n)
min、max 最大和最小
argmin、argmax 最大和最小的索引
cumsum、cumprod 所有元素的累計和、累計積

4) 用於布林型陣列的方法

1) sum 統計布林型陣列中True的個數,由於布林型陣列中True會被當成1來參加運算。

2) any 用於測試陣列中是否存在一個或多個True

3) all 用來檢查陣列中所有值是否都是True

4) 另外 any、all也可以用與非布林型陣列,所有非0元素會被當做True

import numpy as np

bools = np.array([False,False,True,False,True])

bools.sum()
2
bools.any()
True
bools.all()
False

從上述結果中,any和all說明bools中有True但不全是,而sum統計了True的個數。

5)排序

arr = np.arange(5)

arr[2]=5
arr
array([0, 1, 5, 3, 4])
arr.sort()
arr
array([0, 1, 3, 4, 5])
np.sort(arr)
array([0, 1, 3, 4, 5])
array = np.arange(1,5,0.5).reshape(2,4)
array
array([[ 1. ,  1.5,  2. ,  2.5],
       [ 3. ,  3.5,  4. ,  4.5]])
array[:,1] = np.array([3.5,1.5]).T
array
array([[ 1. ,  3.5,  2. ,  2.5],
       [ 3. ,  1.5,  4. ,  4.5]])
array.sort(0)#在縱軸上排序
array
array([[ 1. ,  1.5,  2. ,  2.5],
       [ 3. ,  3.5,  4. ,  4.5]])
array[:,1] = np.array([3.5,1.5]).T
print array
array.sort(1)#在橫軸上排序
array
[[ 1.   3.5  2.   2.5]
 [ 3.   1.5  4.   4.5]]


array([[ 1. ,  2. ,  2.5,  3.5],
       [ 1.5,  3. ,  4. ,  4.5]])

python內建排序程式

array = np.array([1,2,6,3,5,4])

array
array([1, 2, 6, 3, 5, 4])
sorted(array)#python內建一般返回列表
[1, 2, 3, 4, 5, 6]
array#內建不改變原來是陣列?
array([1, 2, 6, 3, 5, 4])

注意,sort會在原陣列上做修改

6) 唯一化以及其他的集合邏輯

numpy提供一些針對**一維**ndarray的基本集合運算,最常用的是np.unique(),它用於找出陣列中的唯一值並返回已排序的結果

names = np.array(['a','b','c','a','c'])
names
array(['a', 'b', 'c', 'a', 'c'], 
      dtype='|S1')
np.unique(names)
array(['a', 'b', 'c'], 
      dtype='|S1')
names
array(['a', 'b', 'c', 'a', 'c'], 
      dtype='|S1')
ints = np.array([3,3,3,2,2,2,1,1,4,4])
ints
array([3, 3, 3, 2, 2, 2, 1, 1, 4, 4])
%timeit 
The slowest run took 42.94 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 3.8 µs per loop
np.unique(ints)
array([1, 2, 3, 4])
#上述程式碼實現功能可以python來實現
%timeit sorted(set(ints))
The slowest run took 25.40 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.75 µs per loop
sorted(set(ints))
[1, 2, 3, 4]

可以看出並不是所有的內建都是效率低的~

np.in1d用於測試一個陣列中的值是否存在於另外一個陣列中,並返回一個大小和測試陣列一樣的布林型陣列

value = np.array([6,0,0,3,2,5])
np.in1d(value,[2,3,6])
array([ True, False, False,  True,  True, False], dtype=bool)

常見的陣列集合運算

方法 說明
unique(x) 計算x中的唯一元素,並返回有序結果
intersect1d(x,y) 計算x和y中的公共元素(交集),並返回有序結果
union1d(x,y) 計算x和y的並集,並返回有序結果
in1d(x,y) 得到一個表示“x中元素是否在y陣列中”的布林型陣列
setdiff1d(x,y) 集合的差,即元素在x中且不在y中
setxor1d(x,y) 集合的對稱差(異或),即存在於一個陣列中但不同時存在於兩個陣列中的元素

7) 用於陣列的檔案輸入輸出

numpy能夠讀寫磁碟上的文字資料和二進位制資料,pandas中有將表格型資料讀取到記憶體的工具

將陣列以二進位制格式儲存到磁碟

np.save和np.load是讀寫磁碟資料的兩個主要函式,預設情況下,陣列是以未壓縮的原始二進位制格式儲存在副檔名為.npy的檔案中。

arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.save('E:\python\juputer\sameArray',arr)#可以不加字尾,系統會自動加.npy
np.load('E:\python\juputer\sameArray.npy')#必須有字尾
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

此外,還可以將多個陣列儲存到一個壓縮檔案中,將陣列以關鍵字引數的形式傳入即可

array = np.array([1,2,0,0,0,0,0])

np.savez('bb',a=arr,b=array)#貌似只能壓縮到預設路徑下,不知道什麼原因
arch = np.load('bb.npz')
arch['b']
array([1, 2, 0, 0, 0, 0, 0])

存取文字資料

從文字中載入說句是一個非常標準的任務。numpy主要有np.loadtxt()和np.genfromtxt()函式,pandas主要有read_csv和read_table()函式。

arr = np.random.randn(4,3)
arr
array([[-0.51108593,  0.72750055, -0.15797328],
       [-0.36643894,  0.55478468,  0.30060344],
       [-0.76537983, -0.28501039, -0.14497014],
       [ 0.72564297, -1.27952004,  0.30936996]])
np.savetxt('test.txt',arr)
arr = np.loadtxt('test.txt')
arr
array([[-0.51108593,  0.72750055, -0.15797328],
       [-0.36643894,  0.55478468,  0.30060344],
       [-0.76537983, -0.28501039, -0.14497014],
       [ 0.72564297, -1.27952004,  0.30936996]])

8)線性代數

線性代數(如矩陣乘法、矩陣分解、行列式以及其他方陣等)是任何陣列庫的重要組成部分。numpy提供了一個用於矩陣乘法的dot函式(陣列方法),實現陣列的點積。

常用的numpy.linalg函式

函式 說明
diag 以一維陣列的形式放回方陣的對角線(或非對角線元素),或將一維陣列換為方陣(非對角線元素為0)
dot 矩陣乘法
trace 計算對角線元素和
det 計算矩陣的行列式
eig 計算方陣的特徵值和特徵向量
inv 計算方陣的逆
pinv 計算矩陣的Moore-Penrose偽逆
qr 計算qr分解
svd 計算奇異值(SVD)
solve 解線性方程組Ax=b,其中A為一個方陣
lstsq 計算Ax=b的最小二乘解
x = np.arange(1,12,2).reshape(2,3)
x
array([[ 1,  3,  5],
       [ 7,  9, 11]])
y = np.arange(2,13,2).reshape(3,2)
y
array([[ 2,  4],
       [ 6,  8],
       [10, 12]])
np.dot(x,y)#等價於x.dot(y)
array([[ 70,  88],
       [178, 232]])
y
array([[ 2,  4],
       [ 6,  8],
       [10, 12]])
x = np.random.randn(5,5)
x
array([[ 1.63103816,  0.71983566,  1.10352515, -0.27938298,  0.11040744],
       [ 0.41088167, -0.73636959,  1.39466507,  0.02659672, -1.20904744],
       [ 0.5186612 , -1.86480014,  2.89604141, -0.63832998, -0.49133989],
       [ 1.63042984,  0.57143769, -1.11857589, -0.02013889,  0.46964764],
       [ 1.23888832,  3.42855521, -2.36622283, -1.22878746,  1.80597763]])
mat = x.T.dot(x)
np.linalg.inv(mat)
array([[ 0.27742733, -0.19565147, -0.16151662,  0.02161428, -0.04933913],
       [-0.19565147,  0.67591051,  0.47450978,  0.64285176, -0.03838762],
       [-0.16151662,  0.47450978,  0.6679418 ,  1.00350966,  0.69607497],
       [ 0.02161428,  0.64285176,  1.00350966,  2.60588578,  1.45256531],
       [-0.04933913, -0.03838762,  0.69607497,  1.45256531,  1.87265356]])
mat.T.dot(np.linalg.inv(mat))
array([[  1.00000000e+00,   1.10290647e-16,   6.50206020e-17,
         -9.56263991e-18,   2.31165248e-16],
       [  1.86021783e-16,   1.00000000e+00,  -4.42906701e-16,
         -2.93319024e-16,  -1.88919268e-15],
       [  4.43545563e-17,   1.16736094e-15,   1.00000000e+00,
          8.64035632e-16,   4.01786135e-16],
       [ -9.10610531e-17,   2.30215482e-16,   2.61428391e-16,
          1.00000000e+00,  -9.26009142e-17],
       [  2.00085966e-16,  -1.58177563e-15,  -1.19547067e-15,
         -1.29203693e-15,   1.00000000e+00]])
s,v,d = np.linalg.svd(mat)
s
array([[-0.16523474,  0.77808826,  0.58918158,  0.13972992, -0.02483462],
       [-0.64883151,  0.20661516, -0.29383095, -0.64803915,  0.17331036],
       [ 0.64914815,  0.49923165, -0.41237116, -0.21362089,  0.33718034],
       [ 0.10505073, -0.30923038,  0.52695933, -0.24319507,  0.74599661],
       [-0.3453783 ,  0.08386396, -0.34466264,  0.67508746,  0.54694172]])
v
array([ 37.27592672,   9.26487289,   1.86483196,   0.86523652,   0.23402418])
d
array([[-0.16523474, -0.64883151,  0.64914815,  0.10505073, -0.3453783 ],
       [ 0.77808826,  0.20661516,  0.49923165, -0.30923038,  0.08386396],
       [ 0.58918158, -0.29383095, -0.41237116,  0.52695933, -0.34466264],
       [ 0.13972992, -0.64803915, -0.21362089, -0.24319507,  0.67508746],
       [-0.02483462,  0.17331036,  0.33718034,  0.74599661,  0.54694172]])

9)隨機數生成

numpy.random模組是對python內建random進行補充,增加了一些用於高效生成多種概率分佈的樣本值的函式,例如,你可以用normal來得到一個標準正態分佈的4*4樣本陣列。

常用的隨機數生成函式

函式 說明
seed 確定隨機數生成器的種子
permutation 返回一個序列的隨機排列或返回一個隨機排列的範圍
shuffle 對一個序列就地隨機排列
rand 產生均勻分佈的樣本值
randint 從給定的上下限範圍內隨機選取整數
randn 產生正態分佈(平均數為0,標準差為1)的樣本值,類似於MATLAB介面
binomial 產生二項分佈的樣本值
normal 產生正態分佈(高斯分佈)的樣本值
beta 產生beta分佈的樣本值
chisquare 產生卡方分佈的樣本值
gamma 產生gamma分佈的樣本值
uniform 產生[0,1)均勻分佈的樣本值
#產生高斯分佈
sample = np.random.normal(size=(4,4))
sample
array([[ 0.89509853, -0.83225074,  1.29474565,  0.45655647],
       [-1.43400126,  1.32985572,  2.30055355,  2.46808663],
       [-2.4563378 , -0.66266506, -1.15600003, -0.60034993],
       [-1.79678809, -0.69896066,  1.02434411,  0.1271823 ]])

總結

1)條件邏輯表示式不改變原陣列,會返回新的布林型陣列

2)聚合函式不改變原陣列,返回結果值

3)監測和檢驗函式不改變原陣列,返回布林型資料

4)排序函式能夠改變原陣列,在原來的資料上修改

5)唯一化及集合邏輯不改變原陣列,返回新的陣列

6)線性代數、矩陣運算不改變原陣列,返回結果陣列

7)切片相當於引用,指向同一記憶體區,因此不管改變原陣列,還是新的引用變數都會改變原陣列

8) numpy元素級通用函式不改變原陣列

相關文章