Python提供了一個(gè)簡(jiǎn)單而強(qiáng)大的生存分析包——lifelines,可以非常方便的進(jìn)行應(yīng)用。這篇文章將為大家簡(jiǎn)單介紹這個(gè)包的安裝和使用。
成都創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于做網(wǎng)站、網(wǎng)站制作、卓尼網(wǎng)絡(luò)推廣、微信小程序定制開(kāi)發(fā)、卓尼網(wǎng)絡(luò)營(yíng)銷、卓尼企業(yè)策劃、卓尼品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供卓尼建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:jinyejixie.com
lifelines支持用pip的方法進(jìn)行安裝,您可以使用以下命令進(jìn)行一鍵安裝:
在python中,可以利用lifelines進(jìn)行累計(jì)生存曲線的繪制、Log Rank test、Cox回歸等。下面以lifelines包中自帶的測(cè)試數(shù)據(jù)進(jìn)行一個(gè)簡(jiǎn)單的示例。
首先加載和使用自帶的數(shù)據(jù)集:
運(yùn)行一下將會(huì)看到以下結(jié)果,
數(shù)據(jù)有三列,其中T代表min(T, C),其中T為死亡時(shí)間,C為觀測(cè)截止時(shí)間。E代表是否觀到“死亡”,1代表觀測(cè)到了,0代表未觀測(cè)到,即生存分析中的刪失數(shù)據(jù),共7個(gè)。 group代表是否存在病毒, miR-137代表存在病毒,control代表為不存在即對(duì)照組,根據(jù)統(tǒng)計(jì),存在miR-137病毒人數(shù)34人,不存在129人。
利用此數(shù)據(jù)取擬合擬生存分析中的Kaplan Meier模型(專用于估計(jì)生存函數(shù)的模型),并繪制全體人群的生存曲線。
圖中藍(lán)色實(shí)線為生存曲線,淺藍(lán)色帶代表了95%置信區(qū)間。隨著時(shí)間增加,存活概率S(t)越來(lái)越小,這是一定的,同時(shí)S(t)=0.5時(shí),t的95%置信區(qū)間為[53, 58]。這并不是我們關(guān)注的重點(diǎn),我們真正要關(guān)注的實(shí)驗(yàn)組(存在病毒)和對(duì)照組(未存在病毒)的生存曲線差異。因此我們要按照group等于“miR-137”和“control”分組,分別觀察對(duì)應(yīng)的生存曲線:
可以看到,帶有miR-137病毒的生存曲線在control組下方。說(shuō)明其平均存活時(shí)間明顯小于control組。同時(shí)帶有miR-137病毒存活50%對(duì)應(yīng)的存活時(shí)間95%置信區(qū)間為[19,29],對(duì)應(yīng)的control組為[56,60]。差異較大,這個(gè)方法可以應(yīng)用在分析用戶流失等場(chǎng)景,比如我們對(duì)一組人群實(shí)行了一些防止流行活動(dòng),我們可以通過(guò)此種方式分析我們活動(dòng)是否有效。
該模型以生存結(jié)局和生存時(shí)間為應(yīng)變量,可同時(shí)分析眾多因素對(duì)生存期的影響,能分析帶有截尾生存時(shí)間的資料,且不要求估計(jì)資料的生存分布類型。
對(duì)于回歸模型的假設(shè)檢驗(yàn)通常采用似然比檢驗(yàn)、Wald檢驗(yàn)和記分檢驗(yàn),其檢驗(yàn)統(tǒng)計(jì)量均服從卡方分布。,其自由度為模型中待檢驗(yàn)的自變量個(gè)數(shù)。一般說(shuō)來(lái),Cox回歸系數(shù)的估計(jì)和模型的假設(shè)檢驗(yàn)計(jì)算量較大,通常需利用計(jì)算機(jī)來(lái)完成相應(yīng)的計(jì)算
通常存活時(shí)間與多種因素都存在關(guān)聯(lián),因此我們的面臨的數(shù)據(jù)是多維的。下面使用一個(gè)更復(fù)雜的數(shù)據(jù)集。首先仍然是導(dǎo)入和使用示例數(shù)據(jù)。
[圖片上傳中...(24515569-a5987d05b5e05a26.png-4ed038-1600008755271-0)]
其中T代表min(T, C),其中T為死亡時(shí)間,C為觀測(cè)截止時(shí)間。E代表是否觀察到“死亡”,1代表觀測(cè)到了,0代表未觀測(cè)到,即生存分析中的 “刪失” 數(shù)據(jù),刪失數(shù)據(jù)共11個(gè)。var1,var2,var3代表了我們關(guān)系的變量,可以是是否為實(shí)驗(yàn)組的虛擬變量,可以是一個(gè)用戶的渠道路徑,也可以是用戶自身的屬性。
我們利用此數(shù)據(jù)進(jìn)行Cox回歸
從結(jié)果來(lái)看,我們認(rèn)為var1和var3在5%的顯著性水平下是顯著的。認(rèn)為var1水平越高,用戶的風(fēng)險(xiǎn)函數(shù)值越大,即存活時(shí)間越短(cox回歸是對(duì)風(fēng)險(xiǎn)函數(shù)建模,這與死亡加速模型剛好相反,死亡加速模型是對(duì)存活時(shí)間建模,兩個(gè)模型的參數(shù)符號(hào)相反)。同理,var3水平越高,用戶的風(fēng)險(xiǎn)函數(shù)值越大。
這次我們使用 Python 來(lái)實(shí)現(xiàn)生命游戲,這是一種簡(jiǎn)單的元胞自動(dòng)機(jī)?;谝欢ㄒ?guī)則,程序可以自動(dòng)從當(dāng)前狀態(tài)推演到下一狀態(tài)。制作的成品如下:
先來(lái)說(shuō)說(shuō)生命游戲的規(guī)則:
在生命游戲中,每個(gè)單元格有兩種狀態(tài),生與死。在我們的實(shí)現(xiàn)中,黃色的單元格代表活著的細(xì)胞,紅色單元格表示死亡的細(xì)胞。而每一個(gè)細(xì)胞的下一狀態(tài),是由該細(xì)胞及周圍的八個(gè)細(xì)胞的當(dāng)前狀態(tài)決定的。
具體而言:
當(dāng)前細(xì)胞為活細(xì)胞
當(dāng)前細(xì)胞為死細(xì)胞
無(wú)需安裝的標(biāo)準(zhǔn)庫(kù):
第三方庫(kù):
導(dǎo)入模塊:
首先,我們要知道細(xì)胞的生存空間是 N * N 的方陣,每個(gè)細(xì)胞都有兩種狀態(tài):on, off。on 為 255,off 為 0。我們使用 numpy 產(chǎn)生 N * N 的方陣。np.random.choice 是在 State.on 和 State.off ,等概率隨機(jī)抽取一個(gè)元素構(gòu)造 N * N 的方陣。
其次我們要明白如何計(jì)算細(xì)胞周圍活細(xì)胞的個(gè)數(shù),尤其是邊界一圈的細(xì)胞。我們可以采用余數(shù)的方式,假設(shè)棋盤大小為 9 * 9,那么對(duì)于左右邊界而言,左邊界的左邊一個(gè)元素的計(jì)算方式: - 1 % 9 = 8,自動(dòng)折到右邊界上。將細(xì)胞周圍八個(gè)單元格的數(shù)值加起來(lái),除以 255,就可以得到細(xì)胞周圍活細(xì)胞的個(gè)數(shù)。
接下來(lái)是對(duì)規(guī)則的翻譯,即根據(jù)當(dāng)前世代的狀態(tài),推演出下一世代,細(xì)胞的狀態(tài)。initial 為當(dāng)前世代的矩陣,data為下一世代的矩陣,我們根據(jù) initial 的數(shù)值,計(jì)算出 data 的數(shù)值。total 為周圍活細(xì)胞的個(gè)數(shù),如果當(dāng)前為活細(xì)胞,total 大于三或者小于二,下一世代就會(huì)死去。如果當(dāng)前為死細(xì)胞,total 等于三,下一世代活細(xì)胞就會(huì)繁殖到該單元格上。
接下來(lái)是制作動(dòng)圖的過(guò)程,前面幾行是繪圖的基本操作。之后,我們使用到了 matplotlib.animation 的方法。其中,F(xiàn)uncAnimation 接受的參數(shù)含義:fig 為圖像句柄,generate 函數(shù)是我們更新每一幀圖像所需數(shù)據(jù)的函數(shù),下面會(huì)有介紹,fargs 為 genrate 函數(shù)的除去第一個(gè)參數(shù)的其他參數(shù),第一個(gè)參數(shù)由 FuncAnimation 指定 framenum(幀數(shù)) 傳給 generate 函數(shù)。frames 是幀數(shù),interval 是更新圖像間隔,save_count 為從幀到緩存的值的數(shù)量。
如果指定保存路徑(html),則保存為 html 動(dòng)畫。
下面我們來(lái)看 generate 函數(shù),NUM 為當(dāng)?shù)螖?shù),frame_num 接收來(lái)自 FuncAnimation 的幀數(shù)。通過(guò)嵌套的 for 循環(huán),我們逐個(gè)地更新方陣中各元素的狀態(tài)。
最后,我們可以通過(guò)命令行參數(shù),運(yùn)行我們的程序:
-- size 參數(shù)為棋盤大小,--seed 為隨機(jī)種子,用于產(chǎn)生不同的隨機(jī)方陣。
高斯帕滑翔機(jī)槍(Gosper Glider Gun)
可將 --gosper 更改為 --glider 滑翔機(jī)。--save 為動(dòng)圖保存的地址。
眾所周知,Python 是一門面向?qū)ο笳Z(yǔ)言,在 Python 的世界一切皆對(duì)象。所以一切變量的本質(zhì)都是對(duì)象的一個(gè)指針而已。
Python 運(yùn)行過(guò)程中會(huì)不停的創(chuàng)建各種變量,而這些變量是需要存儲(chǔ)在內(nèi)存中的,隨著程序的不斷運(yùn)行,變量數(shù)量越來(lái)越多,所占用的空間勢(shì)必越來(lái)越大,如果對(duì)變量所占用的內(nèi)存空間管理不當(dāng)?shù)脑挘敲纯隙〞?huì)出現(xiàn) out of memory。程序大概率會(huì)被異常終止。
因此,對(duì)于內(nèi)存空間的有效合理管理變得尤為重要,那么 Python 是怎么解決這個(gè)問(wèn)題的呢。其實(shí)很簡(jiǎn)單,對(duì)不不可能再使用到的內(nèi)存進(jìn)行回收即可,像 C 語(yǔ)言中需要程序員手動(dòng)釋放內(nèi)存就是這個(gè)道理。但問(wèn)題是如何確定哪些內(nèi)存不再會(huì)被使用到呢?這就是我們今天要說(shuō)的垃圾回收了。
目前垃圾回收比較通用的解決辦法有三種,引用計(jì)數(shù),標(biāo)記清除以及分代回收。
引用計(jì)數(shù)也是一種最直觀,最簡(jiǎn)單的垃圾收集技術(shù)。在 Python 中,大多數(shù)對(duì)象的生命周期都是通過(guò)對(duì)象的引用計(jì)數(shù)來(lái)管理的。其原理非常簡(jiǎn)單,我們?yōu)槊總€(gè)對(duì)象維護(hù)一個(gè) ref 的字段用來(lái)記錄對(duì)象被引用的次數(shù),每當(dāng)對(duì)象被創(chuàng)建或者被引用時(shí)將該對(duì)象的引用次數(shù)加一,當(dāng)對(duì)象的引用被銷毀時(shí)該對(duì)象的引用次數(shù)減一,當(dāng)對(duì)象的引用次數(shù)減到零時(shí)說(shuō)明程序中已經(jīng)沒(méi)有任何對(duì)象持有該對(duì)象的引用,換言之就是在以后的程序運(yùn)行中不會(huì)再次使用到該對(duì)象了,那么其所占用的空間也就可以被釋放了了。
我們來(lái)看看下面的例子。
函數(shù) print_memory_info 用來(lái)獲取程序占用的內(nèi)存空間大小,在 foo 函數(shù)中創(chuàng)建一個(gè)包含一百萬(wàn)個(gè)整數(shù)的列表。從打印結(jié)果我們可以看出,創(chuàng)建完列表之后程序耗用的內(nèi)存空間上升到了 55 MB。而當(dāng)函數(shù) foo 調(diào)用完畢之后內(nèi)存消耗又恢復(fù)正常。
這是因?yàn)槲覀冊(cè)诤瘮?shù) foo 中創(chuàng)建的 list 變量是局部變量,其作用域是當(dāng)前函數(shù)內(nèi)部,一旦函數(shù)執(zhí)行完畢,局部變量的引用會(huì)被自動(dòng)銷毀,即其引用次數(shù)會(huì)變?yōu)榱?,所占用的?nèi)存空間也會(huì)被回收。
為了驗(yàn)證我們的想法,我們對(duì)函數(shù) foo 稍加改造。代碼如下:
稍加改造之后,即使 foo 函數(shù)調(diào)用結(jié)束其所消耗的內(nèi)存也未被釋放。
主要是因?yàn)槲覀儗⒑瘮?shù) foo 內(nèi)部產(chǎn)生的列表返回并在主程序中接收之后,這樣就會(huì)導(dǎo)致該列表的引用依然存在,該對(duì)象后續(xù)仍有可能被使用到,垃圾回收便不會(huì)回收該對(duì)象。
那么,什么時(shí)候?qū)ο蟮囊么螖?shù)才會(huì)增加呢。下面四種情況都會(huì)導(dǎo)致對(duì)象引用次數(shù)加一。
同理,對(duì)象引用次數(shù)減一的情況也有四種。
引用計(jì)數(shù)看起來(lái)非常簡(jiǎn)單,實(shí)現(xiàn)起來(lái)也不復(fù)雜,只需要維護(hù)一個(gè)字段保存對(duì)象被引用的次數(shù)即可,那么是不是就代表這種算法沒(méi)有缺點(diǎn)了呢。實(shí)則不然,我們知道引用次數(shù)為零的對(duì)象所占用的內(nèi)存空間肯定是需要被回收的。那引用次數(shù)不為零的對(duì)象呢,是不是就一定不能回收呢?
我們來(lái)看看下面的例子,只是對(duì)函數(shù) foo 進(jìn)行了改造,其余未做更改。
我們看到,在函數(shù) foo 內(nèi)部生成了兩個(gè)列表 list_a 和 list_b,然后將兩個(gè)列表分別添加到另外一個(gè)中。由結(jié)果可以看出,即使 foo 函數(shù)結(jié)束之后其所占用的內(nèi)存空間依然未被釋放。這是因?yàn)閷?duì)于 list_a 和 list_b 來(lái)說(shuō)雖然沒(méi)有被任何外部對(duì)象引用,但因?yàn)槎咧g交叉引用,以至于每個(gè)對(duì)象的引用計(jì)數(shù)都不為零,這也就造成了其所占用的空間永遠(yuǎn)不會(huì)被回收的尷尬局面。這個(gè)缺點(diǎn)是致命的。
為了解決交叉引用的問(wèn)題,Python 引入了標(biāo)記清除算法和分代回收算法。
顯然,可以包含其他對(duì)象引用的容器對(duì)象都有可能產(chǎn)生交叉引用問(wèn)題,而標(biāo)記清除算法就是為了解決交叉引用的問(wèn)題的。
標(biāo)記清除算法是一種基于對(duì)象可達(dá)性分析的回收算法,該算法分為兩個(gè)步驟,分別是標(biāo)記和清除。標(biāo)記階段,將所有活動(dòng)對(duì)象進(jìn)行標(biāo)記,清除階段將所有未進(jìn)行標(biāo)記的對(duì)象進(jìn)行回收即可。那么現(xiàn)在的為問(wèn)題變?yōu)榱?GC 是如何判定哪些是活動(dòng)對(duì)象的?
事實(shí)上 GC 會(huì)從根結(jié)點(diǎn)出發(fā),與根結(jié)點(diǎn)直接相連或者間接相連的對(duì)象我們將其標(biāo)記為活動(dòng)對(duì)象(該對(duì)象可達(dá)),之后進(jìn)行回收階段,將未標(biāo)記的對(duì)象(不可達(dá)對(duì)象)進(jìn)行清除。前面所說(shuō)的根結(jié)點(diǎn)可以是全局變量,也可以是調(diào)用棧。
標(biāo)記清除算法主要用來(lái)處理一些容器對(duì)象,雖說(shuō)該方法完全可以做到不誤殺不遺漏,但 GC 時(shí)必須掃描整個(gè)堆內(nèi)存,即使只有少量的非可達(dá)對(duì)象需要回收也需要掃描全部對(duì)象。這是一種巨大的性能浪費(fèi)。
由于標(biāo)記清除算法需要掃描整個(gè)堆的所有對(duì)象導(dǎo)致其性能有所損耗,而且當(dāng)可以回收的對(duì)象越少時(shí)性能損耗越高。因此 Python 引入了分代回收算法,將系統(tǒng)中存活時(shí)間不同的對(duì)象劃分到不同的內(nèi)存區(qū)域,共三代,分別是 0 代,1 代 和 2 代。新生成的對(duì)象是 0 代,經(jīng)過(guò)一次垃圾回收之后,還存活的對(duì)象將會(huì)升級(jí)到 1 代,以此類推,2 代中的對(duì)象是存活最久的對(duì)象。
那么什么時(shí)候觸發(fā)進(jìn)行垃圾回收算法呢。事實(shí)上隨著程序的運(yùn)行會(huì)不斷的創(chuàng)建新的對(duì)象,同時(shí)也會(huì)因?yàn)橐糜?jì)數(shù)為零而銷毀大部分對(duì)象,Python 會(huì)保持對(duì)這些對(duì)象的跟蹤,由于交叉引用的存在,以及程序中使用了長(zhǎng)時(shí)間存活的對(duì)象,這就造成了新生成的對(duì)象的數(shù)量會(huì)大于被回收的對(duì)象數(shù)量,一旦二者之間的差值達(dá)到某個(gè)閾值就會(huì)啟動(dòng)垃圾回收機(jī)制,使用標(biāo)記清除算法將死亡對(duì)象進(jìn)行清除,同時(shí)將存活對(duì)象移動(dòng)到 1 代。 以此類推,當(dāng)二者的差值再次達(dá)到閾值時(shí)又觸發(fā)垃圾回收機(jī)制,將存活對(duì)象移動(dòng)到 2 代。
這樣通過(guò)對(duì)不同代的閾值做不同的設(shè)置,就可以做到在不同代使用不同的時(shí)間間隔進(jìn)行垃圾回收,以追求性能最大。
事實(shí)上,所有的程序都有一個(gè)相識(shí)的現(xiàn)象,那就是大部分的對(duì)象生存周期都是相當(dāng)短的,只有少量對(duì)象生命周期比較長(zhǎng),甚至?xí)qv內(nèi)存,從程序開(kāi)始運(yùn)行持續(xù)到程序結(jié)束。而通過(guò)分代回收算法,做到了針對(duì)不同的區(qū)域采取不同的回收頻率,節(jié)約了大量的計(jì)算從而提高 Python 的性能。
除了上面所說(shuō)的差值達(dá)到一定閾值會(huì)觸發(fā)垃圾回收之外,我們還可以顯示的調(diào)用 gc.collect() 來(lái)觸發(fā)垃圾回收,最后當(dāng)程序退出時(shí)也會(huì)進(jìn)行垃圾回收。
本文介紹了 Python 的垃圾回收機(jī)制,垃圾回收是 Python 自帶的功能,并不需要程序員去手動(dòng)管理內(nèi)存。
其中引用計(jì)數(shù)法是最簡(jiǎn)單直接的,但是需要維護(hù)一個(gè)字段且針對(duì)交叉引用無(wú)能為力。
標(biāo)記清除算法主要是為了解決引用計(jì)數(shù)的交叉引用問(wèn)題,該算法的缺點(diǎn)就是需要掃描整個(gè)堆的所有對(duì)象,有點(diǎn)浪費(fèi)性能。
而分代回收算法的引入則完美解決了標(biāo)記清除算法需要掃描整個(gè)堆對(duì)象的性能浪費(fèi)問(wèn)題。該算法也是建立在標(biāo)記清除基礎(chǔ)之上的。
最后我們可以通過(guò) gc.collect() 手動(dòng)觸發(fā) GC 的操作。
題外話,如果你看過(guò) JVM 的垃圾回收算法之后會(huì)發(fā)現(xiàn) Python 的垃圾回收算法與其是如出一轍的,事實(shí)再次證明,程序語(yǔ)言設(shè)計(jì)時(shí)是會(huì)相互參考的。
本文名稱:python生存函數(shù) python函數(shù)之生成器函數(shù)
文章URL:http://jinyejixie.com/article36/dopcgsg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷型網(wǎng)站建設(shè)、電子商務(wù)、靜態(tài)網(wǎng)站、網(wǎng)站排名、移動(dòng)網(wǎng)站建設(shè)、商城網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)