Python 數據分析實戰:Pandas、NumPy、Matplotlib 完整教學
·77 分鐘閱讀
# Python 數據分析實戰:Pandas、NumPy、Matplotlib 完整教學
## 摘要
本教學文章旨在為讀者提供一個全面且實用的 Python 數據分析指南,重點介紹三個核心函式庫:NumPy、Pandas 和 Matplotlib。無論您是數據科學新手還是希望提升技能的開發者,本文都將透過清晰的步驟說明、豐富的程式碼範例和實戰案例,引導您掌握數據處理、分析與視覺化的關鍵技術。我們將深入探討每個函式庫的核心功能、應用場景,並提供常見問題解答與 SEO 優化建議,助您在數據分析領域更上一層樓。
## 前言
在當今數據驅動的時代,數據分析已成為各行各業不可或缺的技能。Python 以其簡潔的語法和強大的生態系統,迅速崛起成為數據分析領域的首選語言。其中,NumPy 提供了高效的數值運算能力,Pandas 則為數據處理和操作提供了靈活的工具,而 Matplotlib 則能將複雜的數據轉化為直觀的視覺化圖表。本篇文章將帶您從零開始,逐步掌握這三大函式庫的精髓,透過實戰演練,讓您能夠自信地處理和分析真實世界的數據。我們將從 NumPy 的基礎知識開始,逐步深入到 Pandas 的數據處理技巧,最後學習如何使用 Matplotlib 進行數據視覺化,讓數據真正「說話」。
## 第一章:NumPy 基礎入門:高效數值運算的基石
### 1.1 什麼是 NumPy?為何在數據分析中不可或缺?
NumPy (Numerical Python) 是 Python 中用於科學計算的核心函式庫,它提供了一個高效的多維陣列物件 `ndarray`,以及用於處理這些陣列的工具。在數據分析領域,NumPy 之所以不可或缺,主要有以下幾個原因:
NumPy 之所以不可或缺,主要歸因於其在數據處理上的**高效性能**、**記憶體效率**以及**豐富的數學函數**。NumPy 的核心 `ndarray` 物件是 C 語言實現的,這使得它在處理大量數據時比 Python 原生的列表 (list) 具有顯著的速度優勢,能夠實現向量化操作,避免了 Python 迴圈的性能瓶頸。此外,NumPy 陣列在記憶體中以連續的方式儲存,不僅提高了存取速度,也減少了記憶體開銷,特別是在處理大型數據集時,其記憶體效率遠高於 Python 列表。NumPy 還提供了大量的數學函數,包括線性代數、傅立葉變換、隨機數生成等,這些函數可以直接作用於整個陣列,極大地簡化了數值計算的過程。
簡而言之,NumPy 為 Python 數據分析奠定了高效的數值運算基礎,是 Pandas 和其他科學計算函式庫的底層支撐。
### 1.2 NumPy 陣列 (ndarray) 的創建與基本操作
NumPy 的核心是 `ndarray` 物件,它是一個同質的、多維的數據容器。接下來,我們將學習如何創建 `ndarray` 並進行基本操作。
#### 1.2.1 從 Python 列表創建 ndarray
NumPy 的核心是 `ndarray` 物件,它是一個同質的、多維的數據容器。創建 `ndarray` 的最常見方式是將 Python 列表轉換為 NumPy 陣列,所有元素必須是相同類型。此外,NumPy 也提供了 `zeros`, `ones`, `empty`, `arange`, `linspace` 等多種函數來快速創建特定形狀和值的陣列。每個 `ndarray` 都具有其**形狀 (shape)**、**維度 (ndim)**、**大小 (size)** 和**數據類型 (dtype)** 等屬性,這些屬性提供了陣列的基本資訊。在數據選取方面,NumPy 陣列的索引和切片操作與 Python 列表類似,但功能更強大,支援一維、二維及多維陣列的精確選取。最後,`reshape`, `flatten`, `transpose` 等函數則能方便地進行陣列形狀變換,以適應不同的運算需求,但這些操作不會改變其數據。
以下是相關的程式碼範例:
```python
import numpy as np
# 從一維列表創建陣列
list_1d = [1, 2, 3, 4, 5]
array_1d = np.array(list_1d)
print("一維陣列:", array_1d)
print("類型:", type(array_1d))
# 從二維列表創建陣列
list_2d = [[1, 2, 3], [4, 5, 6]]
array_2d = np.array(list_2d)
print("\n二維陣列:\n", array_2d)
# 創建全零陣列
zeros_array = np.zeros((3, 4)) # 3行4列
print("\n全零陣列:\n", zeros_array)
# 創建全一陣列
ones_array = np.ones((2, 3), dtype=int) # 指定數據類型為整數
print("\n全一陣列:\n", ones_array)
# 創建空陣列 (內容是隨機值,取決於記憶體狀態)
empty_array = np.empty((2, 2))
print("\n空陣列:\n", empty_array)
# 創建等差數列陣列 (類似 Python 的 range)
arange_array = np.arange(0, 10, 2) # 從0到10 (不包含10),步長為2
print("\n等差數列陣列:", arange_array)
# 創建等間隔數列陣列 (指定起始、結束和元素個數)
linspace_array = np.linspace(0, 1, 5) # 從0到1,生成5個等間隔的數
print("\n等間隔數列陣列:", linspace_array)
array_example = np.array([[1, 2, 3], [4, 5, 6]])
print("陣列:\n", array_example)
print("形狀 (shape):", array_example.shape) # (行數, 列數)
print("維度 (ndim):", array_example.ndim) # 陣列的軸數
print("大小 (size):", array_example.size) # 陣列中元素的總數
print("數據類型 (dtype):", array_example.dtype) # 陣列中元素的數據類型
# 一維陣列索引與切片
arr_1d = np.arange(10)
print("一維陣列:", arr_1d)
print("第一個元素:", arr_1d[0])
print("從索引2到5的元素:", arr_1d[2:6])
print("最後一個元素:", arr_1d[-1])
# 二維陣列索引與切片
arr_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("\n二維陣列:\n", arr_2d)
print("第二行第一列的元素:", arr_2d[1, 0]) # 等同於 arr_2d[1][0]
print("第一行所有元素:", arr_2d[0, :])
print("所有行第二列的元素:", arr_2d[:, 1])
print("前兩行和後兩列的子陣列:\n", arr_2d[:2, 1:])
arr = np.arange(12)
print("原始陣列:", arr)
# reshape: 將一維陣列變為 3x4 的二維陣列
reshaped_arr = arr.reshape((3, 4))
print("\nreshape 為 3x4:\n", reshaped_arr)
# flatten: 將多維陣列展平為一維陣列
flattened_arr = reshaped_arr.flatten()
print("\nflatten 為一維:", flattened_arr)
# transpose: 轉置陣列 (行列互換)
transposed_arr = reshaped_arr.transpose()
print("\n轉置陣列:\n", transposed_arr)
```
### 1.3 NumPy 的廣播 (Broadcasting) 機制
NumPy 的廣播機制允許在不同形狀的陣列之間執行算術運算,而無需顯式地複製數據。這大大提高了運算的效率和程式碼的簡潔性。
NumPy 的廣播機制允許在不同形狀的陣列之間執行算術運算,而無需顯式地複製數據,這大大提高了運算的效率和程式碼的簡潔性。**廣播規則**主要有三點:如果兩個陣列的維度數不同,那麼維度較小的陣列的形狀會在前面填充 1,直到它們的維度數相同;對於每個維度,如果兩個陣列的長度相同,或者其中一個陣列的長度為 1,那麼它們是兼容的;如果兩個陣列在任何維度上都不兼容,則會引發 `ValueError`。理解這些規則對於在不同形狀陣列運算中有效應用廣播至關重要。
```python
import numpy as np
a = np.array([1, 2, 3]) # 形狀 (3,)
b = 2 # 純量
print("陣列 a:", a)
print("純量 b:", b)
print("a + b (廣播):", a + b) # b 被廣播成 [2, 2, 2]
matrix = np.array([[1, 2, 3], [4, 5, 6]]) # 形狀 (2, 3)
vector = np.array([10, 20, 30]) # 形狀 (3,)
print("\n矩陣:\n", matrix)
print("向量:", vector)
print("matrix + vector (廣播):\n", matrix + vector) # vector 被廣播成 [[10, 20, 30], [10, 20, 30]]
# 另一個廣播範例
m1 = np.array([[1, 2, 3]]) # 形狀 (1, 3)
m2 = np.array([[10], [20]]) # 形狀 (2, 1)
print("\nm1:\n", m1)
print("m2:\n", m2)
print("m1 + m2 (廣播):\n", m1 + m2)
# m1 被廣播成 [[1, 2, 3], [1, 2, 3]]
# m2 被廣播成 [[10, 10, 10], [20, 20, 20]]
# 結果為 [[11, 12, 13], [21, 22, 23]]
```
### 1.4 常用數學運算與統計函數
NumPy 提供了豐富的數學運算和統計函數,可以直接應用於陣列。
NumPy 提供了豐富的數學運算和統計函數,可以直接應用於陣列。這些函數包括**基本算術運算**,如加、減、乘、除,這些運算都是元素級的。此外,NumPy 還提供了多種**聚合函數**,如 `sum`, `mean`, `median`, `std`, `min`, `max`,用於計算陣列的統計量,並且可以指定 `axis` 參數來沿著特定軸進行計算。NumPy 也是進行**線性代數操作**的強大工具,支援點積 (`dot`) 和矩陣乘法 (`@`)。在數據篩選方面,NumPy 允許使用**條件篩選與布林索引**,透過布林陣列來高效地篩選數據,這在數據分析中非常有用。
以下是相關的程式碼範例:
```python
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print("a + b:", a + b)
print("a - b:", a - b)
print("a * b:", a * b) # 元素級乘法
print("a / b:", a / b)
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("陣列:\n", arr)
print("總和:", np.sum(arr))
print("平均值:", np.mean(arr))
print("標準差:", np.std(arr))
print("最大值:", np.max(arr))
print("最小值:", np.min(arr))
# 沿著軸進行計算 (axis=0 表示列,axis=1 表示行)
print("\n沿著列的總和:", np.sum(arr, axis=0))
print("沿著行的平均值:", np.mean(arr, axis=1))
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print("矩陣 a:\n", a)
print("矩陣 b:\n", b)
# 點積 (np.dot(a, b))
print("\n點積 (np.dot(a, b)):\n", np.dot(a, b))
# 矩陣乘法 (Python 3.5+ 支援 @ 運算符)
print("\n矩陣乘法 (a @ b):\n", a @ b)
arr = np.arange(10)
print("原始陣列:", arr)
# 篩選出大於 5 的元素
mask = arr > 5
print("布林遮罩:", mask)
print("大於 5 的元素:", arr[mask])
# 簡寫形式
print("簡寫形式篩選大於 5 的元素:", arr[arr > 5])
# 多重條件篩選
print("大於 3 且小於 7 的元素:", arr[(arr > 3) & (arr < 7)])
```
### 1.5 實戰範例:創建與操作簡單數據陣列
透過實際範例,我們可以更好地理解 NumPy 的應用。例如,可以利用 NumPy 輕鬆計算學生考試成績的平均分和標準差,快速獲得數據的統計概況。假設我們有一組學生的數學、物理、化學成績數據,NumPy 可以幫助我們計算每門課的平均分、每位學生的總分和平均分,以及找出不及格的成績數量。此外,NumPy 在圖像處理中也扮演著基礎角色,例如對圖像數據進行簡單的像素操作,圖像在電腦中通常表示為多維陣列,每個元素代表一個像素的顏色強度,NumPy 可以實現圖像反轉、亮度調整和區域提取等操作,這展示了其在多維數據處理上的強大能力。
以下是相關的程式碼範例:
```python
import numpy as np
# 學生考試成績 (數學, 物理, 化學)
# 假設有5位學生
scores = np.array([
[85, 90, 78], # 學生1
[72, 88, 95], # 學生2
[90, 75, 80], # 學生3
[60, 70, 65], # 學生4
[92, 85, 88] # 學生5
])
print("學生考試成績:\n", scores)
# 計算每門課的平均分 (沿著 axis=0,即列)
math_avg = np.mean(scores[:, 0])
physics_avg = np.mean(scores[:, 1])
chemistry_avg = np.mean(scores[:, 2])
print("\n數學平均分:", math_avg)
print("物理平均分:", physics_avg)
print("化學平均分:", chemistry_avg)
# 計算每位學生的總分和平均分 (沿著 axis=1,即行)
total_scores = np.sum(scores, axis=1)
student_avg_scores = np.mean(scores, axis=1)
print("\n每位學生的總分:", total_scores)
print("每位學生的平均分:", student_avg_scores)
# 計算所有成績的總平均分
overall_avg = np.mean(scores)
print("\n所有成績的總平均分:", overall_avg)
# 找出成績最高的學生和科目 (簡化處理,找出最大值)
max_score = np.max(scores)
print("最高分:", max_score)
# 找出不及格 (假設60分以下) 的成績數量
fail_count = np.sum(scores < 60)
print("不及格的成績數量:", fail_count)
```
```python
import numpy as np
# 模擬一個 3x3 的灰度圖像 (像素值從 0 到 255)
# 這裡我們用一個簡單的二維陣列表示
image_data = np.array([
[100, 120, 150],
[130, 160, 180],
[110, 140, 170]
], dtype=np.uint8) # 使用 np.uint8 數據類型表示像素值
print("原始圖像數據:\n", image_data)
# 圖像反轉 (像素值取反,例如 255 - 原始值)
inverted_image = 255 - image_data
print("\n反轉後的圖像數據:\n", inverted_image)
# 調整亮度 (例如,所有像素值增加 50,並確保不超過 255)
brightened_image = np.clip(image_data + 50, 0, 255)
print("\n亮度調整後的圖像數據:\n", brightened_image)
# 提取圖像的某個區域 (切片操作)
roi = image_data[0:2, 0:2] # 提取左上角 2x2 區域
print("\n提取的圖像區域 (ROI):\n", roi)
```
**常見錯誤提醒**:
* **數據類型不匹配**:NumPy 陣列要求所有元素數據類型一致。如果嘗試將不同類型的數據放入陣列,NumPy 會嘗試進行類型轉換,可能導致意外結果或錯誤。
* **形狀不匹配**:在進行陣列運算時,如果陣列形狀不滿足廣播規則,會引發 `ValueError`。務必檢查陣列的 `shape` 屬性。
* **修改原始陣列**:某些 NumPy 操作會返回新的陣列,而有些則會直接修改原始陣列。在進行操作時,請注意函數的行為,必要時使用 `copy()` 方法來避免意外修改。
## 第二章:Pandas 數據處理與分析:結構化數據的利器
### 2.1 什麼是 Pandas?為何是數據分析的核心工具?
Pandas (Python Data Analysis Library) 是一個開源的 Python 函式庫,專為數據操作和分析而設計。它建立在 NumPy 之上,提供了高效、靈活且易於使用的數據結構,使得處理表格型數據變得輕而易舉。Pandas 之所以成為數據分析的核心工具,主要歸因於其以下特性:
Pandas 之所以成為數據分析的核心工具,主要歸因於其**強大的數據結構**、**數據清洗與預處理能力**、**數據操作與轉換功能**以及**與其他函式庫的無縫整合**。Pandas 引入了兩種核心數據結構:`Series` (一維帶標籤陣列) 和 `DataFrame` (二維帶標籤表格數據結構),它們能夠高效地處理各種數據類型,包括數值、字串、時間序列等。它提供了豐富的函數和方法來處理數據中的缺失值、重複值、異常值,以及進行數據類型轉換、數據格式化等操作,是數據清洗階段的利器。此外,Pandas 支援高效的數據篩選、排序、分組聚合、合併、連接等操作,能夠輕鬆地對數據進行重塑和轉換,以滿足不同的分析需求。最重要的是,Pandas 與 NumPy、Matplotlib、Scikit-learn 等科學計算和機器學習函式庫無縫整合,形成了一個強大的數據科學生態系統。
總之,Pandas 極大地簡化了數據的載入、清洗、轉換和分析過程,是任何數據分析師或數據科學家不可或缺的工具。
### 2.2 Series 與 DataFrame 的創建與基本操作
Pandas 的核心是 `Series` 和 `DataFrame`。理解它們的創建和基本操作是掌握 Pandas 的關鍵。
Pandas 的核心是 `Series` 和 `DataFrame`。理解它們的創建和基本操作是掌握 Pandas 的關鍵。我們可以**從列表、字典或 NumPy 陣列創建 Series 與 DataFrame**。DataFrame 具有**行索引 (index) 與列 (columns)**,這使得數據的存取更加直觀。在**數據選取**方面,Pandas 提供了 `loc` (基於標籤) 和 `iloc` (基於整數位置) 兩種主要方式來選取數據。此外,Pandas 也支援方便地**添加、修改、刪除列與行**,以靈活地操作數據結構。
以下是相關的程式碼範例:
```python
import pandas as pd
import numpy as np
# 從列表創建 Series
s_list = pd.Series([1, 3, 5, np.nan, 6, 8])
print("從列表創建的 Series:\n", s_list)
# 從 NumPy 陣列創建 Series
s_np = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
print("\n從 NumPy 陣列創建的 Series (帶索引):\n", s_np)
# 從字典創建 Series
s_dict = pd.Series({'數學': 90, '物理': 85, '化學': 92})
print("\n從字典創建的 Series:\n", s_dict)
# 從字典創建 DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie', 'David'],
'Age': [25, 30, 35, 28],
'City': ['New York', 'Paris', 'London', 'Tokyo']
}
df_dict = pd.DataFrame(data)
print("\n從字典創建的 DataFrame:\n", df_dict)
# 從 NumPy 陣列創建 DataFrame
df_np = pd.DataFrame(np.random.rand(4, 3), columns=['A', 'B', 'C'])
print("\n從 NumPy 陣列創建的 DataFrame:\n", df_np)
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9]
}, index=['row1', 'row2', 'row3'])
print("DataFrame:\n", df)
print("\n行索引:", df.index)
print("列標籤:", df.columns)
print("數據值:\n", df.values) # 返回 NumPy 陣列
df = pd.DataFrame({
'col1': [1, 2, 3, 4],
'col2': [5, 6, 7, 8],
'col3': [9, 10, 11, 12]
}, index=['a', 'b', 'c', 'd'])
print("DataFrame:\n", df)
# 使用 loc (基於標籤)
print("\n使用 loc 選取 'b' 行:\n", df.loc['b'])
print("使用 loc 選取 'a' 到 'c' 行和 'col1' 到 'col2' 列:\n", df.loc['a':'c', 'col1':'col2'])
print("使用 loc 選取 'a' 行的 'col1':", df.loc['a', 'col1'])
# 使用 iloc (基於整數位置)
print("\n使用 iloc 選取第 1 行:\n", df.iloc[1]) # 索引從 0 開始
print("使用 iloc 選取第 0 到 2 行和第 0 到 1 列:\n", df.iloc[0:3, 0:2])
print("使用 iloc 選取第 0 行的第 0 列:", df.iloc[0, 0])
# 直接選取列
print("\n選取 'col1' 列:\n", df['col1'])
print("選取多個列:\n", df[['col1', 'col3']])
df = pd.DataFrame({
'Name': ['Alice', 'Bob'],
'Age': [25, 30]
})
print("原始 DataFrame:\n", df)
# 添加新列
df['City'] = ['New York', 'Paris']
print("\n添加 'City' 列後:\n", df)
# 修改列的值
df['Age'] = [26, 31]
print("\n修改 'Age' 列後:\n", df)
# 添加新行 (使用 loc)
df.loc[2] = ['Charlie', 35, 'London'] # 假設索引為 2
print("\n添加新行後:\n", df)
# 刪除列
df_dropped_col = df.drop('City', axis=1) # axis=1 表示刪除列
print("\n刪除 'City' 列後:\n", df_dropped_col)
# 刪除行 (使用 drop)
df_dropped_row = df.drop(0, axis=0) # axis=0 表示刪除行 (索引為 0 的行)
print("\n刪除索引為 0 的行後:\n", df_dropped_row)
```
### 2.3 數據載入 (CSV, Excel) 與儲存
Pandas 提供了方便的函數來讀取和寫入各種數據格式,其中 CSV 和 Excel 是最常用的。
Pandas 提供了方便的函數來讀取和寫入各種數據格式,其中 CSV 和 Excel 是最常用的。我們可以透過 `read_csv` 和 `read_excel` 函數輕鬆**載入數據**,並使用 `to_csv` 和 `to_excel` 函數將處理後的數據**導出**。在處理文件時,特別是包含中文或其他非 ASCII 字元的數據,**編碼問題**很常見,通常建議使用 `utf-8` 編碼來避免亂碼。
以下是相關的程式碼範例:
```python
import pandas as pd
import os
# 創建一個模擬的 CSV 文件
csv_data = """Name,Age,City
Alice,25,New York
Bob,30,Paris
Charlie,35,London
"""
with open(\'sample.csv\', \'w\') as f:
f.write(csv_data)
# 載入 CSV 文件
df_csv = pd.read_csv(\'sample.csv\')
print("從 CSV 載入的 DataFrame:\n", df_csv)
# 創建一個模擬的 Excel 文件 (需要 openpyxl 函式庫)
# 如果沒有安裝,請先運行:pip install openpyxl
excel_data = pd.DataFrame({
\'Product\': [\'A\', \'B\', \'C\'],
\'Price\': [100, 150, 200]
})
excel_data.to_excel(\'sample.xlsx\', index=False)
# 載入 Excel 文件
df_excel = pd.read_excel(\'sample.xlsx\')
print("\n從 Excel 載入的 DataFrame:\n", df_excel)
# 清理創建的測試文件
os.remove(\'sample.csv\')
os.remove(\'sample.xlsx\')
df = pd.DataFrame({
\'Name\': [\'Alice\', \'Bob\'],
\'Score\': [90, 85]
})
# 導出為 CSV 文件 (不包含索引)
df.to_csv(\'output.csv\', index=False)
print("DataFrame 已導出至 output.csv")
# 導出為 Excel 文件 (不包含索引)
df.to_excel(\'output.xlsx\', index=False)
print("DataFrame 已導出至 output.xlsx")
# 清理創建的測試文件
os.remove(\'output.csv\')
os.remove(\'output.xlsx\')
# 創建一個包含中文的 CSV 文件,並指定編碼
chinese_data = """姓名,年齡,城市
小明,28,北京
小紅,24,上海
"""
with open(\'chinese_sample.csv\', \'w\', encoding=\'utf-8\') as f:
f.write(chinese_data)
# 載入時指定編碼
df_chinese = pd.read_csv(\'chinese_sample.csv\', encoding=\'utf-8\')
print("從包含中文的 CSV 載入的 DataFrame:\n", df_chinese)
# 清理創建的測試文件
os.remove(\'chinese_sample.csv\')
```
### 2.4 數據清洗:處理缺失值、重複值與數據類型轉換
數據清洗是數據分析流程中至關重要的一步,它確保了數據的質量和分析結果的準確性。
數據清洗是數據分析流程中至關重要的一步,它確保了數據的質量和分析結果的準確性。Pandas 提供了強大的功能來處理數據中的各種問題,包括**檢測缺失值** (`isnull`, `notnull`)、**處理缺失值** (`dropna`, `fillna`)、**檢測與處理重複值** (`duplicated`, `drop_duplicates`) 以及**數據類型轉換** (`astype`)。透過這些方法,我們可以有效地清理數據,使其符合分析要求。例如,`dropna()` 可以刪除包含缺失值的行或列,而 `fillna()` 則可以用指定的值填充缺失值。`duplicated()` 和 `drop_duplicates()` 則用於識別和移除重複的數據行。此外,`astype()` 函數能夠將數據列轉換為正確的數據類型,這對於節省記憶體和確保運算正確性至關重要。
以下是相關的程式碼範例:
```python
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [5, np.nan, 7, 8],
'C': [9, 10, 11, 12]
})
print("原始 DataFrame:\n", df)
print("\n檢測缺失值 (isnull):\n", df.isnull())
print("\n檢測非缺失值 (notnull):\n", df.notnull())
print("\n每列的缺失值數量:\n", df.isnull().sum())
# 刪除包含任何缺失值的行
df_dropped_na = df.dropna()
print("刪除包含缺失值的行後:\n", df_dropped_na)
# 刪除所有值都為缺失值的行 (how='all')
df_all_na = pd.DataFrame({
'X': [1, np.nan],
'Y': [np.nan, np.nan]
})
df_dropped_all_na = df_all_na.dropna(how='all')
print("\n刪除所有值都為缺失值的行後:\n", df_dropped_all_na)
# 用特定值填充缺失值
df_filled_zero = df.fillna(0)
print("\n用 0 填充缺失值後:\n", df_filled_zero)
# 用列的平均值填充缺失值
df_filled_mean = df.fillna(df.mean())
print("\n用列平均值填充缺失值後:\n", df_filled_mean)
# 向前填充 (ffill) 或向後填充 (bfill)
df_ffill = df.fillna(method='ffill')
print("\n向前填充缺失值後:\n", df_ffill)
df = pd.DataFrame({
'col1': ['A', 'B', 'A', 'C'],
'col2': [1, 2, 1, 3]
})
print("原始 DataFrame:\n", df)
# 檢測重複行 (預設保留第一個)
print("\n檢測重複行:\n", df.duplicated())
# 刪除重複行 (預設保留第一個)
df_no_duplicates = df.drop_duplicates()
print("\n刪除重複行後:\n", df_no_duplicates)
# 刪除重複行 (保留最後一個)
df_no_duplicates_last = df.drop_duplicates(keep='last')
print("\n刪除重複行 (保留最後一個) 後:\n", df_no_duplicates_last)
# 根據特定列檢測重複值
df_col1_duplicates = df.duplicated(subset=['col1'])
print("\n根據 'col1' 檢測重複值:\n", df_col1_duplicates)
df = pd.DataFrame({
'A': [1, 2, 3],
'B': ['10', '20', '30'],
'C': [1.1, 2.2, 3.3]
})
print("原始 DataFrame 數據類型:\n", df.dtypes)
# 將 'B' 列從字串轉換為整數
df['B'] = df['B'].astype(int)
print("\n轉換 'B' 列為整數後數據類型:\n", df.dtypes)
# 將 'C' 列從浮點數轉換為整數
df['C'] = df['C'].astype(int)
print("\n轉換 'C' 列為整數後數據類型:\n", df.dtypes)
# 嘗試將無法轉換的值轉換為數值會報錯,可以使用 errors='coerce' 處理
df_str_num = pd.DataFrame({'D': ['1', '2', 'abc', '4']})
# df_str_num['D'].astype(int) # 這會報錯
df_str_num['D_numeric'] = pd.to_numeric(df_str_num['D'], errors='coerce')
print("\n包含無法轉換值的列轉換為數值後:\n", df_str_num)
```
### 2.5 數據篩選、排序與分組聚合 (groupby)
這些是 Pandas 中最常用的數據操作,用於從數據中提取有意義的資訊。
Pandas 中最常用的數據操作包括**條件篩選**、**數據排序**和**分組聚合 (groupby)**,這些功能用於從數據中提取有意義的資訊。透過布林條件,我們可以靈活地選取符合特定條件的數據。`sort_values` 和 `sort_index` 函數則提供了強大的數據排序能力,可以根據單一或多個列進行升序或降序排列。而 `groupby` 函數是 Pandas 中一個非常強大的功能,它允許我們將數據根據一個或多個鍵進行分組,然後對每個組應用聚合函數,如統計、計數、求和等,從而實現複雜的數據分析。
以下是相關的程式碼範例:
```python
import pandas as pd
df = pd.DataFrame({
'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'Age': [25, 30, 35, 28, 22],
'City': ['New York', 'Paris', 'London', 'New York', 'Paris'],
'Score': [85, 92, 78, 95, 88]
})
print("原始 DataFrame:\n", df)
# 選取 Age 大於 28 的行
df_age_filter = df[df['Age'] > 28]
print("\nAge 大於 28 的行:\n", df_age_filter)
# 選取 City 為 'New York' 的行
df_city_filter = df[df['City'] == 'New York']
print("\nCity 為 'New York' 的行:\n", df_city_filter)
# 多重條件篩選 (Age 大於 25 且 Score 大於 90)
df_multi_filter = df[(df['Age'] > 25) & (df['Score'] > 90)]
print("\nAge 大於 25 且 Score 大於 90 的行:\n", df_multi_filter)
# 使用 isin 篩選多個值
df_isin_filter = df[df['City'].isin(['New York', 'London'])]
print("\nCity 為 'New York' 或 'London' 的行:\n", df_isin_filter)
# 根據 'Age' 列升序排序
df_sorted_age = df.sort_values(by='Age')
print("\n根據 'Age' 升序排序:\n", df_sorted_age)
# 根據 'Age' 降序排序,並在 'Age' 相同時根據 'Score' 升序排序
df_sorted_multi = df.sort_values(by=['Age', 'Score'], ascending=[False, True])
print("\n根據 'Age' 降序,'Score' 升序排序:\n", df_sorted_multi)
# 根據索引排序
df_with_custom_index = df.set_index('Name')
print("\n帶有自定義索引的 DataFrame:\n", df_with_custom_index)
df_sorted_index = df_with_custom_index.sort_index()
print("\n根據索引排序後:\n", df_sorted_index)
df = pd.DataFrame({
'City': ['New York', 'Paris', 'London', 'New York', 'Paris'],
'Product': ['A', 'B', 'A', 'C', 'B'],
'Sales': [100, 150, 120, 200, 180]
})
print("原始 DataFrame:\n", df)
# 根據 'City' 分組,計算每個城市的總銷售額
grouped_by_city = df.groupby('City')['Sales'].sum()
print("\n按城市分組的總銷售額:\n", grouped_by_city)
# 根據 'City' 和 'Product' 分組,計算每個城市每個產品的平均銷售額
grouped_by_city_product = df.groupby(['City', 'Product'])['Sales'].mean()
print("\n按城市和產品分組的平均銷售額:\n", grouped_by_city_product)
# 對多個聚合函數應用
agg_results = df.groupby('City')['Sales'].agg(['sum', 'mean', 'count'])
print("\n按城市分組的多個聚合結果:\n", agg_results)
```
### 2.6 數據合併與連接 (merge, concat)
在實際數據分析中,我們經常需要將來自不同來源的數據集合併起來。
在實際數據分析中,我們經常需要將來自不同來源的數據集合併起來。Pandas 提供了兩種主要的數據合併方式:`concat` 和 `merge`。`concat` 函數主要用於將多個 Series 或 DataFrame 沿著某個軸 (行或列) 堆疊起來,而 `merge` 函數則用於根據一個或多個共同鍵值將兩個 DataFrame 的行連接起來,類似於資料庫中的 JOIN 操作,支援內連接、左連接、右連接和外連接等多種方式。透過這些功能,我們可以靈活地整合不同數據源,進行更全面的分析。
以下是相關的程式碼範例:
```python
df1 = pd.DataFrame({
'A': ['A0', 'A1'],
'B': ['B0', 'B1']
})
df2 = pd.DataFrame({
'A': ['A2', 'A3'],
'B': ['B2', 'B3']
})
print("df1:\n", df1)
print("\ndf2:\n", df2)
# 沿著行方向連接 (預設 axis=0)
result_rows = pd.concat([df1, df2])
print("\n沿著行方向連接:\n", result_rows)
# 沿著列方向連接 (axis=1)
result_cols = pd.concat([df1, df2], axis=1)
print("\n沿著列方向連接:\n", result_cols)
# 處理索引重複問題 (ignore_index=True)
result_ignore_index = pd.concat([df1, df2], ignore_index=True)
print("\n沿著行方向連接 (忽略索引):\n", result_ignore_index)
import pandas as pd
df_employees = pd.DataFrame({
'employee_id': [1, 2, 3, 4],
'name': ['Alice', 'Bob', 'Charlie', 'David'],
'department_id': [101, 102, 101, 103]
})
df_departments = pd.DataFrame({
'department_id': [101, 102, 104],
'department_name': ['HR', 'IT', 'Marketing']
})
print("df_employees:\n", df_employees)
print("\ndf_departments:\n", df_departments)
# 內連接 (inner join):只保留兩個 DataFrame 中共同的鍵值
inner_join = pd.merge(df_employees, df_departments, on='department_id', how='inner')
print("\n內連接 (inner join):\n", inner_join)
# 左連接 (left join):保留左邊 DataFrame 的所有行,匹配右邊 DataFrame 的行
left_join = pd.merge(df_employees, df_departments, on='department_id', how='left')
print("\n左連接 (left join):\n", left_join)
# 右連接 (right join):保留右邊 DataFrame 的所有行,匹配左邊 DataFrame 的行
right_join = pd.merge(df_employees, df_departments, on='department_id', how='right')
print("\n右連接 (right join):\n", right_join)
# 外連接 (outer join):保留兩個 DataFrame 的所有行,不匹配的用 NaN 填充
outer_join = pd.merge(df_employees, df_departments, on='department_id', how='outer')
print("\n外連接 (outer join):\n", outer_join)
import pandas as pd
# 1月銷售數據
sales_jan = pd.DataFrame({
'Date': ['2026-01-01', '2026-01-02', '2026-01-03'],
'Product_ID': ['P001', 'P002', 'P001'],
'Quantity': [10, 5, 8],
'Price': [50, 120, 50]
})
# 2月銷售數據
sales_feb = pd.DataFrame({
'Date': ['2026-02-01', '2026-02-02', '2026-02-01'],
'Product_ID': ['P002', 'P003', 'P001'],
'Quantity': [7, 12, 15],
'Price': [120, 80, 50]
})
print("1月銷售數據:\n", sales_jan)
print("\n2月銷售數據:\n", sales_feb)
# 使用 concat 合併兩個月的銷售數據
all_sales = pd.concat([sales_jan, sales_feb], ignore_index=True)
print("\n合併後的總銷售數據:\n", all_sales)
# 假設還有一個產品資訊表
product_info = pd.DataFrame({
'Product_ID': ['P001', 'P002', 'P003'],
'Category': ['Electronics', 'Books', 'Clothing']
})
print("\n產品資訊:\n", product_info)
# 將銷售數據與產品資訊合併 (基於 Product_ID)
merged_sales = pd.merge(all_sales, product_info, on='Product_ID', how='left')
print("\n合併產品資訊後的銷售數據:\n", merged_sales)
```
以下是相關的程式碼範例:
```python
import pandas as pd
df1 = pd.DataFrame({'A': ['A0', 'A1'], 'B': ['B0', 'B1']})
df2 = pd.DataFrame({'A': ['A2', 'A3'], 'B': ['B2', 'B3']})
print("df1:\n", df1)
print("\ndf2:\n", df2)
# 沿著行方向連接 (預設 axis=0)
result_rows = pd.concat([df1, df2])
print("\n沿著行方向連接:\n", result_rows)
# 沿著列方向連接 (axis=1)
result_cols = pd.concat([df1, df2], axis=1)
print("\n沿著列方向連接:\n", result_cols)
# 處理索引重複問題 (ignore_index=True)
result_ignore_index = pd.concat([df1, df2], ignore_index=True)
print("\n沿著行方向連接 (忽略索引):\n", result_ignore_index)
import pandas as pd
df_employees = pd.DataFrame({
'employee_id': [1, 2, 3, 4],
'name': ['Alice', 'Bob', 'Charlie', 'David'],
'department_id': [101, 102, 101, 103]
})
df_departments = pd.DataFrame({
'department_id': [101, 102, 104],
'department_name': ['HR', 'IT', 'Marketing']
})
print("df_employees:\n", df_employees)
print("\ndf_departments:\n", df_departments)
# 內連接 (inner join):只保留兩個 DataFrame 中共同的鍵值
inner_join = pd.merge(df_employees, df_departments, on='department_id', how='inner')
print("\n內連接 (inner join):\n", inner_join)
# 左連接 (left join):保留左邊 DataFrame 的所有行,匹配右邊 DataFrame 的行
left_join = pd.merge(df_employees, df_departments, on='department_id', how='left')
print("\n左連接 (left join):\n", left_join)
# 右連接 (right join):保留右邊 DataFrame 的所有行,匹配左邊 DataFrame 的行
right_join = pd.merge(df_employees, df_departments, on='department_id', how='right')
print("\n右連接 (right join):\n", right_join)
# 外連接 (outer join):保留兩個 DataFrame 的所有行,不匹配的用 NaN 填充
outer_join = pd.merge(df_employees, df_departments, on='department_id', how='outer')
print("\n外連接 (outer join):\n", outer_join)
import pandas as pd
# 1月銷售數據
sales_jan = pd.DataFrame({
'Date': ['2026-01-01', '2026-01-02', '2026-01-03'],
'Product_ID': ['P001', 'P002', 'P001'],
'Quantity': [10, 5, 8],
'Price': [50, 120, 50]
})
# 2月銷售數據
sales_feb = pd.DataFrame({
'Date': ['2026-02-01', '2026-02-02', '2026-02-01'],
'Product_ID': ['P002', 'P003', 'P001'],
'Quantity': [7, 12, 15],
'Price': [120, 80, 50]
})
print("1月銷售數據:\n", sales_jan)
print("\n2月銷售數據:\n", sales_feb)
# 使用 concat 合併兩個月的銷售數據
all_sales = pd.concat([sales_jan, sales_feb], ignore_index=True)
print("\n合併後的總銷售數據:\n", all_sales)
# 假設還有一個產品資訊表
product_info = pd.DataFrame({
'Product_ID': ['P001', 'P002', 'P003'],
'Category': ['Electronics', 'Books', 'Clothing']
})
print("\n產品資訊:\n", product_info)
# 將銷售數據與產品資訊合併 (基於 Product_ID)
merged_sales = pd.merge(all_sales, product_info, on='Product_ID', how='left')
print("\n合併產品資訊後的銷售數據:\n", merged_sales)
```
### 2.7 實戰範例:使用真實數據集進行數據清洗與初步分析
為了更貼近真實情境,我們將使用一個虛擬的電商訂單數據集來實際演練 Pandas 的數據清洗與初步分析流程。這個範例將涵蓋數據導入、缺失值與重複值的處理、數據類型轉換,以及最終的初步分析,例如計算總銷售額、找出暢銷產品等,完整地展示一個小型數據分析專案的生命週期。
```python
import pandas as pd
import numpy as np
# 創建一個模擬的電商訂單數據集
data = {
'OrderID': [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010],
'CustomerID': [1, 2, 1, 3, 2, 4, 1, 5, 3, 2],
'OrderDate': ['2026-01-01', '2026-01-01', '2026-01-02', '2026-01-02', '2026-01-03', '2026-01-03', '2026-01-04', '2026-01-04', '2026-01-05', '2026-01-05'],
'Product': ['Laptop', 'Mouse', 'Keyboard', 'Laptop', 'Monitor', 'Mouse', 'Laptop', 'Keyboard', 'Monitor', 'Mouse'],
'Quantity': [1, 2, 1, 1, 1, 1, 2, 1, 1, 3],
'UnitPrice': [1200, 25, 75, 1200, 200, 25, 1200, 75, 200, 25],
'Discount': [0.1, 0, 0, 0.1, 0, 0, 0.1, 0, 0, 0],
'PaymentMethod': ['Credit Card', 'PayPal', 'Credit Card', 'PayPal', 'Credit Card', 'Cash', 'Credit Card', 'PayPal', 'Cash', 'PayPal'],
'ShippingCost': [10, 5, 8, 10, 12, 5, 10, 8, 12, 5]
}
df_orders = pd.DataFrame(data)
# 引入一些缺失值和重複值來模擬真實數據
df_orders.loc[2, 'Quantity'] = np.nan # 模擬缺失值
df_orders.loc[5, 'Product'] = np.nan # 模擬缺失值
df_orders.loc[8, 'CustomerID'] = np.nan # 模擬缺失值
df_orders = pd.concat([df_orders, df_orders.iloc[[0]]], ignore_index=True) # 模擬重複行
print("原始電商訂單數據:\n", df_orders)
print("\n原始數據資訊:")
df_orders.info()
# 1. 數據清洗:處理缺失值
# 檢查缺失值
print("\n缺失值統計:\n", df_orders.isnull().sum())
# 針對 Quantity 和 CustomerID 填充缺失值 (例如,Quantity 填充中位數,CustomerID 填充眾數)
# 注意:這裡為了簡化,直接填充一個固定值,實際應用中應根據業務邏輯處理
df_orders['Quantity'].fillna(df_orders['Quantity'].median(), inplace=True)
df_orders['CustomerID'].fillna(df_orders['CustomerID'].mode()[0], inplace=True)
# 針對 Product 填充缺失值 (例如,填充 'Unknown')
df_orders['Product'].fillna('Unknown', inplace=True)
print("\n填充缺失值後的數據:\n", df_orders)
print("\n填充缺失值後缺失值統計:\n", df_orders.isnull().sum())
# 2. 數據清洗:處理重複值
print("\n重複行數量:", df_orders.duplicated().sum())
df_orders.drop_duplicates(inplace=True)
print("\n刪除重複行後的數據:\n", df_orders)
# 3. 數據類型轉換
# 將 'OrderDate' 轉換為日期時間類型
df_orders['OrderDate'] = pd.to_datetime(df_orders['OrderDate'])
print("\n轉換 'OrderDate' 類型後的數據資訊:")
df_orders.info()
# 4. 創建新特徵:計算總金額
df_orders['TotalPrice'] = df_orders['Quantity'] * df_orders['UnitPrice'] * (1 - df_orders['Discount'])
print("\n添加 'TotalPrice' 列後的數據:\n", df_orders)
# 5. 初步分析:總銷售額
total_sales_amount = df_orders['TotalPrice'].sum()
print(f"\n總銷售額:{total_sales_amount:.2f}")
# 6. 初步分析:暢銷產品
bestselling_products = df_orders.groupby('Product')['Quantity'].sum().sort_values(ascending=False)
print("\n暢銷產品 (按數量):\n", bestselling_products)
# 7. 初步分析:每月銷售趨勢 (假設數據跨越多月)
# 從 OrderDate 提取月份
df_orders['Month'] = df_orders['OrderDate'].dt.month
monthly_sales = df_orders.groupby('Month')['TotalPrice'].sum()
print("\n每月銷售額:\n", monthly_sales)
# 8. 初步分析:不同支付方式的銷售額
payment_method_sales = df_orders.groupby('PaymentMethod')['TotalPrice'].sum().sort_values(ascending=False)
print("\n不同支付方式的銷售額:\n", payment_method_sales)
# 常見錯誤提醒:
# * **數據類型不匹配**:在進行數值運算前,確保相關列的數據類型是數值型。例如,從 CSV 讀取的數字可能被識別為字串,需要使用 `astype()` 或 `pd.to_numeric()` 轉換。
# * **索引錯亂**:在 `concat` 或 `merge` 操作後,如果沒有正確處理索引,可能會導致索引重複或錯亂。使用 `ignore_index=True` 或 `reset_index()` 可以解決此問題。
# * **原地修改 (inplace=True)**:許多 Pandas 方法有 `inplace` 參數。當 `inplace=True` 時,操作會直接修改原始 DataFrame,而不返回新的 DataFrame。這可以節省記憶體,但也可能導致意外的副作用,因此使用時需謹慎。如果希望保留原始 DataFrame,則不要使用 `inplace=True`,而是將結果賦值給一個新的變數。
# * **鏈式賦值警告 (SettingWithCopyWarning)**:當對 DataFrame 的一個「視圖」進行修改時,Pandas 可能會發出 `SettingWithCopyWarning`。這通常發生在篩選後直接賦值。為避免此問題,應明確使用 `.loc` 或 `.iloc` 進行賦值,或使用 `.copy()` 創建一個副本再操作。
```
## 第三章:Matplotlib 數據視覺化:讓數據說故事
### 3.1 什麼是 Matplotlib?為何視覺化如此重要?
Matplotlib 是 Python 中最基礎且廣泛使用的 2D 繪圖函式庫,它能夠生成各種靜態、動態、互動式的圖表。對於數據分析而言,數據視覺化扮演著至關重要的角色:
對於數據分析而言,數據視覺化扮演著至關重要的角色,主要體現在三個方面:首先,透過圖表,我們可以**洞察數據**中的模式、趨勢、異常值和關係,這些資訊往往難以從原始數據或表格中直接看出;其次,視覺化是將複雜數據分析結果傳達給非技術人員最有效的方式,清晰的圖表能夠幫助決策者快速理解數據背後的含義,從而**溝通結果**;最後,基於視覺化洞察,我們可以做出更明智、更數據驅動的決策,進而**支持決策**。
Matplotlib 的 `pyplot` 模組提供了一個類似 MATLAB 的繪圖介面,使得繪圖過程直觀且易於上手。
### 3.2 基本圖表類型與繪製
Matplotlib 支援多種圖表類型,能夠滿足不同的數據視覺化需求。本節將介紹幾種最常用的基本圖表及其繪製方法,包括用於趨勢分析的**折線圖 (Line Plot)**、探索數據關係的**散佈圖 (Scatter Plot)**、比較類別數據的**長條圖 (Bar Plot)**、概覽數據分佈的**直方圖 (Histogram)**,以及展示比例構成的**圓餅圖 (Pie Chart)**。透過這些圖表,我們可以有效地將數據轉化為直觀的視覺資訊。
```python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 設置中文顯示,避免亂碼 (適用於大多數作業系統)
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"] # 或者其他支持中文的字體,如 SimHei
plt.rcParams["axes.unicode_minus"] = False # 解決負號顯示問題
# 數據準備
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# 折線圖 (Line Plot):趨勢分析
plt.figure(figsize=(8, 4))
plt.plot(x, y1, label=\'sin(x)\', color=\'blue\', linestyle=\'-\'')
plt.plot(x, y2, label=\'cos(x)\', color=\'red\', linestyle=\'--\')
plt.title(\'正弦與餘弦函數圖\')
plt.xlabel(\'X 軸\')
plt.ylabel(\'Y 軸\')
plt.legend()
plt.grid(True)
plt.show()
# 散佈圖 (Scatter Plot):關係探索
np.random.seed(42)
num_points = 50
data_x = np.random.rand(num_points) * 10
data_y = np.random.rand(num_points) * 10 + data_x * 0.5 + np.random.randn(num_points) * 2
plt.figure(figsize=(8, 6))
plt.scatter(data_x, data_y, c=\'green\', alpha=0.7, edgecolors=\'w\', s=50)
plt.title(\'隨機數據散佈圖\')
plt.xlabel(\'特徵 X\')
plt.ylabel(\'特徵 Y\')
plt.grid(True)
plt.show()
# 長條圖 (Bar Plot):類別比較
categories = [\'A\', \'B\', \'C\', \'D\']
values = [23, 45, 56, 12]
plt.figure(figsize=(7, 5))
plt.bar(categories, values, color=\'skyblue\')
plt.title(\'各類別銷售額\')
plt.xlabel(\'類別\')
plt.ylabel(\'銷售額\')
plt.show()
# 直方圖 (Histogram):分佈概覽
dist_data = np.random.randn(1000) # 1000 個標準常態分佈隨機數
plt.figure(figsize=(8, 5))
plt.hist(dist_data, bins=30, color=\'purple\', alpha=0.7)
plt.title(\'數據分佈直方圖\')
plt.xlabel(\'數值\')
plt.ylabel(\'頻率\')
plt.grid(axis=\'y\', alpha=0.75)
plt.show()
# 圓餅圖 (Pie Chart):比例展示
labels = [\'Apple\', \'Banana\', \'Cherry\', \'Date\]
sizes = [15, 30, 45, 10]
explode = (0, 0.1, 0, 0) # 突出顯示第二個切片
plt.figure(figsize=(6, 6))
plt.pie(sizes, explode=explode, labels=labels, autopct=\'%1.1f%%\', shadow=True, startangle=90)
plt.axis(\'equal\') # 確保圓餅圖是圓形的
plt.title(\'水果銷售佔比\')
plt.show()
```
### 3.3 圖表客製化:提升視覺表達力
Matplotlib 提供了豐富的選項來客製化圖表,使其更具可讀性和專業性。這些客製化選項包括調整線條顏色、樣式、寬度,添加標題、軸標籤、圖例,設置軸範圍和刻度,以及添加網格線和文字註釋等。透過精細地調整這些視覺元素,我們可以有效地提升圖表的視覺表達力,更清晰地傳達數據背後的資訊。
```python
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]
plt.rcParams["axes.unicode_minus"] = False
x = np.arange(0, 10, 0.1)
y = np.exp(-x) * np.sin(x * 3)
plt.figure(figsize=(10, 6))
plt.plot(x, y, color=\'#FF5733\', linestyle=\'-.\', linewidth=2, marker=\'o\', markersize=6, markevery=10, label=\'衰減正弦波\')
# 添加標題和軸標籤
plt.title(\'衰減正弦波示例圖\', fontsize=16, fontweight=\'bold\')
plt.xlabel(\'時間 (秒)\' , fontsize=12)
plt.ylabel(\'振幅\', fontsize=12)
# 設置圖例
plt.legend(loc=\'upper right\', fontsize=10)
# 設置軸範圍
plt.xlim(0, 9) # X 軸從 0 到 9
plt.ylim(-0.5, 1.0) # Y 軸從 -0.5 到 1.0
# 設置刻度
plt.xticks(np.arange(0, 10, 1)) # X 軸刻度間隔為 1
plt.yticks(np.arange(-0.5, 1.1, 0.25)) # Y 軸刻度間隔為 0.25
# 添加網格線
plt.grid(True, linestyle=\'--\', alpha=0.6)
# 添加文字註釋
plt.text(2, 0.8, \'峰值點\', fontsize=10, color=\'darkblue\')
plt.annotate(\'局部最小值\', xy=(5.5, -0.4), xytext=(6.5, -0.2),
arrowprops=dict(facecolor=\'black\', shrink=0.05), fontsize=10)
# 調整邊距
plt.tight_layout()
plt.show()
```
#### 中文字體顯示問題與解決方案
在 Matplotlib 中直接使用中文字符作為標題或標籤時,可能會出現亂碼 (方塊)。這是因為 Matplotlib 預設使用的字體不包含中文字符。解決方案是指定一個支持中文的字體,例如透過設置全局字體 `plt.rcParams["font.sans-serif"]` 為系統中已安裝的中文通用字體 (如 Windows 的 SimHei、macOS 的 PingFang HK 或 Arial Unicode MS,以及 Linux 的 WenQuanYi Zen Hei 或 Arial Unicode MS),並設置 `plt.rcParams["axes.unicode_minus"] = False` 來解決負號顯示問題。以下是相關的程式碼範例:
```python
import matplotlib.pyplot as plt
# 解決方案:設置全局字體
# 方法一:手動指定字體文件路徑 (如果知道字體文件在哪裡)
# plt.rcParams["font.sans-serif"] = ["/path/to/your/chinese_font.ttf"]
# 方法二:指定系統中已安裝的中文通用字體 (推薦)
# Windows: SimHei, Microsoft YaHei
# macOS: PingFang HK, Arial Unicode MS
# Linux: WenQuanYi Zen Hei, Arial Unicode MS
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"] # 這裡以 Arial Unicode MS 為例,它在多數系統上都存在
plt.rcParams["axes.unicode_minus"] = False # 解決負號顯示問題
plt.figure(figsize=(6, 4))
plt.plot([1, 2, 3], [4, 5, 6])
plt.title(\'中文標題示例\')
plt.xlabel(\'X 軸標籤\')
plt.ylabel(\'Y 軸標籤\')
plt.show()
```
### 3.4 多圖繪製:子圖 (subplot) 的應用
當需要比較多個圖表或在同一畫布上展示不同視角的數據時,Matplotlib 的**子圖 (subplot) 功能**非常有用。它允許我們在一個圖形視窗中創建多個坐標系,每個坐標系都可以獨立繪製圖表。主要有兩種創建子圖的方法:`plt.subplot()` 和 `plt.subplots()`。`plt.subplot()` 採用網格佈局參數 (行數、列數、子圖索引) 來指定當前繪製的子圖,而 `plt.subplots()` 則會返回一個 `Figure` 物件和一個 `Axes` 物件陣列,這種面向對象的方法在處理複雜佈局時更為靈活和推薦。
```python
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]
plt.rcParams["axes.unicode_minus"] = False
# 數據準備
x = np.linspace(0, 2 * np.pi, 400)
y_sin = np.sin(x)
y_cos = np.cos(x)
y_tan = np.tan(x)
y_exp = np.exp(-x)
# 方法一:使用 plt.subplot()
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1) # 2行2列,第一個子圖
plt.plot(x, y_sin, color=\'blue\')
plt.title(\'正弦函數\')
plt.grid(True)
plt.subplot(2, 2, 2) # 2行2列,第二個子圖
plt.plot(x, y_cos, color=\'red\')
plt.title(\'餘弦函數\')
plt.grid(True)
plt.subplot(2, 2, 3) # 2行2列,第三個子圖
plt.plot(x, y_tan, color=\'green\')
plt.title(\'正切函數\')
plt.ylim(-5, 5) # 限制 Y 軸範圍以更好地顯示正切函數
plt.grid(True)
plt.subplot(2, 2, 4) # 2行2列,第四個子圖
plt.plot(x, y_exp, color=\'purple\')
plt.title(\'指數衰減函數\')
plt.grid(True)
plt.tight_layout() # 自動調整子圖參數,使之填充整個圖像區域
plt.show()
# 方法二:使用 plt.subplots() (推薦,更面向對象)
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 8))
# axes 是一個 2x2 的 NumPy 陣列,包含每個子圖的 Axes 物件
axes[0, 0].plot(x, y_sin, color=\'blue\')
axes[0, 0].set_title(\'正弦函數\')
axes[0, 0].grid(True)
axes[0, 1].plot(x, y_cos, color=\'red\')
axes[0, 1].set_title(\'餘弦函數\')
axes[0, 1].grid(True)
axes[1, 0].plot(x, y_tan, color=\'green\')
axes[1, 0].set_title(\'正切函數\')
axes[1, 0].set_ylim(-5, 5)
axes[1, 0].grid(True)
axes[1, 1].plot(x, y_exp, color=\'purple\')
axes[1, 1].set_title(\'指數衰減函數\')
axes[1, 1].grid(True)
fig.suptitle(\'多個數學函數子圖示例\', fontsize=16, fontweight=\'bold\') # 整個圖的總標題
plt.tight_layout(rect=[0, 0.03, 1, 0.95]) # 調整佈局,為總標題留出空間
plt.show()
```
### 3.5 實戰範例:將 Pandas 處理後的數據進行視覺化
結合 Pandas 強大的數據處理能力和 Matplotlib 豐富的視覺化功能,我們可以從原始數據中提取有價值的洞察,並將其以直觀、易於理解的圖表形式呈現。本節將透過具體範例,展示如何利用這兩大工具,從數據清洗、轉換到最終的視覺化呈現,完成一個完整的數據分析流程,從而幫助讀者更好地理解數據背後的意義和趨勢。
```python
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]
plt.rcParams["axes.unicode_minus"] = False
# 模擬電商銷售數據
data = {
\'OrderDate\': pd.to_datetime([\'2026-01-01\', \'2026-01-05\', \'2026-01-10\', \'2026-01-15\', \'2026-01-20\',
\'2026-02-01\', \'2026-02-08\', \'2026-02-15\', \'2026-02-20\', \'2026-02-25\',
\'2026-03-01\', \'2026-03-05\', \'2026-03-10\', \'2026-03-15\', \'2026-03-20\']),
\'ProductCategory\': [\'Electronics\', \'Books\', \'Electronics\', \'Clothing\', \'Books\',
\'Electronics\', \'Clothing\', \'Books\', \'Electronics\', \'Clothing\',
\'Books\', \'Electronics\', \'Clothing\', \'Books\', \'Electronics\'],
\'SalesAmount\': np.random.randint(50, 500, size=15)
}
df_sales = pd.DataFrame(data)
print("原始銷售數據:\n", df_sales)
# 範例一:繪製每月銷售額折線圖
# 提取月份並計算每月總銷售額
df_sales[\'Month\'] = df_sales[\'OrderDate\'].dt.to_period(\'M\')
monthly_sales = df_sales.groupby(\'Month\')[\'SalesAmount\'].sum().reset_index()
monthly_sales[\'Month\'] = monthly_sales[\'Month\'].astype(str) # 轉換為字串以便繪圖
plt.figure(figsize=(10, 6))
plt.plot(monthly_sales[\'Month\'], monthly_sales[\'SalesAmount\'], marker=\'o\', linestyle=\'-\'', color=\'skyblue\')
plt.title(\'2026 年每月銷售額趨勢\', fontsize=16)
plt.xlabel(\'月份\', fontsize=12)
plt.ylabel(\'銷售額\', fontsize=12)
plt.grid(True, linestyle=\'--\', alpha=0.7)
plt.xticks(rotation=45) # 旋轉 X 軸標籤,避免重疊
plt.tight_layout()
plt.show()
# 範例二:展示不同產品類別的銷售佔比圓餅圖
category_sales = df_sales.groupby(\'ProductCategory\')[\'SalesAmount\'].sum()
plt.figure(figsize=(8, 8))
plt.pie(category_sales, labels=category_sales.index, autopct=\'%1.1f%%\', startangle=90,
colors=plt.cm.Paired.colors, wedgeprops={\'edgecolor\': \'black\', \'linewidth\': 1})
plt.axis(\'equal\')
plt.title(\'產品類別銷售佔比\', fontsize=16)
plt.show()
# 範例三:分析產品類別的銷售額長條圖
plt.figure(figsize=(10, 6))
category_sales.plot(kind=\'bar\', color=\'lightcoral\', edgecolor=\'black\')
plt.title(\'各產品類別總銷售額\', fontsize=16)
plt.xlabel(\'產品類別\', fontsize=12)
plt.ylabel(\'總銷售額\', fontsize=12)
plt.xticks(rotation=45)
plt.grid(axis=\'y\', linestyle=\'--\', alpha=0.7)
plt.tight_layout()
plt.show()
# 常見錯誤提醒:
在 Matplotlib 繪圖過程中,有幾個常見錯誤需要特別注意:首先是**中文字體亂碼**問題,務必設置支持中文的字體,否則標題和標籤會顯示為方塊;其次是**圖表元素重疊**,當數據點過多或標籤過長時,圖表元素可能會重疊,此時可以使用 `plt.xticks(rotation=...)` 旋轉 X 軸標籤,或調整 `figsize` 增大圖表尺寸,或使用 `plt.tight_layout()` 自動調整佈局;再者是**數據解讀偏差**,視覺化只是工具,最終的解讀仍需結合領域知識,例如折線圖的趨勢可能受季節性影響,圓餅圖的比例可能因數據量大小而有不同意義,應避免僅憑圖表表面現象做出結論;最後是**選擇不合適的圖表類型**,不同的數據類型和分析目的需要不同的圖表,例如比較類別數據用長條圖,展示趨勢用折線圖,查看分佈用直方圖,展示佔比用圓餅圖,選擇錯誤的圖表會誤導讀者。
```
## 第四章:綜合實戰案例:從數據到洞察的完整旅程
在本章中,我們將透過一個綜合實戰案例,演示如何將 NumPy、Pandas 和 Matplotlib 這三大 Python 數據分析函式庫結合應用,從原始數據中提取有價值的洞察。我們將以一個虛擬的「城市天氣數據集」為例,詳細展示數據載入、清洗、分析到視覺化的完整流程,幫助讀者融會貫通前述知識,並將其應用於實際問題解決中。
### 4.1 案例背景與數據準備
假設我們有一個包含多個城市每日天氣資訊的數據集,其中包括日期、城市、平均溫度、最高溫度、最低溫度和降水量。我們的目標是透過分析這些數據,找出潛在的天氣模式和趨勢,例如不同城市的溫度差異、降水量的季節性變化等。為了演示這個過程,我們將首先創建一個模擬的數據集。
```python
import pandas as pd
import numpy as np
# 創建模擬的城市天氣數據集
data = {
\"Date\": pd.to_datetime([
\"2026-01-01\", \"2026-01-01\", \"2026-01-01\",
\"2026-01-02\", \"2026-01-02\", \"2026-01-02\",
\"2026-01-03\", \"2026-01-03\", \"2026-01-03\",
\"2026-01-04\", \"2026-01-04\", \"2026-01-04\",
\"2026-01-05\", \"2026-01-05\", \"2026-01-05\",
\"2026-01-06\", \"2026-01-06\", \"2026-01-06\",
\"2026-01-07\", \"2026-01-07\", \"2026-01-07\",
\"2026-01-08\", \"2026-01-08\", \"2026-01-08\",
\"2026-01-09\", \"2026-01-09\", \"2026-01-09\",
\"2026-01-10\", \"2026-01-10\", \"2026-01-10\",
]),
\"City\": [
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
\"Taipei\", \"Kaohsiung\", \"Taichung\",
],
\"AvgTemp\": [
18, 22, 20, 19, 23, 21, 17, 21, 19, 16, 20, 18, 15, 19, 17,
14, 18, 16, 13, 17, 15, 12, 16, 14, 11, 15, 13, 10, 14, 12
],
\"MaxTemp\": [
22, 26, 24, 23, 27, 25, 21, 25, 23, 20, 24, 22, 19, 23, 21,
18, 22, 20, 17, 21, 19, 16, 20, 18, 15, 19, 17, 14, 18, 16
],
\"MinTemp\": [
15, 19, 17, 16, 20, 18, 14, 18, 16, 13, 17, 15, 12, 16, 14,
11, 15, 13, 10, 14, 12, 9, 13, 11, 8, 12, 10, 7, 11, 9
],
\"Precipitation\": [
5, 0, 2, 10, 0, 5, 0, 0, 0, 15, 0, 8, 20, 0, 10,
0, 0, 0, 5, 0, 2, 0, 0, 0, 10, 0, 5, 0, 0, 0
]
}
df_weather = pd.DataFrame(data)
# 引入一些缺失值來模擬真實數據
df_weather.loc[3, \"AvgTemp\"] = np.nan
df_weather.loc[7, \"Precipitation\"] = np.nan
df_weather.loc[12, \"MaxTemp\"] = np.nan
print(\"原始天氣數據:\\n\", df_weather.head())
print(\"\\n數據資訊:\")
df_weather.info()
```
### 4.2 數據清洗與預處理
在進行數據分析之前,數據清洗與預處理是不可或缺的步驟。這包括處理數據中的缺失值、異常值,以及進行必要的數據類型轉換,確保數據的品質和一致性,為後續的分析奠定堅實的基礎。
```python
# 檢查缺失值
print(\"\\n缺失值統計:\\n\", df_weather.isnull().sum())
# 處理缺失值:
# AvgTemp, MaxTemp, MinTemp 可以用該城市該日期的平均值或前一天的值填充
# 這裡簡化處理,直接用列的平均值填充數值型缺失值
df_weather[\"AvgTemp\"] = df_weather[\"AvgTemp\"].fillna(df_weather[\"AvgTemp\"].mean())
df_weather[\"MaxTemp\"] = df_weather[\"MaxTemp\"].fillna(df_weather[\"MaxTemp\"].mean())
# Precipitation 缺失值可以考慮填充 0 (假設缺失代表無降水)
df_weather[\"Precipitation\"] = df_weather[\"Precipitation\"].fillna(0)
print(\"\\n填充缺失值後的數據:\\n\", df_weather.isnull().sum())
# 數據類型轉換:\"Date\" 列已經在創建時轉換為 datetime 類型
# 創建新特徵:從日期中提取月份和年份
df_weather[\"Month\"] = df_weather[\"Date\"].dt.month
df_weather[\"Year\"] = df_weather[\"Date\"].dt.year
print(\"\\n添加月份和年份後的數據:\\n\", df_weather.head())
```
### 4.3 數據分析與探索
數據清洗與預處理完成後,我們便可以開始進行**探索性數據分析 (EDA)**。這個階段的目標是透過統計摘要和初步視覺化,揭示數據中的模式、趨勢、異常值和關係,從而對數據有更深入的理解,並為後續的建模或更深入的分析提供方向。
```python
# 計算各城市平均溫度、總降水量
city_summary = df_weather.groupby(\"City\").agg(
AvgTemp_Mean=(\"AvgTemp\", \"mean\"),
Total_Precipitation=(\"Precipitation\", \"sum\")
).reset_index()
print(\"\\n各城市天氣摘要:\\n\", city_summary)
# 分析不同月份的溫度趨勢 (這裡只有一個月,但邏輯適用於多月數據)
monthly_avg_temp = df_weather.groupby(\"Month\")[\"AvgTemp\"].mean().reset_index()
print(\"\\n每月平均溫度:\\n\", monthly_avg_temp)
# 找出最高溫和最低溫的城市與日期
max_temp_record = df_weather.loc[df_weather[\"MaxTemp\"] == df_weather[\"MaxTemp\"].max()]
min_temp_record = df_weather.loc[df_weather[\"MinTemp\"] == df_weather[\"MinTemp\"].min()]
print(\"\\n最高溫紀錄:\\n\", max_temp_record)
print(\"\\n最低溫紀錄:\\n\", min_temp_record)
```
### 4.4 數據視覺化呈現
數據分析的最終目標之一是將複雜的數據和分析結果以直觀、易於理解的視覺形式呈現。透過 Matplotlib,我們可以創建多種圖表,將前一階段的數據分析與探索的成果清晰地展示出來,幫助我們更好地理解數據背後的模式、趨勢和關係,並有效地將這些洞察傳達給他人。
```python
import matplotlib.pyplot as plt
plt.rcParams[\"font.sans-serif\"] = [\"Arial Unicode MS\"]
plt.rcParams[\"axes.unicode_minus\"] = False
# 繪製各城市月平均溫度折線圖 (這裡只有一個月,但可以展示城市間對比)
plt.figure(figsize=(10, 6))
for city in df_weather[\"City\"].unique():
city_data = df_weather[df_weather[\"City\"] == city]
plt.plot(city_data[\"Date\"], city_data[\"AvgTemp\"], label=city, marker=\'o\')
plt.title(\"各城市平均溫度趨勢 (2026 年 1 月)\", fontsize=16)
plt.xlabel(\"日期\", fontsize=12)
plt.ylabel(\"平均溫度 (°C)\", fontsize=12)
plt.legend()
plt.grid(True, linestyle=\'--\', alpha=0.7)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# 繪製城市總降水量長條圖
plt.figure(figsize=(8, 5))
plt.bar(city_summary[\"City\"], city_summary[\"Total_Precipitation\"], color=[\"skyblue\", \"lightcoral\", \"lightgreen\"])
plt.title(\"各城市總降水量 (2026 年 1 月)\", fontsize=16)
plt.xlabel(\"城市\", fontsize=12)
plt.ylabel(\"總降水量 (mm)\", fontsize=12)
plt.grid(axis=\'y\', linestyle=\'--\', alpha=0.7)
plt.tight_layout()
plt.show()
# 繪製溫度與降水量的散佈圖,探索潛在關係
plt.figure(figsize=(10, 6))
plt.scatter(df_weather[\"AvgTemp\"], df_weather[\"Precipitation\"],
c=df_weather[\"Month\"], cmap=\'viridis\', alpha=0.7, s=50)
plt.title(\"平均溫度與降水量關係圖 (按月份著色)\", fontsize=16)
plt.xlabel(\"平均溫度 (°C)\", fontsize=12)
plt.ylabel(\"降水量 (mm)\", fontsize=12)
plt.colorbar(label=\"月份\")
plt.grid(True, linestyle=\'--\', alpha=0.7)
plt.tight_layout()
plt.show()
```
### 4.5 總結與洞察
透過上述分析,我們可以從「城市天氣數據集」中得出以下洞察:
透過上述分析,我們可以從「城市天氣數據集」中得出以下洞察:首先,**溫度趨勢**顯示在 2026 年 1 月份,各城市的平均溫度呈現逐漸下降的趨勢,這符合冬季的氣候特徵,其中台北的溫度相對較低,高雄則相對較高;其次,**降水分佈**方面,台北的總降水量明顯高於高雄和台中,這可能與其地理位置和氣候模式有關,且降水事件似乎在某些特定日期較為集中;最後,**溫度與降水關係**的散佈圖顯示,在較低的平均溫度下,降水量有時會較高,這可能暗示著冬季降雨或濕冷天氣的發生,然而這也需要進一步的數據和更長時間的觀察來驗證。
**如何將這些洞察應用於實際決策**:
這些洞察可以應用於實際決策:例如,在**城市規劃**方面,根據降水數據,城市規劃者可以評估不同城市的排水系統需求;在**旅遊業**方面,旅遊業者可以根據溫度趨勢和降水模式,為不同城市制定季節性的旅遊推廣策略;在**農業**方面,農民可以根據氣溫和降水預測,調整作物種植和灌溉計劃。
**常見錯誤與解決方案**:
在數據分析過程中,也應注意常見錯誤與解決方案:首先是**數據偏見**,本案例數據量較小且僅限於一個月,可能存在偏見,在實際應用中應使用更大量、更長時間跨度的數據來確保分析結果的可靠性;其次是**過度擬合**,在進行更複雜的預測模型時,應注意避免過度擬合,確保模型在未見數據上的泛化能力,這通常需要使用交叉驗證等技術;最後是**忽略領域知識**,數據分析不僅僅是技術操作,更需要結合領域知識來解釋數據背後的含義,例如理解台灣冬季的東北季風對降水的影響,有助於更準確地解讀天氣數據。
這個綜合實戰案例展示了 NumPy、Pandas 和 Matplotlib 如何協同工作,幫助我們從原始數據中發現有意義的資訊,並將其轉化為可操作的洞察。這正是數據分析的魅力所在。
## 結論
本教學文章全面介紹了 Python 數據分析的三大基石:NumPy、Pandas 和 Matplotlib。透過學習 NumPy 的高效數值運算、Pandas 強大的數據處理能力,以及 Matplotlib 靈活的數據視覺化技巧,您已具備處理和分析結構化數據的核心技能。數據分析是一個不斷學習和實踐的過程,鼓勵您將所學應用於更多真實世界的數據集,持續探索和提升。掌握這些工具,您將能夠更好地理解數據、從中提取價值,並為決策提供有力支持。
## 常見問題 (FAQ)
1. **NumPy 和 Pandas 有什麼區別?我應該先學哪個?**
NumPy 主要處理數值陣列運算,提供底層高效計算的能力,是許多科學計算庫的基礎。而 Pandas 則建立在 NumPy 之上,提供了更高級的數據結構,如 Series 和 DataFrame,以及更豐富的數據處理工具,使其更適合處理表格型數據。對於初學者而言,建議先學習 NumPy 的基礎知識,理解其陣列操作的原理,再深入學習 Pandas,這樣能更好地掌握數據處理的精髓。
2. **Matplotlib 和 Seaborn 哪個更好?**
Matplotlib 是 Python 中最基礎且功能強大的繪圖庫,提供了高度的客製化能力,可以繪製各種靜態、動態和互動式圖表。而 Seaborn 則是建立在 Matplotlib 之上的高級數據視覺化庫,它提供了更美觀的預設樣式和更高級的統計圖表功能,能夠更方便地繪製複雜的統計圖表。通常情況下,兩者會結合使用,Matplotlib 負責底層的圖表控制和細節調整,而 Seaborn 則用於快速生成美觀且具有統計意義的圖表。因此,沒有絕對的「更好」,而是根據具體需求選擇或結合使用。
3. **如何選擇合適的數據分析工具?**
選擇合適的數據分析工具主要取決於**任務需求**、**數據類型**和**個人偏好**。Python 及其生態系統 (NumPy, Pandas, Matplotlib) 適用於通用數據分析、機器學習和自動化任務,具有高度靈活性和擴展性。R 語言則在統計分析、學術研究和數據視覺化方面擁有強大優勢。對於小型數據集和快速探索性分析,Excel 仍是一個便捷的選擇。而 SQL 則是用於數據庫查詢和管理的核心工具。在實際工作中,數據分析師通常會根據專案需求,靈活運用多種工具。
4. **如何處理大型數據集以提高 Pandas 效能?**
處理大型數據集時,為了提高 Pandas 的效能,可以採取多種策略:首先,**優化數據類型**,例如使用更小的整數或浮點數類型,可以顯著減少記憶體佔用;其次,對於非常大的文件,可以**使用 `chunksize` 分塊讀取**,避免一次性載入所有數據導致記憶體溢出;再者,應**避免在 DataFrame 上進行迭代**,盡量使用 Pandas 內建的向量化操作,這會比 Python 迴圈快得多;最後,對於超大型數據集,可以**考慮使用 Dask 或 PySpark 等分散式計算框架**,它們能夠將數據處理任務分發到多個核心或機器上並行執行。
5. **學習 Python 數據分析的下一步是什麼?**
在掌握了 NumPy、Pandas 和 Matplotlib 的基礎後,學習 Python 數據分析的下一步可以朝多個方向發展:您可以**學習更多高級視覺化庫**,例如 Seaborn 和 Plotly,以創建更具吸引力和互動性的圖表;**深入統計學和機器學習**,掌握 Scikit-learn 等庫的使用,進行更複雜的數據建模和預測;**學習數據庫操作**,例如使用 SQLAlchemy 與各種數據庫進行交互;最重要的是,**積極參與數據分析專案**,將所學知識應用於真實世界的數據,累積實戰經驗,不斷提升解決問題的能力。
6. **如何將 Matplotlib 圖表保存為高解析度圖片?**
要將 Matplotlib 圖表保存為高解析度圖片,可以使用 `plt.savefig()` 函數。其中,`dpi` 參數用於控制圖片的解析度,例如設置 `dpi=300` 可以獲得 300 DPI 的圖片,而 `bbox_inches=\'tight\'` 參數則可以確保圖表邊界緊湊,避免出現多餘的空白邊緣。例如:`plt.savefig(\'filename.png\', dpi=300, bbox_inches=\'tight\')`。
7. **Python 數據分析的學習路徑建議?**
對於 Python 數據分析的學習路徑,建議從**Python 基礎**開始,掌握基本的語法和程式設計概念。接著,深入學習**NumPy**以理解高效的數值運算,然後是**Pandas**,掌握其強大的數據處理和操作能力。在數據處理的基礎上,學習**Matplotlib/Seaborn**進行數據視覺化。隨後,建議補充**統計學基礎**知識,這對於理解數據背後的意義至關重要。進一步可以學習**機器學習基礎**,例如使用 Scikit-learn 進行模型建立。最後,也是最重要的一步,是透過**實戰專案**來鞏固所學,將理論知識應用於實際問題解決中,不斷累積經驗。
8. **在數據分析中,如何確保數據的準確性和可靠性?**
確保數據的準確性和可靠性是數據分析成功的關鍵。這需要多方面的努力:首先,必須對**數據來源進行可靠性驗證**,了解數據的採集方式、潛在偏差和限制;其次,在**數據清洗階段必須保持嚴謹**,仔細處理缺失值、異常值和重複值,確保數據的完整性和一致性;再者,可以透過**交叉驗證和多種分析方法的比較**來驗證分析結果的穩健性;最後,進行**結果的合理性檢查並結合領域知識**,判斷分析結果是否符合常識和業務邏輯,避免得出錯誤的結論。
## SEO 優化與相關工具推薦
### 長尾關鍵字建議
為了提升文章的搜尋引擎優化 (SEO) 效果,建議包含以下長尾關鍵字:Python 數據分析教學、Pandas 數據處理實戰、NumPy 陣列操作教學、Matplotlib 數據視覺化教學、Python 數據科學入門指南、數據分析師必備 Python 技能、Python 數據分析範例程式碼、Python 數據分析工具比較、如何用 Python 進行數據清洗、Python 數據視覺化圖表類型。
### 內部連結建議
為了增加文章的內部連結,提升網站的 SEO 表現和用戶體驗,建議在文章中適當位置加入以下內部連結:建議連結至「Python 程式設計基礎教學」以提供讀者 Python 基礎知識的補充;建議連結至「機器學習入門與 Scikit-learn 實戰」以引導讀者進一步學習數據建模;建議連結至「數據庫與 SQL 基礎教學」以擴展讀者在數據庫操作方面的知識。
### 相關工具推薦
除了 NumPy、Pandas 和 Matplotlib 之外,還有一些相關工具可以極大地提升數據分析的效率和體驗:**Jupyter Notebook / JupyterLab** 提供了一個互動式數據分析環境,方便程式碼、輸出和說明文字的整合;**VS Code** 是一個強大的程式碼編輯器,支援 Python 開發和 Jupyter Notebook;**Seaborn** 是基於 Matplotlib 的高級數據視覺化庫,能夠提供更美觀的統計圖表;**Scikit-learn** 是一個廣泛使用的機器學習庫,提供了多種機器學習演算法;**Google Colab** 則是一個基於雲端的 Jupyter Notebook 環境,無需本地配置即可運行 Python 程式碼,非常適合學習和快速原型開發。
## 實用性說明
為了確保文章的實用性,本教學文章在設計上特別強調以下幾點:首先,每個主要概念都將搭配具體的**實際範例**和程式碼,展示如何應用 NumPy、Pandas 和 Matplotlib 解決實際問題;其次,對於複雜的操作,將提供清晰的**步驟說明**,確保讀者能夠按部就班地學習和實踐;最後,在各章節和實戰案例中,將指出新手常犯的**常見錯誤**,並提供解決方案,幫助讀者避免踩坑,提升學習效率。