R 删除子集合数据帧中未使用的因子级别
我有一个包含R 删除子集合数据帧中未使用的因子级别,r,dataframe,r-factor,r-faq,R,Dataframe,R Factor,R Faq,我有一个包含因子的数据框。当我使用subset或其他索引函数创建此数据帧的子集时,将创建一个新的数据帧。但是,因子变量保留其所有原始级别,即使新数据帧中不存在这些级别 在进行分面打印或使用依赖于因子级别的函数时,这会导致问题 在新的数据帧中,从因子中删除级别的最简洁的方法是什么 下面是一个例子: df <- data.frame(letters=letters[1:5], numbers=seq(1:5)) levels(df$letters) #
因子的数据框。当我使用subset
或其他索引函数创建此数据帧的子集时,将创建一个新的数据帧。但是,因子
变量保留其所有原始级别,即使新数据帧中不存在这些级别
在进行分面打印或使用依赖于因子级别的函数时,这会导致问题
在新的数据帧中,从因子中删除级别的最简洁的方法是什么
下面是一个例子:
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
# all levels are still there!
levels(subdf$letters)
## [1] "a" "b" "c" "d" "e"
df这是一个已知的问题,一个可能的补救方法是在示例所在的包中提供的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"
包中还有dropUnusedLevels
功能。但是,它仅通过更改子集运算符[
起作用,在这里不适用
作为推论,基于每列的直接方法是简单的As.factor(As.character(data))
:
>级别(subdf$字母)
[1] “a”“b”“c”“d”“e”
>subdf$字母级别(subdf$字母)
[1] “a”“b”“c”
这很讨厌。我通常是这样做的,以避免加载其他软件包:
levels(subdf$letters)<-c("a","b","c",NA,NA)
请注意,新级别将替换旧级别(subdf$字母)中索引中的任何内容,如下所示:
levels(subdf$letters)<-c(NA,"a","c",NA,"b")
levels(subdf$letters)您只需在子集设置后将factor()再次应用于变量:
> subdf$letters
[1] a b c
Levels: a b c d e
subdf$letters <- factor(subdf$letters)
> subdf$letters
[1] a b c
Levels: a b c
要从数据帧中的所有因子列中删除级别,可以使用:
subdf <- subset(df, numbers <= 3)
subdf[] <- lapply(subdf, function(x) if(is.factor(x)) factor(x) else x)
subdf如果您不希望出现这种行为,请不要使用因子,而是使用字符向量。我认为这比事后修补更有意义。在使用read.table
或read.csv
加载数据之前,请尝试以下操作:
options(stringsAsFactors = FALSE)
缺点是只能按字母顺序排列。(重新排序是绘图的好方法)这里有另一种方法,我认为这相当于因子(…)
方法:
> 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"
>df subdf我编写了实用函数来实现这一点。现在我了解了gdata的drop.levels,它看起来非常相似。它们如下所示:
present\u levels自R版本2.12以来,有一个droplevels()
函数
levels(droplevels(subdf$letters))
这里有一种方法
varFactor <- factor(letters[1:15])
varFactor <- varFactor[1:5]
varFactor <- varFactor[drop=T]
varFactor非常有趣的线程,我特别喜欢再次将子选择因子化的想法。我以前也遇到过类似的问题,我只是转换为字符,然后再转换回因子
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))
df使用dplyr执行相同操作的另一种方法
library(dplyr)
subdf <- df %>% filter(numbers <= 3) %>% droplevels()
str(subdf)
库(dplyr)
subdf%过滤器(数量%droplevels()
str(subdf)
编辑:
也有用!谢谢你
subdf%过滤器(数字%droplevels
级别(subdf$字母)
查看它包装到factor
函数的droplevels
方法。这意味着您基本上可以使用factor
函数重新创建列。
下面的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"
库(data.table)
dt=数据。表格(字母=系数(字母[1:5]),数字=序号(1:5))
级别(dt$字母)
#[1] “a”“b”“c”“d”“e”
subdt=dt[numbers为了完整起见,现在在forcats
包中还有fct_drop
它在处理NA
的方式上与droplevels
不同:
f <- factor(c("a", "b", NA), exclude = NULL)
droplevels(f)
# [1] a b <NA>
# Levels: a b <NA>
forcats::fct_drop(f)
# [1] a b <NA>
# Levels: a b
f不幸的是,当使用RevoScaleR的rxDataStep时,factor()似乎不起作用。我分两步来做:
1) 转换为字符并存储在临时外部数据帧(.xdf)中。
2) 转换回因子并存储在最终的外部数据框中。这消除了任何未使用的因子级别,而无需将所有数据加载到内存中
# Step 1) Converts to character, in temporary xdf file:
rxDataStep(inData = "input.xdf", outFile = "temp.xdf", transforms = list(VAR_X = as.character(VAR_X)), overwrite = T)
# Step 2) Converts back to factor:
rxDataStep(inData = "temp.xdf", outFile = "output.xdf", transforms = list(VAR_X = as.factor(VAR_X)), overwrite = T)
我已经尝试了这里的大多数例子,如果不是所有的,但没有一个在我的情况下起作用。
经过一段时间的努力,我尝试在factor列上使用as.character()将其更改为一个带有字符串的col,看起来效果不错
不确定是否存在性能问题。真正的droplevels功能比droplevels
快得多,并且不执行任何不必要的值匹配或制表,它是collapse::fdroplevels
。示例:
library(collapse)
library(microbenchmark)
# wlddev data supplied in collapse, iso3c is a factor
data <- fsubset(wlddev, iso3c %!in% "USA")
microbenchmark(fdroplevels(data), droplevels(data), unit = "relative")
## Unit: relative
## expr min lq mean median uq max neval cld
## fdroplevels(data) 1.0 1.00000 1.00000 1.00000 1.00000 1.00000 100 a
## droplevels(data) 30.2 29.15873 24.54175 24.86147 22.11553 14.23274 100 b
库(折叠)
图书馆(微基准)
#wlddev数据在崩溃中提供,iso3c是一个因素
对于一次性的数据来说这很好,但是在一个包含大量列的data.frame中,您可以在每一列上都这样做,这是一个因素…导致需要一个函数,比如gdata中的drop.levels()。我明白了…但是从用户的角度来看,很快就可以编写类似subdf[]感谢Stephen&Dirk-我对这篇文章中的一个因子的caes表示赞许,但希望大家能够阅读这些评论,以了解您关于清理整个因子数据框的建议。作为一种副作用,函数会将数据框转换为列表,因此mydf也:此方法确实保留了变量的顺序<代码>重新排序
drop.levels
函数的参数值得一提:如果必须保留因子的原始顺序,请将其与FALSE
值一起使用。仅对drop.levels使用gdata会产生“启用gdata:read.xls对'xls'(Excel 97-2004)文件的支持”“gdata:无法加载read.xls()所需的perl库”“gdata:支持'XLSX'(Excel 2007+)文件”“gdata:运行函数'installXLSXsupport()'”“gdata:自动下载并安装perl”“。使用baseR()中的droplevels”事情会随着时间的推移而发生。你正在评论我九年前写的一个答案。因此,让我们把这作为一个提示,让我们普遍倾向于基本R解决方案,因为这些解决方案使用的功能从现在起仍将是N年左右。与使用factor()相比,这种方法的优点是
是指无需修改原始数据帧或创建新的持久数据帧。我可以包装
subdf <- df %>% filter(numbers <= 3) %>% droplevels
levels(subdf$letters)
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"
f <- factor(c("a", "b", NA), exclude = NULL)
droplevels(f)
# [1] a b <NA>
# Levels: a b <NA>
forcats::fct_drop(f)
# [1] a b <NA>
# Levels: a b
# Step 1) Converts to character, in temporary xdf file:
rxDataStep(inData = "input.xdf", outFile = "temp.xdf", transforms = list(VAR_X = as.character(VAR_X)), overwrite = T)
# Step 2) Converts back to factor:
rxDataStep(inData = "temp.xdf", outFile = "output.xdf", transforms = list(VAR_X = as.factor(VAR_X)), overwrite = T)
library(collapse)
library(microbenchmark)
# wlddev data supplied in collapse, iso3c is a factor
data <- fsubset(wlddev, iso3c %!in% "USA")
microbenchmark(fdroplevels(data), droplevels(data), unit = "relative")
## Unit: relative
## expr min lq mean median uq max neval cld
## fdroplevels(data) 1.0 1.00000 1.00000 1.00000 1.00000 1.00000 100 a
## droplevels(data) 30.2 29.15873 24.54175 24.86147 22.11553 14.23274 100 b