代码之家  ›  专栏  ›  技术社区  ›  ecology

如何在多个拆分数据帧中将列强制为行名,然后对所有(长度不等的)数据帧应用函数?

  •  1
  • ecology  · 技术社区  · 6 年前

    我试图在多个拆分数据帧中将列强制为行名,然后对所有数据帧应用函数?(不等长度)我得到了嵌入在下面代码中的错误。我能过去工作吗?

    # sample dataset below
    
    ID <- c("SB1","SB2","SB3","SB4","SB1","SB1","SB2","SB4","SB2", "SB1")
    z <- c("A","B","C","D","E","A","B","C","D","D")
    x <- 1:2
    y <- 1:10
    n <- max(length(x), length(y))
    year <- c(1999,1999,1999,1999,2000,2001,2000,2001,2001,2002)
    length(x) <- n                      
    length(y) <- n
    length(z) <- n
    length(year) <- n
    sitebyspec <- cbind(ID,x,y,z,year)
    sitebyspec <- as.data.frame(sitebyspec)
    
    
    # my process (split df by year, force ID column to rownames)
    sitebyspec.split <- split(sitebyspec, (sitebyspec$year)) # split based on season
    as.data.frame(sitebyspec.split) %>% remove_rownames %>% column_to_rownames(var="ID")
        ## Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : arguments imply differing number of rows: 4, 2, 3, 1
    
    # my next step if this worked ... 
    sitebyspec.split %>%
      sitebyspec.split[,c(1:3)] %>%
      map(~ contribdiv(., "richness")) %>%
      map(summary)
    

    我可以将列与行名集成到最后一步吗?

    3 回复  |  直到 6 年前
        1
  •  1
  •   Parfait    6 年前

    考虑R基 by . 不像 split ,可以直接在子设置的数据帧上传递函数:

    proc_df <- function(df) df %>% remove_rownames %>% column_to_rownames(var="ID")
    
    df_list <- by(sitebyspec, sitebyspec$year, proc_df)
    
    df_list
    # sitebyspec$year: 1999
    #     x y z year
    # SB1 1 1 A 1999
    # SB2 2 2 B 1999
    # SB3 1 3 C 1999
    # SB4 2 4 D 1999
    # ---------------------------------------------------------------------------- 
    # sitebyspec$year: 2000
    #     x y z year
    # SB1 1 5 E 2000
    # SB2 1 7 B 2000
    # ---------------------------------------------------------------------------- 
    # sitebyspec$year: 2001
    #     x y z year
    # SB1 2 6 A 2001
    # SB4 2 8 C 2001
    # SB2 1 9 D 2001
    # ---------------------------------------------------------------------------- 
    # sitebyspec$year: 2002
    #     x  y z year
    # SB1 2 10 D 2002
    

    对于扩展功能,

    proc_df <- function(df) {
        tryCatch({df %>% 
                   remove_rownames %>% 
                   column_to_rownames(var="ID") %>%
                   select(1:2) %>%
                   contribdiv(., "richness")
                 }, error = function(e) NA)
    }
    
    df_list <- by(sitebyspec, sitebyspec$year, proc_df)
    
        2
  •  3
  •   jay.sf    6 年前

    有了修改后的数据(见下文),这里有一个解决方案。

    可能主要问题在于你的数据。如前所述,您的 x 列,我假设 应该自己回收的。那么 vegan::contribdiv() 希望至少有两个维度,并且您只在数据中提供一行。此外,它需要数字,并且只能应用于列 1:2 . 在你的代码中 as.data.frame(sitebyspec.split) ,您正在尝试将列表转换为数据帧,我认为您不希望这样做,并导致错误。

    首先,使用 lapply() 改变 ID 列为行名。

    sitebyspec.split <- lapply(sitebyspec.split, function(x) "rownames<-"(x, x[, 1])[, -1])
    

    第二,使用 拉普莱() 将您的函数应用于列表。

    library(vegan)
    sitebyspec.result <- lapply(sitebyspec.split, function(x) contribdiv(x[, 1:2], "richness"))
    

    结果

    > sitebyspec.result
    $`1999`
            alpha beta     gamma
    SB1 0.6666667    0 0.6666667
    SB2 0.6666667    0 0.6666667
    SB3 0.6666667    0 0.6666667
    
    $`2000`
        alpha beta gamma
    SB4     1    0     1
    SB1     1    0     1
    
    $`2001`
            alpha beta     gamma
    SB1 0.6666667    0 0.6666667
    SB2 0.6666667    0 0.6666667
    SB4 0.6666667    0 0.6666667
    
    $`2002`
        alpha beta gamma
    SB2     1    0     1
    SB1     1    0     1
    

    数据

    sitebyspec <- data.frame(ID=c("SB1", "SB2", "SB3", "SB4", "SB1", "SB1", "SB2", "SB4", "SB2", "SB1"), 
                             x=1:2, 
                             y=1:10, 
                             z=c("A", "B", "C", "D", "E", "A", "B", "C", "D", "D"), 
                             year=c(1999, 1999, 1999, 2000, 2001, 2000, 2001, 2001, 2002, 2002))
    
        3
  •  1
  •   akrun    6 年前

    因为物体是 list ,我们可以循环通过 列表 具有 map 然后应用操作程序中的函数

    sitebyspec.split %>% 
           map(~ .x %>% 
                    remove_rownames %>% 
                    column_to_rownames(var = "ID"))
    #$`1999`
    #    x y z year
    #SB1 1 1 A 1999
    #SB2 2 2 B 1999
    #SB3 1 3 C 1999
    
    #$`2000`
    #    x y z year
    #SB4 2 4 D 2000
    #SB1 2 6 A 2000
    
    #$`2001`
    #    x y z year
    #SB1 1 5 E 2001
    #SB2 1 7 B 2001
    #SB4 2 8 C 2001
    
    #$`2002`
    #    x  y z year
    #SB2 1  9 D 2002
    #SB1 2 10 D 2002
    

    这个 contribdv 函数可以应用于同一个链

    library(vegan)
    sitebyspec.split %>% 
        map(~ .x %>% 
                 remove_rownames %>% 
                 column_to_rownames(var = "ID") %>% 
                 select(1:2) %>% 
                 contribdiv(., "richness"))
    #$`1999`
    #        alpha beta     gamma
    #SB1 0.6666667    0 0.6666667
    #SB2 0.6666667    0 0.6666667
    #SB3 0.6666667    0 0.6666667
    
    #$`2000`
    #    alpha beta gamma
    #SB4     1    0     1
    #SB1     1    0     1
    
    #$`2001`
    #        alpha beta     gamma
    #SB1 0.6666667    0 0.6666667
    #SB2 0.6666667    0 0.6666667
    #SB4 0.6666667    0 0.6666667
    
    #$`2002`
    #    alpha beta gamma
    #SB2     1    0     1
    #SB1     1    0     1
    

    注意:OP将“x”、“y”列创建为 factor s,应该是 numeric

    数据

    sitebyspec <- structure(list(ID = structure(c(1L, 2L, 3L, 4L, 1L, 1L, 2L, 4L, 
     2L, 1L), .Label = c("SB1", "SB2", "SB3", "SB4"), class = "factor"), 
    x = c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L), y = 1:10, 
    z = structure(c(1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 4L), .Label = c("A", 
    "B", "C", "D", "E"), class = "factor"), year = c(1999, 1999, 
    1999, 2000, 2001, 2000, 2001, 2001, 2002, 2002)), .Names = c("ID", 
     "x", "y", "z", "year"), row.names = c(NA, -10L), class = "data.frame")