Hướng dẫn speed up for loop python - tăng tốc cho vòng lặp python
Show
Danh sách các hệ thống toàn diện, lập chỉ mục boolean và biên dịch đúng (JIT) để tăng tốc độ lên tới 200 lần.Ảnh của James Donovan trên unplashKhi khám phá một bộ dữ liệu mới và muốn thực hiện một số kiểm tra hoặc tính toán nhanh chóng, người ta sẽ bị cám dỗ để ghi mã một cách lười biếng mà không suy nghĩ nhiều về tối ưu hóa. Mặc dù điều này có thể hữu ích ngay từ đầu, nhưng có thể dễ dàng xảy ra khi thời gian chờ thực thi mã vượt qua thời gian mà nó sẽ có để viết mọi thứ đúng cách.hen exploring a new dataset and wanting to do some quick checks or calculations, one is tempted to lazily write code without giving much thought about optimization. While this might be useful in the beginning, it can easily happen that the time waiting for code execution overcomes the time that it would have taken to write everything properly. Bài viết này cho thấy một số cách cơ bản về cách tăng tốc thời gian tính toán trong Python. Với ví dụ về dữ liệu lọc, chúng tôi sẽ thảo luận về một số phương pháp sử dụng Python, Numpy, Numba, Pandas cũng như K-D-cây thuần túy. Lọc nhanh các bộ dữ liệuLà một nhiệm vụ ví dụ, chúng tôi sẽ giải quyết vấn đề lọc các bộ dữ liệu một cách hiệu quả. Đối với điều này, chúng tôi sẽ sử dụng các điểm trong một không gian hai chiều, nhưng đây có thể là bất cứ thứ gì trong không gian N chiều, cho dù đây là dữ liệu của khách hàng hay các phép đo của một thí nghiệm. Hãy giả sử, chúng tôi muốn trích xuất tất cả các điểm trong một hình chữ nhật với giữa [0,2, 0,4] và [0,4, 0,6]. Cách ngây thơ để làm điều này sẽ là vòng lặp cho từng điểm và kiểm tra xem nó có đáp ứng tiêu chí này không. CodeWise, điều này có thể trông giống như sau: Đầu tiên, chúng tôi tạo một hàm để phân phối ngẫu nhiên các điểm trong không gian n chiều với Numpy, sau đó là một hàm để lặp qua các mục. Để đo thời gian tính toán, chúng tôi sử dụng thời gian và trực quan hóa các kết quả lọc bằng matplotlib. Loop: 72 ms ± 2.11 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) Như chúng ta có thể thấy, đối với máy được thử nghiệm, nó đã mất khoảng. 70 ms để trích xuất các điểm trong một hình chữ nhật từ bộ dữ liệu 100.000 điểm.
Mặc dù Numpy là tốt để tương tác với các mảng N chiều lớn, chúng tôi cũng nên xem xét chi phí bổ sung mà chúng tôi có được bằng cách sử dụng các đối tượng không có. Trong ví dụ cụ thể này, chúng tôi không sử dụng bất kỳ hoạt động toán học nào mà chúng tôi có thể hưởng lợi từ vectơ hóa Numpy. Vì vậy, bây giờ hãy để điểm chuẩn của vòng lặp này chống lại việc triển khai Python thuần túy của vòng lặp. Ở đây, sự khác biệt là sử dụng một danh sách các bộ dữ liệu thay vì một mảng numpy. Python loop: 27.9 ms ± 638 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) Việc thực hiện bây giờ chỉ mất khoảng. 28 ms, vì vậy ít hơn một nửa thời gian thực hiện trước đó. Điều này nhấn mạnh sự giảm hiệu suất tiềm năng có thể xảy ra khi sử dụng các gói được tối ưu hóa cao cho các nhiệm vụ khá đơn giản. Chức năng Python: Danh sách hiểu, bản đồ và bộ lọcĐể thực hiện một so sánh rộng hơn, chúng tôi cũng sẽ điểm chuẩn so với ba phương thức tích hợp trong Python: Liệt kê toàn diện, bản đồ và bộ lọc.
List comprehension: 21.3 ms ± 299 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) Phương pháp hiểu danh sách nhanh hơn một chút. Đây là, như chúng tôi mong đợi, từ việc tiết kiệm thời gian không gọi chức năng nối tiếp. Hàm bản đồ và bộ lọc không cho thấy sự gia tăng tốc độ đáng kể so với vòng python tinh khiết. Suy nghĩ về việc triển khai đầu tiên của hơn 70 ms Tại sao người ta nên sử dụng Numpy ngay từ đầu? Một điều chúng ta có thể làm là sử dụng lập chỉ mục Boolean. Ở đây chúng tôi thực hiện kiểm tra cho từng cột tiêu chí khôn ngoan. Sau đó, chúng ta có thể kết hợp chúng với một chỉ mục boolean và truy cập trực tiếp các giá trị nằm trong phạm vi. Boolean index: 639 µs ± 28.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) Giải pháp sử dụng chỉ số Boolean chỉ mất khoảng. 640 Laus, vì vậy một cải tiến gấp 50 lần về tốc độ so với lần thực hiện nhanh nhất mà chúng tôi đã thử nghiệm cho đến nay. Đi nhanh hơn: NumbaChúng ta thậm chí có thể đẩy điều này hơn nữa? Vâng, chúng tôi có thể. Một cách là sử dụng numba:
Việc triển khai Numba khá dễ dàng nếu người ta sử dụng Numpy và đặc biệt hiệu suất nếu mã có nhiều vòng lặp. Nếu các chức năng được thiết lập chính xác, tức là sử dụng các vòng lặp và các hàm numpy cơ bản, một bổ sung đơn giản của trình trang trí @njit sẽ gắn cờ hàm được biên dịch trong numba và sẽ được thưởng với tốc độ tăng. Vui lòng kiểm tra tài liệu Numbas để tìm hiểu về các chi tiết trong việc thiết lập các chức năng tương thích numba. Lưu ý rằng chúng tôi đang sử dụng phiên bản gần đây nhất của Numba (0,45) đã giới thiệu danh sách đánh máy. Ngoài ra, lưu ý rằng chúng tôi đang thực hiện các chức năng một lần trước khi thời gian không tính đến thời gian biên dịch. Bây giờ, hãy để Lừa xem các chức năng thực hiện như thế nào khi được biên dịch với Numba: Boolean index with numba: 341 µs ± 8.97 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) Sau khi biên dịch chức năng với LLVM, ngay cả thời gian thực hiện cho bộ lọc boolean nhanh là một nửa và chỉ mất khoảng. 340 Pha. Điều thú vị hơn, ngay cả vòng lặp không hiệu quả ngay từ đầu hiện được tăng từ 72 ms lên dưới 1 ms, làm nổi bật tiềm năng của numba đối với mã tối ưu hóa kém. Dữ liệu trong Bảng: Gấu trúcTrước đây, chúng tôi đã thấy rằng các loại dữ liệu có thể ảnh hưởng đến kiểu dữ liệu. Người ta phải quyết định cẩn thận giữa hiệu suất mã, giao tiếp dễ dàng và mã có thể đọc được. Pandas, ví dụ, rất hữu ích trong việc điều khiển dữ liệu bảng. Tuy nhiên, cấu trúc dữ liệu có thể giảm hiệu suất. Để đặt điều này trong quan điểm, chúng tôi cũng sẽ so sánh các chức năng trên bo mạch để lọc như truy vấn và eval và cũng chỉ lập boolean. Pandas Query: 8.77 ms ± 173 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) Có thể cho rằng, thời gian thực hiện nhanh hơn nhiều so với vòng lặp ban đầu của chúng tôi không được tối ưu hóa. Tuy nhiên, nó chậm hơn đáng kể so với các phiên bản tối ưu hóa. Do đó, nó phù hợp để thăm dò ban đầu nhưng sau đó nên được tối ưu hóa. So sánh định lượng iĐể so sánh các phương pháp theo cách định lượng hơn, chúng ta có thể đánh giá chúng với nhau. Đối với điều này, chúng tôi sử dụng gói perfplot cung cấp một cách tuyệt vời để làm như vậy.
Nhiều truy vấn và bộ dữ liệu lớn hơnCuối cùng, chúng tôi sẽ thảo luận về các chiến lược mà chúng tôi có thể sử dụng cho các bộ dữ liệu lớn hơn và khi sử dụng nhiều truy vấn hơn. Cho đến nay chúng tôi đã xem xét thời gian khi luôn kiểm tra một điểm tham chiếu cố định. Giả sử thay vì một điểm, chúng ta có một danh sách các điểm và muốn lọc dữ liệu nhiều lần. Rõ ràng, sẽ có lợi nếu chúng ta có thể sử dụng một số thứ tự trong dữ liệu, ví dụ: Khi có một điểm ở góc trên bên trái chỉ đến các điểm truy vấn ở góc cụ thể đó. Chúng ta có thể làm như vậy bằng cách sắp xếp dữ liệu trước và sau đó có thể chọn một tiểu mục bằng một chỉ mục. Ý tưởng ở đây là thời gian để sắp xếp mảng phải được bù vào thời gian lưu liên tục tìm kiếm một mảng nhỏ hơn. Để tăng thêm độ phức tạp, bây giờ chúng tôi cũng tìm kiếm trong chiều thứ ba, cắt giảm hiệu quả một voxel trong không gian. Vì chúng tôi chỉ quan tâm đến thời gian, hiện tại, chúng tôi chỉ báo cáo độ dài của các mảng được lọc. Chúng tôi viết lại hàm boolean_index_numba để chấp nhận khối lượng tham chiếu tùy ý ở dạng [xmin, xmax], [ymin, ymax] và [zmin, zmax]. Chúng tôi xác định một trình bao bọc có tên nhiều_queries liên tục thực thi chức năng này. Việc so sánh sẽ chống lại hàm nhiều_queries_index sắp xếp dữ liệu trước và chỉ chuyển một tập hợp con cho boolean_index_numba_multiple. Multiple queries: 433 ms ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) Đối với ví dụ này, thời gian thực hiện hiện đã giảm xuống chỉ còn một phần tư. Tỷ lệ tăng tốc độ với số lượng điểm truy vấn. Như một lưu ý bổ sung, việc trích xuất chỉ số tối thiểu và tối đa tương đối nhanh. Cấu trúc khác: K-D-TreesÝ tưởng cấu trúc trước dữ liệu để tăng thời gian truy cập có thể được mở rộng hơn nữa, ví dụ: Người ta có thể nghĩ đến việc sắp xếp lại trên dữ liệu được tập hợp lại. Người ta có thể nghĩ đến việc tạo ra các thùng N-chiều để tập hợp dữ liệu hiệu quả. Một cách tiếp cận mở rộng ý tưởng này và sử dụng cấu trúc cây để lập chỉ mục dữ liệu là cây K-D cho phép tra cứu nhanh hàng xóm cho một điểm nhất định. Dưới một định nghĩa ngắn từ Wikipedia:
May mắn thay, chúng tôi không cần phải tự mình thực hiện K-D-Tree nhưng có thể sử dụng một triển khai hiện có từ SCIPY. Nó không chỉ có một triển khai Python thuần túy mà còn là phiên bản được tối ưu hóa C mà chúng ta có thể sử dụng cho phương pháp này. Nó đi kèm với một chức năng tích hợp có tên là query_ball_tree cho phép tìm kiếm tất cả các hàng xóm trong một bán kính nhất định. Khi chúng tôi đang tìm kiếm các điểm trong một hình vuông xung quanh một điểm nhất định, chúng tôi chỉ cần đặt định mức Minkowski thành Chebyshev (P = Hồi Inf,). Tree construction: 37.7 ms ± 1.39 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) Từ thời gian, chúng ta có thể thấy rằng phải mất khoảng 40 ms để xây dựng cây, tuy nhiên, bước truy vấn chỉ có trong phạm vi 100, do đó thậm chí còn nhanh hơn so với việc lập chỉ mục Boolean được tối ưu hóa.
So sánh định lượng IIMột lần nữa chúng tôi sẽ sử dụng perfplot để đưa ra một so sánh định lượng hơn. Đối với điều này, chúng tôi sẽ truy vấn một triệu điểm so với số điểm ngày càng tăng.
Đối với phạm vi dữ liệu này, sự so sánh giữa KDTREE, nhiều_queries và phiên bản được lập chỉ mục của nhiều truy vấn cho thấy hành vi mong đợi: chi phí ban đầu của việc xây dựng cây hoặc sắp xếp dữ liệu thừa thềm khi tìm kiếm đối với các bộ dữ liệu lớn hơn. KDTREE dự kiến sẽ vượt trội so với phiên bản được lập chỉ mục của nhiều truy vấn cho các bộ dữ liệu lớn hơn. Đó là để nhấn mạnh rằng khi việc triển khai SCIPY dễ dàng chấp nhận dữ liệu N chiều, rất đơn giản để mở rộng cho nhiều chiều hơn nữa. Bản tóm tắtTốc độ lọc thử nghiệm cho các phương pháp khác nhau làm nổi bật cách mã có thể được tối ưu hóa một cách hiệu quả. Thời gian thực hiện dao động từ hơn 70 ms để triển khai chậm đến khoảng. 300 Pha cho một phiên bản tối ưu hóa bằng cách sử dụng lập chỉ mục Boolean, hiển thị hơn 200 lần cải tiến. Những phát hiện chính có thể được tóm tắt như sau:
Thời gian thực hiện có thể tăng tốc hơn nữa khi nghĩ đến song song, trên CPU hoặc GPU. Lưu ý rằng dấu chân bộ nhớ của các phương pháp không được xem xét cho các ví dụ này. Khi có các tệp quá lớn để tải trong bộ nhớ, việc phân hủy các biểu thức dữ liệu hoặc trình tạo có thể tiện dụng. Nếu bạn thấy rằng bất kỳ cách tiếp cận nào bị thiếu hoặc có khả năng cung cấp kết quả tốt hơn, hãy cho tôi biết. Tôi tò mò muốn xem những cách khác tồn tại để thực hiện lọc nhanh. Là cho vòng lặp nhanh hơn trong khi vòng lặp trong Python?Cho VS trong khi vòng lặp trong Python. Python có phải là vòng lặp nhanh không?Như bạn có thể thấy, ở đây chúng tôi đang sử dụng gần như chỉ các tính năng tích hợp, luôn nhanh hơn Python thuần túy.Đây là lý do tại sao vòng lặp For-Arech nhanh hơn rất nhiều so với các đối tác của nó vì tải trọng nặng được xử lý bởi chính phiên dịch Python theo cách tối ưu hóa.the for-each loop is so much faster than its counterparts because the heavy load is handled by the Python interpreter itself in an optimized way.
Làm cách nào để thực hiện Python nhanh hơn?5 cách để làm cho các chương trình Python của bạn chạy nhanh hơn.. Là Pythonic.Thật dễ dàng, đến từ các ngôn ngữ lập trình khác, để viết mã cắt giảm so với hạt..... Sử dụng ghi nhớ.Điều này nghe có vẻ phức tạp hơn thực tế..... Mã nó trong C. Điều này không phải lúc nào cũng dễ dàng thực hiện..... Biên dịch Python..... Sử dụng 'từ' khi có thể..... Conclusion.. Bản đồ có nhanh hơn so với vòng lặp không?Sự khác biệt chủ yếu với các vòng lặp là sintaxe của bạn và các giá trị trả về của bạn.Bản đồ trả về các đối tượng bản đồ và vòng lặp không trả về không có gì.Kết luận đầu tiên: Bản đồ nhanh hơn các vòng?Trong trường hợp này có.Map are faster than loops? . In this case yes . |