2017-05-07 32 views
10

Tôi hiện đang làm việc với một tệp có hơn 2 triệu dòng. Tôi đã tách các dòng thành danh sách các phần tử (ví dụ: [a,b,c,d] = 1 dòng, các từ được tách biệt).Tối ưu hóa vòng lặp Python

Tôi đang cố gắng sử dụng đoạn mã sau để đi qua tất cả các dòng:

for a in aud: 
    for esps in final: 
     if a[0] in final[esps]: 
      a[0] = esps 

Trong lần đầu tiên cho vòng lặp Tôi đang đề cập đến 2 triệu + dòng. Trong vòng lặp thứ hai, nó đi qua một từ điển với các khóa 2010, mỗi khóa có thể có ít nhất 50 giá trị tương ứng. Tôi muốn tìm phần tử a[0] trong các dòng bằng với các giá trị trong từ điển. Nếu chúng khớp nhau, tôi thay đổi phần tử a[0] trong dòng đã chọn thành giá trị của khóa của từ điển.

Vấn đề là mã này phải mất độ tuổi để chạy và tôi không hiểu nhiều (không có gì) về tối ưu hóa và cách chạy nhanh hơn nhiều. Tôi xin cảm ơn rất nhiều nếu có ai có thể cho tôi biết cách làm điều gì đó nhanh hơn thế này.

+0

hmm, bạn có giới hạn đối với chỉ một máy tính? Tôi nghĩ bạn có thể sử dụng một số công nhân để làm điều đó. Ngay cả với một máy tính, bạn cũng có thể tạo nhiều công nhân với một CPU đa lõi –

+0

Đó là một chút khó khăn để undestand vấn đề thực tế của bạn cho mô tả này không có dữ liệu ví dụ. Có phải tất cả 50 khóa trong mỗi chuỗi từ điển "cuối cùng" phải không? – jsbueno

+0

Điều này sẽ không có tác dụng phụ của việc đột biến một đối tượng trong khi lặp lại nó? – pylang

Trả lời

24

Khi bạn có những thứ "lớn" để chạy qua, như thế này, chìa khóa để làm mọi thứ diễn ra nhanh là "giảm độ phức tạp của thuật toán" - nghĩa là tránh mọi hoạt động phụ thuộc vào kích thước của tập dữ liệu nếu có thể .

Trong ví dụ bạn đã cung cấp, bạn thực hiện, cho mỗi hàng triệu dòng của bạn một tìm kiếm tuyến tính 50 x 2000 - đó là rất nhiều! Vấn đề là nếu mỗi một trong số final[esps] của bạn là một danh sách, Python thực hiện tìm kiếm tuyến tính trong 50 giá trị này - với toán tử in.

Vì bạn đề cập đến bạn đang đọc các giá trị của mình từ một tệp, tôi phải giả định rằng [0] và các phần tử trong các dòng final là các chuỗi - nhưng điều này cũng hoạt động đối với các số.

A đầu tiên, rất đơn giản tối ưu hóa, chỉ đơn giản là thay đổi final hàng từ điển của bạn từ danh sách vào set s - với một set trận đấu từ in thay đổi điều hành từ việc tuyến tính được trong thời gian liên tục (từ O (m) để O (1)) - vì vậy, về cơ bản bạn cắt giảm thời gian tìm kiếm của bạn bởi một yếu tố của 50 nếu trước khi chạy mã trong ví dụ của bạn, bạn cần làm:

for key in final: 
    final[key] = set(final[key]) 

Nhưng bạn vẫn đang thực hiện tìm kiếm tuyến tính trong mỗi người trong số 2010 các phím của final. Cách thay đổi điều đó thành tìm kiếm không đổi là tạo từ điển được đảo ngược - trong đó mỗi giá trị trong số 50 giá trị trong hàng final trỏ đến khóa esp thay thế. Sau đó, bạn chỉ sử dụng [0] làm khóa trong từ điển được đảo ngược này - và bạn đang thay thế tìm kiếm tuyến tính trong 100000 mục (2000 x 50) cho tìm kiếm theo thời gian không đổi trong từ điển;

Đó là dễ dàng để thực hiện - chỉ cần thay đổi mã của bạn để:

rfinal = {} 
for esp, values in final.items(): 
    for value in values: 
     rfinal[value] = esp 


for a in aud: 
    if a[0] in rfinal: 
     a[0] = rfinal[a[0]] 
    else: 
     # code for when there is no match for a[0] 
     ... 
+2

Ví dụ này chỉ thay đổi mọi thứ. Từ hơn 1 giờ mà không hoàn thành ... chỉ trong vài giây. Điều này đã giúp rất nhiều! Với công việc của tôi và tìm hiểu cách tôi có thể tối ưu hóa mã trong tương lai. Cảm ơn bạn 2 triệu + lần ahah! – Targaryel

+0

Nó chỉ khoảng 100.000 lần nhanh hơn trong trường hợp này :-) - Nếu nó hoạt động, hãy nhớ đánh dấu câu trả lời là được chấp nhận. – jsbueno

+2

Một nơi tốt để thực hành loại vấn đề tối ưu hóa này là https://projecteuler.net/ – jsbueno

Các vấn đề liên quan