将 tag/label/attr/attribute 添加到数据框列(变量)

Add tag/label/attr/attribute to dataframe columns (variables)

我发现在 attributes/tags/labels 领域或对数据帧中的列调用的任何内容中产生的混淆很奇怪。

问题很简单:我有一个包含案例(行)和变量(列)的数据框(我们称之为 StackedDataStd)。每列都有一个名称,您可以通过许多不同的方式访问它(恕我直言,有 10 种方法可以完成相同的任务,这会让一切变得更加混乱...)

当我删除列时,相应的名称也会从属性中删除。

现在我有很多其他标签来识别所用变量的类型...让我们以 bw 标签为例(一个整数,在我的例子中是 1,2, 4,8 或 16).每列都有自己的 bw,我想要的是 select,比方说,所有 bw==1.

的列

此刻我做了一个我称之为 selector (selectorBw) 的东西:一个长度为 dim(stackedDataStd)2 的向量,每列的 bw 值。

通过使用 stackedDataStd[selectorBw == 1] 我 select bw==1.

但是,每次我删除一列时,我都必须记住删除 selector 中的相应位置(并且有 10 个 selector 开始变得一团糟)。

stackedDataStd[,-4]
selectorBw[-4]

我尝试通过几种方式添加属性:

attr(stackedDataStd,'bw') <- selectorBw

添加属性,但它不像 colnames 那样链接到列。如果我删除一列 (stackedDataStd$segN <- c()),该属性不会被删除。如果我使用 stackedDataStd <- stackedDataStd[-1] 删除属性消失...(魔术)。

Here 建议将属性分配给列表的每个元素:

for (i in seq_along(stackedDataStd)) { attr(stackedDataStd[[i]], "bw") <- selectorBw[i] }

但它不能与整个数据框一起使用,因为它不是数据框属性(我应该为每个 selection 的每个变量循环)。

我试过其他方法,但我不想用我的尝试打扰你....

你有什么建议吗?也许 Hmisc package?如果可能的话,我不想使用非标准数据框。

如果您想使用属性在数据框中构建额外的功能但不指定新的 S3 class,您必须在其他地方定义该功能。通过添加一个属性 setter、一个属性 getter 和一个小的子集函数,这真的很容易做到:

# Subsetter
ss <- function(df, bw) df[sapply(df, function(x) attr(x, "bw") == bw)]

# Gets attributes as vector
get_col_attr <- function(df) sapply(df, attr, "bw")

# Sets attributes to columns from a single vector
set_col_attr <- function(df, attrs)
{
  as.data.frame(mapply(function(col, bw) {
                         attr(col, "bw") <- bw
                         col
                         }, df, attrs, SIMPLIFY = FALSE))
}

我认为这很好用。假设我们创建了一个包含两个数字列和两个字符列的小数据框,我们希望为这些列提供属性 c(1, 1, 2, 2)。我们可以这样做:

df  <- data.frame(A = 1:5, B = 6:10, C = LETTERS[1:5], D = letters[1:5])
df  <- set_col_attr(df, c(1, 1, 2, 2))

这看起来和行为仍然像一个普通的数据框:

df
#>   A  B C D
#> 1 1  6 A a
#> 2 2  7 B b
#> 3 3  8 C c
#> 4 4  9 D d
#> 5 5 10 E e

但是我们可以看到每一列都有一个bw属性:

get_col_attr(df)
#> A B C D 
#> 1 1 2 2

我们可以很容易地使用这个属性进行子集化:

ss(df, bw = 2)
#>   C D
#> 1 A a
#> 2 B b
#> 3 C c
#> 4 D d
#> 5 E e

ss(df, bw = 1)
#>   A  B
#> 1 1  6
#> 2 2  7
#> 3 3  8
#> 4 4  9
#> 5 5 10

至关重要的是,如果我们对数据框进行子集化,属性也会适当地进行子集化:

df2 <- df[, 2:3]

get_col_attr(df2)
#> B C 
#> 1 2

reprex package (v0.3.0)

于 2020-07-03 创建

按照@Allan Cameron 的建议,我编写了自己的函数来管理标签。

带着不可忽视的痛苦,我对他的代码做了一个小的编辑,以允许显式声明更多标签,并且我在主数据框中添加了一个字段,其中包含所有标签的名称。 如果您对如何改进它有进一步的建议,请随时回答我。

注意:子集删除了主 df 中的属性 'tags'。

# Subsetter
ss <- function(df, tag, val) { 
  if(!is.data.frame(df) | dim(df)[2] < 1 | is.null(attr(df[[1]], tag))) { 
    data.frame() 
  } else {
      df[sapply(df, function(x) attr(x, tag) == val)] 
  }
}

# Gets attributes as vector
get_col_attr <- function(df,tag = 'all') {
  if(tag!='all') {
    sapply(df, function(x) attr(x, tag))
  } else {
    as.data.frame(mapply(function(z) sapply(attr(df,'tags'), function(x) attr(z,x)), df, SIMPLIFY =F))
  }
}
  

# Sets attributes to columns from a single vector
set_col_attr <- function(df,tag, attrs)
{
  outdf <- as.data.frame(mapply(function(col, tagName, bw) {
    attr(col, tagName) <- bw
    col
  }, df, tag, attrs, SIMPLIFY = FALSE))
  attr(outdf,'tags') <- unique(c(attr(df,'tags'),tag))
  outdf
}