在資料科學領域,資料清理和視覺化是不可或缺的環節。資料清理確保資料品質,而視覺化則幫助我們理解資料的分佈和趨勢。本文將示範如何使用 Python 的 pandas 和 Seaborn 函式庫進行資料清理和視覺化。首先,我們會探討如何處理缺失值,包含識別、分析和補充缺失值的策略。接著,我們將使用 Matplotlib 和 Seaborn 建立各種圖表,例如直方圖、KDE 圖、箱型圖、小提琴圖和蜂群圖,以視覺化資料的分佈和特徵。最後,我們將探討 pandas 的資料重塑功能,包含串接、合併和樞紐分析等技巧,讓讀者能有效地整理和分析資料。這些技巧對於從資料中提取有價值的洞察至關重要,也是資料科學家必備的技能。
資料清理與視覺化分析
在進行資料分析時,資料清理是至關重要的一步。資料清理的目的是確保資料的完整性和準確性,以便進行有效的分析。本章節將討論如何清理和視覺化資料。
處理缺失值
在資料集中,缺失值是常見的問題。缺失值可能會導致分析結果的偏差或錯誤。因此,處理缺失值是資料清理的重要步驟。
檢查缺失值
首先,我們需要檢查資料集中哪些欄位存在缺失值。可以使用 pd.isna() 函式來檢查缺失值。
df.select_dtypes(exclude=["string"]).pipe(pd.isna).sum().sort_values(ascending=False).head()
分析缺失值
檢查結果顯示,「cylinders」 和 「displ」 欄位存在較多的缺失值。進一步分析發現,這些缺失值主要對應於電動車輛。
df.loc[df["cylinders"].isna(), ["make", "model"]].value_counts()
補充缺失值
對於 「cylinders」 欄位,由於它是一個類別型變數,將缺失值補充為 0 是合理的。
df["cylinders"] = df["cylinders"].fillna(0)
然而,對於 「displ」 欄位,由於它是一個連續型變數,補充缺失值為 0 可能會導致平均值的偏差。因此,決定保留這些缺失值。
資料視覺化
視覺化是理解資料分佈和特徵的重要工具。本文將介紹如何使用直方圖和 KDE 圖來視覺化連續型資料。
直方圖
直方圖是一種常見的視覺化工具,用於展示資料的分佈。
df["city08"].plot(kind="hist", bins=30)
KDE 圖
KDE(Kernel Density Estimation)圖是一種平滑的直方圖,可以更好地展示資料的分佈。
fig, axes = plt.subplots(nrows=2, ncols=1)
axes[0].set_xlim(0, 40)
axes[1].set_xlim(0, 40)
axes[0].set_ylabel("city")
axes[1].set_ylabel("highway")
df["city08"].plot(kind="kde", ax=axes[0])
df["highway08"].plot(kind="kde", ax=axes[1])
使用 Seaborn 進行進階視覺化
Seaborn 是一個根據 Matplotlib 的視覺化函式庫,提供了更多進階的視覺化功能。
條形圖
import seaborn as sns
sns.set_theme()
sns.set_style("white")
df = pd.DataFrame([
["Q1-2024", "project_a", 1],
["Q1-2024", "project_b", 1],
["Q2-2024", "project_a", 2],
["Q2-2024", "project_b", 2],
["Q3-2024", "project_a", 4],
["Q3-2024", "project_b", 3],
["Q4-2024", "project_a", 8],
["Q4-2024", "project_b", 4],
["Q5-2025", "project_a", 16],
["Q5-2025", "project_b", 5],
], columns=["quarter", "project", "github_stars"])
sns.barplot(df, x="quarter", y="github_stars", hue="project")
線圖
sns.lineplot(df, x="quarter", y="github_stars", hue="project")
圖表翻譯:
此條形圖與線圖用於比較兩個 GitHub 專案在不同季度獲得的星數。從圖中可以看出,project_a 的星數增長速度明顯快於 project_b。
資料視覺化:使用 Seaborn 分析電影評分趨勢
在資料視覺化的過程中,Seaborn 提供了一系列強大的工具,能夠幫助我們更好地理解資料的分佈和趨勢。本文將介紹如何使用 Seaborn 的不同視覺化方法來分析電影評分的變化。
資料準備
首先,我們需要準備好要分析的資料。在這個範例中,我們使用了包含電影標題、發行年份、IMDB 評分和內容分級的電影資料集。為了進行分析,我們需要對資料進行一些清理工作,例如將發行年份轉換為整數型別,並根據發行年份將電影劃分為不同的年代。
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# 讀取資料
df = pd.read_csv(
"data/movie.csv",
usecols=["movie_title", "title_year", "imdb_score", "content_rating"],
dtype_backend="numpy_nullable",
dtype={"title_year": pd.Int16Dtype()},
)
# 根據發行年份劃分年代
df = df.assign(
title_decade=lambda x: pd.cut(x["title_year"], bins=range(1910, 2021, 10))
)
程式碼解密:
pd.read_csv:用於讀取 CSV 檔案中的資料,並選取需要的欄位。dtype={"title_year": pd.Int16Dtype()}:指定title_year欄位的資料型別為整數,以確保資料的正確性。pd.cut:根據指定的區間範圍,將title_year劃分為不同的年代區間,並將結果儲存在title_decade欄位中。
使用箱型圖視覺化評分分佈
箱型圖是一種用於展示資料分佈的強大工具,可以幫助我們觀察不同年代的電影評分變化。
sns.boxplot(
data=df,
x="imdb_score",
y="title_decade",
)
plt.show()
圖表翻譯:
此箱型圖展示了不同年代的電影評分分佈。從圖中可以觀察到,中位數評分(黑線)隨著時間的推移呈現下降趨勢。此外,箱型圖的「鬍鬚」顯示了評分的離散程度,近年來的電影評分範圍似乎更廣。
使用小提琴圖進一步分析評分分佈
小提琴圖結合了箱型圖和 KDE(核密度估計)圖,可以更詳細地展示資料的分佈情況。
sns.violinplot(
data=df,
x="imdb_score",
y="title_decade",
)
plt.show()
圖表翻譯:
小提琴圖顯示了不同年代電影評分的 KDE 分佈,可以觀察到某些年代的評分呈現雙峰分佈,例如 1950 年代和 1960 年代,這表明這些年代的電影評分可能存在不同的群體。
使用蜂群圖觀察評分數量變化
蜂群圖可以幫助我們觀察不同年代的評分數量,並與評分分佈結合起來進行分析。
sns.swarmplot(
data=df,
x="imdb_score",
y="title_decade",
size=.25,
)
plt.show()
圖表翻譯:
蜂群圖顯示了不同年代的電影評分數量和分佈情況。從圖中可以看出,大部分的評分集中在 1990 年代以後,尤其是 2000 年至 2010 年之間。這表明近年來的電影評論數量明顯增加,而早期的電影評論相對較少。
資料重塑的藝術:掌握 pandas 的強大功能
在資料分析的世界裡,原始資料往往並非立即可用。為了獲得有價值的洞察,我們需要對資料進行清理、轉換和重塑,使其變得可用、可理解且易於分析。pandas 函式庫提供了多種強大的工具來幫助我們完成這些任務。在本章中,我們將探討 pandas 中的資料重塑功能,包括串接、合併、樞紐分析和資料轉換等。
使用 pd.concat 進行資料串接
串接是指將多個 DataFrame 物件堆積疊在一起的過程。pandas 支援垂直串接和水平串接兩種方式。垂直串接將 DataFrame 物件堆積疊在彼此之上,而水平串接則將它們並排放置。
垂直串接
import pandas as pd
# 建立兩個 DataFrame 物件
df1 = pd.DataFrame({
'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']
})
df2 = pd.DataFrame({
'A': ['A3', 'A4', 'A5'],
'B': ['B3', 'B4', 'B5']
})
# 垂直串接
result = pd.concat([df1, df2])
print(result)
#### 內容解密:
此程式碼首先建立了兩個 DataFrame 物件 df1 和 df2,然後使用 pd.concat 將它們垂直串接在一起。輸出的結果是一個新的 DataFrame,包含了 df1 和 df2 的所有資料。
水平串接
# 建立兩個 DataFrame 物件
df1 = pd.DataFrame({
'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']
})
df2 = pd.DataFrame({
'C': ['C0', 'C1', 'C2'],
'D': ['D0', 'D1', 'D2']
})
# 水平串接
result = pd.concat([df1, df2], axis=1)
print(result)
#### 內容解密:
此程式碼使用 pd.concat 將 df1 和 df2 水平串接在一起。axis=1 引數指定了串接的方向為水平方向。輸出的結果是一個新的 DataFrame,包含了 df1 和 df2 的所有欄位。
資料合併與重塑
除了串接之外,pandas 還提供了多種方法來合併和重塑資料,包括 pd.merge、pd.DataFrame.join 和 pd.pivot_table 等。這些方法可以幫助我們根據不同的需求對資料進行重組和分析。
使用 pd.merge 合併資料
# 建立兩個 DataFrame 物件
df1 = pd.DataFrame({
'key': ['K0', 'K1', 'K2'],
'A': ['A0', 'A1', 'A2']
})
df2 = pd.DataFrame({
'key': ['K0', 'K1', 'K2'],
'B': ['B0', 'B1', 'B2']
})
# 合併資料
result = pd.merge(df1, df2, on='key')
print(result)
#### 內容解密:
此程式碼使用 pd.merge 將 df1 和 df2 根據共同的 key 欄位進行合併。輸出的結果是一個新的 DataFrame,包含了 df1 和 df2 的相關資料。
資料重塑的高階技巧
pandas 還提供了多種高階的資料重塑技巧,包括使用 pd.DataFrame.stack、pd.DataFrame.unstack 和 pd.DataFrame.melt 等方法。這些方法可以幫助我們對資料進行更複雜的重組和分析。
使用 pd.DataFrame.pivot_table 進行樞紐分析
# 建立一個 DataFrame 物件
df = pd.DataFrame({
'A': ['foo', 'bar', 'foo', 'bar'],
'B': ['one', 'one', 'two', 'two'],
'C': ['small', 'large', 'large', 'small'],
'D': [1, 2, 3, 4]
})
# 進行樞紐分析
result = pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'])
print(result)
#### 內容解密:
此程式碼使用 pd.pivot_table 對 df 進行樞紐分析,根據 A 和 B 欄位進行分組,並計算 D 欄位在不同 C 欄位值下的平均值。輸出的結果是一個樞紐表,清晰地展示了資料的結構和關係。
資料重塑與合併:深入理解 pd.concat
在處理資料分析任務時,經常需要合併多個資料集。Pandas 提供的 pd.concat 函式是實作此任務的強大工具。本章節將探討如何使用 pd.concat 來合併 DataFrame 物件,並介紹其各種引數的使用方法。
基本使用方法
假設我們收集了不同公司在兩個不同季度內的股票表現資料。為了展示 pd.concat 的工作原理,我們故意讓兩個 DataFrame 物件涵蓋不同的時間段、公司和欄位。
import pandas as pd
# 建立第一季度的 DataFrame
df_q1 = pd.DataFrame([
["AAPL", 100., 50., 75.],
["MSFT", 80., 42., 62.],
["AMZN", 60., 100., 120.],
], columns=["ticker", "shares", "low", "high"])
# 資料型別轉換
df_q1 = df_q1.convert_dtypes(dtype_backend="numpy_nullable")
# 建立第二季度的 DataFrame
df_q2 = pd.DataFrame([
["AAPL", 80., 70., 80., 77.],
["MSFT", 90., 50., 60., 55.],
["IBM", 100., 60., 70., 64.],
["GE", 42., 30., 50., 44.],
], columns=["ticker", "shares", "low", "high", "close"])
# 資料型別轉換
df_q2 = df_q2.convert_dtypes(dtype_backend="numpy_nullable")
#### 內容解密:
這裡建立了兩個 DataFrame 物件,分別代表第一季度和第二季度的股票資料。`convert_dtypes` 方法用於最佳化資料型別,以提高運算效率。
### 合併 DataFrame
最基本的 `pd.concat` 呼叫方式是將多個 DataFrame 物件放入一個列表中。預設情況下,這些 DataFrame 將被垂直堆積疊。
```python
# 合併 DataFrame
result = pd.concat([df_q1, df_q2])
print(result)
內容解密:
pd.concat將df_q1和df_q2合併,由於df_q1缺少close欄位,pandas 將自動填充缺失值。- 索引值被保留,因此結果中的索引不是連續的。
控制索引與合併方向
可以透過 ignore_index=True 引數來重置索引。此外,使用 keys 引數可以為來源資料新增標籤。
# 重置索引並新增來源標籤
result = pd.concat([df_q1, df_q2], ignore_index=True, keys=["q1", "q2"])
print(result)
內容解密:
ignore_index=True重置了索引,使其連續。- 使用
keys=["q1", "q2"]為資料來源增加了標籤,但這裡的用法不正確,應直接使用keys於具有層級索引的情境。
控制合併方向
預設情況下,pd.concat 是垂直合併(axis=0)。可以透過設定 axis=1 來實作水平合併。
# 設定 ticker 為索引後進行水平合併
result = pd.concat([df_q1.set_index("ticker"), df_q2.set_index("ticker")], axis=1, keys=["q1", "q2"])
print(result)
內容解密:
- 將
ticker設定為索引後,可以根據ticker對齊資料進行水平合併。 - 由於某些
ticker只出現在一個季度,合併結果中會出現缺失值。
控制對齊行為
預設情況下,pd.concat 執行的是「外連線」(outer join),即包含所有索引值。可以使用 join="inner" 來只保留共同的索引值。
# 只保留共同的 ticker
result = pd.concat([df_q1.set_index("ticker"), df_q2.set_index("ticker")], axis=1, keys=["q1", "q2"], join="inner")
print(result)
內容解密:
- 使用
join="inner"後,只保留了同時出現在兩個季度中的ticker(AAPL 和 MSFT)。
最佳實踐:避免在迴圈中使用 pd.concat
在迴圈中重複呼叫 pd.concat 是低效的。最佳實踐是將 DataFrame 存入列表,最後一次性呼叫 pd.concat。
# 正確的做法:先收集 DataFrame 到列表,最後一次性合併
dataframes = [df_q1]
for _ in range(1000):
dataframes.append(df_q1)
result = pd.concat(dataframes)
print(f"最終 DataFrame 的形狀是 {result.shape}")
內容解密:
- 這種做法大幅提升了效能,因為它減少了重複合併的次數。