【问题标题】:using column numbers for grouping in data table rather than names in R使用列号在数据表中进行分组,而不是在 R 中使用名称
【发布时间】:2016-08-11 19:27:45
【问题描述】:

我的代码需要灵活,我不能在分组时在列名中硬编码。因此,我想对列号进行硬编码以进行分组,因为这些很容易指定超出范围的更改。 (第 1 列到 X 左右,而不是使用 cols 1,2,..X 的名称)

示例数据集:

set.seed(007) 
DF <- data.frame(X=1:20, Y=sample(c(0,1), 20, TRUE), Z=sample(0:5, 20, TRUE), Q =sample(0:5, 20, TRUE))



 DF
    X Y Z Q
1   1 1 3 4
2   2 0 1 2
3   3 0 5 4
4   4 0 5 2
5   5 0 5 5
6   6 1 0 1
7   7 0 3 0
8   8 1 2 4
9   9 0 5 5
10 10 0 2 5
11 11 0 4 3
12 12 0 1 4
13 13 1 1 4
14 14 0 1 3
15 15 0 2 4
16 16 0 5 2
17 17 1 2 0
18 18 0 4 1
19 19 1 5 2
20 20 0 2 1

一个分组(由 Z 和 Q)找到最大化 Y 的 X,并返回两者:

    DF =data.table(DF)
    DF[, list(Y=max(Y),X=X[which.max(Y)]), by=list(Z, Q)]

结果:

        DF[, list(Y=max(Y),X=X[which.max(Y)]), by=list(Z, Q)]
    Z Q Y  X
 1: 3 4 1  1
 2: 1 2 0  2
 3: 5 4 0  3
 4: 5 2 1 19
 5: 5 5 0  5
 6: 0 1 1  6
 7: 3 0 0  7
 8: 2 4 1  8
 9: 2 5 0 10
10: 4 3 0 11
11: 1 4 1 13
12: 1 3 0 14
13: 2 0 1 17
14: 4 1 0 18
15: 2 1 0 20

由于我的代码的性质,我想纯粹使用列号来执行此操作。此外,如果还有另一列,我可能希望按该额外列进行分组。而且我还想在第一部分中返回另一个 argmax。

【问题讨论】:

  • 最好不要使用列号,但如果需要,您可能需要对名称进行子集化,即setDT(DF)[, list(Y=max(Y),X=X[which.max(Y)]), by = c(names(DF)[3:4])]
  • @akrun 我还需要 X 和 Y 部分基于列名,因为我使用的列名必须取决于我正在运行的许多模拟的规范。实现这一点非常困难...... –
  • 您可以简单地保存原始列名,将它们临时重命名为预定约定,然后在分组后将原始列名写回。这可以通过编程来完成,以允许任意数量的列名。
  • 你的意思是像下面的解决方案@Hack-R?问题是我希望它也适用于 X 和 Y。
  • 我猜也可以DF[, list(Y=max(.SD[[2]]),X=.SD[[1]][which.max(.SD[[2]])]), by=c(names(DF)[3:4])]。另外,请不要DF =data.table(DF)。只需setDT(DF) 或首先使用DF &lt;- data.table(... 创建数据集即可

标签: r matrix data.table grouping


【解决方案1】:

也许只是选择带有列号的names(DF),再加上eval(parse(...))

useColNums <- function(data, a, b) {
  n <- names(data) 
  y <- n[a[1]]
  x <- n[a[2]]
  groupby <- sprintf("list(%s)", paste(n[b], collapse=","))
  argmax <-  sprintf("list(%1$s=max(%1$s),%2$s=%2$s[which.max(%1$s)])", y, x)
  data[, eval(parse(text=argmax)), by=eval(parse(text=groupby))]  
}

x <- useColNums(DF, 2:1, 3:4)
y <- DF[, list(Y=max(Y),X=X[which.max(Y)]), by=list(Z, Q)]
identical(x, y)
# [1] TRUE

【讨论】:

  • 谢谢。我已经修改了答案,以便 b 可以是任意数量的分组列。
【解决方案2】:

您找到适合您的答案了吗?像这样的东西是可能的,但它并不漂亮,这可能意味着它很难维护:

DF[, list(Y=max(eval(as.symbol(colnames(DF)[2]))),
          X=eval(as.symbol(colnames(DF)[1]))[which.max(eval(as.symbol(colnames(DF)[2])))]),
          by=list(Z=eval(as.symbol(colnames(DF)[3])),
                  Q=eval(as.symbol(colnames(DF)[4])))]

现在您可以将这些 as.symbol(colnames()) 放入一个函数中并使其更易于阅读:

cn <- function( dt, col ) { as.symbol(colnames(dt)[col]) }

DF[, list(Y=max(eval(cn(DF,2))),
          X=eval(cn(DF,1))[which.max(eval(cn(DF,2)))]),
          by=list(Z=eval(cn(DF,3)), Q=eval(cn(DF,4)))]

这是否为您解决了按列号分组的问题?

【讨论】:

  • 它没有解决问题,因为 Y 和 X 仍然不是列名
  • @robertevansanders 我以为你只是想按列号分组,这就是我只做这些列的原因。使用相同的eval(as.symbol(colnames())) 函数,我将所有列名替换为已编辑答案中的数字。
【解决方案3】:

您可以将grep 与您的代码结合使用:

> set.seed(007) 
> DF <- data.frame(X=1:20, Y=sample(c(0,1), 20, TRUE), Z=sample(0:5, 20, TRUE), Q =sample(0:5, 20, TRUE))
> DF = data.table(DF)
> coly <- na
> DF[, list(Y=max(Y),X=X[which.max(Y)]), by=c(col1 <- names(DF)[grep("Q", colnames(DF))], names(DF)[grep("Z", colnames(DF))])]
    Q Z Y  X
 1: 4 3 1  1
 2: 2 1 0  2
 3: 4 5 0  3
 4: 2 5 1 19
 5: 5 5 0  5
 6: 1 0 1  6
 7: 0 3 0  7
 8: 4 2 1  8
 9: 5 2 0 10
10: 3 4 0 11
11: 4 1 1 13
12: 3 1 0 14
13: 0 2 1 17
14: 1 4 0 18
15: 1 2 0 20 

【讨论】:

  • 想让 X 和 Y 也成为列数 :(
猜你喜欢
  • 1970-01-01
  • 2011-12-06
  • 2021-09-09
  • 2013-07-11
  • 2017-11-07
  • 1970-01-01
  • 2018-03-08
  • 2021-04-16
相关资源
最近更新 更多