【问题标题】:Number of different values per column in a split list拆分列表中每列不同值的数量
【发布时间】:2017-05-12 23:38:33
【问题描述】:

我的数据集中的每一行都是不同的树。 Plot 是指采样区域(其中大约有 700 个),Species 是树的种类,其他列是树是否存在(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 不考虑不同的图。当我有一个拆分列表时,我不确定如何使用应用功能。

欢迎提出任何建议! 谢谢

【问题讨论】:

  • 我认为rowsum(df[-(1:2)], group=df$lot, na.rm=TRUE) 会做到这一点,尽管它与您的总和不太相符。例如,1988 的第三个元素是 3 而不是 2。
  • @Imo 似乎主要工作,但它似乎添加了实际值,而不是存在的不同值的数量。 1988 的第三个元素应该是 2,因为存在两种不同的物种(15 和 11)
  • @Henrik 你是对的!为那里的错误道歉,将编辑它

标签: r split apply


【解决方案1】:

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

【讨论】:

  • 我喜欢这种方法,我还没有遇到过!但是它似乎是在添加值的数量,而不是存在的不同物种的数量 - 您输出中的最后一行与我想要的输出不匹配。
  • 您想要的输出与您的数据不符,这导致我认为您想要对所有存在的物种进行总体计数(参见 plot1 1988,当存在 2 个物种时值为 3)。我已经包含了唯一计数的代码。
  • 第二位对我来说非常有用,非常感谢!
【解决方案2】:

我们可以通过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

【讨论】:

    【解决方案3】:

    计算与接受的答案相同的几个备选方案。在使用 split-apply-combine 方法的基础 R 中,您会得到

    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 列表,然后遍历每个 year 变量。这里,do.callrbind 返回一个矩阵。

    您可以使用rbind.data.framesetNames 来返回一个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
    

    【讨论】:

    • 并非如此。我同时回答它,它使用了我的基本 R 解决方案中的逻辑。
    猜你喜欢
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 2022-12-21
    • 2019-01-06
    • 2020-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多