天天看點

放棄“for循環”,教你用這種算法 !(附代碼)

在11月27日至12月3日的KDnugget網站上,這篇文章被轉載最多(https://www.kdnuggets.com/2017/12/top-news-week-1127-1203.html)。

我們使用for循環來完成大部分工作,這些工作需要對一長串的元素進行更新。我敢斷言,幾乎所有人閱讀這篇文章的讀者,在他們高中或大學裡都裡有肯定有使用過for循環語句編寫自己的第一個矩陣或矢量乘法代碼。for循環為程式設計社群提供了長期穩定的服務。

然而,for循環在處理大型資料集時執行速度通常較慢(例如:在大資料時代處理幾百萬條記錄)。對于像Python這樣的解釋性語言來說尤其如此。如果您的循環體很簡單,那麼循環解釋器會占用大量的開銷。

幸運的是,大部分主流的程式設計語言都有另外一種程式設計語言可以取代它。Python也是如此。

Numpy是Numerical Python(http://numpy.org/)的簡稱,同時也是Python生态系統中高性能科學計算和資料分析所需要的基本包。它幾乎是所有進階語言工具的基礎,如Pandas和 scikit-learn都是在Numpy的基礎上編譯的。TensorFlow使用NumPy陣列作為底層編譯塊。在這之上建構了Tensor對象和用于深度學習的graphflow(使用了大量的線性代數運算在一個長的清單/矢量/矩陣)。

Numpy提供的兩個最重要的特性是:

Ndarray:一個快速空間高效的多元數組,提供了矢量化計算操作和複雜的廣播能力(https://towardsdatascience.com/two-cool-features-of-python-numpy-mutating-by-slicing-and-broadcasting-3b0b86e8b4c7)

标準的數學函數,可以在不寫循環的情況下,對整個資料數組進行快速操作。

在資料科學、機器學習和Python社群中,您經常會遇到這樣的斷言:Numpy是更速度的。因為它是基于矢量的實作,而且它的許多核心例程都是用C語言編寫(基于CPython 架構:https://en.wikipedia.org/wiki/CPython)。

這篇文章是一個CPython 架構的很好闡述(http://notes-on-cython.readthedocs.io/en/latest/std_dev.html)Numpy可以與各個方面協同工作。甚至可以使用Numpy api編寫裸機骨C例程。Numpy陣列是均勻類型的密集陣列。相反,Python清單是指向對象的指針數組,即使它們是相同的對象類型。你可以從區域性關聯(https://en.wikipedia.org/wiki/Locality_of_reference)得到收獲。

許多Numpy操作是用C語言實作的,避免了Python中循環的開銷、指針指向每個元素的動态類型檢查(https://www.sitepoint.com/typing-versus-dynamic-typing/)。Numpy速度的提升取決于你所執行的操作。對于資料科學和現代機器學習來說,這是一個非常寶貴的優勢,因為通常資料集的大小會達到數百萬甚至數十億。并且您不希望使用For循環和它的相關的算法進行更新。

如何用一個中等大小的資料集來驗證它呢?

這裡是Jupyter Github代碼連結(https://github.com/tirthajyoti/PythonMachineLearning/blob/master/How%20fast%20are%20NumPy%20ops.ipynb)。其中在一些簡單的代碼行中,Numpy的操作速度與正常Python程式設計的速度不同,比如for循環、map-function(https://stackoverflow.com/questions/10973766/understanding-the-map-function)或list-comprehension(http://www.pythonforbeginners.com/basics/list-comprehensions-in-python)。

這裡我簡單的概括下基本流程:

建立一個中等數量集的浮點數清單,最好是從連續的統計分布中抽取出來,比如高斯分布或均勻随機分布。為了示範我選擇了100萬條資料

在清單中建立一個ndarray對象,也就是矢量化

編寫簡短的代碼塊來更新清單,并在清單上使用數學運算,比如以10為底的對數。使用for循環、map-function和list-comprehension。并使用time()函數來核實處理100萬條資料需要花費多長時間

用Numpy的内置數學方法(np.log10)在ndarray對象上做同樣的操作。計算出花費了多長時間

在一個清單中存儲執行時間,并繪制出一個差異的柱狀圖

下面是結果顯示。你可以運作Jupyter筆記本上的所有代碼單元塊來重複整個過程。每次它會生成一組新的随機數,是以精準的執行時間可能會有所不同。但總體來說,趨勢始終是相同的。您可以嘗試使用各種其他的數學函數/字元串操作或者集合,來檢查是否适用于一般情況。

這裡有一個由法國神經科學研究員編寫的完整開源線上書籍(https://www.labri.fr/perso/nrougier/from-python-to-numpy/#id7)。

放棄“for循環”,教你用這種算法 !(附代碼)

簡單數學運算比較速度的柱狀圖

如果你有任何問題或想法要分享,請與作者聯系([email protected])。您也可以在Python、R或MATLAB和機器學習資源中檢視作者的GitHub庫(https://github.com/tirthajyoti),獲得其他有趣的代碼片段。你也可以在LinkedIn(https://www.linkedin.com/in/tirthajyoti-sarkar-2127aa7/)上關注我。

原文釋出時間為:2017-12-21

本文作者:資料派