Как преобразовать фактор в целоечисловое число без потери информации?
когда я преобразую фактор в числовое или целое число, я получаю коды базового уровня, а не значения в виде чисел.
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
есть ли лучший способ преобразовать фактор в числовой?
5 ответов:
смотрите раздел предупреждение
?factor:в частности,
as.numericприменить к фактор бессмыслен, и может происходит путем неявного принуждения. К преобразуйте факторfto приблизительно его исходное числовое значение ценности,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.factoras.data.frame.factoras.Date.factoras.list.factoras.vector.factor- ...
но досадно, что нет ничего, чтобы справиться с фактор -> цифровой преобразования. В качестве расширения ответа Джошуа Ульриха я бы предложил преодолеть это упущение с определением вашего собственного идиоматическая функция:
as.numeric.factor <- function(x) {as.numeric(levels(x))[x]}что вы можете хранить в начале вашего скрипта, или даже лучше в вашем
.Rprofile.
самый простой способ-использовать
unfactorфункция из пакета varhandleunfactor(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