由DrivenData提供
為什麼要重視項目結構?
說起資料分析,我們往往會想到報告結果、深入見解或可視化。通常這些最終結果占據了主要地位,是以人們很容易專注于讓結果看起來漂亮而忽略了生成它們的代碼品質。但是,這些最終結果都是以程式設計方式建立的,是以代碼品質仍然很重要!此處我們讨論的不是代碼縮進或格式标準,資料科學的代碼品質的最終标準是正确性和可再現性(reproducibility)。
衆所周知,好的分析通常是随意和偶然探索的結果。各種沒得到結果的探索性實驗和快速測試都是通往好結果道路上的一部分,并且沒有靈丹妙藥可以将資料探索轉變為簡單的線性過程。
一旦開始一個項目,就很難再去思考代碼結構和項目布局了。是以最好從一個幹淨、合乎邏輯的結構開始并一以貫之。我們認為使用這樣的标準化設定是非常有好處的。原因如下:
其他人會感謝你
定義明确的标準項目結構意味着新手無需研究大量文檔就可以了解一項分析。這也意味着他們不一定非得閱讀100%的代碼才知道去哪裡找特定的内容。
組織良好的代碼往往能做到自我記錄(self-documenting),組織結構本身可以在無需太多開銷的情況下為你的代碼提供上下文。人們會是以感謝你,因為他們可以:
● 更輕松地與你在此分析中合作
● 從你對流程和領域的分析中學習
● 對分析得到的結論充滿信心
你可以在任何主流的Web開發架構(如Django或Ruby on Rails)中找到這方面的好例子。在建立一個新的Rails項目之前,沒有人會去思考要在哪個位置放什麼,他們隻是運作rails new來獲得像其他人一樣的标準項目骨架(skeleton)。由于該預設結構在大多數項目中都是合乎邏輯且合理的,是以從未見過該特定項目的人也可以容易地找到各種部件。
另一個很好的例子是類Unix系統的檔案系統層次結構标準(Filesystem Hierarchy Standard)。/ etc目錄有非常特定的目的,就像/ tmp檔案夾一樣,每個人(或多或少)都同意遵守該約定。這意味着Red Hat使用者和Ubuntu使用者都知道在哪裡查找某些類型的檔案,即使他們使用的是對方的系統或者其他任何符合該标準的系統!
理想情況下,當同僚打開您的資料科學項目時,也應該如此。
你會感謝自己
你嘗試過重制幾個月前甚至幾年前做的分析嗎?你可能編寫了代碼,但現在卻不知道是否應該使用make_figures.py.old,make_figures_working.py或者new_make_figures01.py來完成工作。以下是我們的一些問題:
● 在開始之前,是否應該主動把X列加入到資料中?還是說其中某個notebook可以完成這一步?
● 想一想,在運作繪圖代碼之前我們必須首先運作哪個notebook:它是“過程資料”還是“幹淨資料”?
● 地理圖形中所用的shapefiles是從哪下載下傳的?
● 等類似問題
這些問題讓人頭疼,并且是無組織項目的症狀。良好的項目結構應該讓人很容易回到舊時的工作,例如分離關注點,将分析抽象為DAG,以及版本控制等實踐。
沒有任何限制
不贊同某些預設檔案夾名稱?正在做一個不标準且與目前結構不完全比對的項目?更願意使用與(少數)預設包不同的包?
去吧!這是一種輕量級結構,旨在成為許多項目的良好起點。正如PEP 8所說:
項目内部的一緻性更為重要。一個子產品或功能内部的一緻性是最重要的。...但是,要知道何時不一緻,有時風格指南建議并不适用。如有疑問,請用你的最佳判斷。檢視其他示例并确定最佳效果。并且不要猶豫去提問!
開始
我們為Python項目建立了一個資料科學cookiecutter模闆。您的分析不一定要在Python中,但模闆确實提供了一些Python樣闆,您可能想要删除它們(例如,在src檔案夾中,以及docs中的Sphinx文檔架構)。
需求
● Python 2.7 或 3.5
● cookiecutter Python package >= 1.4.0: pip install cookiecutter
開始一個新項目
啟動新項目隻需在指令行中運作如下指令。無需先建立目錄,cookiecutter将為您完成。
cookiecutter
https://github.com/drivendata/cookiecutter-data-science
示例
原文中是一段視訊,建議從原文連結中觀看。
原文連結:
https://www.kdnuggets.com/2018/07/cookiecutter-data-science-organize-data-project.html
目錄結構
├── LICENSE
├── Makefile <- Makefile with commands like `make data` or `make train`
├── README.md <- The top-level README for developers using this project.
├── data
│ ├── external <- Data from third party sources.
│ ├── interim <- Intermediate data that has been transformed.
│ ├── processed <- The final, canonical data sets for modeling.
│ └── raw <- The original, immutable data dump.
│
├── docs <- A default Sphinx project; see sphinx-doc.org for details
├── models <- Trained and serialized models, model predictions, or model summaries
├── notebooks <- Jupyter notebooks. Naming convention is a number (for ordering),
│ the creator's initials, and a short `-` delimited description, e.g.
│ `1.0-jqp-initial-data-exploration`.
├── references <- Data dictionaries, manuals, and all other explanatory materials.
├── reports <- Generated analysis as HTML, PDF, LaTeX, etc.
│ └── figures <- Generated graphics and figures to be used in reporting
├── requirements.txt <- The requirements file for reproducing the analysis environment, e.g.
│ generated with `pip freeze > requirements.txt`
├── src <- Source code for use in this project.
│ ├── __init__.py <- Makes src a Python module
│ │
│ ├── data <- Scripts to download or generate data
│ │ └── make_dataset.py
│ ├── features <- Scripts to turn raw data into features for modeling
│ │ └── build_features.py
│ ├── models <- Scripts to train models and then use trained models to make
│ │ │ predictions
│ │ ├── predict_model.py
│ │ └── train_model.py
│ └── visualization <- Scripts to create exploratory and results oriented visualizations
│ └── visualize.py
└── tox.ini <- tox file with settings for running tox; see tox.testrun.org
觀點
項目結構中隐含着一些觀點,這些觀點源于我們在資料科學項目合作時可行的和不可行的工作經驗。一些觀點是關于工作流程的,一些是關于提高效率的工具的。以下是該項目所依據的一些信念,如果您有想法,請提供或分享。
資料是不可變的
不要編輯原始資料,尤其不要手動編輯,也不要在Excel中編輯。不要覆寫原始資料。不要儲存多個版本的原始資料。将資料(及其格式)視為不可變的。你編寫的代碼應該讓原始資料通過分析流程管道并得到最終分析。沒必要每次想要建立一個新計算時都運作所有步驟(請參閱Analysis是DAG),但是任何人都應該能夠僅使用src中的代碼和data /raw中的資料來重制分析結果。
此外,如果資料是不可變的,則它不需要像代碼那樣進行源代碼控制。是以,預設情況下,data檔案夾包含在.gitignore檔案中。如果你有少量很少會被更改的資料,你可能希望将資料包含在repo中。目前Github會警告檔案是否超過50MB并且拒絕超過100MB的檔案。用于存儲/同步大型資料的一些其他方案包括同步工具(例如,s3cmd的AWS S3,Git Large File Storage,Git Annex和dat)。目前預設情況下,我們請求一個S3 bucket并使用AWS CLI将data檔案夾中的資料與伺服器同步。
Notebooks用于探索和交流
Jupyter notebook, Beaker notebook, Zeppelin和其他互動式程式設計工具對于探索性資料分析(EDA)來說是非常高效的。然而,這些工具對重制分析而言效果較差。 當我們在工作中使用notebook時,我們經常細分notebook的檔案夾。例如,notebook/exploration包括初始探索,而notebook/report包含更漂亮的工作,并可以作為html格式導出到report目錄。
由于notebooks挑戰了源代碼控制的目标(例如,json的差異通常不是人類可讀的,并且幾乎不可能合并),我們不建議直接在Jupyter notebooks上與其他人合作。為了有效的使用notebooks,這裡有兩個建議:
● 遵守一種命名習慣,可以展現作者以及所做分析的順序。我們使用這種格式: <step>-<ghuser>-<description>.ipynb(例如,0.3-bull-visualize-distribution.ipynb)。
● 重構某些好的部分。完成相同任務的代碼不要寫在多個notebook中。如果是一個資料預處理任務,放入處理管道并把代碼寫在src/data/make_dataset.py中,并且從data/interim中加載資料。如果是有用的工具代碼,重構到src中。
譯者注:用文本編輯器打開jupyter notebook的檔案,可以看到其本質上是一個json格式的檔案,是以這裡作者說很難使用Git去diff或merge不同版本的notebook代碼,不過目前已有工具緻力于解決這個問題,例如nbdime。
預設情況我們把項目轉換成一個python包(見setup.py檔案)。你可以導入自己的代碼,并且在notebook中使用,方法如下:
# OPTIONAL: Load the "autoreload" extension so that code can change
%load_ext autoreload
# OPTIONAL: always reload modules so that as you change code in src, it gets loaded
%autoreload 2
from src.data import make_dataset
分析就是DAG
在分析中,你常常會有一些運作時間很長的步驟,比如預處理資料或者訓練模型。如果這些步驟已經運作過了(并且你已經将輸出儲存在了某處,例如data/interim目錄),那你肯定不想每次都等待它們重新運作。我們更喜歡用make來管理彼此依賴的步驟,尤其是運作時間很長的步驟。Make是基于Unix的平台上的常用工具(可用于Windows)。遵守make官方文檔, Makefile conventions和portability guide将幫助確定你的Makefile在各個系統中有效工作。這是一些入門示例。許多從事資料工作的人都使用make作為他們的首選工具,其中就包括Mike Bostock。
還有其他用來管理使用Python而不是DSL(領域特定語言)編寫的DAGs的工具(例如,Paver,Luigi,Airflow,Snakemake,Ruffus或Joblib)。如果它們更适合您的分析,請随意使用。
從環境開始建構
重制某個分析的第一步通常是重制它運作的計算環境。你需要相同的工具,相同的庫和相同的版本,以使一切都很好地協同工作。
一個有效的方法是使用virtualenv(我們建議使用virtualenvwrapper來管理virtualenvs)。通過列舉repo中的所有需求(我們包含一個requirements.txt檔案),你可以輕松跟蹤用于重制分析所需的包。以下是一個不錯的工作流程:
● 運作mkvirtualenv建立新項目
● pip install分析所需的包
● 運作pip freeze > requirements.txt以确定用于重制分析的确切包版本
● 如果你發現需要安裝其他軟體包,請再次運作pip freeze > requirements.txt并将更改送出到版本控制。
如果你對重新建立環境有更複雜的要求,請考慮基于虛拟機的方法,如Docker或Vagrant。這兩個工具都使用基于文本的格式(分别為Dockerfile和Vagrantfile),你可以輕松添加到源代碼控制中,以描述如何建立滿足需求的虛拟機。
密碼和配置不要加入版本控制
你肯定不想在Github上洩露你的AWS密鑰或Postgres使用者名和密碼。不再贅述,請看關于這一點的Twelve Factor App。這是一種方法:
将您的機密和配置變量存儲在一個特殊檔案中
在項目根目錄中建立一個.env檔案。感謝.gitignore,永遠不要把該檔案送出到版本控制repo中。以下是一個例子:
# example .env file
DATABASE_URL=postgres://username:password@localhost:5432/dbname
AWS_ACCESS_KEY=myaccesskey
AWS_SECRET_ACCESS_KEY=mysecretkey
OTHER_VARIABLE=something
使用包自動加載這些變量
如果檢視src / data / make_dataset.py中的存根腳本,它使用了一個名為python-dotenv的包将此檔案中的所有條目作為環境變量加載,以便可以使用os.environ.get通路它們。這是一個改編自python-dotenv文檔的示例片段:
# src/data/dotenv_example.py
import os
from dotenv import load_dotenv, find_dotenv
# find .env automagically by walking up directories until it's found
dotenv_path = find_dotenv()
# load up the entries as environment variables
load_dotenv(dotenv_path)
database_url = os.environ.get("DATABASE_URL")
other_variable = os.environ.get("OTHER_VARIABLE")
AWS CLI配置
當使用Amazon S3存儲資料時,有一個簡單的方法來管理AWS通路,即把通路keys設定為環境變量。但是在一台機器上管理多個keys(例如,同時有多個項目)時,最好還是使用一個憑證檔案(credentials file),通常放在~/.aws/credentials,該檔案看起來像這樣:
[default]
aws_access_key_id=myaccesskey
aws_secret_access_key=mysecretkey
[another_project]
aws_access_key_id=myprojectaccesskey
aws_secret_access_key=myprojectsecretkey
你可以在初始化項目時添加名稱。假設未設定合适的環境變量,則使用預設的配置。
保守地更改預設檔案夾結構
為了使這種結構廣泛适用于不同類型的項目,我們認為最好的方法是對于你自己的項目而言,你可以自由更改檔案夾,但在改變用于所有項目的預設結構時要保守。
我們專門為添加,删減,重命名或移動檔案夾的問題建立了一個檔案夾布局标簽。 更一般地說,我們還建立了一個需求讨論标簽,用于在實施之前應該進行仔細讨論和廣泛支援的問題。
貢獻
Cookiecutter資料科學項目有點武斷,但不怕出錯。最佳實踐總在改變,工具一直在發展,我們從中吸取了教訓。該項目的目标是使啟動、建構和共享一個分析更加容易。我們鼓勵提出請求和送出問題。我們很想知道什麼對你有用,什麼沒用。
如果你使用Cookiecutter資料科學項目,請連結回此頁面或給我們一個贊,并讓我們知道!
相關項目和參考連結
項目結構和可再現性更多地在R研究社群中被讨論。以下是一些項目和部落格文章,如果你使用R工作則可能會幫到你。
● Project Template - An R data analysis template
● "Designing projects" on Nice R Code
● "My research workflow" on Carlboettifer.info
● "A Quick Guide to Organizing Computational Biology Projects" in PLOS Computational Biology
最後,非常感謝Cookiecutter項目(github),它幫助我們花更少的時間思考和編寫樣闆檔案,進而花更多的時間去完成工作。
原文釋出時間為:2018-09-27
本文作者:kdnuggets
本文來自雲栖社群合作夥伴“
資料派THU”,了解相關資訊可以關注“
”。