The Midnight Seminar

読書感想や雑記です。近い内容の記事を他のWeb媒体や雑誌で書いてる場合があります。このブログは単なるメモなので内容に責任は持ちません。

Rの指数表示はどこまで回避できるのか【結果的に意味がなかったエントリ】

【追記】本文は読まず、コメント欄から読んで下さい。

 私は統計も数学もあまり知らないしプログラミングはまったくの素人ですが*1、統計ソフトの「R」というやつがちょっと面白いので使っています。

 で、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の値を大きくしておけば、指数表示されにくくなる」みたいに、曖昧に解説されているだけです。

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


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


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

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


http://minato.sip21c.org/swtips/R180.html


 と解説されてました。「ある程度」て。
 ちなみに実際には、後述するように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


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

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


http://rstudio-pubs-static.s3.amazonaws.com/724_9a4767462a12489ba2d0fe07351f62c5.html


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


 ところで、大学院時代にプログラミングを研究していた後輩にきいてみたところ、「コンピュータの世界だから、10の累乗ではなく2の累乗と関係してるんじゃないですか?」とのこと。
 私にはよく分かりませんが、コンピュータにとっては2の累乗という数字が扱いやすいらしいので、2の累乗を基準になんかの処理が行われて扱える数値の範囲がきまってるのかもしれない。


 また、ひょっとしたら、2の累乗だったらもっと大きな数字でもきちんと表示できるのかもしれない。
 実際、2の累乗で試してみると、

> options(scipen=50)
> 2^205
[1] 51422017416287688817342786954917203280710495801049370729644032


 みたいなことができました(scipen=50の場合、2の206乗だと指数表示になる)。
 さっき、10の累乗を表示しようとすると23桁(10の22乗)が限界だったのに、2の累乗だと62桁というデカい数字でもちゃんと表示できるわけです。
 いや、"ちゃんと表示"されてるのかというと、↑の数字がほんとに2の205乗なのか確認しないといけないんですが、コピペして対数を計算すると、

> x <- 51422017416287688817342786954917203280710495801049370729644032
> log(x, 2)
[1] 205


 というふうにはなったので、正しそうな気がするということにしておきます。
 ちなみに、どうやら固定表示できる数値の範囲は、scipenが増えれば大きくなるというだけではなく、有効数字が増えると大きくなるという関係もあるみたいです。
 なのて、有効数字をdigits=22と最大値に設定して、2の累乗がどこまで耐えられるのかを試してみました(ついでに「2のマイナス○乗」も試しておきました)。
 たとえばscipen=200というところまでいくと、

> options(digits=22, scipen=200)
> 2^757
[1] 758065474756205534740712640850831325809026375545262017157740252942407691741394964028749223060862538061761587254458531838950966818415436714572405896016201728127175281260180617944465471499803928137335448825056869507271897877839872
> 2^758
[1] 1.516130949512411069481e+228
> 2^-680
[1] 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001993438990219513507102
> 2^-681
[1] 9.967194951097567535511e-206
>


 となります。つまり、2の757乗やマイナス680乗までは固定表示できて、758乗やマイナス681乗は指数表示になるわけです。
 で、どんどん大きいscipenを試していくと、scipen=280のときに限界が来ました。

> options(digits=22, scipen=280)
> 2^1023
[1] 89884656743115795386465259539451236680898848947115328636715040578866337902750481566354238661203768010560056939935696678829394884407208311246423715319737062188883946712432742638151109800623047059726541476042502884419075341171231440736956555270413618581675255342293149119973622969239858152417678164812112068608
> 2^1024
[1] Inf


 2の1024乗は、R的にはInf、つまり「無限大」らしいです。
 これはscipenの値を1万とかの大きな値にしても、変わりませんでした。無限なんですね。
 ちなみにscipen=280のときの、マイナス●乗のほうはどうなるかというと、

> options(digits=22, scipen=280)
> 2^-946
[1] 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001681218273811814911728
> 2^-947
[1] 8.40609136905907455864e-286


 となり、マイナス946乗までは固定表示できて、マイナス947乗は指数表示になります。
 このマイナスのほうを突き詰めていくと、マイナス1075乗のときに限界が来ることが分かります。

> #めんどうなので、scipenを1万と大きくしておいて試す
> options(digits=22, scipen=10000)
> 2^-1074
[1] 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441766
> 2^-1075
[1] 0


 2のマイナス1075乗は「ゼロ」になりました。
 ちなみに、2のマイナス1074乗を固定表示できるのは、あとで試してみるとscipen=319からでした。


 つまりRの内部では、2の1024乗みたいな巨大な値や、2のマイナス1075乗みたいな桁数の多い少数は、扱わないことにしてるんでしょう。
 ちなみに、この「Rそのものの限界」がどこらへんにあるか(1023乗と1024乗の間のどこかと、マイナス1074乗とマイナス1075乗の間のどこか)というのをためしてみると、たとえばかけ算で確認すると、

options(digits=22, scipen=100000000) #ノリでscipenは1億にしてみた

2^1023*1.99999999999999988897 #固定表示される
2^1023*1.99999999999999988898 #無限大になる

2^-1074*0.50000000000000006 #固定表示される
2^-1074*0.50000000000000005 #ゼロになる


 という感じになりました。(みづらいので出力結果は載せていません。)
 ただ、コンピュータの世界なので、単なる数字の大小によって限界が決まっているわけではないのかも知れません。さっきの2の累乗の話みたいな感じで、数字の大きさと言うよりはコンピュータにとっての情報量の大きさみたいなやつで決まってるんでしょうかね。


 結局、Rそのものの限界によって、だいたい2の1023乗〜2の-1074乗ぐらいまでしか扱えないのであれば、scipenの値も1万とか1億に設定しても仕方ないということなんでしょう。
 2の1023乗を固定表示可能にするのはscipen=280からであり、2のマイナス1073乗を固定表示可能にするのはscipen=319からですから、まあ300ちょっとよりも大きな値を設定しても意味ないんでしょう。


 ちなみにどうでもいいことですが、たとえば2のマイナス1073乗はscipen=319から固定表示可能だと書いたものの、じつはscipenには小数の値を入れることもできまして、試してみると

 scipen = 318.99999999999997
 scipen = 318.99999999999998

 の間に、2のマイナス1073乗が固定表示可能になるかどうかの境目があることが分かりました。
 ていうか、もっと細かく確かめると、scipenの閾値は、


318.9999999999999715799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999000000000000000000000000000000000000000000000000000000000000000000000000000000000000000999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001


 という値と、最後の「01」を「1」に変えた値の間のどこかにあることが分かりましたが、ほんとにどうでもいいことです。
 しかも、何度も言ってるように、「単純に数字の大小が問題なのではない」かもしれないので、私みたいな素人がこれ以上考えても意味はないでしょう。


 というか、そもそも何十桁という数字を実際に分析することはあり得ないので、「細かいことは考えずに options(scipen=100) にしている。」でいいと思うし、上記の結果から言ってもscipen=400ぐらいにしておけば気分的にも問題ないと思います。

*1:統計は、心理学の実験でよく使う分散分析、回帰分析、因子分析などの基本レベルまでは勉強しました。最近、大学生&大学院生向けの教科書を買ってきてさらに勉強中です……