按类别计算唯一值数量

15

我在R中有这样的数据:

 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

我想知道每个县(Cnty)中独特物种(Spp)的数量。"unique(dfname$Spp)" 可以给出数据框中所有独特物种的总数,但我希望按县分类。

非常感谢您的帮助!抱歉格式有点奇怪,这是我在SO上的第一个问题。

谢谢。


欢迎来到SO。分享更多关于您已经尝试过什么以及遇到了什么问题将有助于获得更好的答案。但是,为了让您开始着手解决问题,像“aggregate”和“tapply”这样的函数会很有帮助。记得使用“?aggregate”查看函数的帮助文本。 - Justin
7个回答

19

我尝试让你的样本数据更有趣一些。你的样本数据目前每个"Cnty"只有一个唯一的"Spp"。

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

接下来,建议使用tapply。结合uniquelength来获取你需要的数据。

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

如果你想进行简单的制表(不涉及唯一值),那么可以探索tableftable函数。
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

Ananda:非常好的答案!您正确地假定每个县存在多种不同的物种,这正是我需要计数的。非常感谢您的帮助。 - Klaus Louis
@KlausLouis,很高兴听到这个消息。如果这些答案中的任何一个对您有帮助,请考虑为它们投票和/或接受其中之一。谢谢,并欢迎来到Stack Overflow! :) - A5C1D2H2I1M1N2O1R2T1

2

正如Justin所提到的,聚合(aggregate)可能是你想要的。如果你将数据框命名为foo,则以下内容应该可以给你想要的结果,即假设每个Butternut行表示属于Butternut物种的唯一个体的数量。请注意,我使用了foo$Age来计算向量的长度,即属于每个物种的个体数(行),但你也可以使用foo$Ht或foo$DBH等。

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

干杯,
丹尼

1
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

dplyr包可以在这里提供帮助:


library(dplyr)
mydf %>% 
  group_by(Cnty) %>% 
  summarise(un_Spp = length(unique(Spp)))
#> # A tibble: 3 × 2
#>   Cnty  un_Spp
#>   <chr>  <int>
#> 1 185        3
#> 2 189        2
#> 3 31         2

0
一个使用 data.table 方法的简单解决方案。
library(data.table)

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

如果您想将输出转换为更漂亮的表格格式:

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

我想补充一下 A Handcart And Mohair 所提到的内容。对于那些想要将下面代码的结果放入数据框(在 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

您需要在您的代码前面加上as.data.frame.matrix修改器,就像这样:

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

当我看到这篇文章时,我对R语言还很陌生,花了很长时间才理解,所以我想分享一下。


0
with(mydf, tapply(Spp, list(Cnty, Yr), 
     FUN = function(x) length(unique(x))))

唯一查询在大数据集上不起作用,我的意思是数据超过1000k行。


-1
我们现在可以使用计数函数来使这更容易。
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

这个计算出现次数,而不是唯一值。 - luchonacho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接