φυβλαςのβλογ
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
モンゴル語
言語学
maya
確率論
日本での日記
中国での日記
-- 北京での日記
-- 香港での日記
-- 澳門での日記
台灣での日記
北欧での日記
他の国での日記
qiita
その他の記事

記事の類別



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

  記事を検索

  おすすめの記事

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

ไทย

日本語

中文