我有一个数字向量:
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值在向量中出现的次数?
当前回答
这是一维原子向量的快速解。它依赖于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
在需要该输出的情况下,您甚至可能不需要它来重新返回原始向量,而第二列可能就是您所需要的全部。你可以用pipe在一行中得到:
match(x, x) %>% `[`(tabulate(.), .)
#> [1] 3 2 3 2 3 1 2 2
其他回答
2021年的基本解决方案
aggregate(numbers, list(num=numbers), length)
num x
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
tapply(numbers, numbers, length)
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
by(numbers, list(num=numbers), length)
num: 4
[1] 2
--------------------------------------
num: 5
[1] 1
--------------------------------------
num: 23
[1] 2
--------------------------------------
num: 34
[1] 2
--------------------------------------
num: 43
[1] 1
--------------------------------------
num: 54
[1] 1
--------------------------------------
num: 56
[1] 2
--------------------------------------
num: 65
[1] 1
--------------------------------------
num: 67
[1] 2
--------------------------------------
num: 324
[1] 1
--------------------------------------
num: 435
[1] 3
--------------------------------------
num: 453
[1] 1
--------------------------------------
num: 456
[1] 1
--------------------------------------
num: 567
[1] 1
--------------------------------------
num: 657
[1] 1
另外一个我觉得方便的方法是:
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)))
这将数据集转换为因子,然后summary()为我们提供控制总数(唯一值的计数)。
输出是:
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
如果愿意,可以将其存储为数据帧。
as.data.frame(cbind(Number = names(s),Freq = s), stringsAsFactors=F, row.names = 1:length(s))
这里row.names用于重命名行名。 在不使用row.names的情况下,s中的列名被用作new 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
我的首选解决方案使用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 ...
如果你想要的值没有显示,或者你需要为以后存储该值,创建一个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似乎是获得计数和存储所有值的最快方法。
一个选项是使用vctrs库中的vec_count()函数:
vec_count(numbers)
key count
1 435 3
2 67 2
3 4 2
4 34 2
5 56 2
6 23 2
7 456 1
8 43 1
9 453 1
10 5 1
11 657 1
12 324 1
13 54 1
14 567 1
15 65 1
默认顺序将最常用的值放在顶部。如果根据键进行排序(类似table()的输出):
vec_count(numbers, sort = "key")
key count
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
下面是一种可以用dplyr实现的方法:
library(tidyverse)
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
ord <- seq(1:(length(numbers)))
df <- data.frame(ord,numbers)
df <- df %>%
count(numbers)
numbers n
<dbl> <int>
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