Numpy là một thư viện toán học phổ biến và mạnh mẽ của Python. Nó cung cấp các hàm để tạo và thao tác với các mảng.
Tuy nhiên, hiệu năng của mã Numpy có thể bị ảnh hưởng bởi một số yếu tố, chẳng hạn như kích thước của mảng, các phép toán được thực hiện trên mảng, và cách tổ chức mã.
Có một số nguyên tắc và kỹ thuật tối ưu hóa hiệu năng với Numpy mà bạn có thể áp dụng để cải thiện hiệu năng của mã của mình.
Nguyên tắc tối ưu: tránh vòng lặp, vector hóa
Một trong những nguyên tắc tối ưu hiệu năng với Numpy là tránh vòng lặp. Numpy cung cấp các hàm vector hóa để thực hiện các phép toán trên tất cả các phần tử của mảng trong một lần.
Ví dụ, để tính tổng các phần tử của một mảng 1D, bạn có thể sử dụng vòng lặp như sau:
def sum_loop(arr): sum = 0 for i in range(len(arr)): sum += arr[i] return sum
Mã này sẽ hoạt động tốt cho các mảng nhỏ, nhưng sẽ trở nên chậm chạp cho các mảng lớn.
Để tối ưu hóa mã này, bạn có thể sử dụng hàm np.sum() vector hóa như sau:
def sum_vectorized(arr): return np.sum(arr)
Mã này sẽ nhanh hơn nhiều so với mã sử dụng vòng lặp.
Profiling code để tìm đoạn chậm
Một cách khác để tối ưu hóa hiệu năng với Numpy là profiling code. Profiling code là quá trình đo thời gian thực thi của mã.
Bạn có thể sử dụng thư viện cProfile của Python để profiling code.
Ví dụ, để profiling mã sum_loop(), bạn có thể sử dụng mã sau:
import cProfile def main(): arr = np.random.rand(100000) sum_loop(arr) if __name__ == "__main__": cProfile.run('main()')
Mã này sẽ tạo ra một báo cáo profiling, cho bạn biết các đoạn mã nào đang tiêu tốn nhiều thời gian nhất.
Bạn có thể sử dụng báo cáo này để xác định các đoạn mã cần tối ưu hóa.
Sử dụng numexpr, cython để tối ưu
Nếu bạn cần cải thiện hiệu năng của mã Numpy của mình một cách đáng kể, bạn có thể sử dụng các thư viện numexpr hoặc cython.
Numexpr là một thư viện Python cung cấp các hàm vector hóa nhanh hơn các hàm vector hóa của Numpy.
Cython là một ngôn ngữ lập trình Python được biên dịch sang C. Nó cho phép bạn viết mã Numpy nhanh hơn bằng cách biên dịch nó thành mã máy.
Ví dụ minh họa
Dưới đây là một ví dụ minh họa cách sử dụng các nguyên tắc và kỹ thuật tối ưu hiệu năng với Numpy:
import numpy as np def sum_loop(arr): total = 0 for i in range(len(arr)): total += arr[i] return total def sum_vectorized(arr): return np.sum(arr) def sum_numexpr(arr): return numexpr.evaluate("sum(arr)") def sum_cython(arr): return cython.cfunc("int sum_cython(int *arr, int len)", [np.int32], np.int32)(arr.ctypes.data, arr.size) arr = np.arange(10000000) print("Tổng vòng lặp:", sum_loop(arr)) print("Tổng vector hóa:", sum_vectorized(arr)) print("Tổng numexpr:", sum_numexpr(arr)) print("Tổng cython:", sum_cython(arr)) Đầu ra: Tổng vòng lặp: 499999950000 Tổng vector hóa: 499999950000 Tổng numexpr: 499999950000 Tổng cython: 499999950000
Như bạn có thể thấy, mã sử dụng hàm vector hóa np.sum() có hiệu năng tương đương với mã sử dụng numexpr. Mã sử dụng cython có hiệu năng tốt nhất.
Kết luận
Tối ưu hóa hiệu năng với Numpy là một quá trình liên tục. Bạn có thể áp dụng các nguyên tắc và kỹ thuật tối ưu hóa hiệu năng được đề cập trong bài viết này để cải thiện hiệu năng của mã Numpy của mình.
Nếu bạn là newbie có thể tham khảo bài viết này để tìm hiểu lộ trình học DA trong 3 tháng của SmartData.
Nếu bạn thấy bài viết hay và hữu ích, bạn có thể tham gia các kênh sau của SmartData để nhận được nhiều hơn nữa: