Module 12a

N-dimensional Array using NumPy (I)

วันนี้เราจะเรียนรู้ 🔢

  1. NumPy คืออะไร และประสิทธิภาพ
  2. การสร้าง NumPy array
  3. การประมวลผลทางคณิตศาสตร์กับ array (element-wise, broadcasting, สถิติ)
import numpy as np

x = np.arange(1, 11, 0.5)
y = x**2 + 2*x + 1
print(y)
[  4.     6.25   9.    12.25 ...
 121.   132.25]

Note

Live Code ในโมดูลนี้ใช้ NumPy จริงใน browser (Pyodide) — กด Run เพื่อดูผลลัพธ์ · โมดูลนี้แบ่งเป็น 2 ตอน ตอนต่อไป → Module 12b — เข้าถึงข้อมูล & Matrix

NumPy คืออะไร? 📦

ไลบรารีสำหรับ array หลายมิติ และการคำนวณเชิงตัวเลข

NumPy คืออะไร

  • ไลบรารี(แพ็กเกจ)สำหรับประมวลผลข้อมูลในรูปแบบ array หลายมิติ ใน Python
  • เป็นแพ็กเกจพื้นฐานสำหรับงานวิทยาการข้อมูล (Data science)
  • นิยมใช้ประมวลผล Matrix และการคำนวณด้านคณิตศาสตร์
  • Data type พื้นฐานเรียกว่า NumPy array

จุดเด่นของ NumPy

  • Speed — เร็วกว่าการใช้ Python List มาก
  • Fewer loops — ลดการใช้ Loop
  • Clearer code — โค้ดใกล้เคียงกับคณิตศาสตร์
  • Better quality — พัฒนาโดยผู้เชี่ยวชาญจำนวนมาก

การ import และตรวจสอบ version

ก่อนใช้งานต้อง import โมดูล (นิยมตั้งชื่อเล่นว่า np)

import numpy as np

ตรวจสอบ version ที่ติดตั้งได้ด้วย

print(np.__version__)
1.26.4

Warning

โค้ดที่พัฒนาด้วยแพ็กเกจ (Matplotlib, NumPy, …) version เก่า อาจเกิดข้อผิดพลาดหากนำไปรันในระบบที่ใช้ version ใหม่กว่า เพราะบางฟังก์ชันอาจถูกตัดออกไปใน version ใหม่

โจทย์ #1.1

สร้างตัวแปร data1 เป็น list ที่เก็บตัวเลขตั้งแต่ 1 ถึง 10,000 โดยใช้ list comprehension

data1 = [i for i in range(1, 10000+1, 1)]
print(data1)
[1, 2, 3, ..., 9998, 9999, 10000]

โจทย์ #1.2

สร้างตัวแปร data2 ที่เก็บตัวเลข 1 ถึง 10,000 แบบเดียวกัน แต่คราวนี้ใช้ NumPy (np.arange())

import numpy as np

data2 = np.arange(1, 10001, 1)
print(data2)
[    1     2     3 ...  9998  9999 10000]

ประสิทธิภาพของ NumPy

เปรียบเทียบการบวก 1 ให้ทุก item ของ [0,1,...,9999] ด้วย List comprehension กับ NumPy (รัน 5 ครั้ง ครั้งละ 1000 รอบ)

# ใช้ List comprehension
%timeit -r5 -n1000 [i+1 for i in range(10_000)]

# ใช้ NumPy
%timeit -r5 -n1000 np.arange(10_000) + 1

Tip

NumPy เร็วกว่ามาก เพราะกระจายการคำนวณเข้าไปในทุก item โดยไม่ต้องใช้ loop ของ Python

การสร้าง NumPy array 🧱

np.array() · np.zeros() · np.ones() · np.identity() · np.arange()

การสร้าง array ด้วย np.array()

ใช้ np.array() สร้าง NumPy array จาก List (List ที่ส่งให้อาจมีมากกว่า 1 มิติ)

np_array_variable = np.array(...)
array 1 มิติ (1D) 1 2 3 4 5 6 shape = (6,) → 6 สมาชิก เรียงแถวเดียว array 2 มิติ (2D) ← 3 คอลัมน์ → 1 2 3 11 22 33 10 20 30 ↑ 3 แถว ↓ shape = (3, 3) → 3 แถว × 3 คอลัมน์ array 3 มิติ (3D) — เอา 2D มาวางซ้อนกันหลายชั้น 123 456 789 ชั้น 1 ชั้น 0 shape = (2, 3, 3) → 2 ชั้น (depth) × 3 แถว × 3 คอลัมน์

Note

ทบทวน: 2D list (Module 10)

โจทย์ #2

สร้างตัวแปร x1, x2, x3

  • x1 — array 1 มิติ [1 2 3 4 5 6] (สร้างด้วย numpy array)
  • x2 — array 2 มิติ [[1,2,3],[11,22,33],[10,20,30]] (numpy array)
  • x3 — array 2 มิติ เดียวกัน แต่สร้างด้วย 2D list
x1 = np.array([1,2,3,4,5,6])
x2 = np.array([[1,2,3],[11,22,33],[10,20,30]])
print(x2)

x3 = [[1,2,3],[11,22,33],[10,20,30]]
print(x3)
[[ 1  2  3]
 [11 22 33]
 [10 20 30]]
[[1, 2, 3], [11, 22, 33], [10, 20, 30]]

โจทย์ #3

แสดงผล array x1, x2 และ 2D list x3

print(f'x1 1D-Array: \n{x1}')
print(f'x2 2D-Array: \n{x2}')
print(f'x3 2D List: \n{x3}')
x1 1D-Array:
[1 2 3 4 5 6]
x2 2D-Array:
[[ 1  2  3]
 [11 22 33]
 [10 20 30]]
x3 2D List:
[[1, 2, 3], [11, 22, 33], [10, 20, 30]]

Tip

การ print() array จะจัดรูปแบบ ไม่มี comma และขึ้นบรรทัดใหม่ในแต่ละ row → อ่านง่ายกว่า List

ตรวจสอบขนาดด้วย .shape

property .shape บอกขนาดในแต่ละมิติ (ผลลัพธ์เป็น Tuple)

# NumPy ".shape" property
print(f"x1.shape: {x1.shape}")  # 1D
print(f"x2.shape: {x2.shape}")  # 2D
x1.shape: (6,)
x2.shape: (3, 3)
# Python List ไม่มี .shape
rows = len(x3)     # มิติแรก
cols = len(x3[0])  # มิติที่ 2
print(rows, cols)
3 3

Note

ทบทวน: Tuple (Module 4)

⚠️ function vs property

function — ต้องมี () ต่อท้าย

  • .upper() ของ String
  • .append() ของ List
  • .array() ของ NumPy

ใช้ ส่งข้อมูลให้ฟังก์ชันทำงาน

propertyไม่มี ()

  • .shape ของ NumPy array
  • .dtype ของ NumPy array

บอกสถานะปัจจุบันของข้อมูล

1D array vs 2D array (1×5)

สังเกตความต่างระหว่าง 1D array 5 item กับ 2D array ขนาด 1×5

a1 = np.array([4,2,1,3,2])    # 1D array
a2 = np.array([[4,2,1,3,2]])  # 2D array
print('x1.shape =', a1.shape)
print('x2.shape =', a2.shape)
x1.shape = (5,)
x2.shape = (1, 5)

Data type ของข้อมูลใน array

ทุก item ใน array เดียวกัน ต้องเป็นชนิดเดียวกัน (ต่างจาก List) — ถ้าสร้างจากข้อมูลต่างชนิด NumPy จะแปลงให้เป็นชนิดเดียวกันอัตโนมัติ

a = np.array([1,2])          # int
b = np.array([1,2.0])        # float
c = np.array(['apple',20])   # string

print(f"{a} data type: {a.dtype}")
print(f"{b} data type: {b.dtype}")
print(f"{c} data type: {c.dtype}")
[1 2] data type: int64
[1. 2.] data type: float64
['apple' '20'] data type: <U21

np.zeros() และ np.ones()

สร้าง array ที่มีสมาชิกเป็น 0 หรือ 1 ทั้งหมด — ส่ง shape เป็น Tuple

  • (15,) — 1D 15 item · (2,4) — 2D 2×4 · (3,3,3) — 3D 3×3×3

โจทย์ #4

สร้าง array ต่อไปนี้ แล้วแสดงค่า

  1. a — 1D array 10 ตัว เป็น 0 ทั้งหมด
  2. b — 2D array ขนาด 5x2 เป็น 1 ทั้งหมด
  3. c — 2D array ขนาด 2x5 เป็น 0 ทั้งหมด
  4. d — 3D array ขนาด 2x3x4 เป็น 1 ทั้งหมด

โจทย์ #4 (ต่อ)

a = np.zeros((10,))
b = np.ones((5,2))
c = np.zeros((2,5))
d = np.ones((2,3,4))
print(f'a={a}'); print(f'b={b}')
print(f'c={c}'); print(f'd={d}')
a=[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
b=[[1. 1.]
 [1. 1.]
 [1. 1.]
 [1. 1.]
 [1. 1.]]
c=[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]
d=[[[1. 1. 1. 1.] ... ]]  (2×3×4)

โจทย์ #5

สร้าง identity matrix ขนาด 5x5 ด้วย np.identity()

g = np.identity(5)
print(f'g={g}')
g=[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]

np.arange() กับข้อมูลทศนิยม

range() สร้างได้เฉพาะ จำนวนเต็ม — step เป็น float จะ error

x = range(1, 11, 0.5)   # error!
TypeError: 'float' object cannot be interpreted as an integer

np.arange(start, stop, step) สร้างรายการเลข ทศนิยม ได้ (ผลลัพธ์เป็น NumPy array)

โจทย์ #6

สร้างข้อมูล x ตั้งแต่ 1 ถึง 10.5 เพิ่มทีละ 0.5 และ y = x^2 + 2x + 1

x = np.arange(1, 11, 0.5)
y = x**2 + 2*x + 1
print(f'x={x}')
print(f'y={y}')
x=[ 1.   1.5  2.  ... 10.  10.5]
y=[  4.     6.25   9.   ... 121.   132.25]

การประมวลผลทางคณิตศาสตร์ ➗

NumPy กระจายการคำนวณเข้าไปในทุก item ของ array

number กับ array

นำ array ไปคำนวณกับ ตัวเลขเดี่ยว (int/float) ด้วย operator ทางคณิตศาสตร์ → กระจายการคำนวณเข้าไปยังทุก item

โจทย์ #7

หา y = x^10 และ z = 3x^2 เมื่อ x อยู่ในช่วง 1 ถึง 10 เพิ่มทีละ 0.5 แล้วแสดง x, y, z

x = np.arange(1, 10.5, 0.5)
y = x**10
z = 3 * (x**2)
print(f'x={x}'); print(f'y={y}'); print(f'z={z}')
(19,)
x=[ 1.   1.5 ...  9.5 10. ]
y=[1.00e+00 5.77e+01 ... 1.00e+10]
z=[  3.     6.75 ... 270.75 300.  ]

Note

array กับ array (ขนาดเท่ากัน)

ใช้ operator กับ array ที่มี shape เหมือนกัน → คำนวณ item ตำแหน่งเดียวกัน (element-wise)

x1 = np.array([1,2,3,4])
x2 = np.array([5,4,3,2])
print(x1 + x2)
print(x1 - x2)
print(x1 * x2)
print(x1 / x2)
print(x1 // x2)
print(x1 % x2)
print(x1 ** x2)
[6 6 6 6]
[-4 -2  0  2]
[5 8 9 8]
[0.2 0.5 1.  2. ]
[0 0 1 2]
[1 2 0 0]
[ 1 16 27 16]

array กับ array (2 มิติ)

ทำงานแบบ element-wise เช่นกันสำหรับ array 2 มิติ

x1 = np.array([[1,2,3],[4,1,0]])
x2 = np.array([[5,4,3],[2,2,1]])

print(x1 + x2)
print(x1 * x2)
print(x1 ** x2)
[[6 6 6]
 [6 3 1]]
[[5 8 9]
 [8 2 0]]
[[ 1 16 27]
 [16  1  0]]

Warning

item-wise: * คือการคูณ item ตำแหน่งเดียวกัน — ไม่ใช่ การคูณเมตริกซ์ (matrix multiplication)

Broadcasting

เมื่อ array มี shape ไม่เท่ากัน NumPy จะกระจายการคำนวณได้ก็ต่อเมื่อ shape สอดคล้องกับกฎ broadcasting

123456 + 10 = 111213141516 10 ถูก broadcast (กระจาย) ไปบวกกับ ทุก item ของ array

Broadcasting — ตัวอย่าง

array (2, 3) 123456 + แถว (3,) 102030 ↓ กระจายลงทุกแถว ↓ = 112233142536 แถว (3,) ถูก broadcast ลงให้ครบทั้ง 2 แถว → เข้ากับ shape (2, 3)

Broadcasting — กรณีที่ทำไม่ได้

# shape (3,2) กับ (2,3) → error
x1 = np.array([[1,2],[3,4],[5,6]])
x2 = np.array([[1,2,3],[4,5,6]])
print(x1 - x2)
ValueError: operands could not be
broadcast together with
shapes (3,2) (2,3)
123456 (3, 2) 123456 (2, 3) มิติไม่สอดคล้อง → ValueError

ฟังก์ชันทางคณิตศาสตร์ของ NumPy

math โมดูลไม่รองรับ List/array ต้องใช้ loop/list comprehension ซึ่งไม่ค่อยมีประสิทธิภาพ

import math
x = [1, np.e, np.e**2]
print(math.log(x))     # error!
TypeError: must be real
number, not list
# ต้องวนทีละ item
y = [math.log(item) for item in x]
print(y)
[0.0, 1.0, 2.0]

ฟังก์ชันคณิตศาสตร์กับ array

NumPy มีฟังก์ชันคณิตศาสตร์ที่กระจายการคำนวณเข้าไปในทุก item เช่น np.cos(), np.log(), np.sqrt(), np.sin() และค่าคงที่ np.pi, np.e

a = np.array([1, np.e, np.e**2])
print(np.log(a))

b = np.array([0, np.pi/2, np.pi*3/4])
print(np.sin(b))
[0. 1. 2.]
[0.  1.  0.70710678]

Note

ทบทวน: math module (Module 3)

ฟังก์ชันทางสถิติของ NumPy

np.sum() np.mean() np.max() np.min() np.var() np.std() — ถ้า ไม่กำหนด axis จะยุบ ทั้ง array เหลือ ค่าเดียว

15310129 รวมทุก 8 ช่อง 22 ค่าเดียว

np.sum(x) = 1+5+3+1+0+1+2+9 = 22

ฟังก์ชันทางสถิติของ NumPy

np.sum() np.mean() np.max() np.min() np.var() np.std() — array 2 มิติกำหนดทิศได้ด้วย axis

axis=0ยุบแถวเหลือผลแต่ละ column

15310129 1 6 5 10 รวมแต่ละ column → 4 ค่า sum(x, axis=0) = [1, 6, 5, 10]

axis=1ยุบ column เหลือผลแต่ละ row

15310129 10 12 รวมแต่ละ row → 2 ค่า sum(x, axis=1) = [10, 12]

โจทย์ #8

หาค่าทางสถิติของ x = [[1,5,3,1],[0,1,2,9]]

  1. ผลรวมทั้งหมด · (2) ผลรวมแต่ละ column · (3) ผลรวมแต่ละ row
x = np.array([[1,5,3,1],[0,1,2,9]])
print(f'Total Sum={np.sum(x)}')
print(f'Column Sum={np.sum(x, axis=0)}')
print(f'Row Sum={np.sum(x, axis=1)}')
Total Sum=22
Column Sum=[ 1  6  5 10]
Row Sum=[10 12]

Summary 🎯

สรุป Module 12a 🎉

NumPy array

  • import numpy as np · np.array()
  • สร้าง: np.arange() np.zeros() np.ones() np.identity()
  • property: .shape .dtype · ทุก item ชนิดเดียวกัน
  • function มี () · property ไม่มี ()

การคำนวณ

  • number ⊕ array · array ⊕ array (element-wise)
  • broadcasting เมื่อ shape ไม่เท่ากัน
  • ฟังก์ชัน: np.log() np.sin() np.sqrt()
  • สถิติ: np.sum/mean/max/min + axis

Tip

ไปต่อ Part II → Module 12b: index/slice, เงื่อนไข, View/Copy, Matrix