Rの要因:煩わしさ以上のもの?


95

Rの基本的なデータ型の1つは因子です。私の経験では、要素は基本的に苦痛であり、私はそれらを使用することはありません。私はいつもキャラクターに変換します。何かが足りないように感じます。

因子データ型が必要になるグループ化変数として因子を使用する関数のいくつかの重要な例はありますか?ファクターを使用する必要がある特定の状況はありますか?


7
この質問を見つける可能性が高い初心者Rユーザー向けにこのコメントを追加します。私は最近、以下の回答からの情報の多くを、いつ、どのように、なぜRでファクターを使用するかについての説明チュートリアルにまとめたブログ投稿を書きました 。gormanalysis.com/?p
Ben

私は常に、各エントリがレベルへのポインタであるかのように、ファクタは文字よりも効率的に格納されると想定していました。しかし、これを書くためにそれをテストすると、私はそれが真実ではないことがわかりました!
同型写像

2
よく@isomorphismes、使用 Rの以前の日で、真実であると、それが変更されました。このブログ投稿を参照してください:simplystatistics.org/2015/07/24/…– MichaelChirico 2017
1

4
数年後に、この「stringsAsFactors:不正伝記は」5+書かれていた:simplystatistics.org/2015/07/24/...
JDロング

回答:


49

係数を使用する必要があります。はい、彼らは苦痛になる可能性がありますが、私の理論では、彼らが苦痛である理由の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

トリッキーなことの1つは、全体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、の動作[.data.frame()が異なります?"[.data.frame"このメールまたはを参照してください。s を使用drop=TRUEdata.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凡例に入れないようにする方法です。

内部的には、factorsは属性レベルの文字ベクトル(attributes(iris$Species)およびを参照class(attributes(iris$Species)$levels))を持つ整数であり、クリーンです。レベル名を変更する必要がある場合(および文字列を使用している場合)、これははるかに効率の悪い操作になります。そして、特にggplot伝説の場合、レベル名を頻繁に変更します。文字ベクトルを使用して因子を偽造した場合、1つの要素のみを変更し、誤って別の新しいレベルを作成するリスクがあります。


1
stringsAsFactors関数ではありません。
IRTFM 2013

30

順序付けられた要素は素晴らしいです。もし私がたまたまオレンジが好きで、リンゴが嫌いなら、ブドウを気にしないのであれば、奇妙なインデックスを管理する必要はありません。

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

それはきちんとしたアプリケーションです。そのことを考えたことはありません。
JD Long

何をしたのd$f <- ordered(d$f, c("apples", "grapes", "oranges"))?私はそれがデータフレームでこれらを注文したと思ったでしょうが、その行を実行してデータフレームを印刷した後、何も変更されません。印刷された注文が変更されない場合でも、内部注文を課すだけですか?
Addem 2014年

...ええ、私が書いたのは正しい文章のようなものだったと思います。私があなたの要点を理解している場合、あなたは因子に順序付けを割り当てることができることを示しています。これは文字列に対して行うことができないことです。
Addem 2014年

4
ordered()は、任意の値から任意の順序を作成します-順序付けられたと言う順序で。辞書編集でソートされた値を使用したのは残念ですが、それは偶然です。たとえば、「Z」が悪い、「3」は良いがラベルは数値でアルファベットでもないデータにこれを使用します-したがって、ordered(data、c( "Z"、 "B"、 "A"、 " 0、「1」、「2」、「3」))なので、データ>「A」を実行するだけで、幸せな日々を過ごせます。
mdsumner 2014年

19

A factorは、他の言語の列挙型に最も類似しています。その適切な使用は、指定された値のセットの1つだけを受け取ることができる変数です。これらの場合、すべての可能な許容値が特定のデータセットに存在するわけではなく、「空」レベルはそれを正確に反映します。

いくつかの例を考えてみましょう。米国全体で収集された一部のデータについては、州を要因として記録する必要があります。この場合、特定の州からケースが収集されなかったという事実が関係します。その州からのデータがあった可能性がありますが、(何らかの理由で、関心の理由である可能性があります)ないことが起こりました。故郷が集まったとしても、それは要因にはなりません。考えられる出身地の事前設定されたセットはありません。全国ではなく3つの町からデータが収集された場合、その町は1つの要因になります。最初に3つの選択肢があり、これらの3つの町のいずれかで関連するケース/データが見つからなかった場合、それは関連しています。

factor文字列のセットに任意のソート順を与える方法を提供するなど、sの他の側面は、sの有用な2次的な特性ですfactorが、それらが存在する理由ではありません。


3
+1。ブライアン、データにないレベルのキャプチャで頭を釘付けにしたと思う。
Ricardo Saporta 2013年

13

統計分析を行って実際にデータを調査しているとき、要因は素晴らしいです。ただし、その前に、データの読み取り、クリーニング、トラブルシューティング、マージ、および一般的な操作を行う場合、要因は非常に苦痛です。最近では、過去数年のように、多くの機能が改善され、要因をより適切に処理できるようになりました。たとえば、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の文字列関数は非常に使いやすく論理的です。したがって、操作するときは、通常、ファクターよりもキャラクターを好みます。


1
因子を使用する統計分析の例はありますか?
JDロング

3
現在、base-R関数がありますdroplevels()。そして、それはデフォルトで因子を再配列しません。
Ben Bolker 2013年

6

なんて卑劣なタイトルだ!

多くの推定関数を使用すると、因子を使用して簡単にダミー変数を定義できると思いますが、私はそのためにそれらを使用しません。

ユニークな観測が​​ほとんどない非常に大きな文字ベクトルがある場合に使用します。これにより、特に文字ベクトルの文字列が長めである場合に、メモリ消費を削減できます。

PS-私はタイトルについて冗談を言っています。ツイートを見ました。;-)


1
つまり、実際にそれらを使用してストレージスペースを節約します。それは理にかなっている。
JD Long

13
まあ、少なくともそれは;-)に使用されました。しかし、いくつかのRバージョン前の文字ストレージは内部でハッシュされるように書き直されたため、この歴史的な議論の一部は無効になっています。それでも、因子はグループ化とモデリングに非常に役立ちます。
Dirk Eddelbuettel、2010

1
よれ?factorば、R-2.6.0であり、それは言う、「文字列への各参照は、4または8バイトのポインタを必要とするのに対し、整数値は4バイトに格納されています。」文字列に8バイトが必要な場合、スペースを因数に変換して節約しませんか?
Joshua Ulrich

2
N <-1000; a <-sample(c( "a"、 "b"、 "c")、N、replace = TRUE); print(object.size(a)、units = "Kb"); print(object.size(factor(a))、units = "Kb"); 8 Kb 4.5 Kbなので、スペースを節約できるようです。
Eduardo Leoni

2
@Eduardo 4.2Kbに対して4Kbを取得しました。以下のためにN=100000I 391.8 KB対391.5 KBを得ました。したがって、factorはメモリをほとんど消費しません。
Marek

1

要因は、優れた「ユニークなケース」のバッジエンジンです。私はこれをひどく何度も再現しましたが、たまにいくつかのしわにもかかわらず、それらは非常に強力です。

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については説明していません。


-2

Tapply(および Aggregate)は、要因に依存しています。これらの関数の情報と努力の比率は非常に高いです。

たとえば、1行のコード(以下の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

7
これらの例はすべて文字列でも機能するため、これは良い例ではありません。
ハドリー2010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.