φυβλαςのβλογ
phyblas的博客



numpy & matplotlib เบื้องต้น บทที่ ๒๑: การเปรียบเทียบอาเรย์
เขียนเมื่อ 2016/06/12 01:02
แก้ไขล่าสุด 2021/09/28 16:42
อาเรย์เป็นออบเจ็กต์ที่ค่อนข้างพิเศษ สามารถทำการคำนวณและเปรียบเทียบระหว่างอาเรย์แต่ละตัวได้

เรื่องของการคำนวณระหว่างอาเรย์ได้พูดถึงไปในบทที่ ๓ แล้ว สำหรับบทนี้จะพูดถึงการเอาอาเรย์มาเปรียบเทียบกัน



การใช้ all และ any
โดยปกติแล้วเวลาที่เอาอาเรย์มาเปรียบเทียบกันด้วย=, <, >, <=, >= != แบบนี้จะเป็นการเปรียบเทียบระหว่างสมาชิกในอาเรย์แต่ละตัว แล้วก็คืนค่าเป็นเมทริกซ์ความจริงเท็จ
import numpy as np
a = np.array([[1,0,1],[1,0,1]])
b = np.array([[1,1,0],[0,0,1]])
print(a==b)

ได้
[[ True False False]
 [False  True  True]]

แต่บางทีเราอาจจะไม่ได้ต้องการผลแบบนี้ แต่ต้องการให้ได้ค่าความจริงเท็จตัวเดียวไปเลย แต่ว่าการทำแบบนั้นมีความคลุมเครืออยู่ เพราะโปรแกรมไม่รู้ว่าเราต้องการให้เป็นจริงเมื่อไหร่
 
ในกรณีแบบนี้ เราอาจใช้ฟังก์ชัน np.all และ np.any เพื่อระบุว่าถ้าผลการเปรียบเทียบสมาชิกแล้วเป็นจริงตัวเดียวก็ให้เป็นจริง เลยหรือเปล่า หรือว่าต้องเป็นจริงทังหมดจึงจะเป็นจริง

np.any จะคืนค่า True เมื่อมีสมาชิกแม้แต่ตัวเดียวเป็น True ส่วน np.all จะคืนค่า False เมื่อมีสมาชิกแม้แต่ตัวเดียวเป็น False
ar = np.array([1,1,0])
print(np.all(ar)) # ได้ False
print(ar.all()) # เขียนแบบนี้ก็ได้
print(np.any(ar)) # ได้ False

จึงนำมาใช้เวลาเปรียบเทียบอาเรย์ได้
 

a = np.array([[1,0,1],[1,0,1]])

b = np.array([[1,1,0],[0,0,1]])

print(np.any(a==b)) # ได้ True

print(np.all(a<=b)) # ได้ False

print(np.any(a>b)) # ได้ True




การเทียบว่าอาเรย์เท่ากันหรือเปล่า
ในบางครั้งอาเรย์ที่ไม่เหมือนกันพอมาเปรียบเทียบกันก็อาจพบว่าได้เท่ากันได้ เช่น
a = np.array([3,0,3])
b = np.array([3,0,3,3,0,3,3,0,3]).reshape(3,3)
print(a==b)
# ได้
# [[ True  True  True]
#  [ True  True  True]
#  [ True  True  True]]

print(a-b)
# ได้
# [[0 0 0]
#  [0 0 0]
#  [0 0 0]]

print(np.all(a==b)) # ได้ True

นั่นเพราะอาเรย์มีสมบัติการกระจาย ทำให้แม้ว่า a และ b จะไม่เหมือนกัน แต่พอเทียบกันแล้วก็พบว่าได้ True ทั้งหมด พอใช้ np.all ก็ยังจะได้ True ผลลัพธ์แบบนี้อาจไม่พึงประสงค์ในบางครั้ง ดังนั้นจะต้องหาทางอื่น

การจะเทียบให้เหมือนเป๊ะแบบตัวต่อตัวเลยจริงๆจะต้องใช้ฟังก์ชัน np.array_equal

np.array_equal จะเทียบว่าอาเรย์สองตัวเหมือนกันทั้งขนาดและสมาชิกข้างในหรือเปล่า
print(np.array_equal(a,b)) # ได้ False

และมีอีกฟังก์ชันที่คล้ายๆกัน แต่จริงๆแล้วให้ผลไม่ต่างจาก np.all(a==b) นั่นคือ np.array_equiv

np.array_equiv จะพิจารณาว่าอาเรย์สองตัวลบกันแล้วได้อาเรย์ที่มีแต่ 0 หรือเปล่า โดยพิจารณาถึงสมบัติการกระจายด้วย
print(np.array_equiv(a,b)) # ได้ True



การเปรียบเทียบจำนวนที่ใกล้เคียงกันมากๆ
ในบางครั้งการที่จะบอกว่าตัวเลขสองตัวนั้นเท่ากันนั้นก็ไม่ได้หมายความว่าจะต้องเท่ากันพอดีเป๊ะ โดยเฉพาะตัวเลขที่ได้มาจากการทดลองต่างๆย่อมมีความคลาดเคลื่อนอยู่ในตัว ดังนั้นแม้จะไม่เท่ากันพอดีเราก็อาจถือว่าเป็นค่าที่เท่ากัน

ในกรณีแบบนี้แทนที่จะใช้การเปรียบเทียบแบบธรรมดาอาจจะใช้ฟังก์ช้น np.isclose

np.isclose เป็นฟังก์ชันสำหรับตรวจสอบว่าค่าตัวเลขสองตัวนั้นใกล้กันมากพอหรือเปล่า ถ้าใกล้กันมากพอก็จะคืนค่า True

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

หากต้องการเปรียบเทียบแบบสัมพัทธ์ให้ใส่เป็นอาร์กิวเมนต์ตัวที่ ๓ ต่อจากค่าตัวเลข ๒ ตัว

ตัวอย่าง ลองเทียบ 100 กับ 101
print(np.isclose(100,101,0.01)) # ได้ True
print(np.isclose(100,101,0.001)) # ได้ False

ค่าสัมพัทธ์ที่ว่านี้คิดจากค่าตัวเลขตัวหลังไม่ใช่ตัวหน้า ดังนั้นการสลับตำแหน่งอาร์กิวเมนต์ ๒ ตัวหน้าจะให้ผลต่างกัน
print(np.isclose(100,99,0.01)) # ได้ False
print(np.isclose(99,100,0.01)) # ได้ True

ที่เป็นแบบนี้เนื่องจาก (100-99)/99 = 0.010101010101... ซึ่งมากกว่า 0.01 ดังนั้นจึงเป็นเท็จ
แต่ (100-99)/100 = 0.01 พอดิบพอดี ดังนั้นจึงเป็นจริง

กรณีที่ไม่ได้กำหนดค่าความต่างสัมพัทธ์จะเทียบเป็น 0.00001
print(np.isclose(99.999,100.000)) # ได้ True
print(np.isclose(99.99,100.00)) # ได้ False

หากต้องการเปรียบเทียบแบบสมบูรณ์ก็ใส่คีย์เวิร์ด atol
print(np.isclose(5.001,5,atol=0.0001)) # ได้ False
print(np.isclose(5.001,5,atol=0.001)) # ได้ True

ต่อให้เลขต่างกันกี่เท่า ถ้ากำหนดการเปรียบเทียบแบบสมบูรณ์ก็ยังได้ True อยู่ดี
print(np.isclose(0.00002,0.00001,atol=0.00001)) # ได้ True

ค่าตั้งต้นของ atol คือ 0.00000001 หรือ 10 ยกกำลัง -8 ดังนั้นต่อให้ ไม่กำหนด atol พอเปรียบเทียบค่าที่ต่ำกว่านั้นก็ได้ True อยู่ดี
print(np.isclose(0.00000002,0.00000001)) # ได้ False

กรณี ที่ใส่ทั้งค่าความต่างสัมบูรณ์และสัมพัทธ์ไปพร้อมกันจะใส่ค่าความต่าง สัมบูรณ์เป็นอาร์กิวเมนต์ตัวที่ ๔ โดยไม่ต้องเติม atol= ก็ได้ เพียงแต่การเปรียบเทียบจะให้ค่า True ทันทีที่เงื่อนไขอันใดอันหนึ่งเป็นจริง
print(np.isclose(0.002,0.001,0.01,0.001)) # ได้ True
print(np.isclose(0.002,0.001,0.01,0.0001)) # ได้ False
print(np.isclose(0.002,0.001,1,0.0001)) # ได้ True

เนื่องจากค่าตั้งต้นของ atol เป็น 0.00000001 ดังนั้นถ้าตัวเลขน้อยกว่านั้นไม่ว่าจะเปรียบเทียบยังไงก็จะได้ True ตลอดไม่ว่าจะใส่ค่าความต่างสัมพัทธ์ไว้สูงก็ตาม ดังนั้นทางแก้คือต้องใส่ 0 ต่อท้าย
print(np.isclose(0.000000002,0.000000001,0.0000001)) # ได้ True
print(np.isclose(0.000000002,0.000000001,0.0000001,0)) # ได้ False

หากใช้กับอาเรย์หรือลิสต์ก็จะทำการเปรียบเทียบสมาชิกแต่ละตัวแล้วคืนค่าอาเรย์ของค่าความจริงเท็จ
print(np.isclose([100,100,100],[100.1,101,110],0.01)) # ได้ [ True  True False]

นอกจากนี้ก็มีฟังก์ชัน np.allclose ซึ่งจะคืนค่า True ต่อเมื่อสมาชิกทั้งหมดใกล้กันมากพอ (ก็คือใช้ np.isclose แล้วได้ True ทุกตัว)
print(np.allclose([100,100,100],[100.1,101,110],0.01)) # ได้ False
print(np.allclose([100,100,100],[100.1,101,110],0.1)) # ได้ True



np.minimum และ np.maximum
บางครั้งเราอาจมี ๒ ฟังก์ชันที่ต้องการนำมาเปรียบเทียบกันแล้วคัดเอาค่าที่สูงกว่าหรือต่ำกว่า ระหว่าง ๒ ฟังก์ชันนั้น ในกรณีนี้อาจใช้ np.minimum และ np.maximum

np.minimum จะนำเอาอาเรย์ ๒ ตัวที่มีขนาดเท่ากันมาเทียบกันแล้วคืนอาเรย์ที่ประกอบไปด้วยค่าที่ต่ำกว่า

ตัวอย่าง ลองดูกราฟที่ได้จาก np.minimum ระหว่าง sin และ cos
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,15,101)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x,y1,':m')
plt.plot(x,y2,':c')
y = np.minimum(y1,y2)
plt.stem(x,y,markerfmt='-g')
plt.show()



ส่วน np.maximum นั้นก็เช่นเดียวกัน แต่จะคืนค่าสูงสุด

จากตัวอย่างบน ลองแก้แค่ ๓ บรรทัดล่าง
y = np.maximum(y1,y2)
plt.stem(x,y,markerfmt='-y')
plt.show()





อ้างอิง


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


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

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

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

หมวดหมู่

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

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

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



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

  查看日志

  推荐日志

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