在子集数据框中放置因子水平
我有一个数据框包含一个因素。 当我使用subset()或其他索引函数创build此数据框的subset() ,会创build一个新的数据框。 但是,因素variables保留了所有的原始级别 – 即使它们不存在于新的数据框架中。 
这在创build多面绘图或使用依赖于因子级别的函数时会产生麻烦。
在我的新数据框架中从一个因素中删除层次的最简洁的方法是什么?
这是我的例子:
 df <- data.frame(letters=letters[1:5], numbers=seq(1:5)) levels(df$letters) ## [1] "a" "b" "c" "d" "e" subdf <- subset(df, numbers <= 3) ## letters numbers ## 1 a 1 ## 2 b 2 ## 3 c 3 ## but the levels are still there! levels(subdf$letters) ## [1] "a" "b" "c" "d" "e" 
	
你所要做的就是在子集化之后再将factor()应用到你的variables中:
 > subdf$letters [1] abc Levels: abcde subdf$letters <- factor(subdf$letters) > subdf$letters [1] abc Levels: abc 
编辑
从因素页面示例:
 factor(ff) # drops the levels that do not occur 
要从数据框中的所有因子列中删除级别,可以使用:
 subdf <- subset(df, numbers <= 3) subdf[] <- lapply(subdf, function(x) if(is.factor(x)) factor(x) else x) 
 由于R版本2.12,有一个droplevels()函数。 
 levels(droplevels(subdf$letters)) 
 这是一个已知的问题,一个可能的补救措施是由gdata包中的drop.levels()提供的,在这个包中你的例子变成了 
 > drop.levels(subdf) letters numbers 1 a 1 2 b 2 3 c 3 > levels(drop.levels(subdf)$letters) [1] "a" "b" "c" 
  Hmisc包中还有dropUnusedLevels函数。 但是,它只能通过修改子集操作符来工作[并且在这里不适用。 
 作为一个必然结果,以as.factor(as.character(data))的直接方法是简单的as.factor(as.character(data)) : 
 > levels(subdf$letters) [1] "a" "b" "c" "d" "e" > subdf$letters <- as.factor(as.character(subdf$letters)) > levels(subdf$letters) [1] "a" "b" "c" 
 如果你不想要这种行为,不要使用因素,而是使用字符向量。 我觉得这比之后补丁更有意义。 在使用read.table或read.csv加载数据之前,请尝试以下read.csv : 
 options(stringsAsFactors = FALSE) 
缺点是你只能按字母顺序排列。 (重新sorting是你的情节的朋友)
 这是另一种方式,我相信这是相当于factor(..)方法: 
 > df <- data.frame(let=letters[1:5], num=1:5) > subdf <- df[df$num <= 3, ] > subdf$let <- subdf$let[ , drop=TRUE] > levels(subdf$let) [1] "a" "b" "c" 
 另一种方式,但与dplyr相同 
 library(dplyr) subdf <- df %>% filter(numbers <= 3) %>% droplevels() str(subdf) 
编辑:
也工作! 感谢agenis
 subdf <- df %>% filter(numbers <= 3) %>% droplevels levels(subdf$letters) 
这是讨厌的。 这是我通常这样做,以避免加载其他包:
 levels(subdf$letters)<-c("a","b","c",NA,NA) 
这让你:
 > subdf$letters [1] abc Levels: abc 
请注意,新的级别将取代旧的级别(subdf $字母)中占据其索引的任何东西,例如:
 levels(subdf$letters)<-c(NA,"a","c",NA,"b") 
将无法工作。
当你有很多关卡的时候,这显然不是很理想,但是有一些关卡很简单。
这是一个这样做的方法
 varFactor <- factor(letters[1:15]) varFactor <- varFactor[1:5] varFactor <- varFactor[drop=T] 
 看看R源中的droplevels方法代码,你可以看到它包裹factorfunction。 这意味着你基本上可以用factor函数重新创build列。 
 在data.table的方式下,从所有因子列中删除级别。 
 library(data.table) dt = data.table(letters=factor(letters[1:5]), numbers=seq(1:5)) levels(dt$letters) #[1] "a" "b" "c" "d" "e" subdt = dt[numbers <= 3] levels(subdt$letters) #[1] "a" "b" "c" "d" "e" upd.cols = sapply(subdt, is.factor) subdt[, names(subdt)[upd.cols] := lapply(.SD, factor), .SDcols = upd.cols] levels(subdt$letters) #[1] "a" "b" "c" 
我写了实用function来做到这一点。 现在我知道了gdata的drop.levels,它看起来很相似。 他们在这里 (从这里 ):
 present_levels <- function(x) intersect(levels(x), x) trim_levels <- function(...) UseMethod("trim_levels") trim_levels.factor <- function(x) factor(x, levels=present_levels(x)) trim_levels.data.frame <- function(x) { for (n in names(x)) if (is.factor(x[,n])) x[,n] = trim_levels(x[,n]) x } 
非常有趣的线程,我特别喜欢的主意,只是再次推翻子选举。 我之前有类似的问题,我只是转换为字符,然后回到因素。
  df <- data.frame(letters=letters[1:5],numbers=seq(1:5)) levels(df$letters) ## [1] "a" "b" "c" "d" "e" subdf <- df[df$numbers <= 3] subdf$letters<-factor(as.character(subdf$letters)) 
 为了完整起见,现在在forcats包中也有fct_drop http://forcats.tidyverse.org/reference/fct_drop.html 。 
 它与处理NA的方式不同: 
 f <- factor(c("a", "b", NA), exclude = NULL) droplevels(f) # [1] ab <NA> # Levels: ab <NA> forcats::fct_drop(f) # [1] ab <NA> # Levels: ab