2010-02-26 71 views
15

Tôi có một iterator số, ví dụ như một đối tượng file:tính toán trung bình và phương sai với một lặp

f = open("datafile.dat") 

bây giờ tôi muốn để tính toán:

mean = get_mean(f) 
sigma = get_sigma(f, mean) 

việc thực hiện tốt nhất là gì? Giả sử rằng tập tin lớn và tôi muốn tránh đọc nó hai lần.

+0

Bạn có muốn tránh đọc tệp hai lần hoặc tránh lặp lại hai lần không? – truppo

+0

Tôi không nghĩ rằng bạn đang hiển thị cho chúng tôi mã đầy đủ. Bạn đang chuyển một tệp tới 'get_mean()' trong đó 'fsum()' chỉ chấp nhận danh sách các số. –

+0

Tại sao bạn cần đặt giới hạn về sửa đổi chức năng? Nếu bạn sắp xếp lại công thức cho phương sai, tôi nghĩ bạn có thể nhận được một cái gì đó như sqrt (1/(n-1) * (tổng (li ** 2 cho li trong l) + n * mm * tổng (li cho li trong l) + n * mm)) trong đó n là len (l). Đó là, nếu toán của tôi là chính xác. Sau đó, bạn có thể lặp lại một lần, tính toán các thuật ngữ tổng trong phép tái cấu trúc ở trên và giá trị trung bình tại cùng một thời điểm. – chradcliffe

Trả lời

11

Nếu bạn muốn lặp một lần, bạn có thể viết hàm sum của bạn:

def mysum(l): 
    s2 = 0 
    s = 0 
    for e in l: 
     s += e 
     s2 += e * e 
    return (s, s2) 

và sử dụng kết quả trong chức năng sigma của bạn.

Sửa: bây giờ bạn có thể tính toán phương sai như thế này: (s2 - (s * s)/N)/N

Bằng việc tài khoản của bình luận @ Adam Bowen,
ghi nhớ rằng nếu chúng tôi sử dụng thủ thuật toán học và chuyển đổi công thức gốc
chúng tôi có thể làm giảm kết quả.

+13

Với giải pháp này, giá trị trung bình là 's/n' và phương sai là' s2/n - mean * mean' nghĩa là, bình phương của ô vuông trừ bình phương của giá trị trung bình. Tuy nhiên, bạn phải lưu ý rằng việc tính toán phương sai theo cách này có thể không chính xác cho n lớn vì sự khác biệt về tỷ lệ giữa s2 và e * e trong quá trình tích lũy. Thật không may, điều này có nghĩa rằng đối với lớn n các thuật toán hai vượt qua là chính xác hơn nhiều (và một sự lựa chọn tốt hơn). –

+0

@Adam Bowen, cảm ơn. Tôi quên đề cập đến. –

+3

Câu trả lời này được tham chiếu trong [PEP 450] (http://www.python.org/dev/peps/pep-0450/) như là lời khuyên cho một cách tiếp cận ngây thơ để tính toán phương sai với tính ổn định và độ chính xác kém. Xem để so sánh các hàm phương sai trong mô-đun Python 3.4+ ['statistics thống kê] (http://hg.python.org/cpython/file/tip/Lib/statistics.py) được đề xuất. – badp

2

Tạo danh sách từ lần lặp lại hoặc sử dụng itertools.tee().

+1

nhưng không phải toàn bộ tệp phải được lưu trong bộ nhớ? bởi vì get_sigma cần đầu vào từ get_mean, trong trường hợp đó, tại sao không chỉ tải toàn bộ tệp trong bộ nhớ –

+0

bây giờ tôi cuối cùng cũng biết làm thế nào để tôi có thể tạo mã khóa với một liên kết –

+0

't1, t2 = tee (...)' không đáng nếu bạn muốn tiêu thụ toàn bộ 't1' trước và toàn bộ' t2' sau đó.Trong trường hợp này chỉ cần sử dụng 'list (seq)' và lặp lại điều đó – Kos

1

Tôi không chắc chắn có nhiều lựa chọn.

Bạn sẽ phải lặp lại các số của mình hai lần trong mọi trường hợp vì độ lệch chuẩn sẽ yêu cầu thông tin trung bình trên mỗi giá trị.

Nếu bạn có đủ bộ nhớ, bạn có thể đạt được quyền truy cập I/O bằng cách tải tệp của bạn vào bộ nhớ trong lần lặp đầu tiên nhưng đó là về IMO.

+0

Điều này là sai, theo bài viết Wikipedia được trích dẫn bên dưới ... – Mapio

0

Bạn có hai giải pháp

  1. Lập một danh sách ra khỏi iterator và vòng lặp của bạn nó như nhiều lần như bạn muốn. Nhược điểm là mọi thứ sẽ có trong bộ nhớ, vì vậy không phù hợp nếu tệp của bạn lớn. sử dụng đơn giản của itertools.tee cũng sẽ không giúp bạn tiết kiệm

  2. Không có giải pháp nào khác, trừ khi , bạn không cần phải vượt qua sản lượng get_mean để get_sigma, bởi vì trong trường hợp đó họ chỉ có thể ở series, nhưng nếu bạn loại bỏ hạn chế này thì bạn có thể chạy cả hai hàm song song bằng cách sử dụng các chuỗi và sử dụng itertools.tee để có hai trình lặp từ một số

5

Tôi nghĩ Nick D có câu trả lời đúng.

Giả sử bạn muốn tính cả trung bình và phương sai trong một lần quét tệp (và bạn không thực sự muốn hai hàm được gọi là cái kia), bạn có thể thu thập tổng giá trị và của hình vuông của họ và họ sử dụng số tiền như vậy (toghether với số lượng các yếu tố đọc) để tính toán tại cùng một thời gian trung bình và phương sai.

Có một số vấn đề ổn định số, nhưng ý tưởng trong

http://en.wikipedia.org/wiki/Computational_formula_for_the_variance

là thành phần cơ bản mà bạn cần. Một số chi tiết đang ở

http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

nơi tôi đề nghị bạn đọc "thuật toán Naïve".

Hope this helps,

Massimo

1

Như tôi đã cảm thấy rằng có những yếu tố tốt nằm rải rác ở nhiều câu trả lời, tôi xin tóm tắt:

  • Nếu tập tin của bạn là quá lớn để thuận tiện phù hợp với bộ nhớ, và nếu bạn muốn có độ chính xác cao trong phương sai, bạn cần phải đọc tệp hai lần (với một lần truyền, phương sai là sự khác biệt giữa hai số lớn, không chính xác vì giới hạn điểm động). Lưu ý rằng hệ điều hành của bạn có khả năng cung cấp một số tốc độ tự động cho việc đọc tệp thứ hai, vì nó có thể vẫn còn trong RAM trong lần truyền thứ hai.

  • Nếu bạn không quan tâm đến độ chính xác của phương sai, bạn chỉ có thể lặp lại một lần trên tệp và tính số lượng được đề xuất bởi Nick D, với các chi tiết được cung cấp trong nhận xét của Adam Bowen.

0

Bạn có thể sử dụng MapReduce một cách thời trang thanh lịch

mẫu là danh sách bạn muốn nhận sai của nó

mẫu = [a, b, c, .. .]

mean = float(reduce(lambda x,y : x+y, sample))/len(sample) 

variance = reduce(lambda x,y: x+y, map(lambda xi: (xi-mean)**2, sample))/ len(sample) 

trong một dòng ngắn gọn mã:

variance = reduce(lambda x,y: x+y, map(lambda xi: (xi-(float(reduce(lambda x,y : x+y, sample))/len(sample)))**2, sample))/ len(sample) 
+0

để có nghĩa là bạn không cần tất cả điều này: bạn có thể chỉ đơn giản là 'tổng (mẫu)/len (mẫu)' và tương tự cho phương sai. Điểm lớn ở đây bạn đang lặp lại hai lần trên tệp * lớn * của tôi. Câu hỏi của tôi đã yêu cầu * một lần lặp lại * –

+0

oops! - vâng, bạn nói đúng. Nhưng đó là một lý do tốt để sử dụng hàm lambda =) – Juan

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