gpt4 book ai didi

r - 为什么使用 as.factor() 而不仅仅是 factor()

转载 作者:行者123 更新时间:2023-12-01 23:26:26 26 4
gpt4 key购买 nike

我最近看到 Matt Dowle 用 as.factor() 写了一些代码, 具体来说

for (col in names_factors) set(dt, j=col, value=as.factor(dt[[col]]))

a comment to this answer .

我使用了这个片段,但我需要明确设置因子水平以确保水平以我想要的顺序出现,所以我不得不改变
as.factor(dt[[col]])


factor(dt[[col]], levels = my_levels)

这让我想到:使用 as.factor() 有什么好处(如果有的话)与只是 factor() ?

最佳答案

as.factorfactor 的包装器,但如果输入向量已经是一个因子,它允许快速返回:

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)
}

评论来自 Frank :它不仅仅是一个包装器,因为这种“快速返回”将保持因子水平不变,而 factor()将不会:
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

两年后扩展答案,包括以下内容:
  • 说明书是怎么说的?
  • 性能:as.factor > factor当输入是一个因子时
  • 性能:as.factor > factor当输入为整数时
  • 未使用的级别或 NA 级别
  • 使用 R 的分组功能时的注意事项:注意未使用或 NA 级别


  • 说明书是怎么说的?
    ?factor 的文档提到以下内容:
    ‘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’.

    性能: as.factor > factor当输入是一个因素时

    “无操作”这个词有点模棱两可。不要把它当作“什么都不做”;事实上,它的意思是“做了很多事情,但本质上什么都不改变”。下面是一个例子:
    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
    as.factor确实可以快速返回,但是 factor不是真正的“无操作”。简介 factor看看它做了什么。
    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

    首先 sort unique输入向量的值 f ,然后转换 f到一个字符向量,最后使用 factor将字符向量强制回一个因子。这是 factor的源代码确认。
    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
    }

    所以函数 factor真正设计用于处理字符向量,它适用于 as.character以确保其投入。我们至少可以从上面了解到两个与性能相关的问题:
  • 对于数据框 DF , lapply(DF, as.factor)lapply(DF, factor)快得多对于类型转换,如果许多列是容易因子。
  • 那个函数factor慢可以解释为什么一些重要的 R 函数很慢,比如 table :R: table function suprisingly slow

  • 性能: as.factor > factor当输入为整数时

    因子变量是整数变量的近亲。
    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"

    这意味着将整数转换为因子比将数字/字符转换为因子更容易。 as.factor只是照顾这个。
    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 级别

    现在让我们看看 factor 上的几个例子和 as.factor对因子水平的影响(如果输入已经是一个因子)。 Frank给了一个未使用的因子水平,我将提供一个 NA等级。
    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

    有一个(通用)函数 droplevels可用于删除未使用的因子水平。但是 NA默认情况下不能删除级别。
    ## "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 的分组功能时的注意事项:注意未使用或 NA 级别

    R 函数执行分组操作,如 split , tapply希望我们提供因子变量作为“by”变量。但通常我们只提供字符或数字变量。因此,在内部,这些函数需要将它们转换为因子,并且可能大多数会使用 as.factor首先(至少 split.defaulttapply 是这样)。 table函数看起来像一个异常(exception),我发现 factor而不是 as.factor里面。不幸的是,当我检查它的源代码时,可能有一些特殊的考虑对我来说并不明显。

    由于大多数 group-by R 函数使用 as.factor , 如果它们被赋予一个未使用的因子或 NA级别,这样的组会出现在结果中。
    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

    有趣的是,虽然 table不依赖 as.factor ,它也保留了那些未使用的级别:
    table(f)
    #a b c
    #1 1 0

    有时这种行为可能是不受欢迎的。一个经典的例子是 barplot(table(f)) :

    enter image description here

    如果这真的不受欢迎,我们需要手动删除未使用的或 NA我们的因子变量的水平,使用 droplevelsfactor .

    提示:
  • split有争论 drop默认为 FALSE因此 as.factor用来;来自 drop = TRUE功能 factor改为使用。
  • aggregate依赖 split ,所以它还有一个 drop参数,它默认为 TRUE .
  • tapply没有drop虽然它也依赖于 split .特别是文档 ?tapplyas.factor被(总是)使用。
  • 关于r - 为什么使用 as.factor() 而不仅仅是 factor(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39279238/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com