2020/2/26改訂
Levels:・・・って?
Rで data.frame を処理して得られた戻り値の下に
Levels: ○,○・・・ のように記載されていることがあります。
これはfactor型と言うらしい
わかりにくいので調べてみました。
例として、文字列ベクトルを用意します。
# Sample1 >( Vc<-c("Jan","Feb","Mar","Apr") ) [1] "Jan" "Feb" "Mar" "Apr"
続いて、文字列をfactor型に変換してみます。
factor型では文字型要素に順序がつく(デフォルトは辞書順)
# Sample2 > Vc<-factor(c("Feb","Jan","Mar","Apr")) > names(Vc)<-c("2月","1月","3月","4月") > Vc 2月 1月 3月 4月 Feb Jan Mar Apr Levels: Apr Feb Jan Mar
Levels: Apr Feb Jan Mar は月順ではなく辞書順ですね。
factor型は順序番号を持っている
factor型では見えないけれど順序番号が振られている
factorとは日本語では因子と言いますが、この例では Jan とか Feb が因子です。これらに(デフォルトでは)辞書順で順番をつけたのがfactor型です。
つけた順序は as.integer() により確認できます。
# Sample2 続き > as.integer(Vc) [1] 2 3 4 1
Levels: Apr Feb Jan Mar の順にFeb=2 Jan=3 Mar=4 Apr=1 と因子に順序が割り振られています。
順序をつけるとソートができる
順序をつけるとソートができるようになります。
# Sample2 から続く > sort(Vc) 4月 2月 1月 3月 Apr Feb Jan Mar Levels: Apr Feb Jan Mar
因子が辞書順にsortされています。
辞書順以外も指定できる
順序(並べ方)は、辞書順が都合が良いとは限りません。希望の並べ方を引数 levels=c(,,,) にて指定することができます。辞書順に並んでいた月名を、月順に設定します。
# Sample3 > Vc<-factor(c("Feb","Jan","Mar","Apr"),levels=c("Jan","Feb","Mar","Apr")) > names(Vc)<-c("2月","1月","3月","4月") > Vc 2月 1月 3月 4月 Feb Jan Mar Apr Levels: Jan Feb Mar Apr > sort(Vc) 1月 2月 3月 4月 Jan Feb Mar Apr Levels: Jan Feb Mar Apr
Levels: Jan Feb Mar Apr が月順になりました。これにより、因子が希望通り月順にsortできています。
factor型では因子の大小比較も可能にできる
ordered=TRUE
因子の順序を利用して行える操作はソートくらいですが、順序に大小関係を付与することもできます。その場合にはfactor()関数の引数に ordered=TRUE(デフォルトではFALSE) を指定します。
大小関係が付与されると、~以下、~より大きいといった比較ができるようになります。
# Sample4 > ( Vc<-factor( c("Jan","Feb","Mar","Apr"),levels=c("Jan","Feb","Mar","Apr"),ordered=TRUE ) ) [1] Jan Feb Mar Apr Levels: Jan < Feb < Mar < Apr ## Mar より前(小さい) > Vc<-[Vc<"Mar"] [1] Jan Feb Levels: Jan < Feb < Mar < Apr
単純な文字列比較ですと "Apr" < "Jan" ですが、Sample4の場合、levelsで指定した順序により Jan=1 Feb=2 Mar=3 Apr=4 となったので Mar=3 より小さい Jan,Feb が抽出されます。
ordered=TRUE なしでは大小比較できない
# Sample5 >Vc<-factor(c("Jan","Feb","Mar","Apr"),levels=c("Jan","Feb","Mar","Apr")) >Vc[Vc<"Mar"] [1] <NA> <NA> <NA> <NA> Levels: Jan Feb Mar Apr 警告メッセージ: Ops.factor(Vc,"Mar") で: ‘<’ not meaningful for factors
警告メッセージの意味は「因子どうしで大小比較はできない(意味がない)」というものです。ordered=TRUE をつけないと大小比較ができないということです。
後からordered()関数を通す手もある
factor() 関数の引数に ordered=TRUE をつけるのを忘れた場合には、ordered() 関数を通せば大小比較ができるようになります。
# Sample6 >Vc<-factor(c("Jan","Feb","Mar","Apr"),levels=c("Jan","Feb","Mar","Apr")) Vc<-ordered(Vc) Vc[Vc<"Mar"] [1] Jan Feb Levels: Jan < Feb < Mar < Apr
invalid factor level, NA generated
最初のlevelsに設定した因子以外は追加できない
factor型ベクトルには levels= に設定した因子は追加できますが、設定外の因子は NA となります( invalid factor level, NA generated )。
# Sample7 >Vc<-factor(c("Jan","Feb","Mar","Apr"),levels=c("Jan","Feb","Mar","Apr")) > Vc[5]<-"Jan" Vc[6]<-"May" 警告メッセージ: `[<-.factor`(`*tmp*`, 6, value = "May") で: invalid factor level, NA generated >Vc [1] Jan Feb Mar Apr Jan <NA> Levels: Jan Feb Mar Apr
実務的な例で言えば、データフレームAにデータフレームBを rbind() する時に、factor型のカラムにてAにはない値がBに出てきた場合にこのようなエラーが出ます。
文字型のデータをデータフレームに引き渡すとfactor型として処理される
文字列をdata.frameにするとfactor型になる
# Sample8 > mn<-c("5","2","3","4") > en<-c("May","Feb","Mar","Apr") > df<-data.frame(mn,en) > df$mn [1] 5 2 3 4 Levels: 2 3 4 5 > df$en [1] May Feb Mar Apr Levels: Apr Feb Mar May
mn のように数値であっても文字型としてデータフレームに引き渡すとfactor型として処理されています。
factor型にしたくない時はstringsAsFactors=FALSEをつける
data.frame(.....,stringsAsFactors=FALSE)```のようにしてやると
# Sample9 > mn<-c("5","2","3","4") > en<-c("May","Feb","Mar","Apr") > df<-data.frame(mn,en,stringsAsFactors=FALSE) > df$en [1] "May" "Feb" "Mar" "Apr" > df$mn [1] "5" "2" "3" "4" > class(df$mn) [1] "character"
stringsAsFactors=FALSEとすることで、文字列はfactor型ではなくcharacter型になりました。
factor型ではなくcharacter型にすればデータ追加可能
# Sample10 Sample9の df を使用 df[5]<-c("12","Dec") > df[5,]<-c("10","Oct") > df mn en 1 5 May 2 2 Feb 3 3 Mar 4 4 Apr 5 10 Oct
最初の要素( 2,3,4,5 や Feb Mar Apr May )にはなかった 10 Oct が追加されています。エラー( invalid factor level, NA generated )が回避できました。
数値からなる factor型をnumeric型にするとトラブルが発生するかも
数値をfactor型として、さらにnumeric型にすると…
# Sample11 > ( fc<-factor(c("5","2","3","4")) ) [1] 5 2 3 4 Levels: 2 3 4 5 > fc[1] [1] 5 Levels: 2 3 4 5 > ( nm<-as.numeric(fc) ) [1] 4 1 2 3 > nm[1] [1] 4
5だった要素が4になるなど数値が変わっています。困りますね。