多維陣列的資料型態
## NumPy `ndarray` 與資料型態簡介
NumPy 的 `ndarray` 是一種多維陣列,除了形狀(`shape`)與維度(`ndim`)之外,每個元素通常都具有相同的資料型態,由 `dtype` 表示。
```python
import numpy as np
a = np.array([1, 2, 3])
print(a.dtype) # 可能是 int64
```
資料型態會影響:
- 每個元素佔用的記憶體大小
- 計算速度
- 可表示的數值範圍
- 運算結果的精確度
- 是否能儲存文字、日期或缺失值
---
## 常見的 NumPy 資料型態
### 1. 整數型態
用來儲存沒有小數的數值。
| 型態 | 說明 |
|---|---|
| `np.int8` | 8 位元有號整數 |
| `np.int16` | 16 位元有號整數 |
| `np.int32` | 32 位元有號整數 |
| `np.int64` | 64 位元有號整數 |
| `np.uint8` | 8 位元無號整數,範圍為 0~255 |
一般情況下,`np.int64` 常用於整數陣列,但實際預設型態可能依作業系統而不同。
### 2. 浮點數型態
用來儲存含小數的數值。
| 型態 | 說明 |
|---|---|
| `np.float16` | 低精度、佔用空間小 |
| `np.float32` | 常用於機器學習與影像處理 |
| `np.float64` | 精度較高,NumPy 常見預設型態 |
### 3. 複數型態
| 型態 | 說明 |
|---|---|
| `np.complex64` | 複數,通常由兩個 `float32` 組成 |
| `np.complex128` | 複數,通常由兩個 `float64` 組成 |
例如:
```python
z = np.array([1 + 2j, 3 + 4j])
```
### 4. 布林型態
`np.bool_` 只能表示 `True` 或 `False`,常用於條件篩選。
```python
mask = np.array([True, False, True])
```
### 5. 字串與物件型態
- `np.str_`:固定長度的 Unicode 字串
- `np.bytes_`:位元組字串
- `object`:可儲存 Python 物件,例如不同長度字串、列表或混合型資料
`object` 彈性較高,但通常速度較慢,也失去 NumPy 同質陣列的部分優勢。
### 6. 日期與時間型態
- `np.datetime64`:日期或時間
- `np.timedelta64`:時間差
例如可表示日期、月份、天數或奈秒等不同時間單位。
### 7. 結構化型態
`structured dtype` 可以讓同一個陣列中的每個元素包含多個具名欄位,類似資料表的一列。
```python
dtype = np.dtype([("name", "U10"), ("age", "i4")])
```
---
## 範例一:指定資料型態與檢查記憶體
```python
import numpy as np
a = np.array([1, 2, 3, 4], dtype=np.int32)
print(a) # [1 2 3 4]
print(a.dtype) # int32
print(a.itemsize) # 4,每個元素佔 4 bytes
print(a.nbytes) # 16,整個陣列佔 16 bytes
```
這個例子指定使用 `int32`,每個元素佔 4 bytes。如果資料量很大,適當選擇較小的型態可以節省記憶體。
---
## 範例二:型態轉換與布林篩選
```python
import numpy as np
x = np.array([1.2, 2.8, 3.5])
y = x.astype(np.int32)
print(y) # [1 2 3]
print(y.dtype) # int32
mask = y > 1
print(y[mask]) # [2 3]
```
`astype(np.int32)` 會將浮點數轉成整數,小數部分會被截去,而不是四捨五入。
---
## 常見的資料型態議題
### 1. 整數溢位
整數型態有固定的可表示範圍。例如 `int8` 的範圍通常是 -128~127,超過範圍可能產生溢位,結果並非預期。
```python
x = np.array([127], dtype=np.int8)
# x + 1 可能得到 -128
```
如果數值可能很大,應使用較大的型態,例如 `int32` 或 `int64`。
---
### 2. 浮點數精度誤差
浮點數通常無法精確表示所有十進位小數,因此可能出現:
```python
0.1 + 0.2 != 0.3
```
這是二進位浮點數表示法的正常現象。比較浮點數時,建議使用:
```python
np.isclose(a, b)
```
而不是直接使用 `a == b`。
---
### 3. 型態自動推導與混合型態
建立陣列時,NumPy 會自動推導共同型態。
```python
np.array([1, 2.5]).dtype
```
通常會提升為浮點型態,因為整數可以轉成浮點數。
若陣列包含字串與數字,可能全部被轉成字串;若包含無法統一的 Python 物件,則可能變成 `object`,導致運算效率降低。
---
### 4. 型態轉換可能遺失資料
從浮點數轉整數會遺失小數;從較大的整數型態轉成較小型態可能溢位;從字串轉數字則可能因格式不正確而失敗。
```python
x.astype(np.int32)
```
使用 `astype()` 前應確認轉換是否安全。
---
### 5. `NaN` 與缺失值
`NaN` 通常屬於浮點數概念,因此整數陣列不能直接儲存一般的 `np.nan`:
```python
np.array([1, np.nan]) # 通常會推導為 float
```
若需要在整數資料中表示缺失值,可以考慮:
- 使用浮點數型態
- 使用遮罩陣列(masked array)
- 使用 pandas 的 nullable integer 型態
---
### 6. `float32` 與 `float64` 的取捨
- `float32`:佔用較少記憶體、速度可能較快,常用於大型模型或 GPU 計算
- `float64`:精度較高,適合科學計算與需要較高精確度的場合
應依資料規模與精度需求選擇,不必一律使用最大的型態。
---
### 7. 字串與 `object` 陣列的效率
NumPy 最擅長處理固定型態的數值陣列。若使用 `object` 儲存各種 Python 物件,許多運算會退回 Python 層級執行,速度與記憶體效率通常不如數值型態。
---
## 小結
使用 NumPy `ndarray` 時,除了關注陣列的形狀,也應注意 `dtype`:
- 數值資料常使用 `int32`、`int64`、`float32` 或 `float64`
- 條件判斷使用 `bool`
- 日期使用 `datetime64`
- 字串與混合資料可能使用 `str` 或 `object`
- 需要留意溢位、浮點誤差、型態轉換與缺失值問題
良好選擇資料型態,通常能兼顧正確性、記憶體使用量與運算效能。
相關學習地圖、教學課程
Python 資料工程