6.9. ฟังก์ชันสากล (Universal Functions)¶
ฟังก์ชันสากล (ufunc) คือฟังก์ชันทางคณิตศาสตร์ที่ทำงานกับทุกสมาชิกของอาร์เรย์ในการเรียกครั้งเดียว ตัวดำเนินการเลขคณิตในหน้าก่อนหน้าคือฟังก์ชันสากลที่แสดงด้วยไวยากรณ์ตัวดำเนินการ หน้านี้คือรายการฟังก์ชันที่มีชื่อซึ่งครอบคลุมตรีโกณมิติ เลขชี้กำลัง/ลอการิทึม การปัดเศษ และอื่น ๆ
แต่ละ ufunc รับสเกลาร์ อิเทอเรเบิลของ Python หรือ ndarray และคืนค่า float เดี่ยว (เมื่ออินพุตเป็นสเกลาร์) หรือ ndarray ชนิด float:
from ulab import numpy as np
np.exp(2.0) # 7.389...
np.sin(range(4)) # 1-D float ndarray
np.sqrt([1, 4, 9, 16]) # array([1.0, 2.0, 3.0, 4.0])
a = np.arange(9).reshape((3, 3))
np.exp(a) # 3x3 float ndarray
6.9.1. รายการฟังก์ชัน¶
numpy เปิดเผยฟังก์ชันทางคณิตศาสตร์ที่แอปพลิเคชันแบบฝังตัวต้องการใช้บ่อยที่สุด:
ตรีโกณมิติ --
sin(),cos(),tan(),asin(),acos(),atan(),arctan2(),sinh(),cosh(),tanh(),asinh(),acosh(),atanh(),sinc().เลขชี้กำลังและลอการิทึม --
exp(),expm1(),log(),log10(),log2(),sqrt().
แต่ละฟังก์ชันประมวลผลอาร์เรย์ทั้งหมดในการเรียกไลบรารีครั้งเดียว ความเร็วที่เพิ่มขึ้นเมื่อเทียบกับ list comprehension ของ Python ที่เรียก math.sin() ทีละสมาชิกอยู่ที่ 10-30 เท่าสำหรับบัฟเฟอร์ทั่วไป
6.9.2. คีย์เวิร์ด out=¶
การเรียก ufunc แต่ละครั้งจะจัดสรรอาร์เรย์ผลลัพธ์ใหม่เพื่อเก็บเอาต์พุต ในลูปที่รันหลายครั้งต่อวินาที การจัดสรรเหล่านั้นสะสมและสิ้นเปลือง RAM การส่ง out= ซึ่งเป็นอาร์เรย์ float ที่มีอยู่แล้วและมีรูปร่างเหมือนอินพุต จะเขียนผลลัพธ์ลงในอาร์เรย์นั้นแทนที่จะจัดสรรใหม่:
x = np.linspace(0, 2 * np.pi, num=256)
y = np.zeros(256)
while True:
np.sin(x, out=y)
# use y ...
หาก out มี dtype หรือรูปร่างที่ไม่ถูกต้อง ฟังก์ชันจะเกิดข้อยกเว้น คีย์เวิร์ดนี้รองรับใน ufunc ทุกฟังก์ชันในหน้านี้ และเป็นวิธีที่สะอาดที่สุดในการทำให้ลูปประมวลผลสัญญาณแบบ streaming ไม่มีการจัดสรรหน่วยความจำ
6.9.3. ufunc ที่มีอาร์กิวเมนต์สอง¶
arctan2() เป็น ufunc ที่มีอาร์กิวเมนต์สองตัวที่แท้จริงเพียงรายการเดียวในรายการข้างต้น มันคืนค่าอาร์กแทนเจนต์ที่รับรู้ควอดแรนต์ของ y / x และบรอดแคสต์ตัวถูกดำเนินการสองตัว:
y = np.array([1, 2.2, 33.33, 444.444])
np.arctan2(y, 1.0) # against a scalar
np.arctan2(1.0, y) # the other way
np.arctan2(y, y) # against another array
6.9.4. การประกอบฟังก์ชันสากล¶
ฟังก์ชันสากลประกอบกันได้เหมือนนิพจน์อาร์เรย์อื่น ๆ รูปแบบบางอย่างที่พบบนกล้อง:
การแก้ไขแกมมา (ในพื้นที่ float)
gamma = 0.5
out = 255.0 * (frame / 255.0) ** gamma
ตัวปรับสัญญาณ low-pass แบบง่าย (alpha ที่ใกล้ 1.0 หมายถึงการอัปเดตช้า):
alpha = 0.95
filtered = alpha * filtered + (1.0 - alpha) * sample
Sigmoid
sigmoid = 1.0 / (1.0 + np.exp(-x))
สเปกตรัมกำลังในหน่วย dB
spectrum = 20.0 * np.log10(np.abs(real) + 1e-12)
6.9.5. np.vectorize¶
ฟังก์ชัน Python ปกติสามารถเลื่อนขั้นเป็นฟังก์ชันที่มีรูปร่างแบบ ufunc ได้ด้วย vectorize() ตัวที่เรียกได้ที่ได้จากการแปลงรับสเกลาร์ อิเทอเรเบิล หรือค่า ndarray
def f(x):
return x * x
vf = np.vectorize(f)
vf(44.0) # array([1936.0])
vf(np.array([1, 2, 3, 4])) # array([1.0, 4.0, 9.0, 16.0])
vf([2, 3, 4]) # array([4.0, 9.0, 16.0])
โดยค่าเริ่มต้น dtype ของผลลัพธ์เป็น float สามารถใช้ otypes= เพื่อแทนที่ได้:
vf_u8 = np.vectorize(f, otypes=np.uint8)
vf_u8([1, 2, 3, 4])
# array([1, 4, 9, 16], dtype=uint8)
ฟังก์ชัน Python ต้องรับอาร์กิวเมนต์เดี่ยวและคืนค่าตัวเลขเดี่ยว
vectorize() ส่วนใหญ่เป็นเพียง ไวยากรณ์ -- ฟังก์ชัน Python ที่ถูกห่อยังต้องรันหนึ่งครั้งต่อสมาชิก ดังนั้นต้นทุนตัวแปลภาษาต่อสมาชิกที่ ufunc จริงหลีกเลี่ยงได้กลับมา คาดว่าจะเร็วขึ้นประมาณ 30%-50% เหนือ list comprehension ไม่ใช่ 30 เท่าของฟังก์ชันสากลแท้จริง เครื่องมือที่เหมาะสมเมื่อฟังก์ชันหนึ่งต้องทำงานกับสเกลาร์ รายการ และ อาร์เรย์ภายใต้ชื่อเดียวกัน -- ไม่ใช่เมื่อความเร็วดิบคือเป้าหมาย
สำหรับลายเซ็นการเรียกแบบเต็มของทุกฟังก์ชันสากลที่ระบุไว้ข้างต้น โปรดดู numpy --- การดำเนินการอาร์เรย์ที่เข้ากันได้กับ numpy