用進度條助您特徵工程一臂之力

在具體的分析或者特徵工程之中,常常會遇處處理時間好久的問題,固然必要的優化是必須的。可是顯然,數據量上升,計算量過大後,處理時間是必須的此。時,若是有個能夠幫助您查看任務進度的進度條,一定能夠提升你抓住處理時間去作(磨)別(洋)事(工)。固然逐行打印是不錯的選擇,但在Jupyter notebook/JupyterLab中,這種實踐最大的問題是,打印過多,影響整個notebook的美觀程度。python

在此探討的是5GB級別如下的數據(之上的Spark分析,有基於Zipplin的分佈式任務精度條),主要環境是Jupyter下基於pandas包的分析和特徵工程任務。git

一個極爲簡單的例子

tqdm是基於Python的精度條模塊,裏面提供了簡單的代碼行進度條和基於ipywidgets的notebook內的進度條。因爲如今tqdm相關模塊還在開發階段,可能會用到一些私有對象,以後正式版中可能具體API會有所變化。github

固然,首先咱們得載入模塊,在notebook中使用tqdm帶的基於Js顯示的進度條前,請務必檢查是否安裝ipywidgets模塊。多線程

from tqdm import tqdm_notebook, _tqdm_notebook
_tqdm_notebook.tqdm_notebook.pandas()

其中第一行載入的兩個方法的做用分別是:app

  • tqdm_notebook:用來包裝任何能夠iterable的對象,在使用其元素進行運算結束後統計時間。
  • _tqdm_notebook:其中含有模塊能夠處理pandas的對象。

第二行則是重載pandas裏面的對象,提供能夠展現精度條的方法。分佈式

下面咱們能夠嘗試直接使用tqdm_notebook包裹iterable對象來展現進度條,效果以下:函數

a = list(range(1, 10000))
b = range(1, 10000)
_ = [(lambda x: x+1)(i) for i in tqdm_notebook(a)]
_ = [(lambda x: x+1)(i) for i in tqdm_notebook(b)]

clipboard.png

固然若是僅僅是使用range也能夠使用tqdm自帶的tnrangeoop

from tqdm._tqdm_notebook import tnrange
_ = [(lambda x: x+1)(i) for i in tnrange(1, 10000)]

效果以下:優化

clipboard.png

命名和深度

在一些場合,可能寫須要多個層級的迭代,此時,咱們能夠經過命名每一個層級的迭代器來實現這個個效果。使用desc參數便可:spa

for i in tnrange(1, 10, desc='i Loop'):
    for j in tnrange(1, 10000, desc='j Loop'):
        i+j

clipboard.png

固然,若是遇到Loop過多時,可能會依舊出現打印過多的困擾。此時leave參數是一個不錯的推薦。

for i in tqdm_notebook(range(100), desc='i-Loop'):
    for j in tqdm_notebook(range(10000), desc='j-Loop', leave=False):
        i+j

clipboard.png

多進程的擴展

固然,在具體計算中,多進程每每是常常會須要的一類擴展(因爲Python只能基於一個運算核心進行計算的限制),這時候線程的運算也是常常須要考量的方式。

在使用過程當中,第一個須要注意的問題是,tqdm每次是在從iterable對象中取值時,進行更新,而若是在map以前的list中作進度條的包裹,是在未使用map的函數以前統計。因此在進度條完成時,可能還會有一段時間後才真的執行結束。

from multiprocessing import Pool
def f(x):
    return x**32
p = Pool(5)
_ = [i for i in p.imap(f, tnrange(1000))]

而一個更好的處理是在使用後標記時間,使用multiprocessing.Pool.imap做爲迭代對象,但這個問題是tqdm沒法識別具體數量,此時,指定tqdm的迭代次數total便可。

_ = [i+1 for i in tqdm_notebook(p.imap(f, range(1000)))]

clipboard.png

_ = [i for i in tqdm_notebook(p.imap(f, range(3, 1000)), total=997)]

clipboard.png

pandas中使用

pandas中的使用,也是很是簡單,在重載命令執行後,SeriresDataFrameGroupBy對象都會擁有progress_apply方法,用法和apply一致,直接能夠調取進度條。

clipboard.png

實戰:複雜場景中的使用

最後,咱們結合一下以前的多線程和pandas操做,處理更大規模的數據。基本思路是,將DataFrame拆成若干組分,最後經過pandas.concat合併起結果。

def parallelize_dataframe(df, func, n_jobs=3, split_num=10):
    ## 拆分數據表
    df_split = np.array_split(df, split_num)
    pool = Pool(n_jobs)
    df_list = []
    
    ## map操做
    for df_element in tqdm_notebook(pool.imap(func, df_split), total=10000):
        df_list.append(df_element)
       
    ## reduce操做
    df = pd.concat(df_list)
    
    ## 關閉進程
    pool.close()
    pool.join()
    return df

以上實現了基本的基於tqdm顯示處理進度的操做。使用方法以下:

def apply_add_1(df):
    return df.apply(lambda row: row['sepal_length']+1, axis=1)
_ = parallelize_dataframe(iris_df, apply_add_1)

clipboard.png

結語

查看了一下進度條,此次預處理我還要花一小時,能夠先去衝杯咖啡了。

相關文章
相關標籤/搜索