Why use as.factor() instead of just factor()
我最近看到Matt Dowle用
1 | for (col in names_factors) set(dt, j=col, value=as.factor(dt[[col]])) |
在对此答案的评论中。
我使用了此代码段,但我需要显式设置因子水平以确保水平按所需顺序显示,因此我必须进行更改
1 | as.factor(dt[[col]]) |
至
1 | factor(dt[[col]], levels = my_levels) |
这让我开始思考:与仅使用
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function (x) { if (is.factor(x)) x else if (!is.object(x) && is.integer(x)) { levels <- sort(unique.default(x)) f <- match(x, levels) levels(f) <- as.character(levels) if (!is.null(nx <- names(x))) names(f) <- nx class(f) <-"factor" f } else factor(x) } |
弗兰克的评论:这不仅仅是一个包装,因为这种"快速回报"将保持因子水平不变,而
好。
1 2 3 4 5 6 7 8 9 10 11 | f = factor("a", levels = c("a","b")) #[1] a #Levels: a b factor(f) #[1] a #Levels: a as.factor(f) #[1] a #Levels: a b |
两年后扩大答案,包括以下内容:
好。
手册说什么?
好。
1 2 3 4 5 6 | ‘factor(x, exclude = NULL)’ applied to a factor without ‘NA’s is a no-operation unless there are unused levels: in that case, a factor with the reduced level set is returned. ‘as.factor’ coerces its argument to a factor. It is an abbreviated (sometimes faster) form of ‘factor’. |
性能:当输入是一个因素时,
"不操作"一词有点含糊。不要把它当作"无所事事";实际上,它的意思是"做很多事情,但本质上什么也没改变"。这是一个例子:
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | set.seed(0) ## a randomized long factor with 1e+6 levels, each repeated 10 times f <- sample(gl(1e+6, 10)) system.time(f1 <- factor(f)) ## default: exclude = NA # user system elapsed # 7.640 0.216 7.887 system.time(f2 <- factor(f, exclude = NULL)) # user system elapsed # 7.764 0.028 7.791 system.time(f3 <- as.factor(f)) # user system elapsed # 0 0 0 identical(f, f1) #[1] TRUE identical(f, f2) #[1] TRUE identical(f, f3) #[1] TRUE |
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Rprof("factor.out") f1 <- factor(f) Rprof(NULL) summaryRprof("factor.out")[c(1, 4)] #$by.self # self.time self.pct total.time total.pct #"factor" 4.70 58.90 7.98 100.00 #"unique.default" 1.30 16.29 4.42 55.39 #"as.character" 1.18 14.79 1.84 23.06 #"as.character.factor" 0.66 8.27 0.66 8.27 #"order" 0.08 1.00 0.08 1.00 #"unique" 0.06 0.75 4.54 56.89 # #$sampling.time #[1] 7.98 |
它首先
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | function (x = character(), levels, labels = levels, exclude = NA, ordered = is.ordered(x), nmax = NA) { if (is.null(x)) x <- character() nx <- names(x) if (missing(levels)) { y <- unique(x, nmax = nmax) ind <- sort.list(y) levels <- unique(as.character(y)[ind]) } force(ordered) if (!is.character(x)) x <- as.character(x) levels <- levels[is.na(match(levels, exclude))] f <- match(x, levels) if (!is.null(nx)) names(f) <- nx nl <- length(labels) nL <- length(levels) if (!any(nl == c(1L, nL))) stop(gettextf("invalid 'labels'; length %d should be 1 or %d", nl, nL), domain = NA) levels(f) <- if (nl == nL) as.character(labels) else paste0(labels, seq_along(levels)) class(f) <- c(if (ordered)"ordered","factor") f } |
因此,函数
好。
性能:输入为整数时,
因子变量是整数变量的近亲。
好。
1 2 3 4 5 6 7 | unclass(gl(2, 2, labels = letters[1:2])) #[1] 1 1 2 2 #attr(,"levels") #[1]"a""b" storage.mode(gl(2, 2, labels = letters[1:2])) #[1]"integer" |
这意味着将整数转换为因数要比将数字/字符转换为因数容易。
好。
1 2 3 4 5 6 7 8 9 | x <- sample.int(1e+6, 1e+7, TRUE) system.time(as.factor(x)) # user system elapsed # 4.592 0.252 4.845 system.time(factor(x)) # user system elapsed # 22.236 0.264 22.659 |
未使用的水平或NA水平
现在让我们看几个关于
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | f <- factor(c(1, NA), exclude = NULL) #[1] 1 <NA> #Levels: 1 <NA> as.factor(f) #[1] 1 <NA> #Levels: 1 <NA> factor(f, exclude = NULL) #[1] 1 <NA> #Levels: 1 <NA> factor(f) #[1] 1 <NA> #Levels: 1 |
有一个(通用)函数
好。
1 2 3 4 5 6 7 8 9 10 11 12 | ##"factor" method of `droplevels` droplevels.factor #function (x, exclude = if (anyNA(levels(x))) NULL else NA, ...) #factor(x, exclude = exclude) droplevels(f) #[1] 1 <NA> #Levels: 1 <NA> droplevels(f, exclude = NA) #[1] 1 <NA> #Levels: 1 |
使用R的分组功能时的警告:注意未使用或不可用的水平
R函数执行分组操作,例如
好。
由于大多数分组R函数都使用
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | x <- c(1, 2) f <- factor(letters[1:2], levels = letters[1:3]) split(x, f) #$a #[1] 1 # #$b #[1] 2 # #$c #numeric(0) tapply(x, f, FUN = mean) # a b c # 1 2 NA |
有趣的是,尽管
好。
1 2 3 | table(f) #a b c #1 1 0 |
有时,这种行为可能是不希望的。一个经典的例子是
好。
好。
如果确实不希望这样做,则需要使用
好。
暗示:
好。
好。