【问题标题】:Duplicate data.table rows from formatted string column格式化字符串列中的重复 data.table 行
【发布时间】:2016-08-16 23:02:20
【问题描述】:

问题:

在 R 中转换 data.table 的最佳方法是什么,如下所示:

> input
   id value        node
1:  1   foo       node3
2:  2   bar   node[2,4]
3:  3   qux   node[2-4]
4:  4   foo node[1-2,4]

变成这样:

> output
   id value  node
1:  1   foo node3
2:  2   bar node2
3:  2   bar node4
4:  3   qux node2
5:  3   qux node3
6:  3   qux node4
7:  4   foo node1
8:  4   foo node2
9:  4   foo node4

示例输入和输出:

input <- data.table(id = c(1,2,3,4), value = c("foo", "bar", "qux", "foo"), node = c("node3","node[2,4]","node[2-4]","node[1-2,4]"))

output <- data.table(id = c(1,2,2,3,3,3,4,4,4), value = c("foo","bar","bar","qux","qux","qux","foo","foo","foo"), node = c("node3", "node2", "node4", "node2", "node3", "node4", "node1", "node2", "node4"))

背景:

我正在从一组机器中提取作业日志,这些日志与上面的输入类似。 id 对应于作业 id,值对应于特定的可执行文件,节点对应于集群中实际执行作业的机器。日志使用节点列的压缩格式来表示作业在哪些机器上运行。

使用library(stringr),我编写了一些丑陋的代码来部分解析节点列。也许这是一个有用的起点:

  expand_node <- function(nodes)
  {
    tokens <- str_match(nodes, "\\[([0-9,\\-]+)\\]")[ ,2]
    tokens <- str_replace_all(tokens, "\\-", ":")
    tokens <- paste0("c(",tokens,")")
    result <- lapply(tokens, function(expr) eval(parse(text = expr)))
    return(result)
  }

【问题讨论】:

  • 节点数是否超过10?
  • 不幸的是,确实如此。
  • 如果我遇到这个问题,我可能会采取与您类似的方法。

标签: r data.table


【解决方案1】:

这里有一个data.table 选项,您可以尝试一下,使用正则表达式可以少一步:

input[, .(node = unlist(lapply(sub("node\\[?([0-9,:]+)\\]?", "c(\\1)", gsub("-", ":", node)), 
          function(expr) paste("node", eval(parse(text = expr)), sep = "")))), .(id, value)]

#   id value  node
#1:  1   foo node3
#2:  2   bar node2
#3:  2   bar node4
#4:  3   qux node2
#5:  3   qux node3
#6:  3   qux node4
#7:  4   foo node1
#8:  4   foo node2
#9:  4   foo node4

【讨论】:

  • 不需要lapply 的东西:input[, .(node = paste0( "node", eval(parse(text = sub("node\\[?([0-9,:]+)\\]?", "c(\\1)", gsub("-", ":", node)) )) )), by = .(id, value)]
  • @Frank 如果一个组的数据有多行但看起来每行都有一个唯一的 ID,这会导致一些问题。您的方法可能更适合 OP 的数据。
  • 很好地使用了内置的正则表达式功能,很棒的data.table 魔法!另外,我总是可以添加一个unique id 列。
【解决方案2】:

这是在更改“节点”列后使用cSplit 的选项

library(stringr)
library(splitstackshape)
library(gsubfn)
input[, node := lapply(str_extract_all(gsubfn("(\\d+)-(\\d+)", 
     ~seq(as.numeric(x), as.numeric(y), by = 1), node), "[0-9]+"), 
        function(x) paste0("node", x, collapse=","))]
cSplit(input, "node", ",", "long")
#   id value  node
#1:  1   foo node3
#2:  2   bar node2
#3:  2   bar node4
#4:  3   qux node2
#5:  3   qux node3
#6:  3   qux node4
#7:  4   foo node1
#8:  4   foo node2
#9:  4   foo node4

【讨论】:

  • 我正在研究同样的想法并且正在做类似input.df %&gt;% separate_rows(new1, sep = ',') %&gt;% select(id, value, new1) ... :)
猜你喜欢
  • 1970-01-01
  • 2013-12-10
  • 2015-01-07
  • 1970-01-01
  • 2017-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-05-17
  • 2014-09-24
相关资源
最近更新 更多