科学の箱

科学・IT・登山の話題

R

factorと数値型の変換

投稿日:2014年5月14日 更新日:

ジニ係数にファクターと数値変換についてコメントをいただいたので調べてみた。

その結果以下の3つのことがわかった。

  • read.csvで桁区切り文字つきの値を読み込むとfactorになる。
  • 区切り文字つき数字はas.numericで変換するとNAになる
  • 桁区切り文字付き数字を数値変換するには桁区切り文字を消去する必要がある。

まず以下のcsvフォーマットで、デフォルト設定で読み込んだときに型を確認する。

Company,TotalRevenues
Pfizer[33] (with Wyeth[34]),"70,696"
Johnson & Johnson,"63,747"
Hoffmann?La Roche,"43,970"
Novartis,"41,460"
GlaxoSmithKline,"40,424"
> revenue<-read.csv(file="data.csv", head=TRUE)
> class(revenue$TotalRevenues)
[1] "factor"

読み込んだ結果はfactorになっていることが確認できた。

unclassでrevenue$TotalRevenuesの内容を確認してみる。

> unclass(revenue$TotalRevenues)
 [1] 46 45 42 41 40 39 33 27 26 20 19 18 17 16 15 14 13 12 11 49 48 47 44 43 38 37 36 35 34 32 31 30
[33] 29 28 25 24 23 22 21 10  9  8  7  6  5  4  3  2  1
attr(,"levels")
 [1] "1,552"  "1,612"  "1,640"  "1,698"  "1,763"  "1,764"  "1,797"  "1,945"  "1,979"  "1,989" 
[11] "10,701" "11,080" "12,300" "13,400" "14,771" "15,407" "15,697" "16,959" "18,634" "19,977"
[21] "2,069"  "2,292"  "2,683"  "2,787"  "2,788"  "23,850" "29,527" "3,026"  "3,063"  "3,187" 
[31] "3,268"  "3,442"  "31,601" "4,264"  "4,426"  "4,694"  "4,700"  "4,897"  "40,328" "40,424"
[41] "41,460" "43,970" "5,175"  "5,583"  "63,747" "70,696" "8,964"  "9,081"  "9,682"

ダブルクォーテーションとカンマについて確認するために、フォーマットを変えてテストをしてみた。

> unclass(as.factor(c(1,2,3)))
[1] 1 2 3
attr(,"levels")
[1] "1" "2" "3"

> unclass(as.factor(c("1000","2000","3000")))
[1] 1 2 3
attr(,"levels")
[1] "1000" "2000" "3000"

> unclass(as.factor(c("1,000","2,000","3,000")))
[1] 1 2 3
attr(,"levels")
[1] "1,000" "2,000" "3,000"

attr(,”levels”)で出力される結果は、入力データの型にかかわらずダブルクォーテーションがつく。カンマはある場合にはそのまま利用されている。

ファクタ型に変換された値について、as.numeircで数値変換をするとラベルが戻ってくる。

> as.numeric(revenue$TotalRevenues[1])
[1] 46

要素同士で足し算をするとエラーになる。

> revenue$TotalRevenues[1]
[1] 70,696
49 Levels: 1,552 1,612 1,640 1,698 1,763 1,764 1,797 1,945 1,979 1,989 10,701 11,080 ... 9,682
> revenue$TotalRevenues[2]
[1] 63,747
49 Levels: 1,552 1,612 1,640 1,698 1,763 1,764 1,797 1,945 1,979 1,989 10,701 11,080 ... 9,682

> revenue$TotalRevenues[1] + revenue$TotalRevenues[2]
[1] NA
 警告メッセージ: 
In Ops.factor(revenue$TotalRevenues[1], revenue$TotalRevenues[2]) :
  +  因子に対しては無意味です

データはそのままでread.csvのパラメータで数値として読み込みができないか調べてみた。その結果2つの方法が使えそうなことがわかったので調べる。

  • 方法1)  stringsAsFactors=FALSEをパラメータで指定する。
  • 方法2) カラムに型を指定する。

stringAsFactors=FALSEを指定してデータを読みこんでみる。

> revenue_c<-read.csv(file="data.csv", head=TRUE, stringsAsFactors=FALSE)
> class(revenue_c$TotalRevenues)
[1] "character"

パラメータを指定した結果、文字型になったことがわかった。

内容を確認してもやはり文字となっている。

> unclass(revenue_c$TotalRevenues)
 [1] "70,696" "63,747" "43,970" "41,460" "40,424" "40,328" "31,601" "29,527" "23,850" "19,977"
[11] "18,634" "16,959" "15,697" "15,407" "14,771" "13,400" "12,300" "11,080" "10,701" "9,682" 
[21] "9,081"  "8,964"  "5,583"  "5,175"  "4,897"  "4,700"  "4,694"  "4,426"  "4,264"  "3,442" 
[31] "3,268"  "3,187"  "3,063"  "3,026"  "2,788"  "2,787"  "2,683"  "2,292"  "2,069"  "1,989" 
[41] "1,979"  "1,945"  "1,797"  "1,764"  "1,763"  "1,698"  "1,640"  "1,612"  "1,552"

では数値変換をしてみると、

> as.numeric(revenue_c$TotalRevenues[1])
[1] NA
 警告メッセージ: 
 強制変換により NA が生成されました

残念ながらNAになってしまった。

次にカラムの型を指定して読み込んでみる。

> revenue_01 <- read.csv(file=”data.csv”,head=TRUE, colClasses=c(“character”, “numeric”))
以下にエラー scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  :
scan 関数は ‘a real’ を期待したのに、得られたのは ‘”70’ でした

エラーとなった。元のデータは以下のようになっている。

Pfizer[33] (with Wyeth[34]),"70,696"

数値として読み込みを強制すると、ダブルクォーテーションを考慮してくれない。このために”70の次に来るカンマが、セパレータとして判断される。しかしこのデータは”70であり、数値には変換できないためにエラーとなっている。これに対して文字列の場合にはダブルクォーテーションで囲まれた値はデータとして取り扱われるために”70の次のカンマはセパレータではなく、データとして保持される。しかしこの場合には読み込まれたデータは文字となる。

カラムの型を”character”にしてみたら問題なく読み込めた

> revenue_01 <- read.csv(file="data.csv",head=TRUE, colClasses=c("character", "character"))
> head(revenue_01)
                      Company TotalRevenues
1 Pfizer[33] (with Wyeth[34])        70,696
2           Johnson & Johnson        63,747
3           Hoffmann?La Roche        43,970

よってread.csvのパラメータで数値として簡単に読み込める方法はない。

read.csvの調査については以下のページを参考にした。

さてここまででread.csvを使って数値読み込みは簡単にできないことがわかったので、factorを数値変換することを考えてみる。

まずfactorについてhelpを確認してみたところ以下の記述が見つかった。

The interpretation of a factor depends on both the codes and the "levels" attribute. 
Be careful only to compare factors with the same set of levels (in the same order). 
In particular, as.numeric applied to a factor is meaningless, 
and may happen by implicit coercion. 
To transform a factor f to approximately its original numeric values, as.numeric(levels(f))[f] is recommended and slightly more efficient than as.numeric(as.character(f)).

ようするにas.numericをfactorにかけることは意味がないよ、もし変換するならば、as.numeric(levels(f)[f]がいいらしい。非効率だが、as.numeric(as.character(f))でもよいらしい。

ということで早速試してみる。

> f<-revenue$TotalRevenues
> as.numeric(levels(f)[f])
 [1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[33] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
 警告メッセージ: 
 強制変換により NA が生成されました 
> as.numeric(as.character(f))
 [1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[33] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
 警告メッセージ: 
 強制変換により NA が生成されました

変換はされたもののすべてNAとなってしまった。factor形式の問題というよりもデータが保管されている形式の問題と考えられる。

数値データに変換できそうなファクターでテストをしてみる。まずはダブルクォートと区切り桁なしの数値で試してみる。

> f<-as.factor(c(1,2,3))
> as.numeric(levels(f)[f])
[1] 1 2 3
> as.numeric(as.character(f))
[1] 1 2 3

ただしく数値変換された。

次にダブルクォートつきのデータで試してみる。

> f<-as.factor(c("1000","2000","3000"))
> as.numeric(levels(f)[f])
[1] 1000 2000 3000
> as.numeric(as.character(f))
[1] 1000 2000 3000

これも正しく変換された。よってダブルクォートが数値データ変換時に認識されないということはない。ではダブルクォートと区切り桁文字で試してみる。

> f<-as.factor(c("1,000","2,000","3,000"))
> as.numeric(levels(f)[f])
[1] NA NA NA
 警告メッセージ: 
 強制変換により NA が生成されました

NAで戻ってきた。よって区切り桁文字に問題がありそうなことがわかる。

以下の意味について考えてみた。

levels(f)[f]

levelsで戻ってくるのはユーザ側で意味を持つデータである。例えば以下のようなファクタを考える。

> f<-as.factor(c("a","b","c","a"))

このときユーザーにとって意味を持つデータは以下である。

"a","b","c"

factor型について属性を含めてみてみる。

> attributes(f)
$levels
[1] "a" "b" "c"

$class
[1] "factor"

データは属性levelsに保管している。このデータを取得するためには、levels()もしくはattr()を使う。

> levels(f)
[1] "a" "b" "c"

> attr(f,"levels")
[1] "a" "b" "c"

levelsの戻り値は文字列のベクトルである。

> class(levels(f))
[1] "character"

ここは推測であるが、levels(f)[f]としたときに[f]の戻り値はindexだと考えられる。具体的にはas.numeric(f)の戻り値である。両方を比較してみると同じ結果が戻ってくることがわかる。

> levels(f)[f]
[1] "a" "b" "c" "a"
> levels(f)[as.numeric(f)]
[1] "a" "b" "c" "a"

factorの仕組みについては以下が詳しい。

区切り桁文字に問題があるとするならば、read.csvで文字型で読み込んでから、numericに変換してもNAが戻ってくること矛盾しない。

では区切り桁文字を取り除いて変換をかけてみたらどうなるか。桁区切り文字のカンマを消してからas.numericをかけてみる。

> f<-as.factor(c("1,000","2,000","3,000"))
> as.numeric(gsub(pattern = ",", replacement = "", x = f, fixed = TRUE))
[1] 1000 2000 3000

よって区切り文字付数値の読み込みについては、区切り文字を消去すればよさそうなことがわかった。

実際のデータを使って検証してみる。以前と同じやり方でcsvを読み込む。

revenue_02 <- read.csv(file="data.csv",head=TRUE)

次に区切り文字を消して数値変換する。

revenue_02$TotalRevenues_n <- as.numeric(gsub(pattern = ",", replacement = "", x = revenue_02$TotalRevenues, fixed = TRUE))

数値に変換されているかを確認する。

> head(revenue_02)
                      Company TotalRevenues TotalRevenues_n
1 Pfizer[33] (with Wyeth[34])        70,696           70696
2           Johnson & Johnson        63,747           63747
3           Hoffmann?La Roche        43,970           43970
4                    Novartis        41,460           41460
5             GlaxoSmithKline        40,424           40424
6              Sanofi-Aventis        40,328           40328
> class(revenue_02$TotalRevenues_n)
[1] "numeric"
> unclass(revenue_02$TotalRevenues_n)
 [1] 70696 63747 43970 41460 40424 40328 31601 29527 23850 19977 18634 16959 15697 15407 14771
[16] 13400 12300 11080 10701  9682  9081  8964  5583  5175  4897  4700  4694  4426  4264  3442
[31]  3268  3187  3063  3026  2788  2787  2683  2292  2069  1989  1979  1945  1797  1764  1763
[46]  1698  1640  1612  1552

ただしく数値変換されることがわかった。

factorと数値の変換については以下を参照した。

 

メタ情報

inarticle



メタ情報

inarticle



-R
-

執筆者:


  1. […] ← factorと数値型の変換 […]

comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

no image

Rによるやさしい統計学/6-2つの平均値を比較する

(1) 統計が好きか嫌いかで統計テスト1の得点について有意な差はあるか。 指導法データは score.csvに作成する。 ID,名前,性別,数学,統計,心理学テスト,統計テスト1,統計テスト2,指導法 …

no image

R Dataset – bone

データの説明 261人の子供たちから得られた年齢別骨密度。 フォーマット idnum: 識別コード age: 測定時の年齢 gender: 性別 spnbmd: 骨密度 チェック テーブル全体について …

no image

因子分析

因子分析とは 因子分析では複雑な現象を単純な要因で理解するための手法。集められた個別のデータは結果である目的変数とその目的変数の原因である説明変数に分かれる。目的変数を観察できた結果とし、目的変数に影 …

no image

分散分析のcase study-2

分散分析のcase study-1からの続き。 さて前回まででとりあえずデータの簡単な分析を終えて、以下のような結論を得た。 図1よりR1とR2を比較するとスピードはR1のほうが常に上である。またS1 …

no image

Rで集計をする

バイナリ ifelse()を利用する ファクタ factor()を利用する カテゴリ集計 cut()関数を利用する クロス集計 Rではクロス集計表を簡単に作れる。クロス集計表はtable()を利用する …

2014年5月
« 4月   6月 »
 1234
567891011
12131415161718
19202122232425
262728293031  

side bar top



アーカイブ

カテゴリー