簡體   English   中英

R 中的因素:不僅僅是煩惱?

[英]Factors in R: more than an annoyance?

R 中的基本數據類型之一是因子。 根據我的經驗,因素基本上是一種痛苦,我從不使用它們。 我總是轉換為字符。 我覺得奇怪,好像我錯過了什么。

是否有一些重要的函數示例,這些函數使用因子作為需要因子數據類型的分組變量? 是否有特定情況下我應該使用因子?

你應該使用因素。 是的,他們可能是一種痛苦,但我的理論是,他們之所以痛苦的原因有90%是因為在read.tableread.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)

變量變換為factor Species

一個棘手的問題是整個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" data.frame上使用drop=TRUE不能像你想象的那樣工作:

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傳說。 如果您使用字符向量偽造因子,則存在您只更改一個元素並意外創建單獨的新級別的風險。

有序的因素是很棒的,如果我碰巧喜歡橘子和討厭蘋果,但不介意葡萄,我不需要管理一些奇怪的索引來說:

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

一個factor最類似於其他語言中的枚舉類型。 適當的用途是變量,它只能采用一組規定的值。 在這些情況下,並非每個可能的允許值都可以存在於任何特定數據集中,並且“空”級別准確地反映了這一點。

考慮一些例子。 對於在美國各地收集的一些數據,應將州記錄為一個因素。 在這種情況下,沒有從特定州收集案件的事實是相關的。 可能有來自該州的數據,但發生了(無論出於何種原因,這可能是感興趣的原因)。 如果收集家鄉,那將不是一個因素。 沒有預先設定的可能的家鄉。 如果從三個城鎮而不是在全國范圍內收集數據,該城鎮將成為一個因素:一開始就有三個選擇,如果在這三個城鎮中沒有一個發現相關案例/數據,則這是相關的。

factor s的其他方面,例如提供給一組字符串賦予任意排序順序的方法,是factor s的有用次要特征,但不是它們存在的原因。

當人們進行統計分析並實際探索數據時,因素非常棒。 然而,在此之前,當人們正在閱讀,清理,排除故障,合並並且通常操縱數據時,因素是完全痛苦的。 最近,與過去幾年一樣,許多功能已得到改進,可以更好地處理這些因素。 例如,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討論能力。

我有一個相當具體的情況,其中因素可以變得方便。 想象一下,您想通過另一個分組變量g來查看變量x的均值,而g有一些NA s。 所以我們得到的是這樣的:

df <- data.frame(x= rnorm(10), g= sample(1:2, 10, replace= TRUE))
df$g[1] <- NA
aggregate(x ~ g, df, mean)
  g          x
1 1  1.0415156
2 2 -0.3071171

如您所見,對於gNA的情況,我們沒有得到x的平均值。 如果我們使用by代替(參見by(df$x, list(df$g), mean)by(df$x, list(df$g), mean)同樣的問題也是如此。 我們可以做的是添加NA作為因子水平,這將導致輸出,其中也給出了NA的均值。 看這里:

aggregate(x ~ addNA(g), df, mean)

addNA函數將向量轉換為因子並將NA添加為因子級別。 例如,這有助於aggregateby等函數。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM