2016-12-28 7 views
1

Каждая строка в моем наборе данных представляет собой другое дерево. Сюжет относится к области отбора проб (из которых около 700), вид - это вид дерева, а другие столбцы - это то, присутствует ли дерево (1) или отсутствует (NA). Ниже приведен минимальный пример набора данныхЧисло различных значений для одного столбца в списке разделов

Plot Species 1983 1988 2003 2008 2013 
    1   11  1  1  1  1  1 
    1   11  1  1  1  1  NA 
    1   21  NA  1  1  1  1 
    2   11  1  1  1  NA  NA 
    2   34  1  1  1  1  1 
    3   15  1  1  1  1  NA 
    3   15  NA  1  1  1  NA 
    3   11  1  1  1  1  NA 

В основном то, что я хочу знать, сколько разных видов есть в каждом участке, каждый год, не включая значения NA:

Plot  1983 1988 2003 2008 2013 
    1   1  2  2  2  2 
    2   2  2  2  1  1 
    3   2  2  2  2  0 

Мои текущая стратегия следующим образом - изменить все значения 1 в их число видов, так что набор данных выглядит, как показано ниже

Plot Species 1983 1988 2003 2008 2013 
    1   11  11  11  11  11  11 
    1   11  11  11  11  11  NA 
    1   21  NA  21  21  21  21 
    2   11  11  11  11  NA  NA 
    2   34  34  34  34  34  34 
    3   15  15  15  15  15  NA 
    3   15  NA  15  15  15  NA 
    3   11  11  11  11  11  NA 

, а затем разделить набор данных в соответствии с номером участка, используя

split(data, as.factor(data$Plot)) 

Я думаю, что я по существу хочу, чтобы длина каждого столбца определялась, сколько разных значений есть, но colSums не учитывает разные графики. Я не уверен, как использовать функции apply, когда у меня есть список разделов.

Любые предложения приветствуются! Благодаря

+2

Я думаю, что 'rowsum (DF [- (1: 2)], группа = DF $ много, na.rm = TRUE)' будет это делать, хотя это не вполне соответствуют вашим суммам. Например, третий элемент 1988 года - это 3, а не 2. – lmo

+0

@Imo, который, похоже, работает в основном, однако кажется, что добавление фактических значений, а не количество различных значений. Третий элемент 1988 года должен быть 2, так как есть два разных вида (15 и 11) – isabelnt

+0

@ Хенрик вы правы! извиниться за ошибку там, отредактировать это – isabelnt

ответ

2

tidyverse подход:

library(tidyr) 
library(dplyr) 

data %>% 
    gather(Year, Value, na.rm = TRUE, -Plot, -Species) %>% 
    group_by(Plot, Year) %>% 
    distinct(Species, .keep_all = TRUE) %>% 
    count(Plot, Year) %>% 
    spread(Year, n, fill = 0) 

Source: local data frame [3 x 6] 
Groups: Plot [3] 

    Plot `1983` `1988` `2003` `2008` `2013` 
* <int> <dbl> <dbl> <dbl> <dbl> <dbl> 
1  1  1  2  2  2  2 
2  2  2  2  2  1  1 
3  3  2  2  2  2  0 
+0

Мне нравится метод, что-то я еще не встретил!однако, похоже, это количество значений, а не количество разных видов - последняя строка в вашем выходе не соответствует моему желаемому результату. – isabelnt

+0

Ваш желаемый результат не согласуется с вашими данными, что привело меня к мысли, что вам нужен общий подсчет всех присутствующих видов (см. Plot1 1988 со значением 3, когда присутствуют 2 вида). Я включил код для уникальных подсчетов. –

+0

Второй бит отлично работает для меня, большое вам спасибо! – isabelnt

1

Мы можем сделать это с data.table

library(data.table) 
setDT(df1)[, lapply(.SD, function(x) uniqueN(na.omit(x*Species))) , Plot, .SDcols = 3:7] 
# Plot 1983 1988 2003 2008 2013 
#1: 1 1 2 2 2 2 
#2: 2 2 2 2 1 1 
#3: 3 2 2 2 2 0 

Или подобный подход с dplyr

library(dplyr) 
df1 %>% 
    group_by(Plot) %>% 
    summarise_each(funs(n_distinct(na.omit(Species * .))), 3:7) 
# A tibble: 3 × 6 
# Plot `1983` `1988` `2003` `2008` `2013` 
# <int> <int> <int> <int> <int> <int> 
#1  1  1  2  2  2  2 
#2  2  2  2  2  1  1 
#3  3  2  2  2  2  0 
2

Пара альтернатив, которые вычисляют то же, что и принятый ответ. В базе R с использованием метода split-apply-comb вы получаете

do.call(rbind, lapply(split(df[-(1:2)] * df$Species, df$lot), 
         function(x) sapply(x, function(y) length(unique(y[!is.na(y)]))))) 
    X1983 X1988 X2003 X2008 X2013 
1  1  2  2  2  2 
2  2  2  2  1  1 
3  2  2  2  2  0 

Для этого требуется вложенный цикл. Во-первых, перебираем список data.frames, созданный путем разбиения на лот, а затем циклически перебираем каждую из переменных года. Здесь do.call с rbind возвращает матрицу.

Вы можете использовать rbind.data.frame с setNames, чтобы вернуть data.frame

setNames(do.call(rbind.data.frame, lapply(split(df[-(1:2)] * df$Species, df$lot), 
             function(x) sapply(x, 
               function(y) length(unique(y[!is.na(y)]))))), 
     names(df)[-(1:2)]) 

    X1983 X1988 X2003 X2008 X2013 
1  1  2  2  2  2 
2  2  2  2  1  1 
3  2  2  2  2  0 

В обоих из них, много содержится в названиях строк.

Затем с data.table

library(data.table) 
setDT(df) 

df[, lapply(.SD, function(x) length(unique((x * Species)[!is.na(x)]))), 
    .SDcols=X1983:X2013, by=lot] 
    lot X1983 X1988 X2003 X2008 X2013 
1: 1  1  2  2  2  2 
2: 2  2  2  2  1  1 
3: 3  2  2  2  2  0 
+0

Не совсем. Я отвечал на него одновременно, и он использует логику из моего базового решения R. – lmo