在
上一篇的文章中,我們提到關於開啟CSV文件的方式,從單純的當作純文字文件開啟,到引入Python內建的csv模組對CSV類型的檔案做基本的讀寫操作。在這篇文章中,我們將進一步使用Pandas這套強大的工具,來簡化CSV文件處理的流程。Pandas是Python用於數據處理與分析的軟體庫,它提供處理表格與時間序列的資料結構和運算操作,屬於Python的外部模組,在使用時必須事先安裝導入。
開始之前,我們先到之前提過位於
交通部中央氣象局的
觀測資料查詢系統,下載新北市永和區2022年2月份的氣象資料,在左方欄位選取查詢資料的相關資訊後,按下「查詢」按鈕後,就會開啟選取資料的報表與下載連結,點選「CSV下載」可將檔案下載下來,並移動到PyCharm專案所在的資料夾。
安裝Pandas模組
初次使用Pandas模組時,在PyCharm打入「import pandas」會跳出警示的燈泡符號,表示此模組尚未安裝在專案中,我們可以依照在
模組這篇文章的說明,到PyCharm的Settings功能頁中新增模組;簡單一點的方式,在這裡點選燈泡即可跳出「Install package pandas」的選項,點擊該選項後就會自動安裝。
安裝的過程在PyCharm下方的狀態列會顯示「Installing package 'pandas'...」的提示與進度條,安裝完成後也會在Event Log跳出安裝成功的訊息。
此時我們到PyCharm的Settings功能頁中即可看到pandas以及其相關的模組已經被安裝到專案中。
開啟CSV檔案
pandas.read_csv(filepath_or_buffer, sep=NoDefault.no_default, header='infer', usecols=None, nrows=None)
- filepath_or_buffer:檔案路徑。
- sep:分隔字元,預設為","。
- header:設定哪一列為欄位標籤,預設為0。
- usecols:設定讀取的欄位。
- nrows:設定讀取前幾列。
先以不帶參數的方式開啟前面下載的檔案,把讀取的內容印出來。
import pandas
weather_data = pandas.read_csv("C0AH10-2022-02.csv")
print(weather_data)
在輸出視窗中,可以得到全部月報表的資料,因為資料過長的關係,大部分被以"..."取代。
觀測時間(day) 測站氣壓(hPa) 海平面氣壓(hPa) ... 日最高紫外線指數 日最高紫外線指數時間(LST) 總雲量(0~10)
0 ObsTime StnPres SeaPres ... UVI Max UVI Max Time Cloud Amount
1 01 1016.1 ... ... ... ... ...
2 02 1016.6 ... ... ... ... ...
3 03 1014.9 ... ... ... ... ...
4 04 1018.9 ... ... ... ... ...
5 05 1021.9 ... ... ... ... ...
6 06 1020.9 ... ... ... ... ...
7 07 1014.2 ... ... ... ... ...
8 08 1017.7 ... ... ... ... ...
9 09 1016.0 ... ... ... ... ...
10 10 1015.7 ... ... ... ... ...
11 11 1013.4 ... ... ... ... ...
12 12 1013.1 ... ... ... ... ...
13 13 1011.3 ... ... ... ... ...
14 14 1015.4 ... ... ... ... ...
15 15 1014.9 ... ... ... ... ...
16 16 1014.2 ... ... ... ... ...
17 17 1013.2 ... ... ... ... ...
18 18 1013.3 ... ... ... ... ...
19 19 1015.0 ... ... ... ... ...
20 20 1021.8 ... ... ... ... ...
21 21 1020.6 ... ... ... ... ...
22 22 1019.8 ... ... ... ... ...
23 23 1021.9 ... ... ... ... ...
24 24 1023.8 ... ... ... ... ...
25 25 1020.4 ... ... ... ... ...
26 26 1017.9 ... ... ... ... ...
27 27 1017.4 ... ... ... ... ...
28 28 1014.7 ... ... ... ... ...
[29 rows x 35 columns]
可以和以Excel開啟的氣象資料月報表互相參照。
為了更清楚觀察資料,可以將前面提到的參數帶入。假設我們想觀察前十天的溫度,可以指定想要輸出的欄位與列數,header=1表示以第二列做為欄位的標籤。
import pandas
weather_data = pandas.read_csv("C0AH10-2022-02.csv", header=1, usecols=["ObsTime", "Temperature"], nrows=10)
print(weather_data)
執行後,就可以看到簡潔的資料呈現。
ObsTime Temperature
0 1 16.8
1 2 17.0
2 3 15.8
3 4 14.3
4 5 13.6
5 6 14.4
6 7 17.6
7 8 15.6
8 9 16.5
9 10 17.2
甚至也可以像字典利用鍵值對的鍵找到對應的值一樣,利用欄位標籤來尋找對應的欄位,例如:
print(weather_data["Temperature"])
結果會印出"Temperature"欄位的資料:
0 16.8
1 17.0
2 15.8
3 14.3
4 13.6
5 14.4
6 17.6
7 15.6
8 16.5
9 17.2
我們可以與
上一篇處理CSV的方法比較一下,如果以csv模組開啟CSV檔案,想如同上方一樣輸出每日氣溫的資料,就必須額外花費一些心力來處理讀取的資料。
import csv
with open("C0AH10-2022-02.csv", encoding="utf-8") as weather_file:
weather_data = csv.reader(weather_file)
for row in weather_data:
if row[7] != "氣溫(℃)":
print(row[0], row[7])
Pandas資料結構
使用type()函式看一下weather_data的資料類型,它告訴我們weather_data整體是一個DataFrame型態的資料,其中的每一個欄位是Series型態的資料。
print(type(weather_data))
print(type(weather_data["Temperature"]))
執行結果:
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.series.Series'>
DataFrame和Series共同構成了Pandas的基本資料結構,可以存放整數、浮點數、字串、串列、字典...等資料型態。其中,除了存放的資料以外,DataFrame包含了索引與欄位標籤,Series僅包含了索引。
我們也可以看一下欄位標籤與索引的內容,例如在weather_data這個DataFrame中,欄位標籤與索引的內容如下:
print(weather_data.columns)
print(weather_data.index)
可看到欄位標籤即是在開啟CSV檔案時所指定的"ObsTime"與"Temperature",而索引因為沒有特別指定,預設由0開始編碼。
Index(['ObsTime', 'Temperature'], dtype='object')
RangeIndex(start=0, stop=10, step=1)
在weather_data["Temperature"]這個Series中,索引值和weather_data相同。
print(weather_data["Temperature"].index)
執行結果:
RangeIndex(start=0, stop=10, step=1)
建立Series物件
Pandas使用Series()方法來建立物件,其
語法如下:
pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)
以下範例重建weather_data["ObsTime"]與weather_data["Temperature"]兩個Series,首先建立索引串列index,在Series()方法中的data帶入ObsTime與Temperature的資料、在index中帶入索引串列。
index = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ObsTime_series = pandas.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], index)
Temperature_series = pandas.Series([16.8, 17.0, 15.8, 14.3, 13.6, 14.4, 17.6, 15.6, 16.5, 17.2], index)
print(ObsTime_series)
print(Temperature_series)
執行結果:
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
dtype: int64
0 16.8
1 17.0
2 15.8
3 14.3
4 13.6
5 14.4
6 17.6
7 15.6
8 16.5
9 17.2
dtype: float64
建立DataFrame物件
Pandas使用DataFrame()方法來建立物件,其
語法如下:
pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=None)
接下來的範例,我們想重建weather_data,因此首先先建立一個字典,以"ObsTime"及其資料內容做為一鍵值對、以"Temperature"及其資料內容做為另一鍵值對,並使用相同的索引串列,帶入DataFrame()方法中。
index = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
weather_dict = {"ObsTime": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"Temperature": [16.8, 17.0, 15.8, 14.3, 13.6, 14.4, 17.6, 15.6, 16.5, 17.2]}
weather_dataframe = pandas.DataFrame(weather_dict, index)
print(weather_dataframe)
這樣就還原了從CSV檔案擷取下來的weather_data資料。
ObsTime Temperature
0 1 16.8
1 2 17.0
2 3 15.8
3 4 14.3
4 5 13.6
5 6 14.4
6 7 17.6
7 8 15.6
8 9 16.5
9 10 17.2
另一種方式,既然前面已經建立了weather_data["ObsTime"]與weather_data["Temperature"]兩個Series物件,我們可以藉由concat()方法將兩個Series組合在一起,
語法如下:
pandas.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)
需要注意的是,除了將Series物件帶入以外,這裡的axis參數必須設定為1,代表將兩個Series物件做為不同的欄位串接,而不是將第二個Series放在第一個Series之後,做為同一個欄位。
weather_dataframe_2 = pandas.concat([ObsTime_series, Temperature_series], axis=1)
print(weather_dataframe_2)
執行結果:
0 1
0 1 16.8
1 2 17.0
2 3 15.8
3 4 14.3
4 5 13.6
5 6 14.4
6 7 17.6
7 8 15.6
8 9 16.5
9 10 17.2
和前面的weather_data比較一下,是否發現有什麼地方不一樣?關鍵在於這裡我們是將兩個Series組合成DataFrame,而Series本身是不包含欄位標籤的。針對這個問題有兩個解決方式,第一種方式從Series物件著手,Series雖然沒有欄位標籤,但它有name屬性,在做DataFrame的串接之前,可以先設定Series的name屬性,串接之後就會自動做為DataFrame的欄位標籤。
ObsTime_series.name = "ObsTime"
Temperature_series.name = "Temperature"
weather_dataframe_2 = pandas.concat([ObsTime_series, Temperature_series], axis=1)
print(weather_dataframe_2)
第二種方式是從DataFrame著手,在串接形成DataFrame之後,直接修改DataFrame的column屬性。
weather_dataframe_2 = pandas.concat([ObsTime_series, Temperature_series], axis=1)
weather_dataframe_2.columns = ["ObsTime", "Temperature"]
print(weather_dataframe_2)
這兩種方法都可以完整建立原本的weather_data資料。
ObsTime Temperature
0 1 16.8
1 2 17.0
2 3 15.8
3 4 14.3
4 5 13.6
5 6 14.4
6 7 17.6
7 8 15.6
8 9 16.5
9 10 17.2
總結
這篇文章中,我們說明了Pandas這套強大的外部模組處理CSV資料的方式,並利用網路上可以找到的天氣資料,展示如何使用PyCharm導入Pandas模組、讀取CSV檔案、以及Series和DataFrame的資料結構,並說明如何從頭自己創造出Series和DataFrame物件,最後還原我們從CSV檔案所讀取出來的資料。
程式範例