Python 練習: 處理癌症開放資料

最近拜 AI/DL/ML 興起之賜,Python變得好熱門。以前我並沒有用Python開發的經驗,這些日子也跟著學習使用Python一陣子,才發現到, Python在資料處理上,的確是好用。同樣的工作,我雖然自己用C/C++也可以處理,但程式閧發的時間,也許比一面學著用Python來處理長。所以我在資料的前處理上,開始改用Python,後面才接著用C/C++繼續處理資料。

兩年前曾處理過癌症開放資料,這次就試著用Python重新處理,也練習一下Python。

而我在學 Python,也有從kaggle上看他們的範例一步步跟著做。這次會想試著重新處理癌症開放資料,便是看了kaggle的 competition,其中最基礎的範例:Titanic: Machine Learngin from Disaster。 有一位提供的解法裡用到 Pandas 這個工具模組;因為我才開始學 Python 所以以前沒用過Pandas,也許做資料處理的人早很熟悉了。我覺得 Pandas 對於 csv 處理的功能實在太強大了。而 kaggle 裡的解法也顯示了 correlation map。讓我興起把癌症開放資料拿來重新做處理的念頭。讀者有興趣可以去 kaggle 研究那解法。

以下是整個流程,我對 Python其實還是初學者,所以如果有些地方還可以再改進的,歡迎提供建議。


資料來源: 癌症發生統計

資料說明: 台灣在民國68-103年各縣市的癌症發生率資料 (CSV格式)。

資料欄位: 包含: 癌症診斷年、性別、縣市別、癌症別、年齡標準化發生率 WHO 2000世界標準人口 (每10萬人口)、癌症發生數、平均年齡、年齡中位數、粗發生率 (每10萬人口)

目標: 計算出不同癌症發生率的correlation(針對男性),並視覺化呈現。

下圖是原始檔案內容截圖:

為了方便程式操作,我先用文字編輯器(Notepad++)把第一行欄位名稱改成英文:


Python 開發過程:

由上圖資料內容截圖,可以看出資料是由上往下一一列出。而我想要以縣市為單位,計算出不同癌症發生率的關聯。所以我需要把以上資料轉成每一列中,列出單一縣市這幾年各癌症粗發生率的平均值,然後就可以用Pandas提供的 corr() 工具來算出 correlation。

首先, 先 import 需要的 module:

import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

然後,載入資料,用Pandas只要用 read_csv()這函式就可以讀入 csv 資料

cancer_data = pd.read_csv('./Cancer_1979-2014.csv')

因為只需要粗發生率,先把不需要的欄位去掉

cancer_data=cancer_data.drop(['WHO2000','Count','AgeAvg','AgeMed'], axis=1)

要根據每種癌症計算出這幾年每種癌症的平均粗發生,首先我們需要找出有哪些癌症。原本的檔案每一列都是單一癌症某一年的統計數字,可以用 Pandas 中的 unique() ,找出'Cancer'這欄位不同的值來完成。

cancer_list = cancer_data['Cancer'].unique()
cancer_list  # 顯示結果

cancer_list 內容如下:

array(['口腔、口咽及下咽', '主唾液腺', '鼻咽', '食道', '胃', '小腸', '結直腸', '肝及肝內膽管',
       '膽囊及肝外膽管', '胰', '後腹膜腔及腹膜', '消化器官其他分界不明部位', '鼻腔、中耳及副鼻竇', '喉',
       '肺、支氣管及氣管', '胸膜', '胸腺、心臟與中隔', '呼吸系統與胸內器官之其他分界不明部位', '骨、關節及關節軟骨',
       '結締組織、皮下組織及其他軟組織', '皮膚', '女性乳房', '男性乳房', '子宮', '子宮頸', '子宮體',
       '卵巢、輸卵管及寬韌帶', '其他女性生殖器官', '攝護腺', '睪丸', '其他男性生殖器官', '膀胱', '腎',
       '腎盂及其他泌尿系統', '眼及淚腺', '腦', '其他神經系統', '甲狀腺', '其他內分泌腺', '其他分界不明的部位',
       '不明原發部位', '何杰金氏淋巴瘤', '白血病', '非何杰金氏淋巴瘤', '漿細胞瘤', '全癌症'], dtype=object)

接下來,要找出男性患者,每個癌症粗發生率的例年平均,以縣市為單位。

我以for loop,對每一癌症,男性患者,以縣市為單位,找出該癌症在資料裡在各年度粗發生率數值,再做平均,把結果放到一個新的表格中(TT)。

但是這表格TT,粗發率平均的欄位名稱會是 "IncidenceRate",所以還要把欄位改名為那癌症的名稱。最後將每個癌症的結果結合(join()),得到最終的結果。程式如下:

index = 0
for cancer in cancer_list:
    TT=cancer_data.loc[(cancer_data['Gender']=='男') &  
        (cancer_data['Cancer']==cancer)].groupby(['County']).mean()
    TT=TT.drop(['Year'], axis=1) #計算平均後就不需要年份了
    TT.rename(columns = {'IncidenceRate': cancer}, inplace=True) #改欄位名稱
    if (index==0):
        result = TT
    else:
        result=result.join(TT)
    index=index+1

下一步,把NA的值填上 0

result=result.fillna(0)

result 列出來如下:

以上表格每一行都昰癌症的粗發生率平均,就可以拿來做關聯分析了。

照著 kaggle 範例解法,用 seaborn 這個工具來產生 correlation map:

colormap = plt.cm.RdBu
plt.figure(figsize=(20,18))
plt.title('Pearson Correlation of Features', y=1.05, size=10)
sns.heatmap(result.astype(float).corr(),linewidths=0.1,vmax=1.0,
            square=True, cmap=colormap, linecolor='white', annot=True)

得到的結果如下圖 。

但要注意的,matplotlib 一開始是無法顯示中文字型的。要顯示中文,需要特別處理。上網查資料後,最簡單的做法,是從 windows/Fonts/ 目錄,將微軟正黑(Microsoft JhengHei UI)複製到 matplotlib 的字型目錄裡(site-packages/matplotlib/mpl-data/fonts/ttf),然後手動將 msjh.ttc改名為 DejaVuSans.ttf,重啟Python,就可以了。

可以觀察到上圖的中間有空白區域,經過檢查,原來是'女性乳房'、'子宮'、'子宮頸'、'子宮體'、'卵巢、輸卵管及寬韌帶', '其他女性生殖器官' 這幾欄沒數值,因為我們是以在男性患者為目標,所以可以把這幾個欄位去掉,'全癌症'這欄也可以去掉。

result=result.drop(['全癌症','女性乳房', '子宮', '子宮頸', '子宮體', '卵巢、輸卵管及寬韌帶', '其他女性生殖器官',],axis=1)

上圖的顏色對照表,是plt.cm.RdBu,從紅到藍。數值高的反而為藍色。可以參照使用不同的顏色表

把上圖以新的顏色重新顯示,並把結果輸出成png。

colormap = plt.cm.rainbow
plt.figure(figsize=(40,40))
plt.title('男性癌症關聯分析', y=1.05, size=32)
sns.heatmap(result.astype(float).corr(),linewidths=0.1,vmax=1.0,
            square=True, cmap=colormap, linecolor='white', annot=True)
plt.savefig('out1.png')

結果如下:

以上就是以Python處理癌症開放資料得到不癌症的 correlation 的過程。要說明的是,算出 correlation,不見得這兩個癌症彼此間真有連帶關係。我們只是純粹由數字來計算correlation,要真的研究不同癌症間的關聯,需要醫學方面專家來幫忙。

 


接下來想再做的,是想再整合不同資料。開放資料還有癌症死因資料。裡面統計各鄉鎮行政區每年度癌症死亡人數。但癌症統計以是縣市,癌症死因統計是鄉鎮里行政區做畫分,例如現在台中市市區和偏鄉區域因城鄉差異而有不同,但若整合到以縣市為單位,可能就看不出什麼意義了。

或是整合收入/環境等資料,觀察收入和癌症發生種類有無關係,或是和環境有沒有關係,例如現在熱門的空污議題。PM2.5的濃度,或一年內PM2.5超標天數,和某些特定癌症有無關係。但同樣的,那也需要更細的統計,而不是以縣市為統計資料。

結合癌症死因資料及人口資料做關聯,若有一個小地方居民因某種癌症致死率特別高,應可以容易的抓出來。不過,我已下載人口統計資料,初步觀察資料後,若要和癌症死因資料整合,開始的 data cleaning,就是一個非常麻煩的工程。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。