Pandas 提供了便捷的資料視覺化功能,可以直接從 Series 和 DataFrame 物件生成圖表。這對於快速理解資料分佈、趨勢和關聯性非常有幫助。利用 pd.Series.plotpd.DataFrame.plot,可以輕鬆建立各種基本圖表,例如折線圖、條形圖、區域圖和餅圖等。這些方法預設使用 Matplotlib 作為後端,方便進行更細緻的圖表客製化。在資料探索階段,快速生成圖表有助於識別異常值、缺失值以及潛在的分析方向。需要注意的是,這些基本圖表型別通常適用於已聚合的資料。對於未聚合的資料,則需要先進行資料聚合或使用更進階的視覺化工具,例如 Seaborn。

捕捉各隊伍得分最高之排序位置

棒球比賽允許隊伍安排九名擊球手形成「擊球順序」,從第一名開始按順序進行接替擊打直至最後一人再重新迴圈回第一名。通常隊伍會將一些優秀擊手安排在「擊球順序」前端(即低號位置),以增加他們得分機會。然而這並不表示第一名擊手總是第一個得分。 在此範例中我們將觀察所有大聯盟棒球場隊伍從2年開始至今累積得到之得分並分析那個排序位置為他們贏得最高比分.

首先我們需要讀取與年份及隊伍相關之資料集並將年份與隊伍標記為索引:

df = pd.read_parquet("data/runs_scored_by_team.parquet").set_index(["year", "team"])
print(df)

內容解密:

df = pd.read_parquet("data/runs_scored_by_team.parquet").set_index(["year", "team"])

Pandas 的 read_parquet() 函式用於讀取 Parquet 檔案格式並將讀取到資料放置於一個 DataFrame 中。 “set_index([‘year’,’team’])”用來設定 “year”和 “team”這兩個變數作為DataFrame資料框架中的索引。 接著將 “year” 和 “team” 作為雙層索引建立起來方便查詢特定年份或團隊資料。 要注意的是 “DataFrame.set_index()” 函式會傳回一個新建立 DataFrame 不會修改原本DataFrame。

print(df)

Pandas 在處理雙層索引時可以透過 .loc[] 和 .iloc[] 效率地查詢特定資料亦或是切割某段資料範圍。透過以下方法亦能夠實作對該雙層索引Dataframe做高效率操作

透過以下方法我們可以得知哪些隊伍在那些年份中得到了最高分:

top_positions = df.idxmax(axis=1)
print(top_positions)

內容解密:

top_positions = df.idxmax(axis=1)

在 Python 中使用 idxmax() 函式是針對某個維度獲得最大值對應索引。 資料框架有兩個維度:行 (axis=o) 和列 (axis=l);所以當呼叫 idxmax(axis=l) 時,它會計算每一列最大值對應索引並且傳回一個 Series,這是一個與原始 DataFrame 行數相同的一維陣列。 我們會將計算結果儲存於 top_positions 中以便後續處理。

print(top_positions)

# 年份     隊伍         排序最高得分專案(例如:第N名)

year team           best_position_in_order

...
...
...
...

透過 pd.Series.value_counts(normalize=True) 函式獲得頻率我們將瞭解到該擊者順序代表團隊獲得最高分數:

top_position_frequency = top_positions.value_counts(normalize=True)
print(top_position_frequency)

內容解密:


top_position_frequency = top_positions.value_counts(normalize=True)

# value_counts(normalize=True)會統計每個唯一值(擊者順序)在Series中的頻率,並且歸一化(歸為總和為l),這樣我們將得到一個百分比而不是絕對數量

print(top_position_frequency)

# 輸出結果為:

#        best_position_in_order     frequency

#        
---
---
-                   
---
-
---
-

#        first                  ...%      # 第一擊者排名最高

#        second                 ...%      # 第二擊者排名最高

#        third                  ...%      # 第三擊者排名最高

若想了解更多細節例如第一擊者沒有帶領團隊獲得最高分數時第二擊者排名最高時如何?透過以下方法即可取得:


mask = top_positions.eq("first")

second_top_positions = df[mask].drop(columns=["first"]).idxmax(axis=l).value_counts(normalize=True)

print(second_top_positions)

內容解密:

使用 布林遮罩 (Boolean Masking)技術來篩選滿足條件(第一名擊者沒有帶領團隊獲得分數最高時)後續進行資料處理。 首先透過 top_positions.eq(“first”) 獲得一個布林序列,其中所有等於 “first” 的地方為 True,其餘為 False。 然後透過 df[mask] 對 Dataframe 做篩選操作,僅保留第一擊者沒有帶領團隊獲得分數最高時符合條件之行,接著刪除 “first"欄位,並對剩餘資料透過 idxmax(axis=l) 取得第二擊者排名最高之專案。 最後透過 value_counts(normalize=True) 把結果歸一化得到頻率。 根據上述分析結果我們可以發現當第一擊者無法帶領團隊獲得最高得分時 第二擊者也會成為領先團隊獲得高得分機率較高約百分之五十

資料視覺化在資料探索中的重要性

資料視覺化在資料探索分析、報告製作以及應用程式開發中扮演著關鍵角色。在進行資料探索分析時,通常是獨自或與小組合作,快速生成圖表來幫助理解資料。視覺化能幫助識別異常值和缺失資料,並引發進一步的分析需求。這類別視覺化主要用於個人理解,圖表不需要完美。

當準備為報告或應用程式製作視覺化時,需採取不同的方法。必須注意細節,並將所有可能的視覺化縮小到最能代表資料的少數幾個。優質的資料視覺化能讓觀看者享受資訊提取過程,就像影片讓觀眾沉浸其中,提供大量有趣的資訊。

Pandas 提供了 pd.Series.plotpd.DataFrame.plot 方法來快速生成圖表。這些方法會轉交給一個繪圖後端,預設使用 Matplotlib。我們將在本章稍後討論不同的後端,但在此之前,讓我們開始安裝 Matplotlib 和 PyQt5:

python -m pip install matplotlib pyqt5

本章所有程式碼範例都假設以下匯入:

import matplotlib.pyplot as plt
plt.ion()

上述命令啟用 Matplotlib 的互動模式,每次執行繪圖命令時會自動生成和更新圖表。如果執行繪圖命令但沒有顯示圖表,很可能是非互動模式(可以使用 matplotlib.pyplot.isinteractive() 進行檢查),這時需要顯式呼叫 matplotlib.pyplot.show() 才能顯示圖表。

本章將涵蓋的範例

  • 從聚合資料生成圖表
  • 繪製未聚合資料的分佈情況
  • 使用 Matplotlib 進一步自定義圖表
  • 探索散佈圖
  • 探索類別資料
  • 探索連續資料
  • 使用 Seaborn 生成高階圖表

從聚合資料生成圖表

Pandas 函式庫讓我們能夠輕鬆地視覺化 pd.Seriespd.DataFrame 物件中的資料,分別使用 pd.Series.plotpd.DataFrame.plot 方法。在本範例中,我們將從相對簡單的折線、條形、區域和餅圖開始,同時也會看到 Pandas 提供的高層次自定義選項。這些圖表型別雖然簡單,但有效地使用它們可以大大幫助探索資料、識別趨勢以及與非技術同事分享研究結果。

需要注意的是,這些圖表型別假設您的資料已經是聚合後的結果。如果您處理的是尚未聚合的資料,需要參考第七章《重塑 DataFrame》和第八章《群組分析》,或者本章稍後介紹的《使用 Seaborn 生成高階圖表》範例中的技術。

範例程式碼:從聚合資料生成圖表

import pandas as pd

# 建立一個簡單的 pd.Series 表示七天內的書籍銷售量
ser = pd.Series(
    (x ** 2 for x in range(7)),
    name="book_sales",
    index=(f"Day {x + 1}" for x in range(7)),
    dtype=pd.Int64Dtype(),
)
print(ser)

內容解密:

此段程式碼建立了一個 Pandas Series 物件 ser,表示七天內的書籍銷售量。我們使用生成器 (x ** 2 for x in range(7)) 生成每天銷售量(平方值),並為每天分配了形如 “Day n” 的索引標籤。name 屬性設定為 “book_sales”,而 dtype=pd.Int64Dtype() 用於指定資料型態為整數。

生成折線圖

ser.plot()
plt.show()

內容解密:

此程式碼會生成一個折線圖,其中 x 軸上的標籤來自 Series 的索引(即 “Day n”),而 y 軸上的值則對應 Series 中的資料。折線圖假設資料是連續的,因此會顯示每天之間的值。

生成條形圖

ser.plot(kind="bar")
plt.show()

內容解密:

此程式碼會生成一個條形圖,其中 x 軸上的標籤來自 Series 的索引(即 “Day n”),而 y 軸上的值則對應 Series 中的資料。條形圖將每天顯示為離散值。

生成水平條形圖

ser.plot(kind="barh")
plt.show()

內容解密:

此程式碼會生成一個水平條形圖,其中 x 軸上的值對應 Series 中的資料,而 y 軸上的標籤來自 Series 的索引(即 “Day n”)。這種方式讓人更容易從上到下閱讀。

生成區域圖

ser.plot(kind="area")
plt.show()

內容解密:

此程式碼會生成一個區域圖,它類別似於折線圖但會填滿折線下方的區域。這樣可以強調不同區域之間的差異。

生成餅圖

ser.plot(kind="pie")
plt.show()

內容解密:

此程式碼會生成一個餅圖,其中每個餅片代表 Series 中的一個值。餅片的大小由對應值決定,索引標籤則表示每個餅片。

DataFrame 的視覺化

當處理 DataFrame 時,API 與 Series 的一致性保持不變,但可能需要提供更多關鍵字引數來達到所需的視覺化效果。

延伸範例:同時顯示書本銷售量和退貨量

df = pd.DataFrame({
    "book_sales": (x ** 2 for x in range(7)),
    "book_returns": [3, 2, 1, 0, 1, 2, 3],
}, index=(f"Day {x + 1}" for x in range(7)))
df = df.convert_dtypes(dtype_backend="numpy_nullable")
print(df)

內容解密:

此段程式碼建立了一個 DataFrame 物件 df,包含兩列:「book_sales」和「book_returns」。每列都有七個元素(從零到六),並且有與前面相同格式的索引標籤「Day n」。DataFrame 的轉換指定為 numpy_nullable 型別以確保整數型態正確處理。

生成 DataFrame 的折線圖

df.plot()
plt.show()

內容解密:

此程式碼會生成 DataFrame 的折線圖,其中每一列都用不同顏色表示。「book_sales」和「book_returns」兩列分別以不同顏色線條表示。

生成 DataFrame 的條形圖

df.plot(kind="bar")
plt.show()

內容解密:

此程式碼會生成 DataFrame 的條形圖,「book_sales」和「book_returns」兩列分別以不同顏色表示。

生成堆積疊條形圖

df.plot(kind="bar", stacked=True)
plt.show()

內容解密:

此程式碼會生成堆積疊條形圖,「book_sales」和「book_returns」兩列分別以堆積疊方式表示。

水平堆積疊條形圖

df.plot(kind="barh", stacked=True)
plt.show()

內容解密:

此程式碼會生成水平堆積疊條形圖,「book_sales」和「book_returns」兩列分別以堆積疊方式表示。

透過這些基本範例展示瞭如何從聚合後的資料中建立各種常見型別的視覺化效果。下一節將進一步探討如何自定義這些視覺化效果以更好地滿足具體需求。