Python/Numpy的一些高級用法(個人筆記)

Python/numpy 常用與高級用法總結(jié)(實時更新)
開始在商湯做算法研究員后,工作中要寫大量python,但因為一直以來習(xí)慣C/C++的寫法,經(jīng)常在程序中使用for循環(huán)。然而python作為動態(tài)語言,不像C++有編譯器能對大循環(huán)有全局的智能并行優(yōu)化,而是會低效率地反復(fù)對循環(huán)部分內(nèi)容逐行編譯運(yùn)行,導(dǎo)致在一些大循環(huán)里速度極慢,也導(dǎo)致我剛開始一段時間寫的代碼一直被同事和老板吐槽。

后來才慢慢學(xué)會了用numpy,numpy的功能非常豐富,在算法實現(xiàn)中大部分的需求都有已經(jīng)封裝好的函數(shù),且都是做好底層加速優(yōu)化的,運(yùn)行速度也非???。
在研究員的工作中,numpy用的好壞直接決定了代碼的質(zhì)量與工作效率的高低,因此寫了這篇博客,來記錄平時工作中發(fā)現(xiàn)的一些好用的python/numpy用法。

1、求數(shù)列中,數(shù)值等于某個值的所有數(shù)字的位置:np.nonzero

a=np.array([0, 1, 2, 1, 1, 3, 4, 1, 5])
np.nonzero(a==1)
Out[15]: (array([1, 3, 4, 7], dtype=int64),)  #就找到了array a中所有等于1的元素位置

nonzero是很常用的函數(shù),比如對一批數(shù)據(jù)聚類后,得到一個prediction label列表,我們希望把聚為同一類的對象拿出來看看,就要用到這個nonzero找到同為某個label的元素在list中的位置)
要注意直接使用nonzero返回的是一個tuple類型,如果希望得到array結(jié)果,記得加上[0]的索引

np.nonzero(a==1)[0]
Out[16]: array([1, 3, 4, 7], dtype=int64)

2、np.intersect1d #待更新
3、np.argwhere
4、np.where
5、np.argsort
6、np.sum
7、np.mean np.mean(axis=1)
8、np.newaxis
9、Np.where(np.isin)

2、生成空的帶有一定shape的array,np.empty:
很多時候需要設(shè)置一個起始的空數(shù)組,在后面循環(huán)的時候?qū)⑿碌臄?shù)組合并進(jìn)來,但是直接np.array([])生成的數(shù)組如果直接和后續(xù)數(shù)據(jù)用拼接concatenate操作的話,會報錯dimension對不上,

>>> a
array([], dtype=float64)
>>> b
array([[1, 2],
       [2, 5]])
>>> np.concatenate((a,b))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: all the input arrays must have same number of dimensions

此時就需要用np.empty,就能生成帶有一定shape的空array,避免維度不對應(yīng)的報錯。

>>> a=np.empty((0,2),np.int)

生成升序數(shù)列np.arrange

np.arange(4)
Out[5]: array([0, 1, 2, 3])

等分?jǐn)?shù)組np.split
不過只能均分一個數(shù)組,如果需要按個數(shù)分割數(shù)組,可能還得自行用for循環(huán)。

np.split(np.arange(8),4)
Out[19]: [array([0, 1]), array([2, 3]), array([4, 5]), array([6, 7])]

python部分
assert報錯函數(shù)
assert(條件)
如果條件滿足,則正常運(yùn)行,如果不滿足,則報錯退出

打印日志sys.stdout(建議Logger寫法)
如果想要同時輸出日志到控制臺與Log文件中,可以先定義logger類,包含兩個成員console,out_dir,

class logger(object):
    def __init__(self, fpath):
        self.console = sys.stdout
        self.file = fpath

然后在主程序中讓sys.stdout等于此對象即可

import sys
sys.stdout = logger(‘your log path’)

絕對引入
為了防止一些自己寫的腳本與系統(tǒng)默認(rèn)的包重名,導(dǎo)致無法引入的情況,比如:
你的腳本目錄有一個文件名為math,你想要import這個math文件,然而由于python庫中有同名的math包,這樣總是會優(yōu)先import系統(tǒng)默認(rèn)的math,此時就需要聲明絕對引入,這樣引入自己腳本時,就需要明確寫出完整的from路徑,而系統(tǒng)的包則直接import即可

from __future__ import absolute_import

內(nèi)存回收
雖說python通常不需要內(nèi)存管理,當(dāng)一塊內(nèi)存沒有變量指向的引用時,python會有某種邏輯在一定條件下回自動回收這塊內(nèi)存,然而使用python腳本處理大規(guī)模數(shù)據(jù)時,單純使用del 去刪除引用,內(nèi)存塊不會被即時回收掉,導(dǎo)致一定概率內(nèi)存溢出從而進(jìn)程被kill。

a=np.array([1, 2, 3, 4])
id(a)
Out[35]: 1812623222304     #獲得地址
ctypes.cast(1812623222304,ctypes.py_object).value    #取得地址指向的內(nèi)存
Out[36]: array([1, 2, 3, 4])
del a        #刪除內(nèi)存指向的指針,讓這塊內(nèi)存沒有指針指向
ctypes.cast(1812623222304,ctypes.py_object).value
Out[38]: array([1, 2, 3, 4])          #結(jié)果發(fā)現(xiàn)a被del了,然而這塊內(nèi)存依然沒有釋放

實際上,經(jīng)過個人的測試,python的自動內(nèi)存回收邏輯大概是:當(dāng)系統(tǒng)內(nèi)存不停被占用,直到可用內(nèi)存低于某一臨界值后,才會開始內(nèi)存回收,對沒有引用的內(nèi)存塊執(zhí)行回收動作;

然而處理超大規(guī)模數(shù)據(jù)時,往往內(nèi)存來不及回收完,大量讀入的新數(shù)據(jù)導(dǎo)致爆內(nèi)存,從而進(jìn)程被kill,此時可以考慮手動回收內(nèi)存(gc模塊),就能及時回收內(nèi)存

import gc
a=np.array([1, 2, 3, 4])
del a
gc.collect()

args 參數(shù)說明:
action='store_true'
parser.add_argument('--t', help=' ', action='store_true', default=False)
即當(dāng)運(yùn)行時,此變量有傳參,就設(shè)為True

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容