2020年1月20日 星期一

xls 或 xlsx 批次轉成 csv

看到 非典型大選分析 的漂亮地圖版大選資料視覺化, 我也手癢了。 到 中選會資料庫 的歷屆公職選舉資料, 找到 2020-第 10 屆 立法委員選舉, 下載了 「各投票所得票明細及概況」, 用 unzip -O cp950 檔名.zip 解壓縮。 下一個問題是: 要怎麼把一堆 xls 檔轉成 csv 檔? 對, 可以用 libreoffice 一個一個打開、 另存新檔。 可是我希望可以用指令批次處理啊~

【方法一】 Ubuntu 有一個 catdoc 套件, 其中包含 xls2csv 指令。 可惜轉出來都是亂碼。 用 xls2csv -l 查看, 發現它並不支援 cp950 (Windows 對 big5 編碼的稱呼), 只好放棄。

【方法二】 Libreoffice 有一個 "headless" 模式不會開視窗, 直接在命令列上轉檔。 根據 這個問答 解決編碼問題, 再根據 官網文件 指定以 ";" (ASCII 碼 59) 作為分隔符號 (因為 xls 檔裡面的數字包含逗號), 最後得到成功的轉檔指令: libreoffice --headless --convert-to csv --infilter=CSV:59,,UTF8 --outdir /tmp '區域立委-A05-2-得票數一覽 表(臺中市).xls' 但是! 它永遠只轉第一個分頁 (sheet); 若要轉其他分頁, 有點麻煩

[推] 【方法三】 Python 有一個套件叫做 csvkit (簡中教學) 用 pip3 install --user csvkit 安裝之後, 可以用 in2csv --names '區域立委-A05-2-得票數一覽表(臺中市).xls' 列出所有分頁, 再用 in2csv --sheet '臺中市第2選舉區' '區域立委-A05-2-得票數一覽表(臺中市).xls' 把其中一個分頁轉成 csv 檔, 很方便! 一個小缺點: csvkit 的相依套件蠻多的 -- 可以 用 pipdeptree 畫圖 讚嘆一下。

[推]【方法四】 (從 這個問答 學來的) 如果想要自己寫 python 程式, 可以直接用 pandas 的讀取 xls 功能: 安裝套件 pip3 install --user pandas xlrd 然後進入 python3, 用 .read_excel() 讀入 xls 檔、 用 .keys() 查看分頁清單、 用 .to_csv() 把其中一個分頁存檔:

import pandas as pd
xlsdf = pd.read_excel('區域立委-A05-2-得票數一覽表(臺中市).xls', None, encoding='utf-8', skiprows=2)
xlsdf.keys()
# 順便小小整理一下:
xlsdf['臺中市第2選舉區'].rename(columns={'Unnamed: 0':'鄉鎮區','Unnamed: 1':'村里','Unnamed: 11':'選舉人數'},inplace=True)
xlsdf['臺中市第2選舉區']['鄉鎮區'].fillna(method='ffill',inplace=True)
xlsdf['臺中市第2選舉區'].to_csv('/tmp/result.csv', index=None, encoding='utf-8')

這篇文章介紹更多其他方法: 5 Methods to Convert xlsx Format Files to CSV on Linux CLI

如果你的 xls 檔 「只含英文不含國語」, 那麼 catdoc 是最輕巧的方案。 如果你的 xls 檔只有一個分頁, 那麼也可以不必安裝額外套件, 直接使用 libreoffice 的 headless 模式。 一般說來,我會推薦 csvkit 轉檔, 這對於習慣寫 bash script 的讀者而言最為通用又簡單。

不過這次我要處理的立委得票統計, 想要去掉立委姓名、 根據政黨別來加總。 其中 「無」 黨在一個選區內可能出現好幾位, 而且原住民立委採用複數選區制, 也就是一個選區可以有好幾位同黨參選人, 所以後續還是要寫程式處理。 雖然 處理高維度資料時, pandas 很慢, 但現在這個簡單的場合卻正好適用。 於是寫出 elecxls2csv.py 。 使用方式: 將上述立委檔案解壓縮後, python3 elecxls2csv.py '區域立委-A05-2-得票數一覽表(臺中市).xls' 會在 /tmp 底下產生 「區域立委_臺中市第?選舉區.csv」 共 8 個檔案 (對應到 8 個分頁)。 也可以一次處理很多個 xls 檔: python3 elecxls2csv.py $(ls *.xls | grep -v '各村里') 。 更多選項請見 python3 elecxls2csv.py -h

有了 csv 檔, 後續要畫圖、 分析就方便多啦!

沒有留言:

張貼留言

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。