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

时间:2018-08-05 14:01:48

标签: r list data-manipulation

我试图将列拆分为多个拆分数据框中的行名,然后在所有数据框中应用一个函数? (长度不等)我得到了下面的代码中嵌入的错误。我可以解决这个问题吗?

# 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 个答案:

答案 0 :(得分:3)

使用修改后的数据(见下文),这是一个解决方案。

可能的主要问题在于您的数据。按照规定,您的x列中有很多NA,我假设x应该已经回收了。然后vegan::contribdiv()至少需要两个维度,并且您只在数据中提供一行。此外,它需要数字,并且只能应用于列1:2。在使用as.data.frame(sitebyspec.split)的代码中,您试图将一个列表变成一个数据框,我认为这不是您想要的,并且会导致错误。

首先,使用lapply()ID列转换为行名。

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

第二,使用lapply()将函数应用于列表。

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))

答案 1 :(得分:1)

由于对象是std::allocate_shared(),因此我们可以使用list遍历list,然后在OP的帖子中应用这些功能

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

注意:OP将{x1,'y'列创建为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 ,而应该是factor

数据

numeric

答案 2 :(得分:1)

考虑基数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)