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

1554095 次浏览

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

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

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

但是,请注意,对于浮点数,最好使用sum(abs(numbers - x) < 1e-6)这样的格式。

在R中有一个标准函数

tabulate(numbers)

我的首选解决方案使用rle,它将返回一个值(标签,在你的例子中是x)和一个长度,它表示该值连续出现了多少次。

通过结合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 ...

如果你想要的值没有显示,或者你需要为以后存储该值,将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似乎是获得计数和存储所有值的最快方法。

还有plyr包中的count(numbers)。在我看来,比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

如果愿意,可以将其存储为数据帧。

as.data.frame(cbind(Number = names(s),Freq = s), stringsAsFactors=F, row.names = 1:length(s))

here 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))
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']])
这可以用outer来完成,以得到一个等式的矩阵,后面跟着rowSums,具有明显的含义 为了将计数和numbers放在同一个数据集中,首先创建data.frame。如果您希望将输入和输出分开,则不需要此步骤
df <- data.frame(No = numbers)
df$count <- rowSums(outer(df$No, df$No, FUN = `==`))

对于较长的向量,一个相对较快的方法是使用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提出的rle相当,甚至在非常长的向量上更快。下面是R操作中的一个微基准测试,其中包含一些提议的函数

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

在需要该输出的情况下,您甚至可能不需要它来重新返回原始向量,而第二列可能就是您所需要的全部。你可以用pipe在一行中得到:

match(x, x) %>% `[`(tabulate(.), .)


#> [1] 3 2 3 2 3 1 2 2

一种选择是使用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

默认顺序将最常用的值放在顶部。如果根据键查找排序(类似__abc0的输出):

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年的基本解决方案

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