ジニ係数にファクターと数値変換についてコメントをいただいたので調べてみた。
その結果以下の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の調査については以下のページを参考にした。
- R:read.csv / read.tableで型と列名を指定して読み込む。
- Importing csv file into R – numeric values read as characters
- Imported a csv-dataset to R but the values becomes factors
さてここまでで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.numericapplied to a factor is meaningless, and may happen by implicit coercion. To transform a factorfto approximately its original numeric values,as.numeric(levels(f))[f]is recommended and slightly more efficient thanas.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と数値の変換については以下を参照した。
- [R]numericとfactorの相互変換
- How to convert factor format to numeric format in R without changing the values? [duplicate]
- How to convert a factor to an integer\numeric without a loss of information
- Converting a factor to numeric without losing information R (as.numeric() doesn’t seem to work) [duplicate]
- Numeric variables converted to factors when reading a CSV file
[…] ← factorと数値型の変換 […]