
CDA數據分析師 出品
相信大家在做一些算法經常會被龐大的數據量所造成的超多計算量需要的時間而折磨的痛苦不已,接下來我們圍繞四個方法來幫助大家加快一下Python的計算時間,減少大家在算法上的等待時間。今天給大家介紹Numba這一塊的內容。
所以什么是Numba呢?Numba是Python的即時編譯器,也就是說當你調用Python
函數時,你的全部或部分代碼都會被計時轉換成為機器碼進行執行,然后它就會以你的本機機器碼速度運行,Numba由Anaconda公司贊助,并得到了許多組織的支持。
使用Numba,你可以加速所有以集中計算的、計算量大的python函數(例如循環)的速度。它還支持numpy庫!因此,你也可以在計算中使用numpy,并加快整體計算的速度,因為python中的循環非常慢。你還可以使用python標準庫中的數學庫的許多功能,例如sqrt等。
所以,為什么要選擇Numba?特別是當存在有許多其他編譯器,例如cython或任何其他類似的編譯器,或類似pypy的東西時。
選擇Numba的理由很簡單,那就是因為你不需要離開使用Python編寫代碼的舒適區。是的,你沒看錯,你不需要為了加速數據的運行速度而改變你的代碼,這與從具有類型定義的相似cython代碼獲得的加速相當。那不是更好么?
你只需要在函數周圍添加一個熟悉的Python功能,也就是裝飾器(包裝器)。目前類的裝飾器也在開發之中。
所以,你只需要添加一個裝飾器就可以了。例如:
from numba import jit@jitdef function(x): # 循環或數值密集型的計算 return x
它看起來仍然像是純python代碼,不是嗎?
Numb使用LLVM編譯器基礎結構,從純Python代碼生成優化的機器碼。使用Numba的代碼運行速度與C,C ++或Fortran中的類似代碼相媲美。
這是代碼的編譯方式:
首先,獲取,優化Python函數并將其轉換為Numba的中間表示形式,然后類似于Numpy的類型推斷一樣進行類型判斷(因此python float為float64),然后將其轉換為LLVM可解釋的代碼。然后,該代碼被饋送到LLVM的即時編譯器以發出機器代碼。
你可以根據需要在運行時生成代碼或在CPU(默認)或GPU上導入代碼。
小菜一碟!
為了獲得最佳的性能,numba建議在你的jit包裝器中使用參數nopython = True,但它根本不會使用Python解釋器?;蛘吣阋部梢允褂聾njit。如果你使用nopython = True的包裝器失敗并出現錯誤,則可以使用簡單的@jit包裝器,該包裝器將編譯部分代碼,對其進行循環,然后將其轉換為函數,再編譯為機器碼,然后將其余部分交給python解釋器。
因此,你只需要執行以下操作:
from numba import njit, jit@njit # 或者@jit(nopython=True)def function(a, b): # 循環或數值密集型計算 return result
使用@jit時,請確保你的代碼具有Numba可以編譯的內容,例如計算密集型循環,使用它支持的庫(Numpy)及其支持的函數。否則,它將無法編譯任何內容。
首先,numba在首次用作機器代碼后還會緩存這些函數。因此,在第一次使用之后,它會變得更快,因為你無需再次編譯該代碼,因為你使用的參數類型和你之前使用的相同。
而且,如果你的代碼是可以并行化運行的,那么也可以將parallel = True作為參數傳遞,但是必須跟參數nopython = True結合使用。目前,它僅可以在CPU上工作。
你也可以指定你想要的函數簽名,但是它不會編譯你給他的任何其他類型的參數,比如:
你還可以指定你希望函數具有的函數簽名,但是對于提供給它的任何其他類型的參數,它將不會編譯。例如:
from numba import jit, int32@jit(int32(int32, int32))def function(a, b): #循環或數值型密集型計算 return result#或者你還沒有導入類型的名稱#你可以將他們作為字符串傳遞@jit('int32(int32, int32)')def function(a, b): #循環或數值型密集型計算 return result
現在,你的函數將只接受兩個int32并返回一個int32。這樣,你可以更好地控制自己的函數。你甚至可以根據需要傳遞多個)函數簽名。
你還可以使用numba提供的其他裝飾器:
1. @vectorize:允許將標量參數用作numpy ufunc,
1. @guvectorize:產生NumPy廣義ufuncs
1. @stencil:將函數聲明為類似模板操作的內核,
1. @jitclass:對于支持jit的類,
1. @cfunc:聲明一個用作本機回調的函數(從C / C ++等調用),
1. @overload:注冊自己的函數實現以在nopython模式下使用,例如@overload(scipy.special.j0)。
Numba還具有預先(AOT)編譯功能,它生成一個編譯后的擴展模塊,該模塊不依賴于Numba。但:
1. 它只允許使用常規函數(不能使用ufuncs),
1. 你必須指定一個函數簽名。你只能指定一個,因為許多指定使用不同的名稱。
它還會為你的CPU架構系列生成通用代碼。
通過使用@vectorize包裝器,你可以將對標量進行操作的函數轉換為數組,例如,如果你正在使用math僅在標量上運行的python 庫,則可以對數組使用。這提供了類似于numpy數組操作(ufuncs)的速度。例如:
@vectorizedef func(a, b): # 對標量進行運算 return result
你還可以將target參數傳遞給此包裝器,該包裝器的值可以等于parallel用于并行化代碼,cuda用于在cuda / GPU上運行代碼的值。
@vectorize(target="parallel")def func(a, b): # 對標量進行運算 return result
假設你的代碼具有足夠的計算密集性或數組足夠大,則使用numpy進行矢量化target = "parallel"或"cuda"通常比numpy實現運行得更快。如果不是這樣的話,這將花費大量時間來制作線程和為不同的線程拆分元素,這可能會超過整個過程的實際計算時間。因此,工作應該足夠繁重才能加快速度。
你也可以像包裝器一樣傳遞@jit來在cuda / GPU上運行函數。為此,你將必須numba庫中導入cuda。但是在GPU上運行代碼不會像以前那樣容易。為了在GPU上的數百個甚至數千個線程上運行函數,它需要完成一些初始計算。你必須聲明和管理網格,塊和線程的層次結構。但是這并不難。
要在GPU上執行一個函數,你必須定義一個 kernel function(內核函數)或一個device function(設備函數)。首先,讓我們看一下kernel function(核函數)。
關于內核函數需要記住的幾點:
a)內核在被調用時顯式聲明其線程層次結構,即塊數和每個塊的線程數。你可以編譯一次內核,然后使用不同的塊和網格大小多次調用它。
b)內核無法返回值。因此,你將不得不在原始數組上進行更改,或者傳遞另一個數組來存儲結果。對于計算標量,你將必須傳遞一個一元數組。
# 定義一個內核函數from numba import cuda@cuda.jitdef func(a, result): # 然后是一些CUDA相關的計算 # 你的計算密集的代碼 # 你的答案儲存在'result'中
因此,要啟動內核,你將必須傳遞兩個東西:
1. 每個塊的線程數,
1. 塊的數量。
例如:
threadsperblock = 32blockspergrid = (array.size + (threadsperblock - 1)) // threadsperblockfunc[blockspergrid, threadsperblock](array)
每個線程中的內核函數必須知道它在哪個線程中,知道它負責數組的哪個元素。通過Numba,只需一次調用即可輕松獲得元素的這些位置。
@cuda.jitdef func(a, result): pos = cuda.grid(1) # 對一維數組 # x, y = cuda.grid(2) # 對二維數組 if pos < a.shape[0]: result[pos] = a[pos] * (some computation)
為了節省將numpy數組復制到特定設備并再次將結果存儲在numpy數組中的時間,Numba提供了一些函數來聲明和發送數組到特定的設備,如:numba.cuda.device_array,numba.cuda.device_array_like,numba.cuda.to_device,等等,以節省不必要的時間復制到cpu(除非必要)。
另一方面,device function只能從設備內部(通過內核或其他設備函數)好處是,你可以從device function返回一個值。因此,你可以使用此函數的返回值來計算kernel function或device function的一些內容。
from numba import cuda@cuda.jit(device=True)def device_function(a, b): return a + b
Numba 在其cuda庫中還具有原子操作,隨機數生成器,共享內存實現(以加快數據訪問速度)等。
ctypes / cffi / cython互操作性:
· cffi- 在nopython模式下支持CFFI函數的調用。
· ctypes — 在nopython模式下支持ctypes包裝器函數的調用…
· Cython導出的函數是可調用的。
下一期我們來看加快Python算法的另一種方法——數據并行化!
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
CDA數據分析師證書考試體系(更新于2025年05月22日)
2025-05-26解碼數據基因:從數字敏感度到邏輯思維 每當看到超市貨架上商品的排列變化,你是否會聯想到背后的銷售數據波動?三年前在零售行 ...
2025-05-23在本文中,我們將探討 AI 為何能夠加速數據分析、如何在每個步驟中實現數據分析自動化以及使用哪些工具。 數據分析中的AI是什么 ...
2025-05-20當數據遇見人生:我的第一個分析項目 記得三年前接手第一個數據分析項目時,我面對Excel里密密麻麻的銷售數據手足無措。那些跳動 ...
2025-05-20在數字化運營的時代,企業每天都在產生海量數據:用戶點擊行為、商品銷售記錄、廣告投放反饋…… 這些數據就像散落的拼圖,而相 ...
2025-05-19在當今數字化營銷時代,小紅書作為國內領先的社交電商平臺,其銷售數據蘊含著巨大的商業價值。通過對小紅書銷售數據的深入分析, ...
2025-05-16Excel作為最常用的數據分析工具,有沒有什么工具可以幫助我們快速地使用excel表格,只要輕松幾步甚至輸入幾項指令就能搞定呢? ...
2025-05-15數據,如同無形的燃料,驅動著現代社會的運轉。從全球互聯網用戶每天產生的2.5億TB數據,到制造業的傳感器、金融交易 ...
2025-05-15大數據是什么_數據分析師培訓 其實,現在的大數據指的并不僅僅是海量數據,更準確而言是對大數據分析的方法。傳統的數 ...
2025-05-14CDA持證人簡介: 萬木,CDA L1持證人,某電商中廠BI工程師 ,5年數據經驗1年BI內訓師,高級數據分析師,擁有豐富的行業經驗。 ...
2025-05-13CDA持證人簡介: 王明月 ,CDA 數據分析師二級持證人,2年數據產品工作經驗,管理學博士在讀。 學習入口:https://edu.cda.cn/g ...
2025-05-12CDA持證人簡介: 楊貞璽 ,CDA一級持證人,鄭州大學情報學碩士研究生,某上市公司數據分析師。 學習入口:https://edu.cda.cn/g ...
2025-05-09CDA持證人簡介 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度、美團、阿里等 ...
2025-05-07相信很多做數據分析的小伙伴,都接到過一些高階的數據分析需求,實現的過程需要用到一些數據獲取,數據清洗轉換,建模方法等,這 ...
2025-05-06以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda.cn/g ...
2025-04-30CDA持證人簡介: 邱立峰 CDA 數據分析師二級持證人,數字化轉型專家,數據治理專家,高級數據分析師,擁有豐富的行業經驗。 ...
2025-04-29CDA持證人簡介: 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度,美團,阿里等 ...
2025-04-28CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-27數據分析在當今信息時代發揮著重要作用。單因素方差分析(One-Way ANOVA)是一種關鍵的統計方法,用于比較三個或更多獨立樣本組 ...
2025-04-25CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-25