numpy:python數據領域的功臣

前言

numpy對python的意義非凡,在數據分析與機器學習領域爲python立下了汗馬功勞。如今用python搞數據分析或機器學習常用的pandas、matplotlib、sklearn等庫,都須要基於numpy構建。絕不誇張地說,沒有numpy,python今天在數據分析與機器學習領域只能是捉襟見肘。javascript

什麼是一門好的數據分析語言

數據分析面向的數據大多數是二維表。一門好的數據分析語言,首先須要可以直接有個數據結構存下這個二維表,而後要配上一套成熟的類SQL的數據操做接口,最後要有一套好用的可視化工具。R語言就是一個極好的典範:用內置的data.frame結構作數據的存儲;data.frame自己提供足夠強大的數據操做能力,另有dplyr、tidyr、data.table、plyr、reshape2等庫提供更好用更高效的數據操做能力;在繪圖上,除了基本的plot功能外,還提供了ggplot2這樣一套優雅的繪圖語言,還經過htmlwidget庫與javascript各類繪圖庫創建了緊密的聯繫,讓可視化的動態展現效果更進一步。Excel也是一個極好的例子,有單元格這種靈活的結構爲數據存儲作支撐,有大量的函數實現靈活的操做,也有強大的繪圖系統。html

python目前在數據分析領域也已經具有了至關可觀的能力,包括pandas庫實現的DataFrame結構,pandas自己提供的數據操做能力,matplotlib提供的數據可視化能力,而這一切都離不開numpy庫。java

什麼是一門好的機器學習語言

通常來說,一門好的機器學習語言在數據分析上也必定很吃得開,由於數據分析每每是機器學習的基礎。可是機器學習的要求更高,由於在模型訓練階段每每須要較爲複雜的參數估計運算,所以語言須要具有較強的科學計算能力。科學計算能力,最核心的就是矩陣運算能力。關於矩陣運算能力,這篇文章對各類語言有很好的比較。python

若是沒有numpy,python內部只能用list或array來表示矩陣。假如用list來表示[1,2,3],因爲list的元素能夠是任何對象,所以list中所保存的是對象的指針,因此須要有3個指針和三個整數對象,比較浪費內存和CPU計算時間。python的array和list不一樣,它直接保存數值,和C語言的一維數組比較相似,可是不支持多維,表達形式很簡陋,寫科學計算的算法很難受。numpy彌補了這些不足,其提供的ndarray是存儲單一數據類型的多維數組,且採用預編譯好的C語言代碼,性能上的表現也十分不錯。算法

python最流行的機器學習庫sklearn構建在numpy之上,提供了各類標準機器學習模型的訓練與預測接口,其中模型訓練接口的內部實現是基於numpy庫實現的。好比很常見的線性迴歸模型,參數估計調用的是numpy.linalg.lstsq函數。編程

numpy的核心結構:ndarray

如下內容摘錄自用Python作科學計算segmentfault

a = np.array([[0,1,2],[3,4,5],[6,7,8]], dtype=np.float32)

ndarray是numpy的核心數據結構。咱們來看一下ndarray如何在內存中儲存的:關於數組的描述信息保存在一個數據結構中,這個結構引用兩個對象,一塊用於保存數據的存儲區域和一個用於描述元素類型的dtype對象。數組

clipboard.png

數據存儲區域保存着數組中全部元素的二進制數據,dtype對象則知道如何將元素的二進制數據轉換爲可用的值。數組的維數、大小等信息都保存在ndarray數組對象的數據結構中。數據結構

strides中保存的是當每一個軸的下標增長1時,數據存儲區中的指針所增長的字節數。例如圖中的strides爲12,4,即第0軸的下標增長1時,數據的地址增長12個字節:即a[1,0]的地址比a[0,0]的地址要高12個字節,正好是3個單精度浮點數的總字節數;第1軸下標增長1時,數據的地址增長4個字節,正好是單精度浮點數的字節數。機器學習

如下內容總結自Numpy官方文檔Numpy basics

關於ndarray的索引方式,有如下幾個重點須要記住:

  • 雖然x[0,2] = x0,可是前者效率比後者高,由於後者在應用第一個索引後須要先建立一個temporary array,而後再應用第二個索引,最後找到目標值。

  • 分片操做不會引起copy操做,而是建立原ndarray的view;他們所指向的內存是同一片區域,不管是修改原ndarray仍是修改view,都會同時改變兩者的值。

  • index array和boolean index返回的是copy,不是view。

關於上面列舉的分片操做不會引起copy操做,咱們來進一步探討一下。先看一下numpy的例子:

clipboard.png

再來看一下R的例子:

clipboard.png

能夠看到numpy和R在矩陣的分片操做有不一樣的設計理念:在R裏分片操做會引發數據的複製,在numpy裏不會。事實上,R的設計理念不少時候能夠用一句話來歸納:copy on modify,一旦對數據有修改就會引發內存上的複製操做,這個操做要花很多時間,所以常常會聽到人們抱怨R費內存且速度慢。因此,咱們能夠看到numpy在處理這件事情上明顯要用心不少,根據場景設計了不一樣的策略,不是簡單地採用R的一刀切方式。固然,這也帶來了一些學習成本,須要對numpy足夠熟悉才能避免踩坑。R社區裏對copy on modify的哲學也有詬病並在努力改變,好比同是data.frame操做庫的data.table和dplyr,data.table性能比dplyr高不少,部分緣由也是data.table規避了copy on modify的方式。

Structured Array

根據numpy的官方文檔,定義結構化數組有四種方式。本文采用字典方法,經過定義一個dtype對象實現,須要指定的鍵值有names和formats。

persontype = np.dtype({
        'names': ['name', 'age', 'weight'], 
        'formats': ['S32', 'i', 'f']
    })
a = np.array([("Zhang", 32, 75.5), ("Wang", 24, 65.2)], dtype=persontype)

咱們用IPython的計時函數看一下提取數據的效率:

%timeit a[1]
%timeit a['name']
%timeit a[1]['name']
%timeit a['name'][1]

輸出結果以下:

The slowest run took 46.83 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 153 ns per loop
The slowest run took 34.34 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 3: 174 ns per loop
The slowest run took 13.00 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.08 µs per loop
The slowest run took 9.84 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 412 ns per loop

從上面的結果,咱們發現,獲取相同的數據有多種操做,不一樣的操做性能差異很大。我作了一個推測,純粹是瞎猜:numpy在創建結構化數組時,將整個結構體連續存儲在一塊兒,即按行存儲,所以a[1]的速度最快;可是爲了保證提取列的效率,對a['name']創建了索引,所以a['name']的效率也很高;可是這個索引只對整個a起做用,若是輸入只有a的一部分,仍然須要遍歷整個a,去提取出對應的數據,所以a[1]['name']a['name'][1]的效率差不少。

關於做者:丹追兵:數據分析師一枚,編程語言python和R,使用Spark、Hadoop、Storm、ODPS。本文出自丹追兵的pytrafficR專欄,轉載請註明做者與出處:https://segmentfault.com/blog...

相關文章
相關標籤/搜索