φυβλαςのβλογ
บล็อกของ phyblas



numpy & matplotlib เบื้องต้น บทที่ ๓: การคำนวณของอาเรย์
เขียนเมื่อ 2016/06/11 11:41
แก้ไขล่าสุด 2021/09/28 16:42
การคำนวณเป็นความสามารถโดดเด่นหลักๆของอาเรย์ ในบทนี้จะพูดถึงพื้นฐานการนำอาเรย์มาใช้ในการคำนวณต่างๆ



การคำนวณขั้นพื้นฐานของอาเรย์
อาเรย์สามารถนำมาคำนวณได้โดยตรง การนำอาเรย์มาบวกลบกันนั้นก็ทำได้เหมือนกับเป็นการบวกลบเมทริกซ์ คือบวกลบตัวต่อตัวให้โดยอัตโนมัติ

ขอยกตัวอย่างโดยใช้อาเรย์นี้
import numpy as np
ar1 = np.array([[1,1,2],[2,2,3],[3,3,4]])
ar2 = np.array([[4,4,4],[2,2,2],[1,1,1]])
print(ar1)
print(ar2)
ผลลัพธ์
[[1 1 2]
 [2 2 3]
 [3 3 4]]
[[4 4 4]
 [2 2 2]
 [1 1 1]]

นำอาเรย์สองตัวนี้มาคำนวณค่าบวกลบ
print(ar1+ar2)
print(ar1-ar2)

ผลลัพธ์
[[5 5 6]
 [4 4 5]
 [4 4 5]]
[[-3 -3 -2]
 [ 0  0  1]
 [ 2  2  3]]

นอกจากการบวกและลบแล้ว การนำเมทริกซ์สองตัวมาคำนวณกันคือการนำสมาชิกแต่ละตัวมาคำนวณกันเป็นคู่ๆเหมือนกันทุกตัว

ดังนั้นที่จริงแล้วอาเรย์มีสมบัติหลายอย่างที่ไม่เหมือนกับเมทริกซ์ เพราะการคูณหารเมทริกซ์จะไม่ใช่การนำสมาชิกมาคูณหารกันเป็นคู่ๆ

ลองดูตัวอย่าง การคูณ, หาร, ยกกำลัง และหารเอาเศษ จะเห็นว่าเป็นการคำนวณเป็นคู่ๆทีละตัว
print(ar1*ar2)
print(ar1/ar2)
print(ar1**ar2)
print(ar1%ar2)

ผลลัพธ์
[[4 4 8]
 [4 4 6]
 [3 3 4]]
[[ 0.25  0.25  0.5 ]
 [ 1.    1.    1.5 ]
 [ 3.    3.    4.  ]]
[[ 1  1 16]
 [ 4  4  9]
 [ 3  3  4]]
 [[1 1 2]
 [0 0 1]
 [0 0 0]]

***ในส่วนของการหารถ้าเป็นไพธอน 2 จะถูกปัดเศษเพื่อให้คงความเป็นจำนวนเต็ม จึงได้
[[0 0 0]
 [1 1 1]
 [3 3 4]]

และยังรวมถึงการหาค่าความจริงเท็จด้วย
ar3 = np.ones([3,3])
ar4 = np.identity(3)
print(ar3)
print(ar4)
print(ar3==ar4)
print(ar3>ar4)

ผลลัพธ์
[[ True False False]
 [False  True False]
 [False False  True]]
[[False  True  True]
 [ True False  True]
 [ True  True False]]

การคำนวณอาเรย์ในลักษณะนี้ได้ผลเหมือนกับการที่เราใช้วังวน for เพื่อเข้าถึงสมาชิกในแต่ละตัวและคำนวณไปเรื่อยๆทีละตัว เพียงแต่จะเห็นว่าเขียนง่ายกว่ามาก นอกจากนี้ยังทำงานเร็วกว่าด้วย

เช่นยกตัวอย่าง สร้างอาเรย์ที่มีเลข 1 อยู่สิบล้านตัว จากนั้นก็ใช้ for เพื่อเข้าถึงเลขแต่ละตัวเพื่อให้มันคำนวณบวกตัวเอง
a = np.ones(10000000)
for i in range(len(a)):
    a[i] = a[i]+a[i]

แบบนี้จะพบว่าต้องรอนานมากหลายวินาที (ขึ้นกับความเร็วเครื่อง) เพราะโปรแกรมต้องวนคำนวณซ้ำถึงสิบล้านครั้ง

แต่หากลองทำใหม่ให้ได้ผลลัพธ์แบบเดิมโดยใช้การคำนวณกับตัวอาเรย์โดยตรง
a = np.ones(10000000)
a = a+a

จะพบว่านอกจากจะเขียนสั้นกว่ามากแล้ว การคำนวณยังทำเสร็จภายในพริบตาเดียว แทบไม่ต้องรอเลย เพราะเบื้องหลังการทำงานนั้นการคำนวณทำอยู่บนภาษาซีซึ่งทำงานเร็วกว่าเป็น ร้อยเท้า

นี่ให้ข้อคิดที่สำคัญว่าในการจัดการกับข้อมูลภายในอาเรย์ นั้น แม้จะใช้ for เพื่อเข้าถึงสมาชิกแต่ละตัวได้เช่นเดียวกับลิสต์แต่ก็ไม่ควรทำ หากมีวิธีที่ไม่จำเป็นต้องใช้ for อยู่ละก็ควรใช้วิธีนั้นดีที่สุด

หากต้องการเห็นเวลาเปรียบเทียบเป็นตัวเลขชัดอาจลองใช้ฟังก์ชัน time วัดเวลา รายละเอียดลองอ่านดูใน https://phyblas.hinaboshi.com/20160610

ไม่ใช่แค่เรื่องการคำนวณเท่านั้น อาเรย์ยังมีคำสั่งอีกหลายตัวสำหรับจัดการกับสมาชิกในอาเรย์โดยไม่ต้องวนทำ ซ้ำเอง ซึ่งจะได้กล่าวถึงต่อไป



การคำนวณอาเรย์กับตัวเลขเดี่ยวหรืออาเรย์ที่จำนวนมิติไม่เท่ากัน
หากนำอาเรย์ไปคำนวณกับตัวเลขเดี่ยวจะเกิดการกระจายค่า โดยตัวเลขนั้นจะทำกับทุกตัวบนอาเรย์
print(ar3*4)
print(ar4-2)

ผลลัพธ์
[[ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]]
[[-1. -2. -2.]
 [-2. -1. -2.]
 [-2. -2. -1.]]

ถ้าขนาดของเมทริกซ์ไม่เท่ากันจะไม่สามารถนำมาคำนวณกันได้
np.ones([3,3])+np.ones([2,2]) # ได้ ValueError: operands could not be broadcast together with shapes (3,3) (2,2)

แต่กรณีที่จำนวนมิติต่างกันจะเกิดการกระจายค่าได้ถ้าหากตัวที่จำนวนมิติน้อยกว่ามีขนาดเท่ากับจำนวนของมิติหลังสุด

ตัวอย่างเช่นกรณีนี้อาเรย์ตัวหลังมีขนาด 3 และอาเรย์ตัวแรกมีขนาดของมิติหลังสุดเป็น 3 จึงกระจายได้
ar5 = np.ones([2,3])*3
ar6 = np.arange(3)
print(ar5)
print(ar6)
print(ar5*ar6)

ได้
[[ 3.  3.  3.]
 [ 3.  3.  3.]]
[0 1 2]
[[ 0.  3.  6.]
 [ 0.  3.  6.]]

กรณีสองกับสามมิติก็เช่นเดียวกัน เช่นแบบนี้สามารถกระจายได้
ar7 = np.ones([2,2,3])
ar8 = np.eye(2,3)



ฟังก์ชันคำนวณ
นอกจาก การคำนวณพื้นฐานแล้ว numpy ยังได้เตรียมฟังก์ชันสำหรับคำนวณที่ใกล้เคียงกับในมอดูล math เช่น abs, sqrt, log, log10, exp, sin, cos, tan, arcsin, arccos, arctan, sinh, cosh, tanh, arcsinh, arccosh, arctanh

ฟังก์ชันพวกนี้มีในมอดูล math หมด ข้อแตกต่างก็คือฟังก์ชันเหล่านี้ใน numpy เมื่อใช้กับอาเรย์จะเกิดการกระจายเพื่อคำนวณกับสมาชิกทุกตัว แต่ก็สามารถใช้กับตัวเลขเดี่ยวได้ด้วยและจะให้ผลไม่ต่างจากของมอดูล math
ari1 = np.arange(1,9)
print(ari1)
print(np.sin(ari1))
print(np.log(ari1))
print(np.exp(np.log(ari1)))
print(np.log(ari1)/np.log(2))

ผลลัพธ์
[1 2 3 4 5 6 7 8]
[ 0.84147098  0.90929743  0.14112001 -0.7568025  -0.95892427 -0.2794155
  0.6569866   0.98935825]
[ 0.          0.69314718  1.09861229  1.38629436  1.60943791  1.79175947
  1.94591015  2.07944154]
[ 1.  2.  3.  4.  5.  6.  7.  8.]
[ 0.          1.          1.5849625   2.          2.32192809  2.5849625
  2.80735492  3.        ]

log ในที่นี้คือฐาน e ไม่สามารถเลือกเลขฐานได้เหมือนอย่างในมอดูล math ต้องใช้วิธีการมาหารด้วย log ของฐานที่ต้องการอีกที

นอกจากนี้ยังมีฟังก์ชันสำหรับเปลี่ยนหน่วยที่ใช้ในตรีโกณมิติ คือ deg2rad หรือ radians สำหรับเปลี่ยนจากองศาเป็นเรเดียน และ rad2deg หรือ degrees สำหรับเปลี่ยนจากเรเดียนเป็นองศา
print(np.radians(180)) # ได้ 3.1415926535897931
print(np.degrees(1) == np.rad2deg(1)) # ได้ True

ที่เหลือส่วนใหญ่ก็เหมือนกับมอดูล math สามารถอ่านได้ในเนื้อหาภาษาไพธอนเบื้องต้นบทที่ ๑๖

ถ้าเราไม่ใช้ฟังก์ชันคำนวณของ numpy เราสามารถใช้ for วนซ้ำเพื่อทำการคำนวณได้ แต่จะเขียนยุ่งยากกว่าแถมยังทำงานช้ากว่ามากด้วย

ลองสร้างอาเรย์ขนาดใหญ่ๆแล้วเทียบกันดู

ใช้ np.sin จะเป็นแบบนี้
a = np.arange(10000000)
sina = np.sin(a)

ถ้าใช้ math.sin จะเป็นแบบนี้
import math
a = np.arange(10000000)
sina = np.empty(10000000)
for i in range(10000000):
    sina[i] = math.sin(a[i])

จะเห็นว่าเวลาที่ใช้นั้นต่างกันมาก



การคูณเมทริกซ์
เราสามารถนำอาเรย์มาคูณกันในลักษณะที่เหมือนเป็นการคูณเมทริกซ์ได้โดยใช้ฟังก์ชัน np.dot

ฟังก์ชันนี้จะใช้ได้ก็ต่อเมื่อจำนวนหลัก (แนวนอน) ของตัวซ้ายเท่ากับจำนวนแถว (แนวตั้ง) ของตัวขวาซึ่งก็เป็นกฎของการคูณเมทริกซ์ทั่วไป
a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[1,3,5],[2,4,6]])
print(a)
print(b)
print(np.dot(a,b))
print(np.dot(b,a))

ผลลัพธ์
[[1 2]
 [3 4]
 [5 6]]
[[1 3 5]
 [2 4 6]]
[[ 5 11 17]
 [11 25 39]
 [17 39 61]]
[[35 44]
 [44 56]]

เพียงแต่ว่ากรณีที่เป็นอาเรย์มิติเดียวทั้งคู่นั้นตัวหลังจะถูกทรานสโพสอัตโนมัติ ผลที่ได้จะเหมือนเป็นการด็อตกันของเว็กเตอร์ (เว็กเตอร์คืออาเรย์หนึงมิติ) คือเอาสมาชิกแต่ละตัวมาคูณกันเป็นคู่ๆแล้วบวกกันทั้งหมด
print(np.dot(np.array([1,2,3]),np.array([2,3,4]))) # ได้ 20



การครอสเว็กเตอร์
ฟังก์ชันสำหรับครอสเว็กเตอร์คือ np.cross มีไว้สำหรับนำอาเรย์แทนเว็กเตอร์สองตัวมาครอสกัน

ตัวอย่าง สร้างอาเรย์แทนเว็กเตอร์ขึ้นมาสองตัวแล้วครอสกัน
a = np.array([2,2,3])
b = np.array([3,3,1])
print(np.cross(a,b)) # ได้ [-7  7  0]

อาเรย์ที่จะครอสกันได้ต้องมีสมาชิก ๒ หรือ ๓ ตัว (แทนเว็กเตอร์สองหรือสามมิติ) เท่านั้น กรณี ๓ ตัวจะได้ผลออกมาเป็น ๓ ตัว แต่กรณี ๒ ตัว ผลที่ได้จะออกมาเป็นตัวเดียว
a = np.array([3,2])
b = np.array([3,3])
print(np.cross(a,b)) # ได้ 3

กรณีที่ใช้กับอาเรย์มากกว่าหนึ่งมิติจะเป็นการจับมาครอสกันเป็นคู่ๆ
a = np.array([[2,2,3],[2,3,3]])
b = np.array([[3,3,1],[2,0,3]])
print(np.cross(a,b))
c = np.array([[2,3],[2,3],[1,4]])
d = np.array([[3,1],[0,3],[2,4]])
print(np.cross(c,d))

ได้
[[-7  7  0]
 [ 9  0 -6]]
[-7  6 -4]



อ้างอิง


<< บทที่แล้ว     บทถัดไป >>
หน้าสารบัญ


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> numpy

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文