web-dev-qa-db-fra.com

R: Compter les valeurs uniques par catégorie

J'ai des données dans R qui ressemblent à ceci:

 Cnty   Yr   Plt       Spp  DBH Ht Age
 1  185 1999 20001 Bitternut  8.0 54  47
 2  185 1999 20001 Bitternut  7.2 55  50
 3   31 1999 20001    Pignut  7.4 71  60
 4   31 1999 20001    Pignut 11.4 85 114
 5  189 1999 20001        WO 14.5 80  82
 6  189 1999 20001        WO 12.1 72  79

J'aimerais connaître la quantité d'espèces uniques (Spp) dans chaque comté (Cnty). "unique (dfname $ Spp)" me donne le nombre total d'espèces uniques dans la trame de données, mais j'aimerais les connaître par comté.

Toute aide est appréciée! Désolé pour le formatage étrange, ceci est ma première question sur SO.

Merci.

10
Klaus Louis

J'ai essayé de rendre vos échantillons de données un peu plus intéressants. Votre exemple de données ne contient actuellement qu’un seul "Spp" par "Cnty".

set.seed(1)
mydf <- data.frame(
  Cnty = rep(c("185", "31", "189"), times = c(5, 3, 2)),
  Yr = c(rep(c("1999", "2000"), times = c(3, 2)), 
         "1999", "1999", "2000", "2000", "2000"),
  Plt = "20001",
  Spp = sample(c("Bitternut", "Pignut", "WO"), 10, replace = TRUE),
  DBH = runif(10, 0, 15)
)
mydf
#    Cnty   Yr   Plt       Spp       DBH
# 1   185 1999 20001 Bitternut  3.089619
# 2   185 1999 20001    Pignut  2.648351
# 3   185 1999 20001    Pignut 10.305343
# 4   185 2000 20001        WO  5.761556
# 5   185 2000 20001 Bitternut 11.547621
# 6    31 1999 20001        WO  7.465489
# 7    31 1999 20001        WO 10.764278
# 8    31 2000 20001    Pignut 14.878591
# 9   189 2000 20001    Pignut  5.700528
# 10  189 2000 20001 Bitternut 11.661678

Ensuite, comme suggéré, tapply est un bon candidat ici. Combinez unique et length pour obtenir les données que vous recherchez.

with(mydf, tapply(Spp, Cnty, FUN = function(x) length(unique(x))))
# 185 189  31 
#   3   2   2 
with(mydf, tapply(Spp, list(Cnty, Yr), FUN = function(x) length(unique(x))))
#     1999 2000
# 185    2    2
# 189   NA    2
# 31     1    1

Si vous êtes intéressé par une simple tabulation (pas de valeurs uniques), alors vous pouvez explorer table et ftable:

with(mydf, table(Spp, Cnty))
#            Cnty
# Spp         185 189 31
#   Bitternut   2   1  0
#   Pignut      2   1  1
#   WO          1   0  2
ftable(mydf, row.vars="Spp", col.vars=c("Cnty", "Yr"))
#           Cnty  185       189        31     
#           Yr   1999 2000 1999 2000 1999 2000
# Spp                                         
# Bitternut         1    1    0    1    0    0
# Pignut            2    0    0    1    0    1
# WO                0    1    0    0    2    0
15

Comme Justin l'a mentionné, l'agrégat est probablement ce que vous voulez. Si vous appelez votre bloc de données foo, les éléments suivants doivent vous donner ce que vous voulez, à savoir le nombre d'individus par espèce, en supposant que chaque rangée de noyer cendré représente un individu unique appartenant à l'espèce de noyer cendré. Remarque J'ai utilisé foo $ Age pour calculer la longueur du vecteur, c'est-à-dire le nombre d'individus (rangée) appartenant à chaque espèce, mais vous pouvez utiliser foo $ Ht ou foo $ DBH, etc.

aggregate(foo$Age, by = foo[c('Spp','Cnty')], length)

À votre santé,

Danny

2
Arhopala

Nous pouvons maintenant utiliser la fonction de décompte pour rendre cela plus facile.

tally(group_by(mydf, Spp, Cnty))

        Spp   Cnty     n
     <fctr> <fctr> <int>
1 Bitternut    185     2
2 Bitternut    189     1
3    Pignut    185     2
4    Pignut    189     1
5    Pignut     31     1
6        WO    185     1
7        WO     31     2
0
Vaibhav Bhat
with(mydf, tapply(Spp, list(Cnty, Yr), 
     FUN = function(x) length(unique(x))))

une requête unique ne fonctionne pas avec un ensemble de données volumineux.

0
user3835068
set.seed(1)
mydf <- data.frame(
  Cnty = rep(c("185", "31", "189"), times = c(5, 3, 2)),
  Yr = c(rep(c("1999", "2000"), times = c(3, 2)), 
         "1999", "1999", "2000", "2000", "2000"),
  Plt = "20001",
  Spp = sample(c("Bitternut", "Pignut", "WO"), 10, replace = TRUE),
  DBH = runif(10, 0, 15)
)
mydf

La fonction dplyr::count() ressemble à une solution simple:

library(dplyr)
count(mydf, Spp, Cnty)
# A tibble: 7 x 3
# Spp       Cnty      n
# <fct>     <fct> <int>
# 1 Bitternut 185       2
# 2 Bitternut 189       1
# 3 Pignut    185       2
# 4 Pignut    189       1
# 5 Pignut    31        1
# 6 WO        185       1
# 7 WO        31        2
0
Jot eN

Je voulais ajouter quelque chose à ce que A Handcart And Mohair a mentionné. Pour ceux d'entre vous qui souhaitent obtenir les résultats du code ci-dessous dans un bloc de données (utile dans R studio) ...

with(mydf, table(Spp, Cnty))
#            Cnty
# Spp         185 189 31
#   Bitternut   2   1  0
#   Pignut      2   1  1
#   WO          1   0  2
ftable(mydf, row.vars="Spp", col.vars=c("Cnty", "Yr"))
#           Cnty  185       189        31     
#           Yr   1999 2000 1999 2000 1999 2000
# Spp                                         
# Bitternut         1    1    0    1    0    0
# Pignut            2    0    0    1    0    1
# WO                0    1    0    0    2    0

Vous aurez besoin de mettre le modificateur as.data.frame.matrix devant votre code comme suit:

as.data.frame.matrix(with(mydf, table(Spp, Cnty)))

J'étais assez nouveau chez R quand je suis tombé sur ce poste et il m'a fallu beaucoup de temps pour le comprendre.

0
Matt Ober

Une solution simple utilisant l'approche data.table.

library(data.table)

output <- setDT(mydf)[ , .(count=.N) , by = .(Spp,Cnty)]

au cas où vous souhaiteriez remodeler la sortie dans un format de tableau plus agréable:

library(tidyr)

spread(data=a, key =Spp, count)

#   Cnty Bitternut Pignut WO
# 1:  185         2      2  1
# 2:  189         1      1 NA
# 3:   31        NA      1  2

# or perhaps like this:

spread(data=a, key =Cnty, count)

#          Spp 185 189 31
# 1: Bitternut   2   1 NA
# 2:    Pignut   2   1  1
# 3:        WO   1  NA  2
0
rafa.pereira