# W3教材大綱: pandas–資料處理套件介紹
## Source
- 成為python數據分析達人的第一堂課 5
- [website](https://blog.techbridge.cc/2020/09/21/python-pandas-zen-tutorial/)
- 大數據分析與資料探勘
- W2 P29-41
- W3
- 練習資料集: grades.csv
- [Website: Pandas資料合併技巧](https://medium.com/@hui509/pandas-%E8%B3%87%E6%96%99%E5%90%88%E4%BD%B5%E7%9A%84%E4%B8%89%E7%A8%AE%E5%B8%B8%E7%94%A8%E8%AA%9E%E6%B3%95-cd2918774efe)
- [Website圖片](https://hackmd.io/@linweipo/r1lkaXGlK)
## 淳瑜的Gamma prompt
- Write for: 剛開始接觸機器學習,正在學習資料分析和 Pandas,且有一些python基礎的初學者
- Tone: 專業、有邏輯、教導、重點明確
- Additional instructions: 請生成大學機器學習教學投影片,教授對象是僅有微弱python基礎的文商學院同學,請盡可能展示所有程式碼及教學細節
## 課堂投影片與練習
- [x] **資料處理的重要性**
- 資料品質和資料完整性決定資料探勘效果的好壞。
- 資料蒐集的方式(或工具)各異,導致資料庫或資料倉儲可能存在著許多資料雜訊、資料遺漏及資料格式不一致的狀況;加上大數據資料具有4V特性,若直接分析原始資料,很可能因資料品質不佳而導致事倍功半的結果或有偏誤的結論。
- 資料準備(data preparation)是指在瞭解問題與目的之後,進行資料探勘與建立模式之前,為確保分析資料品質和分析結果正確性所進行的資料蒐集、資料預處理、資料轉換及資料分割等一連串程序。
---
- [x] **為什麼要學 Pandas?**
* 可以簡單地將 Pandas 想成是 **Python 裡面的 Excel**。
* 為什麼重要?在數據分析中,我們常說 **80% 的時間都花在「資料清理」**上。Pandas 就是幫助我們完成這項任務的強大工具。
* Pandas 是 Python 之所以能在數據分析領域佔據龍頭地位的重要原因之一。
* 學習 Pandas 能讓你更方便地使用程式來整理資料,比手動操作 Excel 更有效率、更不容易出錯。
* 掌握 Pandas 是邁向數據分析和機器學習的第一步!
---
- [x] **開始使用 Pandas**
* 就像使用 NumPy 和 Matplotlib 一樣,使用 Pandas 前需要先匯入。
* 標準的匯入方式是:`import pandas as pd`。
* 每次進行數據分析或機器學習前,建議在 Jupyter Notebook 中先執行以下標準指令:
```python=
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
```
---
- [x] **課堂練習: 安裝 Pandas 並在 Python 環境中導入**
1. 指導學生在命令行中輸入:
```
pip install pandas
```
2. 在 Python 環境中導入 Pandas:
```python
import pandas as pd
```
3. 確認安裝成功:
```python
print(pd.__version__)
```
---
- [x] **Pandas 的核心資料結構**
* Pandas 主要有兩種核心的資料結構:
1. **Series (序列)**
* 可以想成是一個有「名字」(index)的 List 或 NumPy Array。
* 通常是 DataFrame 中的**單一欄位**。
* 例如,一串學生的「國文」成績,就可以是一個 Series。
2. **DataFrame (資料框)**
* 可以想成就是一張**表格**,就像 Excel 的試算表。
* 這是 Pandas 中最標準、最常用的資料結構。
* 包含「列」(Row)和「行」(Column)。
* 每一列的前面有「index」(索引),每一行的上面有「columns」(欄位名)。
---
- [x] **課堂練習: 建立 Series**
1. 創建帶有自定義索引的 Series:
```python
grades = pd.Series([60, 27, 72, 53], index=['小郭', '小王', '小華', '小明'])
print(grades)
```
2. 使用索引取值:
```python
print(grades['小王'])
print(grades[1:3])
```
---
- [x] **課堂練習: 建立 DataFrame**
1. 準備傳入 Dataframe 的資料:
```python
data = {
'name': ['多拉A夢', '大雄', '小夫', '胖虎'],
'email': ['Dora@gmail.com', 'hibino@gmail.com', 'rich@gmail.com', 'goodSinger@gmail.com'],
'grades': [60, 77, 92, 43]
}
df = pd.DataFrame(data)
print(df)
```
2. 建立 DataFrame:
```python
df_custom = pd.DataFrame(data, index=['one', 'second', 'third', 'fourth'])
print(df_custom)
```
---
- [x] **DataFrame 與 NumPy 的關係**
* 雖然 Pandas 提供了很多數據分析功能,但有時我們仍需要將 Pandas 的 Series 或 DataFrame 轉換成 NumPy Array。
* 這是因為某些複雜的數值運算或特定的函式庫需要 NumPy Array 作為輸入。
* **如何轉換?** 在 Series 或 DataFrame 後面加上 `.values` 屬性。
* 範例:`df['國文'].values` 會將「國文」這個 Series 轉換成 NumPy Array。
* 你可以使用 `type()` 函式來檢查資料的類型。
---
- [x] **使用 Pandas - 讀取資料**
* Pandas 可以讀取幾乎所有常見的資料格式,特別是 **CSV** 和 Excel 檔案。
* **讀取 CSV 檔案:** 使用 `pd.read_csv()` 函式。
* 可以讀取本地的檔案:`df = pd.read_csv('檔案名稱.csv')`.
* 也可以直接讀取網路上的檔案 (只要網址指向一個 CSV 檔案):`df = pd.read_csv('http://檔案網址/檔案名稱.csv')`。
* 我們習慣將讀入的 DataFrame 存到一個變數,通常簡稱 `df`。
---
- [x] **課堂練習:基礎操作與資料載入**
1. 下載課程提供的 csv檔案==(須提供資料集)==
2. 讀取 CSV 文件
```python
df= pd.read_csv('grades.csv')
print(df.head())
```
3. 將 DataFrame 寫入 CSV 文件:
```python
df.to_csv('grades2.csv', index=False)
```
---
- [x] **初步探索資料**
* 讀入資料後,第一件要做的事通常是**查看資料的樣子**,確認讀入是否正確。
* 使用 `.head()` 方法:`df.head()`。
* 會顯示 DataFrame 的**前 5 筆**資料(預設值)。
* 可以指定顯示筆數:`df.head(10)` 會顯示前 10 筆。
* DataFrame 包含:
* **Index:** 每一列前面的標籤或名字 (預設從 0 開始的數字)。
* **Columns:** 每一行上面的欄位名稱。
* df.index(), df.columns
* 列出 DataFrame 資訊
---
- [x] **課堂練習: DataFrame 基本操作**
1. 列出 DataFrame 資訊:
```python
print(df.info())
```
2. 查看 DataFrame 的頭尾部分:
```python
print(df.head(3))
print(df.tail(3))
```
3. 查看索引和列名:
```python
print(df.index)
print(df.columns)
```
---
- [x] **欄位存取**
* **如何存取單一欄位 (Column)?**
* 使用中括號 `[]`:`df['姓名']`。這是最常用且彈性的方法。
* 使用點記法 `.`: `df.姓名`。方便但不適用於所有情況 (例如欄位名有空格或特殊字元、中文)。
* 存取結果會是一個 **Series**。
```python=
# 存取「姓名」欄位
print(df['姓名'])
```
- 若要取得2個以上欄位資料,則需使用串列
```python=
df[['姓名', '性別']]
```
- 根據條件篩選資料
- 範例: 找出英文成績超過 90 分的學生
```python=
df[df['英文'] > 90] #可以print觀察結果喔!
```
---
- [x] **Pandas 的基本數據分析功能**
* Pandas 本身就提供了方便的基礎統計和分析功能。
* **單一欄位的統計:**
* 計算平均值:`df['國文'].mean()` (來源未直接提供,但 `.std()` 等有提供,可推斷)。
* 計算標準差:`df['國文'].std()`。
* 計算最小值:`df['國文'].min()` (來源未直接提供,但 `.describe()` 有)。
---
- [x] **Pandas 的基本數據分析功能**
* **快速總覽數值欄位統計:** 使用 `.describe()` 方法。
* 會一次計算出數值型欄位的:筆數 (count)、平均值 (mean)、標準差 (std)、最小值 (min)、25%/50%/75% 四分位數 (quantile)、最大值 (max)。
* **計算欄位間的相關性:** 使用 `.corr()` 方法。
* DataFrame 的 `.corr()` 會計算所有數值欄位之間的相關係數矩陣。
* 可以計算兩個指定欄位之間的相關係數:`df['欄位1'].corr(df['欄位2'])`。
- 課堂練習
```python=
# 國文與數學成績的相關係數
df['國文'].corr(df['數學'])
```
---
- [x] **認識軸(axis)與軸操作**
* **重要的觀念:Axis (軸)**
* Pandas 很多操作(如求和、計算平均)需要指定方向 (軸)。
* `axis=0`: 表示沿著**列**的方向操作 (即對**每一行**做運算)。想像成是「垂直」或「往下」的方向。
* `axis=1`: 表示沿著**行**的方向操作 (即對**每一列**做運算)。想像成是「水平」或「往右」的方向。
* 這點新手容易混淆,請多加練習
---
- [x] **數學運算結合新增欄位之應用**
* **欄位間的數學運算:** Pandas DataFrame/Series 支援基本的數學運算符號 (`+`, `-`, `*`, `/`)。
* 計算總分,需要將**每一列**的科目成績加總。
* 先取出需要加總的欄位:`df[['國文', '英文', '數學', '自然', '社會']]`。
* 對這些欄位進行加總,方向是**跨欄位 (每一列)**,所以使用 `axis=1`。
```python=
# 計算總分(五科相加)
df['總積分'] = df[['國文', '英文', '數學', '自然', '社會']].sum(axis=1)
# 顯示前幾列確認
print(df.head())
```
* 計算加權成績 = 數學*1.5 + 英文。
```python=
df['主科'] = df['數學'] * 1.5 + df['英文']
```
- 課堂練習: 新增"平均分數"欄位
```python=
df['平均分'] = df['總分'] / 5
```
---
- [x] **新增欄位**
* 我們可以很容易地在現有的 DataFrame 中新增欄位。
* 新增欄位的方式是直接為一個新的欄位名稱賦值:`df['新欄位名稱'] = 值或計算結果`。
* 新的欄位值可以是一個固定的值,也可以是對現有欄位進行運算得到的結果。
---
# 以下第二堂課
- [x] **資料操作 - 排序 (`sort_values`)**
* 對資料進行排序是常見的需求,例如找出總積分最高的同學。
* 使用 `.sort_values()` 方法可以根據一個或多個欄位的值對 DataFrame 的**列**進行排序。
* **指定排序依據的欄位:** 使用 `by` 參數。
* 單一欄位:`df.sort_values(by='總積分')`。
* 多個欄位:`df.sort_values(by=['主科', '總積分'])`。排序時會先依第一個欄位排序,值相同再依第二個,以此類推。
* **指定排序方向:** 使用 `ascending` 參數。
* `ascending=True`:由小到大排序 (預設值).
* `ascending=False`:由大到小排序.
* 範例:`df.sort_values(by='總積分', ascending=False)` 會依總積分由高到低排序.
* 排序操作預設會回傳一個新的 DataFrame,不會修改原始 DataFrame。
---
- [x] **資料操作 - 分組 (`groupby`)**
* 當你想要根據某個欄位的分類(例如不同縣市、不同組別)來計算統計值時,就可以使用分組功能。
* 使用 `.groupby()` 方法:`df.groupby('分類欄位名稱')`。
* `groupby()` 本身的回傳值是一個特殊的 GroupBy 物件,需要搭配**聚合 (Aggregation)** 函式才能得到結果。
* 常見的聚合函式有:`.count()` (計算每組的數量)、`.mean()` (計算每組的平均值)、`.sum()` (計算每組的總和) 等。
* 範例:統計每個州的 UFO 目擊次數。
* `df_state = df.groupby('State').count()`。
* 這會根據 'State' 欄位分組,然後計算每個組(每個州)的行數(即目擊次數)。
* 分組後的結果通常也是一個 DataFrame 或 Series,可以再進行排序、篩選等操作。
---
- [ ] **課堂練習:數據分析與操作**
1. **任務:** 使用您載入的 `df` DataFrame,計算所有數值欄位的基本統計資訊,並顯示出來。
2. **任務:** 計算「國文」和「數學」成績之間的相關係數。
3. **任務:** 為 DataFrame 新增一個名為「總分」的欄位,其值為所有科目成績的加總 (假設所有科目都是數值欄位)。**提示:** 注意使用正確的 `axis` 方向。
4. **任務:** 為 DataFrame 新增一個名為「平均分」的欄位,其值為總分除以科目數量 (假設有 5 個科目)。
5. **任務:** 根據「總分」欄位,將 DataFrame 由高到低排序,並顯示排序後的前 10 筆資料。
---
- [ ] Python 資料合併:Pandas 的強大工具
* 在數據分析中,資料合併是一個關鍵步驟
* Pandas 提供了多種合併方法,適用於不同場景
* 今天我們將學習三種主要的合併方法:
1. concat()
2. merge()
3. join()
---
- [ ] Pandas 合併方法介紹與比較
* concat(): 用於簡單的垂直或水平合併
* merge(): 基於特定列或索引的智能合併
* join(): 基於索引的合併
* 選擇合適的方法取決於:
- 資料結構
- 合併需求
- 效能考量
---
- [ ] **Concat**
* 有時候你需要將不同的資料表合併起來,Pandas 提供了 `pd.concat()` 函式。
* `pd.concat()` 接受一個要合併的 DataFrame 列表 (List) 作為輸入。
* **指定合併方向:** 使用 `axis` 參數。
* `axis=0`:沿著**列**的方向合併 (上下疊),這是預設值。就像在 Excel 中把一個表格貼到另一個表格的下方。
* `axis=1`:沿著**行**的方向合併 (左右接),需要指定 `axis=1`。就像在 Excel 中把一個表格貼到另一個表格的右方。
* **水平合併 (`axis=1`) 的注意事項:** 如果合併的 DataFrame 列數不一致,缺少資料的地方會自動填入 `NaN` (Not a Number),表示「遺失值」。
* 合併後可能需要重設或修改索引 (Index)。
---
- [ ] merge()
* 用途:基於一個或多個鍵(列)合併 DataFrame
* 語法:`pd.merge(left, right, on=None, how='inner')`
* 參數:
- left, right: 要合併的 DataFrame
- on: 用於合併的列名
- how: 合併方式('inner', 'outer', 'left', 'right')
* 適用場景:需要基於特定條件合併不同結構的資料集
---
- [ ] **Join**
- Inner Join (取交集),如 : pd.merge(df1,df2, left_on='cid', right_on='cid', how='inner')
- Outer Join (取聯集),如 : pd.merge(df1,df2, left_on='cid', right_on='cid', how='outer')
- Left Join (以左邊DataFrame欄位為主體),如 : pd.merge(df3,df4, left_on='cid', right_on='cid', how='left')
- Right Join (以右邊DataFrame欄位為主體),如 : pd.merge(df3,df4, left_on='cid', right_on='cid', how='right')
---
- [ ] **進階觀念:`.loc` 的使用**
* **新手最容易困惑的地方來了!** 當你想要「根據某些條件篩選資料,然後修改篩選出來的資料」時,常會遇到問題。
* 例如,你想找到國文成績及格的同學,然後把他們的數學成績設定為 100。你可能會寫 `df[df['國文'] >= 60]['數學'] = 100`。
* 但這樣做,**原始的 `df` 可能根本沒被修改!** 這是因為 `df[df['國文'] >= 60]` 可能會回傳一個新的 DataFrame 的**拷貝 (Copy)**,你修改的是這個拷貝,而不是原始資料。
* **解決方法:使用 `.loc`!** `.loc` 是 Pandas 中用於**基於標籤 (Label)** 進行選取和修改的強大工具。學會它會讓你覺得 Pandas 親切很多。
* `.loc` 的基本語法:`df.loc[row_indexer, column_indexer]`。
* `row_indexer` 可以是單個標籤、標籤列表、切片、布林值 Series (就是你的條件)。
* `column_indexer` 可以是單個欄位名、欄位名列表、切片。
* **正確的條件式修改範例:**
* 選取國文成績大於等於 60 的**列**,以及「數學」這個**行**:`df.loc[df['國文'] >= 60, '數學']`
* 將這些位置的值設定為 100:`df.loc[df['國文'] >= 60, '數學'] = 100`
* **總結:** 只要你想根據 index 或 column name 來**精確選取或修改** DataFrame 的特定位置,特別是進行條件式的修改,請**務必使用 `.loc`**!
---
- [ ] **課堂練習:使用 `.loc` 進行精確操作**
1. **任務:** 建立一個簡單的 DataFrame,包含至少兩列數值欄位(例如:'A' 和 'B')和一些隨機數據。
```python=
import pandas as pd
import numpy as np
df_test = pd.DataFrame(np.random.randn(5, 2), columns=['A', 'B'])
print("原始 DataFrame:")
print(df_test)
```
2. **任務:** 使用 `.loc` 選取 DataFrame 中 Index 為 1 和 3 的兩列資料,以及 'A' 欄位,並顯示出來。
```python=
# 請在這裡寫你的程式碼
```
3. **任務:** 使用 `.loc` 選取 DataFrame 中 Index 為 2 的列,以及 'B' 欄位,並將其值修改為 999。然後再次顯示整個 DataFrame 檢查是否修改成功。
```python=
# 請在這裡寫你的程式碼
```
4. **任務:** 使用 `.loc`,找出 DataFrame 中 'A' 欄位值大於 0 的列,將這些列的 'B' 欄位值全部設為 0。然後再次顯示整個 DataFrame 檢查是否修改成功。
```python=
# 請在這裡寫你的程式碼
```
5. **討論:** 如果你在任務 4 中沒有使用 `.loc`,而是寫 `df_test[df_test['A'] > 0]['B'] = 0`,可能會發生什麼情況?為什麼 `.loc` 是更正確的方式?
---
- [ ] **常見問題與除錯**
* **大小寫搞混 (`NameError: NameX Not Defined`)**
* Python **區分大小寫**!`my_variable` 和 `My_Variable` 是不同的變數。
* Pandas 的函式、方法、欄位名稱也都是區分大小寫的。
* 檢查你的變數名稱、函式名稱、欄位名稱是否大小寫正確。
* **忘記匯入套件 (`NameError` 或 `AttributeError`)**
* 使用任何套件的功能前,**必須**先使用 `import` 匯入。
* 例如,你嘗試使用 `pd.read_csv()` 但沒有執行 `import pandas as pd`,就會出錯。
* 看到錯誤訊息時,檢查一下你的程式碼開頭是否已經匯入所有需要的套件。
* **核心重新啟動 (Kernel Restart)**
* 如果在 Jupyter Notebook 中重新啟動 (Restart) 了 Kernel,之前執行的程式碼、定義的變數、匯入的套件**都會被清除**。
* 你需要從頭執行所有必要的程式碼 (包括匯入套件、讀取資料等)。
* **Axis 方向混淆**
* 再次強調:`axis=0` 是**列**的方向 (垂直),`axis=1` 是**行**的方向 (水平)。記不住就多查官方文件或筆記。
* **操作是否改變原始 DataFrame (`inplace`)**
* Pandas 許多操作(如排序 `sort_values`,但不包括 `.loc` 的賦值操作)預設會回傳一個**新的** DataFrame,而不是修改原始的。
* 如果你確定想直接修改原始 DataFrame,可以使用 `inplace=True` 參數。
* 但對於條件式修改,使用 `.loc` 是更推薦和正確的方式。
---
- [ ] **總結**
* 本週我們學習了 Pandas 這個強大的 Python 資料處理工具。
* 掌握了 Pandas 的核心結構:Series 和 DataFrame。
* 學會了如何匯入 Pandas、讀取資料。
* 學會了初步探索資料 (`.head()`) 和存取欄位。
* 學習了 Pandas 的基本數據分析功能 (`.describe()`, `.corr()`)。
* 學會了新增欄位和進行數學運算 (特別是 Axis 的概念)。
* 學會了排序 (`.sort_values()`) 和分組 (`.groupby()`)。
* **特別強調了使用 `.loc` 進行精確選取和修改的重要性**!
* 了解了一些常見問題和除錯方法。
* **課後:** 請務必花時間多練習,熟練今天教的操作。