數據科學家是“比軟件工程師更擅長統計學,比統計學家更擅長軟件工程的人”。許多數據科學家都具有統計學背景,但是在軟件工程方面的經驗甚少。我是一名資深數據科學家,在Stackoverflow的python編程方面排名前1%,并與許多(初級)數據科學家共事。以下是我經常看到的10大常見錯誤,本文將為你相關解決方案:
不共享代碼中引用的數據
對無法訪問的路徑進行硬編碼
將代碼與數據混合
在Git中和源碼一起提交數據
編寫函數而不是DAG
寫for循環
不編寫單元測試
不寫代碼說明文檔
將數據保存為csv或pickle文件
使用jupyter notebook
1.不共享代碼中引用的數據
數據科學需要代碼和數據。因此,為了讓別人可以復現你的結果,他們需要能夠訪問到數據。道理很簡單,但是很多人忘記分享他們代碼中的數據。
importpandasaspddf1=pd.read_csv('file-i-dont-have.csv')#failsdo_stuff(df)
解決方案:使用d6tpipe來共享你的代碼中的數據文件、將其上傳到S3/web/google驅動等,或者保存到數據庫,以便于別人可以檢索到文件(但是不要將其添加到git,原因見下文)。
2.對無法訪問的路徑進行硬編碼
與錯誤1相似,如果你對別人無法訪問的路徑進行硬編碼,他們將無法運行你的代碼,并且必須仔細查看代碼來手動更改路徑。令人崩潰!
importpandasaspddf=pd.read_csv('/path/i-dont/have/data.csv')#failsdo_stuff(df)#orimportosos.chdir('c:\Users\yourname\desktop\python') # fails
解決方案:使用相對路徑、全局路徑配置變量或d6tpipe,使你的數據易于訪問。
3.將代碼與數據混合
既然數據科學的代碼中包含數據,為什么不把它們放到同一目錄中?那樣你還可以在其中保存圖像、報告和其他垃圾。哎呀,真是一團糟!
├──data.csv├──ingest.py├──other-data.csv├──output.png├──report.html└── run.py
解決方案:將你的目錄進行分類,比如數據、報告、代碼等。請參閱Cookiecutter Data Science或d6tflow項目模板[見#5],并使用#1中提到的工具來存儲和共享數據。
4.在Git中和源碼一起提交數據
現在,大多數人對他們的代碼使用版本控制(如果你不使用,那就是另外一個錯誤,請參閱git:https://git-scm.com/)。在嘗試共享數據時,很容易將數據文件添加到版本控制中。當文件很小時是可以的,但是git并沒有針對數據進行優化,尤其是大文件。
gitadddata.csv
解決方案:使用第1點中提到的工具來存儲和共享數據。如果你真的希望對數據進行版本控制,請參閱d6tpipe,DVC和Git大文件存儲。
5.編寫函數而不是DAG
關于數據部分已經夠多了,現在來談一談實際的代碼!在學習編程時最先學習的內容之一就是函數,數據科學代碼通常由一系列線性運行的函數組成。
這會導致一些問題,請參閱“為什么你的機器學習代碼可能不好的4個原因”:
defprocess_data(data,parameter):data=do_stuff(data)data.to_pickle('data.pkl')data = pd.read_csv('data.csv')process_data(data)df_train=pd.read_pickle(df_train)model=sklearn.svm.SVC()model.fit(df_train.iloc[:,:-1],df_train['y'])
解決方案:數據科學代碼不是一系列線性連接的函數,而是一組具有依賴關系的任務集合。
6.寫for循環
與函數類似,for循環也是你學習編程時最初學習的內容。它們易于理解,但是運行緩慢且過于冗長,通常意味著你不了解矢量化的替代方案。
x = range(10)avg=sum(x)/len(x);std=math.sqrt(sum((i-avg)**2foriinx)/len(x));zscore=[(i-avg)/stdforx]#shouldbe:scipy.stats.zscore(x)# orgroupavg=[]foriindf['g'].unique():dfg=df[df[g']==i]groupavg.append(dfg['g'].mean())#shouldbe:df.groupby('g').mean()
解決方案:Numpy,scipy和pandas為你需要for循環的情況提供了矢量化函數。
7.不編寫單元測試
隨著數據、參數或用戶輸入的改變,你的代碼可能會出現問題,有時你并沒有注意到。這可能會導致糟糕的輸出結果,而如果有人基于你的輸出做出決策,那么糟糕的數據將會導致糟糕的決策。
解決方案:使用assert語句來檢查數據質量。pandas有相等測試,d6tstack有數據提取檢查以及用于數據連接的d6tjoin。
以下是數據檢查的示例代碼:
assert df['id'].unique().shape[0] == len(ids) # have data for all ids?assertdf.isna().sum()<0.9?#?catch?missing?valuesassert?df.groupby(['g','date']).size().max()?==1?#?no?duplicate?values/date?assert?d6tjoin.utils.PreJoin([df1,df2],['id','date']).is_all_matched()?#?all?ids?matched?
8.不寫代碼說明文檔
我明白,你急著做出一些分析結果。你把事情匯總到一起分析,將結果交給你的客戶或老板。一個星期之后,他們回來說,“可以把XXX改一下嗎”或者“可以更新一下這里嗎”。你看著你的代碼,但是并不記得你當初為什么這么寫。現在就像是在運行別人的代碼。
defsome_complicated_function(data):data=data[data['column']!='wrong']data=data.groupby('date').apply(lambdax:complicated_stuff(x))data=data[data['value']<0.9] return data
解決方案:即使在你已經提交分析報告后,也要花費額外的時間,來對你做的事情編寫說明文檔。以后你會感謝自己,別人更會感謝你。那樣顯得你很專業!
9.將數據保存為csv或pickle文件
回到數據,畢竟是在講數據科學。就像函數和for循環一樣,CSV和pickle文件很常用,但是并不好用。CSV文件不包含綱要(schema),因此每個人都必須再次解析數字和日期。Pickle文件解決了這個問題,但是它只能在python中使用,并且不能壓縮。兩者都不是存儲大型數據集的最優格式。
defprocess_data(data,parameter):data=do_stuff(data)data.to_pickle('data.pkl')data=pd.read_csv('data.csv')process_data(data)df_train = pd.read_pickle(df_train)
解決方案:使用parquet或其他帶有數據綱要的二進制數據格式,在理想情況下可以壓縮數據。d6tflow將任務的數據輸出保存為parquet,無需額外處理。
10.使用jupyter notebook
最后一個是頗有爭議的錯誤:jupyter notebook和csv文件一樣普遍。許多人使用它們,但是這并不意味著它們很好。jupyter notebook助長了上述提到的許多不良編程習慣,尤其是:
把所有文件保存在一個目錄中
編寫從上至下運行的代碼,而不是DAG
沒有對代碼進行模塊化
很難調試
代碼和輸出混在一個文件中
沒有很好的版本控制
它容易上手,但是擴展性很差。
解決方案:使用pycharm和/或spyder。
-
編程
+關注
關注
88文章
3637瀏覽量
93905 -
函數
+關注
關注
3文章
4345瀏覽量
62868
原文標題:數據科學家常犯的 10 個編程錯誤
文章出處:【微信號:DBDevs,微信公眾號:數據分析與開發】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論