如何从data.frame中删除行而不会丢失属性

时间:2012-05-01 20:55:32

标签: r statistics

对于初学者:我现在在这个问题上搜索了几个小时 - 所以如果答案应该是微不足道的,请原谅我......

我想要做的是从data.frame中删除一行(编号101)。它包含测试数据,不应出现在我的分析中。我的问题是:每当我从data.frame中进行子集化时,属性(特别是注释)都会丢失。

str(x)
# x has comments for each variable
x <- x[1:100,]
str(x)
# now x has lost all comments

有充分证据表明,子集将丢弃所有属性 - 到目前为止,它非常清楚。手册(例如http://stat.ethz.ch/R-manual/R-devel/library/base/html/Extract.data.frame.html)甚至建议了一种保留属性的方法:

## keeping special attributes: use a class with a
## "as.data.frame" and "[" method:


as.data.frame.avector <- as.data.frame.vector

`[.avector` <- function(x,i,...) {
  r <- NextMethod("[")
  mostattributes(r) <- attributes(x)
  r
}

d <- data.frame(i= 0:7, f= gl(2,4),
                u= structure(11:18, unit = "kg", class="avector"))
str(d[2:4, -1]) # 'u' keeps its "unit"

到目前为止,我还不知道究竟发生了什么。但是,只需运行这些行(除了最后三行)不会改变我的子集的行为。使用带有适当向量的命令subset()(100次TRUE + 1 FALSE)给出了相同的结果。简单地将属性存储到变量并在子集之后恢复它也不起作用。

# Does not work...
tmp <- attributes(x)
x <- x[1:100,]
attributes(x) <- tmp

当然,我可以将所有注释写入向量(var =&gt; comment),子集并使用循环将其写回 - 但这似乎不是一个有根据的解决方案。而且我很确定在将来的分析中我会遇到其他相关属性的数据集。

所以这就是我在stackoverflow,Google和脑力方面的努力陷入困境的地方。如果有人能帮我提示,我将非常感激。谢谢!

4 个答案:

答案 0 :(得分:10)

如果我理解正确,您在data.frame中有一些数据,而data.frame的列具有与之关联的注释。或许像以下那样?

set.seed(1)

mydf<-data.frame(aa=rpois(100,4),bb=sample(LETTERS[1:5],
  100,replace=TRUE))

comment(mydf$aa)<-"Don't drop me!"
comment(mydf$bb)<-"Me either!"

所以这会给你类似

的东西
> str(mydf)
'data.frame':   100 obs. of  2 variables:
 $ aa: atomic  3 3 4 7 2 7 7 5 5 1 ...
  ..- attr(*, "comment")= chr "Don't drop me!"
 $ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2 2 5 4 2 1 3 5 3 ...
  ..- attr(*, "comment")= chr "Me either!"

当您对此进行子集化时,评论将被删除:

> str(mydf[1:2,]) # comment dropped.
'data.frame':   2 obs. of  2 variables:
 $ aa: num  3 3
 $ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2

要保留注释,请按照上面的说明(从文档中)定义函数[.avector,然后将相应的类属性添加到data.frame中的每个列(编辑:保持bb的因子水平,将"factor"添加到bb的类中。):

mydf$aa<-structure(mydf$aa, class="avector")
mydf$bb<-structure(mydf$bb, class=c("avector","factor"))

以便保留评论:

> str(mydf[1:2,])
'data.frame':   2 obs. of  2 variables:
 $ aa:Class 'avector'  atomic [1:2] 3 3
  .. ..- attr(*, "comment")= chr "Don't drop me!"
 $ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2
  ..- attr(*, "comment")= chr "Me either!"

修改

如果您的data.frame中有许多列要保留您的属性,则可以使用lapply EDITED 来包含原始列类):

mydf2 <- data.frame( lapply( mydf, function(x) {
  structure( x, class = c("avector", class(x) ) )
} ) )

但是,这会删除与data.frame本身相关的注释(例如comment(mydf)<-"I'm a data.frame"),所以如果你有,请将它们分配给新的data.frame:

comment(mydf2)<-comment(mydf)

然后你有

> str(mydf2[1:2,])
'data.frame':   2 obs. of  2 variables:
 $ aa:Classes 'avector', 'numeric'  atomic [1:2] 3 3
  .. ..- attr(*, "comment")= chr "Don't drop me!"
 $ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2
  ..- attr(*, "comment")= chr "Me either!"
 - attr(*, "comment")= chr "I'm a data.frame"

答案 1 :(得分:4)

对于那些根据BenBarnes解释寻找“全押”解决方案的人:就是这样。

(如果这对你有用,请将你的“向上”发给BenBarnes的帖子)

# Define the avector-subselection method (from the manual)
as.data.frame.avector <- as.data.frame.vector
`[.avector` <- function(x,i,...) {
  r <- NextMethod("[")
  mostattributes(r) <- attributes(x)
  r
}

# Assign each column in the data.frame the (additional) class avector
# Note that this will "lose" the data.frame's attributes, therefore write to a copy
df2 <- data.frame(
  lapply(df, function(x) {
    structure( x, class = c("avector", class(x) ) )
  } )
)

# Finally copy the attribute for the original data.frame if necessary
mostattributes(df2) <- attributes(df)

# Now subselects work without losing attributes :)
df2 <- df2[1:100,]
str(df2)

好事:当将类附加到所有data.frame的元素时,子选择永远不会再打扰属性。

好的 - 有时候我很惊讶在R中进行最简单的操作是多么复杂。但是如果我只是在SPSS中标记并删除了这个案例,我肯定没有学过“类”功能;)

答案 2 :(得分:1)

这是由sticky包解决的。 (完全披露:我是包的作者。)将sticky()应用于向量,并通过子集操作保留属性。例如:

> df <- data.frame( 
+   sticky   = sticky( structure(1:5, comment="sticky attribute") ),
+   nonstick = structure( letters[1:5], comment="non-sticky attribute" )
+ )
> 
> comment(df[1:3, "nonstick"])
NULL
> comment(df[1:3, "sticky"])
[1] "sticky attribute"

这适用于任何属性,而不仅仅是comment

有关详细信息,请参阅sticky包:

答案 3 :(得分:0)

我花了好几个小时试图弄清楚如何在对数据帧进行子集化(删除列)时保留属性数据(特别是变量标签)。答案很简单,我简直不敢相信。只需使用Hmisc包中的函数spss.get,然后无论您如何子集,都会保留变量标签。