智研所 logo智研所

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 解決實際問題;其次,對於複雜的操作,將提供清晰的**步驟說明**,確保讀者能夠按部就班地學習和實踐;最後,在各章節和實戰案例中,將指出新手常犯的**常見錯誤**,並提供解決方案,幫助讀者避免踩坑,提升學習效率。

相關文章