gpt4 book ai didi

r - 按 data.table 中的列表列子集快速分组

转载 作者:行者123 更新时间:2023-12-04 15:24:34 25 4
gpt4 key购买 nike

我正在处理一个大型(数百万行)数据表,其中包含一个包含深度嵌套列表的列表列,这些列表没有统一的结构、大小或元素顺序(list(x=1,y=2)list(y=2,x=1) 可能都存在并且应该被视为相同)。我需要重复执行任意分组,包括数据表中的一些列以及列表列中的数据子集。并非所有行都具有与子集匹配的值。

我提出的方法感觉过于复杂。以下是关键点:

  • 识别嵌套列表结构中的值。 我的方法是使用 ul <- unlist(list_col) ,它“扁平化”嵌套数据结构并构建层次名称以直接访问每个元素,例如 address.country.code
  • 从分组的角度确保相同未列出数据的排列被认为是相等的。 我的方法是通过 ul[order(names(ul))] 按值的名称对未列出的向量进行排序,并通过引用将结果分配为新的字符向量列。
  • 对展平值的子集执行分组。 我无法让 by= 以任何方式处理值为列表或向量的列。因此,我必须找到一种将唯一字符向量映射到简单值的方法。我用 digest 做到了这一点。

  • 这是两个主力函数:
    # Flatten list column in a data.table
    flatten_list_col <- function(dt, col_name, flattened_col_name='props') {

    flatten_props <- function(d) {
    if (length(d) > 0) {
    ul <- unlist(d)
    names <- names(ul)
    if (length(names) > 0) {
    ul[order(names)]
    } else {
    NA
    }
    } else {
    NA
    }
    }

    flattened <- lapply(dt[[col_name]], flatten_props)
    dt[, as.character(flattened_col_name) := list(flattened), with=F]
    }

    # Group by properties in a flattened list column
    group_props <- function(prop_group, prop_col_name='props') {
    substitute({
    l <- lapply(eval(as.name(prop_col_name)), function(x) x[names(x) %in% prop_group])
    as.character(lapply(l, digest))
    }, list(prop_group=prop_group, prop_col_name=prop_col_name))
    }

    这是一个可重现的示例:
    library(data.table)

    dt <- data.table(
    id=c(1,1,1,2,2,2),
    count=c(1,1,2,2,3,3),
    d=list(
    list(x=1, y=2),
    list(y=2, x=1),
    list(x=1, y=2, z=3),
    list(y=5, abc=list(a=1, b=2, c=3)),
    NA,
    NULL
    )
    )

    flatten_list_col(dt, 'd')
    dt[, list(total=sum(count)), by=list(id, eval(group_props(c('x', 'y'))))]

    输出是:
    > flatten_list_col(dt, 'd')
    id count d props
    1: 1 1 <list> 1,2
    2: 1 1 <list> 1,2
    3: 1 2 <list> 1,2,3
    4: 2 2 <list> 1,2,3,5
    5: 2 3 NA NA
    6: 2 3 NA

    > dt[, list(total=sum(count)), by=list(id, eval(group_props(c('x', 'y'))))]
    id group_props total
    1: 1 325c6bbb2c33456d0301cf3909dd1572 4
    2: 2 7aa1e567cd0d6920848d331d3e49fb7e 2
    3: 2 ee7aa3b9ffe6bffdee83b6ecda90faac 6

    这种方法有效但效率很低,因为需要对列表进行展平和排序,并且需要计算摘要。我想知道以下几点:
  • 是否可以通过直接从列表列中检索值而无需创建扁平列来完成此操作?这可能需要将选定的属性指定为表达式而不是简单的名称。
  • 有没有办法解决对 digest 的需求?
  • 最佳答案

    这里有很多问题。最重要的(也是由于其他原因你还没有来​​过)是你通过引用赋值,但试图用比你有空间来引用的值更多的值来替换。

    举这个非常简单的例子

    DT <- data.table(x=1, y = list(1:5))
    DT[,new := unlist(y)]
    Warning message:
    In `[.data.table`(DT, , `:=`(new, unlist(y))) :
    Supplied 5 items to be assigned to 1 items of column 'new' (4 unused)

    除了第一个 nrow(DT),你将失去所有新创建的列表中的项目。它们不会对应于 data.table 的行

    因此,您必须创建一个新的 data.table这将足以让您分解这些列表变量。这是不可能的。
     newby <- dt[,list(x, props = as.character(unlist(data))), by = list(newby = seq_len(nrow(dt)))][,newby:=NULL]
    newby


    x props
    1: 1 1
    2: 1 2
    3: 1 2
    4: 1 1
    5: 1 10
    6: 2 1
    7: 2 2
    8: 2 3
    9: 2 5
    10: 2 1
    11: 2 2
    12: 2 3
    13: 3 NA
    14: 3 NA

    请注意,需要 as.character 以确保所有值的类型相同,并且类型不会在转换中丢失数据。此刻你有一个合乎逻辑的 NA数值/整数数据列表中的值。

    另一个编辑强制所有组件都是字符(甚至是 NA)。 props 现在是一个列表,每行有 1 个字符向量。

    flatten_props <- 函数(数据){
    如果(is.list(数据)){
    ul <- 取消列表(数据)
    如果(长度(ul)> 1){
    ul <- ul[order(names(ul))]
    }
    as.character(ul) } else {
    as.character(unlist(data))}}
    dt[, props := lapply(data, flatten_props)]
    dt
    x data props
    1: 1 <list> 1,2
    2: 1 <list> 10,1,2
    3: 2 <list> 1,2,3
    4: 2 <list> 1,2,3,5
    5: 3 NA NA
    6: 3

    dt[,lapply(props,class)]
    V1 V2 V3 V4 V5 V6
    1: character character character character character character

    关于r - 按 data.table 中的列表列子集快速分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13983874/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com