如何在不丢失信息的情况下将因子转换为整数\数字?

Ada*_* SO 565 casting r r-faq

当我将因子转换为数字或整数时,我得到基础级别代码,而不是值作为数字.

f <- factor(sample(runif(5), 20, replace = TRUE))
##  [1] 0.0248644019011408 0.0248644019011408 0.179684827337041 
##  [4] 0.0284090070053935 0.363644931698218  0.363644931698218 
##  [7] 0.179684827337041  0.249704354675487  0.249704354675487 
## [10] 0.0248644019011408 0.249704354675487  0.0284090070053935
## [13] 0.179684827337041  0.0248644019011408 0.179684827337041 
## [16] 0.363644931698218  0.249704354675487  0.363644931698218 
## [19] 0.179684827337041  0.0284090070053935
## 5 Levels: 0.0248644019011408 0.0284090070053935 ... 0.363644931698218

as.numeric(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2

as.integer(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2
Run Code Online (Sandbox Code Playgroud)

我不得不求助于paste获得真正的价值观:

as.numeric(paste(f))
##  [1] 0.02486440 0.02486440 0.17968483 0.02840901 0.36364493 0.36364493
##  [7] 0.17968483 0.24970435 0.24970435 0.02486440 0.24970435 0.02840901
## [13] 0.17968483 0.02486440 0.17968483 0.36364493 0.24970435 0.36364493
## [19] 0.17968483 0.02840901
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法将因子转换为数字?

Jos*_*ich 662

请参阅以下警告部分?factor:

特别是,as.numeric应用于一个因素是没有意义的,并且可能通过隐式强制发生.要将因子转换f为大约其原始数值,as.numeric(levels(f))[f]建议使用效率稍高一些 as.numeric(as.character(f)).

关于R的FAQ 有类似的建议.


为什么as.numeric(levels(f))[f]比这更有效as.numeric(as.character(f))

as.numeric(as.character(f))是有效的as.numeric(levels(f)[f]),因此您正在执行转换为数字length(x)值而不是nlevels(x)值.对于具有较少水平的长向量,速度差异将是最明显的.如果这些值大多是唯一的,那么速度就没有太大差异.但是,如果进行转换,此操作不太可能成为代码中的瓶颈,因此不要过于担心.


一些时间

library(microbenchmark)
microbenchmark(
  as.numeric(levels(f))[f],
  as.numeric(levels(f)[f]),
  as.numeric(as.character(f)),
  paste0(x),
  paste(x),
  times = 1e5
)
## Unit: microseconds
##                         expr   min    lq      mean median     uq      max neval
##     as.numeric(levels(f))[f] 3.982 5.120  6.088624  5.405  5.974 1981.418 1e+05
##     as.numeric(levels(f)[f]) 5.973 7.111  8.352032  7.396  8.250 4256.380 1e+05
##  as.numeric(as.character(f)) 6.827 8.249  9.628264  8.534  9.671 1983.694 1e+05
##                    paste0(x) 7.964 9.387 11.026351  9.956 10.810 2911.257 1e+05
##                     paste(x) 7.965 9.387 11.127308  9.956 11.093 2419.458 1e+05
Run Code Online (Sandbox Code Playgroud)

  • 当应用as.numeric(levels(f))[f]或as.numeric(as.character(f))时,我有一个警告消息:警告消息:由强制引入的NAs.你知道问题出在哪里吗?谢谢 ! (12认同)
  • @Sam as.character(f)需要一个"原始查找"来找到函数as.character.factor(),它被定义为as.numeric(levels(f))[f]. (7认同)
  • 有关时间,请参阅此答案:http://stackoverflow.com/questions/6979625/arithmetic-operations-on-r-factors/6980780#6980780 (4认同)
  • 非常感谢你的解决方案.我可以问为什么as.numeric(levels(f))[f]更精确,更快?谢谢. (3认同)

Jea*_*lie 81

R有许多(未记录的)便利函数用于转换因子:

  • as.character.factor
  • as.data.frame.factor
  • as.Date.factor
  • as.list.factor
  • as.vector.factor
  • ...

但令人讨厌的是,没有什么可以处理因素 - >数字转换.作为约书亚乌尔里希答案的延伸,我建议用你自己惯用函数的定义来克服这个遗漏:

as.numeric.factor <- function(x) {as.numeric(levels(x))[x]}
Run Code Online (Sandbox Code Playgroud)

您可以存储在脚本的开头,甚至可以存储在.Rprofile文件中.

  • 没有什么可以处理因子到整数(或数字)转换,因为它期望`as.integer(factor)`返回基础整数代码(如`?factor`的示例部分所示).在全局环境中定义此函数可能没问题,但如果您实际将其注册为S3方法,则可能会出现问题. (14认同)
  • 如果你发现自己做了很多**,那么你应该做一些上游的事情以避免它全部在一起. (4认同)
  • 这是一个很好的观点,我同意:对因子-&gt; 数字转换的完全重新定义可能会搞砸很多事情。我发现自己写了很多麻烦的 `factor-&gt;numeric` 转换**,然后才意识到它实际上是 R 的一个缺点:一些方便的函数*应该*可用......称之为`as.numeric.factor ` 对我来说很有意义,但是 YMMV。 (2认同)
  • as.numeric.factor 返回 NA? (2认同)

Meh*_*ian 33

最简单的方法是使用unfactorpackage varhandle中的函数

unfactor(your_factor_variable)
Run Code Online (Sandbox Code Playgroud)

这个例子可以快速入门:

x <- rep(c("a", "b", "c"), 20)
y <- rep(c(1, 1, 0), 20)

class(x)  # -> "character"
class(y)  # -> "numeric"

x <- factor(x)
y <- factor(y)

class(x)  # -> "factor"
class(y)  # -> "factor"

library(varhandle)
x <- unfactor(x)
y <- unfactor(y)

class(x)  # -> "character"
class(y)  # -> "numeric"
Run Code Online (Sandbox Code Playgroud)

  • @Selrac我已经提到过这个函数可以在[varhandle](http://cran.r-project.org/web/packages/varhandle/index.html)包中找到,这意味着你应该加载包(`library( "varhandle")`)首先(正如我在答案第一行中提到的那样!!) (2认同)
  • 我很高兴您的包可能还有其他一些不错的功能,但是安装新包(并向您的代码添加外部依赖项)并不像键入“as.character(as.numeric())”那么好或容易。 (2认同)

Ind*_*ndi 18

这篇文章中的每个答案都无法为我产生结果,NAs正在生成.

y2<-factor(c("A","B","C","D","A")); 
as.numeric(levels(y2))[y2] 
[1] NA NA NA NA NA Warning message: NAs introduced by coercion
Run Code Online (Sandbox Code Playgroud)

对我有用的是 -

as.integer(y2)
# [1] 1 2 3 4 1
Run Code Online (Sandbox Code Playgroud)

注意:此特定答案不是用于将数值因子转换为数值因子,而是用于将分类因子转换为其对应的级别数.

  • 好的,这不是上面提到的问题.在这个问题中,因子水平都是"数字".在你的情况下,`as.numeric(y)`应该工作正常,不需要`unclass()`.但同样,这不是这个问题的内容.这个答案在这里不合适. (3认同)
  • 嗯,我真的希望它可以帮助那些像我一样匆忙的人并阅读标题! (3认同)

djh*_*rio 9

在因子标签与原始值匹配的情况下才有可能.我将用一个例子来解释它.

假设数据是矢量x:

x <- c(20, 10, 30, 20, 10, 40, 10, 40)
Run Code Online (Sandbox Code Playgroud)

现在我将创建一个包含四个标签的因子:

f <- factor(x, levels = c(10, 20, 30, 40), labels = c("A", "B", "C", "D"))
Run Code Online (Sandbox Code Playgroud)

1)x是double类型,f是整数类型.这是第一次不可避免的信息丢失.因子总是存储为整数.

> typeof(x)
[1] "double"
> typeof(f)
[1] "integer"
Run Code Online (Sandbox Code Playgroud)

2)无法恢复到仅f可用的原始值(10,20,30,40).我们可以看到f只保留整数值1,2,3,4和两个属性 - 标签列表("A","B","C","D")和类属性"factor".而已.

> str(f)
 Factor w/ 4 levels "A","B","C","D": 2 1 3 2 1 4 1 4
> attributes(f)
$levels
[1] "A" "B" "C" "D"

$class
[1] "factor"
Run Code Online (Sandbox Code Playgroud)

要恢复原始值,我们必须知道创建因子时使用的级别值.在这种情况下c(10, 20, 30, 40).如果我们知道原始级别(按正确顺序),我们可以恢复原始值.

> orig_levels <- c(10, 20, 30, 40)
> x1 <- orig_levels[f]
> all.equal(x, x1)
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

这仅适用于为原始数据中的所有可能值定义标签的情况.

因此,如果您需要原始值,则必须保留它们.否则很有可能只能从一个因素回到它们.


dav*_*job 5

hablar::convert如果您有数据框,则可以使用。语法很简单:

样本 df

library(hablar)
library(dplyr)

df <- dplyr::tibble(a = as.factor(c("7", "3")),
                    b = as.factor(c("1.5", "6.3")))
Run Code Online (Sandbox Code Playgroud)

解决方案

df %>% 
  convert(num(a, b))
Run Code Online (Sandbox Code Playgroud)

给你:

# A tibble: 2 x 2
      a     b
  <dbl> <dbl>
1    7.  1.50
2    3.  6.30
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望一列是整数,一列是数字:

df %>% 
  convert(int(a),
          num(b))
Run Code Online (Sandbox Code Playgroud)

结果是:

# A tibble: 2 x 2
      a     b
  <int> <dbl>
1     7  1.50
2     3  6.30
Run Code Online (Sandbox Code Playgroud)


Rob*_*ray 5

strtoi()如果您的因子水平是整数,则有效。