Bir vektördeki x değerlerine sahip eleman sayısını sayma


400

Bir sayı vektörüm var:

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'nin x değerinin vektörde kaç kez göründüğünü nasıl gösterebilirim ?

Yanıtlar:


505

Sadece şunu kullanabilirsiniz 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 

Sonra alt kümeye ayarlayabilirsiniz:

> a[names(a)==435]
435 
  3

Ya da bununla çalışmaktan daha rahatsanız bir data.frame'e dönüştürün:

> as.data.frame(table(numbers))
   numbers Freq
1        4    2
2        5    1
3       23    2
4       34    2
...

21
Sayıları dizelere zorlayan özellikle tablo ile ilgili olası kayan nokta sorunlarını unutmayın.
hadley

4
Harika bir nokta. Bunların hepsi tamsayıdır, bu nedenle bu örnekte gerçek bir sorun değildir, değil mi?
Shane,

tam olarak değil. Tablonun öğeleri sınıf tamsayı sınıfına (tablo (sayılar) [1]) aittir, ancak 435 bir kayan nokta sayısıdır. Bir tamsayı yapmak için 435L kullanabilirsiniz.
Ian Fellows

@Ian - Bu örnekte 435'in neden bir şamandıra olduğu konusunda kafam karışık. Biraz açıklığa kavuşabilir misiniz? Teşekkürler.
Heather Stark

4
Neden a["435"]inatçı değil a[names(a)==435]?
bombacı

262

En doğrudan yol sum(numbers == x).

numbers == xx'in meydana geldiği her konumda TRUE olan bir mantıksal vektör oluşturur ve suming sırasında mantıksal vektör TRUE değerini 1 ve FALSE değerini 0'a dönüştüren sayıya zorlanır.

Ancak, kayan nokta sayıları için neye kullanım şey daha iyi olacağını not: sum(abs(numbers - x) < 1e-6).


1
kayan nokta sorunu hakkında iyi bir nokta. Bu benim popo genellikle itiraf istediğimden daha fazla ısırır.
JD Uzun

3
@ Jason soruya doğrudan cevap verirken, tahminim millet xbelirli bir bilinen değeri yerine tüm veriler için cevap sağlayan daha genel çözümü sevdim olduğunu x. Adil olmak gerekirse, asıl sorunun konusu buydu. Aşağıdaki
cevabımda söylediğim gibi,

62

Muhtemelen böyle bir şey yapardım

length(which(numbers==x))

Ama gerçekten, daha iyi bir yol

table(numbers)

10
table(numbers)en kolay çözümden çok daha fazla iş yapacak sum(numbers==x), çünkü listedeki diğer tüm sayıların sayısını da çözecek.
Ken Williams

1
tablo ile ilgili sorun, daha karmaşık bir hesaplama içine dahil etmek daha zor olmasıdır, örneğin veri kareleri üzerinde Apply () kullanma
skan

38

Orada da count(numbers)gelen plyrpaketin. tableBence çok daha uygun .


Bunun bir dplyr eşdeğeri var mı?
stevec

34

Tercih ettiğim çözüm rle, bir değer ( xörneğinizdeki etiket ) ve bu değerin sırayla kaç kez göründüğünü gösteren bir uzunluk döndürecek şekilde kullanır .

Birleştirerek rleile sort, herhangi bir değer görüntülenme sayısını saymak için son derece hızlı bir yol var. Bu daha karmaşık sorunlarda yardımcı olabilir.

Misal:

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

İstediğiniz değer görünmüyorsa veya bu değeri daha sonra kullanmak üzere saklamanız gerekiyorsa, aa 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

Tüm değerlerin değil, bir değerin frekansını bilmek istediğimi nadir görüyorum ve rle, sayımı alıp hepsini depolamanın en hızlı yolu gibi görünüyor.


1
Bunun, vs tablosunun avantajı, daha kolay kullanılabilir bir formatta sonuç vermesi midir? teşekkürler
Heather Stark

@HeatherStark İki avantajı olduğunu söyleyebilirim. Birincisi, kesinlikle tablo çıktısından daha kolay kullanılan bir format olmasıdır. İkincisi, bazen tüm veri kümesinden ziyade "bir satırda" öğe sayısını saymak istiyorum. Örneğin, c(rep('A', 3), rep('G', 4), 'A', rep('G', 2), rep('C', 10))geri dönecek values = c('A','G','A','G','C')ve lengths=c(3, 4, 1, 2, 10)bu bazen yararlı olacaktır.
JBecker

1
mikrobenchmark kullanarak table, daha hızlı when the vector is long(100000 denedim) ama daha kısa (1000 denedim) biraz daha uzun görünüyor
ClementWalter

Çok sayıda numaranız varsa bu gerçekten yavaş olacak.
skan

19

Bunun için R'de standart bir fonksiyon vardır

tabulate(numbers)


Dezavantajı, tabulatesıfır ve negatif sayılarla başa çıkamamanızdır.
omar

2
Ancak, diğer çözümlerin işlemediği belirli bir sayının sıfır örneğiyle başa çıkabilirsiniz
Dodgie

Fevkalade hızlı! Ve omar'un dediği gibi, görünmeyen değerler için sıfır sayım verir, bir frekans dağılımı oluşturmak istediğimizde son derece yararlıdır. Sıfır veya negatif tamsayılar kullanılmadan önce sabit eklenerek işlenebilir tabulate. Not: sortgenel olarak doğru kullanımı için gerekli gibi görünüyor: tabulate(sort(numbers)).
pglpm

11
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

9

İşte hızlı ve kirli bir yol:

x <- 23
length(subset(numbers, numbers==x))

9

Daha sonra görünüm sayısını saymak isterseniz, sapplyişlevi kullanabilirsiniz :

index<-sapply(1:length(numbers),function(x)sum(numbers[1:x]==numbers[x]))
cbind(numbers, index)

Çıktı:

        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

Bu hiçbir şekilde tablodan daha hızlı mı ??
Garini


3

Uygun bulmanın bir yolu daha:

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

Bu, veri kümesini faktöre dönüştürür ve sonra özet () bize kontrol toplamlarını (benzersiz değerlerin sayısı) verir.

Çıktı:

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 

İstenirse bu veri çerçevesi olarak saklanabilir.

as.data.frame (cbind (Sayı = ad (lar), Frek = s), dizelerAsFactors = F, row.names = 1: uzunluk (lar))

burada row.names, satır adlarını yeniden adlandırmak için kullanılmıştır. row.names kullanılmadan, s'deki sütun adları yeni veri çerçevesinde satır adları olarak kullanılır

Çıktı:

     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

3

Tablo kullanarak ancak aşağıdakilerle karşılaştırmadan 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 

tablebirkaç kez farklı elemanların sayısını kullanırken faydalıdır. Yalnızca bir sayıya ihtiyacınız varsa,sum(numbers == x)


2

Belirli bir öğeyi saymanın farklı yolları vardır

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

Uzun vektörlerde nispeten hızlı olan ve uygun bir çıktı veren bir yöntem kullanmaktır lengths(split(numbers, numbers))( sonundaki S'ye dikkat edin 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 

Çıktı sadece adlandırılmış bir vektördür.
Hız rle, JBecker tarafından önerilenle karşılaştırılabilir ve çok uzun vektörlerde biraz daha hızlı görünüyor . İşte R 3.6.2'de önerilen bazı işlevlerle birlikte bir mikrobenchmark :

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  

Önemli olan, ayrıca eksik değerleri sayar tek işlevi NAolduğunu plyr::count. Bunlar ayrıca ayrı olarak elde edilebilirsum(is.na(vec))


1

Bu, tek boyutlu atom vektörleri için çok hızlı bir çözümdür. Güvenir match(), bu nedenle aşağıdakilerle uyumludur 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

Ayrıca algoritmayı çalıştıracak şekilde değiştirebilirsiniz 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

Bu çıktının arzu edildiği durumlarda, muhtemelen orijinal vektörü yeniden döndürmek için ona ihtiyacınız yoktur ve ikinci sütun muhtemelen ihtiyacınız olan tek şeydir. Bunu boru ile bir satırda alabilirsiniz:

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

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

1
Gerçekten harika bir çözüm! Bu da gelebileceğim en hızlı olanı. U <- if (is.factor (x)) x [! Duplicated (x)] else unique (x) kullanarak faktör girişi performansı için biraz geliştirilebilir.
Taz

0

Bu ile yapılabilir outer eşitliklerin bir metrikini elde etmek için bunu rowSumsbariz bir anlamla takip eder.
Sayımlara sahip olmak ve numbersaynı veri kümesinde, önce bir data.frame oluşturulur. Ayrı bir giriş ve çıkış istiyorsanız bu adıma gerek yoktur.

df <- data.frame(No = numbers)
df$count <- rowSums(outer(df$No, df$No, FUN = `==`))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.