静かなる名辞

pythonとプログラミングのこと

アドレス変更のおしらせ

 本日、本ブログを独自ドメイン化しました。それに伴い、アドレスが変更になりました。

  • 旧URL

 https://hayataka2049.hatenablog.jp/

  • 新URL

 https://www.haya-programming.com/

 旧URLからも301リダイレクトされますが、ブックマーク登録等はお早めにご更新ください。

 今後共よろしくおねがいします。

 

【python】matplotlibで背景色と枠線の色を変える

はじめに

 matplotlibでは図(figure)の背景色と枠線(エッジ)の色を自由に設定できる。その方法についてメモしておく。

 目次

設定方法

 plt.figure()の引数に渡してあげる。facecolorおよびedgecolor引数で指定できる。

matplotlib.pyplot.figure — Matplotlib 3.0.0 documentation

 なお、枠線のデフォルト幅は0.0にされている。そのため、edgecolorを変更しても一見すると何も起きないように見える。linewidth引数で別途枠線の太さを指定して、はじめて効果を見ることができる。僕は最初これに気づかなくて、検索して答えにたどり着くまで無駄に色々試行錯誤してしまった。

 参考:python - matplotlib can not see the effect of setting edgecolor in plt.savefig() or plt.figure() - Stack Overflow

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure(facecolor="azure", edgecolor="coral", linewidth=2)
plt.plot(x, y)
plt.show()

 こんな感じで表示される。

結果1
結果1

 見ての通り、axesの背景色は別に存在しているので、グラフの中だけ白く表示される。

 もし色を揃えたければ、axesを取得してこちらにも背景色を設定する。それか、rcParamのaxes.facecolor をいじる(こちらの方法だとすべてのaxesに対して設定が反映されるので注意)。

 方法1

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

fig = plt.figure(facecolor="azure", edgecolor="coral", linewidth=2)
ax = plt.subplot()
ax.plot(x, y)
ax.set_facecolor((1,1,1,0))
plt.show()

 方法2

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.rcParams["axes.facecolor"] = (1,1,1,0)
fig = plt.figure(facecolor="azure", edgecolor="coral", linewidth=2)
plt.plot(x, y)
plt.show()

 今回はどちらの方法でも結果は同じ。

結果2
結果2

 色そのものはalphaが0なら他は何でも良い(透過させるから)。もちろんalphaを0より大きくして任意の色を設定することも可能。

 ちなみにaxesにrcParamsでaxes.edgecolorを設定することもできる(することに意味があるかは不明)。set_edgecolor()は存在しないようだ。

plt.savefig()で反映されない

 上の画像はスクリーンショットで撮った。

 plt.savefig()ではこれらの背景色・枠線の色は反映されない。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure(facecolor="azure", edgecolor="coral", linewidth=2)
plt.plot(x, y)
plt.savefig("result.png")

result.png
result.png

 理由は、plt.savefig()がfigureの設定を上書きするから(新たなfigureを作るような感じかな)。

 参考:python - Matplotlib figure facecolor (background color) - Stack Overflow

 plt.savefig()自身がfacecolor, edgecolorなどの引数を取るので、そちらで指定してあげよう。

matplotlib.pyplot.savefig — Matplotlib 3.0.0 documentation

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure(linewidth=2)
plt.plot(x, y)
plt.savefig("result.png", facecolor="azure", edgecolor="coral")

 facecolor, edgecolorはこっちで指定すれば良いみたい。linewidthは上のplt.figure()側で指定しないと駄目。ルールがよくわからないが、とにかく動く。

result.png
result.png

まとめ

 やりたいことが単純な割に、注意点が多い気がする。「設定したのに反映されねえ」ってなるシチュエーションが容易に幾つも思い浮かぶ。

 ので、自分で設定するよりはseabornとかでスタイルを設定してそれを使った方が実用的かもしれない。

 けど、設定する方法を覚えておくと使いたいとき困らないので、知っておいて損はしないと思う。

【python】matplotlibで図の余白を調整する

 matplotlibで図を描画するとき、余白に納得がいかないことがある。

 調整方法を自分用にメモ。

余白の大きさを変える

 plt.subplots_adjust()を使うと余白を調整できる。

 ドキュメントによると、デフォルト値は以下の通り。

left  = 0.125  # the left side of the subplots of the figure
right = 0.9    # the right side of the subplots of the figure
bottom = 0.1   # the bottom of the subplots of the figure
top = 0.9      # the top of the subplots of the figure
wspace = 0.2   # the amount of width reserved for space between subplots,
               # expressed as a fraction of the average axis width
hspace = 0.2   # the amount of height reserved for space between subplots,
               # expressed as a fraction of the average axis height

matplotlib.pyplot.subplots_adjust — Matplotlib 3.0.0 documentation

 たとえば次のようなコードを実行すると、結果は下の図のようになる。わかりやすいように背景を着色している。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure()
plt.plot(x, y)
plt.savefig("result.png", facecolor="azure")

結果
結果

 余白を削れるだけ削ってみる。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure()
plt.plot(x, y)
plt.subplots_adjust(left=0, right=1, bottom=0, top=1)
plt.savefig("result.png", facecolor="azure")

結果
結果

 納得がいかないが、こうなるものは仕方ない。適当に調整する。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure()
plt.plot(x, y)
plt.subplots_adjust(left=0.1, right=0.95, bottom=0.1, top=0.95)
plt.savefig("result.png", facecolor="azure")

結果
結果

 それらしくなった。

余白をギリギリまで詰める

 plt.savefig()の引数でbbox_inches='tight', pad_inches=0を指定する。

 plt.subplots_adjust()で手動で調整しても良いけど、savefigでファイルに出力したい場合はこちらの方が実用的。論文やパワポに載せる図などを作る際に便利なのだと思う。

matplotlib.pyplot.savefig — Matplotlib 3.0.0 documentation

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure()
plt.plot(x, y)
plt.savefig("result.png", facecolor="azure", bbox_inches='tight', pad_inches=0)

結果
結果

subplotsの間の余白を調整する

 複数のグラフを描画しているときに、余白が狭くなることがよくある。図ごとにタイトルや軸ラベルを付けたりすると基本的にそうなる。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(nrows=2, ncols=1)
axes[0].plot(x, y1)
axes[0].set_title("y = sin(x)")
axes[1].plot(x, y2)
axes[1].set_title("y = cos(x)")
plt.savefig("result.png")

y = cos(x)が上のx軸目盛りに食い込む
y = cos(x)が上のx軸目盛りに食い込む

 plt.subplots_adjust()で調整できる。wspaceが横方向、hspaceが縦方向の余白に対応。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(nrows=2, ncols=1)
axes[0].plot(x, y1)
axes[0].set_title("y = sin(x)")
axes[1].plot(x, y2)
axes[1].set_title("y = cos(x)")
plt.subplots_adjust(hspace=0.4)
plt.savefig("result.png")

 このように改善する。

結果
結果

【python】pythonで動的にメソッドを追加する

前置き

 この辺りの話、以前からちょっとモヤモヤしていたので、この際実験してすっきりさせておきます。

はじめに

 そもそも、pythonのメソッドは関数オブジェクト(もどき)のはずです。

 ということは、クラス定義構文を使わなくても生成する手段があるはずです。

 というあたりを、実験して確かめていこうと思います。

staticmethod

 まず、問題の少なさそうなstaticmethodから試します。

>>> class Hoge:  # 比較対象
...     @staticmethod
...     def hoge():
...         print("hoge")
... 
>>> Hoge.hoge()
hoge
>>> type(Hoge.hoge)  # 型を確認しておく
<class 'function'>
>>> class Hoge:  # 動的に追加する対象
...     pass
... 
>>> @staticmethod
... def hoge():
...     print("hoge")
... 
>>> Hoge.hoge = hoge
>>> Hoge.hoge()
hoge
>>> type(Hoge.hoge)
<class 'function'>

 えっと、できたっぽい。僕の目には区別がつきません。よしとします。

classmethod

 classmethodではどうか。

>>> class Hoge:  # 比較対象
...     @classmethod
...     def printname(cls):
...         print(cls.__name__)
... 
>>> Hoge.printname()
Hoge
>>> type(Hoge.printname)
<class 'method'>
>>> class Hoge:  # 動的に追加する対象
...     pass
... 
>>> @classmethod
... def printname(cls):
...     print(cls.__name__)
... 
>>> Hoge.printname = printname
>>> Hoge.printname()
Hoge
>>> type(Hoge.printname)
<class 'method'>

 これもできてると思います。

インスタンスメソッド

 これは難しいんじゃないの? と思っているインスタンスメソッドです。

 とりあえず先に、型を見ることにします。

>>> class Hoge:
...     def __init__(self, name):
...         self.name = name
...     def printnamehoge(self):
...         print(self.name, "hoge")
... 
>>> h = Hoge("taro")
>>> h.printnamehoge()
taro hoge
>>> type(Hoge.printnamehoge)
<class 'function'>
>>> type(h.printnamehoge)
<class 'method'>

 クラス配下のprintnamehogeはfunction、インスタンス配下のprintnamehogeはmethodという型になっていることがわかります。

 これを踏まえて、まずクラスに関数を追加してみます。

>>> def f(self):
...     print(self.name, "fuga")
... 
>>> Hoge.printnamefuga = f
>>> h = Hoge("taro")
>>> h.printnamehoge()
taro hoge
>>> h.printnamefuga()
taro fuga

 できました。ちょっと感動。

 次に、インスタンスに追加してみます。method型なので、うまくいくものだろうか。

>>> def p(self):
...     print(self.name, "piyo")
... 
>>> h.printnamepiyo = p
>>> h.printnamepiyo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: p() missing 1 required positional argument: 'self'

 案の定うまくいかない。

 こんな感じでmethodのhelpを調べます。

>>> help(type(h.printnamehoge))
Help on class method in module builtins:

class method(object)
 |  method(function, instance)  # こうやって使えということ
 |  
 |  Create a bound instance method object.
 |  
 |  Methods defined here:
 |  
# 長いので省略

 使い方はわかりました。ただ、methodはどこからimportすれば良いのか(というかそもそもimportできるのか)わかりません。

 だけど、上のようにtype(h.printnamehoge)で取り出せているので、実は困らないのです。

 名前があると嬉しいので、こんな感じで使いやすくしておきます。

>>> method = type(h.printnamehoge)

 あとはhelpの通り使って呼び出します。動くかな。

>>> h.printnamepiyo = method(p, h)
>>> h.printnamepiyo()
taro piyo

 動いた!

 やった。これで、pythonのメソッドはすべて動的に追加できるとわかりました。

考察のようなもの

 こういう性質があるということは、pythonは本質的にクラスベースのオブジェクト指向言語とは一線を画しています。むしろインスタンスベース(プロトタイプベース)のように思えます。

 クラス構文ができた最近のjavascriptみたいなものです。クラス構文は一種の糖衣構文ということでしょう。本当のところ、きっとすべてが動的に行われているのです。

 なお、クラスオブジェクト自体は以下のようにインスタンス化できるようです。

>>> class Hoge:
...     pass
... 
>>> Hoge
<class '__main__.Hoge'>
>>> type("Hoge", Hoge.__bases__, dict(Hoge.__dict__))  # 同じものを作る
<class '__main__.Hoge'>

 後はこれにアレコレしてメソッドを付け加えていける。インスタンス化はクラスの__call__が呼ばれた後の処理に委ねられるはずで、これは自動的に生成されるのでちょっと暗黙的ですが、インスタンスメソッドの項目で記述したようなboundがその中で行われているはずです。

 いや、素敵ですねー。

まとめ

 すべて動的に行えることがわかって嬉しいと思いました。

 これを使って実用的なコードを書くのは正気の沙汰ではないので、やめてください。

【python】numpy配列の複雑な連結にはnp.blockが便利

 numpy配列を連結したいとき、通常np.vstackやnp.hstack、np.concatenateなどを使うと思います。

 しかし、これらでは一度で表せないような連結をしたいときがあります。たとえば、2次元配列を平面的に連結するような場合です。

>>> import numpy as np
>>> a = np.array([[0,1],[2,3]])
>>> b = np.array([[4,5],[6,7]])
>>> c = np.array([[8,9],[10,11]])
>>> d = np.array([[12,13],[14,15]])
""" 下のようにしたい
array([[ 0,  1,  4,  5],
       [ 2,  3,  6,  7],
       [ 8,  9, 12, 13],
       [10, 11, 14, 15]])
"""

 この例のように、複数のaxisにまたがって連結をしたい場合、上に挙げた関数ではうまくいきません。このような場合、とりあえずnp.vstackで縦方向に連結してからnp.hstackで横方向に連結する(あるいは逆の順番でも可)というのが一つの方法ですが、ちょっとややこしいですね。

>>> np.vstack([np.hstack([a,b]), np.hstack([c,d])])  # たいへん
array([[ 0,  1,  4,  5],
       [ 2,  3,  6,  7],
       [ 8,  9, 12, 13],
       [10, 11, 14, 15]])

 こういうとき、np.blockを使うと配列の連結を簡単に行なえます。

>>> np.block([[a,b],[c,d]])
array([[ 0,  1,  4,  5],
       [ 2,  3,  6,  7],
       [ 8,  9, 12, 13],
       [10, 11, 14, 15]])

 すごいですね。直感的に配列の連結が書けます。

 直感的なのは良いけど、具体的にどんな仕様なの? という疑問が浮かびますが、

Blocks in the innermost lists are concatenated (see concatenate) along the last dimension (-1), then these are concatenated along the second-last dimension (-2), and so on until the outermost list is reached.

numpy.block — NumPy v1.14 Manual

 という仕様になっているようです。リストの外に達するまで-1, -2, ...のdimension(=axisかな)でconcatenateされる。

 このようにnp.blockはとても便利なので、配列の複雑な連結が必要になった際には、ぜひ使ってみてください。

【python】missing 1 required positional argument: 'self'などの対処法

はじめに

 pythonに不慣れな方は、よくタイトルのようなエラーを見かけると思います。

 実際には、このエラーはTypeErrorで、全体は以下のようなものです。

TypeError: メソッドの名前 missing 1 required positional argument: 'self'

 では、どうしてこのエラーは出るのでしょうか。そして、どうすれば良いのでしょうか。簡単に解説していきます。なおpython3を使っていることを前提とします。

クラスをインスタンス化していない

 このエラーは、なんとなくエラーの文面だけ見ると、引数を渡してあげれば良いのかな? というような気がします。実際、引数を要求する関数を引数無しで呼び出すとほぼ同じエラーが出ます。

>>> def f(a):
...     pass
... 
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required positional argument: 'a'

 だけど、ライブラリやモジュールのドキュメントをのぞいてもselfという引数に関する記載はなかったりします

 実は、このエラーにはpythonのクラスの言語仕様が関係しています。

 pythonでは、通常のメソッドでは第一引数にオブジェクトのインスタンスそのもの(Javaでいうthis)が渡されてやってくる、という仕様になっています。

 たとえば次のようなコードを試しに実行してみます。

test_hoge.py

class Hoge:
    def print_hoge():
        print("hoge")

h = Hoge()
h.print_hoge()

実行結果

Traceback (most recent call last):
  File "test_hoge.py", line 6, in <module>
    h.print_hoge()
TypeError: print_hoge() takes 0 positional arguments but 1 was given

 print_hoge()は1つも引数を取らない関数として定義されているのに、1つ渡されています、というエラーが出ます。ここで渡されているものがインスタンス自身です。

 インスタンス自身を受け取る名前は、実はどんな名前でも構わないのですが、慣習的にpythonでは「self」を使います。さっきのコードをselfを受け取るように書き換えましょう。

test_hoge.py

class Hoge:
    def print_hoge(self):
        print("hoge")

h = Hoge()
h.print_hoge()

実行結果

hoge

 無事実行できるようになりました。よかったね、という話なのですが、これを今度はインスタンス化しないで呼んでみましょう。

test_hoge.py

class Hoge:
    def print_hoge(self):
        print("hoge")

Hoge.print_hoge()

実行結果

Traceback (most recent call last):
  File "test_hoge.py", line 5, in <module>
    Hoge.print_hoge()
TypeError: print_hoge() missing 1 required positional argument: 'self'

 はい、エラーが再現しました。このような状況になっていた訳ですね。

対策

 このエラーに遭遇した場合、大抵はインスタンス化して使うべきクラスを不適切にインスタンス化せずに使っていたというケースだと思います。インスタンス化してあげましょう。上の例の、ちゃんと実行できるコードを再掲します。

class Hoge:
    def print_hoge(self):
        print("hoge")

h = Hoge()  # この行でインスタンス化
h.print_hoge()

 ただし、自作クラスで「インスタンス自身なんか処理に使わないから、クラスのまま呼べるようにしたい」という場合もあると思います。その場合は、@staticmethodとメソッド宣言の前に付けてあげるとスタティックメソッドを定義できます。
 (「@staticmethod」そのものは特別な記述子とかではなく、pythonでは一般的に使われるデコレータという機能で実装されています。詳細はドキュメントやヘルプを参照してください)

class Hoge:
    @staticmethod  # これによってスタティックメソッドになる
    def print_hoge():
        print("hoge")

Hoge.print_hoge()

 ただし、これはつまるところただの関数と何も違いません。スタティックメソッドを使うメリットはかなり限られた場面にしかありません。だいたい、pythonではクラスを入れ物的に使うということをあまりしません(通常はトップレベル関数として定義し、モジュールで管理する)。本当にそのスタティックメソッド必要? と考え直す視点は常に持っておいた方が良いです。

 なお、似たようなデコレータに@classmethodというというものもありますが、これは第一引数に「クラス自身」が渡されるというもので、スタティックメソッドとはまた別物です。間違えないようにしてください。

色々なパターン

 これに似ているパターンが幾つかあると思うので、カバーしておきます。

引数を受け取るメソッド

 このようなケースです。

test_hoge.py

class Hoge:
    def print_hoge(s):
        print("hoge", s)

h = Hoge()
h.print_hoge("fuga")

実行結果

Traceback (most recent call last):
  File "test_hoge.py", line 6, in <module>
    h.print_hoge("fuga")
TypeError: print_hoge() takes 1 positional argument but 2 were given

 この記事をここまで読んできた皆さんは、もうどうすれば良いかおわかりだと思います。

正しいコード

class Hoge:
    def print_hoge(self, s):
        print("hoge", s)

h = Hoge()
h.print_hoge("fuga")

まとめ

 pythonのクラス周りは他の言語と比べてちょっと独特ですが、「通常のメソッドではインスタンス自身が暗黙的に第一引数に渡される」というルールさえ理解してしまえば、むしろわかりやすいと言えます。「thisが自動的にインスタンス自身を表すキーワードとして機能する」という魔法がない分、一貫性があってすっきりしているからです。


 ただ、理解するまではタイトルのようなエラーにはよく遭遇すると思います。早く覚えてこんなエラーは出さないようにしましょう。

決定木回帰、ランダムフォレスト回帰、SVRを可視化してみた

 目次

はじめに

 最近回帰モデルで遊んでいるのですが、決定木系の回帰に好印象が持てなくなりました。

 だって、決定木ってオーバーフィット番長ですよ? 回帰とは名ばかりのカクカクの回帰曲線が出てくることは目に見えています。

 「そんなあなたのためにランダムフォレスト」という、アンサンブル番長な手法もありますが、以前分類で検討した感じだと、木の本数を相当増やしてもSVMなどで得られるなめらかな分離境界とは違う結果になる・・・という結論を得ているので、あまり信頼できません。

hayataka2049.hatenablog.jp

 ぶっちゃけた話、決定木はデータの可視化くらいにしか使えないし、ランダムフォレストは高次元・スパース・高ノイズ・非線形みたいな条件の悪いときには健闘するものの、低次元で普通のタスクを解くにはちょっと・・・な面がある、という認識、というか印象です。

 じゃあ、実際はどうなんでしょう?

 ということで、定番のサイン波の回帰で決定木回帰、ランダムフォレスト回帰、SVRを可視化します。

実験

 それぞれで回帰して、プロットします。ついでに、決定係数 R^2も計算して表示します。

  y=\sin(x)\ (0\leq x \leq 15)で、学習データのサンプル数は50個(等間隔)、標準偏差0.3の正規分布をまぶしております。テストデータは同じxの区間で500点、真値としてはノイズなしの純正正弦波を持ってきます。

 後の細かいことはコードと結果を見て理解してください。

 コード

import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.svm import SVR

def test_reg(reg, name, X_train, y_train, X_test, y_test, ax):
    reg.fit(X_train, y_train)
    y_pred = reg.predict(X_test)
    score = reg.score(X_test, y_test)

    x_train = X_train.ravel()
    x_test = X_test.ravel()
    ax.scatter(x_train, y_train,
               label="学習データ(真値+ノイズ)", c="g")
    ax.plot(x_test, y_test, label="真値")
    ax.plot(x_test, y_pred, label="予測値")
    ax.set_title("{0}  score:{1:.4f}".format(name, score))
    ax.legend()

def main():
    x_train = np.linspace(0, 15, 50)
    X_train = x_train.reshape(-1, 1)
    rand = np.random.RandomState(seed=0)
    y_train = (np.sin(x_train) + 
               rand.normal(scale=0.3, size=x_train.shape))

    x_test = np.linspace(0, 15, 500)
    X_test = x_test.reshape(-1, 1)
    y_test = np.sin(x_test)

    dtr = DecisionTreeRegressor()
    rfr = RandomForestRegressor(n_estimators=100, n_jobs=-1)
    svr = SVR()

    fig, axes = plt.subplots(figsize=(14,7), nrows=3, ncols=1)
    plt.subplots_adjust(wspace=1, hspace=0.5)
    for reg, ax in zip([dtr, rfr,  svr], axes):
        test_reg(reg, reg.__class__.__name__,
                 X_train, y_train, X_test, y_test, ax)
    plt.savefig("result.png")

if __name__ == "__main__":
    main()

結果

 次の図のようになりました。

回帰の結果
回帰の結果

 決定木は一見して分かる通り、かくかくですね。というか、最近傍補間に限りなく近い何か。回帰を名乗るのはおこがましいと思う。

 ランダムフォレストは気持ち改善する程度。バギングの力でデータの中間点以外でも階段の段が作れる、データそのものにぴったり載っからなくてもよくなるため、多少滑らかになるという性質を持っています。評価指標は(決定木と比べて)けっこう劇的に改善していますが、見た目はこの程度か感が否めないような・・・。

 SVRは見た目、評価指標ともに最高と言って良いと思います。汎化性能のちからで違和感のない回帰になっております。

考察

 決定木がこんななのは原理的に仕方ない。ランダムフォレストも仕方ない。

 ランダムフォレストに関しては、高次元での挙動次第で使うかどうか考えることになります。割と直感的にわかる低次元と違って高次元空間はいろいろ面白い(カオス)世界、そしてランダムフォレストの得意分野なので、うまく汎化が効けば有効な可能性は十分にあります。

 でも可視化して評価する方法がないので、そしてやるとしたら評価指標頼りになってまったく面白くないので、とりあえずこの記事ではやらない。

 SVRに関しては良いですね。今回はデフォルトパラメータで奇跡的にほどよくフィットしましたが。実用的にはチューニング必須。

まとめ

 決定木を回帰に使うと、あんまり狙ったような回帰にはなりません。ランダムフォレストだと多少緩和されます。SVRは狙ったような回帰ができます。

 どちらにせよ評価指標はそこそこ出るので、そして直感的に正しそうな回帰は実はそこまで重要視されないというシチュエーションも多いと思うので、実用的には評価指標見て選べば良いです。

 余談ですが、このまとめを書き始めたとき「誰だよ決定木を回帰に使おうとか最初に考えた奴」とか書こうとして、すぐ「あっ、Leo Breiman先生(CART法とランダムフォレストの生みの親)だ・・・」と思ってやめました。