提问人:RQuestions 提问时间:12/18/2009 最后编辑:epo3RQuestions 更新时间:8/31/2021 访问量:1613421
计算向量中具有 x 值的元素数
Counting the number of elements with the values of x in a vector
问:
我有一个数字向量:
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
...
评论
这是一种快速而肮脏的方法:
x <- 23
length(subset(numbers, numbers==x))
我可能会做这样的事情
length(which(numbers==x))
但实际上,更好的方法是
table(numbers)
评论
table(numbers)
将比最简单的解决方案做更多的工作,因为它也会计算出列表中所有其他数字的计数。sum(numbers==x)
最直接的方式是.sum(numbers == x)
numbers == x
创建一个逻辑向量,该向量在 x 出现的每个位置均为 TRUE,当 ing 时,逻辑向量被强制转换为数值,从而将 TRUE 转换为 1,将 FALSE 转换为 0。sum
但是,请注意,对于浮点数,最好使用类似以下内容。sum(abs(numbers - x) < 1e-6)
R 中有一个标准函数
tabulate(numbers)
我的首选解决方案使用 ,它将返回一个值(在您的示例中为标签)和一个长度,该长度表示该值按顺序出现的次数。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 似乎是获取计数并存储所有值的最快方法。
还有来自包装。比我认为方便得多。count(numbers)
plyr
table
我觉得方便的另一种方法是:
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
如果愿意,可以将其存储为 DataFrame。
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
使用表格,但不与: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)
如果要计算随后的出现次数,可以使用以下功能: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))
评论
sum(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)
> 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
有多种方法可以计算特定元素
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']])
这可以通过得到一个等式的度量,后跟 ,具有明显的含义。
为了在同一数据集中进行计数,首先要创建一个 data.frame。如果需要单独的输入和输出,则不需要此步骤。outer
rowSums
numbers
df <- data.frame(No = numbers)
df$count <- rowSums(outer(df$No, df$No, FUN = `==`))
一种在长向量上相对较快并提供方便输出的方法如下(请注意末尾的 S):lengths(split(numbers, numbers))
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 提出的相当,甚至在很长的向量上甚至更快一些。下面是 R 3.6.2 中的微基准测试,其中包含建议的一些函数:rle
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
评论
一种选择是使用库中的函数:vec_count()
vctrs
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
你可以做一个函数来给你结果。
# your list
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
function1<-function(x){
if(x==value){return(1)}else{ return(0) }
}
# set your value here
value<-4
# make a vector which return 1 if it equal to your value, 0 else
vector<-sapply(numbers,function(x) function1(x))
sum(vector)
结果:2
2021 年基本 r 解决方案
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
最近(快速)回答了一个老问题。两个选项和一个使用(此答案的变体)。collapse
tabulate
collapse::qtable
and (custom function) 返回一个命名向量 (à la ),而返回一个 data.frame (à la 或 )。这三个函数经过优化,速度要快得多,并且这两个函数都适用于组和权重。ftabulate
table
collapse::fcount
dplyr::count
vctrs::vec_count
collapse
collapse::qtab(numbers) #or collapse::qtable(numbers)
# 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
ftabulate <- function(x){
u <- unique.default(x)
setNames(tabulate(match(x, u), length(u)), u)
}
ftabulate(numbers)
# 4 23 5 43 54 56 657 67 435 453 324 34 456 567 65
# 2 2 1 1 1 2 1 2 3 1 1 2 1 1 1
collapse::fcount(numbers)
# x N
# 1 4 2
# 2 23 2
# ...
现有解决方案,并以具有 100 个唯一值的 1e6 长度向量为基准。
下面是现有解决方案的全景图,按它们返回命名向量还是 data.frame 进行分组,以及与大小为 1,000,000 且具有 100 个不同值的向量的速度比较。
collapse
选项是最快的,无论需要返回命名向量 () 还是 data.frame()。 解决方案也是选项中最快的。qtab
fcount
tabulate
base R
法典:
library(microbenchmark)
library(ggplot2)
set.seed(1)
numbers <- sample(sample(1000, 100), size = 1e6, replace = TRUE)
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
}
mb <-
microbenchmark(
#Named vectors
"collapse::qtab" = qtab(numbers),
table = table(numbers),
tapply = tapply(numbers, numbers, length),
lengths = lengths(split(numbers,numbers)),
ftabulate = ftabulate(numbers),
#Data.frame
"collapse::fcount" = fcount(numbers),
"vctrs::vec_count" = vctrs::vec_count(numbers),
tabulate_df = fn(numbers),
aggregate = aggregate(numbers, list(num=numbers), length),
rle = with(rle(sort(numbers)), data.frame(number = values, n = lengths)),
times = 50L
)
mb$ntime <- microbenchmark:::convert_to_unit(mb$time, "t")
type <- setNames(levels(mb$expr), c(rep("Named vector", 5), rep("Data frame", 5)))
mb$type <- names(type)[match(mb$expr, levels(mb$expr))]
ggplot(mb, aes(x = expr, y = ntime)) +
geom_violin() +
scale_x_discrete(name = "", limits = rev) +
scale_y_log10(name = sprintf("Time [%s]", attr(mb$ntime, "unit"))) +
coord_flip() +
ggforce::facet_col(facets = vars(type), scales = "free_y", space = "free")
Unit: milliseconds
expr min lq mean median uq max neval
collapse::qtab 7.992801 12.122301 18.08057 15.03340 17.1635 71.8245 50
table 259.816201 370.759301 453.11712 447.25705 533.3613 613.8360 50
tapply 51.133300 69.950101 95.82087 91.15720 101.9496 248.4416 50
lengths 32.467401 51.007100 64.84489 60.97170 72.2331 179.6724 50
ftabulate 24.455901 37.864101 46.76249 43.06755 56.3162 92.3557 50
collapse::fcount 5.770500 7.499401 10.52078 10.53265 11.1268 32.4896 50
vctrs::vec_count 15.830001 27.466501 32.60882 29.31685 37.8101 87.4450 50
tabulate_df 24.235500 36.730401 45.35056 43.59385 51.3074 143.7773 50
aggregate 404.713901 510.090201 592.82286 606.85290 644.4701 922.6984 50
rle 52.259502 71.437701 92.71214 87.64515 99.4625 245.9526 50
上一个:将数据帧转换为向量(按行)
评论