NumPy 通用函式(ufunc):高效能陣列運算的利器

小万哥丶發表於2024-06-05

NumPy 通用函式(ufunc)

簡介

NumPy 通用函式(ufunc),代表“通用函式”,是一類用於對 ndarray 物件進行逐元素運算的高效能函式。ufunc 使 NumPy 能夠在底層高效地利用 C 語言實現向量化操作,從而顯著提高計算速度。

優勢

ufunc 的主要優勢體現在以下幾個方面:

向量化操作: ufunc 可以對整個陣列進行逐元素運算,避免了使用迴圈語句遍歷每個元素的低效率操作。
廣播機制: ufunc 支援廣播機制,能夠自動將不同形狀的陣列廣播為相同形狀,方便進行運算。
多種函式型別: ufunc 包含了豐富的數學運算、邏輯運算和比較運算等,涵蓋了常見的資料處理需求。
靈活擴充套件: ufunc 支援自定義函式,可以根據需求建立新的 ufunc 來滿足特定場景的運算需求。

基本概念

向量化: 將原本需要使用迴圈語句逐個處理元素的操作,改為對整個陣列進行操作,稱為向量化。
廣播: 在 NumPy 中,運算子可以對不同形狀的陣列進行運算,規則是將陣列廣播為相同的形狀,具體規則由陣列的維度和 shape 屬性決定。

示例

加法運算

使用迴圈:

import numpy as np

x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])

z = []
for i, j in zip(x, y):
    z.append(i + j)

print(z)

使用 ufunc:

import numpy as np

x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])

z = np.add(x, y)
print(z)

解釋:

  • 在第一個示例中,使用 zip() 函式將 xy 陣列中的元素一一對應,並使用 append() 函式將計算結果儲存在 z 列表中。
  • 在第二個示例中,直接使用 np.add() 函式對 xy 陣列進行加法運算,並將結果儲存在 z 陣列中。

ufunc 的優勢在於,它可以避免使用迴圈語句,直接對整個陣列進行操作,效率更高。

建立自定義 ufunc

NumPy 允許使用者建立自定義的 ufunc,以滿足特定場景的運算需求。

步驟如下:

  1. 定義要封裝的運算函式:
    • 函式應接收任意數量的 ndarray 陣列作為輸入引數。
    • 函式應返回一個或多個 ndarray 陣列作為輸出結果。
  2. 使用 frompyfunc() 函式將自定義函式轉換為 ufunc:
    • frompyfunc() 函式接收以下引數:
      • function: 要轉換的自定義函式。
      • inputs: 輸入引數的數量。
      • outputs: 輸出結果的數量。
      • dtype: 可選引數,指定輸出陣列的資料型別。

示例:建立自定義加法函式 myadd

import numpy as np

def myadd(x, y):
    return x + y

myadd = np.frompyfunc(myadd, 2, 1)

print(myadd([1, 2, 3, 4], [5, 6, 7, 8]))

解釋:

  • myadd 函式定義了自定義的加法運算邏輯。
  • np.frompyfunc()myadd 函式轉換為 ufunc,並指定其輸入引數為 2 個,輸出結果為 1 個。
  • 最後,呼叫 myadd ufunc 對兩個陣列進行加法運算。

判斷函式是否是 ufunc

可以使用 type() 函式檢查函式的型別,如果結果為 numpy.ufunc,則該函式是 ufunc。

import numpy as np

print(type(np.add))

練習

  1. 使用 ufunc 實現陣列的平方和平方根運算。
  2. 建立自定義 ufunc,用於計算兩個陣列的元素之積並返回最大值。
  3. 比較使用 ufunc 和迴圈語句進行陣列運算的效能差異。

解決方案

import numpy as np
import time

# 1. 使用 ufunc 實現陣列的平方和平方根運算

x = np.random.rand(10000)

## 最後

為了方便其他裝置和平臺的小夥伴觀看往期文章:

微信公眾號搜尋:`Let us Coding`,關注後即可獲取最新文章推送

看完如果覺得有幫助,歡迎點贊、收藏、關注

相關文章