จากบทความตอนที่ 1 ได้ติดตั้งและใช้งาน ulab กันไปเล็กน้อยเพื่อให้เห็นภาพการใช้งาน ส่วนบทความนี้กล่าวถึงโมดูลย่อย array เพื่อใช้สร้างแถวลำดับ 1 มิติและ 2 มิติในรูปแบบที่หลากหลายมากขึ้น พร้อมตัวอย่างการใช้งาน โดยในตอนที่ 2 จะเพิ่มเติมเรื่องเครื่องหมายดำเนินการต่าง ๆ ที่ใช้กับแถวลำดับที่สร้างขึ้น
array
โมดูลย่อย array เป็นโมดูลสำหรับใช้สร้างโครงสร้างข้อมูลแถวลำดับทั้งแบบ 1 มิติ และ 2 มิติ โดยข้อมูลที่ถูกสร้างจาก ulab ล้วนอยู่ในรูปแบบของ ndarray หรือ array ซึ่งรูปแบบของการสร้างแถวลำดับ 1 มิติมีรูปแบบดังนี้
วัตถุ = ulab.array([สมาชิก1, สมาชิก2, …, สมาชิกn], dtype=ชนิดของสมาชิก)
การสร้างแถวลำดับ 2 มิติมีรูปแบบดังนี้
วัตถุ = ulab.array( [ [สมาชิกแถว1สดมภ์1, สมาชิกแถว1สดมภ์2, …, สมาชิกแถว1สดมภ์n], [สมาชิกแถว2สดมภ์1, สมาชิกแถว2สดมภ์2, …, สมาชิกแถว2สดมภ์n], … , [สมาชิกแถวmสดมภ์1, สมาชิกแถวmสดมภ์2, …, สมาชิกแถวmสดมภ์n] ], dtype=ชนิดของสมาชิก
ข้อมูลประเภท ndarray รองรับเครื่องหมายดำเนินการ ==, !=, <, <=, >, >=, +, -, /, *, **, +=, -=, *=, /=, **= และเครื่องหมายนำหน้าข้อมูลอย่าง – และ + เช่น -a หรือ +a เป็นต้น และรองรับฟังก์ชันต่าง ๆ ดังนี้
- len() สำหรับนับจำนวนสมาชิกภายใน ndarray
- abs( ) สำหรับค่าสัมบูรณ์ของข้อมูลใน ndarray
ฟังก์ชันของโมดูลย่อย array ที่สามารถเรียกใช้ได้ เป็นดังนี้
- วัตถุ.reshape((จำนวนแถว,จำนวนสดมภ์)) สำหรับแปลงการเรียงของข้อมูลในแถวลำดับของวัตถุใหม่ให้เป็นตามที่กำหนด
- วัตถุใหม่=วัตถุ.transpose() สำหรับทำการแปลงข้อมูลจากแถวให้กลายเป็นสดมภ์
- วัตถุใหม่=วัตถุ.flatten() สำหรับทำให้วัตถุกลายเป็นแถวลำดับ 1 มิติ
- (จำนวนแถว,จำนวนสดมภ์)=วัตถุ.shape() สำหรับรายงานจำนวนแถวและสดมภ์ของวัตถุประเภท array ในรูปแบบของ tuple
- จำนวนสมาชิกทั้งหมด=วัตถุ.size() สำหรับหาจำนวนสมาชิกทั้งหมดในวัตถุ
- ขนาดของสมาชิก=วัตถุ.itemsize() สำหรับหาขนาดของสมาชิกแต่ละตัวในวัตถุ
ตัวอย่าง 1
ตัวอย่างโปรแกรม code18-2 เป็นการสร้างวัตถุ a b และ c ให้เป็นประเภท array แบบ 1 มิติ หลังจากนั้นหาขนาดของ a ค่าสมบูรณ์ของ a นำ a คูณด้วย 3 หาร a ด้วย 2 และเปรียบเทียบระหว่าง a กับ b เปรียบเทียบระหว่าง a กับ c หาผลรวมระหว่าง a กับ b และหาผลต่างระหว่าง a กับ c ซึ่งได้ผลลัพธ์เป็นดังภาพที่ 1
# code18-2
import ulab as np
a = np.array([-1,0,1],dtype=np.float)
b = np.array([1,2,3])
c = np.array([-1,0,1],dtype=np.int8)
print("type of a is {}.".format(type(a)))
print("value of a is {}.".format(a))
print("len() of a is {}.".format(len(a)))
print("abs() of a is {}.".format(abs(a)))
print("value of a*3 is {}.".format(a*3))
print("value of a/2 is {}.".format(a/2))
print("value of b is {}.".format(b))
print("value of c is {}.".format(c))
print("a == [1,2,3] ? {}".format(a==b))
print("a == int([-1,0,1]) ? {}".format(a==c))
print("a+b = {}".format(a+b))
print("a-c = {}".format(a-c))
ตัวอย่าง 2
ตัวอย่าง code18-3 สร้างแแถวลำดับ a และ b ให้เป็น 1 มิติ และ 2 มิติ หลังจากนั้นรายงานขนาดของแถวลำดับ ขนาดของสมาชิก และทดลองเปลง a จากเดิมที่เป็นแถวลำดับ 1 มิติ 3 สมาชิก หรือ (1,3) ให้กลายเป็น (3,1) โดยผลลัพธ์เป็นดังภาพที่ 2
# code18-3
import ulab as np
a = np.array([1,2,3],dtype=np.int8)
b = np.array([[1,0,-1],[1,0,-1],[1,0,-1]],dtype=np.float)
print("data:\na={}\nb={}".format(a,b))
print("shape: a={} b={}".format(a.shape(),b.shape()))
print("size: a={} b={}".format(a.size(),b.size()))
print("item's size: a={} b={}".format(a.itemsize(),b.itemsize()))
a.reshape((3,1))
print("data:a={} shape={}".format(a,a.shape()))
ตัวอย่าง 3
ตัวอย่างโปรแกรม 18-4 เป็นการนำฟิลเตอร์ของ Prewitt มาสร้างเป็นแถวลำดับ 2 มิติชื่อ Gx หลังจากนั้นหา Gy ซึ่งเป็นทรานสโพสของ Gx และทดลองแปลง Gx และ Gy ให้กลายเป็นแถวลำดับ 1 มิติ โดยผลลัพธ์ของการทำงานเป็นดังภาพที่ 3
# code18-4
# Prewitt operator
import ulab as np
Gx = np.array([[1,0,-1],[1,0,-1],[1,0,-1]])
Gy = Gx.transpose()
print("Gx={}\nGy={}".format(Gx,Gy))
print("size: Gx={} Gy={}".format( Gx.size(), Gy.size()))
print("shape: Gx={} Gy={}".format( Gx.shape(), Gy.shape() ))
GxFlat = Gx.flatten()
GyFlat = Gy.flatten()
print("GxFlat={}\nGyFlat={}".format( GxFlat, GyFlat ))
print("size: GxFlat={} GyFlat={}".format( GxFlat.size(), GyFlat.size()))
print("shape: GxFlat={} GyFlat={}".format( GxFlat.shape(), GyFlat.shape()))
ตัวอย่าง 4
ตัวอย่างโปรแกรม code18-5 เป็นตัวอย่างการประยุกต์ใช้กับการคำนวณกราฟิก 2 มิติ คือ ทำการปรับขนาดของสี่เหลี่ยมที่อยู่พิกัด (p0,p1,p2,p3) ให้มีขนาดใหญ่ขึ้น 2 เท่า โดยนำพิกัดของจุดทั้ง 4 เป็น array และสร้างเมตริกซ์ของการขยายขนาดเป็นแถวลำดับ 2 มิติ และทำการคูณเมตริกซ์ p0กับM, p1กับM, p2กับM และ p3กับM (ในฟังก์ชัน matMul) จะได้ตัวอย่างผลลัพธ์ดังภาพที่ 4 และตัวอย่างการนำไปใช้กับการคำนวณขนาดของสี่เหลี่ยมพร้อมทั้งแสดงผลออกจอแสดงผลแอลซีดีกราฟิกในภาพที่ 5 และคลิปประกอบ
#code18-5
import ulab as np
p0 = np.array([-1,1,1],dtype=np.float)
p1 = np.array([1,1,1],dtype=np.float)
p2 = np.array([1,-1,1],dtype=np.float)
p3 = np.array([-1,-1,1],dtype=np.float)
def matMul(p,M):
x = p[0]*M[0][0]+p[0]*M[1][0]+p[0]*M[2][0]
y = p[1]*M[0][1]+p[1]*M[1][1]+p[1]*M[2][1]
z = p[2]*M[0][2]+p[2]*M[1][2]+p[2]*M[2][2]
return (x,y,z)
def scale(p0,p1,p2,p3,Sx=1.0,Sy=1.0):
Ms = np.array([[Sx,0.0,0.0],[0.0,Sy,0.0],[0.0,0.0,1.0]],dtype=np.float)
return (matMul(p0,Ms), matMul(p1,Ms), matMul(p2,Ms), matMul(p3,Ms))
print(scale(p0,p1,p2,p3,2.0,2.0))
ตัวอย่างที่ 5
ตัวอย่าง code18-6 เป็นตัวอย่างการแปลงข้อมูลจากแถวลำดับประเภท ulab.int16 เป็น ulab.float และแปลงจาก ulab.float เป็น ulab.int16 โดยตัวอย่างของผลลัพธ์เป็นดังภาพที่ 6
# code18-6
import ulab as np
a = np.array([1,2,3,4,5], dtype=np.int16)
b = np.array(a,dtype=np.float)
c = np.array(b,dtype=np.int16)
print("a is {}".format(a))
print("b is {}".format(b))
print("c is {}".format(c))
สรุป
จากบทความจะได้ว่า array เป็นโมดูลย่อยที่ทำให้ผู้ใช้สามารถสร้างแถวลำดับ 1 มิติ หรือ 2 มิติขึ้นมาใช้งาน พร้อมมีฟังก์ชันอำนวยความสะดวกในการรายงานจำนวนแถว/สดมภ์ ขนาดของข้อมูลทั้งหมด ขนาดของสมาชิกแต่ละตัว การทรานสโพส การปรับขนาดของแถวลำดับ การแปลงแถวลำดับหลายมิติให้เป็น 1 มิติ เป็นต้น
ในบทความครั้งหน้าจะเป็นเรื่องของโมดูลย่อย vector และสุดท้ายหวังว่าบทความคงมีประโยชน์บ้างไม่มากก็น้อย ขอให้สนุกกับการเขียนโปรแกรมครับ
(C) 2020, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2020-11-07
ปรับปรุงเมื่อ 2020-11-09
ปรับปรุงเมื่อ 2021-08-12