【问题标题】:Data frame rows to nested list elements by groups按组到嵌套列表元素的数据框行
【发布时间】:2018-08-09 19:39:27
【问题描述】:

我有一个这样的数据框

  id key value
1  x   a     1
2  x   b     2
3  y   a     3
4  y   b     4

read.table(text = "id   key value
x   a   1
x   b   2
y   a   3
y   b   4", header = TRUE, sep = "\t")

我想获得每个id 的列表以及每个key 的子列表

所以在我的例子中,预期的输出是:

$x
$x$a
$x$a$value
[1] 1

$x$b
$x$b$value
[1] 2

$y
$y$a
$y$a$value
[1] 3

$y$b
$y$b$value
[1] 4

list(
  x = list(
    a = list(value = 1), 
    b = list(value = 2)
  ), 
  y = list(
    a = list(value = 3), 
    b = list(value = 4)
  )
)

我可以通过嵌套的lapplysplit 来实现它,但我认为应该有更直接的方法来实现它。

任何帮助将不胜感激。

【问题讨论】:

  • 一般来说,您可以使用递归的split/lapply 来解决这个问题。例如。 (至少在这里):ff = function(x) if(is.data.frame(x)) lapply(split(x[, -1], x[[1]]), ff) else x; ff(dat); ff(cbind(dat[1:2], "value", dat[3])) 似乎有效
  • 感谢您的提示,它证实了我肯定应该有一个不错的purrr 解决方案
  • 如果我有一个附加列 value2 应该与 value 处于同一列表级别,你会怎么做:例如list(x = list(a = list(value1 = 1, value2 = 2)))
  • 您可以尝试将要递归的列数指定为参数:ff = function(x, nrec) if(nrec) lapply(split(x[-1], x[[1]]), ff, nrec - 1L) else as.list(x); ff(dat, 2); dat2 = cbind(dat, value2 = c(10, 20, 30, 40)); ff(dat2, 2)。我不确定这可以推广到什么程度

标签: r


【解决方案1】:

概述

两种方法(一种使用base,另一种使用plyr)按组拆分数据框,对每个组应用一个函数,然后以列表的形式返回结果。

使用base::split.data.frame() 后跟lapply() 为每个唯一的id-key 对提取value 元素。

# split data frame
# based on 'id' and 'key' pairs
df.split <-
    split.data.frame(
        x = df
        , f = list( df$id, df$key )
    )
# keep only the value
# element within each list
df.split <-
    lapply(
        X = df.split
        , FUN = function( i )
            i[["value"]]
    )

# view results
df.split
# $x.a
# [1] 1
# 
# $y.a
# [1] 3
# 
# $x.b
# [1] 2
# 
# $y.b
# [1] 4

# end of script #

使用plyr::dlply() 做同样的事情,而不需要lapply()

# load necessary packages
library( plyr )

# splits df by the 'id' and 'key' variables
# and return the 'value' for each pairing
df.split <-
    dlply( 
        .data = df
        , .variables = c( "id", "key" )
        , .fun = function(i) i[["value"]]
    )

# view results
df.split
# $x.a
# [1] 1
# 
# $x.b
# [1] 2
# 
# $y.a
# [1] 3
# 
# $y.b
# [1] 4
# 
# attr(,"split_type")
# [1] "data.frame"
# attr(,"split_labels")
# id key
# 1  x   a
# 2  x   b
# 3  y   a
# 4  y   b

# end of script #

@Colonel Beauvel 对 SO 帖子 Emulate split() with dplyr group_by: return a list of data frames 的回答有助于回答这个问题。

【讨论】:

  • 感谢您的回答,但您的解决方案并不是我想要的
【解决方案2】:

split 数量有限且嵌套*apply 的一种解决方案:

lapply(split(df, df$id), function(x) setNames(apply(x, 1L, function(x) as.list(x["value"])), x[["key"]]))

嵌套lapplysplit 替代:

lapply(split(df, df$id), function(x) lapply(split(x["value"], x$key), as.list))

欢迎改进!

【讨论】:

    猜你喜欢
    • 2020-03-06
    • 2021-12-11
    • 2021-04-29
    • 1970-01-01
    • 2018-03-06
    • 2020-05-21
    • 1970-01-01
    • 2015-03-11
    • 1970-01-01
    相关资源
    最近更新 更多