2010-04-08 33 views
74

Tôi đã cố gắng để tìm một built-in cho trung bình hình học nhưng không thể.Hình học có nghĩa là: có tích hợp sẵn không?

(Rõ ràng là một built-in sẽ không giúp tôi tiết kiệm thời gian trong khi làm việc trong trình bao, cũng không phải tôi nghi ngờ có bất kỳ sự khác biệt về độ chính xác, cho kịch bản tôi cố gắng sử dụng built-in càng thường xuyên càng tốt, nơi các (tích lũy) đạt được hiệu suất thường đáng chú ý.

Trong trường hợp không có một (mà tôi nghi ngờ là trường hợp) ở đây là của tôi.

gm_mean = function(a){prod(a)^(1/length(a))} 
+9

Cẩn thận về số âm và tràn. prod (a) sẽ bị tràn hoặc tràn rất nhanh. Tôi đã cố gắng để thời gian này bằng cách sử dụng một danh sách lớn và nhanh chóng có Inf bằng cách sử dụng phương pháp của bạn vs 1,4 với điểm kinh nghiệm (có nghĩa là (log (x))); vấn đề làm tròn có thể khá nghiêm trọng. – Tristan

+0

tôi vừa viết chức năng ở trên nhanh chóng vì tôi đã chắc chắn rằng 5 phút sau khi đăng bài này Q, ai đó sẽ cho tôi biết R được xây dựng trong cho gm. Vì vậy, không có sẵn để nó là giá trị nhất định dành thời gian để tái mã trong ánh sáng của nhận xét của bạn. + 1 từ tôi. – doug

Trả lời

42

Đây là một vectorized, chức năng zero- và NA-khoan dung để tính trung bình hình học trong R. Các tiết mean tính liên quan đến length(x) là cần thiết cho các trường hợp x chứa các giá trị không tích cực.

gm_mean = function(x, na.rm=TRUE){ 
    exp(sum(log(x[x > 0]), na.rm=na.rm)/length(x)) 
} 

Cảm ơn @ ben-bolker vì đã chú ý đến thông số na.rm và @Gregor để đảm bảo nó hoạt động chính xác.

Tôi nghĩ rằng một số nhận xét có liên quan đến sự tương đương giả của các giá trị NA trong dữ liệu và số không. Trong ứng dụng tôi có trong tâm trí họ là như nhau, nhưng tất nhiên điều này thường không đúng. Do đó, nếu bạn muốn bao gồm việc truyền bá số không bắt buộc, và xử lý length(x) khác nhau trong trường hợp xóa NA, sau đây là một thay thế hơi dài hơn đối với hàm ở trên.

gm_mean = function(x, na.rm=TRUE, zero.propagate = FALSE){ 
    if(any(x < 0, na.rm = TRUE)){ 
    return(NaN) 
    } 
    if(zero.propagate){ 
    if(any(x == 0, na.rm = TRUE)){ 
     return(0) 
    } 
    exp(mean(log(x), na.rm = na.rm)) 
    } else { 
    exp(sum(log(x[x > 0]), na.rm=na.rm)/length(x)) 
    } 
} 

Lưu ý rằng nó cũng kiểm tra đối với bất kỳ giá trị âm, và trả về một thông tin mới hơn và phù hợp NaN tôn trọng điều đó có nghĩa là hình học không được định nghĩa cho các giá trị tiêu cực (nhưng là dành cho số không). Cảm ơn những người bình luận đã ở lại trường hợp của tôi về việc này.

+1

sẽ không tốt hơn nếu vượt qua 'na.rm' thông qua làm đối số (tức là cho phép người dùng quyết định xem họ có muốn chịu được NA hay không, để nhất quán với các hàm tổng hợp R khác)? Tôi lo lắng về việc tự động loại trừ zeroes - tôi cũng sẽ làm một lựa chọn đó. –

+1

Có lẽ bạn đang đúng về việc chuyển 'na.rm' làm tùy chọn. Tôi sẽ cập nhật câu trả lời của mình. Đối với việc loại trừ số không, giá trị trung bình hình học không được xác định cho các giá trị không dương, bao gồm cả số không. Trên đây là một sửa chữa chung cho trung bình hình học, trong đó zeroes (hoặc trong trường hợp này tất cả các số không) được cho một giá trị giả là 1, không ảnh hưởng đến sản phẩm (hoặc tương đương, bằng không trong tổng lôgarit). –

+0

* Tôi có nghĩa là một sửa chữa chung cho các giá trị không dương, không là phổ biến nhất khi trung bình hình học đang được sử dụng. –

70

không, nhưng có một vài người đã viết một, chẳng hạn như here.

Một thuộc tính khác lity là sử dụng điều này:

exp(mean(log(x))) 
+4

liên kết đó đã chết – eddi

+0

Một ưu điểm khác của việc sử dụng exp (mean (log (x)) là bạn có thể làm việc với danh sách dài các số lớn, đó là vấn đề khi sử dụng công thức rõ ràng hơn bằng cách sử dụng prod(). Lưu ý rằng prod (a)^(1/length (a)) và exp (mean (log (a))) cho cùng một câu trả lời. – lukeholman

5

Tôi sử dụng chính xác những gì Mark nói. Bằng cách này, ngay cả với tapply, bạn có thể sử dụng chức năng được xây dựng trong mean, không cần phải xác định của bạn! Ví dụ, để tính toán cho mỗi nhóm trung bình nhân của dữ liệu $ value:

exp(tapply(log(data$value), data$group, mean)) 
10

bạn có thể sử dụng psych gói và gọi geometric.mean chức năng trong đó.

+0

'psych :: geometric.mean()' – smci

+0

Những chức năng này nên lấy chuỗi và không phải sự tăng trưởng của chúng, ít nhất là một tùy chọn, tôi sẽ nói. –

10

Các

exp(mean(log(x))) 

sẽ làm việc trừ khi có một 0 trong x. Nếu vậy, các bản ghi sẽ sản xuất -INF (-Infinite) mà luôn luôn kết quả trong một bình hình học của 0.

Một giải pháp là để loại bỏ các giá trị -INF trước khi tính toán giá trị trung bình:

geo_mean <- function(data) { 
    log_data <- log(data) 
    gm <- exp(mean(log_data[is.finite(log_data)])) 
    return(gm) 
} 

Bạn có thể sử dụng một lớp lót để làm điều này nhưng nó có nghĩa là tính toán nhật ký hai lần không hiệu quả.

exp(mean(log(i[is.finite(log(i))]))) 
+0

tại sao tính nhật ký hai lần khi bạn có thể làm: exp (trung bình (x [x! = 0])) – zzk

+0

cả hai phương pháp đều sai, bởi vì mẫu số trung bình, 'sum (x)/length (x) 'sai nếu bạn lọc x và sau đó chuyển nó sang' mean'. –

+0

Tôi nghĩ rằng lọc là ý tưởng tồi trừ khi bạn có ý nghĩa rõ ràng để làm điều đó (ví dụ: nếu tôi đang viết một chức năng * chung * tôi sẽ không lọc mặc định) - OK nếu đây là một đoạn mã một lần và bạn đã suy nghĩ rất kỹ về những gì lọc zeroes ra thực sự có nghĩa là trong bối cảnh của vấn đề của bạn (!) –

3

Trong trường hợp thiếu giá trị trong dữ liệu của bạn, đây không phải là trường hợp hiếm hoi. bạn cần thêm một đối số nữa. Bạn có thể thử các mã sau đây.

exp(mean(log(i[is.finite(log(i))]),na.rm=T)) 
Các vấn đề liên quan