Факторы в R: больше, чем раздражение?

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

Существуют ли некоторые важные примеры функций, которые используют факторы как группирующие переменные, где необходим факторный тип данных? Существуют ли конкретные обстоятельства, когда я должен использовать факторы?

Ответ 1

Вы должны использовать факторы. Да, они могут быть болью, но моя теория заключается в том, что 90% причин, по которым они болеют, потому что в read.table и read.csv аргумент stringsAsFactors = TRUE по умолчанию (и большинство пользователей пропустит эту тонкость). Я говорю, что они полезны, потому что моделирующие пакеты, такие как lme4, используют факторы и упорядоченные факторы для дифференциального соответствия моделей и определения типа контрастов для использования. И графические пакеты также используют их для группировки. ggplot, и большинство функций подгонки модели налагают на векторные векторы факторы, поэтому результат один и тот же. Однако вы получите предупреждения в своем коде:

lm(Petal.Length ~ -1 + Species, data=iris)

# Call:
# lm(formula = Petal.Length ~ -1 + Species, data = iris)

# Coefficients:
#     Speciessetosa  Speciesversicolor   Speciesvirginica  
#             1.462              4.260              5.552  

iris.alt <- iris
iris.alt$Species <- as.character(iris.alt$Species)
lm(Petal.Length ~ -1 + Species, data=iris.alt)

# Call:
# lm(formula = Petal.Length ~ -1 + Species, data = iris.alt)

# Coefficients:
#     Speciessetosa  Speciesversicolor   Speciesvirginica  
#             1.462              4.260              5.552  

Предупреждающее сообщение: В model.matrix.default(mt, mf, contrasts):

variable Species преобразован в factor

Одна сложная вещь - это бит drop=TRUE. В векторах это хорошо работает, чтобы удалить уровни факторов, которые не находятся в данных. Например:

s <- iris$Species
s[s == 'setosa', drop=TRUE]
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa
s[s == 'setosa', drop=FALSE]
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica

Однако с data.frame s поведение [.data.frame() отличается: см. это электронное письмо или ?"[.data.frame". Использование drop=TRUE на data.frame не работает так, как вы могли себе представить:

x <- subset(iris, Species == 'setosa', drop=TRUE)  # susbetting with [ behaves the same way
x$Species
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica

К счастью, вы можете легко понизить коэффициенты с помощью droplevels(), чтобы сбросить неиспользуемые уровни факторов для отдельного фактора или для каждого фактора в data.frame (так как R 2.12):

x <- subset(iris, Species == 'setosa')
levels(x$Species)
# [1] "setosa"     "versicolor" "virginica" 
x <- droplevels(x)
levels(x$Species)
# [1] "setosa"

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

Внутри factor - целые числа с символом символа уровня атрибута (см. attributes(iris$Species) и class(attributes(iris$Species)$levels)), который является чистым. Если вам нужно было изменить имя уровня (и вы использовали строки символов), это было бы гораздо менее эффективной операцией. И я сильно меняю названия уровней, особенно для ggplot легенд. Если вы подделываете факторы с символьными векторами, существует риск того, что вы измените только один элемент и случайно создадите отдельный новый уровень.

Ответ 2

упорядоченные факторы являются удивительными, если я случайно люблю апельсины и ненавижу яблоки, но не против винограда. Мне не нужно управлять каким-то странным индексом, чтобы сказать так:

d <- data.frame(x = rnorm(20), f = sample(c("apples", "oranges", "grapes"), 20, replace = TRUE, prob = c(0.5, 0.25, 0.25)))
d$f <- ordered(d$f, c("apples", "grapes", "oranges"))
d[d$f >= "grapes", ]

Ответ 3

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

Рассмотрим несколько примеров. Для некоторых данных, которые были собраны во всех Соединенных Штатах, государство должно регистрироваться как фактор. В этом случае актуальным является тот факт, что ни один случай не был собран из определенного государства. Там могли быть данные из этого состояния, но произошло (по какой-то причине, что может быть причиной интереса) не быть. Если бы собирался родной город, это не было бы фактором. Существует не предустановленный набор возможных родных городов. Если бы данные были собраны из трех городов, а не на национальном уровне, город был бы одним из факторов: есть три варианта, которые были даны с самого начала, и если в одном из этих трех городов не было найдено соответствующих случаев/данных. p >

Другие аспекты factor s, такие как предоставление способа предоставления произвольного порядка сортировки набору строк, являются полезными вторичными характеристиками factor s, но не являются причиной их существования.

Ответ 4

Факторы фантастичны, когда вы делаете статистический анализ и фактически изучаете данные. Тем не менее, до того, когда вы читаете, чистите, устраните неполадки, слейте и вообще манипулируете данными, факторы являются полной болью. Совсем недавно, как и в последние несколько лет, многие функции улучшились для лучшего управления факторами. Например, rbind отлично играет с ними. Я все еще нахожу, что это полная неприятность, оставленная на пустых уровнях после функции подмножества.

#drop a whole bunch of unused levels from a whole bunch of columns that are factors using gdata
require(gdata)
drop.levels(dataframe)

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

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

Ответ 5

Какой злобный титул!

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

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

PS - Я шучу о названии. Я видел твой твит.; -)

Ответ 6

Факторы - отличный механизм "уникальных дел". Я воссоздал это плохо много раз, и, несмотря на пару морщин, они чрезвычайно мощные.

library(dplyr)
d <- tibble(x = sample(letters[1:10], 20, replace = TRUE))

## normalize this table into an indexed value across two tables
id <- tibble(x_u = sort(unique(d$x))) %>% mutate(x_i = row_number())
di <- tibble(x_i = as.integer(factor(d$x)))


## reconstruct d$x when needed
d2 <- inner_join(di, id) %>% transmute(x = x_u)
identical(d, d2)
## [1] TRUE

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

Ответ 7

tapply aggregate) полагаются на факторы. Отношение данных к усилиям этих функций очень велико.

Например, в одной строке кода (вызов нажать ниже) вы можете получить среднюю цену бриллиантов с помощью Cut и Color:

> data(diamonds, package="ggplot2")

> head(dm)

   Carat     Cut    Clarity Price Color
1  0.23     Ideal     SI2   326     E
2  0.21   Premium     SI1   326     E
3  0.23      Good     VS1   327     E


> tx = with(diamonds, tapply(X=Price, INDEX=list(Cut=Cut, Color=Color), FUN=mean))

> a = sort(1:diamonds(tx)[2], decreasing=T)  # reverse columns for readability

> tx[,a]

         Color
Cut         J    I    H    G    F    E    D
Fair      4976 4685 5136 4239 3827 3682 4291
Good      4574 5079 4276 4123 3496 3424 3405
Very Good 5104 5256 4535 3873 3779 3215 3470
Premium   6295 5946 5217 4501 4325 3539 3631
Ideal     4918 4452 3889 3721 3375 2598 2629