數據科學中的的十大編碼錯誤

翻譯:瘋狂的技術宅html

原文:towardsdatascience.com/top-10-codi…python

數據科學家是「比任何軟件工程師都更擅長統計數據的人,並且比任何統計學家都更擅長軟件工程」。許多數據科學家都有統計學背景,而且在軟件工程方面經驗不多。我是一名高級數據科學家,在 Stackoverflow 上的 python 板塊排名前 1%,並與許多(初級)數據科學家合做。如下是我常常看到的 10 個常見錯誤列表。git

1. 不共享代碼中引用的數據

數據科學須要代碼和數據。所以爲了讓其餘人可以重現你的結果,他們須要可以訪問數據。但不少人忘記了共享他們的代碼用到的數據。github

import pandas as pd
df1 = pd.read_csv('file-i-dont-have.csv') # fails
do_stuff(df)
複製代碼

解決方案:使用 d6tpipe與 你的代碼共享數據文件或上傳到 S三、web、google drive 等或保存到數據庫,以便他人能夠檢索文件(但不要不要把它們添加到 git 中,見下文)。web

2. 對沒法訪問的路徑作了硬編碼

與錯誤 1 相似,若是你對其餘人無權訪問的路徑進行了硬編碼,那麼他們沒法運行你的代碼而且必須檢查許多地方以手動更改路徑。 Booo!數據庫

import pandas as pd
df = pd.read_csv('/path/i-dont/have/data.csv') # fails
do_stuff(df)
# or 
impor os
os.chdir('c:\\Users\\yourname\\desktop\\python') # fails
複製代碼

解決方案:使用相對路徑、全局路徑配置變量或 d6tpipe 使你的數據易於訪問。apache

3. 將數據與代碼混在一塊兒

因爲數據科學的代碼須要數據,爲何不把它們放在一塊兒呢?不過當你在查看本身項目的時候,會發現數據文件、圖片、輸出結果和其餘垃圾文件混在一塊兒。哎呀,真是一團糟!bash

├── data.csv
├── ingest.py
├── other-data.csv
├── output.png
├── report.html
└── run.py
複製代碼

解決方案:將你的目錄按照類別進行組織,如數據、報告、代碼等。請參閱Cookiecutter數據科學d6tflow 項目模板 並使用第一條中提到的工具來存儲和共享數據。cookie

4. 用 Git 把數據和源代碼一塊兒提交

大多數人如今對他們的代碼進行版本控制(若是你不這樣作那就是另外一個錯誤!!見git)。在共享數據時,可能很容易將數據文件添加到版本控制中。這對於很是小的文件是能夠的,可是 git 沒有針對數據進行優化,尤爲是大文件。app

git add data.csv
複製代碼

解決方案:使用第一條中提到的工具來存儲和共享數據。若是你真的想要用版本控制系統去管理數據,請參閱d6tpipeDVCGit 大文件存儲

5. 編寫函數而不是 DAG

關於數據的問題夠多了,接下來讓咱們談談實際的代碼!因爲你在學習編碼時第一個學到的就是函數,所以數據科學代碼主要被組織爲一系列線性運行的函數。這樣會致使一些問題,請參閱機器學習代碼出問題的4個緣由

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'])
複製代碼

**解決方案:**數據科學代碼不是對函數進行線性連接,而是更好地寫爲一組具備依賴關係的任務。使用 d6tflowairflow

6. 過多的依賴循環

與函數同樣,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()
複製代碼

解決方案Numpyscipypandas 能夠幫你把不少你認爲可能須要循環的工做矢量化。

7. 不寫單元測試

隨着數據、參數或用戶輸入的變化,你的代碼可能會發生異常中斷,你可能不會注意這點,可是這可能致使輸出錯誤,若是有人根據你的輸出作出決定,那麼糟糕的數據將會致使錯誤的決策!

**解決方案:**使用 assert 語句檢查數據質量。 pandas 有相似的測試,也能夠用 d6tstack 檢查數據提取和 d6tjoin 對數據鏈接進行。代碼示例數據檢查:

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?
複製代碼

8. 不給代碼加註釋

我明白了,你急着作一些分析。你把事情搞混在一塊兒,把結果交給你的客戶或老闆。而後一個星期後,他們回來講「你能改變xyz」或「你能更新嗎」。你看看你的代碼,不記得你爲何作了你作的。如今想象其餘人必須運行它。

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
複製代碼

解決方案:即便在你提供數據分析的代碼以後,也要花費額外的時間來對你的所做所爲進行註釋。你會感謝本身,一樣別人也會這樣作!這使你看起來更像專業人士!

9. 將數據保存爲 csv 或 pickle 格式

再回到數據,畢竟這是數據科學。就像函數和 for 循環同樣,CSV 和 pickle 文件格式也是經常使用的,但實際上它們並非很好。 CSV 不包含結構,所以別人必須再次解析數字和日期。儘管 Pickles 解決了這個問題,但只能在 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 格式,所以你無需另行處理。

10. 使用 jupyter notebook

這是一個有爭議的結論:jupyter 筆記本和 CSV 同樣廣泛,不少人都在用它,這並不意味着它是合適的。 Jupyter notebook 形成了上面提到的許多不良軟件工程的習慣,特別是:

  1. 你很想將全部文件保存到同一個目錄中
  2. 編寫運行於上下文代碼關係而不是 DAG 的代碼
  3. 你沒有把你的代碼模塊化
  4. 難以調試
  5. 代碼和輸出混在同一個文件中
  6. 沒有良好的版本控制

Solution: Use pycharm and/or spyder.

解決方案:使用 pycharmspyder

相關文章
相關標籤/搜索