Python讀取CSV檔案

CSV檔案是一個用來交換資料的標準文字檔格式,CSV三個英文字母是Comma Seperated Values,也就是以逗號分隔的資料之意。它是一個標準文字檔,副檔名是.csv,可以用一般的文字編輯程式(例如記事本或是一些程式碼編輯器)進行編輯,有些資料也是採取類似的方式,但是不採用逗號而是用定位鍵來分隔資料,此種格式則稱為TSV檔案。

CSV格式是Microsoft Excel所支援的標準格式之一,除了可以使用記事本編輯之外,也可以直接利用Excel編輯資料之後再儲存成CSV格式。它基本上符合了表格的型態,第一列是欄位名稱,接下來往下對應的資料則是欄位裡面的每一個值。典型的CSV格式如下所示:

姓名,國文,英文
王小花,89,65
林小明,45,89,80
陳小華,92,90,65

此種格式利用Python可以很容易地讀取出來,假設上述的檔案名稱為data05.csv,則利用以下的程式可以很輕易地把資料讀出並顯示出來:

fp = open("data05.csv", "r", encoding="utf-8")
data = fp.readlines()
fp.close()
print(data)

上面這個程式把data05.csv開啟成讀取用的檔案物件,因為檔案中有中文資料,因此還需要加上encoding參數,指定它的編碼方式是UTF-8,才不會在讀取時出現編碼錯誤。

開檔案後利用readlines()函式,把資料的內容以分列的方式讀取成串列,放在data變數中。本程式執行之結果如下所示:

['姓名,國文,英文\n', '王小花,89,65\n', '林小明,45,89,80\n', '陳小華,92,90,65']

如上述的資料所示,在此例中雖然已經把每一列都變成一個串列中的元素了,但是單列中的欄位(在此例為姓名、國文、英文等3個欄位)都還沒有切割開來,也就是3個欄位的資料目前是一個單一的字串,如此並無法取出其個別的資料加以計算,因此,我們還需要再利用一個迴圈,把每一列的資料再次拆成3個欄位(每個欄位間是以逗號進行分隔),請參考以下的程式:

fp = open("data05.csv", "r", encoding="utf-8")
data = fp.readlines()
fp.close()
for d in data:
    row = d.split(",")
    print(row)

在上述的程式中,我們利用split(“,”)以逗號為基準把字串拆開成串列變數放在row變數中,並在每分割一列之後隨即把內容列印出來,印出來的結果如下所示:

['姓名', '國文', '英文\n']
['王小花', '89', '65\n']
['林小明', '45', '89', '80\n']
['陳小華', '92', '90', '65']

從上面的結果就可以看到,基本上是把這些內容拆開成不同的記錄,之後如果需要進行計算時,就比較簡單了。不過,因為CSV是標準的格式,如果連這樣標準的格式我們都要自己手動去拆解的話,也太沒有效率了,使用csv模組可以讓整件事變得更加地簡單。請參考以下的程式碼:

import csv
fp = open("data05.csv", "r", encoding="utf-8")
csv_reader = csv.reader(fp)
data = list(csv_reader)
fp.close()
print(data)

使用上面這樣的寫法等於是利用csv.reader(fp)去幫我們解讀資料, 最後利用list(csv_reader)就可以取出正確的格式了,執行之後的結果如下:

[['姓名', '國文', '英文'], ['王小花', '89', '65'], ['林小明', '45', '89', '80'], ['陳小華', '92', '90', '65']]

從上述的資料結果可以看出,這是一個2維的串列,假設我們把資料放在變數data中,則data[0]即為表格的標題列,data[1]之後的內容即為實際資料的內容,如果想要把這些資料列印出來並加以計算,可以使用以下的程式完成:

import csv
fp = open("data05.csv", "r", encoding="utf-8")
csv_reader = csv.reader(fp)
data = list(csv_reader)
fp.close()
for d in data[1:]:
    total = int(d[1])+int(d[2])
    average = total / 2
    print("{}的總分是{},平均是{}".format(d[0], total, average))

上述程式的執行結果如下(在for迴圈中使用data[1:]的原因是為了把標題列去掉):

王小花的總分是154,平均是77.0
林小明的總分是134,平均是67.0
陳小華的總分是182,平均是91.0

之後如果在網路上遇到CSV格式的檔案,就可以放心地使用csv模組來加以讀取,非常方便。以內政部的「全國各鄉鎮市區前二十大姓人口數」資料為例,它的網址如下:

https://data.moi.gov.tw/MoiOD/Data/DataDetail.aspx?oid=54BED408-2A7D-49D2-A247-FC63C156A8BB

當我們把檔案下載之後會得到1個.zip的壓縮檔,解壓縮之後會得到2個CSV的檔案,如下所示:

因為原始的檔案名稱較長,我們分別把它們命名為t1.csv以及t2.csv,以t1.csv為例,以下的程式可以把t1.csv的資料讀取到變數data中:

import csv
fp = open("t1.csv", "r", encoding="utf-8")
csv_reader = csv.reader(fp)
data = list(csv_reader)
fp.close()
print(data[1])

上述的程式在解析之後會顯示出第1列的內容,其內容剛好是中文的欄位名稱,如下所示:

['統計年月', '區域別', '姓氏', '性別', '人口數']

這些資料全部有14722筆,我們可以利用一個迴圈把所有的資料找過一遍,而且利用if敘述,過濾出想要顯示的內容,假設我們只想要顯示高雄市楠梓區的前20大姓氏資料,可以把程式編寫如下:

import csv
fp = open("t1.csv", "r", encoding="utf-8")
csv_reader = csv.reader(fp)
data = list(csv_reader)
fp.close()
for row in data:
    if "楠梓區" in row[1]:
        print(row[2], row[3], row[4])

上述的程式執行結果如下:

陳 男 9585
陳 女 9945
林 男 6650
林 女 6784
黃 男 5973
黃 女 6073
李 男 4760
李 女 4943
張 男 4202
張 女 4210
王 男 4141
王 女 4064
吳 男 3514
吳 女 3563
蔡 男 3467
蔡 女 3495
劉 男 2769
劉 女 2899
楊 男 2704
楊 女 2700
許 男 1831
許 女 1976
鄭 男 1769
鄭 女 1869
郭 男 1614
郭 女 1718
曾 男 1584
曾 女 1582
謝 男 1504
謝 女 1656
洪 男 1311
洪 女 1394
蘇 男 1266
蘇 女 1295
邱 男 1132
邱 女 1211
葉 男 996
葉 女 1079
周 男 894
周 女 943

如你所看到的,這些姓氏的人口數資料即為楠梓區的前20大姓氏以性別為區分的人數,不知道同學們自己的姓氏有沒有在這裡面呢?

有了這個資料,不知道同學們有沒有興趣知道全台灣的前十大姓氏排行榜各是哪些呢?面對這些資料,又該如何修改我們的程式以便統計出我們感興趣的結果呢?

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *