放研究工作流實(shí)操指南:從數(shù)據(jù)版本控制到可復(fù)現(xiàn)論文)
不少朋友看到“OpenResearch”這個(gè)詞第一反應(yīng)是某個(gè)具體的研究項(xiàng)目或者是某個(gè)高校實(shí)驗(yàn)室的代號(hào)。其實(shí)往大了說(shuō)它更像是一種正在席卷全球科研圈的方法論和工具鏈組合用開(kāi)放源代碼的思路去做研究把論文、數(shù)據(jù)、代碼、實(shí)驗(yàn)記錄統(tǒng)統(tǒng)攤開(kāi)來(lái)曬在陽(yáng)光下。往小了說(shuō)它也是一批具體開(kāi)源項(xiàng)目的集合幫助你從文獻(xiàn)管理、實(shí)驗(yàn)記錄到數(shù)據(jù)分析和論文寫(xiě)作形成一條完全透明、可復(fù)現(xiàn)的流水線。這篇文章不只是解釋概念我打算把它當(dāng)作一份“實(shí)踐地圖”來(lái)寫(xiě)聊聊開(kāi)放研究到底解決了什么痛點(diǎn)有哪些核心工具能直接上手以及我踩過(guò)幾次坑之后總結(jié)出的避坑要點(diǎn)。無(wú)論你是研究生、剛進(jìn)實(shí)驗(yàn)室的科研助理還是純粹對(duì)科研過(guò)程好奇的技術(shù)愛(ài)好者照著這篇文章的路徑走一遍都能搭起一套屬于你自己的開(kāi)放研究工作流。1. OpenResearch到底在“開(kāi)”什么先聊一個(gè)最基本的問(wèn)題開(kāi)放研究開(kāi)放的核心對(duì)象到底是什么很多人以為開(kāi)放研究就是“論文免費(fèi)下載”那只是冰山一角。開(kāi)放研究真正想撬動(dòng)的是整個(gè)知識(shí)生產(chǎn)鏈條的透明度。鏈條的第一環(huán)是研究問(wèn)題和假設(shè)第二環(huán)是實(shí)驗(yàn)設(shè)計(jì)和數(shù)據(jù)采集第三環(huán)是數(shù)據(jù)分析和代碼第四環(huán)是論文寫(xiě)作和同行評(píng)審最后一環(huán)才是出版和傳播。傳統(tǒng)模式下除了最后一環(huán)的最終論文前四環(huán)基本都鎖在抽屜里審稿人看不到、同行看不到、社會(huì)公眾更看不到。OpenResearch的思路是把前四環(huán)也一并打開(kāi)。這帶來(lái)的直接好處有三層。第一層是可復(fù)現(xiàn)性。劍橋大學(xué)曾經(jīng)做過(guò)一項(xiàng)統(tǒng)計(jì)心理學(xué)和經(jīng)濟(jì)學(xué)領(lǐng)域有相當(dāng)比例發(fā)表過(guò)的論文在別人手里無(wú)法復(fù)現(xiàn)出同樣的結(jié)果。不是因?yàn)樵旒俣且驗(yàn)樵紨?shù)據(jù)、分析腳本、參數(shù)設(shè)置根本沒(méi)公開(kāi)別人無(wú)從下手。第二層是協(xié)作效率。當(dāng)數(shù)據(jù)和代碼托管在公開(kāi)平臺(tái)上任何人發(fā)現(xiàn)bug或者想到更好的分析方法可以直接提Pull Request像給開(kāi)源軟件貢獻(xiàn)代碼一樣給論文貢獻(xiàn)分析這種協(xié)作模式在傳統(tǒng)科研里幾乎不可想象。第三層是學(xué)術(shù)公平。發(fā)展中國(guó)家的小實(shí)驗(yàn)室訂閱不起頂刊數(shù)據(jù)庫(kù)但開(kāi)放研究讓核心數(shù)據(jù)和預(yù)印本免費(fèi)可得等于把知識(shí)壁壘拉低了一截。用一個(gè)生活化的比喻來(lái)說(shuō)傳統(tǒng)科研像私房菜大廚把菜端上來(lái)你只能看到成品色香味但用了什么火候、什么調(diào)料、中間有沒(méi)有翻車全憑大廚一面之詞開(kāi)放研究像“云廚房直播做菜”從洗菜切菜到出鍋裝盤(pán)全程可見(jiàn)你想學(xué)還能直接拿同一份菜譜在自己廚房里復(fù)刻一遍。這樣“做菜過(guò)程”本身也成了知識(shí)資產(chǎn)而不是只有“那盤(pán)菜”才算成果。所以當(dāng)你聽(tīng)到OpenResearch這個(gè)概念時(shí)不要只把它理解成一堆開(kāi)放獲取期刊的名單它本質(zhì)上是一種科研生產(chǎn)關(guān)系的重構(gòu)。它不要求每個(gè)研究者都變成程序員但它要求每個(gè)研究者具備“把過(guò)程記錄下來(lái)并共享出去”的意識(shí)和能力。1.1 從Open Access到Open Research的進(jìn)化邏輯要理解OpenResearch得先分清兩個(gè)經(jīng)常被混為一談的詞Open Access開(kāi)放獲取和Open Research開(kāi)放研究。開(kāi)放獲取是開(kāi)放研究的前置階段它關(guān)注的核心是“論文本身能不能免費(fèi)讀”。最有名的行動(dòng)是柏林宣言和布達(dá)佩斯開(kāi)放獲取倡議它們推動(dòng)了數(shù)千種期刊轉(zhuǎn)向開(kāi)放獲取模式。國(guó)內(nèi)讀者最熟悉的例子是Sci-Hub雖然它的法律爭(zhēng)議很大但它把“論文應(yīng)該免費(fèi)讀”這個(gè)訴求推到了大眾面前。開(kāi)放獲取解決的是知識(shí)消費(fèi)端的公平問(wèn)題也就是“讀得起”。開(kāi)放研究則往前走了一大步它關(guān)心“研究過(guò)程能不能公開(kāi)查”。光讀論文還不夠還得能拿到數(shù)據(jù)、腳本、實(shí)驗(yàn)材料清單、倫理審批記錄、同行評(píng)審意見(jiàn)甚至包括“被斃掉”的失敗實(shí)驗(yàn)。最典型的表現(xiàn)形式就是注冊(cè)報(bào)告Registered Report研究者在做實(shí)驗(yàn)之前先把研究問(wèn)題和分析方法寫(xiě)成預(yù)注冊(cè)文檔提交給期刊期刊先審方案方案通過(guò)就原則上接受論文不管實(shí)驗(yàn)結(jié)果是什么。這種做法直接打擊了所謂的“文件抽屜效應(yīng)”——很多陰性結(jié)果因?yàn)椴弧捌痢倍绘i在抽屜里導(dǎo)致整個(gè)領(lǐng)域的知識(shí)體系被陽(yáng)性結(jié)果污染。從開(kāi)放獲取到開(kāi)放研究本質(zhì)上是把科研的評(píng)價(jià)單元從“最終論文”前移到“整個(gè)流程”。這種進(jìn)化不是某一個(gè)機(jī)構(gòu)推動(dòng)的而是一系列基礎(chǔ)設(shè)施成熟后的必然結(jié)果Git和GitHub讓代碼共享毫無(wú)門(mén)檻Zenodo和Figshare讓數(shù)據(jù)和附件有了穩(wěn)定的DOI編號(hào)Jupyter Notebook和R Markdown讓“分析代碼圖表解釋文字”能揉在同一個(gè)文檔里Overleaf讓LaTeX寫(xiě)作協(xié)作變得像Google Docs一樣順滑。我自己的體會(huì)是很多人一聽(tīng)“開(kāi)放”兩個(gè)字就緊張覺(jué)得這是道德綁架好像不把全部家底掏出來(lái)就不配做科研。其實(shí)真不是這樣。開(kāi)放是有梯度的你可以在論文投稿時(shí)附帶數(shù)據(jù)也可以把代碼托管到GitHub還可以更進(jìn)一步托管整個(gè)實(shí)驗(yàn)環(huán)境比如Docker鏡像一步一步來(lái)只要比“啥都不開(kāi)”前進(jìn)一小步整個(gè)科研生態(tài)都會(huì)因此受益。1.2 開(kāi)放研究適合哪些人和團(tuán)隊(duì)回到實(shí)踐層面我接觸到的情況是會(huì)認(rèn)真搭建開(kāi)放研究工作流的人通常集中在這么幾類第一類是博士和青年教師。他們面臨最直接的考核壓力論文數(shù)量、引用量都是硬指標(biāo)。開(kāi)放研究對(duì)他們而言不僅是“道德選擇”更是“傳播策略”把數(shù)據(jù)和代碼公開(kāi)的論文引用率普遍比同類封閉論文高出不少這在多個(gè)實(shí)證研究里都被驗(yàn)證過(guò)。第二類是數(shù)據(jù)密集型的計(jì)算科學(xué)團(tuán)隊(duì)。生物信息、地理信息、計(jì)算化學(xué)、機(jī)器學(xué)習(xí)這些領(lǐng)域研究成果本身就是代碼和數(shù)據(jù)閉著反而會(huì)拖累團(tuán)隊(duì)內(nèi)部協(xié)作。第三類是真正想讓研究產(chǎn)生社會(huì)影響的人。比如做環(huán)境監(jiān)測(cè)、公共衛(wèi)生、教育政策的研究者他們的成果要被地方政府或公益組織采用首要前提就是對(duì)方能看懂并驗(yàn)證你的數(shù)據(jù)和分析過(guò)程封閉論文基本做不到這一點(diǎn)。反過(guò)來(lái)也有一類人目前不適合強(qiáng)行擁抱開(kāi)放研究涉及商業(yè)機(jī)密的企業(yè)實(shí)驗(yàn)室涉及個(gè)人隱私的醫(yī)療數(shù)據(jù)研究以及涉及國(guó)家安全等敏感領(lǐng)域的研究。這類研究的開(kāi)放邊界需要非常謹(jǐn)慎不是簡(jiǎn)單把所有文件丟到GitHub就完事。后文我會(huì)專門(mén)講一講在合規(guī)框架下怎樣做“有限度開(kāi)放”。2. 搭建一套OpenResearch工作流的頂層設(shè)計(jì)說(shuō)了這么多理念接下來(lái)進(jìn)入實(shí)操層面。別急著下載工具先花十分鐘把整體架構(gòu)想清楚不然很容易裝了一堆軟件卻不知道怎么配合。我給自己的團(tuán)隊(duì)設(shè)計(jì)過(guò)一套工作流核心原則是每一個(gè)環(huán)節(jié)都產(chǎn)出公開(kāi)可追蹤的“證據(jù)”。具體來(lái)說(shuō)整個(gè)科研生命周期被我切成五個(gè)階段每個(gè)階段都有對(duì)應(yīng)的開(kāi)放工具和交付物。第一階段是選題與預(yù)注冊(cè)。研究問(wèn)題確定后先寫(xiě)一份預(yù)注冊(cè)文檔說(shuō)明研究假設(shè)、樣本量計(jì)算、主要和次要結(jié)局指標(biāo)、分析方法。交付物是一份帶有時(shí)間戳的版本化文檔可以放到OSFOpen Science Framework或自己搭建的Git倉(cāng)庫(kù)里。第二階段是數(shù)據(jù)采集與清洗。這個(gè)階段的關(guān)鍵是原始數(shù)據(jù)絕對(duì)不能動(dòng)所有的清洗和轉(zhuǎn)換操作要用腳本完成。交付物是原始數(shù)據(jù)目錄只讀屬性和清洗腳本數(shù)據(jù)文件建議用CSV或Parquet等開(kāi)放格式避免用SPSS的.sav或MATLAB的.mat這種專有格式替未來(lái)的自己和合作者省點(diǎn)力氣。第三階段是分析與建模。每一個(gè)分析步驟都要有可重跑的腳本或Notebook對(duì)關(guān)鍵結(jié)果保留運(yùn)行日志。交付物是Jupyter Notebook或R Markdown文件、依賴環(huán)境說(shuō)明、隨機(jī)種子記錄。第四階段是論文寫(xiě)作。用可版本控制的格式寫(xiě)作Markdown或LaTeX都比Word合適配合Git能看清每一處修改是誰(shuí)在什么時(shí)候做的審稿意見(jiàn)也能逐條對(duì)應(yīng)到修改記錄。第五階段是發(fā)布與歸檔。論文預(yù)印本放到arXiv、bioRxiv或SocArXiv數(shù)據(jù)和代碼歸檔到Zenodo獲取DOI必要時(shí)把整個(gè)軟件環(huán)境打包成Docker鏡像。這一步做完任何人理論上都能從零開(kāi)始把你的研究完整復(fù)現(xiàn)一遍。聽(tīng)起來(lái)復(fù)雜但真正落地時(shí)你只需要把精力集中在少數(shù)幾個(gè)“樞紐工具”上。下面我把每一個(gè)環(huán)節(jié)的工具選型和配置方式拆開(kāi)講。2.1 文獻(xiàn)管理Zotero依然是我最推薦的開(kāi)源方案文獻(xiàn)管理是開(kāi)放研究工作流里最容易被低估的環(huán)節(jié)。很多人用的是EndNote或NoteExpress但它們?cè)凇伴_(kāi)放”這件事上有個(gè)天然短板文獻(xiàn)庫(kù)文件是閉源格式換軟件等于換一套生態(tài)想在團(tuán)隊(duì)里協(xié)作同步也很麻煩。Zotero是我從研究生階段一直用到現(xiàn)在的工具大概用了七八年期間試過(guò)Mendeley、ReadCube Papers和EndNote最終都換回了Zotero。原因很簡(jiǎn)單第一它完全開(kāi)源免費(fèi)數(shù)據(jù)存在本地SQLite數(shù)據(jù)庫(kù)里任何軟件都能直接讀取不存在“綁架”問(wèn)題第二插件生態(tài)極其豐富能自動(dòng)抓取網(wǎng)頁(yè)元數(shù)據(jù)、和Overleaf聯(lián)動(dòng)引用文獻(xiàn)、把文獻(xiàn)庫(kù)同步到WebDAV或自建服務(wù)器第三它在處理中文文獻(xiàn)時(shí)細(xì)節(jié)做得好CNKI條目也能正確抓取作者和期刊信息。安裝Zotero之后的第一個(gè)動(dòng)作我建議設(shè)置“附件存儲(chǔ)目錄”和“同步策略”。打開(kāi)設(shè)置面板把數(shù)據(jù)目錄放到一個(gè)堅(jiān)果云或WebDAV同步的文件夾里這樣換電腦時(shí)文獻(xiàn)庫(kù)能一鍵恢復(fù)。第二個(gè)動(dòng)作是安裝兩個(gè)必裝插件Better BibTeX用來(lái)生成穩(wěn)定的引用鍵ZotFile用來(lái)把PDF附件重命名并移動(dòng)到統(tǒng)一目錄。如果說(shuō)Zotero是一座文獻(xiàn)圖書(shū)館這兩個(gè)插件就是圖書(shū)館的編目系統(tǒng)和文件傳輸帶缺一個(gè)都會(huì)感覺(jué)別扭。最進(jìn)階的用法是把Zotero的文獻(xiàn)庫(kù)和Quarto或LaTeX寫(xiě)作鏈打通。Better BibTeX插件會(huì)自動(dòng)生成一份.bib文件你在Markdown里像寫(xiě)代碼一樣引用文獻(xiàn)時(shí)引用鍵直接匹配Zotero條目編譯生成的參考文獻(xiàn)表一字不差。整個(gè)流程從“查文獻(xiàn)”到“寫(xiě)論文”不需要手動(dòng)復(fù)制粘貼一條引用信息這種體驗(yàn)一旦習(xí)慣就再也回不到Word手輸引用的時(shí)代了。2.2 數(shù)據(jù)管理用DataLad或DVC管理數(shù)據(jù)和代碼的版本科研數(shù)據(jù)和軟件代碼有一個(gè)本質(zhì)區(qū)別代碼是文本文件用Git管理天經(jīng)地義數(shù)據(jù)往往是大文件可能有幾千個(gè)GB直接塞進(jìn)Git倉(cāng)庫(kù)會(huì)把倉(cāng)庫(kù)撐爆。所以數(shù)據(jù)管理需要專門(mén)的工具我試過(guò)的方案里有三個(gè)值得認(rèn)真考慮DataLad、DVC和Git LFS。Git LFSLarge File Storage)是GitHub官方推出的擴(kuò)展方案思路是讓Git在提交大文件時(shí)只記錄文件指針實(shí)際內(nèi)容上傳到LFS服務(wù)器。它在單個(gè)文件不超過(guò)幾百M(fèi)B時(shí)很好用但每月的流量有配額限制免費(fèi)額度用完就得付費(fèi)對(duì)動(dòng)輒幾十GB的視頻或影像數(shù)據(jù)并不友好。DVCData Version Control)本質(zhì)上是“Git的副駕駛”。它不會(huì)替代Git而是把數(shù)據(jù)文件路徑記錄在Git倉(cāng)庫(kù)里數(shù)據(jù)本體存放在本地或云端的存儲(chǔ)桶里。當(dāng)你切換Git分支時(shí)DVC會(huì)根據(jù)記錄自動(dòng)檢出對(duì)應(yīng)的數(shù)據(jù)版本。對(duì)機(jī)器學(xué)習(xí)項(xiàng)目特別友好模型文件、數(shù)據(jù)集、訓(xùn)練參數(shù)都能精確追溯。DataLad是我目前最偏愛(ài)的選擇因?yàn)樗菍iT(mén)為神經(jīng)科學(xué)和心理學(xué)研究設(shè)計(jì)的原生支持“數(shù)據(jù)即Git子模塊”的概念。它不僅能版本化數(shù)據(jù)還能從遠(yuǎn)程數(shù)據(jù)集獲取數(shù)據(jù)子集適合大型公開(kāi)數(shù)據(jù)集的多團(tuán)隊(duì)協(xié)作。它的學(xué)習(xí)曲線比DVC陡峭一些但一旦理解“數(shù)據(jù)集是可以嵌套的”這個(gè)思想能力上限會(huì)高很多。走一條最穩(wěn)妥的入門(mén)路徑我建議從DVC入手。安裝很簡(jiǎn)單用pip安裝然后在項(xiàng)目根目錄初始化把原始數(shù)據(jù)目錄加入管理每次改動(dòng)數(shù)據(jù)后跑一遍dvc add和dvc push。我自己的習(xí)慣是把DVC和Git配合使用代碼走Git數(shù)據(jù)走DVC兩者靠.dvc文件關(guān)聯(lián)。這樣做的好處是別人克隆你的Git倉(cāng)庫(kù)后只需要一條dvc pull命令就能把你全部的數(shù)據(jù)資產(chǎn)拉到本地整個(gè)復(fù)現(xiàn)過(guò)程非常順暢。2.3 電子實(shí)驗(yàn)記錄讓實(shí)驗(yàn)過(guò)程像代碼一樣可追溯實(shí)驗(yàn)記錄本在傳統(tǒng)科研里是紙質(zhì)手寫(xiě)本重要實(shí)驗(yàn)要蓋章、簽字、存檔。但在計(jì)算驅(qū)動(dòng)的研究里紙質(zhì)實(shí)驗(yàn)本根本記錄不了腳本的一步步演化過(guò)程。所以現(xiàn)在越來(lái)越多的團(tuán)隊(duì)開(kāi)始用電子實(shí)驗(yàn)記錄本這里要區(qū)分兩個(gè)層面ELNElectronic Lab Notebook和計(jì)算工作流版本控制。正式的ELN產(chǎn)品有開(kāi)源方案比如開(kāi)源界的eLabFTW和RSpace。它們提供帶時(shí)間戳的記錄頁(yè)面、實(shí)驗(yàn)?zāi)0?、?quán)限管理、電子簽名適合化學(xué)、生物這類濕實(shí)驗(yàn)為主的實(shí)驗(yàn)室。我所在的領(lǐng)域是計(jì)算方向的更常用的其實(shí)是“Markdown Git”組合每天新建一個(gè)Markdown文件記錄當(dāng)天做了什么實(shí)驗(yàn)、跑了什么參數(shù)、得到什么結(jié)果、遇見(jiàn)了什么報(bào)錯(cuò)文件名按日期命名每周提交一次到Git倉(cāng)庫(kù)。很多程序員朋友聽(tīng)到這里可能會(huì)笑這不就是寫(xiě)開(kāi)發(fā)日志嗎確實(shí)本質(zhì)上是同一回事。但科研和開(kāi)發(fā)有個(gè)重要區(qū)別科研的記錄必須保留“失敗分支”。做軟件開(kāi)發(fā)時(shí)你通常只關(guān)注最終能跑的代碼路徑做科研時(shí)那些“跑不通的參數(shù)組合”往往是下一個(gè)正確決策的重要依據(jù)。所以我給自己定了一條紀(jì)律無(wú)論實(shí)驗(yàn)成功還是失敗都在當(dāng)天記錄里寫(xiě)清楚“今天嘗試了什么”“為什么這么嘗試”“結(jié)果是什么”“下一步改什么”。這套方法堅(jiān)持半年后回頭翻記錄你會(huì)發(fā)現(xiàn)以前模棱兩可的決策來(lái)源其實(shí)都清清楚楚寫(xiě)在某一天的記錄里。2.4 寫(xiě)作與發(fā)布Quarto是一條連接分析和寫(xiě)作的捷徑論文寫(xiě)作是整個(gè)流程的“出口”也是最容易讓開(kāi)放研究卡殼的環(huán)節(jié)。很多研究者的痛點(diǎn)在于分析結(jié)果在Notebook里論文在Word里圖表需要手動(dòng)導(dǎo)出后一張張粘貼一旦數(shù)據(jù)更新所有圖表要重新做一遍。這種工作方式不僅低效還容易出錯(cuò)——貼錯(cuò)圖、版本對(duì)不上是家常便飯。我推薦用Quarto來(lái)打通這個(gè)環(huán)節(jié)。Quarto是RStudio團(tuán)隊(duì)推出的開(kāi)源科學(xué)出版系統(tǒng)支持Python、R、Julia和Observable JS等多種語(yǔ)言你可以用純文本格式寫(xiě)論文在文中直接嵌入分析代碼塊編譯時(shí)自動(dòng)執(zhí)行代碼并生成圖表最后輸出為HTML、PDF或Word格式。簡(jiǎn)單說(shuō)論文里每一個(gè)數(shù)字、每一張圖都是從數(shù)據(jù)實(shí)時(shí)計(jì)算出來(lái)的不存在“貼錯(cuò)版本”的問(wèn)題。對(duì)于還沒(méi)用過(guò)Quarto的朋友我提供一個(gè)兩周上手路徑。第一周先別碰論文拿一篇自己的舊文章練手把文字內(nèi)容轉(zhuǎn)成Markdown格式圖表用Quarto的代碼塊重畫(huà)一遍不追求完美只求流程走得通。第二周選一篇計(jì)劃投稿的新論文嘗試用Quarto從零開(kāi)始寫(xiě)重點(diǎn)練習(xí)“參數(shù)化報(bào)告”的寫(xiě)法把樣本選擇標(biāo)準(zhǔn)、統(tǒng)計(jì)閾值、文件名這些要素定義成YAML參數(shù)這樣同一份Quarto文檔改一下參數(shù)就能生成不同分析條件下的不同版本。這套流程熟練后你會(huì)感覺(jué)寫(xiě)論文像在寫(xiě)一份會(huì)自我更新的分析報(bào)告效率提升非常明顯。發(fā)布環(huán)節(jié)國(guó)內(nèi)作者優(yōu)先考慮兩條路徑一是把預(yù)印本放到arXiv、bioRxiv等平臺(tái)上獲得搶跑的公開(kāi)時(shí)間戳二是把最終數(shù)據(jù)和代碼歸檔到Zenodo獲取DOI后寫(xiě)入論文的Data Availability Statement。如果論文是雙盲評(píng)審記得預(yù)印本發(fā)布和投稿時(shí)間要錯(cuò)開(kāi)具體策略我放在常見(jiàn)問(wèn)題章節(jié)里詳細(xì)說(shuō)。3. 一個(gè)能直接抄作業(yè)的實(shí)操案例水文觀測(cè)數(shù)據(jù)的開(kāi)放研究全流程理論講太多沒(méi)用我拿一個(gè)簡(jiǎn)化但完整的具體案例把上面提到的工具串起來(lái)跑一遍。案例背景是某區(qū)域水文觀測(cè)站積累了10年的日尺度降雨和徑流數(shù)據(jù)我想研究“極端降雨事件對(duì)徑流響應(yīng)時(shí)間的影響”并把這個(gè)研究做成一個(gè)任何人都能復(fù)現(xiàn)的開(kāi)放項(xiàng)目。3.1 第一步建立項(xiàng)目目錄結(jié)構(gòu)目錄結(jié)構(gòu)是整個(gè)流程的骨架我的習(xí)慣是一開(kāi)始就按功能分好目錄避免后期一團(tuán)亂麻。下面是一個(gè)經(jīng)過(guò)多次迭代后我比較滿意的目錄結(jié)構(gòu)extreme-rainfall-runoff/ ├── README.md ├── LICENSE ├── data/ │ ├── raw/ # 原始數(shù)據(jù)只讀權(quán)限 │ ├── processed/ # 清洗后的數(shù)據(jù) │ └── metadata/ ├── code/ │ ├── 01_download_data.py │ ├── 02_clean_data.py │ ├── 03_analysis.py │ └── 04_make_figures.py ├── notebooks/ │ ├── 01_exploration.ipynb │ └── 02_model_diagnostics.ipynb ├── docs/ │ ├── protocol.md # 預(yù)注冊(cè)文檔 │ └── data_dictionary.md # 數(shù)據(jù)字典 ├── paper/ │ ├── manuscript.qmd # 主論文 │ ├── references.bib # 文獻(xiàn)庫(kù) └── environment.yml # 環(huán)境依賴允許我多解釋兩句data/raw目錄一旦放入原始數(shù)據(jù)就設(shè)置成只讀整個(gè)分析過(guò)程只在processed目錄里操作這樣能保證原始數(shù)據(jù)不被污染code目錄里的腳本用數(shù)字前綴標(biāo)明執(zhí)行順序別人克隆項(xiàng)目后照著順序跑一遍就能復(fù)現(xiàn)docs/protocol.md是預(yù)注冊(cè)文檔要記錄研究問(wèn)題和分析方法這個(gè)文件的時(shí)間戳就是“我不作弊”的證據(jù)environment.yml是conda環(huán)境導(dǎo)出文件鎖定所有依賴庫(kù)的版本。3.2 第二步用DVC管理數(shù)據(jù)版本我在項(xiàng)目根目錄執(zhí)行以下命令dvc init dvc add data/raw dvc remote add myremote s3://my-bucket/rainfall-runoff-dvc dvc push這里說(shuō)明一下每個(gè)命令的用途。dvc init初始化DVC環(huán)境dvc add data/raw會(huì)把原始數(shù)據(jù)目錄的元信息寫(xiě)入一個(gè).dvc文件同時(shí)把數(shù)據(jù)內(nèi)容加入DVC的緩存dvc remote add添加一個(gè)遠(yuǎn)程存儲(chǔ)位置可以是S3、阿里云OSS或者本地其他磁盤(pán)dvc push把數(shù)據(jù)推送到遠(yuǎn)程。此后每次有新的原始數(shù)據(jù)進(jìn)來(lái)重復(fù)一遍dvc add和dvc pushGit提交時(shí)連同.dvc文件一起提交。如果哪天發(fā)現(xiàn)某個(gè)分析結(jié)果對(duì)不上你可以用dvc checkout切換到任意歷史版本的數(shù)據(jù)重新跑分析定位問(wèn)題到底出在數(shù)據(jù)更新還是代碼改動(dòng)。這個(gè)能力在傳統(tǒng)工作流里幾乎沒(méi)法實(shí)現(xiàn)。3.3 第三步以提交記錄為時(shí)間軸的實(shí)驗(yàn)管理分析階段我用的是“Notebook用于探索Python腳本用于生產(chǎn)”的模式。探索階段我會(huì)開(kāi)著Jupyter Notebook快速驗(yàn)證各種統(tǒng)計(jì)模型的適用性一旦確認(rèn)某個(gè)分析思路可行就把Notebook里的核心代碼重構(gòu)到code/04_make_figures.py這樣的腳本里保證最終圖表是可重復(fù)生成的。同時(shí)每次跑完一輪完整的分析我會(huì)在Git里打一個(gè)tag命名格式類似analysis_20241013_v1然后在實(shí)驗(yàn)記錄文檔里寫(xiě)下這個(gè)tag對(duì)應(yīng)什么階段、用了哪套參數(shù)、得到了什么結(jié)論。很多人在這一步會(huì)偷懶覺(jué)得“反正代碼都在Git里歷史記錄不會(huì)丟”。但Git歷史只記錄了代碼變更不能直觀告訴你“哪次提交對(duì)應(yīng)論文的哪個(gè)版本”。打tag加實(shí)驗(yàn)記錄文檔等于給時(shí)間線加上了可讀的注釋三個(gè)月后再看也清楚。3.4 第四步用Quarto生成可復(fù)現(xiàn)論文論文主體用Quarto的qmd格式寫(xiě)正文是Markdown圖表用代碼塊直接生成--- title: 極端降雨對(duì)徑流響應(yīng)時(shí)間的影響 author: 你的名字 format: pdf bibliography: references.bib --- ## 引言 正文省略 ## 結(jié)果 我們分析了{(lán){ param site_id }}站點(diǎn)近10年的降雨徑流數(shù)據(jù)。 {python} #| label: fig-response #| fig-cap: 降雨事件與徑流響應(yīng)時(shí)間關(guān)系 import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(data/processed/event_response.csv) fig, ax plt.subplots() ax.scatter(df[rainfall_intensity], df[response_time]) ax.set_xlabel(降雨強(qiáng)度 (mm/h)) ax.set_ylabel(徑流響應(yīng)時(shí)間 (h)) plt.savefig(figures/response_time.png, dpi300)編譯時(shí)執(zhí)行quarto renderQuarto會(huì)自動(dòng)運(yùn)行代碼塊、生成圖表、引用文獻(xiàn)、排版成PDF。如果審稿人要求換一種圖的形式比如把散點(diǎn)圖改成箱線圖我只需要改一下代碼塊的繪圖邏輯然后重新編譯所有相關(guān)圖表和描述文字會(huì)自動(dòng)更新不會(huì)出現(xiàn)正文和圖表對(duì)不上的尷尬。 ### 3.5 第五步發(fā)布?xì)w檔 最后一步也是很多人最容易忽略的一步。論文寫(xiě)完并不代表項(xiàng)目結(jié)束一個(gè)真正開(kāi)放的項(xiàng)目要讓人“接力”得起來(lái)。 我會(huì)做四個(gè)動(dòng)作一是把論文預(yù)印本上傳到arXiv或SocArXiv獲得公開(kāi)時(shí)間戳和預(yù)印本編號(hào)二是把數(shù)據(jù)和代碼打包上傳到Zenodo通過(guò)GitHub和Zenodo的集成自動(dòng)生成版本記錄并分配DOI三是在README里寫(xiě)清楚“如何復(fù)現(xiàn)”克隆倉(cāng)庫(kù)、創(chuàng)建conda環(huán)境、運(yùn)行特定腳本、編譯論文四是把這個(gè)DOI和倉(cāng)庫(kù)鏈接寫(xiě)進(jìn)論文的Data Availability Statement里。 關(guān)于第四步期刊投稿時(shí)如果要求雙盲評(píng)審我的策略是先在投稿系統(tǒng)里勾選“數(shù)據(jù)可用但評(píng)審期間保密”把Git倉(cāng)庫(kù)設(shè)為匿名訪問(wèn)或者把代碼托管到像Anonymous GitHub這樣的匿名平臺(tái)等論文正式接收后再公開(kāi)。這個(gè)操作往往比選任何“開(kāi)放數(shù)據(jù)”選項(xiàng)都關(guān)鍵。 ## 4. 開(kāi)放研究實(shí)踐中的常見(jiàn)坑與排查手冊(cè) 方案再好實(shí)操中總會(huì)踩坑。下面這幾個(gè)問(wèn)題是幾乎每一個(gè)剛開(kāi)始做開(kāi)放研究的人都會(huì)遇到的我把它們整理成了一個(gè)速查表也附帶了我自己的排查思路。 | 問(wèn)題現(xiàn)象 | 常見(jiàn)原因 | 排查與解決思路 | | --- | --- | --- | | 數(shù)據(jù)文件太大Git提交時(shí)卡死 | 沒(méi)有用DVC或Git LFS管理大文件 | 把data目錄從Git中移除改用DVC確認(rèn).dvc文件是文本文件 | | Notebook在別人電腦上跑不通 | 依賴庫(kù)版本不一致 | 用conda導(dǎo)出environment.yml并鎖定版本號(hào)用requirements.txt固定pip依賴 | | 圖表的數(shù)字和論文正文對(duì)不上 | 圖表是手動(dòng)粘貼的沒(méi)有實(shí)時(shí)生成 | 改用Quarto或R Markdown嵌入代碼塊實(shí)現(xiàn)“一處改動(dòng)全文更新” | | 審查結(jié)束后數(shù)據(jù)集被刪除 | 沒(méi)有歸檔到長(zhǎng)久的公共平臺(tái) | 上傳到Zenodo或Figshare這些平臺(tái)承諾長(zhǎng)期保存并分配DOI | | 預(yù)印本時(shí)間早于期刊投稿導(dǎo)致期刊拒稿 | 部分期刊不支持提前公開(kāi)預(yù)印本 | 投稿前查一下期刊的預(yù)印本政策雙盲評(píng)審期刊要特別注意 | | 數(shù)據(jù)里包含個(gè)人隱私信息 | 沒(méi)有做去標(biāo)識(shí)化處理 | 刪除姓名、證件號(hào)、精確坐標(biāo)等直接標(biāo)識(shí)地理數(shù)據(jù)做空間模糊化涉及隱私的問(wèn)卷數(shù)據(jù)只發(fā)布聚合統(tǒng)計(jì) | 這里展開(kāi)說(shuō)幾個(gè)最典型的坑。 ### 4.1 坑一數(shù)據(jù)太大Git倉(cāng)庫(kù)直接罷工 我見(jiàn)過(guò)不少朋友用GitHub管理科研項(xiàng)目一開(kāi)始特別順利代碼提交速度飛快。直到某一天他們把一份幾GB的原始影像數(shù)據(jù)塞進(jìn)了Git倉(cāng)庫(kù)然后一切都變了每次git push要等半小時(shí)GitHub提示倉(cāng)庫(kù)超過(guò)建議大小甚至直接拒絕推送。 解決這個(gè)問(wèn)題最干凈的方案是“從一開(kāi)始就分區(qū)管理”代碼走Git數(shù)據(jù)走DVC兩者之間只通過(guò)文本化的.dvc指針文件關(guān)聯(lián)。如果已經(jīng)踩了坑處理起來(lái)會(huì)有一些麻煩需要用git filter-repo把歷史提交中的大文件徹底抹掉然后重新推送倉(cāng)庫(kù)。注意只是刪除當(dāng)前文件是不夠的Git會(huì)保留歷史中的所有版本倉(cāng)庫(kù)體積不會(huì)變小。 ### 4.2 坑二環(huán)境“能跑”但“復(fù)現(xiàn)不了” 科研項(xiàng)目最尷尬的瞬間是審稿人回信說(shuō)“按照你的README我在我電腦上運(yùn)行到第三步就報(bào)錯(cuò)了”。這往往不是代碼寫(xiě)錯(cuò)而是環(huán)境沒(méi)對(duì)齊Python版本不同、依賴庫(kù)的版本不同、系統(tǒng)庫(kù)缺失都有可能讓“在我機(jī)器上能跑”變成“在你機(jī)器上跑不了”。 最可靠的方案是使用容器技術(shù)把整個(gè)環(huán)境打包。Docker和Singularity是科研領(lǐng)域最常用的兩個(gè)Singularity在HPC集群上更常見(jiàn)因?yàn)樗恍枰猺oot權(quán)限且與集群調(diào)度器集成更好。我一般會(huì)在項(xiàng)目的environment.yml里定義conda環(huán)境然后寫(xiě)一個(gè)Dockerfile把這個(gè)環(huán)境完整地打包成鏡像。這樣做最大的好處是復(fù)現(xiàn)方只需要裝一個(gè)Docker然后run一條命令環(huán)境就一模一樣地跑起來(lái)了。雖然前期學(xué)習(xí)成本高一點(diǎn)但相比“審稿人跑不通”帶來(lái)的損失這點(diǎn)成本完全值得。 ### 4.3 坑三開(kāi)源協(xié)議沒(méi)選對(duì)數(shù)據(jù)被用了還不能聲張 開(kāi)放研究里的“開(kāi)放”不等于“沒(méi)有權(quán)限約束”。代碼、數(shù)據(jù)、文本這三種資產(chǎn)最好分別選擇不同的許可證。代碼通常用MIT、BSD、Apache 2.0或GPL數(shù)據(jù)通常用CC0或CC BY論文文本通常用CC BY。選許可證不是隨便找個(gè)模板復(fù)制要明確“別人能用你的東西做什么、必須滿足什么條件”。 讓我舉一個(gè)真實(shí)的例子我在一次項(xiàng)目里拿到了某機(jī)構(gòu)提供的水文數(shù)據(jù)對(duì)方在公共門(mén)戶上標(biāo)了“開(kāi)放使用”但實(shí)際數(shù)據(jù)包里又夾著一份PDF使用協(xié)議規(guī)定“禁止用于商業(yè)目的”。這就是典型的許可證不清晰。如果不注意這一層貿(mào)然把數(shù)據(jù)整合進(jìn)自己的開(kāi)放項(xiàng)目里后期可能面臨法律糾紛。 在做數(shù)據(jù)發(fā)布前我的自查清單是數(shù)據(jù)來(lái)源有沒(méi)有明確的許可或授權(quán)聲明如果沒(méi)有就只發(fā)布自己采集或明確擁有權(quán)利的數(shù)據(jù)數(shù)據(jù)里有沒(méi)有第三方版權(quán)的內(nèi)容有的話需要先獲得授權(quán)選用的許可協(xié)議是否和期刊、資助方的要求沖突各個(gè)機(jī)構(gòu)對(duì)開(kāi)放許可的要求不完全一樣以資助方的口徑為準(zhǔn)。 ### 4.4 坑四把“公開(kāi)”當(dāng)成“可復(fù)現(xiàn)” 有些項(xiàng)目雖然把所有文件都公開(kāi)了但第三方根本復(fù)現(xiàn)不了。比如公開(kāi)了一份Excel表但沒(méi)說(shuō)明每一列的計(jì)算邏輯公開(kāi)了一份訓(xùn)練好的模型權(quán)重但沒(méi)有提供訓(xùn)練代碼和超參數(shù)公開(kāi)了一個(gè)Notebook但中間狀態(tài)已經(jīng)被手動(dòng)修改過(guò)執(zhí)行順序?qū)Σ簧稀?“公開(kāi)”是手段“可復(fù)現(xiàn)”才是目的。判斷一個(gè)項(xiàng)目是否可復(fù)現(xiàn)我常用一個(gè)“陌生人測(cè)試”讓自己完全不參與這個(gè)項(xiàng)目的同事只憑README和公開(kāi)文件從頭跑一遍完整流程看能不能得到論文里的核心結(jié)果。如果這一步走通了這個(gè)項(xiàng)目才能真正被稱為開(kāi)放研究項(xiàng)目而不是單純把文件掛在網(wǎng)上。 ## 5. 我沉淀下來(lái)的幾條選型和建議 工具選型是一個(gè)動(dòng)態(tài)調(diào)整的過(guò)程沒(méi)有哪一套方案是放之四海而皆準(zhǔn)的。根據(jù)自己的項(xiàng)目類型和團(tuán)隊(duì)背景我對(duì)不同工具有一些親身的體會(huì)和建議。 ### 5.1 關(guān)于“先選工具”還是“先定流程” 我的經(jīng)驗(yàn)是先定流程再選工具。流程是骨架工具是血肉。如果你連“數(shù)據(jù)怎么組織”“分析怎么記錄”“產(chǎn)出怎么發(fā)布”都沒(méi)想清楚裝再多的開(kāi)源工具也只會(huì)讓項(xiàng)目更亂。反過(guò)來(lái)流程一旦確定工具選型就清晰很多需要版本控制就選Git需要管理大文件就選DVC或DataLad需要一體化寫(xiě)作就選Quarto或R Markdown。 在團(tuán)隊(duì)協(xié)作場(chǎng)景下流程比工具更關(guān)鍵。我見(jiàn)過(guò)兩個(gè)團(tuán)隊(duì)用完全一樣的工具套件一個(gè)協(xié)作順暢一個(gè)天天沖突差別就是前者在項(xiàng)目啟動(dòng)第一天就約定了分支策略、命名規(guī)范和數(shù)據(jù)管理流程而后者完全靠個(gè)人自覺(jué)。所以如果要組隊(duì)做開(kāi)放研究建議第一次組會(huì)就拿出一份書(shū)面的“項(xiàng)目操作手冊(cè)”把流程約定下來(lái)。 ### 5.2 關(guān)于開(kāi)放研究的“度”與合規(guī)邊界 我始終強(qiáng)調(diào)開(kāi)放不是目的創(chuàng)造價(jià)值才是。有些數(shù)據(jù)天然不適合完全公開(kāi)比如涉及個(gè)人隱私的醫(yī)療健康數(shù)據(jù)、涉及商業(yè)機(jī)密的行業(yè)調(diào)研數(shù)據(jù)。這類研究的開(kāi)放策略是“有限度開(kāi)放”數(shù)據(jù)本身不公開(kāi)但分析代碼、處理流程、結(jié)果報(bào)告可以公開(kāi)原始數(shù)據(jù)留在受控環(huán)境里需要申請(qǐng)和審批才能獲取。 具體做法上可以參考一些大型生物醫(yī)學(xué)項(xiàng)目的做法數(shù)據(jù)分級(jí)管理一級(jí)數(shù)據(jù)完全公開(kāi)二級(jí)數(shù)據(jù)需要在平臺(tái)注冊(cè)并提交使用申請(qǐng)三級(jí)數(shù)據(jù)則只能在指定的安全計(jì)算環(huán)境內(nèi)分析連下載都不允許。這種模式既保障了開(kāi)放協(xié)作又守住了安全和隱私的底線。 對(duì)于涉及人類被試的研究還有一個(gè)容易被忽視的點(diǎn)知情同意書(shū)里有沒(méi)有寫(xiě)“數(shù)據(jù)將公開(kāi)共享”。如果當(dāng)初收集數(shù)據(jù)時(shí)只告知被試“數(shù)據(jù)僅用于本研究”那后續(xù)是不能直接把原始數(shù)據(jù)公開(kāi)的。這種情況下可以考慮發(fā)布聚合統(tǒng)計(jì)結(jié)果或脫敏后的衍生數(shù)據(jù)并說(shuō)明數(shù)據(jù)共享的邊界。 ### 5.3 關(guān)于長(zhǎng)期維護(hù)與“人走項(xiàng)目涼”的問(wèn)題 學(xué)術(shù)圈人員流動(dòng)快一個(gè)博士生畢業(yè)后他負(fù)責(zé)的項(xiàng)目很可能就沒(méi)人維護(hù)了。開(kāi)放研究項(xiàng)目一旦發(fā)布理論上就屬于公共知識(shí)資產(chǎn)但“發(fā)布”不等于“有人維護(hù)”。如果項(xiàng)目倉(cāng)庫(kù)里的代碼依賴了某個(gè)已經(jīng)停止維護(hù)的庫(kù)或者數(shù)據(jù)更新到一半就斷了后續(xù)使用者的體驗(yàn)會(huì)很快惡化。 我的應(yīng)對(duì)策略有三條一是盡量在論文接收后的一兩個(gè)月內(nèi)把代碼、數(shù)據(jù)、文檔一次性完整歸檔到Zenodo生成快照版本哪怕以后倉(cāng)庫(kù)不再更新快照版的DOI仍然可用這意味著研究結(jié)論至少還能被找到二是盡量用長(zhǎng)期存在的公共平臺(tái)而非個(gè)人服務(wù)器做托管用好GitHub和Zenodo這些老牌平臺(tái)三是在README里明確“維護(hù)狀態(tài)”寫(xiě)上最后更新時(shí)間和維護(hù)人聯(lián)系方式后人接手時(shí)至少有線索可循。 說(shuō)到底開(kāi)放研究的終極目標(biāo)不是讓每一個(gè)項(xiàng)目都萬(wàn)古長(zhǎng)青而是讓每一個(gè)研究過(guò)程都經(jīng)得起追溯。哪怕人走了證據(jù)還在后來(lái)者可以接續(xù)工作這就是它比封閉科研更有生命力的地方。 最后再分享一個(gè)小體會(huì)搭建這套工作流前期的學(xué)習(xí)曲線確實(shí)會(huì)陡一點(diǎn)尤其是剛開(kāi)始接觸Git和DVC時(shí)會(huì)有那么一兩個(gè)星期覺(jué)得“這比寫(xiě)論文還累”。但熬過(guò)這個(gè)階段當(dāng)你三個(gè)月后回頭翻自己的Git提交記錄發(fā)現(xiàn)每一個(gè)結(jié)論都能找到對(duì)應(yīng)的代碼和數(shù)據(jù)當(dāng)你把項(xiàng)目鏈接發(fā)給合作者對(duì)方一個(gè)下午就復(fù)現(xiàn)了你的全部結(jié)果——那種踏實(shí)感是傳統(tǒng)科研方式給不了的。我的建議是不用等“準(zhǔn)備好”再開(kāi)始就從下一篇論文甚至從這篇論文的“數(shù)據(jù)分析”階段開(kāi)始把至少一個(gè)環(huán)節(jié)接入開(kāi)放工作流。邁出這一步你就已經(jīng)走在“OpenResearch”這條路上了。