一所懸命に手抜きする

デスクワークばかりのスポーツ嫌いで50歳も過ぎ、いよいよ足腰に衰えを感じつつある昨今。

【R】factor型について(2)_因子型(factor)から数値型(numeric)に戻すと数値が変わる?

数値(numeric型)を因子(factor型)として扱う時には注意を

 前回、factor型(1)_Levels:・・・って?では
 Levels: ○,○・・・ のように記載されているのはfactor型で、文字型のデータをデータフレームに引き渡すとfactor型として処理されることをとりあげました。たとえ中身が数値であっても文字列として引き渡すとfactor型になってしまうのでした。
a-habakiri.hateblo.jp  今回の内容は、例えば、c(2,3)という数値型をfactor型に変換した後、数値型に変換すると1,2になって元の値と変わってしまって困るなあというものです。

# Sample 1  vector→numeric
  nm<-c("2","3","4","5")
  as.numeric(nm)
##[1] 2 3 4 5

 Sample 1 では、文字(character型)ベクトルを数値(numeric型)に戻しています。"2"→2と当たり前に変換されています。

数値(numeric型)を因子(factor型)に変換すると数値が変わってしまうように見える

 次に、

# Sample 2  numeric→factor→numeric
  nm<-c(2,3,4,5)
  as.factor(nm)
##[1] 2 3 4 5
##Levels: 2 3 4 5
  as.numeric(as.factor(nm))
##[1] 1 2 3 4

 Sample 2 では、 数値(numeric型)ベクトルを因子(factor型)に変換した後、数値(numeric型)に戻しています。
 2→"2"→1 となっていて、数値が変わっています。この後の処理に支障をきたすことが多いでしょう。

factorは元データをソートした結果を1から順に連番にして返す(デフォルト)

文字(character)型の体裁の数値をdata.frameに変換した時も数値が変わってしまうように見える

 続いて二つのサンプルを比較してみます。

# Sample 3  numeric→data.frame(factor)→numeric
  nm<-c(2,3,4,5)
  df<-data.frame(nm)
  df$nm
##[1] 2 3 4 5
  as.numeric(df$nm) 
##[1] 2 3 4 5

 Sample 3 では数値ベクトルをデータフレームに変換していますが、そのまま数値として元の値で処理されています。

# Sample 4  (numeric)character→data.frame(factor)→numeric
  nm<-c("2","3","4","5")
  df<-data.frame(nm)
  df$nm
##[1] 2 3 4 5
##Levels: 2 3 4 5
  as.numeric(df$nm) 
##[1] 1 2 3 4

 Sample 4 では数値を文字型ベクトルとしてデータフレームに変換していますが、factor型として処理され、数値はもとの値とは変わっています。

ファイル読み込みのときにも注意

 データをファイルから読み込みデータフレームにする場合にも注意が必要です。
 数値の列のはずが、文字列として扱われてしまうとfactor型に変換されてしまいます。
 それはSample2,Sample4と同じことです。
 

factor型で数値が変わらないようにするための対策

対策1

 数値をfactor型に変換すると、as.numericで数値に戻してももとに戻らないことがあります(Sample5)。

# Sample 5
  nm<-c(2,3,4,5)
  as.factor(nm)
##[1] 2 3 4 5
##Levels: 2 3 4 5
  as.numeric(as.factor(nm))
##[1] 1 2 3 4

# Sample 6  counterplan
  as.character(as.factor(nm))
##[1] "2" "3" "4" "5"
  as.numeric(as.character(as.factor(nm)))
##[1] 2 3 4 5

 対策としては、Sample6のようにas.numeric(as.character())で一旦文字型に変換した後、数値型に戻すのが簡単かと思います。

対策2

 ファイルからの読み込みの際に勝手にfactor型に変換されて困るのであれば、read.csv() などで stringsAsFactors=FALSE を指定すれば問題が解消するでしょう。

read.table(...,stringsAsFactors=FALSE)
read.csv(...,stringsAsFactors=FALSE)