ฉันมีเวกเตอร์ของตัวเลข:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
ฉันจะให้ R นับจำนวนครั้งที่ค่าxปรากฏในเวกเตอร์ได้อย่างไร
ฉันมีเวกเตอร์ของตัวเลข:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
ฉันจะให้ R นับจำนวนครั้งที่ค่าxปรากฏในเวกเตอร์ได้อย่างไร
คำตอบ:
คุณสามารถใช้table()
:
> a <- table(numbers)
> a
numbers
4 5 23 34 43 54 56 65 67 324 435 453 456 567 657
2 1 2 2 1 1 2 1 2 1 3 1 1 1 1
จากนั้นคุณสามารถเซตย่อย:
> a[names(a)==435]
435
3
หรือแปลงเป็น data.frame ถ้าคุณทำงานกับมันได้สะดวกกว่า:
> as.data.frame(table(numbers))
numbers Freq
1 4 2
2 5 1
3 23 2
4 34 2
...
a["435"]
insetead ของa[names(a)==435]
?
sum(numbers == x)
วิธีที่ตรงที่สุดคือ
numbers == x
สร้างเวกเตอร์แบบลอจิคัลซึ่งเป็น TRUE ในทุกตำแหน่งที่ x เกิดขึ้นและเมื่อsum
ing เวกเตอร์แบบลอจิคัลจะถูกบังคับให้เป็นตัวเลขซึ่งแปลง TRUE เป็น 1 และ FALSE ถึง 0
sum(abs(numbers - x) < 1e-6)
อย่างไรก็ตามทราบว่าสำหรับตัวเลขทศนิยมดีกว่าที่จะใช้สิ่งที่ชอบ:
x
x
เพื่อความเป็นธรรมนั่นคือสิ่งที่เป็นคำถามดั้งเดิมเกี่ยวกับ ดังที่ฉันได้กล่าวไว้ในคำตอบของฉันด้านล่าง "ฉันคิดว่าเป็นเรื่องยากที่ฉันต้องการทราบความถี่ของค่าหนึ่งค่าและไม่ใช่ค่าทั้งหมด ... "
ฉันอาจทำอะไรแบบนี้
length(which(numbers==x))
แต่จริงๆแล้ววิธีที่ดีกว่าคือ
table(numbers)
table(numbers)
จะทำงานมากกว่าโซลูชั่นที่ง่ายที่สุดsum(numbers==x)
เพราะมันจะคำนวณจำนวนของตัวเลขอื่น ๆ ทั้งหมดในรายการด้วย
นอกจากนี้ยังมีcount(numbers)
จากplyr
แพ็คเกจ สะดวกกว่าtable
ในความคิดของฉัน
โซลูชันที่ฉันต้องการใช้rle
ซึ่งจะส่งคืนค่า (ฉลากx
ในตัวอย่างของคุณ) และความยาวซึ่งแสดงถึงจำนวนครั้งที่ค่านั้นปรากฏตามลำดับ
เมื่อรวมrle
กับsort
คุณจะมีวิธีที่รวดเร็วที่สุดในการนับจำนวนครั้งที่มีค่าใด ๆ ปรากฏขึ้น สิ่งนี้จะเป็นประโยชน์กับปัญหาที่ซับซ้อนมากขึ้น
ตัวอย่าง:
> numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,453,435,324,34,456,56,567,65,34,435)
> a <- rle(sort(numbers))
> a
Run Length Encoding
lengths: int [1:15] 2 1 2 2 1 1 2 1 2 1 ...
values : num [1:15] 4 5 23 34 43 54 56 65 67 324 ...
หากค่าที่คุณต้องการไม่ปรากฏขึ้นหรือคุณจำเป็นต้องเก็บค่าที่ในภายหลังทำให้a
data.frame
> b <- data.frame(number=a$values, n=a$lengths)
> b
values n
1 4 2
2 5 1
3 23 2
4 34 2
5 43 1
6 54 1
7 56 2
8 65 1
9 67 2
10 324 1
11 435 3
12 453 1
13 456 1
14 567 1
15 657 1
ฉันพบว่าหายากที่ฉันต้องการทราบความถี่ของค่าหนึ่งค่าและไม่ใช่ค่าทั้งหมดและ rle น่าจะเป็นวิธีที่เร็วที่สุดในการนับและจัดเก็บทั้งหมด
c(rep('A', 3), rep('G', 4), 'A', rep('G', 2), rep('C', 10))
จะกลับมาvalues = c('A','G','A','G','C')
และlengths=c(3, 4, 1, 2, 10)
บางครั้งก็มีประโยชน์
table
จะเร็วกว่าwhen the vector is long
(ฉันลอง 100000) แต่อีกเล็กน้อยเมื่อมันสั้นกว่า (ฉันลอง 1,000)
มีฟังก์ชั่นมาตรฐานใน R สำหรับสิ่งนั้น
tabulate(numbers)
tabulate
คือคุณไม่สามารถจัดการกับศูนย์และจำนวนลบ
tabulate
ศูนย์หรือเชิงลบจำนวนเต็มสามารถจัดการได้โดยการเพิ่มอย่างต่อเนื่องก่อนที่จะใช้ หมายเหตุ: น่าจะเป็นสิ่งที่จำเป็นสำหรับการใช้งานที่ถูกต้องโดยทั่วไป:sort
tabulate(sort(numbers))
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435 453,435,324,34,456,56,567,65,34,435)
> length(grep(435, numbers))
[1] 3
> length(which(435 == numbers))
[1] 3
> require(plyr)
> df = count(numbers)
> df[df$x == 435, ]
x freq
11 435 3
> sum(435 == numbers)
[1] 3
> sum(grepl(435, numbers))
[1] 3
> sum(435 == numbers)
[1] 3
> tabulate(numbers)[435]
[1] 3
> table(numbers)['435']
435
3
> length(subset(numbers, numbers=='435'))
[1] 3
นี่เป็นวิธีหนึ่งที่รวดเร็วและสกปรก:
x <- 23
length(subset(numbers, numbers==x))
หากคุณต้องการนับจำนวนการปรากฏตัวในภายหลังคุณสามารถใช้ประโยชน์จากsapply
ฟังก์ชั่น:
index<-sapply(1:length(numbers),function(x)sum(numbers[1:x]==numbers[x]))
cbind(numbers, index)
เอาท์พุท:
numbers index
[1,] 4 1
[2,] 23 1
[3,] 4 2
[4,] 23 2
[5,] 5 1
[6,] 43 1
[7,] 54 1
[8,] 56 1
[9,] 657 1
[10,] 67 1
[11,] 67 2
[12,] 435 1
[13,] 453 1
[14,] 435 2
[15,] 324 1
[16,] 34 1
[17,] 456 1
[18,] 56 2
[19,] 567 1
[20,] 65 1
[21,] 34 2
[22,] 435 3
คุณสามารถเปลี่ยนจำนวนเป็นสิ่งที่คุณต้องการในบรรทัดต่อไปนี้
length(which(numbers == 4))
อีกวิธีหนึ่งที่ฉันพบว่าสะดวกคือ:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,453,435,324,34,456,56,567,65,34,435)
(s<-summary (as.factor(numbers)))
สิ่งนี้จะแปลงชุดข้อมูลเป็นตัวประกอบจากนั้นสรุป () จะให้ผลรวมการควบคุม (นับจากค่าที่ไม่ซ้ำกัน)
ผลลัพธ์คือ:
4 5 23 34 43 54 56 65 67 324 435 453 456 567 657
2 1 2 2 1 1 2 1 2 1 3 1 1 1 1
สามารถเก็บไว้เป็น dataframe ได้ถ้าต้องการ
as.data.frame (cbind (Number = ชื่อ), Freq = s), stringsAsFactors = F, row.names = 1: ความยาว
ที่นี่ row.names ถูกใช้เพื่อเปลี่ยนชื่อแถว โดยไม่ใช้ row.names ชื่อคอลัมน์ใน s จะถูกใช้เป็นชื่อแถวใน dataframe ใหม่
ผลลัพธ์คือ:
Number Freq
1 4 2
2 5 1
3 23 2
4 34 2
5 43 1
6 54 1
7 56 2
8 65 1
9 67 2
10 324 1
11 435 3
12 453 1
13 456 1
14 567 1
15 657 1
ใช้ตาราง แต่ไม่มีการเปรียบเทียบกับnames
:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435)
x <- 67
numbertable <- table(numbers)
numbertable[as.character(x)]
#67
# 2
table
มีประโยชน์เมื่อคุณใช้จำนวนองค์ประกอบต่าง ๆ หลายครั้ง หากคุณต้องการเพียงหนึ่งนับใช้sum(numbers == x)
มีวิธีการนับองค์ประกอบที่แตกต่างกัน
library(plyr)
numbers =c(4,23,4,23,5,43,54,56,657,67,67,435,453,435,7,65,34,435)
print(length(which(numbers==435)))
#Sum counts number of TRUE's in a vector
print(sum(numbers==435))
print(sum(c(TRUE, FALSE, TRUE)))
#count is present in plyr library
#o/p of count is a DataFrame, freq is 1 of the columns of data frame
print(count(numbers[numbers==435]))
print(count(numbers[numbers==435])[['freq']])
วิธีการที่ค่อนข้างเร็วบนเวกเตอร์ที่มีความยาวและให้ผลลัพธ์ที่สะดวกคือการใช้lengths(split(numbers, numbers))
(หมายเหตุSในตอนท้ายlengths
):
# Make some integer vectors of different sizes
set.seed(123)
x <- sample.int(1e3, 1e4, replace = TRUE)
xl <- sample.int(1e3, 1e6, replace = TRUE)
xxl <-sample.int(1e3, 1e7, replace = TRUE)
# Number of times each value appears in x:
a <- lengths(split(x,x))
# Number of times the value 64 appears:
a["64"]
#~ 64
#~ 15
# Occurences of the first 10 values
a[1:10]
#~ 1 2 3 4 5 6 7 8 9 10
#~ 13 12 6 14 12 5 13 14 11 14
ผลลัพธ์เป็นเพียงเวกเตอร์ที่มีชื่อ
ความเร็วนั้นเทียบได้กับJBecker ที่rle
เสนอและเร็วขึ้นเล็กน้อยเมื่อเทียบกับเวกเตอร์ที่ยาวมาก นี่คือ microbenchmark ในR 3.6.2พร้อมกับฟังก์ชั่นบางส่วนที่เสนอ:
library(microbenchmark)
f1 <- function(vec) lengths(split(vec,vec))
f2 <- function(vec) table(vec)
f3 <- function(vec) rle(sort(vec))
f4 <- function(vec) plyr::count(vec)
microbenchmark(split = f1(x),
table = f2(x),
rle = f3(x),
plyr = f4(x))
#~ Unit: microseconds
#~ expr min lq mean median uq max neval cld
#~ split 402.024 423.2445 492.3400 446.7695 484.3560 2970.107 100 b
#~ table 1234.888 1290.0150 1378.8902 1333.2445 1382.2005 3203.332 100 d
#~ rle 227.685 238.3845 264.2269 245.7935 279.5435 378.514 100 a
#~ plyr 758.866 793.0020 866.9325 843.2290 894.5620 2346.407 100 c
microbenchmark(split = f1(xl),
table = f2(xl),
rle = f3(xl),
plyr = f4(xl))
#~ Unit: milliseconds
#~ expr min lq mean median uq max neval cld
#~ split 21.96075 22.42355 26.39247 23.24847 24.60674 82.88853 100 ab
#~ table 100.30543 104.05397 111.62963 105.54308 110.28732 168.27695 100 c
#~ rle 19.07365 20.64686 23.71367 21.30467 23.22815 78.67523 100 a
#~ plyr 24.33968 25.21049 29.71205 26.50363 27.75960 92.02273 100 b
microbenchmark(split = f1(xxl),
table = f2(xxl),
rle = f3(xxl),
plyr = f4(xxl))
#~ Unit: milliseconds
#~ expr min lq mean median uq max neval cld
#~ split 296.4496 310.9702 342.6766 332.5098 374.6485 421.1348 100 a
#~ table 1151.4551 1239.9688 1283.8998 1288.0994 1323.1833 1385.3040 100 d
#~ rle 399.9442 430.8396 464.2605 471.4376 483.2439 555.9278 100 c
#~ plyr 350.0607 373.1603 414.3596 425.1436 437.8395 506.0169 100 b
ที่สำคัญฟังก์ชั่นเดียวที่ยังนับจำนวนของค่าที่ขาดหายไปเป็นNA
plyr::count
สิ่งเหล่านี้สามารถรับแยกได้โดยใช้sum(is.na(vec))
นี่เป็นวิธีแก้ปัญหาที่รวดเร็วมากสำหรับเวกเตอร์อะตอมเดียว มันอาศัยmatch()
ดังนั้นจึงเข้ากันได้กับNA
:
x <- c("a", NA, "a", "c", "a", "b", NA, "c")
fn <- function(x) {
u <- unique.default(x)
out <- list(x = u, freq = .Internal(tabulate(match(x, u), length(u))))
class(out) <- "data.frame"
attr(out, "row.names") <- seq_along(u)
out
}
fn(x)
#> x freq
#> 1 a 3
#> 2 <NA> 2
#> 3 c 2
#> 4 b 1
คุณสามารถปรับแต่งอัลกอริทึมเพื่อไม่ให้ทำงานunique()
ได้
fn2 <- function(x) {
y <- match(x, x)
out <- list(x = x, freq = .Internal(tabulate(y, length(x)))[y])
class(out) <- "data.frame"
attr(out, "row.names") <- seq_along(x)
out
}
fn2(x)
#> x freq
#> 1 a 3
#> 2 <NA> 2
#> 3 a 3
#> 4 c 2
#> 5 a 3
#> 6 b 1
#> 7 <NA> 2
#> 8 c 2
ในกรณีที่ผลลัพธ์ที่ต้องการคุณอาจไม่จำเป็นต้องใช้มันเพื่อคืนค่าเวกเตอร์ดั้งเดิมอีกครั้งและคอลัมน์ที่สองน่าจะเป็นสิ่งที่คุณต้องการ คุณสามารถรับได้ในหนึ่งบรรทัดด้วยไพพ์:
match(x, x) %>% `[`(tabulate(.), .)
#> [1] 3 2 3 2 3 1 2 2
สิ่งนี้สามารถทำได้ด้วยouter
การหาเมทริกซ์ของความเท่าเทียมกันตามมาrowSums
ด้วยความหมายที่ชัดเจน
เพื่อให้มีการนับและnumbers
ในชุดข้อมูลเดียวกัน data.frame จะถูกสร้างขึ้นเป็นครั้งแรก ขั้นตอนนี้ไม่จำเป็นถ้าคุณต้องการอินพุตและเอาต์พุตแยกกัน
df <- data.frame(No = numbers)
df$count <- rowSums(outer(df$No, df$No, FUN = `==`))