覆盖[.data.frame以默认删除未使用的因子级别

时间:2011-06-18 23:38:42

标签: r dataframe subset r-factor

在子集化出现时丢弃未使用的因子级别的问题before。常见的解决方案包括通过声明

尽可能使用字符向量
options(stringsAsFactors = FALSE)

但有时候,有序因素对于绘图是必要的,在这种情况下,我们可以使用droplevels之类的便利函数为subset创建包装:

subsetDrop <- function(...){droplevels(subset(...))}

我意识到subsetDrop主要解决了这个问题,但在某些情况下,通过[进行子集化会更方便(并减少输入!)。

我的问题是,为了方便起见,我们可以通过覆盖[数据帧来自动降低因子级别,从而将其作为R的“默认”行为。例如,Hmisc包中包含dropUnusedLevels,它会覆盖[.factor以对单个因子进行子集化(不再需要,因为默认的[.factor似乎有一个drop参数丢弃未使用的水平)。我正在寻找一种类似的解决方案,允许我使用[对数据帧进行子集化,但会自动删除未使用的因子级别(当然,在有序因子的情况下保留顺序)。

3 个答案:

答案 0 :(得分:6)

我真的很想改变默认行为;你永远不知道你使用的其他功能何时取决于通常的默认行为。我会为你的subsetDrop写一个类似的函数,但对于[,就像

一样
sel <- function(x, ...) droplevels(x[...])

然后

> d <- data.frame(a=factor(LETTERS[1:5]), b=factor(letters[1:5]))
> str(d[1:2,])
'data.frame':   2 obs. of  2 variables:
 $ a: Factor w/ 5 levels "A","B","C","D",..: 1 2
 $ b: Factor w/ 5 levels "a","b","c","d",..: 1 2
> str(sel(d,1:2,))
'data.frame':   2 obs. of  2 variables:
 $ a: Factor w/ 2 levels "A","B": 1 2
 $ b: Factor w/ 2 levels "a","b": 1 2

如果您确实想要更改默认值,可以执行类似

的操作
foo <- `[.data.frame`
`[.data.frame` <- function(...) droplevels(foo(...))

但请确保您知道命名空间是如何工作的,因为这将适用于从全局命名空间调用的任何内容,但基本命名空间中的版本不会更改。这可能是一件好事,但这是你想要确保理解的东西。在此更改之后,输出就是您想要的。

> str(d[1:2,])
'data.frame':   2 obs. of  2 variables:
 $ a: Factor w/ 2 levels "A","B": 1 2
 $ b: Factor w/ 2 levels "a","b": 1 2

答案 1 :(得分:5)

你可以通过覆盖drop参数的默认值来完成这项工作,如下所示:

formals(`[.factor`)$drop <- TRUE

更新

对于data.frame,你可以这样做:

`[.data.frame` <- function(...)droplevels(base::`[.data.frame`(...))

实际上和@ Aaron的相似。

如果要取消此行为,则:

rm(`[.data.frame`)

会这样做。

> d <- data.frame(a=letters[1:10], b=LETTERS[1:10])
> str(d[1:5, ])
'data.frame':   5 obs. of  2 variables:
 $ a: Factor w/ 10 levels "a","b","c","d",..: 1 2 3 4 5
 $ b: Factor w/ 10 levels "A","B","C","D",..: 1 2 3 4 5
> `[.data.frame` <- function(...)droplevels(base::`[.data.frame`(...))
> str(d[1:5, ])
'data.frame':   5 obs. of  2 variables:
 $ a: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
 $ b: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
> rm(`[.data.frame`)
> str(d[1:5, ])
'data.frame':   5 obs. of  2 variables:
 $ a: Factor w/ 10 levels "a","b","c","d",..: 1 2 3 4 5
 $ b: Factor w/ 10 levels "A","B","C","D",..: 1 2 3 4 5

答案 2 :(得分:2)

我认为更改默认设置非常危险,请参阅我的回复here

大多数情况下,人们担心会降低因素水平,你或者真的不需要(使你被迫拥有1个值的东西变得愚蠢),或者有更好的方法来完成你正在尝试的东西。自动丢弃可能产生的副作用可能比保存的几次击键更糟糕。此外,如果您正在进行可重复的研究,那么您不应该依赖甚至允许计算机在没有您特定发言权的情况下更改数据。