【问题标题】:Extracting data from lists of different levels using a function使用函数从不同级别的列表中提取数据
【发布时间】:2021-09-25 18:28:04
【问题描述】:

大家早上好。

我有一个函数,它使用列表作为参数,通过将元素提取到 df 中来生成不同的指标。但是,我打算使用的列表具有不同的层级,因此我不能在所有列表上都使用它。

我在下面给出一个例子(不是真正的功能):

# the function pulls out a df from a list
df_func <- function(list){
  
  df_temp <- list[[1]]
  
  return(df_temp)  
  
}

data("iris") 

list_a <- list("list_a" = iris, "list_b" = iris,
                     "list_c" = iris, "list_d" = iris)

list_b <- list()
list_b[["list_a"]] <- list_a
list_b[["list_b"]] <- list_a
list_b[["list_c"]] <- list_a
list_b[["list_d"]] <- list_a

df1 <- df_func(list_a) # correct (returns a df)
df2 <- df_func(list_b) # wrong (returns a list of dfs)

我知道问题在于,要从list_a 访问正确的元素,我们使用list_a[[1]],而要从list_b 提取正确的元素,我们必须使用list_b[[1]][[1]]

我的问题是,如何在函数中对此进行编码,以便 R 知道在哪里寻找我需要的 df?

感谢大家对新手的帮助。

【问题讨论】:

    标签: r list dataframe extract hierarchy


    【解决方案1】:

    考虑使用已经可用的递归函数,即rapply/rrapply

    df_func <- function(listObj) {
         rrapply::rrapply(listObj, classes = "data.frame", how = 'flatten')[[1]]
       }
    

    -测试

    > out1 <- df_func(list_a)
    > out2 <- df_func(list_b)
    > str(out1)
    'data.frame':   150 obs. of  5 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
     $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
     $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
     $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
    > str(out2)
    'data.frame':   150 obs. of  5 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
     $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
     $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
     $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
    

    【讨论】:

    • 这是一个创建递归函数。谢谢,我试过了,效果很好。
    【解决方案2】:

    如果您有一个列表列表(嵌套列表),您可以在函数中指定第二个参数(以及第三个、第四个等)以在嵌套列表中使用。

    df_func <- function(list, list2, index = 1){
        df_temp <- list[[list2]][[index]] # default index = 1
        return(df_temp)  
    }
    
    df_func(list_b, 1) # outputs `list_b[[1]][[1]]`
    df_func(list_b, 2) # outputs `list_b[[2]][[1]]`
    df_func(list_b, 2, 2) # outputs `list_b[[2]][[2]]`
    

    它不适用于list_a,因为它不是嵌套列表(也不是同一级别的嵌套列表)。对于更高级别的嵌套列表,您还需要更多参数。

    这是一种更高级的方法,不受任何特定嵌套级别的限制:

    df_func2 <- function(list, index = 1) {
        l <- paste0("[[",index,"]]", collapse="")
        l2 <- paste0(deparse(substitute(list)),l)
        df_temp <- eval(parse(text=l2))
        return(df_temp)
    }
    
    df_func2(list_a) # outputs `list_a[[1]]`
    df_func2(list_a, 2) # outputs `list_a[[2]]`
    df_func2(list_b, 1) # outputs `list_b[[1]]` (list of data frames)
    df_func2(list_b, c(1, 1)) # outputs `list_b[[1]][[1]]`
    df_func2(list_b, c(1, 2)) # outputs `list_b[[1]][[2]]`
    

    【讨论】:

    • 谢谢你。我没有想到。但是,我也希望能够访问list_a 的元素,这可以通过list_a[[1]] 完成。我怎样才能用相同的功能做到这两个?
    • 有没有办法用 IF 语句告诉 R 它是一个什么样的列表,即是否是嵌套列表,所以要使用适当的方法?有没有给出列表级别的函数?
    • @DM - 需要明确的是,您是否只想要 get 并且始终是列表的第一个索引(多层嵌套与否)(即,@987654326 中始终为“1” @),还是希望每个索引都是可选的/函数中的参数?
    • 可以在函数内部通过 for 循环选择索引(我不喜欢使用 apply 系列函数)。因此,基本上,我遍历列表的整个长度,并在每次迭代时提取列表内的 df 并使用它。
    • 但是,我想我找到了解决该问题的方法,使用if 语句检查list[[1]] 列表中的nrow。如果它返回某些内容,则意味着它不是嵌套列表。如果它返回null,那么它是一个嵌套列表,因为nrow 不能用于列表。
    【解决方案3】:

    使用递归函数怎么样?

    df_func <- function(list){
      tmp <- list[[1]]
      if(class(tmp) == 'list') {
        df_func(tmp)
      } else tmp
    }
    

    【讨论】:

    • 这是我正在寻找的函数 (class)。我是 R 新手,所以我没有想到 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-01
    • 2012-10-19
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 2023-04-01
    相关资源
    最近更新 更多