【问题标题】:How to make type-stable function that selects subset of data.frame如何制作选择data.frame子集的类型稳定函数
【发布时间】:2018-01-17 10:36:59
【问题描述】:

我正在编写一个非常基本的函数,它检测具有特定名称的列,然后返回不包括这些列的表。我不知道什么是使这个函数类型稳定的最简洁的方法,其中它接受 data.frames 或 data.tables 并在它进入的同一个类中吐出结果表。

例如,我通常的工作流程是使用 data.table。

library(data.table)
dt <- data.table(names = sample(c("Ruby","Fire","Azure","Green"), 10, replace = T), age = 10:19, phone = 123456:123465)
df <- data.frame(names = sample(c("Ruby","Fire","Azure","Green"), 10, replace = T), age = 10:19, phone = 123456:123465)
detach("package:data.table")

removeAge <- function(db){
    ageCols <- grepl("age",names(db))
    db <- db[, !ageCols]
    return(db)
}

removeAge(df) # returns data.frame with age column removed
removeAge(dt) # returns vector of logical T,F,T

如何使我的示例中的removeAge 函数不知道输入表是data.frame 还是data.table?这个例子也将帮助我学习更复杂的功能。我假设一种方法是检查输入表类是否转换为 data.frame,但对于大型表,我猜这在计算上会很昂贵。

很想知道在这种情况下有什么好的做法。

谢谢!

【问题讨论】:

  • 如果传入函数的表不是 data.table 并且 R 会话没有加载 data.table 包,那么我的函数将无法工作。是否可以编写一行/两行代码来对 data.frame 或 data.table 输入的列进行子集
  • 编辑:实际上,只需替换该行,我就得到了两者的逻辑向量。
  • 没错,这是我的第一个想法。请参阅我的答案以获取解决方案;-)

标签: r data.table


【解决方案1】:

最简单的选择是将函数更改为:

removeAge <- function(db){
  ageCols <- grepl('age', names(db))
  db <- as.data.frame(db)[, !ageCols]
  return(db)
}

现在使用removeAge(df)removeAge(dt) 给出预期结果:

> removeAge(df) 
   names  phone
1   Ruby 123456
2  Azure 123457
3   Ruby 123458
4   Ruby 123459
5   Fire 123460
6  Azure 123461
7  Green 123462
8   Ruby 123463
9  Green 123464
10 Azure 123465

> removeAge(dt)
   names  phone
1  Azure 123456
2   Fire 123457
3  Green 123458
4  Azure 123459
5   Fire 123460
6  Green 123461
7  Azure 123462
8  Green 123463
9   Fire 123464
10 Azure 123465

要使用data.table-like 子集,您还可以将您的函数调整为:

removeAge <- function(db){
  nonAgeCols <- setdiff(names(db), 'age')
  db <- setDT(db)[, ..nonAgeCols]
  return(db)
}

如果您想保留data.tabledata.frame 的类,那么您可以将函数更改为:

removeAge <- function(db) {
  if (any(class(db) == 'data.table')) {
    nonAgeCols <- setdiff(names(db), 'age')
    db <- setDT(db)[, ..nonAgeCols]
    return(db)
  } else {
    ageCols <- grepl("age",names(db))
    db <- db[, !ageCols]
    return(db)
  }
}

根据输入的类返回 data.tabledata.frame

> class(removeAge(df))
[1] "data.frame"
> class(removeAge(dt))
[1] "data.table" "data.frame"

【讨论】:

  • @SehjKashyap Here you can find more on the ..-notation。它是去年推出的。
  • 非常感谢 Jaap。这真的很有帮助。我确实意识到您的两种解决方案都将输入表的类更改为一个特定的类。我不明白吗?我希望data.frame --> function --> data.frame,而data.table --> function --> data.table,或者通常对于任何类的表,它返回输入表。有没有办法做到这一点?
  • 我意识到的另一件事是,如果这是一个通过库而不是源函数加载的函数,那么在 data.table 上使用 data.frame 术语就没有问题,因为 data .tables 本身与 data.frame 函数兼容。另一方面,如果这是通过源加载的,则 data.frame 术语不起作用。是什么解释了同一函数的源加载与库加载之间的行为差​​异?
  • 你对 setDT 的使用也发送了一个追逐来弄清楚那是什么。看起来像一个很棒的功能,我可以在将来使用。谢谢!
  • @SehjKashyap 如果您使用source(your_R_file.R) 加载您的函数,请在该文件中也包含library(data.table)
猜你喜欢
  • 2018-01-19
  • 1970-01-01
  • 2011-03-22
  • 2013-08-14
  • 1970-01-01
  • 2021-10-03
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
相关资源
最近更新 更多