计算向量中具有 x 值的元素数

Counting the number of elements with the values of x in a vector

提问人:RQuestions 提问时间:12/18/2009 最后编辑:epo3RQuestions 更新时间:8/31/2021 访问量:1613421

问:

我有一个数字向量:

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 在向量中出现的次数?

向量 计数 R-FAQ

评论


答:

618赞 Shane 12/18/2009 #1

你可以只使用: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
...

评论

25赞 hadley 12/18/2009
不要忘记潜在的浮点问题,尤其是表,它将数字强制转换为字符串。
10赞 JD Long 12/18/2009 #2

这是一种快速而肮脏的方法:

x <- 23
length(subset(numbers, numbers==x))
83赞 Jesse 12/18/2009 #3

我可能会做这样的事情

length(which(numbers==x))

但实际上,更好的方法是

table(numbers)

评论

10赞 Ken Williams 12/19/2009
table(numbers)将比最简单的解决方案做更多的工作,因为它也会计算出列表中所有其他数字的计数。sum(numbers==x)
1赞 skan 12/2/2015
Table 的问题在于,将它包含在更复杂的演算中更加困难,例如在 DataFrame 上使用 apply()
315赞 hadley 12/18/2009 #4

最直接的方式是.sum(numbers == x)

numbers == x创建一个逻辑向量,该向量在 x 出现的每个位置均为 TRUE,当 ing 时,逻辑向量被强制转换为数值,从而将 TRUE 转换为 1,将 FALSE 转换为 0。sum

但是,请注意,对于浮点数,最好使用类似以下内容。sum(abs(numbers - x) < 1e-6)

22赞 Sergej Andrejev 4/19/2012 #5

R 中有一个标准函数

tabulate(numbers)

38赞 JBecker 12/14/2012 #6

我的首选解决方案使用 ,它将返回一个值(在您的示例中为标签)和一个长度,该长度表示该值按顺序出现的次数。rlex

通过与 结合使用,您可以非常快速地计算任何值出现的次数。这对更复杂的问题很有帮助。rlesort

例:

> 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 ...

如果所需的值未显示,或者需要存储该值以供以后使用,请创建一个 .adata.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 似乎是获取计数并存储所有值的最快方法。

40赞 geotheory 6/6/2013 #7

还有来自包装。比我认为方便得多。count(numbers)plyrtable

4赞 Akash 12/26/2014 #8

我觉得方便的另一种方法是:

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
4赞 pomber 12/27/2014 #9

使用表格,但不与: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)

12赞 Berny 5/15/2015 #10

如果要计算随后的出现次数,可以使用以下功能: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
7赞 uttkarsh dharmadhikari 2/18/2016 #11

您可以在下一行中将号码更改为您想要的任何数字

length(which(numbers == 4))

评论

0赞 ninpnin 8/2/2022
sum(numbers == 4)也会做。
14赞 ishandutta2007 6/7/2017 #12
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
2赞 Therii 11/17/2018 #13

有多种方法可以计算特定元素

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']])
1赞 GWD 12/17/2018 #14

这可以通过得到一个等式的度量,后跟 ,具有明显的含义。
为了在同一数据集中进行计数,首先要创建一个 data.frame。如果需要单独的输入和输出,则不需要此步骤。
outerrowSumsnumbers

df <- data.frame(No = numbers)
df$count <- rowSums(outer(df$No, df$No, FUN = `==`))
1赞 Pascal Martin 2/21/2020 #15

一种在长向量上相对较快并提供方便输出的方法如下(请注意末尾的 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  

重要的是,唯一同时计算缺失值数量的函数是 。这些也可以单独获得NAplyr::countsum(is.na(vec))

2赞 Nik 3/13/2020 #16

这是一维原子矢量的非常快速的解决方案。它依赖于 ,因此它与 兼容: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

评论

1赞 Taz 5/25/2020
真的很棒的解决方案!这也是我能想到的最快的一个。使用 u <- if(is.factor(x)) x[!duplicated(x)] else unique(x) 可以稍微提高因子输入的性能。
6赞 tmfmnk 6/26/2020 #17

一种选择是使用库中的函数: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
1赞 DonnyDolio 7/11/2020 #18

这是您可以使用 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
0赞 see2 11/13/2020 #19

你可以做一个函数来给你结果。

# 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

3赞 Eyayaw 8/31/2021 #20

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

0赞 Maël 11/24/2023 #21

最近(快速)回答了一个老问题。两个选项和一个使用(此答案的变体)。collapsetabulate

collapse::qtableand (custom function) 返回一个命名向量 (à la ),而返回一个 data.frame (à la 或 )。这三个函数经过优化,速度要快得多,并且这两个函数都适用于组和权重。ftabulatetablecollapse::fcountdplyr::countvctrs::vec_countcollapse

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()。 解决方案也是选项中最快的。qtabfcounttabulatebase R

enter image description here

法典:

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