Факторы в R: больше, чем раздражение? - PullRequest
94 голосов
/ 10 августа 2010

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

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

Ответы [ 7 ]

48 голосов
/ 10 августа 2010

Вы должны использовать факторы. Да, они могут причинять боль, но моя теория состоит в том, что 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):

переменная 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 s не работает, как вы думаете:

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 s являются целыми числами с векторным символом уровня атрибута (см. attributes(iris$Species) и class(attributes(iris$Species)$levels)), который является чистым. Если бы вам пришлось изменить имя уровня (и вы использовали строки символов), это было бы на намного менее эффективной операцией. И я сильно меняю названия уровней, особенно для ggplot легенд. Если вы имитируете факторы с помощью векторов символов, есть риск, что вы измените только один элемент и случайно создадите отдельный новый уровень.

29 голосов
/ 10 августа 2010

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

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", ]
18 голосов
/ 16 октября 2013

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

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

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

12 голосов
/ 10 августа 2010

Факторы фантастические, когда кто-то проводит статистический анализ и фактически изучает данные.Тем не менее, до этого, когда кто-то читает, очищает, устраняет неполадки, объединяет и в целом манипулирует данными, факторы являются общей болью.Совсем недавно, как и в последние несколько лет, многие функции были улучшены, чтобы лучше обрабатывать факторы.Например, 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 довольно просты и логичны в использовании.Поэтому, когда я манипулирую, я обычно предпочитаю персонажей факторам.

6 голосов
/ 10 августа 2010

Какой странный заголовок!

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

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

1 голос
/ 06 сентября 2016

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

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 обсуждать.

0 голосов
/ 10 августа 2010

tapply совокупность ) зависят от факторов.Соотношение информации и усилий этих функций очень велико.

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

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