เมทริกซ์แนวทแยงอีกทั้งเมทริกซ์สามเหลี่ยมเป็นเมทริกซ์รูปแบบหนึ่งที่มีคุณสมบัติพิเศษมักถูกใช้งานบ่อย
numpy จึงมีการเตรียมวิธีต่างๆในการสร้างอาเรย์ที่แทนเมทริกซ์แนวทแยงและเมทริกซ์สามเหลี่ยมไว้
ในบทที่ ๒ ได้พูดถึงฟังก์ชัน np.eye กับ np.identity ไปแล้ว นั่นก็เป็นอาเรย์แนวทแยงในรูปแบบหนึ่ง สำหรับในบทนี้จะพูดถึงฟังก์ชันอื่นๆที่เหลือ
อาเรย์แนวทแยงใดๆสามารถสร้างได้โดยใช้ np.diag โดยใส่ลิสต์ของสมาชิกแนวทแยงที่ต้องการลงไปเป็นอาร์กิวเมนต์
ตัวอย่าง
import numpy as np
print(np.diag([3,3,9]))
ได้
[[3 0 0]
[0 3 0]
[0 0 9]]
ค่าที่ใช้ใน np.diag จะเป็นอาเรย์ก็ได้ เช่นลองใช้ร่วมกับ np.arange ดูก็จะได้อาเรย์แนวทแยงที่มีค่าเรียงกันไป
print(np.diag(np.arange(4,8)))
ได้
[[4 0 0 0]
[0 5 0 0]
[0 0 6 0]
[0 0 0 7]]
นอกจาก นี้หากต้องการให้ค่าไม่ได้อยู่ที่แนวทแยงพอดีแต่อยู่ที่ตำแหน่งถัดๆไปก็ ทำได้โดยการใส่อาร์กิวเมนต์ตัวที่สองลงไปเพิ่มเป็นตำแหน่งที่ต้องการให้ เลื่อน โดยค่าบวกคือเลื่อนไปทางขวาบน ค่าลบคือซ้ายล่าง
ตัวอย่าง
print(np.diag(np.arange(4,8),1))
print(np.diag(np.arange(4,8),-2))
ได้
[[0 4 0 0 0]
[0 0 5 0 0]
[0 0 0 6 0]
[0 0 0 0 7]
[0 0 0 0 0]]
[[0 0 0 0 0 0]
[0 0 0 0 0 0]
[4 0 0 0 0 0]
[0 5 0 0 0 0]
[0 0 6 0 0 0]
[0 0 0 7 0 0]]
นอกจากนี้ก็มีฟังก์ชัน np.diagflat ซึ่งคล้ายกับ np.diag แต่อาเรย์หรืิอลิสต์ที่ใส่จะมีกี่มิติก็ได้ จะถูกยุบให้เหลือมิติเดียวโดยอัตโนมัติ
print(np.diagflat([[1,7], [4,6]]))
ได้
[[1 0 0 0]
[0 7 0 0]
[0 0 4 0]
[0 0 0 6]]
การดึงสมาชิกแนวทแยงจากอาเรย์สองมิติ ฟังก์ชัน np.diag นั้นนอกจากจะใช้สำหรับสร้างเมทรกซ์แนวทแยงแล้วยังมีอีกความสามารถหนึ่ง นั่นคือหากใช้กับอาเรย์สองมิติก็จะเป็นการนำเอาสมาชิกในแนวทแยงออกมาสร้าง เป็นอาเรย์ใหม่
ตัวอย่าง
x = np.arange(7,27).reshape(4,5)
print(x)
print(np.diag(x))
ได้
[[ 7 8 9 10 11]
[12 13 14 15 16]
[17 18 19 20 21]
[22 23 24 25 26]]
[ 7 13 19 25]
จะเห็นว่าฟังก์ชันนี้ใช้ได้แม้แต่กับอาเรย์ที่มีจำนวนแถวกับหลักไม่เท่ากัน
นอกจาก นี้หากระบุ อาร์กิวเมนต์ตัวที่สองต่อจากอาเรย์เป้าหมายก็จะเป็นการเอาแถวที่ไม่ใช่แนว ทแยงตรงแกนกลาง แต่เลื่อนตำแหน่งไป หากใส่ค่าเป็นบวกจะเลื่อนไปขวาบน หากลบก็จะเลื่อนไปซ้ายล่าง
ตัวอย่าง ใช้อาเรย์ x จากตัวอย่างที่แล้ว
print(np.diag(x,1)) # ได้ [ 8 14 20 26]
print(np.diag(x,2)) # ได้ [ 9 15 21]
print(np.diag(x,3)) # ได้ [10 16]
print(np.diag(x,-1)) # ได้ [12 18 24]
แต่ว่าอาเรย์ที่ได้มาจากตรงนี้จะเป็นอาเรย์มุมมองเท่านั้น ต่อให้เอาตัวแปรมารับค่าก็ไม่สามารถแก้ไขเปลี่ยนแปลงค่าอะไรในตัวแปรนั้นได้
x2 = np.diag(x,-1)
x2[0] = 999 # ได้ ValueError: assignment destination is read-only
หากต้องการสร้างอาเรย์ใหม่ที่แก้ค่าได้ก็ต้องใช้ copy
x2 = np.diag(x,-1).copy()
x2[0] = 999
print(x2) # ได้ [999 18 24]
การแก้ไขสมาชิกในแนวทแยง แม้ว่า np.diag จะดึงมุมมองในแนวทแยงของอาเรย์ออกมาได้แต่ว่าก็แค่เพื่อดูค่า เราไม่สามารถแก้ไขค่าอะไรในแนวทแยงของอาเรย์นั้นได้
หากต้องการเปลี่ยนแปลงแก้ไขค่าในแนวทแยงของอาเรย์ก็อาจทำได้โดยใช้ np.fill_diagonal
ตัวอย่าง
x = np.ones([5,4])
print(x)
np.fill_diagonal(x,[3,4,5,7])
print(x)
ได้
[[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]
[[ 3. 1. 1. 1.]
[ 1. 4. 1. 1.]
[ 1. 1. 5. 1.]
[ 1. 1. 1. 7.]
[ 1. 1. 1. 1.]]
ถ้าใส่เป็นตัวเลขตัวเดียวก็จะเป็นการใส่แทนด้วยตัวเลขนั้นทั้งหมด
np.fill_diagonal(x,0)
print(x)
ได้
[[ 0. 1. 1. 1.]
[ 1. 0. 1. 1.]
[ 1. 1. 0. 1.]
[ 1. 1. 1. 0.]
[ 1. 1. 1. 1.]]
การดึงสมาชิกแนวทแยงจากอาเรย์สามมิติ มีอีกฟังก์ชันที่ใช้ดึงสมาชิกแนวทแยงของอาเรย์สองมิติออกมาได้เช่นเดียวกัน คือ np.diagonal หากใช้กับอาเรย์สองมิติจะให้ผลเหมือนกับ np.diag
อย่างไรก็ตาม np.diagonal สามารถใช้กับอาเรย์สามมิติขึ้นไปได้ด้วย ในขณะที่ np.diag ใช้กับอาเรย์หนึ่งหรือสองมิติเท่านั้น
ตัวอย่างการใช้
x = np.arange(3*3*4).reshape(3,3,4)
print(np.diagonal(x))
ได้
[[ 0 16 32]
[ 1 17 33]
[ 2 18 34]
[ 3 19 35]]
จะเห็นว่า np.diagonal จะทำการหาเมทริกซ์แนวทแยงโดยคิดตามด้านสูงและด้านลึก แต่แยกแต่ละหลักในแนวซ้ายขวาคิดต่างหากกัน
หาก ต้องการให้เปลี่ยนแนวในการคิดก็ทำได้โดยการใส่คีย์เวิร์ด axis1 กับ axis2 ลงไป เป็นเลขของแกนที่ต้องการ ค่าตั้งต้นคือ axis1=0 และ axis1=2
ลองสลับแกนอื่นนอกจากค่าตั้งต้นดูก็จะได้ผลที่ต่างออกไป
print(np.diagonal(x,axis1=0,axis2=2))
print(np.diagonal(x,axis1=1,axis2=2))
ได้
[[ 0 13 26]
[ 4 17 30]
[ 8 21 34]]
[[ 0 5 10]
[12 17 22]
[24 29 34]]
การหาผลรวมตลอดแนวทแยง ในการหาผลรวมตลอดแนวทแยงนั้นสามารถทำได้ โดยใช้ np.trace
กรณีใช้กับสองมิติจะเป็นการบวกสมาชิกทั้งหมดที่มีเลขแถวและหลักเท่ากัน เช่น
x = np.arange(12,24).reshape(3,4)
print(x)
print(np.trace(x))
ได้
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]
51
ถ้าหากต้องการผลรวมของสมาชิกที่ไม่ใช่แนวแกนกลางพอดีแต่เลื่อนออกไปก็ทำได้โดย ใส่อาร์กิวเมนต์ตัวที่สอง เช่นเดียวกับ diag หรือ diagonal
print(np.trace(x,1)) # ได้ 54
print(np.trace(x,-2)) # ได้ 20
กรณี ที่ใช้กับสามมิติจะคิดแยกทีละคู่แกน ลักษณะเดียวกับ np.diagonal อาจถือว่า np.trace(x) มีค่าเท่ากับ np.sum(np.diagonal(x),axis=1)
x = np.arange(21,48).reshape(3,3,3)
print(np.trace(x))
ได้
[ 99 102 105]
การสร้างอาเรย์สามเหลี่ยม เมทริกซ์สามเหลี่ยมคืออาเรย์ที่มีสมาชิกที่มีค่าไม่ใช่ 0 อยู่แค่ไม่เกินไปจากแนวทแยง ที่เหลือเป็น 0
เมทริกซ์สามเหลี่ยมมีสองแบบคือสามเหลี่ยมบนและสามเหลี่ยมล่าง
เราสามารถสร้างอาเรย์แทนเมทริกซ์สามเหลี่ยมบนได้จากฟังก์ชัน np.triu โดยใช้อาเรย์ที่มีอยู่เดิมมาตัดสมาชิกส่วนที่อยู่แถวล่างออกให้เป็น 0
และอาเรย์แทนเมทริกซืสามเหลี่ยมล่างก็สามารถสร้างได้ในทำนองเดียวกันโดยใช้ ฟังก์ชัน np.tril แต่ต่างกันตรงที่ np.tril จะทำให้ด้านบนเป็น 0 แทน
ตัวอย่าง
x = np.arange(10,19).reshape(3,3)
print(x)
print(np.triu(x))
print(np.tril(x))
ได้
[[10 11 12]
[13 14 15]
[16 17 18]]
[[10 11 12]
[ 0 14 15]
[ 0 0 18]]
[[10 0 0]
[13 14 0]
[16 17 18]]
หากใส่อาร์กิวเมนต์ตัวที่สองจะเป็นการเลื่อนแถวที่พิจารณาเป็นขอบเขต
print(np.triu(x,1))
print(np.tril(x,1))
ได้
[[ 0 11 12]
[ 0 0 15]
[ 0 0 0]]
[[10 11 0]
[13 14 15]
[16 17 18]]
นอกจากนี้ยังมีฟังก์ชัน tri สำหรับสร้างอาเรย์สามเหลี่ยมล่างที่มีสมาชิกเป็น 1 ล้วนขึ้นมาใหม่
ถ้าใส่อาร์กิวเมนต์ไปตัวเดียวจะได้อาเรย์สามเหลี่ยมล่างที่มีจำนวนแถวและหลักตามค่านั้น
x = np.tri(3)
print(x)
ได้
[[ 1. 0. 0.]
[ 1. 1. 0.]
[ 1. 1. 1.]]
แต่ถ้าใส่สองตัวก็จะได้จำนวนแถวตามเลขแรกและจำนวนหลักตามเลขหลัง
x = np.tri(3,4)
print(x)
ได้
[[ 1. 0. 0. 0.]
[ 1. 1. 0. 0.]
[ 1. 1. 1. 0.]]
หากใส่อาร์กิวเมนต์ตัวที่สาม จะเป็นการเลื่อนแถวที่พิจารณาเป็นขอบเขต
x = np.tri(3,4,-1)
print(x)
ได้
[[ 0. 0. 0. 0.]
[ 1. 0. 0. 0.]
[ 1. 1. 0. 0.]]
อ้างอิง