国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python中的Numeric包和Numarray包使用教程

2019-11-25 17:45:17
字體:
來源:轉載
供稿:網友

要了解 Numerical Python 軟件包的第一件事情是,Numerical Python 不會讓您去做標準 Python 不能完成的任何工作。它只是讓您 以快得多的速度去完成標準 Python 能夠完成的相同任務。實際上不僅僅如此;許多數組操作用 Numeric 或者 Numarray 來表達比起用標準 Python 數據類型和語法來表達要優雅得多。不過,驚人的速度才是吸引用戶使用 Numerical Python 的主要原因。

其實,Numerical Python 只是實現了一個新的數據類型:數組。與可以包含不同類型元素的列表、元組和詞典不同的是,Numarray 數組只能包含同一類型的數據。Numarray 數組的另一個優點是,它可以是多維的 -- 但是數組的維度與列表的簡單嵌套稍有不同。Numerical Python 借鑒了程序員的實踐經驗(尤其是那些有科學計算背景的程序員,他們抽象出了 APL、FORTRAN、MATLAB 和 S 等語言中數組的最佳功能),創建了可以靈活改變形狀和維度的數組。我們很快會回來繼續這一話題。

在 Numerical Python 中對數組的操作是 按元素進行的。雖然二維數組與線性代數中的矩陣類似,但是對它們的操作 (比如乘) 與線性代數中的操作 (比如矩陣乘) 是完全不同的。

讓我們來看一個關于上述問題的的具體例子。在純 Python 中,您可以這樣創建一個“二維列表”:
清單 1. Python 的嵌套數組

>>> pyarr = [[1,2,3],...     [4,5,6],...     [7,8,9]]>>> print pyarr[[1, 2, 3], [4, 5, 6], [7, 8, 9]]>>> pyarr[1][1] = 0>>> print pyarr[[1, 2, 3], [4, 0, 6], [7, 8, 9]]

很好,但是您對這種結構所能做的只是通過單獨的 (或者多維的) 索引來設置和檢索元素。與此相比,Numarray 數組要更靈活:
清單 2. Numerical Python 數組

>>> from numarray import *>>> numarr = array(pyarr)>>> print numarr[[1 2 3] [4 0 6] [7 8 9]]

改變并不大,但是使用 Numarray 進行的操作如何呢? 下面是一個例子:
清單 3. 元素操作

>>> numarr2 = numarr * 2>>> print numarr2[[ 2 4 6] [ 8 0 12] [14 16 18]]>>> print numarr2 + numarr[[ 3 6 9] [12 0 18] [21 24 27]]

改變數組的形狀:
清單 4. 改變形狀

>>> numarr2.shape = (9,)>>> print numarr2[ 2 4 6 8 0 12 14 16 18]

Numeric 與 Numarray 之間的區別

總體來看,新的 Numarray 軟件包與早期的 Numeric 是 API 兼容的。不過,開發者基于用戶經驗進行了一些與 Numric 并不兼容的改進。開發者沒有破壞任何依賴于 Numeric 的應用程序,而是開創了一個叫做 Numarray 的新項目。在完成本文時,Numarray 還缺少 Numeric 的一些功能,但是已計劃實現這些功能。

Numarray 所做的一些改進:

  •     以分層的類結構來組織元素類型,以支持 isinstance() 檢驗。Numeric 在指定數據類型時只使用字符類型編碼 (但是 Numarray 中的初始化軟件仍然接受老的字符編碼)。
  •     改變了類型強制規則,以保持數組(更為常見)中的類型 ,而不是轉換為 Python 標量的類型。
  •     出現了附加的數組屬性 (不再只有 getter 和 setter)。
  •     實現了更靈活的異常處理。

新用戶不必擔心這些變化,就這一點來說,最好一開始就使用 Numarray 而不是 Numeric。

計時的例子

讓我們來感受一下在 Numerical Python 中的操作相對于標準 Python 的速度優勢。作為一個“演示任務”,我們將創建一個數字序列,然后使它們加倍。首先是標準 Python 方法的一些變體:
清單 5. 對純 Python 操作的計時

def timer(fun, n, comment=""):  from time import clock  start = clock()  print comment, len(fun(n)), "elements",  print "in %.2f seconds" % (clock()-start)def double1(n): return map(lambda n: 2*n, xrange(n))timer(double1, 5000000, "Running map() on xrange iterator:")def double2(n): return [2*n for n in xrange(n)]timer(double2, 5000000, "Running listcomp on xrange iter: ")def double3(n):  double = []  for n in xrange(n):    double.append(2*n)  return doubletimer(double3, 5000000, "Building new list from iterator: ")

我們可以看出 map() 方法、list comprehension 和傳統循環方法之間的速度差別。那么,需要同類元素類型的標準 array 模塊呢?它可能會更快一些:
清單 6. 對標準 array 模塊的計時

import arraydef double4(n): return [2*n for n in array.array('i',range(n))]timer(double4, 5000000, "Running listcomp on array.array: ")

最后我們來看 Numarray 的速度如何。作為額外對照,我們來看如果必須要將數組還原為一個標準的列表時,它是否同樣具有優勢:
清單 7. 對 Numarray 操作的計時

from numarray import *def double5(n): return 2*arange(n)timer(double5, 5000000, "Numarray scalar multiplication: ")def double6(n): return (2*arange(n)).tolist()timer(double6, 5000000, "Numarray mult, returning list:  ")

現在運行它:
清單 8. 比較結果

$ python2.3 timing.pyRunning map() on xrange iterator: 5000000 elements in 13.61 secondsRunning listcomp on xrange iter: 5000000 elements in 16.46 secondsBuilding new list from iterator: 5000000 elements in 20.13 secondsRunning listcomp on array.array: 5000000 elements in 25.58 secondsNumarray scalar multiplication:  5000000 elements in 0.61 secondsNumarray mult, returning list:  5000000 elements in 3.70 seconds

處理列表的不同技術之間的速度差異不大,也許還是值得注意,因為這是嘗試標準的 array 模塊時的方法問題。但是 Numarray 一般用不到 1/20 的時間內就可以完成操作。將數組還原為標準列表損失了很大的速度優勢。

不應通過這樣一個簡單的比較就得出結論,但是這種加速可能是典型的。對大規模科學計算來說,將計算的時間由幾個月下降到幾天或者從幾天下降到幾個小時,是非常有價值的。

系統建模

Numerical Python 的典型用例是科學建模,或者可能是相關領域,比如圖形處理和旋轉,或者信號處理。我將通過一個比較實際的問題來說明 Numarray 的許多功能。假設您有一個參量可變的三維物理空間。抽象地說,任何參數化空間,不論有多少維,Numarray 都適用。實際上很容易想像,比如一個房間,它的各個點的溫度是不同的。我在 New England 的家已經到了冬天,因而這個問題似乎更有現實意義。

為簡單起見,下面我給出的例子中使用的是較小的數組(雖然這可能是顯然的,但是還是有必要明確地指出來)。不過,即使是處理有上百萬個元素而不僅僅是幾十個元素的數組,Numarray 也還是很快;前者可能在真正的科學模型中更為常見。

首先,我們來創建一個“房間”。有很多方法可以完成這項任務,但是最常用的還是使用可調用的 array() 方法。使用這個方法,我們可以生成具有多種初始化參數 (包括來自任何 Python 序列的初始數據) 的 Numerical 數組。不過對于我們的房間來說,用 zeros() 函數就可以生成一個溫度均勻的寒冷房間:
清單 9. 初始化房間的溫度

>>> from numarray import *>>> room = zeros((4,3,5),Float)>>> print room[[[ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.]] [[ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.]] [[ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.]] [[ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.]]]

自上而下每一個二維的“矩陣”代表三維房間的一個水平層面。

首先,我們將整個房間的溫度提高到比較舒適的 70 華氏度 (大約是 20 攝氏度):
清單 10. 打開加熱器

>>> room += 70>>> print room[[[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]]]

請注意,在我們接下來對 Numarray 數組和 Python 列表進行操作時有很重要的區別。當您選取數組的層面時 -- 我們將會看到,多維數組中的分層方法非常靈活且強大 -- 您得到的不是一個拷貝而是一個“視圖”。指向相同的數據可以有多種途徑。

讓我們具體來看。假設我們房間有一個通風裝置,會將地面的溫度降低四度:
清單 11. 溫度的變化

>>> floor = room[3]>>> floor -= 4>>> print room[[[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 66. 66. 66. 66. 66.] [ 66. 66. 66. 66. 66.] [ 66. 66. 66. 66. 66.]]]

與此相對,北面墻上的壁爐將每個鄰近位置的溫度升高了 8 度,而它所在位置的溫度為 90 度。
清單 12. 使用壁爐取暖

>>> north = room[:,0]>>> near_fireplace = north[2:4,2:5]>>> near_fireplace += 8>>> north[3,2] = 90 # the fireplace cell itself>>> print room[[[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 70. 78. 78. 78. 70.] [ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.]] [[ 66. 74. 90. 74. 66.] [ 66. 66. 66. 66. 66.] [ 66. 66. 66. 66. 66.]]]

這里我們使用了一些比較巧妙的索引方法,可以沿多維的方向來指定層面。這些視圖應該保留,以后還會用到。例如,您可能希望知道整個北面墻上的當前溫度:
清單 13. 查看北面的墻

>>> print north[[ 70. 70. 70. 70. 70.] [ 70. 70. 70. 70. 70.] [ 70. 78. 78. 78. 70.] [ 66. 74. 90. 74. 66.]]

更多操作

以上介紹的僅僅是 Numarray 中便捷的函數和數組方法/屬性中的一小部分。我希望能給您一些初步的認識;Numarray 文檔是深入學習的極好參考資料。

既然我們的房間現在各處的溫度不再相同,我們可能需要判斷全局的狀態。例如,當前房間內的平均溫度:
清單 14. 查看平均化后的數組

>>> add.reduce(room.flat)/len(room.flat)70.066666666666663

這里需要解釋一下。您可以對數組進行的所有操作都有相對應的 通用函數 (ufunc)。所以,我們在前面的代碼中使用的 floor -= 4 ,可以替換為 subtract(floor,4,floor) 。指定 subtract() 的三個參數,操作就可以正確完成。您還可以用 floor=subtract(floor,4) 來創建 floor 的一個拷貝,但這可能不是您所期望的,因為變化將發生在一個新的數組中,而不是 room 的一個子集中。

然而,unfunc 不僅僅是函數。它們還可以是可調用的對象,具有自己的方法:其中 .reduce() 可能是最為有用的一個。 reduce() 的工作方式如同 Python 中的內置函數 reduce() ,每個操作都是基本的 ufunc (不過這些方法在應用于 Numerical 數組時會快得多)。換句話說, add.reduce() 表示的是 sum() , multiply.reduce() 表示的是 product() (這些快捷名稱也是定義好了的)。

在求房間各單元溫度的和之前,您需要先得到數據的一個一維視圖。不然,您得到的是第一維的和,并生成一個降低了維數的新數組。例如:
清單 15. 非平面數組的錯誤結果

>>> add.reduce(room)array([[ 276., 292., 308., 292., 276.],    [ 276., 276., 276., 276., 276.],    [ 276., 276., 276., 276., 276.]])

這樣一個空間和可能會有用,但它并不是我們這里想要得到的。

既然我們是在對一個物理系統建模,我們來讓它更真實一些。房間內有微小的氣流,使得溫度發生變化。在建模時我們可以假設每一個小的時間段內,每個單元會根據它周圍的溫度進行調整:
清單 16. 微氣流模擬

>>> def equalize(room):...  z,y,x = map(randint, (1,1,1), room.shape)...  zmin,ymin,xmin = maximum([z-2,y-2,x-2],[0,0,0]).tolist()...  zmax,ymax,xmax = [z+1,y+1,x+1]...  region = room[zmin:zmax,ymin:ymax,xmin:xmax].copy()...  room[z-1,y-1,x-1] = sum(region.flat)/len(region.flat)...  return room

這個模型當然有一些不現實:單元不會只根據它周圍的溫度進行調整而不去影響它相鄰的單元。盡管如此,還是讓我們來看一下它執行的情況。首先我們選擇一個隨機的單元 -- 或者實際上我們選取的是單元本身在每一維度上的索引值加上 1,因為我們通過 .shape 調用得到的是長度而不是最大的索引值。 zmin 、 ymin 和 xmin 確保了我們的最小值索引值為 0,不會取到負數; zmax 、 ymax 和 xmax 實際上并不需要,因為數組每一維的大小減去 1 之后的索引值就被當作最大值來使用(如同 Python 中的列表)。

然后,我們需要定義鄰近單元的區域。由于我們的房間很小,所以經常會選擇到房間的表面、邊沿或者一角 -- 單元的 region 可能會比最大的 27 元素 (3x3x3) 子集要小。這沒關系;我們只需要使用正確的分母來計算平均值。這個新的平均溫度值被賦給前面隨機選擇的單元。

您可以在您的模型中執行任意多次的平均化過程。每一次調用只調整一個單元。多次調用會使用房間的某些部分的溫度逐漸趨于平均。即使數組是動態改變的, equalize() 函數照樣可以返回它的數組。當您只想平均化模型的一個 拷貝時這將非常有用:
清單 17. 執行 equalize()

>>> print equalize(room.copy())[[[ 70.    70.    70.    70.    70.   ] [ 70.    70.    70.    70.    70.   ] [ 70.    70.    70.    70.    70.   ]] [[ 70.    70.    71.333333 70.    70.   ] [ 70.    70.    70.    70.    70.   ] [ 70.    70.    70.    70.    70.   ]] [[ 70.    78.    78.    78.    70.   ] [ 70.    70.    70.    70.    70.   ] [ 70.    70.    70.    70.    70.   ]] [[ 66.    74.    90.    74.    66.   ] [ 66.    66.    66.    66.    66.   ] [ 66.    66.    66.    68.    66.   ]]]

結束語

本文僅介紹了 Numarray 的部分功能。它的功能遠不止這些。例如,您可以使用填充函數來填充數組,這對于物理模型來說非常有用。您不但可以通過層面而且可以通過索引數組來指定數組的子集 -- 這使您不但可以對數組中不連續的片斷進行操作,而且可以 -- 通過 take() 函數 -- 以各種方式重新定義數組的維數和形狀。

前面我所描述的大部分操作都是針對于標量和數組的;您還可以執行數組之間的操作,包括那些不同維度的數組之間。這涉及到的內容很多,但通過 API 可以直觀地完成所有這些操作。

我鼓勵您在自己的系統上安裝 Numarray 和 / 或 Numeric。它不難上手,并且它提供的對數組的快速操作可以應用于極廣泛的領域 -- 往往是您開始時意想不到的。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 抚远县| 铜川市| 湖北省| 和静县| 钦州市| 新安县| 茶陵县| 青海省| 张家川| 宽甸| 新余市| 耒阳市| 尼勒克县| 长岭县| 怀安县| 潍坊市| 天镇县| 鄂尔多斯市| 新绛县| 甘南县| 浮山县| 霍林郭勒市| 仪陇县| 林口县| 曲沃县| 留坝县| 田林县| 长武县| 新郑市| 香港| 闻喜县| 探索| 阿瓦提县| 拜城县| 岗巴县| 吴桥县| 梁平县| 泸溪县| 息烽县| 西畴县| 紫金县|