當前位置:
首頁 > 最新 > 機器學習如何從 Python 2 遷移到 Python 3

機器學習如何從 Python 2 遷移到 Python 3

關鍵時刻,第一時間送達!

本文經授權轉自人工智慧頭條。

Python 已經成為機器學習及其他科學領域中的主流語言。它不但與多種深度學習框架兼容,而且還包含優秀的工具包和依賴庫,方便我們對數據進行預處理和可視化操作。

據最新消息,到 2019 年底,Numpy 等很多科學計算工具包都將停止支持 Python 2版本,而 2018 年後 Numpy 的所有新功能版本也都將只支持 Python 3。

為了使初學者能夠輕鬆地從 Python 2 向 Python 3 實現遷移,我收集了一些 Python 3 的功能,希望對大家有所幫助。

使用 pathlib 模塊來更好地處理路徑

在 Python 2 中,我們需要通過級聯字元串的形成來實現路徑的拼接。而現在有了 pathlib 模塊後,數據路徑處理將變得更加安全、準確,可讀性更強。

此外,pathlib.Path 含有大量的方法,這樣 Python 的初學者將不再需要搜索每個方法:

使用 pathlib 還將大大節約你的時間。更多功能請查看:

官方文檔https://docs.python.org/3/library/pathlib.html

參考信息https://pymotw.com/3/pathlib/

類型提示(Type hinting)成為 Python3 中的新成員

下面是在編譯器 PyCharm 中,類型提示功能的一個示例:

Python 不只是一門腳本的語言,如今的數據流程還包括大量的邏輯步驟,每一步都包括不同的框架(有時也包括不同的邏輯)。

Python 3 中引入了類型提示工具包來處理複雜的大型項目,使機器可以更好地對代碼進行驗證。而在這之前,不同的模塊需要使用自定義的方式,對文檔中的字元串指定類型 (注意:PyCharm 可以將舊的文檔字元串轉換成新的類型提示)。

下面是一個簡單的代碼示例,利用類型提示功能來處理不同類型的數據:

上述代碼對多維的 numpy.array、astropy.Table 和 astropy.Column、bcolz、cupy、mxnet.ndarray 等操作同樣適用。

這段代碼還可用於 pandas.Series 操作,但是這種形式是錯誤的:

這僅僅是一段兩行的代碼。所以,複雜系統的行為是非常難預測的,有時一個函數就可能導致整個系統的錯誤。因此,明確地了解哪些類型方法,並在這些類型方法未得到相應參數的時候發出錯誤提示,這對於大型系統的運作是很有幫助的。

如果你有一個很棒的代碼庫,諸如 MyPy 這樣的類型提示工具將可能成為一個大型項目的集成流程中的一部分。不幸的是,類型提示功能還沒辦法強大到為 ndarrays/tensors 這種細粒度類型發出提示。或許,不久的將來我們就可以擁有這樣全面的的類型提示工具,這將成為數據科學領域需要的強大功能。

從類型提示(運行前)到類型檢查(運行時)

默認情況下,函數的注釋對於代碼的運行是沒有影響的,它只是幫你指出每段代碼所要做的工作。

在代碼運行階段,很多時候類型提示工具是不起作用的。這種情況你可以使用 enforce 等工具,強制性對代碼進行類型檢查,同時也可以幫助你調試代碼。

函數注釋的其他用途

正如上面我們提到的,函數的注釋部分不僅不會影響代碼的執行,還會提供可以隨時使用的一些元信息(meta-information)。

例如,計量單位是科學界的一個普遍難題,Python 3 中的 astropy 包提供了一個簡單的裝飾器(Decorator)來控制輸入的計量單位,並將輸出轉換成相應的單位。

如果你需要用 Python 處理表格類型的科學數據,你可以嘗試 astropy 包,體驗一下計量單位隨意轉換的方便性。你還可以針對某個應用專門定義一個裝飾器,用同樣的方式來控制或轉換輸入和輸出的計量單位。

通過 @ 實現矩陣乘法

下面,我們實現一個最簡單的機器學習模型,即帶 L2 正則化的線性回歸 (如嶺回歸模型),來對比 Python2 和 Python3 之間的差別:

在 Python3 中,以@作為矩陣乘法符號使得代碼整體的可讀性更強,且更容易在不同的深度學習框架間進行轉譯:因為一些代碼如 X @ W + b[None, :] 在 numpy、cupy、pytorch 和 tensorflow 等不同庫中都表示單層感知機。

使用 ** 作為通配符

Python2 中使用遞歸文件夾的通配符並不是很方便,因此可以通過定製的 glob2 模塊來解決這個問題。遞歸 flag 在 Python 3.6 中得到了支持。

Python3 中更好的選擇是使用 pathlib:(缺少個import)

Python3 中的 print 函數

誠然,print 在 Python3 中是一個函數,使用 print 需要加上圓括弧(),雖然這是個麻煩的操作,但它還是具有一些優點:

使用文件描述符的簡單句法:

在不使用 str.join 情況下能夠輸出 tab-aligned 表格:

修改與重新定義 print 函數的輸出:

在 Jupyter notebook 中,這種形式能夠記錄每一個獨立的文檔輸出,並在出現錯誤的時候追蹤到報錯的文檔。這能方便我們快速定位並解決錯誤信息。因此我們可以重寫 print 函數。

在下面的代碼中,我們可以使用上下文管理器來重寫 print 函數的行為:

但是,重寫 print 函數的行為,我們並不推薦,因為它會引起系統的不穩定。print 函數可以結合列表生成器或其它語言結構一起使用:

f-strings 可作為簡單和可靠的格式化

默認的格式化系統提供了一些靈活性操作。但在數據實驗中這些操作不僅不是必須的,還會導致代碼的修改變得冗長和瑣碎。

而數據科學通常需要以固定的格式,迭代地列印出一些日誌信息,所使用的代碼如下:

樣本輸出為:

Python 3.6 中引入了格式化字元串 (f-strings):

另外,這對於查詢語句的書寫也是非常方便的:

「true division」和「integer division」之間的明顯區別

雖然說對於系統編程來說,Python 3 所提供的改進還遠遠不夠,但這些便利對於數據科學來說已經足夠。

Python 2 中的結果依賴於『時間』和『距離』(例如,以米和秒為單位),關注其是否被保存為整數。

而在 Python 3 中,結果的表示都是精確的,因為除法運算得到的都是精確的浮點數。

另一個例子是整數除法,現在已經作為明確的運算:

值得注意的是,整除運算可以應用到 Python 的內建類型和由 numpy、pandas 等數據包提供的自定義類型。

嚴格排序

下面是一個嚴格排序的例子:

嚴格排序的主要功能有:

防止不同類型實例之間的偶然性排序。

在處理原始數據時幫助我們發現存在的問題。此外,嚴格排序對 None 值的合適性檢查是(這對於兩個版本的 Python 都適用):

自然語言處理中的Unicode編碼

下面來看一個自然語言處理任務:

比較兩個版本 Python 的輸出:

Python2: 6
??

Python3: 2
您好

再來看個例子:

在這裡,Python 2 會報錯,而 Python 3 能夠正常工作。因為我在字元串中使用了俄文字母,對於 Python 2 是無法識別或編碼這樣的字元。

Python 3 中的 strs 是 Unicode 字元串,這對非英語文本的自然語言處理任務來說將更加地方便。還有些其它有趣的應用,例如:

Python 2: Counter({"xc3": 2, "b": 1, "e": 1, "c": 1, "k": 1, "M": 1, "l": 1, "s": 1, "t": 1, "xb6": 1, "xbc": 1})

Python 3: Counter({"M": 1, "?": 1, "b": 1, "e": 1, "l": 1, "s": 1, "t": 1, "ü": 1, "c": 1, "k": 1})

對於這些,Python 2 也能正常地工作,但 Python 3 的支持更為友好。

保留詞典和**kwargs 的順序

CPython 3.6+ 的版本中字典的默認行為是一種類似 OrderedDict 的類,但最新的 Python3.7 版本,此類已經得到了全面的支持。這就要求在字典理解、json 序列化/反序列化等操作中保持字典原先的順序。

下面來看個例子:

這種保順性同樣適用於 Python3.6 版本中的 **kwargs:它們的順序就像參數中顯示的那樣。當設計數據流程時,參數的順序至關重要。

以前,我們必須以這樣繁瑣的方式來編寫:

注意到了嗎?名稱的唯一性也會被自動檢查。

迭代拆封

Python 3 中引入迭代式拆封功能,下面來看一段代碼:

默認的 pickle 引擎為數組提供更好的壓縮

Python 3 中引入 pickle 引擎,為數組提供更好的壓縮,節省參數空間:

這個小的改進節省了 3 倍的空間,而且運行階段速度更快。實際上,如果不關心速度的話,類似的壓縮性能也可以通過設置參數 protocol=2 來實現,但是用戶經常會忽略這個選項或者根本不了解這個功能。

更安全的解析功能

Python 3 能為代碼提供更安全的解析,提高代碼的可讀性。具體如下段代碼所示:

關於 super(),simply super()

Python 2 中的 super() 方法,是常見的錯誤代碼。我們來看這段代碼:

有關 super() 方法及方法解析順序的更多內容,參見 stackoverflow:

https://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods

更好的 IDE 會給出變數注釋

編程過程中使用一個好的 IDE,能夠給初學者一種更好的編程體驗。一個好的 IDE 能夠給不同的編程語言如 Java、C# 等,提供友好的編程環境及非常有用的編程建議,因為在執行代碼之前,所有標識符的類型都是已知的。

對於 Python,雖然這些 IDE 的功能是很難實現,但是代碼的注釋能夠在編程過程幫助到我們:

以清晰的形式提示你下一步想要做的;

從 IDE 獲取良好的建議。

這是 PyCharm IDE 的一個示例。雖然例子中所使用的函數不帶注釋,但是這些帶注釋的變數,利用代碼的後向兼容性,也能保證程序的正常工作。

多種拆封(unpacking)

下面是 Python 3 中字典融合的代碼示例:

如果你想對比兩個版本之間的差異性,可以參考以下這個鏈接來了解更多的信息:https://stackoverflow.com/questions/38987/how-to-merge-two-dictionaries-in-a-single-expression

aame 方法對於 Python 中的列表(list)、元組(tuple)和集合(set)等類型都是有效的,通過下面這段代碼我們能夠更清楚地了解它們的工作原理,其中 a、b、c 是任意的可迭代對象:

此外,函數同樣支持 *args 和 **kwargs 的 unpacking 過程:

不會過時的技術—只帶關鍵字參數的 API

我們來看這段代碼:

顯而易見,這段代碼的作者還不熟悉 Python 的代碼風格,很可能剛從 C++ 或 rust語言轉 Python。代碼風格不僅是個人偏好的問題,還因為在 SVC 介面中改變參數順序(adding/deleting)會使代碼無效。特別是對於 sklearn,經常要通過重新排序或重命名大量的演算法參數以提供一致的 API。而每次的重構都可能使代碼失效。

在 Python 3 中依賴庫的編寫者通常會需要使用*以明確地命名參數:

使用時,用戶需要明確規定 sklearn.svm.SVC(C=2, kernel="poly", degree=2, gamma=4, coef0=0.5) 中參數的命名。

這種參數命名機制使得 API 同時兼具可靠性和靈活性。

微調:math模塊中的常量

Python 3 中 math 模塊的改動,可以查看下面這段代碼:

微調:單精度整數類型

Python 2 中提供了兩種基本的整數類型,即 int(64 位符號整數)和用於長整型數值計算的 long 類型(長整型)。而在 Python 3 中對單精度的整型數據有個微小的改動,使其包含長整型(long) 的運算。下面這段代碼教你如何查看整型值:

其他改動

Enums 的改動具有理論價值,是因為字元串輸入已廣泛應用在 python 數據棧中。Enums 雖然不與 numpy 庫交互,但是在 pandas 中有良好的兼容性。

協同程序將很有可能用於數據流程的處理,雖然目前還沒有大規模應用的出現。

Python 3 有穩定的 ABI。

Python 3 支持 unicode 編碼格式,如 ω = Δφ / Δt 也是可以允許的,但最好使用兼容性更好的舊 ASCII 名稱。

一些庫比如 jupyterhub(jupyter in cloud)、django 和新版 ipython 都只支持 Python 3,因此這些用處不大的庫對你來講,可能只會偶爾使用一次。

數據科學中代碼遷移所會碰到的問題及解決方案

放棄對嵌套參數的支持:

然而,它依然能夠完美地適用於不同的理解:

通常,理解在 Python 2 和 3 之間差異能夠幫助我們更好地『轉義』代碼。

map(), .keys(), .values(), .items() 等等,返回的是迭代器而不是列表。迭代器的主要問題包括:沒有瑣碎的分割,以及無法進行二次迭代。將返回的結果轉化為列表幾乎可以解決所有問題。

如遇到其他問題請參見這篇有關 Python 的問答:「如何將 Python3 移植到我的程序中?」(https://eev.ee/blog/2016/07/31/python-faq-how-do-i-port-to-python-3/)

Python 機器學習和 python 數據科學領域所會碰到的主要問題

這些課程的作者首先要花點時間解釋 python 中什麼是迭代器,為什麼它不能像字元串那樣被分片/級聯/相乘/二次迭代(以及如何處理它)。

我相信大多數課程的作者都很希望能夠避開這些繁瑣的細節,但是現在看來這幾乎是個不可避免的話題。

結論

Python 的兩個版本( Python 2 與 Python 3 )共存了近 10 年的時間。時至今日,我們不得不說:是時候該轉向 Python 3 了。

科學研究和實際生產中,代碼應該更短,可讀性更強,並且在遷移到 Python 3 後的代碼庫將更加得安全。

目前 Python 的大多數庫仍同時支持 2.x 和 3.x 兩個版本。但我們不應等到這些依賴庫開始停止支持 Python 2 才開始轉向 Python 3,我們現在就可以享受新語言的功能。

遷移到 Python 3 後,我敢保證你的程序運行會更加順暢:「我們不會再做向後不兼容的事情了(https://snarky.ca/why-python-3-exists/)」。

參考內容:

Key differences between Python 2.7 and Python 3.x

http://sebastianraschka.com/Articles/2014_python_2_3_key_diff.html

Python FAQ: How do I port to Python 3?

https://eev.ee/blog/2016/07/31/python-faq-how-do-i-port-to-python-3/

10 awesome features of Python that you can"t use because you refuse to upgrade to Python 3

http://www.asmeurer.com/python3-presentation/slides.html

Trust me, python 3.3 is better than 2.7 (video)

http://pyvideo.org/pycon-us-2013/python-33-trust-me-its-better-than-27.html

Python 3 for scientists

http://python-3-for-scientists.readthedocs.io/en/latest/

https://github.com/arogozhnikov/python3_with_pleasure#future-proof-apis-with-keyword-only-arguments

編譯:林椿眄

編輯:Donna


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 機器學習 的精彩文章:

機器學習如何從Python 2遷移到Python 3
沒有什麼是機器學習解決不了的,如果有,那就區塊鏈

TAG:機器學習 |