วิธีนับค่า TRUE ในเวกเตอร์เชิงตรรกะ


160

ใน R วิธีใดที่มีประสิทธิภาพมากที่สุดในการนับจำนวนTRUEค่าในเวกเตอร์เชิงตรรกะ? ฉันนึกได้สองวิธี:

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

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

คุณชอบอันไหน? มีอะไรที่ดีกว่านี้อีกไหม

คำตอบ:


174

มีปัญหาบางอย่างเมื่อเวกเตอร์โลจิคัลมีNAค่า
ดูตัวอย่าง:

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)

ดังนั้นฉันคิดว่าปลอดภัยที่สุดคือการใช้na.rm = TRUE:

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

(ซึ่งให้ 1) ฉันคิดว่าtableวิธีแก้ปัญหานั้นมีประสิทธิภาพน้อยกว่า (ดูที่รหัสtableฟังก์ชั่น)

นอกจากนี้คุณควรระวังด้วยวิธีแก้ปัญหา "ตาราง" ในกรณีที่ไม่มีค่า TRUE ในเวกเตอร์เชิงตรรกะ สมมติว่าz <- c(NA, FALSE, NA)หรือเพียงz <- c(FALSE, FALSE)แล้วtable(z)["TRUE"]จะช่วยให้คุณNAทั้งสองกรณี


table(c(FALSE))["TRUE"]ให้ NA ไม่ใช่ 0
Yossi Farjoun

@YossiFarjoun ใช่และเป็นคำตอบของฉัน นี่คือตัวอย่างทำไมมันไม่ทำงาน ลำพังของฉันคือsum(z, na.rm = TRUE)
มาเร็ค

84

ตัวเลือกอื่นที่ไม่ได้กล่าวถึงคือการใช้which:

length(which(z))

เพียงเพื่อให้บริบทบางอย่างเกี่ยวกับ "ซึ่งเป็นคำถามที่เร็วกว่า" มันง่ายที่สุดเพียงแค่ทดสอบตัวเอง ฉันทำให้เวกเตอร์มีขนาดใหญ่กว่ามากสำหรับการเปรียบเทียบ:

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 

ดังนั้นการใช้อย่างชัดเจนจึงsumเป็นวิธีที่ดีที่สุดในกรณีนี้ คุณอาจต้องการตรวจสอบNAค่าตามที่ Marek แนะนำ

เพียงเพิ่มบันทึกเกี่ยวกับค่า NA และwhichฟังก์ชัน:

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

โปรดทราบว่าสิ่งใดที่จะตรวจสอบเชิงตรรกะTRUEเท่านั้นดังนั้นจึงไม่สนใจค่าที่ไม่ใช่เชิงตรรกะ


BTW มีเคล็ดลับที่ดีกับจังหวะเวลาใน Dirk คำตอบ: stackoverflow.com/questions/1748590/revolution-for-r/…
Marek

12

อีกวิธีคือ

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

ในขณะที่sum(z) ดีและสั้นสำหรับฉันlength(z[z==TRUE])อธิบายตัวเอง แม้ว่าฉันจะคิดว่างานง่าย ๆ แบบนี้มันไม่ได้สร้างความแตกต่าง ...

sum(z)ถ้ามันเป็นเวกเตอร์ที่มีขนาดใหญ่คุณอาจจะไปกับวิธีที่เร็วที่สุดซึ่งเป็น length(z[z==TRUE])เป็นเรื่องเกี่ยวกับ 10x ช้าลงและtable(z)[TRUE]เป็นเรื่องเกี่ยวกับ 200x sum(z)ช้ากว่า

ข้อสรุปsum(z)คือพิมพ์และดำเนินการได้เร็วที่สุด


6

whichเป็นทางเลือกที่ดีโดยเฉพาะอย่างยิ่งเมื่อคุณทำงานกับเมทริกซ์ (ตรวจสอบ?whichและสังเกตarr.indข้อโต้แย้ง) แต่ฉันขอแนะนำให้คุณติดอยู่sumเพราะการna.rmโต้แย้งที่สามารถจัดการกับNAเวกเตอร์เชิงตรรกะ ตัวอย่างเช่น

# 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

หากคุณพิมพ์sum(x)คุณจะได้รับNAผลที่ตามมา แต่ถ้าคุณผ่านna.rm = TRUEในsumการทำงานของคุณจะได้รับผลที่คุณต้องการ

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

คำถามของคุณเกี่ยวกับทฤษฎีอย่างเคร่งครัดหรือคุณมีปัญหาในทางปฏิบัติเกี่ยวกับเวกเตอร์เชิงตรรกะ


ฉันพยายามทำแบบทดสอบ ทำอะไรบางอย่างเช่นผลรวม (youranswer == rightanswer) ภายในการสมัคร
Jyotirmoy Bhattacharya

คำตอบของฉันยาวเกินไปดังนั้นฉันจึงโพสต์คำตอบใหม่เนื่องจากคำตอบนั้นแตกต่างจากคำตอบก่อนหน้า
aL3xa

6

อีกทางเลือกหนึ่งคือการใช้ฟังก์ชั่นการสรุป มันให้ข้อมูลสรุปของ Ts, Fs และ NAs

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

1
เพิ่มเติมเพื่อให้ได้ผลลัพธ์ "TRUE" เท่านั้น (ซึ่งจะส่งออกเป็นสตริง แต่ยังรวมถึง "TRUE" ในผลลัพธ์) summary(hival)["TRUE"]:;
ไมเคิล

0

ฉันได้ทำสิ่งที่คล้ายกันไม่กี่สัปดาห์ที่ผ่านมา นี่เป็นวิธีแก้ปัญหาที่เป็นไปได้มันเขียนมาตั้งแต่ต้นดังนั้นจึงเป็นรุ่นเบต้าหรืออะไรทำนองนั้น ฉันจะพยายามปรับปรุงโดยลบลูปออกจากรหัส ...

แนวคิดหลักคือการเขียนฟังก์ชั่นที่จะรับอาร์กิวเมนต์ 2 (หรือ 3) อันแรกคือdata.frameข้อมูลที่เก็บรวบรวมจากแบบสอบถามและอันที่สองเป็นเวกเตอร์ตัวเลขที่มีคำตอบที่ถูกต้อง (ใช้ได้กับแบบสอบถามตัวเลือกเดียวเท่านั้น) หรือคุณสามารถเพิ่มอาร์กิวเมนต์ที่สามที่จะส่งคืนเวกเตอร์ตัวเลขด้วยคะแนนสุดท้ายหรือ data.frame พร้อมคะแนนที่ฝังไว้

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)
}

ฉันจะลองทำสิ่งนี้อย่างสง่างามด้วยฟังก์ชั่น * ply โปรดสังเกตว่าฉันไม่ได้na.rmโต้แย้ง ... จะทำเช่นนั้น

# 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))

ตอนนี้ใช้ฟังก์ชั่น:

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

หากคุณส่งผ่าน data.frame อาร์กิวเมนต์มันจะส่งคืน data.frame ที่ถูกแก้ไข ฉันจะพยายามแก้ไขสิ่งนี้ ... หวังว่ามันจะช่วยได้!


6
rowSums(t(t(d)==sol), na.rm=TRUE)หนึ่งซับ: เวกเตอร์รีไซเคิล R สำหรับการเปรียบเทียบ หากdเมทริกซ์ของคุณมีตัวพิมพ์เล็กและตัวใหญ่ในคอลัมน์ก็จะทำให้มันง่ายrowSums(d==sol, na.rm=TRUE)ขึ้น
Marek

0

ฉันเพิ่งมีปัญหาเฉพาะที่ฉันต้องนับจำนวนงบจริงจากเวกเตอร์เชิงตรรกะและสิ่งนี้ทำงานได้ดีที่สุดสำหรับฉัน ...

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

ดังนั้นนี่จะใช้ชุดย่อยของวัตถุ gene.rep.matrix และใช้การทดสอบแบบลอจิคัลส่งคืนเวกเตอร์โลจิคัล เวกเตอร์นี้ถูกใส่เป็นอาร์กิวเมนต์สำหรับ grep ซึ่งส่งคืนตำแหน่งของรายการ TRUE ใด ๆ จากนั้นความยาวจะคำนวณจำนวน grep ที่พบรายการดังนั้นจึงให้จำนวนรายการ TRUE


0

นอกจากนี้ยังมีแพ็คเกจที่เรียกbitว่าออกแบบมาโดยเฉพาะสำหรับการดำเนินการบูลีนอย่างรวดเร็ว มันมีประโยชน์อย่างยิ่งถ้าคุณมีเวกเตอร์ขนาดใหญ่หรือต้องทำการบูลีนหลายครั้ง

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
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.