數據科學家是「比軟件工程師更擅長統計學,比統計學家更擅長軟件工程的人」。許多數據科學家都具備統計學背景,可是在軟件工程方面的經驗甚少。我是一名資深數據科學家,在Stackoverflow的python編程方面排名前1%,並與許多(初級)數據科學家共事。如下是我常常看到的10大常見錯誤,本文將爲你相關解決方案:html
數據科學須要代碼和數據。所以,爲了讓別人能夠復現你的結果,他們須要可以訪問到數據。道理很簡單,可是不少人忘記分享他們代碼中的數據。python
import pandas as pd df1 = pd.read_csv('file-i-dont-have.csv') # fails do_stuff(df)
解決方案:使用d6tpipe(https://github.com/d6t/ d6tpipe)來共享你的代碼中的數據文件、將其上傳到S3/web/google驅動等,或者保存到數據庫,以便於別人能夠檢索到文件(可是不要將其添加到git,緣由見下文)。git
與錯誤1類似,若是你對別人沒法訪問的路徑進行硬編碼,他們將沒法運行你的代碼,而且必須仔細查看代碼來手動更改路徑。使人崩潰!github
import pandas as pd df = pd.read_csv('/path/i-dont/have/data.csv') # fails do_stuff(df) # or import os os.chdir('c:\\Users\\yourname\\desktop\\python') # fails
解決方案:使用相對路徑、全局路徑配置變量或d6tpipe,使你的數據易於訪問。web
d6tpipe:數據庫
https://github.com/d6t/d6tpipapache
既然數據科學的代碼中包含數據,爲何不把它們放到同一目錄中?那樣你還能夠在其中保存圖像、報告和其餘垃圾。哎呀,真是一團糟!編程
├── data.csv ├── ingest.py ├── other-data.csv ├── output.png ├── report.html └── run.py
解決方案:將你的目錄進行分類,好比數據、報告、代碼等。請參閱Cookiecutter Data Science或d6tflow項目模板[見#5],並使用#1中提到的工具來存儲和共享數據。數組
Cookiecutter Data Science: https://drivendata.github.io/cookiecutter-data-science/ d6tflow項目模板: https://github.com/d6t/d6tflow-templat
如今,大多數人對他們的代碼使用版本控制(若是你不使用,那就是另一個錯誤,請參閱git:https://git-scm.com/)。在嘗試共享數據時,很容易將數據文件添加到版本控制中。當文件很小時是能夠的,可是git並無針對數據進行優化,尤爲是大文件。cookie
git add data.csv
解決方案:使用第1點中提到的工具來存儲和共享數據。若是你真的但願對數據進行版本控制,請參閱 d6tpipe,DVC和Git大文件存儲。
d6tpipe: https://github.com/d6t/d6tpipe DVC: https://dvc.org/ Git大文件存儲: https://git-lfs.github.com
關於數據部分已經夠多了,如今來談一談實際的代碼!在學習編程時最早學習的內容之一就是函數,數據科學代碼一般由一系列線性運行的函數組成。
這會致使一些問題,請參閱「爲何你的機器學習代碼可能很差的4個緣由」:
https://github.com/d6t/d6t-python/blob/master/blogs/reasons-why-bad-ml-code.rst
def process_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'])
解決方案:數據科學代碼不是一系列線性鏈接的函數,而是一組具備依賴關係的任務集合。請使用d6tflow或airflow。
d6tflow:
https://github.com/d6t/d6tflow-template
airflow:
與函數相似,for循環也是你學習編程時最初學習的內容。它們易於理解,可是運行緩慢且過於冗長,一般意味着你不瞭解矢量化的替代方案。
x = range(10) avg = sum(x)/len(x); std = math.sqrt(sum((i-avg)**2 for i in x)/len(x)); zscore = [(i-avg)/std for x] # should be: scipy.stats.zscore(x) # or groupavg = [] for i in df['g'].unique(): dfg = df[df[g']==i] groupavg.append(dfg['g'].mean()) # should be: df.groupby('g').mean()
解決方案:Numpy,scipy和pandas爲你須要for循環的狀況提供了矢量化函數。
Numpy:
scipy:
pandas:
隨着數據、參數或用戶輸入的改變,你的代碼可能會出現問題,有時你並無注意到。這可能會致使糟糕的輸出結果,而若是有人基於你的輸出作出決策,那麼糟糕的數據將會致使糟糕的決策。
解決方案:使用assert語句來檢查數據質量。pandas有相等測試,d6tstack有數據提取檢查以及用於數據鏈接的d6tjoin。
pandas相等測試:
https://pandas.pydata.org/pandas-docs/stable/reference/general_utility_functions.html
d6tstack:
https://github.com/d6t/d6tstack
d6tjoin:
https://github.com/d6t/d6tjoin/blob/master/examples-prejoin.ipyn
如下是數據檢查的示例代碼:
assert df['id'].unique().shape[0] == len(ids) # have data for all ids? assert df.isna().sum()<0.9 # catch missing values assert 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?
我明白,你急着作出一些分析結果。你把事情彙總到一塊兒分析,將結果交給你的客戶或老闆。一個星期以後,他們回來講,「能夠把XXX改一下嗎」或者「能夠更新一下這裏嗎」。你看着你的代碼,可是並不記得你當初爲何這麼寫。如今就像是在運行別人的代碼。
def some_complicated_function(data): data = data[data['column']!='wrong'] data = data.groupby('date').apply(lambda x: complicated_stuff(x)) data = data[data['value']<0.9] return data
解決方案:即便在你已經提交分析報告後,也要花費額外的時間,來對你作的事情編寫說明文檔。之後你會感謝本身,別人更會感謝你。那樣顯得你很專業!
回到數據,畢竟是在講數據科學。就像函數和for循環同樣,CSV和pickle文件很經常使用,可是並很差用。CSV文件不包含綱要(schema),所以每一個人都必須再次解析數字和日期。Pickle文件解決了這個問題,可是它只能在python中使用,而且不能壓縮。二者都不是存儲大型數據集的最優格式。
def process_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,無需額外處理。
parquet:
https://github.com/dask/fastparquet
d6tflow:
https://github.com/d6t/d6tflow-template
最後一個是很有爭議的錯誤:jupyter notebook和csv文件同樣廣泛。許多人使用它們,可是這並不意味着它們很好。jupyter notebook滋長了上述提到的許多不良編程習慣,尤爲是:
把全部文件保存在一個目錄中
編寫從上至下運行的代碼,而不是DAG
沒有對代碼進行模塊化
很難調試
代碼和輸出混在一個文件中
沒有很好的版本控制
它容易上手,可是擴展性不好。
解決方案:使用pycharm和/或spyder。
pycharm:
https://www.jetbrains.com/pycharm/
spyder:
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。