将 tag/label/attr/attribute 添加到数据框列(变量)
Add tag/label/attr/attribute to dataframe columns (variables)
我发现在 attributes/tags/labels 领域或对数据帧中的列调用的任何内容中产生的混淆很奇怪。
问题很简单:我有一个包含案例(行)和变量(列)的数据框(我们称之为 StackedDataStd)。每列都有一个名称,您可以通过许多不同的方式访问它(恕我直言,有 10 种方法可以完成相同的任务,这会让一切变得更加混乱...)
colnames(stackedDataStd)
名称(stackedDataStd)
标签(stackedDataStd)2
attr(stackedDataStd,'names')
属性(stackedDataStd)$名称
[1] "segN" "patN" "Elongation" "Flatness" "LeastAxisLength"
[6] "MajorAxisLength" "Maximum2DDiameterColumn" "Maximum2DDiameterRow" "Maximum2DDiameterSlice" "Maximum3DDiameter"
[11] "MeshVolume" "MinorAxisLength" "Sphericity" "SurfaceArea" "SurfaceVolumeRatio"
[16] "VoxelVolume"
当我删除列时,相应的名称也会从属性中删除。
现在我有很多其他标签来识别所用变量的类型...让我们以 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
}
我发现在 attributes/tags/labels 领域或对数据帧中的列调用的任何内容中产生的混淆很奇怪。
问题很简单:我有一个包含案例(行)和变量(列)的数据框(我们称之为 StackedDataStd)。每列都有一个名称,您可以通过许多不同的方式访问它(恕我直言,有 10 种方法可以完成相同的任务,这会让一切变得更加混乱...)
colnames(stackedDataStd)
名称(stackedDataStd)
标签(stackedDataStd)2
attr(stackedDataStd,'names')
属性(stackedDataStd)$名称
[1] "segN" "patN" "Elongation" "Flatness" "LeastAxisLength" [6] "MajorAxisLength" "Maximum2DDiameterColumn" "Maximum2DDiameterRow" "Maximum2DDiameterSlice" "Maximum3DDiameter" [11] "MeshVolume" "MinorAxisLength" "Sphericity" "SurfaceArea" "SurfaceVolumeRatio" [16] "VoxelVolume"
当我删除列时,相应的名称也会从属性中删除。
现在我有很多其他标签来识别所用变量的类型...让我们以 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
}