φυβλαςのβλογ
บล็อกของ 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
ภาษา 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月

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

ไทย

日本語

中文