【问题标题】:Manually construct factor from integer vector从整数向量手动构造因子
【发布时间】:2021-12-25 13:34:58
【问题描述】:

我试图了解 R 中的各种对象是如何由原子向量和通用向量组成的。

可以通过手动设置属性namesrow.namesclass,从list 构造data.frame,请参阅here

我想知道这对于内部表示为整数向量的因子是如何工作的。我想出的解决方案如下:

> f <- 1:3
> class(f) <- "factor"
> levels(f) <- c("low", "medium", "high")
Warning message:
In str.default(val) : 'object' does not have valid levels()

但由于某种原因,这看起来仍然与正确构造的因素不同:

> str(unclass(f))
 int [1:3] 1 2 3
 - attr(*, "levels")= chr [1:3] "low" "medium" "high"
> str(unclass(factor(c("low", "medium", "high"))))
 int [1:3] 2 3 1
 - attr(*, "levels")= chr [1:3] "high" "low" "medium"

我错过了什么吗? (我知道这可能不应该在生产代码中使用,而是仅用于教育目的。)

【问题讨论】:

    标签: r metaprogramming factors


    【解决方案1】:

    顺序很重要。

    f <- 1:3
    levels(f) <- c("low", "medium", "high")  ## mark
    class(f) <- "factor"
    f
    # [ 1] low    medium high  
    # Levels: low medium high
    

    `levels&lt;-` 为向量添加一个属性,而不是行 ## 标记 你也可以这样做

    attr(f, 'levels') <- c("low", "medium", "high")
    

    这里一步一步发生了什么:

    f <- 1:3
    attributes(f)
    # NULL
    
    levels(f) <- c("low", "medium", "high")
    attributes(f)
    # $levels
    # [1] "low"    "medium" "high"  
    
    class(f) <- "factor"
    attributes(f)
    # $levels
    # [1] "low"    "medium" "high"  
    # 
    # $class
    # [1] "factor"
    

    检查“自动”因子生成。

    attributes(factor(1:3, labels=c("low", "medium", "high")))
    # $levels
    # [1] "low"    "medium" "high"  
    # 
    # $class
    # [1] "factor"
    

    而且,重要的是

    stopifnot(all.equal(unclass(f), 
                        unclass(factor(1:3, labels=c("low", "medium", "high")))))
    

    注意 1,f 的顺序无关紧要。 f 的级别由它们的索引标识,并且分配的级别向量的元素 n 成为第一级别,即以下示例中的`1`='low', `2`='medium', `3`='high'

    f <- 3:1
    levels(f) <- c("low", "medium", "high")
    class(f) <- 'factor'
    f
    # [1] high   medium low   
    # Levels: low medium high
    

    注意 2,这仅在 f1 开头并且级别增加 1 时才有效,因为一个因子实际上是一个标记的整数结构。

    g <- 2:4
    levels(g) <- c("low", "medium", "high")
    class(g) <- 'factor'
    g
    # Error in as.character.factor(x) : malformed factor
    
    h <- c(1, 3, 4)
    levels(h) <- c("low", "medium", "high")
    class(h) <- 'factor'
    # Error in class(h) <- "factor" : 
    #   adding class "factor" to an invalid object
    

    【讨论】:

    • 关于使用attr(obj, "levels") &lt;- 代替levels(obj) &lt;- 的可能性:?levels 处的文档指出:“请注意,对于一个因素,通过levels(x) &lt;- value 替换级别与(并且首选)attr(x, "levels") &lt;- value。”但是使用我的 R 4.1.2 我只能找到定义为 attr(x, "levels")levels.default 而没有 levels.factor。所以这很可能已经过时了(?)。
    • @Quasimodo 有趣的见解,谢谢!但是,我们不是在这里替换关卡,而是创建它们,这可能会有所不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2017-06-11
    • 2018-01-11
    • 1970-01-01
    • 2013-12-13
    相关资源
    最近更新 更多