Как преобразовать фактор в целоечисловое число без потери информации?



когда я преобразую фактор в числовое или целое число, я получаю коды базового уровня, а не значения в виде чисел.



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


Я должен прибегнуть к 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


есть ли лучший способ преобразовать фактор в числовой?

646   5  

5 ответов:

смотрите раздел предупреждение ?factor:

в частности, as.numeric применить к фактор бессмыслен, и может происходит путем неявного принуждения. К преобразуйте фактор f to приблизительно его исходное числовое значение ценности, as.numeric(levels(f))[f] is рекомендуется и немного больше эффективными, чем as.numeric(as.character(f)).

FAQ по R есть подобные советы.


почему 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

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

что вы можете хранить в начале вашего скрипта, или даже лучше в вашем .Rprofile.

самый простой способ-использовать unfactor функция из пакета varhandle

unfactor(your_factor_variable)

этот пример может быть быстрый старт:

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"

каждый ответ в этом посте не смог генерировать результаты для меня, 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

что сработало для меня это -

as.integer(y2)
# [1] 1 2 3 4 1

Примечание: этот конкретный ответ не для преобразования числовых коэффициентов в цифры, это для преобразования категориальных факторов в соответствующие им номера уровней.

возможно только в случае, когда метки факторов совпадают с исходными значениями. Я объясню это на примере.

предположим, что данные вектор x:

x <- c(20, 10, 30, 20, 10, 40, 10, 40)

теперь я создам фактор с четырьмя метками:

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

1) x С типом double,f имеет тип integer. Это первая неизбежная потеря информации. Факторы всегда хранятся в виде целых чисел.

> typeof(x)
[1] "double"
> typeof(f)
[1] "integer"

2) это невозможно вернуться к исходным значениям (10, 20, 30, 40), имеющим только f доступен. Мы видим, что f содержит только целочисленные значения 1, 2, 3, 4 и два атрибута - список меток ("A", "B", "C", "D") и атрибут класса "фактор". Ничего больше.

> 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"

чтобы вернуться к исходным значениям, мы должны знать значения уровней, используемых при создании фактора. В данном случае c(10, 20, 30, 40). Если мы знаем исходные уровни (в правильном порядке), мы можем вернуться назад к исходным значениям.

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

и это будет работать только в случае, когда метки были определены для всех возможных значений исходных данных.

поэтому, если вам понадобятся исходные значения, вы должны их сохранить. В противном случае есть высокая вероятность, что вернуться к ним не удастся только из-за фактора.

Comments

    Ничего не найдено.