2019.3.23
因?yàn)樽约簺](méi)什么動(dòng)力,真的很久沒(méi)有順著自己的心思來(lái)學(xué)習(xí)了,趁著有數(shù)據(jù)分析的課,今天一大早起來(lái)學(xué)習(xí)一下Numpy庫(kù)的使用。特以此文記錄學(xué)習(xí)進(jìn)度。

一.ndarray數(shù)組的創(chuàng)建
1. 概述
NumPy是使用Python進(jìn)行科學(xué)計(jì)算的基礎(chǔ)包。它包含其他內(nèi)容:一個(gè)強(qiáng)大的N維數(shù)組對(duì)象、復(fù)雜的(廣播)功能、用于集成C / C ++和Fortran代碼的工具、有用的線性代數(shù),傅里葉變換和隨機(jī)數(shù)功能除了明顯的科學(xué)用途外,NumPy還可以用作通用數(shù)據(jù)的高效多維容器??梢远x任意數(shù)據(jù)類型。這使NumPy能夠無(wú)縫快速地與各種數(shù)據(jù)庫(kù)集成。Numpy具有兩類對(duì)象,分別是ndarray(N-dimensional Array Object)以及ufunc(Universal Function Object),前者類似于多維數(shù)組,后者則是可以對(duì)前者操作的函數(shù)。
2. 基本方法
- numpy.array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0)
numpy.array()是最原始的手動(dòng)生成ndarray對(duì)象的方法。其中的object 需傳入一個(gè)數(shù)組對(duì)象(n維)。注:當(dāng)ndarray的維度過(guò)大時(shí),numpy的輸出會(huì)折疊中間結(jié)果。如果想要取消折疊。需要這樣設(shè)置
np.set_printoptions(threshold=np.nan)
# Use the numpy.array to create the ndarray
import numpy as np
array1 = np.array([[1, 2, 3], [4, 5, 6]]) #必須傳入一個(gè)列表或數(shù)組
"""Output:
[[1 2 3]
[4 5 6]]
"""
-
常用屬性
常用屬性 屬性說(shuō)明 ndim 矩陣的秩,即軸的數(shù)量或維度的數(shù)量 shape 數(shù)組的維度,對(duì)于矩陣,n 行 m 列 size 數(shù)組元素的總個(gè)數(shù),相當(dāng)于 .shape 中 nm 的值* dtype ndarray 對(duì)象的元素類型 real ndarray元素的實(shí)部 imag ndarray 元素的虛部 -
使用樣例
# Use the numpy.array to create the ndarray import numpy as np array1 = np.array([[1, 2, 3], [4, 5, 6]]) print(array1.ndim) """ Output: 2 """
- arange([start]stop[,step], dtype=Nope)
numpy.arange()用于生成一個(gè)指定步長(zhǎng)的等差數(shù)組。其做法與range()相似,包括start而不包括stop。其中start和step為可選參數(shù),默認(rèn)start為0,step為1;stop指定了區(qū)間的結(jié)束(開(kāi)區(qū)間);dtype默認(rèn)為Nope。可惜的是,無(wú)法指定其形狀shape,故只能通過(guò)修改shape的值的方法來(lái)生成多維數(shù)組。
-
使用樣例
# Use the numpy.array to create the ndarray import numpy as np print("利用arange()來(lái)創(chuàng)建一個(gè)ndarray:", np.arange(0, 1, 0.1)) """ Output: 利用arange()來(lái)創(chuàng)建一個(gè)ndarray: [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9] """
- numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
numpy.logspace()用于創(chuàng)建一個(gè)等比數(shù)組。其中start, stop 都是必須給出的參數(shù),表示區(qū)間(規(guī)則與range()相同)。num表示元素的個(gè)數(shù),默認(rèn)50。在閉合區(qū)間[start,stop]或半開(kāi)區(qū)間[start,stop]中存在數(shù)量等間距的樣本(取決于端點(diǎn)是True還是False)。
- numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0)
numpy.logspace()與numpy.lonspqce()的區(qū)別在于,前者多了一個(gè)參數(shù)base,這意味著numpy.logspace()是根據(jù)10為底數(shù)來(lái)創(chuàng)建等比數(shù)組的(當(dāng)然,可以傳入別的值作為底),start與stop將被理解為“在[10^start, 10^stop]區(qū)間內(nèi)構(gòu)建等比數(shù)組”。
- 幾個(gè)構(gòu)建特殊矩陣數(shù)組的函數(shù)(不予以例子說(shuō)明)
numpy.zeros(): 需要一個(gè)元組類似于(3,4)來(lái)指定形狀,元素全部用0充填
numpy.ones():需要一個(gè)元組類似于(3,4)來(lái)指定形狀,元素全部用1充填
numpy.eye():只需傳入一個(gè)代表維數(shù)的int型整數(shù)即可,生成一個(gè)單位n維矩陣
numpy.diag():需要傳入一個(gè)具有n個(gè)元素的一維數(shù)組, 生成一個(gè)n維的,對(duì)角線上的元素依次為傳入的一維數(shù)組的元素的矩陣(類似于對(duì)角矩陣)
二.Numpy的各種操作方式
- 矩陣運(yùn)算
import numpy as np
a = np.array([20, 30, 40, 50])
b = np.arange(4)
print(a-b)
""" Output: [20 29 38 47] """
print(b**2)
""" Output: [0 1 4 9] """
print(10*np.sin(a))
""" Output: array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854]) """
print(a<35)
""" Output: [ True True False False] """
與大部分的數(shù)學(xué)語(yǔ)言(如MATLAB)不同,Numpy中的乘號(hào)(*) 的數(shù)組運(yùn)算是求元素積,而不是數(shù)量積(矩陣相乘)。如果需要求數(shù)量積,就需要使用@或者dot()。其他的諸如加減除(+ - /)等運(yùn)算符,均在Numpy中通用。還有一些諸如求和,求最大最小值的函數(shù)也可用(sum(), min()等)。
import numpy as np
A = np.array([[1, 1], [0, 1]])
B = np.array([[2, 0], [3, 4]])
print(A * B)
""" Output:
[[2, 0]
[0, 4]]
"""
print(A @ B)
""" Output:
[[5, 4]
[3, 4]]
"""
print(A.dot(B))
""" Output:
[5, 4]
[3, 4]]
"""
- 通用函數(shù)
一些通用的數(shù)學(xué)函數(shù),例如sin、cos、exp等,此類函數(shù)被稱作 通用函數(shù),其操作的對(duì)象也是數(shù)組的元素,即元素積之類的。
import numpy as np
B = np.arange(3)
print(np.exp(B))
""" Output: [1. 2.71828183 7.3890561 ] """
print(np.sqrt(B))
""" Output: [0. 1. 1.41421356] """
- 索引
ndarray的索引使用方法與列表的寫(xiě)法相近。如果是多維的數(shù)組,則每一維的索引用逗號(hào)分隔。 其中還有一種比較有趣的寫(xiě)法--- 省略號(hào):表示全集(即那個(gè)維度的全部元素)。索引甚至可以是一個(gè)數(shù)組,表示一次索引多個(gè)值、還可以是布爾表達(dá)式。 還有更多的高級(jí)玩法就不一一演示了。
import numpy as np
a = np.arange(10)**3 # 冪的寫(xiě)法,表示3次方
print(a[2:5])
""" Output: [ 8 27 64] """
def f(x, y):
return 10*x + y
# fromfunction()可以從一個(gè)函數(shù)中獲得數(shù)據(jù)來(lái)創(chuàng)建ndarray
b = np.fromfunction(f, (5, 4), dtype=int)
print(b[1:3, 2:3])
"""Output:
[[12]
[22]]
"""
print(b[:2 ,...]) #表示第二維輸出全部元素
"""Output:
[[ 0 1 2 3]
[10 11 12 13]]
"""
print(b[..., :2]) #表示第一維輸出所有元素
"""Output:
[[ 0 1]
[10 11]
[20 21]
[30 31]
[40 41]]
"""
- 遍歷
對(duì)一個(gè)多維的ndarray對(duì)象使用迭代器的話,默認(rèn)是遍歷一行。
import numpy as np
def f(x, y):
return 10*x + y
b = np.fromfunction(f, (5, 4), dtype=int)
for row in b:
print(row)
"""Output:
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]
"""
for elements in b.flat:
print(elements)
"""Output:
0
1
2
3
...
"""
- 維度控制
numpy中有很多函數(shù)可以改變一個(gè)ndarray的維度。以下列出幾個(gè)常用的。
- ravel(): 對(duì)多維的矩陣進(jìn)行降到一維的操作。并且,numpy.ravel()返回的是視圖,會(huì)影響原始矩陣。
- flatten():功能與ravel()一致。但其是對(duì)矩陣的一個(gè)深拷貝進(jìn)行操作,所以不會(huì)改變?cè)仃嚒?/strong>(不予以例子)
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
print(a) # 輸出原矩陣
"""Output:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
"""
a = a.ravel()
print(a) #輸出降維的矩陣,發(fā)現(xiàn)確實(shí)改變了原矩陣
"""Output: [ 1 2 3 4 5 6 7 8 9 10 11 12] """
- reshape()與resize():兩者的功能都是將矩陣改變成指定的維度。reshape()傳入一個(gè)元組,表示指定的維度(要合理);resize()需要傳入矩陣,和一個(gè)指定的元組。區(qū)別是,resize()會(huì)改變?cè)仃嚒?/strong>
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
print(a.reshape(3, 4))
"""Output:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
"""Output:
print(a) # 原數(shù)組并沒(méi)有被改變
"""Output:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
"""
print(np.resize(a, (3, 4))) # 必須這樣來(lái)調(diào)用
"""Output:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
"""
print(a) # 原矩陣被改變
"""Output:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
"""
print(a.reshape(2, -1)) # 可以傳入-1,numpy會(huì)自動(dòng)計(jì)算剩下的維度,但還是要合理
"""Output:
[[ 1 2 3 4 5 6]
[ 7 8 9 10 11 12]]
"""
- 復(fù)制
一般的矩陣復(fù)制并不會(huì)復(fù)制任何內(nèi)存(只是改變了標(biāo)簽名)。 而視圖(view)是矩陣的一個(gè)淺拷貝,雖不是原矩陣(即會(huì)另外分配內(nèi)存),但對(duì)視圖的操作會(huì)影響到原矩陣。 深復(fù)制則是另外分配內(nèi)存,把原矩陣所有值復(fù)制過(guò)來(lái),操作不會(huì)改變?cè)仃嚒?/em>
import numpy as np
a = np.arange(12).reshape(3, 4)
b = a
b is a # True表示b和a是同一個(gè)內(nèi)存對(duì)象
"""Output: True """
c = a.view()
c is a # c并不和a是同一個(gè)對(duì)象
"""Output: False """
print(a) # 輸出原矩陣
"""Output:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
"""
c[0, 0] = 111
print(a) # 改變視圖,原矩陣元素改變
"""Output:
[[111 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
"""
b = a.copy()
b is a # 深拷貝不是同一對(duì)象
"""Output: False """
b[0, 0] = 222
print(a) # 深拷貝的操作不會(huì)改變?cè)仃?"""Output:
[[111 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
"""
更多的進(jìn)階功能:
官方教程
函數(shù)詳細(xì)說(shuō)明文檔及手冊(cè)
三.實(shí)例聯(lián)系:康威生命棋(用Numpy和pygame模擬)
劍橋大學(xué) 約翰·何頓·康威(John Horton Conway) 教授設(shè)計(jì)了一個(gè)叫做“生命游戲”的計(jì)算機(jī)程序,生命游戲是一個(gè)二維網(wǎng)格游戲,這個(gè)網(wǎng)格中每個(gè)方格居住著一個(gè)活著或死了的細(xì)胞。一個(gè)細(xì)胞在下一個(gè)時(shí)刻的生死取決于相鄰8個(gè)方格中活著或死了的細(xì)胞的數(shù)量。如果相鄰方格活著的細(xì)胞數(shù)量過(guò)多,這個(gè)細(xì)胞會(huì)因?yàn)橘Y源匱乏而在下一個(gè)時(shí)刻死去;相反,如果周圍活細(xì)胞過(guò)少,這個(gè)細(xì)胞會(huì)因?yàn)楣聠味廊ァ?/em>
大致規(guī)則
(1)當(dāng)前細(xì)胞為死亡狀態(tài)時(shí),當(dāng)周圍有3個(gè)存活細(xì)胞時(shí),則迭代后該細(xì)胞變成存活狀態(tài)(模擬繁殖);若原先為生,則保持不變。
(2)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周圍的鄰居細(xì)胞低于兩個(gè)(不包含兩個(gè))存活時(shí),該細(xì)胞變成死亡狀態(tài)(模擬生命數(shù)量稀少)。
(3)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周圍有兩個(gè)或3個(gè)存活細(xì)胞時(shí),該細(xì)胞保持原樣。
(4)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周圍有3個(gè)以上的存活細(xì)胞時(shí),該細(xì)胞變成死亡狀態(tài)(模擬生命數(shù)量過(guò)多)。
這里就不多說(shuō)什么了,直接上訓(xùn)練的代碼。
import sys
import numpy as np # numpy用于存儲(chǔ)康威生命棋的矩陣
import pygame # pygame可以提供游戲窗口
def life_step(x, y, world):
# sum(a[, axis, dtype, out, keepdims]) 給定軸上的數(shù)組元素的總和
neighbours = np.sum(world[x-1:x+2, y-1:y+2])-world[x, y]
if world[x, y] == 1 and not 2 <= neighbours <= 3:
return 0
elif neighbours == 3:
return 1
return world[x, y]
def main():
screen_size = 500
tile_size = 10
background_color = (0, 0, 0)
cell_color = (255, 55, 255)
pygame.init()
screen = pygame.display.set_mode((screen_size, screen_size))
pygame.display.set_caption('Convay\'s Game of Life')
clock = pygame.time.Clock()
world = np.random.choice(a=[0], size=(screen_size // tile_size + 1, screen_size // tile_size+1))
gun = [(5, 1), (5, 2), (6, 1), (6, 2), (5, 11), (6, 11), (7, 11), (4, 12),
(3, 13), (3, 14), (8, 12), (9, 13), (9, 14), (6, 15), (4, 16), (5, 17),
(6, 17), (7, 17), (6, 18), (8, 16), (3, 21), (4, 21), (5, 21), (3, 22),
(4, 22), (5, 22), (2, 23), (6, 23), (1, 25), (2, 25), (6, 25), (7, 25),
(3, 35), (4, 35), (3, 36), (4, 36)]
# 根據(jù)gun里的元素,將world相應(yīng)位置的元素設(shè)置為1
for i, j in gun:
world[j, i] = 1
fps = 0
epoch = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.set_caption("Convay\'s Game of Life /" + str(fps) +"FPS /" + str(epoch) + "epoch")
screen.fill(background_color)
new_world = np.copy(world)
for (x, y), value in np.ndenumerate(world):
new_world[x, y] = life_step(x, y, world)
if new_world[x, y] == 1:
pygame.draw.rect(screen, cell_color, (tile_size*(x-1), tile_size*(y-1), tile_size, tile_size), 0)
world = new_world
epoch += 1
pygame.display.update()
clock.tick(fps)
if __name__ == '__main__':
main()
運(yùn)行截圖

