翻譯:瘋狂的技術宅html
原文:towardsdatascience.com/top-10-codi…python
數據科學家是「比任何軟件工程師都更擅長統計數據的人,並且比任何統計學家都更擅長軟件工程」。許多數據科學家都有統計學背景,而且在軟件工程方面經驗不多。我是一名高級數據科學家,在 Stackoverflow 上的 python 板塊排名前 1%,並與許多(初級)數據科學家合做。如下是我常常看到的 10 個常見錯誤列表。git
數據科學須要代碼和數據。所以爲了讓其餘人可以重現你的結果,他們須要可以訪問數據。但不少人忘記了共享他們的代碼用到的數據。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
與錯誤 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
因爲數據科學的代碼須要數據,爲何不把它們放在一塊兒呢?不過當你在查看本身項目的時候,會發現數據文件、圖片、輸出結果和其餘垃圾文件混在一塊兒。哎呀,真是一團糟!bash
├── data.csv
├── ingest.py
├── other-data.csv
├── output.png
├── report.html
└── run.py
複製代碼
解決方案:將你的目錄按照類別進行組織,如數據、報告、代碼等。請參閱Cookiecutter數據科學 或 d6tflow 項目模板 並使用第一條中提到的工具來存儲和共享數據。cookie
大多數人如今對他們的代碼進行版本控制(若是你不這樣作那就是另外一個錯誤!!見git)。在共享數據時,可能很容易將數據文件添加到版本控制中。這對於很是小的文件是能夠的,可是 git 沒有針對數據進行優化,尤爲是大文件。app
git add data.csv
複製代碼
解決方案:使用第一條中提到的工具來存儲和共享數據。若是你真的想要用版本控制系統去管理數據,請參閱d6tpipe,DVC 和 Git 大文件存儲。
關於數據的問題夠多了,接下來讓咱們談談實際的代碼!因爲你在學習編碼時第一個學到的就是函數,所以數據科學代碼主要被組織爲一系列線性運行的函數。這樣會致使一些問題,請參閱機器學習代碼出問題的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'])
複製代碼
**解決方案:**數據科學代碼不是對函數進行線性連接,而是更好地寫爲一組具備依賴關係的任務。使用 d6tflow 或 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 能夠幫你把不少你認爲可能須要循環的工做矢量化。
隨着數據、參數或用戶輸入的變化,你的代碼可能會發生異常中斷,你可能不會注意這點,可是這可能致使輸出錯誤,若是有人根據你的輸出作出決定,那麼糟糕的數據將會致使錯誤的決策!
**解決方案:**使用 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?
複製代碼
我明白了,你急着作一些分析。你把事情搞混在一塊兒,把結果交給你的客戶或老闆。而後一個星期後,他們回來講「你能改變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
複製代碼
解決方案:即便在你提供數據分析的代碼以後,也要花費額外的時間來對你的所做所爲進行註釋。你會感謝本身,一樣別人也會這樣作!這使你看起來更像專業人士!
再回到數據,畢竟這是數據科學。就像函數和 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 格式,所以你無需另行處理。
這是一個有爭議的結論:jupyter 筆記本和 CSV 同樣廣泛,不少人都在用它,這並不意味着它是合適的。 Jupyter notebook 形成了上面提到的許多不良軟件工程的習慣,特別是: