StatsBeginner: 初学者の統計学習ノート

初学者が統計学、機械学習、R、Pythonの勉強の過程をメモっていくノート。

Rの指数表示を回避するoptions(scipen)の法則

Rの指数表示の回避方法

 以前、別のブログのほう(リンク)で、Rの指数表示の回避を行う方法についてのエントリを書いたのですが、せっかく統計とRに関するブログを書き始めたので、こっちに転載しておきます。
 元の記事ではいろいろ悩んだ過程を書いてるのですが、なんとR-1.8.0のリリースノートの日本語訳をされていた方がコメントを下さって、一瞬で解決しました。記事のほとんどの部分は結果的に無駄になったのでw、疑問の部分と、コメントによって解決した結論だけ書いておきます。

元のエントリからの部分的コピペ(一部修正済み)

 Rで桁数の大きい数値を表示しようとすると、指数表示になってしまうのがウザいと思いました。

> 1000000000  #10億
[1] 1e+09


 みたいな感じです。まぁこれはExcelでもよくあることで、べつに指数表示になっていても単に数字を見るだけなら構わない場合もあるんですが、計算の結果出てきた数値を1の位までコピペしてどっかに貼りたい時とかもあるわけです。


 で、ネットで調べるとこれは一応回避する方法があって、options()関数にscipen=数値という引数を指定すればいいらしいということが分かりました。つまり、

> options(scipen=10)
> 1000000000  #10億
[1] 1000000000


 というふうに固定表示ができるわけです。ちなみにscipenのデフォルト値はゼロだそうです。
 他に、桁数の表示的なもので困ることがあるのは、小数の有効桁数ぐらいですかね。

> pi  #円周率
[1] 3.141593


 みたいな感じになるんですが、有効数字についてはdigitsという引数(デフォルトは7らしい)があるので、

> options(digits=22)  #22が上限
> pi
[1] 3.141592653589793115998


 というふうにすることができます。


 ところで、"digits"は、指定した値がそのまま有効桁数になるので分かりやすいです。しかし、さっきの"scipen"のほうは、どのぐらいの値に設定すれば、どのぐらいの値まで指数表示を回避できるのかというのが、よく分からない。
 各種解説サイトをみても、「scipenの値を大きくしておけば、指数表示されにくくなる」みたいに、曖昧に解説されているだけです。

http://rstudio-pubs-static.s3.amazonaws.com/724_9a4767462a12489ba2d0fe07351f62c5.html
http://stat.ethz.ch/R-manual/R-patched/library/base/html/options.html


scipenに正の整数を指定し、その値が大きいほど桁数の大きな数値でも指数表記を回避しやすくなる。一方、負の整数を指定すると指数表記になりやすくなる。

http://cse.naro.affrc.go.jp/takezawa/r-tips/r/11.html


scipen を変更することで指数部分に表現しなおされる基準の桁数を変えることが出来る.デフォルトの値は 0 で,値を増やせば基準の桁数が増える.


 R1.8.0のリリースノートの粗訳というページをみてみると、

R-1.8.0リリースノート粗訳


options("scipen")は,数値を固定小数点表示するか指数表示するかを,ある程度ユーザが制御できるようにする(David Brahmの貢献による)。(中澤注:R-Announceに流れたメールではoption("scipen")となっていたが,明らかにtypoである。helpによると,scipenは整数値で指定し,数値を固定小数点表示か指数表示かを決めるときのペナルティとして使われる。正方向だと固定小数点表示されやすくなり,負方向だと指数表示されやすくなる)


 と解説されてました。「ある程度」て。
 ちなみに実際には(というか現在のバージョンではというべきか)、scipenに小数の値を入れても機能します。


 で、Yahoo!知恵袋の力によって、10の累乗を計算していく分には、たとえば


 options(scipen=x)


 とした場合に


 10^(x+4) ・・・固定表示
 10^(x+5) ・・・指数表示


 となる単純な関係があることがわかり、

> options(scipen=18)
> 10^22
[1] 10000000000000000000000


 まではこのとおりに動いてくれます。
 桁をこれより1つ大きくしようとすると、

> options(scipen=19)
> 10^23
[1]  99999999999999991611392


 となってしまって、そもそも数値の表示そのものが崩れてしまうようです。Rの、ソフトとしての限界なんでしょう。
 また、よく分からないのが、たとえばscipen=10なら16桁の数字はすべて指数表示になってしまうのかというとそうでもなくて、

> options(scipen=10)
> 10^15  #16桁
[1] 1e+15
> 5555555555555555  #16桁
[1] 5555555555555555


 みたいなことも起きるので、「桁」という概念はあまり関係ないのかも知れません。
 さきほど引用した解説サイトの一つは、

関数option()のscipenによって指数表記を回避する


細かいことは考えずに options(scipen=100) にしている。


 と言っており、たぶん、細かいことは考えないほうがいいようです。

 

明らかになった結論

 ブログのコメント欄にコメントを頂いて、簡単な法則になっていることが分かりました。
 コメントを引用します。

Yahooアカウントがないので知恵袋には回答できませんでしたが,scipenのルールはそんなに複雑ではありません(URL先として入力したページをご覧ください)。
指数表示にした時に必要な文字列長と指数でない表示にした時に必要な文字列長の差がscipenで指定した数値を超えると指数表示になります。
なお,Rでは実数保持バイト数の制約から1e+23すら正確に保持できませんが,gmpパッケージやRmpfrパッケージを使えば扱えます。
ご参考まで。

鵯記 (bulbul records)


もう少し丁寧に例示するため,1300000の場合を考えてみる。

Rコンソールに,1300000と打ってエンターキーを押すと,[1] 1.3e+07と表示される。"1.3e+07"という表示は文字列として7桁あるから,8桁で表示できる"13000000"という表示をさせるには,8桁と7桁の差である1以上の数字をscipenに指定すればいい。

果たして,options(scipen=1)と打ってから13000000を打ったら,ちゃんと13000000と表示されることが確認できた。


 なるほど簡単!
 あと、大きい数字の保持には限界があるんですね。このへんって、コンピュータが数値というものをどういうふうに処理しているのかを知らない私のような人間には、よくわからないところです。


 ところで、この結論を得た上でRのヘルプ(options関数の項)を読むと最後に言ってることの意味が分かります。

scipen:
integer. A penalty to be applied when deciding to print numeric values in fixed or exponential notation. Positive values bias towards fixed and negative towards scientific notation: fixed notation will be preferred unless it is more than scipen digits wider.*1


 最初は何のことを言ってるのか分からず読み飛ばしてましたが、「固定表示した場合の文字数(桁数)が、scipenに設定した値よりも大きな値分だけ、指数表示した場合の字数よりも大きくないならば、固定表示になる」と。比較級が重なってしかもunlessなので分かりづらいですが、要するに「固定表示した場合の文字数が、指数表示した場合の文字数よりも、scipenの値分を超えて大きい場合は、指数表示になる」ということですね。
 たしかに、桁数が増えると数字が見づらくなるという問題を解決するための指数表示なので、「計算結果を実際に表示したときに、固定表示の場合と指数表示の場合でそれぞれ何文字になるか」を比べているというのは、自然な発想ですね。
 なぜペナルティという単語が使われているのかはよく分かりませんが、制約条件付きの最適化問題を解く時のペナルティ関数法のペナルティと似た語感なんでしょうか。

*1:指数表示のことは英語でscientific notationというらしい。