iT邦幫忙

2025 iThome 鐵人賽

DAY 7
0

今天Focus在csv和excel的處理。明天介紹JSON。

Pandas是一種in-memory工具,也就是讀檔需要先把資料存在到記憶體,所以書上建議系統的記憶體是dataframe大小的3-10倍,才有餘裕去處理data的運算。

可以利用開放資料網站做測試

csv

CSV講得比較詳細。主要是因為工作上應用的比較多,加上excel跟它能使用的屬性差不多。最基礎的讀csv檔非常直覺,而且一行解決。

讀取csv

df.read_csv()

但是存取檔案的過程常常不是那麼輕鬆的,遇上的問題包含但不限以下

  • 編碼
  • 缺失值處理
  • 檔案太大
  • 格式不如預期

這些問題,pandas也有因應的作法。
要先知道檔案的編碼才能指定用什麼編碼。可以用notepad++開啟檔案查看。
https://ithelp.ithome.com.tw/upload/images/20250920/20178631cJKPRhReze.png

Pandas提供很多屬性可以靈活讀取。

#指定編碼為big5
df = pd.read_csv('YouBike.csv', encoding='big5')
#指定編碼為utf-8-sig, for具有bom的utf8編碼
df = pd.read_csv('meterials.csv', encoding='utf-8-sig')

#將內容為"NA","--","無"的data都設為缺失值
df = pd.read_csv("YouBike.csv", encoding='big5', na_values=["NA","--","無"])
#將id欄設定為索引
df = pd.read_csv("YouBike.csv", index_col="seq")
# 指定欄位
df = pd.read_csv("YouBike.csv", usecols=["id","name"])  
# 只讀前 1000 列
df = pd.read_csv("YouBike.csv", nrows=1000) 

就是這麼ez!接下來聊聊關於大檔案。

大檔案處理

用這個檔案當範例:https://catalog.data.gov/dataset/electric-vehicle-population-data

首先介紹一個指令: df.info()
它會回傳如下資料

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 261698 entries, 0 to 261697
Data columns (total 17 columns):

Index Column Non-Null Count Dtype
0 VIN (1-10) 261698 non-null object
1 County 261688 non-null object
2 City 261688 non-null object

dtypes: float64(5), int64(2), object(10)
memory usage: 33.9+ MB

可以很快速的知道是否有缺失值要處理,非數值欄位pandas會將其型別轉為object,數值則是int64,

大量的字串會佔用大量的記憶體空間,可以把它轉成category型態,有用過c#或python的朋友,可以把它想成enum,每個data將會被以數值存檔,只是有個對照檔,這樣能節省大量的記憶體空間,並且在groupby / value_counts / merge的運算會更快。

Category 特別適合重複值多、有限種類的欄位,優點是 省記憶體 + 提升效能 + 支援有序比較。

數值的部分則如果確定是短數值,也可以改成Int8。

df = pd.read_csv('Electric_Vehicle.csv', dtype={"County":"category",
                                                "Postal Code":"Int8",
                                                "Model Year":"Int8", 
                                                "Make":"category", 
                                                "Model":"category", 
                                                "Electric Vehicle Type":"category", 
                                                "Electric Range":"Int8",
                                                "Base MSRP":"Int8",
                                                "Electric Utility":"category",
                                                "Legislative District":"Int8"})
df.info()

結果memory usage就立刻從33.9+ MB → 16.8+ MB,是不是很amazing!

另一個狀況是它大到不太方便一次load進來,那可以跟zip一樣分割處理,並指定chunksize(每次讀進來的大小)

for chunk in pd.read_csv("big.csv", chunksize=100000):
    process(chunk)

可以用的屬性還有很多,我就簡單列一下我目前了解的了。

寫入csv

df.to_csv()

to_csv就比較簡單了,只要注意兩件事:

  • 編碼
    Pandas預設會存utf8,但如果你的csv裡面有中文,且這個data不只是給程式讀,還需要用excel開來看的話,建議要存utf-8-sig。上次我才在編碼的深淵掙扎了一天就為了沒有bom的utf8開起來是亂碼。

  • index
    如果程式裡沒有給dataframe set index,可以很輕鬆愉快的to_csv(),但要是有設定的話記得要把index設定成false,不然會多出不必要的欄位

#編碼設定成utf-8-sig且index為false
df.to_csv("output.csv", index=False, encoding="utf-8-sig")
#只存特定欄位
df.to_csv("out.csv", columns=["id","name"], index=False)
#浮點數格式化
df.to_csv("out.csv", float_format="%.2f")

也可以搭配昨天的資料過濾的結果再to_csv,總之就是一個靈活的熊貓師父。

Excel

讀取Excel

df.read_excel()

多數的屬性跟csv是一樣的,但畢竟是excel,可以指定sheet_name也是合理的,沒有指定sheet_name會預設返回第一個sheet。

#df_0和df_1是一樣der
df_0 = pd.read_excel('ubike_excel.xlsx')
df_1 = pd.read_excel('ubike_excel.xlsx', sheet_name='ubike')
df_2 = pd.read_excel('ubike_excel.xlsx', index_col=0, sheet_name='ubike_2')

#讀多個 sheet(回傳 dict)
dfs = pd.read_excel("ubike_excel.xlsx", sheet_name=["ubike","ubike_2"])
#讀全部 sheet
dfs = pd.read_excel("ubike_excel.xlsx", sheet_name=None) 
#指定欄位與列
df = pd.read_excel("ubike_excel.xlsx", usecols=["月份","發布機關名稱"], nrows=100)

寫入Excel

寫excel有兩個方式,如果只是要做一個sheet的保存,可以直接dataframe去to_excel,如果是多個sheet就需要先使用pd.ExcelWrite,

  • df.to_excel()
  • pd.ExcelWriter() > df.to_excel()

要使用ExcelWriter需要pip install xlsxwriter

df_1.to_excel("single.xlsx",sheet_name="Summary", index=False)
df_2[df_2["西元年"]==2024].to_excel("single_2024.xlsx", sheet_name="Year2024", index=False)

with pd.ExcelWriter("multi.xlsx", engine="xlsxwriter") as writer:
    df_1.to_excel(writer, sheet_name="Summary", index=False)
    df_2[df_2["西元年"]==2024].to_excel(writer, sheet_name="Year2024", index=False)

下集預告:明天來講JSON。


上一篇
Day5: 條件過濾
下一篇
Day7: 資料讀寫 - JSON/關於orientation
系列文
從零開始Pandas-外加一點Matplotlib11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言