Cách đếm giá trị TRUE trong một vectơ logic


160

Trong R, cách hiệu quả / thành ngữ nhất để đếm số lượng TRUEgiá trị trong một vectơ logic là gì? Tôi có thể nghĩ về hai cách:

z <- sample(c(TRUE, FALSE), 1000, rep = TRUE)
sum(z)
# [1] 498

table(z)["TRUE"]
# TRUE 
#  498 

Bạn thích cái nào hơn Có điều gì thậm chí còn tốt hơn?

Câu trả lời:


174

Có một số vấn đề khi vector logic chứa NAgiá trị.
Xem ví dụ:

z <- c(TRUE, FALSE, NA)
sum(z) # gives you NA
table(z)["TRUE"] # gives you 1
length(z[z == TRUE]) # f3lix answer, gives you 2 (because NA indexing returns values)

Vì vậy, tôi nghĩ rằng an toàn nhất là sử dụng na.rm = TRUE:

sum(z, na.rm = TRUE) # best way to count TRUE values

(cho 1). Tôi nghĩ rằng tablegiải pháp đó là ít hiệu quả hơn (nhìn vào mã tablechức năng).

Ngoài ra, bạn nên cẩn thận với giải pháp "bảng", trong trường hợp không có giá trị TRUE trong vectơ logic. Giả sử z <- c(NA, FALSE, NA)hoặc đơn giản z <- c(FALSE, FALSE), sau đó table(z)["TRUE"]cung cấp cho bạn NAcho cả hai trường hợp.


table(c(FALSE))["TRUE"]cho NA, không phải 0.
Yossi Farjoun

@YossiFarjoun Vâng, và đó là câu trả lời của tôi. Đây là ví dụ tại sao nó không hoạt động. Sự hài hước của tôi làsum(z, na.rm = TRUE)
Marek

84

Một tùy chọn khác chưa được đề cập là sử dụng which:

length(which(z))

Chỉ cần thực sự cung cấp một số bối cảnh về "câu hỏi nào nhanh hơn", việc kiểm tra bản thân luôn dễ dàng nhất. Tôi đã làm cho vector lớn hơn nhiều để so sánh:

z <- sample(c(TRUE,FALSE),1000000,rep=TRUE)
system.time(sum(z))
   user  system elapsed 
   0.03    0.00    0.03
system.time(length(z[z==TRUE]))
   user  system elapsed 
   0.75    0.07    0.83 
system.time(length(which(z)))
   user  system elapsed 
   1.34    0.28    1.64 
system.time(table(z)["TRUE"])
   user  system elapsed 
  10.62    0.52   11.19 

Vì vậy, sử dụng rõ ràng sumlà phương pháp tốt nhất trong trường hợp này. Bạn cũng có thể muốn kiểm tra các NAgiá trị như Marek đề xuất.

Chỉ cần thêm một ghi chú liên quan đến các giá trị NA và whichchức năng:

> which(c(T, F, NA, NULL, T, F))
[1] 1 4
> which(!c(T, F, NA, NULL, T, F))
[1] 2 5

Lưu ý rằng chỉ kiểm tra logic TRUE, vì vậy về cơ bản nó bỏ qua các giá trị phi logic.


BTW, có một mẹo hay với thời gian trong câu trả lời Dirk: stackoverflow.com/questions/1748590/revolution-for-r/ Kẻ
Marek

12

Một cách khác là

> length(z[z==TRUE])
[1] 498

Trong khi sum(z) là tốt đẹp và ngắn, đối với tôi length(z[z==TRUE])là tự giải thích nhiều hơn. Mặc dù, tôi nghĩ rằng với một nhiệm vụ đơn giản như thế này, nó không thực sự tạo ra sự khác biệt ...

Nếu nó là một vector lớn, có lẽ bạn nên đi với giải pháp nhanh nhất, đó là sum(z). length(z[z==TRUE])chậm hơn khoảng 10 lần và chậm hơn table(z)[TRUE]khoảng 200 lần sum(z).

Tóm tắt, sum(z)là cách nhanh nhất để gõ và thực hiện.


6

whichlà sự thay thế tốt, đặc biệt là khi bạn hoạt động trên ma trận (kiểm tra ?whichvà chú ý arr.indđối số). Nhưng tôi khuyên bạn nên kiên trì sum, vì na.rmlý lẽ có thể xử lý NAcác vectơ logic. Ví dụ:

# create dummy variable
set.seed(100)
x <- round(runif(100, 0, 1))
x <- x == 1
# create NA's
x[seq(1, length(x), 7)] <- NA

Nếu bạn nhập vào, sum(x)bạn sẽ nhận được NAkết quả, nhưng nếu bạn chuyển na.rm = TRUEvào sumchức năng, bạn sẽ nhận được kết quả mà bạn muốn.

> sum(x)
[1] NA
> sum(x, na.rm=TRUE)
[1] 43

Là câu hỏi của bạn đúng lý thuyết, hoặc bạn có một số vấn đề thực tế liên quan đến vectơ logic?


Tôi đã cố gắng để chấm điểm một bài kiểm tra. Làm một cái gì đó như sum (youranswer == rightanswer) trong một ứng dụng.
Jyotirmoy Bhattacharya

Câu trả lời của tôi quá dài, vì vậy tôi đã đăng một câu trả lời mới, vì nó khác với câu trả lời trước.
aL3xa

6

Một lựa chọn khác là sử dụng chức năng tóm tắt. Nó đưa ra một bản tóm tắt về Ts, Fs và NA.

> summary(hival)
   Mode   FALSE    TRUE    NA's 
logical    4367      53    2076 
> 

1
Hơn nữa, để chỉ nhận kết quả "TRUE" (sẽ là đầu ra dưới dạng chuỗi, nhưng cũng bao gồm "TRUE" trong đầu ra) : summary(hival)["TRUE"];
michael

0

Tôi đã làm một cái gì đó tương tự một vài tuần trước. Đây là một giải pháp khả thi, nó được viết từ đầu, vì vậy đây là loại phát hành beta hoặc đại loại như thế. Tôi sẽ cố gắng cải thiện nó bằng cách loại bỏ các vòng lặp khỏi mã ...

Ý tưởng chính là viết một hàm sẽ lấy 2 (hoặc 3) đối số. Đầu tiên là một data.framedữ liệu chứa dữ liệu được thu thập từ bảng câu hỏi và cái thứ hai là một vectơ số có câu trả lời đúng (điều này chỉ áp dụng cho bảng câu hỏi lựa chọn duy nhất). Ngoài ra, bạn có thể thêm đối số thứ ba sẽ trả về vectơ số với điểm số cuối cùng hoặc data.frame với điểm số được nhúng.

fscore <- function(x, sol, output = 'numeric') {
    if (ncol(x) != length(sol)) {
        stop('Number of items differs from length of correct answers!')
    } else {
        inc <- matrix(ncol=ncol(x), nrow=nrow(x))
        for (i in 1:ncol(x)) {
            inc[,i] <- x[,i] == sol[i]
        }
        if (output == 'numeric') {
            res <- rowSums(inc)
        } else if (output == 'data.frame') {
            res <- data.frame(x, result = rowSums(inc))
        } else {
            stop('Type not supported!')
        }
    }
    return(res)
}

Tôi sẽ cố gắng làm điều này một cách tao nhã hơn với một số chức năng * ply. Lưu ý rằng tôi đã không đưa ra na.rmlập luận ... Sẽ làm điều đó

# create dummy data frame - values from 1 to 5
set.seed(100)
d <- as.data.frame(matrix(round(runif(200,1,5)), 10))
# create solution vector
sol <- round(runif(20, 1, 5))

Bây giờ áp dụng một chức năng:

> fscore(d, sol)
 [1] 6 4 2 4 4 3 3 6 2 6

Nếu bạn truyền đối số data.frame, nó sẽ trả về data.frame đã sửa đổi. Tôi sẽ cố gắng sửa cái này ... Hy vọng nó có ích!


6
Một lớp lót : rowSums(t(t(d)==sol), na.rm=TRUE). R tái chế vector để so sánh. Nếu dma trận của bạn có các trường hợp trong các cột thì nó đơn giản hóa thành rowSums(d==sol, na.rm=TRUE).
Marek

0

Tôi vừa gặp một vấn đề cụ thể khi tôi phải đếm số lượng phát biểu đúng từ một vectơ logic và điều này hiệu quả nhất với tôi ...

length(grep(TRUE, (gene.rep.matrix[i,1:6] > 1))) > 5

Vì vậy, Điều này lấy một tập hợp con của đối tượng gen.rep.matrix và áp dụng một bài kiểm tra logic, trả về một vectơ logic. Vectơ này được đặt làm đối số cho grep, trả về vị trí của bất kỳ mục TRUE nào. Độ dài sau đó tính toán số lượng mục grep tìm thấy, do đó đưa ra số lượng mục TRUE.


0

Ngoài ra còn có một gói được gọi bitlà được thiết kế đặc biệt cho các hoạt động boolean nhanh. Nó đặc biệt hữu ích nếu bạn có các vectơ lớn hoặc cần thực hiện nhiều thao tác boolean.

z <- sample(c(TRUE, FALSE), 1e8, rep = TRUE)

system.time({
  sum(z) # 0.170s
})

system.time({
  bit::sum.bit(z) # 0.021s, ~10x improvement in speed
})
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.