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



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



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

576   7  

7 ответов:

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

предупреждение: In 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() is разные: см. этот адрес электронной почты или ?"[.data.frame". Используя drop=TRUE on data.frames не работает, как Вы себе представляете:

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 легенды.

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

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

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

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

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

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

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

какое язвительное название!

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

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

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

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

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

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

Comments

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