<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Python】這個裝飾器竟讓 Python 提速了 30 倍!

          共 5193字,需瀏覽 11分鐘

           ·

          2022-12-08 16:09

          Python是一種解釋語言,其代碼不是直接編譯成機(jī)器碼,而是由另一個叫做 解釋器 的程序?qū)崟r解釋的(一般是 cpython )。因此,與其他編譯語言相比,Python靈活性高(動態(tài)類型,兼容性高,...)。但這也造成了Python非常慢的缺點。

          加速 Python的方法

          實際上,有多種解決方案可以解決python的緩慢問題。

          dc1bb31d899b93e375183ed86c624e48.webp
          • 使用 cython:一種編程語言,是python的超集。Cython是Python編程語言和擴(kuò)展 Cython 編程語言(基于Pyrex)的優(yōu)化靜態(tài)編譯器。它使得為 Python 編寫 C 擴(kuò)展就像 Python 本身一樣容易。
          • 使用C/C++語言結(jié)合 ctypes pybind11 CFFI 來編寫Python的綁定程序
          • 用C/C++擴(kuò)展Python
          • 使用其他編譯過的語言,如rust[1]

          而所有這些方法,都需要使用除Python外的另一種語言,并編譯代碼使之與Python一起工作。盡管這些方法都很不錯,但并不是最適合我們初學(xué)者的使python更快的方法,更別提他們通常比較難以設(shè)置了。

          Numba & JIT 編譯器

          Numba[2]是一個Python包,在兼具Python的便利的同時,可以使你的代碼更快。

          67f819c54c683c22eb9c035b1a04827b.webp

          numba使用Just-in-time (JIT)編譯(即在Python代碼執(zhí)行過程中的實時編譯的),使用起來非常方便,無需向其他工具一樣,還需安裝一個C/C++編譯器,它僅需用 pip/conda 安裝它即可。

                pip?install?numba

          接下來試一個例子:用蒙特卡洛模擬來計算π的估計值。

                import?random
          from?numba?import?njit
          def?monte_carlo_pi_without_numba(nsamples):
          ????acc?=?0
          ????for?i?in?range(nsamples):
          ????????x?=?random.random()
          ????????y?=?random.random()
          ????????if?(x?**?2?+?y?**?2)?<?1.0:
          ????????????acc?+=?1
          ????return?4.0?*?acc?/?nsamples

          #?添加numba的裝飾器,使該函數(shù)更快。
          @njit
          def?monte_carlo_pi_with_numba(nsamples):
          ????acc?=?0
          ????for?i?in?range(nsamples):
          ????????x?=?random.random()
          ????????y?=?random.random()
          ????????if?(x?**?2?+?y?**?2)?<?1.0:
          ????????????acc?+=?1
          ????return?4.0?*?acc?/?nsamples

          在使用該方法時,我們只需要導(dǎo)入numba的一個裝飾器(njit),剩下的都由它自己完成即可,可以說是非常方便。

          我們運行兩個版本的代碼,并進(jìn)行計時對比。顯示numba比普通python快30倍

                %timeit?monte_carlo_pi_with_numba(100_000)
          #?1.24?ms?±?10.4?μs?per?loop?(mean?±?std.?dev.?of?7?runs,?1000?loops?each)

          %timeit?monte_carlo_pi_without_numba(100_000)
          #?40.6?ms?±?814?μs?per?loop?(mean?±?std.?dev.?of?7?runs,?10?loops?each)

          一些注意事項

          df22ca1b3759ec90247744521dde8583.webp

          值得一提的是,numba確實有一些缺點:

          • 在首次運行numba裝飾的函數(shù)時,有一定的時間開銷。這是因為首次執(zhí)行時,numba會試圖找出參數(shù)的類型并編譯函數(shù),從而導(dǎo)致程序有一定的延遲。
          • 不是所有的Python代碼都能用numba編譯,例如,如果你對同一個變量或?qū)α斜碓厥褂没旌蠑?shù)據(jù)類型,此種情況將會拋出異常。

          加速 Pandas

          Numba是專門為numpy設(shè)計的,對numpy數(shù)組非常友好。而 pandas 是建立在 numpy 之上的,這使得在使用用戶定義的函數(shù)或甚至執(zhí)行不同的Dataframe操作時,可以進(jìn)行瘋狂優(yōu)化。

          6f4295f9aaa25c58a19d46fad80b7cdc.webp

          首先創(chuàng)建一個DataFrame數(shù)據(jù)集。

                import?numpy?as?np
          import?pandas?as?pd

          n?=?1_000_000

          df?=?pd.DataFrame({
          ????'height':?1?+?1.3?*?np.random.random(n),
          ????'weight':?40?+?260?*?np.random.random(n),
          ????'hip_circumference':?94?+?14?*?np.random.random(n)
          })

          用戶定義的函數(shù)

          numba 的另一個重要的方法是 vectorize,使用該方法可以很容易的創(chuàng)建numpy通用函數(shù)(ufuncs[3])

          通用函數(shù)(或簡稱ufunc)是以ndarrays逐個元素的方式運行的函數(shù),支持?jǐn)?shù)組廣播、類型轉(zhuǎn)換和其他幾個標(biāo)準(zhǔn)特性。也就是說,ufunc 是一個函數(shù)的“矢量化”包裝器,它接受固定數(shù)量的特定輸入并產(chǎn)生固定數(shù)量的特定輸出。

          下面是計算數(shù)據(jù)集中列height的平方。

                from?numba?import?vectorize

          def?get_squared_height_without_numba(height):
          ??return?height?**?2

          @vectorize
          def?get_squared_height_with_numba(height):
          ??return?height?**?2

          %timeit?df['height'].apply(get_squared_height_without_numba)
          #?279?ms?±?7.31?ms?per?loop?(mean?±?std.?dev.?of?7?runs,?1?loop?each)


          %timeit?df['height']?**?2
          #?2.04?ms?±?229?μs?per?loop?(mean?±?std.?dev.?of?7?runs,?1000?loops?each)

          #?我們首先將列轉(zhuǎn)換為numpy數(shù)組,
          #?因為numba與numpy兼容,與pandas并不兼容。
          %timeit?get_squared_height_with_numba(df['height'].to_numpy())
          #?1.6?ms?±?51.5?μs?per?loop?(mean?±?std.?dev.?of?7?runs,?1000?loops?each)

          基本操作

          使用njit,并計算 BMI(身體質(zhì)量指數(shù))。

                from?numba?import?njit

          @njit
          def?get_bmi(weight_col,?height_col):
          ??n?=?len(weight_col)
          ??result?=?np.empty(n,?dtype="float64")

          ??#?與python循環(huán)相比,Numba的循環(huán)非???/span>
          ??for?i,?(weight,?height)?in?enumerate(zip(weight_col,?height_col)):
          ????result[i]?=?weight?/?(height?**?2)
          ??return?result

          #?不要忘記將列轉(zhuǎn)換為?numpy?
          %timeit?df['bmi']?=?get_bmi(df['weight'].to_numpy(),?
          ????????????????????????????df['height'].to_numpy())
          #?6.77?ms?±?230?μs?per?loop?(mean?±?std.?dev.?of?7?runs,?100?loops?each)

          %timeit?df['bmi']?=?df['weight']??/?(df['height']?**?2)
          #?8.63?ms?±?316?μs?per?loop?(mean?±?std.?dev.?of?7?runs,?100?loops?each)

          你可以看到,即使是基本的操作,numba仍然比原始 pandas 花費的時間更少(6.77ms vs 8.63ms)。

          寫在最后

          numba 是一種開箱即用的方法,可以輕而易舉地 讓你的 Python 代碼變得更快。當(dāng)然,在成功編譯代碼之前可能需要多幾次嘗試,你可以試試使用它。如果本文對你有用,那就點個贊和在看支持下云朵君吧!

          拓展閱讀

          [1]

          rust: https://github.com/PyO3/pyo3

          [2]

          Numba: https://numba.pydata.org/

          [3]

          ufuncs: https://numpy.org/doc/stable/reference/ufuncs.html

          44345a8e6e6735bdde65c5cc5300ea2f.webp
              
                    
                      
                        
                          
                                
                                                    往期
                                                    精彩
                                                    回顧
                                                  
                                                



          瀏覽 103
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  美女口鸡免费网站 | 天天躁日日躁狠狠躁免费麻豆 | 操逼视频网站免费观看 | 91 丝袜一区二区 | 欧美色图亚洲第一 |