博客專欄

EEPW首頁(yè) > 博客 > 獨(dú)家 | 數(shù)據(jù)科學(xué)家對(duì)可復(fù)用Python代碼的實(shí)用管理方法(附鏈接)

獨(dú)家 | 數(shù)據(jù)科學(xué)家對(duì)可復(fù)用Python代碼的實(shí)用管理方法(附鏈接)

發(fā)布人:數(shù)據(jù)派THU 時(shí)間:2021-09-19 來(lái)源:工程師 發(fā)布文章

作者:Matthew Mayo, KDnuggets

翻譯:殷之涵

校對(duì):歐陽(yáng)錦

有很多不同的方法管理自己的代碼,這取決于您的具體要求、個(gè)性、技術(shù)知識(shí)、所扮演角色和諸多其他因素。雖然經(jīng)驗(yàn)豐富的開(kāi)發(fā)人員可能有一套非常嚴(yán)格的方法可以跨多語(yǔ)言、項(xiàng)目和用例進(jìn)行代碼管理,但很少編寫(xiě)自己的代碼的數(shù)據(jù)分析師由于缺乏必要性,可能會(huì)較為疏于代碼管理。其實(shí),在管理代碼這件事情上并沒(méi)有對(duì)錯(cuò)之分,這只是一個(gè)是否對(duì)您自己“有用”和“合適”的問(wèn)題而已。

具體來(lái)說(shuō),我所指的“代碼管理”是指您如何組織、存儲(chǔ)和調(diào)用您自己編寫(xiě)的不同的代碼段——這些代碼段作為您對(duì)自己的編程工具箱的長(zhǎng)期積累,是很有用的。編程的本質(zhì)是自動(dòng)化,因此如果一名編程者發(fā)現(xiàn)自己正在重復(fù)執(zhí)行一些類(lèi)似任務(wù),那么就勢(shì)必要考慮以某種方式對(duì)該任務(wù)的相關(guān)代碼進(jìn)行自動(dòng)調(diào)用。

這就是我們經(jīng)常要使用第三方庫(kù)的原因。比如要使用支持向量機(jī)(SVM)算法時(shí),我們不需要每次都把代碼重新實(shí)現(xiàn)一遍;相反,我們可以使用一個(gè)庫(kù)——也許是 Scikit-learn——這樣我們就能好好利用眾多前人隨著時(shí)間推移所不斷完善而成的智慧結(jié)晶了。

除了第三方庫(kù)的使用,我們還要把這種“自動(dòng)化思想”擴(kuò)展到個(gè)人編程領(lǐng)域。您可能已經(jīng)這樣做了(我希望是的),但如果沒(méi)有,以下是我作為一名數(shù)據(jù)科學(xué)家,對(duì)自己所寫(xiě)的可復(fù)用 Python 代碼進(jìn)行管理的幾種固化下來(lái)的方法(按照最通用到最不通用來(lái)進(jìn)行排序)。

自建代碼庫(kù)(Full-blown Libraries)

這是一種最通用的方法,也可以說(shuō)是最“專業(yè)”的方法;然而,這并不意味著它適用于所有的情況。

如果您發(fā)現(xiàn)您在許多用例中都在頻繁使用相同的功能,那么自己搭建一個(gè)代碼庫(kù)就是正確的選擇。此外,如果您要復(fù)用的功能很容易參數(shù)化,那這個(gè)選擇也十分合理;參數(shù)化的意思是,您可以通過(guò)編寫(xiě)和調(diào)用帶有變量的通用函數(shù)來(lái)重復(fù)多次地處理任務(wù),每次調(diào)用時(shí)都可以對(duì)變量進(jìn)行重新定義。

舉例說(shuō)明,我經(jīng)常發(fā)現(xiàn)我想在一個(gè)字符串中找到某個(gè)子字符串第 n 次出現(xiàn)的位置索引,但是并沒(méi)有一個(gè)現(xiàn)成的Python標(biāo)準(zhǔn)庫(kù)函數(shù)能支持這一需求。因此,我自己寫(xiě)了一段簡(jiǎn)單的代碼,它接受一個(gè)字符串、一個(gè)子字符串以及我所求的第n次出現(xiàn)的“n”作為輸入,返回值是字符串中子字符串第n次出現(xiàn)開(kāi)始的位置索引(具體代碼出處見(jiàn):

https://stackoverflow.com/questions/1883980/find-the-nth-occurrence-of-substring-in-a-string)。

def find_nth(haystack, needle, n):
    start = haystack.find(needle)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start+len(needle))
        n -= 1
    return start

由于我平日有很多文本處理類(lèi)型的工作,所以我將上述函數(shù)連同一些經(jīng)常使用的其他文本處理函數(shù)集合起來(lái)并創(chuàng)建了一個(gè)庫(kù),這個(gè)庫(kù)就像其他任何Python 庫(kù)一樣被儲(chǔ)存在我的計(jì)算機(jī)上,并且能夠像其他任何庫(kù)一樣進(jìn)行導(dǎo)入。創(chuàng)建庫(kù)的方法雖然不難,但是步驟比較多,所以我就不做過(guò)多介紹了,感興趣的讀者可以參考這篇文章:

https://medium.com/analytics-vidhya/how-to-create-a-python-library-7d5aea80cc3f

所以現(xiàn)在我有了一個(gè)名為textproc的自建代碼庫(kù),我可以隨時(shí)輕松地導(dǎo)入和使用我的find_nth函數(shù),再也不用復(fù)制并粘貼整段代碼到我編寫(xiě)的每個(gè)要用到它的程序中了。

from textproc import find_nth
segment = line[:find_nth(line, ',', 4)].strip()

此外,如果我想擴(kuò)展這個(gè)庫(kù)——即把更多函數(shù)添加進(jìn)去,或者想更改現(xiàn)有的 find_nth函數(shù)的代碼,我只需要在底層這一處進(jìn)行修改后再重新導(dǎo)入即可(而不需要在所有調(diào)用之處都進(jìn)行一次相應(yīng)的修改)。

基于特定項(xiàng)目的共享腳本

有時(shí)候并不需要自建代碼庫(kù),因?yàn)槟胍獜?fù)用的代碼并沒(méi)有當(dāng)前項(xiàng)目以外的用途,但您確實(shí)需要在本項(xiàng)目中對(duì)它進(jìn)行復(fù)用。在這種情況下,您可以將這些函數(shù)放在一個(gè)腳本中,然后簡(jiǎn)單地按名稱導(dǎo)入該腳本即可。

我在讀研究生期間編寫(xiě)了大量和無(wú)監(jiān)督學(xué)習(xí)相關(guān)的代碼,特別是k-means 聚類(lèi)。我編寫(xiě)了用于簇中心初始化、數(shù)據(jù)點(diǎn)和簇中心之間的距離計(jì)算、簇中心重新計(jì)算等函數(shù),并使用不同的算法對(duì)這些任務(wù)進(jìn)行實(shí)現(xiàn)。我很快發(fā)現(xiàn),將其中一些算法函數(shù)的副本各自保存在一個(gè)單獨(dú)的腳本中以供調(diào)用并不是最佳選擇,反而將它們先集中在一個(gè)腳本中再進(jìn)行導(dǎo)入會(huì)更好?!肮蚕砟_本”這個(gè)工作方式與庫(kù)幾乎相同,但這個(gè)過(guò)程是基于特定路徑的,并且僅適用于某一特定項(xiàng)目。

很快我就積累了不同簇中心初始化函數(shù)和距離計(jì)算函數(shù)的腳本,以及加載和處理數(shù)據(jù)的函數(shù)的腳本。隨著這些代碼變得越來(lái)越參數(shù)化和具有普適性,它們最終被放到了一個(gè)正式的庫(kù)中。

這似乎是事情的常見(jiàn)進(jìn)展方式,至少根據(jù)我的經(jīng)驗(yàn)是這樣的:您在腳本中編寫(xiě)了一個(gè)滿足當(dāng)下使用需要的函數(shù),然后使用它。隨著項(xiàng)目擴(kuò)展,或者又接手了一個(gè)類(lèi)似項(xiàng)目,您意識(shí)到現(xiàn)在使用一個(gè)相同的函數(shù)會(huì)很方便,所以該函數(shù)就被放入了一個(gè)腳本中以便導(dǎo)入和使用。如果這種用途在短期內(nèi)繼續(xù)發(fā)揮作用,并且您發(fā)現(xiàn)該函數(shù)具有更廣泛和更長(zhǎng)期的用途,那么它就會(huì)被添加到現(xiàn)有庫(kù)中,或者成為一個(gè)新庫(kù)的基礎(chǔ)組成部分。

導(dǎo)入簡(jiǎn)單腳本這個(gè)方法在使用Jupyter Notebook時(shí)同樣有用,但在使用方式上有所不同。鑒于Jupyter Notebooks中大部分代碼內(nèi)容的臨時(shí)性、探索性和實(shí)驗(yàn)性,我通常不會(huì)把一些notebooks作為模塊導(dǎo)入到其他notebooks中。如果我發(fā)現(xiàn)多個(gè)notebooks都經(jīng)常使用某些代碼片段,那我就會(huì)把這些代碼片段放入一個(gè)單獨(dú)腳本中,并存儲(chǔ)在這些notebooks所屬的同一文件夾下,然后將其導(dǎo)入到需要使用它們的notebooks中。這種方法對(duì)我來(lái)說(shuō)會(huì)更合理一些,同時(shí)具有更高的穩(wěn)定性——相比于特定腳本,notebooks有更高的風(fēng)險(xiǎn)會(huì)被重新編輯,難以長(zhǎng)期依賴。

基于特定任務(wù)的模板

我發(fā)現(xiàn)我經(jīng)常重復(fù)執(zhí)行一些相同的任務(wù),而這些任務(wù)并不適合參數(shù)化,或者參數(shù)化的性價(jià)比實(shí)在很低(需要付出的時(shí)間精力遠(yuǎn)超所能得到的回報(bào))。在這種情況下,我會(huì)把代碼進(jìn)行模板化,或者標(biāo)準(zhǔn)化(boiler-plating)。比起我在本文開(kāi)頭所提到的簡(jiǎn)單復(fù)制粘貼——這些是我在所有情況下都想要避開(kāi)的工作,模板化的做法顯然要復(fù)雜一些,但有時(shí)候這卻是正確的選擇。

例如,我經(jīng)常需要進(jìn)行列表化(listify)操作——即使我壓根不清楚待處理的Pandas DataFrame中的內(nèi)容,仍然需要確定列數(shù)和待輸入的列以完成相關(guān)函數(shù)的編寫(xiě),通常還需要對(duì)輸出進(jìn)行調(diào)整——上述這些都表明編寫(xiě)函數(shù)的確太耗時(shí)了。

為了應(yīng)對(duì)這種情況,我編寫(xiě)了一個(gè)可靈活更改的腳本模板,并把它放在了一個(gè)用于儲(chǔ)存此類(lèi)模板的專用文件夾中。下面就是listify_df的代碼段,它能把 CSV 文件轉(zhuǎn)換成Pandas DataFrame,然后再輸出為所需的HTML文件。

import pandas as pd
# Read CSV file into dataframe
csv_file = 'data.csv'
df = pd.read_csv(csv_file)
# Iterate over df, creating numbered list entries
i = 1
for index, row in df.iterrows():
entry = '<b>' + str(i) + \
'. <a href="' + \
row['url'] + \
'">' + \
row['title'] + \
'</a> + \
'\n\n<blockquote>\n' + \
row['description'] + \
'\n</blockquote>\n'
i += 1
print(entry)

在這個(gè)案例中,我們能夠看到清晰的文件名以及對(duì)文件夾的有序管理,是很有助于管理這些常用代碼段的。

單行代碼和短代碼塊

重復(fù)的單行代碼和短代碼塊總是難免出現(xiàn)在我們的日常工作中,為什么不想想辦法做些自動(dòng)化呢?

您可以在需要的時(shí)候使用文本擴(kuò)展工具來(lái)插入簡(jiǎn)短的“短語(yǔ)”。我會(huì)用AutoKey來(lái)管理這樣的短語(yǔ),這些短語(yǔ)和一些觸發(fā)關(guān)鍵字相聯(lián)系,一旦輸入這些關(guān)鍵字,短語(yǔ)就會(huì)自動(dòng)插入。

AutoKey

https://github.com/autokey/autokey

例如,您在處理特定類(lèi)型的項(xiàng)目時(shí)是否總是需要導(dǎo)入一批相同的庫(kù)?您可以通過(guò)輸入“#nlpimport”來(lái)設(shè)置處理特定任務(wù)所需的所有導(dǎo)入工作,這一輸入會(huì)被識(shí)別為觸發(fā)關(guān)鍵字并被替換為以下內(nèi)容:

import sys, requests
import numpy as np
import pandas as pd
import texthero
import scattertext as st
import spacy
from spacy.lang.en.stop_words import STOP_WORDS
from datasets import load_metric, list_metrics
from transformers import pipeline
from fastapi import FastAPI

需要注意的是,一些 IDE 是具有這種自動(dòng)插入功能的。我自己通常使用美化的文本編輯器來(lái)編寫(xiě)代碼,所以對(duì)于我來(lái)說(shuō)AutoKey是非常必要且有用的。如果您用的是具備此類(lèi)功能的IDE,那就太好了。關(guān)鍵是,您再也不用總是寫(xiě)一些重復(fù)的代碼了。

以上就是我作為數(shù)據(jù)科學(xué)家對(duì)可復(fù)用 Python 代碼管理方法的概述。希望它們能對(duì)您有所幫助!

編輯:王菁

校對(duì):汪雨晴

*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞: AI

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉