不間斷 Python 挑戰 Day 29 - 使用Pandas處理CSV文件

2022/04/07閱讀時間約 22 分鐘
上一篇的文章中,我們提到關於開啟CSV文件的方式,從單純的當作純文字文件開啟,到引入Python內建的csv模組對CSV類型的檔案做基本的讀寫操作。在這篇文章中,我們將進一步使用Pandas這套強大的工具,來簡化CSV文件處理的流程。Pandas是Python用於數據處理與分析的軟體庫,它提供處理表格與時間序列的資料結構和運算操作,屬於Python的外部模組,在使用時必須事先安裝導入。
開始之前,我們先到之前提過位於交通部中央氣象局觀測資料查詢系統,下載新北市永和區2022年2月份的氣象資料,在左方欄位選取查詢資料的相關資訊後,按下「查詢」按鈕後,就會開啟選取資料的報表與下載連結,點選「CSV下載」可將檔案下載下來,並移動到PyCharm專案所在的資料夾。
觀測資料查詢系統
氣象資料月報表
關於Pandas函式庫的詳細用法,可以參考官方網站的說明,這篇文章主要針對在PyCharm中使用Pandas處理CSV文件的方法,做進一步的說明。
https://pandas.pydata.org/

安裝Pandas模組

初次使用Pandas模組時,在PyCharm打入「import pandas」會跳出警示的燈泡符號,表示此模組尚未安裝在專案中,我們可以依照在模組這篇文章的說明,到PyCharm的Settings功能頁中新增模組;簡單一點的方式,在這裡點選燈泡即可跳出「Install package pandas」的選項,點擊該選項後就會自動安裝。
未安裝模組警示
安裝Pandas選項
安裝的過程在PyCharm下方的狀態列會顯示「Installing package 'pandas'...」的提示與進度條,安裝完成後也會在Event Log跳出安裝成功的訊息。
安裝進行中
安裝完成
此時我們到PyCharm的Settings功能頁中即可看到pandas以及其相關的模組已經被安裝到專案中。
檢視專案安裝模組

開啟CSV檔案

Pandas使用read_csv()函式讀取CSV檔案,根據Pandas網站的使用說明,擷取部分參數如下:
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開啟的氣象資料月報表互相參照。
以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僅包含了索引。
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檔案所讀取出來的資料。

程式範例

為什麼會看到廣告
Wei-Jie Weng
Wei-Jie Weng
留言0
查看全部
發表第一個留言支持創作者!