數據分析師的工作日常3 – 建立資料團隊的文化與程式規範 - 领英

文章推薦指數: 80 %
投票人數:10人

完整的背景知識對於資料科學家和數據分析師來說,雖然他們也寫程式, ... 或許你會說,「因為現在很多做數據分析的都不是本科系,理論知識當然不會 ... 原始文章〈數據分析師的工作日常3–建立資料團隊的文化與程式規範〉這是〈數據分析師的工作日常〉系列的第三篇文章。

第一篇文章是比較總覽型的文章;第二篇討論數據團隊可能的組織編制,以及每一種編制下的優缺點。

這篇文章會著墨在更技術面與實務面的內容,像是不好的codingstyle可能會造成什麼樣的風險,甚至進一步對公司造成什麼樣的傷害。

完整的背景知識對於資料科學家和數據分析師來說,雖然他們也寫程式,但他們寫程式的習慣和一般認知的工程師不太相同,甚至有些人對於寫code的背景知識明顯不足。

或許你會說,「因為現在很多做數據分析的都不是本科系,理論知識當然不會那麼紮實」,我認同這是個可能的原因,但我也認為這不能當成藉口,一個專業工作者本來就應該補足自身的不足。

我知道軟體工程師中也有類似的問題存在,但我畢竟對於資料科學界比較熟悉,因此只在我熟悉的領域內作評論。

舉個我親眼見證的例子。

我們數據團隊有一台Server,可以用來運算較大量的資料。

在Server上通常可以開多個帳號,每個人在自己的帳號底下作業,偶爾也會為了某些業務新增獨立的帳號,所有的程式碼與運算結果就放在這個帳號底下。

另外,數據團隊也經常需要排程執行某些運算,像是每個月初會預測即將流失的顧客,並與行銷部門合作,針對這些顧客進行挽回的行銷活動。

我曾經在Server上發現一個很少人使用的帳號,根據團隊的說明文件,這個帳號會在每天執行某些檢查,並判斷是否需要進行運算及資料更新。

當我登入這個帳號的時候,發現它的自動排程不是使用Linux的crontab執行,而是寫一個for迴圈,每天在固定時間點檢查是否需要進行運算,不需要的話就等24小時候再檢查。

當我發現這支驚為天人的code時,它已經不眠不休的跑了兩年,程式的撰寫者早已離職,而且這支程式占用了一顆CPU99.8%的效能,極度荒謬。

另一個例子,是我發現竟然有人會在code裡面使用中文作為變數名稱,這在技術面上可能可行,但有一定的風險,因為中文字會牽涉到編碼問題,當同樣一份檔案換到另一台電腦執行時,可能會因為電腦系統的設定不同,或是編輯器(IDE)的設定不同,導致無法正常運作。

如果要寫中文,強烈建議還是寫在註解裡面就好。

模組化/Function化先說一下什麼是function。

function是程式設計中常見的技巧,把一些會重複使用到的程式碼寫成特定格式,這些程式碼可能有數十或數百行,當需要使用到這些程式碼的時候,只需要花短短的幾行呼叫這個function即可,這樣的效果與多次複製貼上那數百行程式碼的效果是完全相同,但後者在維護性上明顯不佳。

我發現做資料科學圈中,不論使用R語言或Python,很多人都不喜歡寫function,但是寫function的好處顯而易見,不論對提升工作效率、程式維護性、資料正確性來說都是,因此,這樣的現象讓我非常難以理解。

而我的同事也曾經不能理解,為什麼我偏執的想把這麼多東西寫成function。

事實上,我更偏執的認為,codebase,也就是function的集合體,是數據團隊的資產,是可以重複使用、快速使用的工具組,這樣的資產某種程度上反應了這個團隊的戰力。

每個團隊成員手上都會有不同的專案,每個專案都會有不同的目標,雖然專案可能會結束,但在專案中寫出來的function會被納到codebase中,讓團隊越來越強大。

如果你在一間接案型的公司,這樣的需求可能沒有那麼強烈,因為每一次客戶給的資料格式可能都不太一樣;相反,如果你是In-House的分析師,強烈建議你開始建立自己的分析架構,因為內部資料再怎麼用就是那些,不需要每次都重新造輪子。

高效率對於某些經常執行的動作,或經常抓取的資料,只要寫成function,並且把可能會調整的部份寫成參數(argument),就可以保持一定的彈性,不需要每次都重頭來過。

我看過許多人抓資料時,都從第一行的SQL開始寫,或是將舊有的code複製貼上,這不只降低效率,在維護性上也是一大硬傷。

舉例來說,如果你需要計算公司每一張的訂單明細,並帶出訂單中的商品資料,這裡面至少會需要join兩張資料表。

把這些程式碼function化,並將日期區間設成參數,這就是一支容易理解,而且可以重複使用的function。

用參數加速開發流程除了使用方便外,這在開發速度上也有絕對的好處。

延續上面的例子,如果你需要用訂單明細及商品資料,計算過去一年每個商品分類在每個月的營收及毛利,並且還要跟前一年作比較,計算業績成長率。

可想而知,這會是一支篇幅與計算量都滿大的程式,如果你用hardcode的方式,也就是把全部的參數都寫死在程式中,這在開發及debug時都相當不方便。

更好的方法是把日期設為function的變數,在開發及debug時可以只用一個月或一周的資料量計算。

在正常情況下,如果這支function能夠正確計算一個月的資料,理所當然也可以計算一年的資料。

減少錯誤數據團隊的重大挑戰有兩個,一個是要保證每次提供出去的數據都是對的。

巴菲特曾經形容衍生性金融商品是大規模毀滅性武器,數據團隊也有等值的破壞力,亦正亦邪。

只要寫程式的人不小心手滑,多敲了一個零,執行出來的結果可能天差地遠。

如果這個錯誤讓整支程式掛掉,那還算是不幸中的大幸,最怕的是看起來很正常,但事實上一團亂的結果。

如果更不幸地,使用者也沒有看出其中的錯誤,進一步拿去做出重大但錯誤的商業決策時,數據部門很容易會被認為是競爭對手派來搞破壞的臥底。

這樣的錯誤在一流的跨國公司中也可能出現,像是Facebook在2016年出的包,〈【廣告商哭了】Facebook承認演算法錯誤,影片效果被嚴重高估〉。

第二個是要讓使用者聽懂你的分析流程,即使他們不懂統計、不會寫code、不熟悉演算法,但數據部門的使命之一就是將複雜的計算邏輯簡單說。

當使用者認同你的分析流程後,才會放心使用你產出的結果,因為沒有人會完全信任你的報告,尤其錯誤的決策可能會影響他們的個人績效時。

但究其根本,我認為第一個原因才是重中之重。

提供正確的數字,這聽起來很簡單,但卻是許多數據團隊真實面臨的挑戰。

因為沒有制式的、嚴謹的驗證機制,導致產出錯誤的資料,而錯誤的資料會傷害使用者對於數據團隊的信賴感,最後可能的情況是使用者對於與數據團隊合作感到興趣缺缺,數據驅動(Data-Driven)的文化也就沒辦法在公司內部推行,大家還是使用舊有的方法和習慣在做事。

為了避免資料錯誤,我認為解決方法有兩個,一個是從程式碼著手,將常用功能function化,並內建檢查機制;第二個是從團隊文化著手,建立codereview。

這兩者可以同時並行,但應該以前者為優先,因為在程式撰寫階段就先排除大部份錯誤,可以有效降低後續codereview的時間和人力成本。

從程式碼著手舉個例子,在沒有function化之前,一樣都是計算業績,但同事A和同事B算出來的業績可能就是不一樣。

喔,可能因為同事A排除了退貨,也就是業績為負值的部份,但在商業邏輯及公司慣例上,退貨到底該不該排?然後大家就開始熱烈討論,甚至詢問相關部門。

然而,這樣的情況經常會發生,大家可能在一個月後就會忘記今天的討論結果,同樣的錯誤、同樣的戲碼會再度上演。

更別說團隊可能有新人加入,新人可能會因為對公司業務的不熟悉,一樣計算出錯誤的數據結果。

既然知道會有這樣的情況發生,為什麼不要把定義和篩選條件寫成function,並在function內留下註解就好了?甚至可以把幾月幾號,問了哪個部門的誰都寫進去,因為商業環境快速變動,今天的定義可能在幾個月後就會修正。

對於修正定義的部門來說,沒有人知道你DataTeam會用到這些資料,所以當定義變動的時候,理所當然沒有人會去通知你。

直接把說明內容寫在註解中有另一個好處,團隊成員不需要再花很多時間寫說明文件。

大家都知道說明文件很重要,但大家也都會說自己沒空寫文件,或是文件太多找不到,乾脆重新用問的。

當然有些時候還是必須有獨立的說明文件,但在大多數情況中,把說明文件與function結合,不論在撰寫上或取用上都有一定的正面影響。

另一個程式設計面的大重點,是將驗證機制寫在程式中,像是確認資料筆數有沒有因為錯誤的join方式而爆增,或是可以用另一個資料源驗證產出結果的正確性等。

至於程式錯誤時的處理方式,可以直接停止執行,如果是在Server上的自動化排程,則可以寄mail給團隊成員,告知哪一支程式出現錯誤。

從團隊文化著手這裡的團隊文化指的是codereview的文化。

對軟體工程師來說,正式上code之前通常都會經過codereview的過程,通常會由較資深的同事協助確認程式的邏輯及品質。

但我認為codereview可以細分成兩個層次,一個是軟體面,一個是文化面。

常見codereview的方式必須透過軟體來進行。

由於業務性質不同,軟體公司通常願意投資這類軟體,但如果你是在金融業、製造業、零售業這種應用性質的產業,公司不一定會願意花錢買license。

如果你的團隊沒有codereview軟體,但你寫完的code會請同事到你的位子上幫你檢查,雖然聽起來有點愚蠢,但這正是codereview文化的精髓,大家要習慣且樂意做這件事,也相信codereview對於個人能力的成長,以及團隊戰力的提升都有正面幫助。

老實說,我也還在摸索該怎麼建立這個文化,建議參考Google釋出的說明文件Google’sEngineeringPracticesdocumentation。

降低協作的困難度先說說CodingStyle很多寫程式的人多少都有點小潔癖,不論是軟體工程師或是數據分析師。

因為每個人習慣的codingstyle不同,接手別人的code時,經常心裡面冒出OS,「我要改他的東西,還要先搞懂他的邏輯,倒不如整個打掉重練比較快」。

所謂的codingstyle也不是非黑即白的規則,中間還是有很多模糊地帶,像是Python的codingstyle就有官方的〈PEP8—StyleGuideforPythonCode〉,也有Google大神的〈GooglePythonStyleGuide〉。

我沒有仔細比較過兩者的差異,但隨著團隊的核心理念(Philosophy)不同,會長出不一樣的codingstyle也是相當合理。

像是Facebook強調產品的快速迭代,而Google強調高品質的程式碼。

雖然codingstyle有很多流派,但其中許多的根本性原理是相同的,像是不要把一個變數從頭用到尾,不停的覆寫它,這是相當常見的壞習慣。

因為正常人寫出來的code不會一次完美到位,中間一定會有修修改改的過程,如果你把一個變數從頭用到尾,代表你沒辦法同時將計算結果與原始資料print出來相互比對,這會大幅拉長開發所需要時間。

通常使用這種寫法的人,他們的回答會是「大量的變數會增加記憶體用量」。

我承認,這確實是個潛在的缺點,但我也不相信他們的每一支程式都會計算這麼龐大的資料量。

以顯而易見的開發效率為代價,去預防不一定會發生的風險,我不認為這是個聰明的作法。

在每個coder的學習之路上,我認為只要挑一個具有代表性的codingstyle,模仿它,學習它,先讓自己不寫出爛code。

當哪天需要和不同style的人合作時,可以禁得起檢驗,有自信的說出「雖然我們的風格不一樣,但不代表我的比較差」。

把function作為協作的斷點如前面所說,因為codingstyle不同,所以很多寫程式的人不喜歡接別人的code。

也確實,即使團隊制定了明確的codingstyle,成員們還是或多或少會在小地方維持自己的個人習慣,因為人畢竟不同於機器,這樣的不確定性是人之常情,也是建立團隊文化時必須要有的基礎認知。

然而,這樣的不確定性也讓function文化有了發揮的空間。

即使你再怎麼不能忍受別人寫的程式,只要它夠正確、夠穩定,你就放心的使用它吧,完全不需要管function裡面的程式寫成什麼樣子。

這樣的認知非常重要,只有接受了這個工作模式,數據團隊才可以站在前人的肩膀上,持續壯大,也就是下一段的重點。

站在前人的肩膀上數據分析案的兩種類型我通常會將數據分析案分成兩種類型,一種是找條件,一種是找原因,也就是所謂的根本原因分析(RootCauseAnalysis);前者比較容易,後者比較難。

什麼是找條件?舉例來說,如果你是IKEA的數據團隊,要找出近期可能要入住新家的消費者,並給予他們特定優惠,這就是找條件。

條件的依據來源可能是過往的消費記錄、網站的瀏覽記錄,或是網站上儲存的願望清單,透過各種條件篩選出一批人,進一步計算購買機率、預估消費金額、投資報酬率等,然後依照行銷預算,決定要將促銷訊息傳達給多少潛在消費者。

從商品面來說,如果IKEA要淘汰一些舊產品,並引進新商品,哪些舊產品需要被淘汰,又應該以多少的價錢出清才不至於虧本。

或是廚具區的陳列面積是不是需要縮小,玩具區的面積是不是需要擴大,這都是找條件的例子之一。

另外,找條件的分析其實是有方法可以偷懶的,直接套用80/20法則就對了,因為這是個知名、容易理解、容易實行,且普遍被接受的原則。

有些公司會應用這個原則,將80%的資源用於鞏固既有顧客,20%的資源開發新顧客;或是保留業績占比前80%的商品,淘汰其餘的20%。

我不認為無腦套用80/20法則是個好方法,但確實在商業環境中,很難在每個決策之前都執行完整的分析研究,所以80/20法則還是有一定的實用價值。

至於找原因的案例,如果你曾經被問過「可以幫我分析為什麼這一季的沙發業績衰退嗎」,這就是典型的找原因的案例。

找條件通常會在公司既有的資料框下的作分析,這也是我認為難度較低的理由;但找原因可能會有無限多個可能性,而且非常有可能要結合外部資料,可能是競爭對手大規模殺價促銷;或是房價持續攀升,買房的人越來越少,連帶影響傢俱需求減少;或是去年的產品品質不佳,有不少網友在各大論壇發文抱怨,造成今年的業績不佳。

以上每一項原因都有點道理,而且每一條都需要結合外部資料才能進行分析。

然而,能否取得所需的外部量化資料是一回事,最慘的情況是潛在原因只能用質化的方式進行研究;而外部資料需要時間導入又是另一回事,但通常找原因的時候都是業績衰退的時候,老闆可能沒這麼多時間讓你慢慢來。

用Function來累積內部變數在TowardDataScience的Medium上有一篇文章〈Howtoconductaproperrootcauseanalysis〉,裡面提到,要找RootCause的時候必須要收集很多的資料,並分析每一個潛在原因的影響性。

我認為它最終的結果會是一條迴歸方程式,以係數大小來判斷哪些是真正的RootCause。

之所以說「哪些」,因為現實世界總是複雜且環環相扣,業績的好壞不可能是單一因素造成的。

這樣的分析架構即使收集公司的內部資料作為變數,那也是個浩大的工程。

像是業績受影響是不是因為沒有促銷,或是用了一個沒這麼有效的行銷手法促銷;也可能是因為供貨量不足,導致業績衰退;甚至是顧客通常希望看到客廳的家具風格有一致性,所以會同時購買沙發和桌子,是桌子缺貨連帶影響沙發的業績。

在理想架構下,行銷手法的有效性會是一支function,判斷是否有足夠庫存是一支function,沙發與桌子之間的業績是否有相關性是一支function。

唯有團隊持續累積程式碼、累積智慧,才有可能面對這樣分析案。

相反,如果團隊過去沒有累積function的習慣,這時一定會疲於奔命,一邊思考潛在的原因,一邊開始從第一行code開始寫;或是過去可能在其他專案中寫過類似的程式,又花了一些時間在電腦中翻箱倒櫃,可能找不到,或是找到了卻發現不能用。

如果你是現役的數據分析師,對這樣的情境一定會有滿滿的既視感。

結論以上是我在工作中得到的一些經驗與啟發,希望對於大家提升工作效率或是建立團隊文化能有所幫助。

補充說明一點,在物件導向的程式語言中,除了function之外,也可以寫成類別(class)。

以我目前的專案經驗,不論使用R語言或Python,我暫時不認為有非寫class不可的理由,硬要寫的話當然可以,但似乎又有點矯枉過正。

如果你有其他的想法,歡迎留言告訴我。

線上學習資源如果你對於資料科學有興趣,在國內外都有不少優質的線上教學平台,像是台灣的Hahow或美國的Udemy。

Udemy的課程內容雖然以英文為主,但陸續也有不少中文課程上架。

另外,也有一些專門做程式設計教學的平台,使用者可以直接在網站上練習寫程式,如DataCamp,可以參考〈在DataCamp學Python和R語言,快速入門資料科學〉。

推薦文章〈數據分析師的工作日常1–在資料和程式中挖掘商業價值〉〈在Python中載入自己寫的套件/模組/包/Library/Modules/Codebase〉 12 赞 评论 分享 要查看或添加评论,请登录 要查看或添加评论,请登录 AI落地,資料科學專案的規劃、執行與商業影響力1-規劃篇 2022年2月20日 機器學習預測股價趨勢,修煉數據分析與投資能力的最強專案 2021年10月16日 WhyIsAPortfolioWebsiteImportantForADataScientist? 2021年8月15日



請為這篇文章評分?