6.10. Broadcasting¶
เมื่อตัวดำเนินการไบนารีได้รับอาร์เรย์สองตัวที่มีรูปร่างไม่ตรงกัน numpy จะไม่ raise -- มัน broadcast Broadcasting คือชุดกฎเล็กๆ ที่ตัดสินว่ารูปร่างสองแบบเข้ากันได้หรือไม่ และถ้าได้ จะขยายตัวที่เล็กกว่าเสมือนจริงให้ตรงกับตัวที่ใหญ่กว่าอย่างไร
6.10.1. กฎ¶
เมื่อตัวดำเนินการสองตัวมีรูปร่าง A และ B numpy จะทำงานผ่านกัน 2 ขั้นตอน
จับคู่ rank หากตัวดำเนินการตัวหนึ่งมีแกนน้อยกว่าอีกตัว
numpyจะเพิ่มแกนขนาด 1 ไว้ด้านหน้าของรูปร่างเสมือนจริงจนทั้งสองรูปร่างมีจำนวนแกนเท่ากัน ตัวดำเนินการ 1 มิติที่มีรูปร่าง(3,)ที่จับคู่กับตัวดำเนินการ 2 มิติที่มีรูปร่าง(2, 3)จะกลายเป็น(1, 3)เทียบกับ(2, 3)ตรวจสอบแต่ละแกน เมื่อเดินผ่านรูปร่างที่มีความยาวเท่ากันตอนนี้ทีละแกน แต่ละคู่ขนาดต้องตรงตามหนึ่งในสองเงื่อนไข: ขนาดเท่ากัน หรือหนึ่งในนั้นเป็น 1 แกนขนาด 1 จะถูกขยายเสมือนจริงให้เท่ากับขนาดอีกด้าน คู่
(1, 3)เทียบกับ(2, 3)เข้ากันได้เพราะแกนแรกมี 1 (ขยายเป็น 2) และแกนที่สองตรงกัน (3 == 3) ผลลัพธ์มีรูปร่าง(2, 3)
หากคู่แกนใดไม่ตรงตามเงื่อนไขใด รูปร่างจะไม่เข้ากันและตัวดำเนินการจะ raise ValueError
6.10.2. ตัวอย่าง¶
สเกลาร์เทียบกับอาร์เรย์ใดก็ได้ สเกลาร์ทำตัวเหมือนรูปร่าง (1,) และขยายไปยังอะไรก็ได้:
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float)
a + 10 # (2, 3) + scalar -> (2, 3)
เวกเตอร์ 1 มิติข้ามเมทริกซ์ 2 มิติ กฎ 1 เพิ่มแกนขนาด 1 ด้านหน้าเพื่อให้ (3,) กลายเป็น (1, 3) จากนั้นกฎ 2 ขยายแถวนั้นลงแต่ละคอลัมน์ของ a
row = np.array([100, 200, 300], dtype=np.float)
a + row # (2, 3) + (3,) -> (2, 3)
อาร์เรย์ 1 มิติสองตัวที่มีความยาวเท่ากัน บวกแบบ element-wise -- ไม่ต้องใช้ broadcasting:
np.arange(4) + np.arange(4)
เวกเตอร์คอลัมน์เทียบกับเวกเตอร์แถว สร้างรูปร่าง "outer" 2 มิติ: (4, 1) จับคู่กับ (3,) กลายเป็น (4, 1) เทียบกับ (1, 3) หลังการเพิ่ม rank และกฎ 2 ขยายแต่ละตัวดำเนินการตามแกนขนาด 1 ของมัน:
x = np.array([1, 2, 3, 4]).reshape((4, 1)) # column
y = np.array([10, 20, 30]) # row
x + y # (4, 3) matrix
กฎรูปร่างเดิมใช้กับ ufunc ที่รับสองอาร์กิวเมนต์ใดๆ รวมถึง arctan2()
np.arctan2(y, 1.0)
np.arctan2(y, x)
6.10.3. สิ่งที่ broadcasting ไม่ จัดสรร¶
การขยายนั้นเสมือนจริง numpy เดินผ่านตัวดำเนินการทั้งสองพร้อมกัน โดยอ่านตัวที่เล็กกว่าซ้ำตามแกน broadcast แทนที่จะคัดลอก ข้อมูลของอาร์เรย์ที่สั้นกว่าไม่ถูกทำซ้ำในหน่วยความจำ
ขนาดของอาร์เรย์ ผลลัพธ์ คือสิ่งที่สำคัญสำหรับหน่วยความจำ a + row จัดสรรผลลัพธ์ตามรูปร่างของ a ไม่ใช่รูปร่างของ a บวกรูปร่างของ row เชน broadcasting ยาวยังสามารถสร้างค่ากลางขนาดใหญ่ได้
6.10.4. เมื่อ broadcasting ผิดพลาด¶
ความล้มเหลวแบบคลาสสิกคือรูปร่างสองแบบที่ไม่มีแกนขนาด 1 ให้ขยายและขนาดไม่ตรงกัน -- เช่น (3, 4) เทียบกับ (4, 3) กฎ 2 ไม่สามารถจับคู่ 3 กับ 4 ได้ ดังนั้น numpy จึง raise ValueError
ปัญหาที่ลึกซึ้งกว่าคือ broadcast ที่สำเร็จ แต่ไม่ใช่ตามที่แอปพลิเคชันตั้งใจ (5,) เทียบกับ (5, 1) คือกรณีต้นแบบ: การเพิ่ม rank เปลี่ยน (5,) เป็น (1, 5) ซึ่ง broadcast กับ (5, 1) ได้เมทริกซ์ (5, 5) -- การรวมกันแบบ outer ของเวกเตอร์ทั้งสอง ไม่ใช่ผลลัพธ์แบบ element-wise ความยาว 5 ที่แอปพลิเคชันอาจต้องการ เมื่อไม่แน่ใจ ให้พิมพ์ shape ของทั้งสองด้านและเดินผ่านกฎก่อนที่จะใช้ reshape() หรือ transpose()