❗️重要❗️ $800 購課金還沒領嗎? \\ 週年慶限定全站 85 折 // 再領 $1600 券❗️趁今天把屯好久的課帶回家🛒
時
分
秒
小資購課去🔥
登入/註冊
Aron
2021/06/23
1,774

想提升數據團隊效率、讓協作更順暢,從 coding 下手吧!

想了解資料科學家的工作日常?這篇文章我們來談談團隊協作:你的 coding style 其實會影響整個團隊?要怎麼透過「Function 化」提升團隊效率?一次告訴你!

對文章有興趣來不及看?點選右上角「橘色小書籤」收藏 文章,再也不怕錯過就是一輩子!


Hello 我是資料科學家 Aron!這是【資料科學家的工作日常】的系列文章。

第一篇文章我們簡介了資料科學家的工作內容;這篇文章會著墨在更技術面與實務面的內容,像是不好的 coding style 可能會造成什麼樣的風險,甚至進一步對公司造成什麼樣的傷害。

你的 coding style 如何影響整個數據團隊

對於資料科學家和數據分析師來說,雖然他們也寫程式,但他們寫程式的習慣和一般認知的工程師不太相同,甚至有些人對於寫 code 的背景知識明顯不足。或許你會說,「因為現在很多做數據分析的都不是本科系,理論知識當然不會那麼紮實」,我認同這是個可能的原因,但我也認為這不能當成藉口,一個專業工作者本來就應該補足自身的不足。我知道軟體工程師中也有類似的問題存在,但我畢竟對於資料科學界比較熟悉,因此只在我熟悉的領域內作評論。

舉個我親眼見證的例子。我們數據團隊有一台 Server,可以用來運算較大量的資料。在 Server 上通常可以開多個帳號,每個人在自己的帳號底下作業,偶爾也會為了某些業務新增獨立的帳號,所有的程式碼與運算結果就放在這個帳號底下。另外,數據團隊也經常需要排程執行某些運算,像是每個月初會預測即將流失的顧客,並與行銷部門合作,針對這些顧客進行挽回的行銷活動。

我曾經在Server上發現一個很少人使用的帳號,根據團隊的說明文件,這個帳號會在每天執行某些檢查,並判斷是否需要進行運算及資料更新。當我登入這個帳號的時候,發現它的自動排程不是使用 Linux 的 crontab 執行,而是寫一個 for 迴圈,每天在固定時間點檢查是否需要進行運算,不需要的話就等 24 小時候再檢查。當我發現這支驚為天人的 code 時,它已經不眠不休的跑了兩年,程式的撰寫者早已離職,而且這支程式占用了一顆 CPU 99.8% 的效能,極度荒謬。

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


businessman headache


用「Function 化」累積團隊資產,讓手上的專案不只是專案

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

我發現做資料科學圈中,不論使用 R 語言或 Python,很多人都不喜歡寫 function,但是寫 function 的好處顯而易見,不論對提升工作效率、程式維護性、資料正確性來說都是,因此,這樣的現象讓我非常難以理解。而我的同事也曾經不能理解,為什麼我偏執的想把這麼多東西寫成 function。事實上,我更偏執的認為,codebase,也就是 function 的集合體,是數據團隊的資產,是可以重複使用、快速使用的工具組,這樣的資產某種程度上反應了這個團隊的戰力。每個團隊成員手上都會有不同的專案,每個專案都會有不同的目標,雖然專案可能會結束,但在專案中寫出來的 function 會被納到 codebase 中,讓團隊越來越強大。

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

高效率

對於某些經常執行的動作,或經常抓取的資料,只要寫成 function,並且把可能會調整的部份寫成參數 (argument),就可以保持一定的彈性,不需要每次都重頭來過。 我看過許多人抓資料時,都從第一行的 SQL 開始寫,或是將舊有的 code 複製貼上,這不只降低效率,在維護性上也是一大硬傷。

舉例來說,如果你需要計算公司每一張的訂單明細,並帶出訂單中的商品資料,這裡面至少會需要 join 兩張資料表。把這些程式碼 function 化,並將日期區間設成參數,這就是一支容易理解,而且可以重複使用的 function。


用參數加速開發流程

除了使用方便外,這在開發速度上也有絕對的好處。延續上面的例子,如果你需要用訂單明細及商品資料,計算過去一年每個商品分類在每個月的營收及毛利,並且還要跟前一年作比較,計算業績成長率。可想而知,這會是一支篇幅與計算量都滿大的程式,如果你用 hard code 的方式,也就是把全部的參數都寫死在程式中,這在開發及 debug 時都相當不方便。

更好的方法是 把日期設為 function 的變數,在開發及 debug 時可以只用一個月或一周的資料量計算。 在正常情況下,如果這支 function 能夠正確計算一個月的資料,理所當然也可以計算一年的資料。


coding job


減少錯誤

數據團隊的重大挑戰有兩個,一個是要保證每次提供出去的數據都是對的。巴菲特曾經形容衍生性金融商品是大規模毀滅性武器,數據團隊也有等值的破壞力,亦正亦邪。只要寫程式的人不小心手滑,多敲了一個零,執行出來的結果可能天差地遠。如果這個錯誤讓整支程式掛掉,那還算是不幸中的大幸,最怕的是看起來很正常,但事實上一團亂的結果。如果更不幸地,使用者也沒有看出其中的錯誤,進一步拿去做出重大但錯誤的商業決策時,數據部門很容易會被認為是競爭對手派來搞破壞的臥底。這樣的錯誤在一流的跨國公司中也可能出現,像是 Facebook 在 2016 年出的包,〈【廣告商哭了】Facebook 承認演算法錯誤,影片效果被嚴重高估〉。

第二個是要讓使用者聽懂你的分析流程,即使他們不懂統計、不會寫 code、不熟悉演算法,但數據部門的使命之一就是將複雜的計算邏輯簡單說。當使用者認同你的分析流程後,才會放心使用你產出的結果,因為沒有人會完全信任你的報告,尤其錯誤的決策可能會影響他們的個人績效時。但究其根本,我認為第一個原因才是重中之重。

提供正確的數字,這聽起來很簡單,但卻是許多數據團隊真實面臨的挑戰。因為沒有制式的、嚴謹的驗證機制,導致產出錯誤的資料,而錯誤的資料會傷害使用者對於數據團隊的信賴感,最後可能的情況是使用者對於與數據團隊合作感到興趣缺缺,數據驅動 (Data-Driven) 的文化也就沒辦法在公司內部推行,大家還是使用舊有的方法和習慣在做事。

為了避免資料錯誤,我認為解決方法有兩個,一個是從程式碼著手,將常用功能 function 化,並內建檢查機制;第二個是從團隊文化著手,建立 code review。 這兩者可以同時並行,但應該以前者為優先,因為在程式撰寫階段就先排除大部份錯誤,可以有效降低後續 code review 的時間和人力成本。


woman coding


如何避免資料錯誤:(1) 從程式碼著手


舉個例子,在沒有 function 化之前,一樣都是計算業績,但同事 A 和同事 B 算出來的業績可能就是不一樣。喔,可能因為同事A排除了退貨,也就是業績為負值的部份,但在商業邏輯及公司慣例上,退貨到底該不該排?然後大家就開始熱烈討論,甚至詢問相關部門。然而,這樣的情況經常會發生,大家可能在一個月後就會忘記今天的討論結果,同樣的錯誤、同樣的戲碼會再度上演。更別說團隊可能有新人加入,新人可能會因為對公司業務的不熟悉,一樣計算出錯誤的數據結果。

既然知道會有這樣的情況發生,為什麼不要把定義和篩選條件寫成 function,並在 function 內留下註解就好了?甚至可以把幾月幾號,問了哪個部門的誰都寫進去,因為商業環境快速變動,今天的定義可能在幾個月後就會修正。對於修正定義的部門來說,沒有人知道你 Data Team 會用到這些資料,所以當定義變動的時候,理所當然沒有人會去通知你。

直接把說明內容寫在註解中有另一個好處,團隊成員不需要再花很多時間寫說明文件。 大家都知道說明文件很重要,但大家也都會說自己沒空寫文件,或是文件太多找不到,乾脆重新用問的。當然有些時候還是必須有獨立的說明文件,但在大多數情況中,把說明文件與 function 結合,不論在撰寫上或取用上都有一定的正面影響。

另一個程式設計面的大重點,是將驗證機制寫在程式中,像是確認資料筆數有沒有因為錯誤的 join 方式而爆增,或是可以用另一個資料源驗證產出結果的正確性等。至於程式錯誤時的處理方式,可以直接停止執行,如果是在 Server 上的自動化排程,則可以寄 mail 給團隊成員,告知哪一支程式出現錯誤。


如何避免資料錯誤:(2) 從團隊文化著手


這裡的團隊文化指的是 code review 的文化 。對軟體工程師來說,正式上 code 之前通常都會經過 code review 的過程,通常會由較資深的同事協助確認程式的邏輯及品質。 但我認為 code review 可以細分成兩個層次,一個是軟體面,一個是文化面。

常見 code review 的方式必須透過軟體來進行。由於業務性質不同,軟體公司通常願意投資這類軟體,但如果你是在金融業、製造業、零售業這種應用性質的產業,公司不一定會願意花錢買 license。

如果你的團隊沒有 code review 軟體,但你寫完的 code 會請同事到你的位子上幫你檢查,雖然聽起來有點愚蠢,但這正是 code review 文化的精髓,大家要習慣且樂意做這件事,也相信 code review 對於個人能力的成長,以及團隊戰力的提升都有正面幫助。老實說,我也還在摸索該怎麼建立這個文化,建議參考 Google 釋出的說明文件 Google’s Engineering Practices documentation。


code review


想降低團隊協作的困難度,你可以怎麼做?

一、先說說 Coding Style

很多寫程式的人多少都有點小潔癖,不論是軟體工程師或是資料科協ㄐㄚ 。因為每個人習慣的 coding style 不同,接手別人的 code 時,經常心裡面冒出 OS,「我要改他的東西,還要先搞懂他的邏輯,倒不如整個打掉重練比較快」。

所謂的 coding style 也不是非黑即白的規則,中間還是有很多模糊地帶,像是 Python 的 coding style 就有官方的〈PEP 8 — Style Guide for Python Code〉,也有 Google 大神的〈Google Python Style Guide〉。我沒有仔細比較過兩者的差異,但隨著團隊的核心理念 (Philosophy) 不同,會長出不一樣的 coding style 也是相當合理。像是 Facebook 強調產品的快速迭代,而 Google 強調高品質的程式碼。

雖然 coding style 有很多流派,但其中許多的根本性原理是相同的,像是不要把一個變數從頭用到尾,不停的覆寫它,這是相當常見的壞習慣。因為正常人寫出來的 code 不會一次完美到位,中間一定會有修修改改的過程,如果你把一個變數從頭用到尾,代表你沒辦法同時將計算結果與原始資料 print 出來相互比對,這會大幅拉長開發所需要時間。

通常使用這種寫法的人,他們的回答會是「大量的變數會增加記憶體用量」。我承認,這確實是個潛在的缺點,但我也不相信他們的每一支程式都會計算這麼龐大的資料量。以顯而易見的開發效率為代價,去預防不一定會發生的風險,我不認為這是個聰明的作法。

在每個 coder 的學習之路上,我認為只要挑一個具有代表性的 coding style,模仿它,學習它,先讓自己不寫出爛 code。當哪天需要和不同 style 的人合作時,可以禁得起檢驗,有自信的說出「雖然我們的風格不一樣,但不代表我的比較差」。


二、把 function 作為協作的斷點

如前面所說,因為 coding style 不同,所以很多寫程式的人不喜歡接別人的 code。也確實,即使團隊制定了明確的 coding style,成員們還是或多或少會在小地方維持自己的個人習慣,因為人畢竟不同於機器,這樣的不確定性是人之常情,也是建立團隊文化時必須要有的基礎認知。

然而,這樣的不確定性也讓 function 文化有了發揮的空間。即使你再怎麼不能忍受別人寫的程式,只要它夠正確、夠穩定,你就放心的使用它吧,完全不需要管 function 裡面的程式寫成什麼樣子。這樣的認知非常重要,只有接受了這個工作模式,數據團隊才可以站在前人的肩膀上,持續壯大,也就是下一段的重點。


woman coding2


數據團隊如何能站在前人的肩膀上、持續壯大?

數據分析案的兩種類型

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

什麼是找條件?舉例來說,如果你是 IKEA 的數據團隊,要找出近期可能要入住新家的消費者,並給予他們特定優惠,這就是找條件。條件的依據來源可能是過往的消費記錄、網站的瀏覽記錄,或是網站上儲存的願望清單,透過各種條件篩選出一批人,進一步計算購買機率、預估消費金額、投資報酬率等,然後依照行銷預算,決定要將促銷訊息傳達給多少潛在消費者。

從商品面來說,如果 IKEA 要淘汰一些舊產品,並引進新商品,哪些舊產品需要被淘汰,又應該以多少的價錢出清才不至於虧本。或是廚具區的陳列面積是不是需要縮小,玩具區的面積是不是需要擴大,這都是找條件的例子之一。

另外,找條件的分析其實是有方法可以偷懶的,直接套用 80/20 法則就對了,因為這是個知名、容易理解、容易實行,且普遍被接受的原則。有些公司會應用這個原則,將 80% 的資源用於鞏固既有顧客,20% 的資源開發新顧客;或是保留業績占比前 80% 的商品,淘汰其餘的 20%。 我不認為無腦套用 80/20 法則是個好方法,但確實在商業環境中,很難在每個決策之前都執行完整的分析研究,所以 80/20 法則還是有一定的實用價值。

至於找原因的案例,如果你曾經被問過「可以幫我分析為什麼這一季的沙發業績衰退嗎」,這就是典型的找原因的案例。找條件通常會在公司既有的資料框下的作分析,這也是我認為難度較低的理由;但找原因可能會有無限多個可能性,而且非常有可能要結合外部資料,可能是競爭對手大規模殺價促銷;或是房價持續攀升,買房的人越來越少,連帶影響傢俱需求減少;或是去年的產品品質不佳,有不少網友在各大論壇發文抱怨,造成今年的業績不佳。以上每一項原因都有點道理,而且每一條都需要結合外部資料才能進行分析。然而,能否取得所需的外部量化資料是一回事,最慘的情況是潛在原因只能用質化的方式進行研究;而外部資料需要時間導入又是另一回事,但通常找原因的時候都是業績衰退的時候,老闆可能沒這麼多時間讓你慢慢來。


data analysis


用 Function 來累積內部變數

在 Toward Data Science 的 Medium上有一篇文章〈How to conduct a proper root cause analysis〉,裡面提到,要找 Root Cause 的時候必須要收集很多的資料,並分析每一個潛在原因的影響性。我認為它最終的結果會是一條迴歸方程式,以係數大小來判斷哪些是真正的 Root Cause。之所以說「哪些」,因為現實世界總是複雜且環環相扣,業績的好壞不可能是單一因素造成的。

這樣的分析架構即使收集公司的內部資料作為變數,那也是個浩大的工程。像是業績受影響是不是因為沒有促銷,或是用了一個沒這麼有效的行銷手法促銷;也可能是因為供貨量不足,導致業績衰退;甚至是顧客通常希望看到客廳的家具風格有一致性,所以會同時購買沙發和桌子,是桌子缺貨連帶影響沙發的業績。

在理想架構下,行銷手法的有效性會是一支 function,判斷是否有足夠庫存是一支 function,沙發與桌子之間的業績是否有相關性是一支 function。唯有團隊持續累積程式碼、累積智慧,才有可能面對這樣分析案。

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


結論

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

補充說明一點,在物件導向的程式語言中,除了 function 之外,也可以寫成類別 (class)。以我目前的專案經驗,不論使用 R 語言或 Python,我暫時不認為有非寫 class 不可的理由,硬要寫的話當然可以,但似乎又有點矯枉過正。如果你有其他的想法,也歡迎分享給我。


看完文章要用時卻忘光光?點選下方按鈕 收藏 此文章,我隨時都在這等你回來!


line-short

🎉 太棒了!你又學會了新知識!

▶ 用 5 分鐘再多學一點

▶ 推薦線上課程


(本文原載於 Aron Hack 亞倫害的,原標題:《資料科學家的工作日常3 – 建立資料團隊的文化與程式規範》)

2
給創作者來點掌聲!
2


Aron

以前用MIX這個名字在網路打滾,後來改為Aron。工業設計系畢業,曾任職知名品牌行銷企劃,做點設計,寫文案也寫網站;目前擔任零售業數據分析師。最近開始玩雙截棍、單輪車和Python量化投資。

其他人也在看

更多文章
2