用程序員思維優化核酸檢測效率

1. 前言

    本文只是以計算機算法的角度,對核酸檢測效率的一些思考,期望爲廣大程序員對算法的應用帶來一些啓發與思考。
    由於實踐的複雜性(參考鏈接1),本文中的方法並不一定能應用於實際核酸檢測過程,歡迎提出更好更優的想法一起探討,不過煩請勿槓,槓就是你贏!!

2. 背景

    從2019年12月新冠疫情爆發開始,不論各國抗疫表現如何,大規模的核酸檢測,已經成爲了國內外抗疫第一重任。
    作爲抗疫最成功的國家之一,對動態清零的執着追求,無疑是我國抗疫的成功的保障。
    動態清零是一場與病毒代際傳播的賽跑——對每一起新的本地傳播,搶在病毒代際傳播之前,通過全員核酸和流行病學調查,找出並隔離所有潛在病例和密切接觸者,無疑是阻斷病毒傳播的關鍵。
    每一輪核酸檢測,我國都投入了海量的採樣人員、實驗室檢驗人員、志願者和檢測物資,力求在最短的時間內完成全員的核酸檢測。直到當下,實驗室檢驗仍然是大規模核酸檢測的主要瓶頸,畢竟我們可以像全國支援武漢一樣,調集、培訓大量的醫務人員支援一個點的核酸採樣,但是實驗室檢驗的效率不易快速提升,況且大規模核酸檢測結束後,建好的檢測實驗室利用率也不高。

    作爲程序員的我們也不難看出——實驗室檢驗明顯是個的低頻的流量突發場景,與其將硬件擴容到峯值,不如從算法上進行優化——如何減少實驗室檢驗的樣本數量和批次,無疑是縮短總檢測時間的關鍵,當然這一切的前提是陽性病例不能漏檢。
    核酸的實驗室檢驗是個典型的在m(檢測人數)個元素中找出0~n個值爲True(陽性)的二值過濾求更優解問題。

3. 現有方法

    我們先來看看現有檢測方法及優化:

3.1 最標準方法1人1採1檢

    如果不做任何優化,就是對集合m的遍歷、比較過程,時間複雜度爲O(m),這正是最原始的核酸檢測過程——1人1採1檢。
對於100個人,100人個核酸檢測的時間約等於實驗室檢驗100份核酸的時間。

    在大規模核酸檢測中,每個城市要在1天之內檢測十萬、百萬的核酸,實驗室檢驗的壓力可想而知。

3.2 10合1混採檢測

    在我國實際的大規模排查中,普遍採用了[10合1混採檢測]的方法,即每10人的採樣合併爲一個樣本,只做一次實驗室檢驗,這樣做的好處是潛在病例佔比極低的情況下,極大地減少了實驗室檢驗的工作量:

100人檢驗工作量:100÷10=10樣本

    理想情況下(潛在陽性0人),最少只須檢測10次即可完成100人的全員核酸檢測,即實驗室檢驗量只是原來的十分之一。這無疑是一大突破,極大地降低了核酸檢測的成本,關鍵還在大規模新冠篩查時減少了檢驗的壓力,整體縮短了核酸檢測週期。

    當然這樣做也有一定的侷限性——當潛在病例數較多且較分散時,需要展開第二輪檢測:
100人中有1例陽性:第一輪10樣本+第二輪10樣本=20樣本次檢測;
100人中有2例陽性:第一輪10樣本+第二輪10(陽性集中)或20(陽性分散)樣本
100人中有3例陽性:10+(1~3)×10=20~40樣本次檢驗
...
100人中有10例陽性:10+(1~10)×10=20~110樣本次檢驗

    可以看出當潛在病例數達到10%時,[10合1混採檢測]不再有優勢,甚至有可能還要多出10%的檢測量,以及多一輪的採集&檢驗。
    毋庸置疑的是,在我國動態清零的國情下,本地傳播必然是極少數,每次的潛在病例佔比不超過0.01%,[10合1混採檢測]在大規模核酸檢測中提升了效率,並節省了大量的人力、物力和資金成本。

但是作爲程序員的我們,[10合1混採檢測]是最優的檢測方式麼?

4. 潛在方案

    由於核酸檢測過程無法排序、無法像數據庫那樣建索引,因此常規的基於大小比較的查找算法都不合適。那要如何優化檢測效率呢?

4.1 分(3+)層混採檢測

    由於核酸檢測類似於二值查找,無法排序、無法像數據庫那樣建索引,因此常規的基於大小比較的查找算法都不合適。
    其實[10合1混採檢測]很類似於圖書館的分層檢索——先按類目確定樓層、區域,再按細類確定書架,最後按編號/名稱找到具體的書本。
    計算機領域與之對應的方法是分層聚類,比如圖片搜索不可能像數據那樣去建立一維索引,但是可以先用聚類的方式,把圖片從粗到細地爲多個層次的類別(如:上衣->圓領上衣->圓領T裇),然後經過簡單的幾次與類別特徵進先比較,就能快速縮小搜索範圍。
    應用到核酸檢測,如果感染率非常低的情況下,分三輪進先檢測,會得出一個更優的解
1000人有1例潛在病例:
第一輪100混1:1000÷100=10樣本次
第二輪針對第一輪潛在病例所在的那一組10混1:100÷10=10樣本次
第三輪針對第二輪潛在病例所在組1採1檢:1×10樣本次
三輪一共:10+10+10=30樣本次
1000人有2例潛在病例:
三輪一共:10+10×(1~2)+10×(1~2)=30~50樣本次
1000人有10例潛在病例:
三輪一共:10+10×(1~10)+10×(1~10)=30~210樣本次
1000人有10例潛在病例,10混1檢測:
三輪一共:100+10×(1~10)=110~200樣本次
1000人有100例潛在病例:
三輪一共:10+10×(1~10)+10×(10~100)=120~1110樣本次

    不難看出,在潛在病例佔比很小、檢測人數衆多的情況下,分三層檢測需要檢測的樣本數更少。但是它的侷限性在於需要更多的輪次來確定確診病例,且100混1可能會因爲病毒被稀釋太多而檢測不出來。

    結論:分(3+)層檢測引入更多的輪次,可行性低

4.2 \(\sqrt{N}\)合一混採檢測

    分層檢測有增加輪次的問題,那即使兩輪檢測,[10合1混採檢測]就是最優嗎?
    如果限制檢測輪次數爲兩輪,那這個問題,就變成了“X×Y=N,求X+Y最小值”的問題。僅根據小學知識我們就能知道,當X=Y=\(\sqrt{N}\)時,X+Y最小:

圖4.2 求X+Y最小值

    也就是說,同樣是兩輪檢測,10合一混採只是一個相對優解混採批次越接近混採總人數的平方根總檢測次數越少比如要對1000人進行檢測,20合一混採檢測效率高於10合一混採檢測,30合一混採檢測效率高於20合一混採,32合一混採檢測檢測效率最高(32*32=1024>1000)。

    結論:\(\sqrt{N}\)合一混檢可能更優,但要注意病毒有效濃度的問題,在有效濃度內,批次越接近\(\sqrt{N}\)越優。

4.3 二進制編碼檢測法——小鼠試毒算法

作爲程序員的你,很可能聽過“小鼠試毒算法”:
    有 1000 個一模一樣的瓶子,其中有 999 瓶是普通的水,有一瓶是毒藥。任何喝下一滴毒藥的生物都會在一星期之後死亡。現在我們用小白鼠來做實驗試毒,你只有一個星期的時間,如何檢驗出哪個瓶子裏有毒藥?最少用多少隻小白鼠?
    按照大部分人給出的答案,這是個二進制編碼問題,即使用小鼠的生與死當作二進制的0或1,來對藥瓶進行編碼:
瓶子1餵給小鼠1,瓶子2餵給小鼠2,瓶子3餵給小鼠1和小鼠2...
瓶子1:00 0000 0001
瓶子2:00 0000 0010
瓶子3:00 0000 0011
瓶子4:00 0000 0100
瓶子5:00 0000 0101
瓶子6:00 0000 0110
編碼完1000瓶藥水只需要10只小鼠(\(2^{10}\)=1024>1000)。
喂完藥水之後,靜待一週,根據小鼠死亡情況,可以精確推導出第幾瓶藥水有毒。

    大規模核酸檢測與“小鼠試毒算法”的場景有一些相同之處,比如單輪檢測週期長,實驗室檢測資源緊張,不同之處在於,被檢者是“藥水”,實驗室檢測的併發能力是“小鼠”,單輪檢測週期是“一星期”。
小鼠實驗的優點是隻需少量的小鼠,一輪就可以精準確定唯一那瓶毒藥。
有幾個致命的缺陷限制了“小鼠試毒算法”的實用性:

  1. 每隻小鼠要喝下1024/2=512瓶藥水,而小鼠不可能一口氣喝下512瓶甚至100瓶藥水,即使強行灌下,由於毒藥被過度稀釋,小鼠更可能被集體撐死而非中毒身亡。
  2. 只適用於有0~1瓶毒藥的場景。如果不止或不確定只有1瓶毒藥,那麼整個算法的就幾乎無效了,比如有1~2瓶毒藥,而死了4只小鼠,那這4只老鼠一共喝過24-1=15瓶藥水,這些藥水都得換個方法重測才能確定有幾瓶毒藥毒死了這些老鼠...如果第2n-1瓶藥水有毒,那麼會有大批老鼠陣亡,但是又無法確定第2瓶毒藥,那這2n-1瓶藥水都得重測。

    大規模核酸檢測,剛好以上兩個問題特別明顯——不太可能拆分組合數百份樣本而不影響檢測結果,且不清楚每次排查有多少潛在病例。

    結論:二進制編碼檢測法不可行

4.4 \(C_{n}^{2}\)混合檢測法

    基於對二進制編碼法兩個問題,我們可以使用排列組合法來改進:每份採樣分爲兩份,多份樣本合併進行一次檢驗,將多份樣本與檢驗過程進行不重複地組合。用表格表示如下:


圖4.4.1  \(C_{n}^{2}\)混檢示例圖

    如此按排列組合中組合公式,n次結果的組合檢驗能力爲\(C_{n}^{2}\)=\(\dfrac{n!}{2!\times \left( n-2\right) !}\),6次檢驗可檢測15人,10次檢驗可檢測55人。

    通過兩個檢驗陽性結果可以確定唯一的陽性病例:


圖4.4.2 檢驗結果2例陽性可以唯一確定一例陽性病例

而當檢驗結果多餘2例陽性時,也能比較快地鎖定需要下一輪檢測的人員:


圖4.4.3 檢驗結果2例陽性可以圈定3名潛在陽性病例

    檢驗結果陽性數與需要第二輪複覈人數的關係,可以用\(C_{m}^{2}\)組合公式計算:
0例檢驗陽性:無陽性病例,皆大歡喜
2例檢驗陽性:C(2,2)=1,代表了1位陽性病例,無須再檢即可精確鎖定
3例檢驗陽性:C(3,2)=3,代表了2~3位陽性病例,需要複查3人
4例檢驗陽性:C(4,2)=6,代表了2~6位陽性病例,需要複查6人
5例檢驗陽性:C(5,2)=10,代表了3~10位陽性病例,需要複查10人

    從下表可以看出\(C_{n}^{2}\)混合檢測的適用場景:


羅圖4.4.4 混檢的適用場景

    當檢測人數小於200時,\(C_{n}^{2}\)混檢需要比10合1混檢更多的檢驗次數,不太合算;
    但是當檢測人數大於210時,\(C_{n}^{2}\)混檢對減少檢驗次數的優勢就開始突顯,並且最大的優點是有望在一輪檢測中,精確鎖定唯一的陽性病例——這點對與時間賽跑的大規模核酸檢測非常有意義!

    結論:\(C_{n}^{2}\)混合檢測在檢測人數>200時且潛在病例佔比很少時,有較明顯優勢——能減少檢驗次數和輪次,更快地確定潛在陽性病例!

5. 結語

\(\sqrt{N}\)合一混採檢測理論上更優於10合1混採檢測;如在送檢數超過1000時,加大n合1混採檢測n的大小至32時,檢驗效率最高;

\(C_{20}^{2}\)混合檢測是一種潛在更優的大規模核酸檢測的方法——在送檢數超過200時,比10合1混採檢測檢驗次數更少,確定陽性病例的輪次更少。

參考

  1. 關於印發新冠病毒核酸10合1混採檢測技術規範的通知 (www.gov.cn)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章