R: считать уникальные значения по категориям
У меня есть данные в 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
Я хотел бы знать количество уникальных видов (Spp) в каждом графстве (Cnty). "unique (dfname $Spp)" дает мне общее количество уникальных видов в кадре данных, но я хотел бы это сделать по графству.
Любая помощь приветствуется! Извините за странное форматирование, это мой первый вопрос о SO.
Спасибо.
Ответы
Ответ 1
Я попытался сделать ваши данные образца немного интереснее. В ваших образцовых данных в настоящее время имеется только одна уникальная "Spp" для "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
Далее, как было предложено, tapply
является хорошим кандидатом здесь. Объедините unique
и length
, чтобы получить данные, которые вы ищете.
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
Если вас интересует простая табуляция (а не уникальные значения), вы можете изучить table
и 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
Ответ 2
Как сказал Джастин, совокупность, вероятно, того, чего вы хотите. Если вы вызываете свой фрейм данных foo, то следующее должно дать вам то, что вы хотите, а именно количество индивидуумов на каждого вида, предполагая, что каждая строка с Butternut представляет собой уникальное лицо, принадлежащее к видам butternut. Примечание. Я использовал foo $Age для вычисления длины вектора, т.е. Числа индивидуумов (строк), принадлежащих каждому виду, но вы могли бы использовать foo $Ht или foo $DBH и т.д.
aggregate(foo$Age, by = foo[c('Spp','Cnty')], length)
Приветствия,
Дэнни
Ответ 3
with(mydf, tapply(Spp, list(Cnty, Yr),
FUN = function(x) length(unique(x))))
уникальный запрос не работает с большим набором данных. Я имею в виду данные более 1000 тыс. строк.
Ответ 4
Я хотел добавить к тому, что упоминалось в Handcart и Mohair. Для тех из вас, кто хочет получить результаты кода ниже в кадре данных (полезно в студии R)...
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, когда я пришел на этот пост, и мне потребовалось много времени, чтобы понять это, поэтому я подумал, что поделюсь.
Ответ 5
Простое решение с использованием подхода 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
Ответ 6
Теперь мы можем использовать функцию таллинга, чтобы сделать это проще.
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
Ответ 7
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::count()
выглядит как простое решение:
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