Scala日記

Scalaの備忘録。ときどき研究の話。

Matplotlib (with seaborn) で出力するPDFの下のほうが切れてしまうときは bbox_inches='tight'

Scalaとは関係ないですが…。探すのに苦労したので。 結局は学生さんに教えてもらいました。

import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt

data = ['some data points']
df = pd.DataFrame(data=data, columns=['model', 'score'])

sns.set_context("talk",1, {"lines.linewidth": 1})
plt.xticks(rotation=60)
plot = sns.boxplot(x="model", y="score", data=df)
plt.xlabel(' ')
plt.figure(figsize=(6, 5), dpi=300)
plot.figure.savefig('sample.pdf', bbox_inches='tight')

Matplotlibで出力するPDFの下のほうが切れてしまうときは bbox_inches='tight'

Scalaとは関係ないですが…。探すのに苦労したので。

import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt

data = ['some data points']
df = pd.DataFrame(data=data, columns=['model', 'category', 'score'])

sns.set_context("talk",1, {"lines.linewidth": 1})
plt.xticks(rotation=60)
plot = sns.boxplot(x="model", y="score", data=df)
plt.xlabel(' ')
plt.figure(figsize=(6, 5), dpi=300)
plot.figure.savefig('sample.pdf', bbox_inches='tight')

Argmax: Seqが関数であることを利用してmax値のインデックスを簡潔に取る

以前、ScalaSeq が関数であることを書きましたが、

ym.hatenadiary.jp

これを利用して、最大値のインデックスを取得する関数を簡潔に実装することが出来ます。

val seq = scala.util.Random.shuffle(1 to 10)
seq.indices.maxBy(seq)

美しいですね。

maxBy高階関数で、数式記号で言うところの argmax に相当します。ここでは、seq のインデックスを seq(という関数)で seq の中の実際の値に変換して、その値が最大になるようなインデックスを返しています。

Seq の拡張メソッドとして実装したい場合は以下のようにすればOK。

argmax in Scala

None を含むオブジェクトを Java の deep clone ライブラリで clone すると複数の None オブジェクトができる。この None は case 文で match しない。

完全にハマったので覚書。 ディープクローンを手軽にやりたくて、このライブラリを使ったはいいのだけど、

github.com

突然 case 文で Nonecase None => にマッチしなくなった。 そんなことがありうるのかと思って調べてみたら、このあたりで議論されていた。おおよそ同じ現象と思われる。

「Two scala.None$ references do not match」 Google グループ

手軽にやりたいなら、多少遅いが、シリアライズ → デシリアライズが無難。

基本コンストラクタの引数は他のメソッド内で使わない場合 private field として保持されない

入門書で明示的に教えてくれないシリーズその2。

class A(s:String){
    def i = s.toInt
}

class B(s:String)

class C(s:String){
    val i = s.toInt
}

上のようなコードにおいて、Asが private field として保持されるのはみんな知っているが、BCsが private field として保持されるのかどうかを明示的に記述している文献はなかなか見当たらない。 コップ本の基本コンストラクタの項目には、基本コンストラクタの引数は「必要なら、渡された値でフィールドを初期化し」や「クラス本体で使われないフィールドは保持『しなくてよい』」などと書かれているが、「しなくてよい」という書き方は定義としてはなんとも曖昧で実際の動作が気になる。

本当のところどうなっているのかいろいろ調べたが、文献からは確信が持てずじまいだったので、以前書いた

ym.hatenadiary.jp

で自分で調べてみた。やり方は

scala -Xprint:constructors

として、上のコードを張り付け、コンパイル結果を見る。すると、表題の結論であることが分かる。 ちなみに、同じ研究室の方に調べてもらったところによると、Martin Odasky 曰く、

"(メソッドで使われている場合は private field になり、使われていない場合は基本コンストラクタの処理が終わった時点で捨てられるという推測は) That's all true, but it should be treated as an implementation technique. That's why the spec is silent about it. "

とのこと。つまり、この仕組みは特にScalaの仕様に含まれているわけではないということ。 どのようにプログラミングを行うかという作法に関わる結構重要な決め事のようにも思えるのだが、何を仕様に含めるべきかという理念の違いなのだろうか。

参考:

  1. Scala Reference and Primary Constructor Parameters | The Scala Programming Language

Option型のコレクションから Some(x) の値 x だけを取り出すには flatten

val opts: Seq[Option[Int]] = Seq(Some(2), None, Some(3))

のようなものから値のあるものだけを取り出して、

List(2, 3)

を作りたいときに、Scalaを覚えたての頃はやり方がよく分からなくて、最初にやっていたのが

opts.filter(_ != None).map(_.get)

だった。その後、Scalaがだいぶ書けるようになった頃に

for(Some(x) <- opts) yield x

やら、

opts.collect{ case Some(x) => x }

となり、最終的にたどり着いたのが

opts.flatten

である。標準ライブラリを理解してくると自然に行き着くことではあるのだが、 それにしても、このようなことは何故か誰も教えてくれない。初学者の頃にこれを書こうとする度に苦労したので、これからScalaを学ぶ人向けに。