コンピュータやソフトウェアのあれこれ@道民(&元道民)
Scala
[レポート][scala]今日は Akasaka.scala 36 の日です
4月 12th
Akasaka.scala 36に途中から参加してます。タグは#akskscalaです。
Scala言語仕様読書会8 / @seratch さん
6章の後半。
- 前置、中置、後置演算
- :が右結合なのはなぜ? → ::のため
- 代入演算子
play2.0について / @seratch さん
- play コマンド
- sbtのラッパー (sh/bat)
- play new hello-play → 1 - Create a simple Scala application を選ぶ
- play run → 9000ポート
- 参考資料
- 公式ドキュメント
- Play20/samples/scala
- Google Groups の [2.0] つきのスレッド
- StackOverFlow の playframework-2.0
- #playframework, #play_ja
[math][scala]95%の信頼区間とは
4月 10th
10000本のクジにx本の当たりが入っているとする。ここから100本のクジを引いた結果を元に、当たりクジが何本入っているか区間推定したい。
非復元抽出なので厳密にいえば100本中の当たりクジの本数yは超幾何分布に従うが、抽出する数と比較して全体数が大きいので二項分布で近似して良いだろう。さらに引いたクジの本数も十分に大きいので、正規分布として近似できる。
当たりくじの割合がp = x / 10000でそこから100本クジを引くのだから、確率変数yが二項分布だと考えれば平均値は100p、分散は100p(1-p)となる。これを元に正規化した、(y - 100p) / 10√(p(1-p))は標準正規分布に従うと言える。標準正規分布であれば-1.96から1.96の間の値をとる確率が95%であるから、-1.96 < (y - 100p) / 10√(p(1-p)) < 1.96 をpについて解けば*1、pがその範囲内に入る確率は95%であるということになる。これが95%の信頼区間。
見方を変えれば、この方法で推定すると、5%の確率で外れるってことになる。本当かどうか、シミュレーションしてみる。100個を無作為抽出してそこから95%の信頼区間を求めるという試行を1000回やって、実際の確率pが信頼区間に入った回数、入らなかった回数をカウントしてみる。
import scala.math._
import scala.util.Random._
val n: Int = 10000
val x: Int = 4321
val p: Double = x.toDouble / n.toDouble
val sampleN: Int = 100
val count: Int = 1000
val population: Array[Boolean] =
(1 to n).map(n => if (n <= x) true else false).toArray
def square(x: Double) = x * x
def randomSampling[T](x: Seq[T], n: Int) = {
val shuffled: Seq[T] = shuffle(x)
shuffled.take(n)
}
def solveQuadratic(
a: Double = 1, b: Double = 0, c: Double = 0
): (Double, Double) = {
val hanbetu = sqrt(square(b) - 4 * a * c)
((- b - hanbetu) / 2.0 / a, (- b + hanbetu) / 2.0 / a)
}
def estimate (samples: Seq[Boolean]): (Double, Double) = {
val n = samples.length
val x = samples count {x => x}
solveQuadratic(n + square(1.96), - 2 * x - square(1.96), square(x) / n)
}
val results = (1 to count).map { _ =>
val sample = randomSampling(population, sampleN)
val (min, max) = estimate(sample)
if (min <= p && p <= max) true else false
}
println(
"hit: %d, miss: %d" format (
results count {x => x}, results count {x => ! x}
)
)
結果は以下の通り、やはり5%は推定に失敗するという結果になる。
hit: 952, miss: 48
*1:二乗して二次不等式にして解く
[math][scala]超幾何分布と二項分布
4月 6th
非復元抽出とは、有限個のものから複数個を抽出する際に、抽出したものを戻さずに2回目以降の抽出を行うこと。こうすると二回目以降の試行の確率はだんだんと変化していくことになる。
復元抽出する場合は二項分布となるが、非復元抽出をすると超幾何分布となる。が、全体数に比べて試行回数が十分に小さい場合は、非復元抽出を二項分布で近似できる。
試しに、白玉100個、赤玉900個から玉を取り出す試行を10回行う場合に白玉が二個以下である確率を求めてみると、二項分布でも超幾何分布でも同じ値になることが分かる。
---*snip*--- def hypergeometricDistribution( n: Int, N: BigInt, Np: BigInt ): (Int) => Double = { import scala.math.pow def distribution(x: Int): Double = (combi(Np, x) * combi(N - Np, n - x)).toDouble / combi(N, n).toDouble distribution _ } val n = 10 val N = 1000 val p = 0.1 val binomial = binomialDistribution(n, p) val hypergeometric = hypergeometricDistribution(n, N, (N.toDouble * p).toInt) println("hypergeometric: %.2f" format ((0 to 2).map {hypergeometric(_)}.sum)) println("binomial: %.2f" format ((0 to 2).map {binomial(_) }.sum))
hypergeometric: 0.93 binomial: 0.93
[math][scala]二項分布とポアソン分布
4月 4th
二項分布は試行回数が多くなると階乗周りの計算量が多くなる。一回の事象の発生確率pが十分に小さければ、ポアソン分布で近似ができる。
例えば、5枚の硬貨を投げてすべて表がでるかどうかを64回やったときの分布を二項分布とポアソン分布で比較すると、以下のように高い精度で近似できていることがわかる。
import scala.math.BigInt def factor(n: BigInt): BigInt = if (n <= 1) 1 else n * factor(n - 1) def combi(n: BigInt, m: BigInt): BigInt = factor(n) / factor(m) / factor(n - m) def binomialDistribution(n: Int, p: Double): (Int) => Double = { import scala.math.pow def distribution(x: Int) = combi(n, x).toDouble * pow(p, x) * pow(1 - p, n - x) distribution _ } def poissonDistribution(m: Double): (Int) => Double = { import scala.math.pow def distribution(x: Int) = pow(m, x).toDouble / pow(2.71828, m).toDouble / factor(x).toDouble distribution _ } val n = 64 val p = 1.0 / 32.0 val binomial = binomialDistribution(n, p) val poisson = poissonDistribution(n * p) (0 to 10).foreach {n => println("[n=%d]".format(n)) println("binomial: %.3f".format(binomial(n))) println("poisson: %.3f".format(poisson(n))) }
[n=0] binomial: 0.131 poisson: 0.135 [n=1] binomial: 0.271 poisson: 0.271 [n=2] binomial: 0.275 poisson: 0.271 [n=3] binomial: 0.183 poisson: 0.180 [n=4] binomial: 0.090 poisson: 0.090 [n=5] binomial: 0.035 poisson: 0.036 [n=6] binomial: 0.011 poisson: 0.012 [n=7] binomial: 0.003 poisson: 0.003 [n=8] binomial: 0.001 poisson: 0.001 [n=9] binomial: 0.000 poisson: 0.000 [n=10] binomial: 0.000 poisson: 0.000
[math][scala]3囚人問題
3月 31st
こちらはモンティ・ホール問題より有名だと思う。
ある監獄にA、B、Cという3人の囚人がいて、それぞれ独房に入れられている。罪状はいずれも似たりよったりで、近々3人まとめて処刑される予定になっている。ところが恩赦が出て3人のうち1人だけ助かることになったという。誰が恩赦になるかは明かされておらず、それぞれの囚人が「私は助かるのか?」と聞いても看守は答えない。
囚人Aは一計を案じ、看守に向かってこう頼んだ。「私以外の2人のうち少なくとも1人は死刑になるはずだ。その者の名前が知りたい。私のことじゃないんだから教えてくれてもよいだろう?」すると看守は「Bは死刑になる」と教えてくれた。それを聞いた囚人Aは「これで助かる確率が1/3から1/2に上がった」とひそかに喜んだ。果たして囚人Aが喜んだのは正しいか?
まず「Bが死刑になる確率」と「Bが死刑になることを知る確率」が別の物だと気がつくことが大事。通常は「Cが恩赦のとき、Bが死刑になることを知る確率」と「Aが恩赦のとき、Bが死刑になることを知る確率」は同じと考えるべき。しかし、この問題文のような質問の仕方をしてしまうと、「Cが恩赦のとき、Bが死刑になることを知る確率」は1であり、「Aが恩赦のとき、Bが死刑になることを知る確率」は1/2であって、ズレが起こってしまう。
この説明でも怪しいと思う人は、やっぱりシミュレーションして試すとよい。
import scala.util.Random._ val A = 0 val B = 1 val C = 2 def playRole(keeperDecision: Array[Boolean] => Boolean): (Boolean, Boolean) = { val whoAlives = nextInt(3) val isDeath: Array[Boolean] = (0 to 2).map((x: Int) => x != whoAlives).toArray val hearBsDeath: Boolean = keeperDecision(isDeath) (hearBsDeath, isDeath(A)) } def whichIsDeath(isDeath: Array[Boolean]) = { if (! isDeath(C)) true else if (! isDeath(B)) false else nextBoolean() } val leakRate: Double = 0.8 def withNoAssumption(isDeath: Array[Boolean]) = if (isDeath(B) && nextDouble() < leakRate) true else false def statistics(keeperDecision: Array[Boolean] => Boolean): Double = { val results = (1 to 10000).map(_ => playRole(keeperDecision)).toList val resultsKnowOfB = results.filter(_._1) val numOfDead = resultsKnowOfB.count(_._2) numOfDead.toDouble / resultsKnowOfB.length.toDouble * 100 } println("normal situation: %.2f %%" format statistics(withNoAssumption)) println("ask which is death: %.2f %%" format statistics(whichIsDeath))
結果はほぼ理論値通りで、何も仮定しないと死刑となる確率は1/2になるが、この問題の仮定の場合は死刑となる確率は2/3のまま変化しない。
normal situation: 49.51 % ask which is death: 66.85 %
[math][scala]モンティ・ホール問題
3月 31st
3囚人問題は有名だけど、こちらを見かけたのは恥ずかしながら初めて。
「プレイヤーの前に3つのドアがあって、1つのドアの後ろには景品の新車が、2つのドアの後ろにはヤギ(はずれを意味する)がいる。プレイヤーは新車のドアを当てると新車がもらえる。プレイヤーが1つのドアを選択した後、モンティが残りのドアの内ヤギがいるドアを開けてヤギを見せる。
ここでプレイヤーは最初に選んだドアを、残っている開けられていないドアに変更しても良いと言われる。プレイヤーはドアを変更すべきだろうか?」
答えは、変更した方が勝率が高くなる。ベイズの定理できちんと考えれば答えは出るのだけど、非常に嘘っぽく感じてしまうのがこの問題の特徴*1。嘘っぽいなら実際やらせて確かめてみればいい。
import scala.util.Random._
def didWinGame(isChange: Boolean): Boolean = {
val doors: Array[Boolean] = Array(false, false, false)
doors(nextInt(3)) = true
val playerChoice = nextInt(3)
def tryChoosing(): Int = {
val choice = nextInt(3)
if (choice != playerChoice && ! doors(choice))
choice
else
tryChoosing()
}
val montyChoice = tryChoosing()
val finalAnswer =
if (isChange) List(0, 1, 2).filter(
(x: Int) => x != playerChoice && x != montyChoice
)(0)
else playerChoice
return doors(finalAnswer)
}
def winningRate(doGame: () => Boolean) = {
val total = 10000
val winCount = (1 to total).map(_ => doGame()).count((x: Boolean) => x)
winCount.toDouble / total.toDouble * 100
}
println("not change: %.2f %%".format(winningRate(() => didWinGame(false))))
println("change: %.2f %%".format(winningRate(() => didWinGame(true))))
実行するとほぼ理論値となる。
not change: 33.18 % change: 66.38 %
*1:この嘘っぽさは、引用した問題文だけだと前提条件が説明不足だってのもあるけど
[レポート][scala]今日は Akasaka.scala 35 の日です
3月 22nd
Akasaka.scala 35に参加してます。タグは#akskscalaです。ustreamはこちら。
一度でも参加者したことがある方はgithubのOrganizationに入っているので、適当にcommitして下さいとのこと。
Scala言語仕様読書会8 / @seratch さん
今日は6章です。
- 6.1 → Expression Typing、スコーレム化
- 6.2 → リテラルの型付け
- 6.3 → scala.Null型
- 6.4 → Designaters
- 宿題: 安定型を要求するコンテキストの1〜4はどういう意味?
- 6.5 → superとthis。super[T]のようにTraitを指定できる
- 6.6 → 関数適用。メソッド型。#apply()。名前付き引数。名前呼び出し。シーケンス引数
- 6.7 → メソッド値(η変換)
- 6.8 → 型適用
Squeryl を使った DB アクセスをいろいろ試してみましょう
サンプルコードを読みましょう。
- 読み方は → スクイレルでは?
- case class? → updateを考えるとミュータブルな方が
- type safe なのが利点。でも、動くまでがトライアンドエラー?
- PrimitiveTypeMode を見ると色々なメソッドがある
- test の MusicDb.scala を見ると様々なコードが入ってる
[メモ][scala]sbt g8-test 時の依存関係でエラー出た
3月 9th
giter8-plugin を使って sbt g8-testしたときに、
sbt.ResolveException: unresolved dependency: org.scala-tools.sbt#scripted-sbt_2.9.1;0.11.2: not found
とか言われるときは build.sbt に
resolvers += Resolver.url("Typesafe repository", url("http://typesafe.artifactoryonline.com/typesafe/ivy-releases/"))(Resolver.defaultIvyPatterns)
って書いとけばいい。
[レポート][scala]今日は Akasaka.scala 34 の日です
3月 8th
Akasaka.scala 34に参加してます。タグは#akskscalaです。
Scala言語仕様読書会7 / @seratch さん
詳細はこちら。
- 前回の復習
- メンバーマッチング
- 事前定義
- 修飾子
- 2回出てはいけない
- (a, b)のような定義に先行する場合は両方に
- private → コンパニオンからもアクセスできる。 class-private
- 限定修飾 private[C] → object-private
- protected
- override → 親クラスの具象メンバをオーバーライドするときは必須
- abstract → traitには不要
- abstract override → traitで使える。AIPっぽくなる
- final → abstractやsealedとは使えない
- sealed → 同じファイル内のみ継承できる。サブクラスは継承できる
- lazy val → 無限ループするかも
lazy val y:Int = x
lazy val x:Int = y
println(x)
[RESULT]
% scala /tmp/hoge.scala 2>&1 | head
java.lang.StackOverflowError
at Main$$anon$1.x(hoge.scala:7)
at Main$$anon$1.y(hoge.scala:6)
at Main$$anon$1.x(hoge.scala:7)
at Main$$anon$1.y(hoge.scala:6)
at Main$$anon$1.x(hoge.scala:7)
at Main$$anon$1.y(hoge.scala:6)
at Main$$anon$1.x(hoge.scala:7)
at Main$$anon$1.y(hoge.scala:6)
at Main$$anon$1.x(hoge.scala:7)
- 用語:valは「値」
- クラス定義
- private, protected でコンストラクタのアクセス修飾
- アノテーション、カリー化された引数の並び
- valだとゲッター、varだとセッターも
- 補助コンストラクタは基本コンストラクタを必ず呼ぶ
- ケースクラス
- 2.9.xから?パラメータリストなしではwarningが出る
- コンパニオンオブジェクトと、copy, equals, hashCode, toString などが追加される
- Trait
- コンストラクタパラメータは定義できない
- オブジェクト定義
- object 宣言は lazy val = new ... とほぼ同じ振る舞い
- 次回は6章
g8 テンプレートをつくってみよう(ハンズオン) / @tototoshi さん
- giter8とは
- github上のプロジェクトをテンプレにできるツール
- csコマンドでインストール
- g8コマンドでテンプレが作られる
- カレントに展開されるので注意
- src/main/g8 の中にテンプレ化したいものを突っ込む
- テストはgiter8-pluginを使う
- Exceptionが出てもビビらない
- 作者のn8hanさんは色々書いているけど、ソースに癖がある
- xsbti.AppMain → sbtから
- カレントに展開されるのは名前を指定してないから
# apply.scala parameters.get("name").map(normalize).getOrElse(".")
- giter8 使ってみるといいのでは
- seratch さんのanorm を使うサンプル
[java][scala]Scalaの空括弧とUnit
2月 2nd
Unit周りでハマったのでメモ。
まず、() => Any という型はあるが、()という型はない。
scala> def id(x: () => Int): () => Int = x
id: (x: () => Int)() => Int
scala> def id(x: ()): () = x
<console>:1: error: '=>' expected but ')' found.
def id(x: ()): () = x
^
Unit型の唯一の要素が()である。
scala> ().isInstanceOf[Unit]
res67: Boolean = true
() => Any は Unit => Any とは違う。
// 型が違って代入できない scala> val emptyParentheses: () => Any = { () => 10 } emptyParentheses: () => Any = <function0> scala> val unit: Unit => Any = emptyParentheses <console>:17: error: type mismatch; found : () => Any required: Unit => Any val unit: Unit => Any = emptyParentheses ^ // 型が違って代入できない scala> val unit: Unit => Any = {(u: Unit) => 20} unit: Unit => Any = <function1> scala> val emptyParentheses: () => Any = unit <console>:17: error: type mismatch; found : Unit => Any required: () => Any val emptyParentheses: () => Any = unit ^
が、Unit => Any は空括弧で呼び出すことができる。
scala> def one(u: Unit): Int = 1 one: (u: Unit)Int scala> one(()) res68: Int = 1 // これ、なんでエラーにならないのかわからず (Value Discardingから??) scala> one() res69: Int = 1 scala> one <console>:18: error: missing arguments for method one in object $iw; follow this method with `_' if you want to treat it as a partially applied function one ^ // これは、要請がUnit型なら{ e; () }に変換するルール(Value Discarding)より scala> one("DUMMYYY") res71: Int = 1 // これもValue Discarding から?? scala> one(1, "XXX", Nil) res72: Int = 1