2016 年 3 月

第 31 卷,第 3 期

本文章是由機器翻譯。

Python - 為 C# 開發人員介紹 SciPy 程式設計

James McCaffrey

詞彙的資料科學,沒有任何正式定義,但我將它視為使用軟體程式,使用傳統的統計資料的技術和機器學習演算法來分析資料。直到最近,大部分的資料科學分析昂貴的商業產品來執行,但在過去幾年來使用的開放原始碼替代項目已大幅增加。

根據我的同事的交談,資料科學分析的三個最常見的開放原始碼方法的 R 語言,Python 語言結合 SciPy (「 科學 Python 」) 程式庫和整合語言和執行環境,例如 SciLab 和 Octave。

在本文中我會提供您 SciPy 以程式設計的快速教學以便完全它是什麼,決定您是否要花點時間學習它了。本文假設您已有使用 C# 或 Java 之類的類似一般用途程式設計語言的經驗,但不會假設您知道任何 Python 或 SciPy。

在我看來,學習新的程式設計語言或技術最困難的部分是剛開始,因此我將詳細說明如何執行 SciPy 程式所需的軟體安裝 (及解除安裝)。然後,我將說明幾種方式可以編輯和執行 SciPy 程式,並說明為什麼我比較喜歡使用整合式開發環境 (閒置) 程式。

最後我將帶您逐步完成使用 SciPy 解決為了示範的相似與相異 C# 程式設計系統的線性方程式的代表性程式。[圖 1 顯示示範程式的輸出,並讓您了解這篇文章向其中。

代表 SciPy 程式輸出
[圖 1 代表 SciPy 程式輸出

安裝 SciPy 堆疊

SciPy 堆疊有三個元件 ︰ Python、 NumPy 及 SciPy。Python 語言有基本的功能,例如迴圈控制結構和一般用途的清單資料型別,但有趣的是,沒有內建的陣列型別。NumPy 程式庫加入陣列和矩陣,加上一些相當簡單的功能,例如陣列搜尋和排序陣列的支援。SciPy 文件庫加入中級和進階函式,使用儲存在陣列和矩陣中的資料。

若要執行 SciPy 程式 (技術上的指令碼因為 Python 會解譯而不編譯),您安裝 Python,然後 NumPy、 SciPy。安裝並不太困難,您可以安裝軟體套件組合,其中包含三個元件。一個常見的組合是 Anaconda 分佈,在持續性分析由維護 continuum.io。然而,我將說明如何個別安裝元件。

幾乎所有的 Windows 版本都支援 Python。若要安裝 Python,請移至 python.org/downloads, ,您可以在其中找到安裝 Python 3.x 版本或 2.x 版本的選項 (請參閱 [圖 2)。兩個版本不是完全相容,但兩者都支援 NumPy 和 SciPy 文件庫。我建議安裝 2.x 版本,因為有 3.x 版目前尚不支援某些協力廠商函式。

安裝 Python
[圖 2 安裝 Python

當您按一下 [下載] 按鈕時,您會選擇立即執行.msi 安裝程式,或將它儲存以便稍後執行。您可以按一下 [執行] 按鈕。安裝程式會使用精靈。第一個畫面會詢問您是否要安裝的所有使用者] 或 [目前的使用者。預設值是所有使用者,因此都按一下 [下一步] 按鈕。

下一個畫面會要求您指定的根安裝目錄。預設為 C:\Python27 (而非更一般的 C:\Program Files 目錄),我建議您使用的預設位置,然後按 [下一步]。下列畫面可讓您包含或排除各種功能,例如文件、 公用程式工具像 pip (「 pip 安裝 Python 」)。預設的 Python 功能是正常的因此請按 [下一步] 按鈕。

開始進行安裝,您會看到熟悉的藍色進度列的視窗。安裝完成後,您會看到 [完成] 按鈕的視窗。按下按鈕。

根據預設,Python 安裝程序不會修改您電腦的 PATH 環境變數。您會想要將 C:\Python27 及 C:\Python27\Scripts C:\Python27\Lib\idlelib 新增至 PATH 變數,因此您可以從命令殼層執行 Python,並啟動閒置的編輯器,而不需要巡覽至目錄的位置。

您應該確認已正確安裝 Python。啟動命令殼層,並輸入 cd,即可巡覽至系統根目錄 \ 命令。現在輸入命令 python-版本 (請注意這兩個虛線字元)。如果 Python 回應,它已成功安裝。

安裝 NumPy 和 SciPy

就可以使用 Python pip 公用程式的原始程式碼中安裝 NumPy 和 SciPy 的封裝。Pip 方法適用於純 Python 程式碼,可封裝但 NumPy 和 SciPy 有勾點連結至已編譯的 C 語言程式碼,因此將它們安裝使用 pip 是相當麻煩。

所幸,Python 社群的成員建立先行編譯的二進位安裝程式安裝 NumPy 和 SciPy。我建議使用的項目會保留 SourceForge 儲存機制中。若要安裝 NumPy,請移至 bit.ly/1Q3mo4M, ,您會在其中看到各種版本的連結。我建議使用的最新的版本都有大部分的下載活動。

您會看到連結的清單。尋找具有類似 numpy-1.10.2-win32-時為止-python2.7.exe,名稱的連結中所示 [圖 3。請確定您的 Python 版本有對應的可執行檔,按一下該連結。短暫的延遲之後您會立即執行自動解壓縮可執行安裝程式的選項,或將它儲存到稍後再安裝。按一下 [執行] 按鈕。

安裝 NumPy
[圖 3 安裝 NumPy

NumPy 安裝程式會使用精靈。第一個畫面只會顯示簡介開頭顯示視窗。按一下 [下一步] 按鈕。下一個畫面會要求您指定安裝目錄。安裝程式會尋找現有的 Python 安裝,並建議您安裝 NumPy C:\Python27\Lib\site-packages 目錄中。接受此位置,然後按一下 [下一步]。

下一個畫面可讓您變更心意不想進行安裝,但不這樣做,最後。按一下 [下一步] 按鈕。您會看到進度視窗,在安裝期間,如果您仔細觀察,您會看到一些有趣的記錄訊息。NumPy 安裝完成後,您將會看到 [完成] 按鈕。按一下它。然後您會看到最後完成安裝程式視窗,與 [關閉] 按鈕。按一下它。

安裝 NumPy 之後下, 一個步驟是安裝 SciPy 封裝,這等同於安裝 NumPy。移至 bit.ly/1QbwJ0z 並尋找最近使用的目錄。移至該目錄並找到可執行檔的名稱,例如 scipy-0.16.1-win32-時為止-python2.7.exe 的連結,然後按一下連結以啟動自動解壓縮可執行安裝程式。

SciPy 堆疊的其中一項不錯的特性是非常容易解除安裝元件。您可以移至 Windows 控制台中、 程式和元件 (也就是 Python 或 NumPy 或 SciPy),以移除,然後按一下 [解除安裝] 按鈕和元件將會快速地完全移除的選取的功能。

編輯和執行 SciPy 程式

如果您撰寫程式使用.NET 語言,許多選項無法使用,您幾乎肯定使用 Visual Studio。但是,您撰寫 Python 程式時有許多選項。我建議使用閒置的編輯器和執行環境。

Idle.bat 程式啟動器檔位於預設 C:\Python27\Lib\idelib 目錄中。如果此目錄新增至系統路徑環境變數,您可以開啟命令殼層,並輸入閒置命令啟動閒置。在上半部所示,這會啟動閒置 Python 殼層程式 [圖 4

編輯和執行程式,使用閒置
[圖 4 編輯和執行程式,使用閒置

您可以建立新的 Python 來源的程式碼檔案在檔案上按一下 |在功能表列上的新檔案項目。這會開啟類似尋找個別編輯器] 視窗的下半部所示 [圖 4。在編輯器視窗中輸入這些七個陳述式 ︰

# test.py
import numpy as np
import scipy.misc as sm
arr = np.array([1.0, 3.0, 5.0])
print arr
n = sm.factorial(4)
print "4! = " + str(n)

然後將程式儲存為 test.py 便捷的目錄中。現在,您可以執行您的程式,即可在執行 |在編輯器視窗中,或按 F5 快速鍵,請執行模組的功能表項目。程式輸出會顯示在 [Python 殼層] 視窗中。簡單了 !

某些有經驗的 Python 開發人員需要在閒置 potshots,因為它是相當簡單。但是,這正是我喜歡的原因。沒附近的 Visual Studio 中,複雜的程式設計環境,但您撰寫了不正確的程式碼時不要取得語法標色和良好的錯誤訊息的產生器。

除了使用閒置編輯和執行程式,您可以使用任何文字編輯器] 中,包括 [記事本],寫入並儲存 Python 程式。然後您可以執行這個程式,從命令列如下 ︰

C:\IntroToPython> python test.py

這是假設您 python.exe 解譯器在系統 PATH 環境變數。輸出會顯示在命令殼層。

有許多的 Python Ide。一個常用開放原始碼 IDE,特別要搭配 SciPy 是科學 Python 開發環境 (Spyder) 程式。您可以找到資訊資訊,請參閱 pythonhosted.org/spyder

閒置和 Spyder 有趣的替代方式是開放原始碼 Python Tools for Visual Studio (PTVS) 外掛程式。正如其名,PTVS 可讓您編輯和執行使用 Visual Studio 的 Python 程式。您可以找到資訊在 PTVS microsoft.github.io/PTVS

SciPy 示範程式

看看的 Python 程式 [圖 5, ,或更棒的是,輸入或下載檔案到 Python 編輯器本文章,並執行程式。不能是一組完整的 SciPy 範例示範,但它所設計,讓您很好的感覺 SciPy 程式設計是類似。

[圖 5] 代表 SciPy 程式

# linear_systems.py
# Python 2.7
import numpy as np
import scipy.linalg as spla
def my_print(arr, cols, dec, nl):
  n = len(arr)
  fmt = "%." + str(dec) + "f" # like %.4f
  for i in xrange(n):  # alt: for x in arr
    if i > 0 and i % cols == 0:
      print ""
    print fmt % arr[i],
  if nl == True:
    print "\n"
def main():
  print "\nBegin linear system using SciPy demo \n"
  print "Goal is to solve the system: \n"
  print "3x0 + 4x1 - 8x2 = 9"
  print "2x0 - 5x1 + 6x2 = 7"
  print " x0 + 9x1 - 7x2 = 3"
  print ""
  A = np.matrix([[3.0, 4.0, -8.0],
                 [2.0, -5.0, 6.0],
                 [1.0, 9.0, -7.0]])
  b = np.array([9.0, 7.0, 3.0])      # b is an array
  b = np.reshape(b, (3,1))           # b is a col vector
  print "Matrix A is "
  print A
  print ""
  print "Array b is "
  my_print(b, b.size, 2, True)
  d = spla.det(A)
  if d == 0.0:
    print "Determinant of A is zero so no solution "
  else:
    Ai = spla.inv(A)
    print "Determinant of A is non-zero "
    print "Inverse of A is "
    print Ai
    print ""
  Aib = np.dot(Ai, b)
  print "A inverse times b is "
  print Aib
  print ""
  x = spla.solve(A, b)
  print "Using x = linalg.solve(A,b) gives x = "
  print x
  print ""
  try:
    A = np.array([[2.0, 4.0], [3.0, 6.0]])
    print "Matrix A is "
    print A
    print ""
    print "Inverse of A is "
    Ai = spla.inv(A)
    print Ai
  except Exception, e:
    print "Fatal error: " + str(e)
  print "\nEnd SciPy demo \n"
if __name__ == "__main__":
  main()

示範程式的兩個註解行開頭 ︰

# linear_systems.py
# Python 2.7

Python 2.x 及 3.x 版本並非完全相容,因為它不是個好主意,要使用的 Python 版本。接下來,示範載入整個 NumPy 模組和一個 SciPy 子模組 ︰

import numpy as np
import scipy.linalg as spla

您可以將像是從 Microsoft.NET Framework DLL 的參考加入 C# 程式,然後將組件帶入範圍內使用這些陳述式的陳述式。代表線性代數 linalg 子模組。SciPy 會組織成 16 主要子模組加上兩個公用程式的子模組。接下來,示範實作程式定義的函數,以顯示陣列 ︰

def my_print(arr, cols, dec, nl):
  n = len(arr)
  fmt = "%." + str(dec) + "f" # like %.4f
  for i in xrange(n):  # alt: for x in arr
    if i > 0 and i % cols == 0:
      print ""
    print fmt % arr[i],
  if nl == True:
    print "\n"

Python 使用縮排,而不是大括號字元來分隔程式碼區塊。在這裡,我使用兩個縮排的空格以節省空間;大部分的 Python 程式設計師用來縮排的四個空格。

函式 my_print 有四個參數 ︰ 若要顯示,以顯示的值,每個值的旗標,指出是否要列印一個新行的小數位數的資料行數目的陣列。Len 函數會傳回陣列的大小 (資料格數目)。另一個方法是使用陣列大小屬性 ︰

n = arr.size

Xrange 函式會傳回迭代器,且是標準的方式來周遊陣列。另一個方法是使用"中的 x arr 」 模式,這類似於 C# foreach 陳述式。

因為 Python 和 C# 有根目錄 C 語言中,大部分都 Python 語法是 C# 程式設計人員熟悉。在示範中,%是模數運算子,但它也可用於格式化浮點數的點值輸出;做為邏輯運算子而非 (& s) (& s)。= = 檢查是否相等。True 和 False (大寫) 都是布林值的常數。

接下來,示範建立程式定義的函數,名為 main 的開頭說明解決問題的某些列印陳述式 ︰

def main():
  print "\nBegin linear system using SciPy demo \n"
  print "Goal is to solve the system: \n"
  print "3x0 + 4x1 - 8x2 = 9"
  print "2x0 - 5x1 + 6x2 = 7"
  print " x0 + 9x1 - 7x2 = 3"

目標是要尋找的 x0 x1,x2 變數的值,以便滿足所有三個方程式。主要的名稱不能是 Python 關鍵字,因此它可以呼叫任何項目。您不需要有某種形式的 main 函式。簡短的程式 (程式碼通常不會超過一頁),我通常省卻 main 函式,並可執行陳述式開始。

接下來,範例程式設定問題的係數值放入名為 A,並將常數轉換成名為 b 的 NumPy 陣列 NumPy 3x3 矩陣

A = np.matrix([[3.0, 4.0, -8.0],
               [2.0, -5.0, 6.0],
               [1.0, 9.0, -7.0]])
b = np.array([9.0, 7.0, 3.0])

矩陣和陣列此處的函式實際上會接受以硬式編碼值 Python 清單 (以方括號表示) 做為其引數。您也可以建立矩陣和陣列使用 NumPy 零函式,以及您可以從文字檔讀取資料到矩陣或使用 loadtxt 函式的陣列。

如果您花了代數課程,您可能會請記住,解決方程式 Ax 系統 = x,其中 A 是正方形矩陣的係數和 b 是常數的資料行矩陣 (也就是 n 個資料列,但只有 1 個資料行),您必須尋找的矩陣反而反向然後矩陣相乘時間資料行的矩陣 b b。

此時在示範中,b 是具有三個資料格,而不是 3 x 1 矩陣的陣列。若要轉換矩陣 b,示範程式會使用重塑函式 ︰

b = np.reshape(b, (3,1))

NumPy 程式庫有許多功能,可以管理陣列和矩陣。例如,壓平合併函式會將矩陣轉換成陣列。現在,其實,SciPy 矩陣乘法函式很聰明,推斷預期如果將 matrix 乘以和陣列因此這裡不真的有必要重繪的呼叫。

接下來,示範程式會顯示值在矩陣中,A 和 b:

print "Matrix A is "
print A
print ""
print "Array b is "
my_print(b, b.size, 2, True)

在 Python 2.x,列印是陳述式,而不是函式,因為它是以 Python 3.x 中,因此括號是選擇性。程式定義 my_print 函式不會傳回值,並且讓它相當於 void 的 C# 函式稱為跟您預期的一樣。Python 支援具名參數呼叫,因此可能已被呼叫 ︰

my_print(arr=b, cols=3, dec=2, nl=True)

接下來,範例程式會尋找的反矩陣 a:

d = spla.det(A)
if d == 0.0:
  print "Determinant of A is zero so no solution "
else:
  Ai = spla.inv(A)
  print "Determinant of A is non-zero "
  print "Inverse of A is "
  print Ai

SciPy det 函式傳回的正方形矩陣的行列式。如果系統的線性方程式的係數的矩陣的行列式等於零,就無法反轉的矩陣。Python if-else 陳述式看起來應該很熟悉。Python 會有簡潔"elif 」 關鍵字 if else if 控制結構,例如 ︰

if n < 0:
  print "n is negative"
elif n == 0:
  print "n equals zero"
else:
  print "n is positive"

接下來,示範解決方程式使用矩陣相乘透過 NumPy 點函式的系統 ︰

Aib = np.dot(Ai, b)
print "A inverse times b is "
print Aib

因此命名為點函式,因為矩陣相乘是一種所謂的內積。

接下來,範例程式可直接解決方程式的系統,請使用 NumPy 解決函式 ︰

x = spla.solve(A, b)
print "Using x = linalg.solve(A,b) gives x = "
print x

許多 SciPy 和 NumPy 函式有具有預設值的選擇性參數,這有點相當於 C# 方法多載。SciPy 解決函式有五個選擇性參數。重點是當您看到 SciPy 或 NumPy 範例函式呼叫,即使您認為您了解範例,是個不錯的主意,看看文件,查看是否有任何有用的選擇性參數。

會有一些 NumPy 和 SciPy 的程式庫之間的重疊。例如,NumPy 套件也會有 linalg 子模組具有求解函式。不過,NumPy 解決函式沒有選擇性參數。

接下來,範例程式示範 Python try-除了機制 ︰

try:
  A = np.array([[2.0, 4.0], [3.0, 6.0]])
  Ai = spla.inv(A)
  print Ai
except Exception, e:
  print "Fatal error: " + str(e)

如果您曾經使用過 C# try-catch 陳述式看起來很熟悉這種模式。在 C# 中,當您串連字串,您可以進行隱含。例如,在 C# 中您可以撰寫 ︰

int n = 99;
Console.WriteLine("The value of n is " + n);

但是,當您串連 Python 中的字串,就必須明確使用 str 函式的轉換 ︰

n = 99
print "The value of n is " + str(n)

示範程式將使用 print 陳述式和特殊的 Python incantation 結束 ︰

print "\nEnd SciPy demo \n"
if __name__ == "__main__":
  main()

示範程式的最後一個陳述式有可能只是 main (),它會被解譯為呼叫程式定義的函式主要的指示,並執行程式,沒問題。加入 if __name__ = ="__main__"模式 (請注意,有兩個底線字元之前和之後名稱 」 和 「 主要) 」 會建立目前的模組做為程式進入點。Python 程式開始執行時,解譯器在內部標籤做為初始的模組 ︰

"__main__"

因此,假設您有某些其他程式定義模組的可執行陳述式,而您匯入。如果檢查沒有 Python 解譯器會查看在匯入的模組中的可執行陳述式,並加以執行。如果將此方式稍有不同,如果檢查加入您的程式定義的 Python 檔案,這些檔案可匯入其他的 Python 程式,才不會造成問題。

因此,是要幹嘛?

您對本文的反應也可能相當類似,「 嗯,這是所有有點有趣,但我日常工作中我真的不需要解決的線性方程式,或使用難以理解的數學函式。 」 為我的回應,「 嗯,沒錯,但其中一個原因而不使用一些 SciPy 程式庫的功能可能是您不知道您可以解決哪些類型的問題 」。

換句話說,在我看來,開發人員傾向於處理他們擁有這些工具的問題。例如,如果您知道 Windows Communication Foundation (WCF),則您會使用 WCF (和具有我表達贊同)。如果您將 SciPy 加入您的個人技能組合,您可能會發現有的資料可以轉換成有用的資訊。


Dr。James McCaffreyRedmond,華盛頓中的 Microsoft Research 的運作方式他曾在包括 Internet Explorer 和 Bing 的數個 Microsoft 產品。Dr.McCaffrey 可以到達 jammc@microsoft.com

感謝以下的微軟技術專家對本文的審閱: Dan Liebling 和 Kirk Olynyk