なまもの備忘録

気になったことをつらつらと書いていきます

scipyによる3次スプライン補完

未知の関数に出会った時3次スプライン補完をしたいと思うのは人類の普遍的欲求です。 普遍的欲求はだいたいpythonのライブラリが満たしてくれるもので、今回のケースではscipyがその役割を担ってくれます。

scipyの3次スプライン補完についてはいくつか日本語解説ページがあるのですが、

qiita.com

ここで使われているkind='cubic'interp1d関数だと、スプライン補完の係数取得に少々非自明な処理をする必要が出てきます。 人間が3次スプライン補完をするときって、欲しいものは大抵関数そのものではなく係数なので、これは困りますね。

さて、scipyではinterp1d以外にもCubicSpline関数で3次スプライン補完を実行することができ、こちらを使えばこの問題は解決します。 使い方は以下

import numpy
from scipy import interpolate
import matplotlib.pyplot as plt

if __name__ == '__main__':

    x_coordinates = []
    y_coordinates = []
    for line in open('test.txt', 'r'):
        point = [float(coord.split()[0]) for coord in line.split(',')]
        x_coordinates.append(point[0])
        y_coordinates.append(point[1])
        
    spline_func = interpolate.CubicSpline(x_coordinates, y_coordinates)
    print(spline_func.c) # ここで係数を取得しています
    
    x_res = numpy.linspace(1, 5, 200)
    y_res = spline_func(x_res)
   
    plt.plot(x_coordinates, y_coordinates, 'o', x_res, y_res)
    plt.show()

CubicSplineの返り値であるPPolyオブジェクトのcを呼び出すことで、係数にアクセスしています。

テストデータとしては下記を使用しました。

1.5, 1.65
1.677, 5.64
2.3, 5.53
3.0, 4.354
3.8, 3.555

出力グラフ

f:id:purple-apple:20180226130144p:plain

標準出力(コメント部分は後から追記)

[[ 25.17215028  25.17215028  -3.16687764  -3.16687764] # 3次の係数
 [-52.99186318 -39.62545138   7.42129748   0.77085443] # 2次の係数
 [ 31.13331437  14.74004969  -5.32313819   0.41136815]    # 1次の係数 
 [  1.65         5.64         5.53         4.354     ]]    # 定数項

バージョン情報

$ python -V
Python 3.5.2
>>> import scipy as sp
>>> sp.version.full_version
'0.18.1'

参考

https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.CubicSpline.html

https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PPoly.html#scipy.interpolate.PPoly

バランスドネットワーク理論

「バランスドネットワーク」という言葉は、Computational Neurosience界隈では割とよく聞く言葉じゃないのかな、と思うのですが、日本語で検索をかけても引っかかる文献があまりないので、勉強がてらにメモを残すことにしました。下記の記事が綺麗にまとまっていそうだったので、その要約になっています。管理人はこの分野に関してほぼ素人なので、間違いなどありましたらご指摘いただけると幸いです。

Pierre Yger » The Balanced Network

背景

大枠として、in vivo実験で観察されるニューロンの不規則な発火をネットワークを介してモデリングしたい、という要求がある。 この際、天下り的にネットワークに確率的なinputを与えないとすると、ニューロンに大きな揺らぎを導入して不規則性を付与することになる。具体的には、興奮性ニューロンと抑制性ニューロンが重み付き結合を介して閾値を下回った状態で釣り合い、揺らぎが上振れした時に閾値を超えてスパイクする。

バランスドネットワークとは

integrate-and-fire modelのニューロンで形成されたスパースなネットワークのモデル。上記のような仕組みで不規則な発火を実現する。

  • 興奮性ニューロンと抑制性ニューロンの二つの集団からなり、それぞれのニューロンは確率的に重みを持って結合している。
  • 一般に、ニューロンは相互の結合以外にもいくつかのパラメータの影響を受ける。外部からのノイズを入力として受け取るケースなどがメジャー。 f:id:purple-apple:20180221111722p:plain

ネットワークの動態は、同期的/非同期的(ニューロン集団について)、規則的/不規則的(特定のニューロンについて)などの観点から分類することができる。

  • 同期的/非同期的の分類は、特定集団での発火率が一定に近いかどうかで判定することができる。一定に近ければ非同期的で、振動していれば同期的。
  • 規則的/不規則的の分類は、変動係数を用いて判定されることが多い。変動係数は、ポアッソン分布に基づく発火であれば1に近く、発火が規則的であればあるほど0に近づく。

in vivoでの発火計測では変動係数が1に近い値を示すことが多く、そのため、モデルも非同期現象の再現に焦点を当てることが多い。

f:id:purple-apple:20180221111828p:plain

上図はネットワークの動態を先の観点から4種類に分類したもので、同期的/規則的(左上)、同期的/不規則的(右上)、非同期的/規則的(左下)、非同期的/不規則的(右下)となっている。

関数的メソッドをメソッド引数として渡す

関数的メソッドを引数にとる関数の定義がしたかったのだが、調べてもなかなか丁度良い記事がなかったのでメモ代わりに。 関数的メソッドとは明示的なレシーバを持たないメソッドのこと。素直にグローバルスコープにメソッドを定義するとこれになる。

def test_func(a,b,c)        
  p a + b + c
end

def test_func_func(func)    
  func.call(1,2,3)
end

func = BasicObject.method(:test_func)
test_func_func(func)

# 6
# => 6

どうもにメソッドに引数としてメソッドを渡すときはObject#methodを使ってメソッドを一度オブジェクト化する見たいなのだが、Object#methodは呼び出し時にメソッドのレシーバを明示する必要がある。 では関数的メソッドのレシーバとして記述するオブジェクトは何が適切なのか、という話になるが、これについて明確にこれが良い、というものは分からなかった。 例には、取り敢えず余計な要素を持たないBasicObjectなんか適しているんじゃないだろうか、という推測のもとBasicObjectを用いている。 どなたかご存知でしたら教えてください。

ブロック付きgsubの返り値の違いについて

基本的な話なのだがRubyのブロックには二通りの記法がある。

Objects.each { |object|
    object.method
}

Objects.each do  |object|
    object.method
end

だ。

僕は、手続き上両記法は等価なものだと思っていたのだが、どうもそうでは無いらしい、ということが分かったのでメモとして残しておく。

違い

さて、どのようなケースで等価ではないかというと、下記のような時だ。

pry(main)> s = "hello, world"
pry(main)> puts s.gsub(/\w+/) {|word| word.capitalize }
Hello, World
=> nil

このコードをdo...endによる記法で書くと以下の様な挙動になる。

pry(main)> s = "hello, world"
pry(main)> puts s.gsub(/\w+/) do |word|
pry(main)*   word.capitalize
pry(main)* end
#<Enumerator:0x000056474a99ef70> 
=> nil 

原因

原因は、{...}do...endの結合の強さの違いにある。 Ruby 2.4.0 リファレンスマニュアルには下記のようにある

{ ... } の方が do ... end ブロックよりも強く結合します。 次に例を挙げますが、このような違いが影響するコードは読み辛いので避けましょう:

foobar a, b do .. end # foobarの引数はa, bの値とブロック
foobar a, b { .. } # ブロックはメソッドbの引数、aの値とbの返り値とがfoobarの引数

つまり、

pry(main)> s = "hello, world"
pry(main)> puts s.gsub(/\w+/) do |word|
pry(main)*   word.capitalize
pry(main)* end
#<Enumerator:0x000056474a99ef70> 
=> nil 

では、putsメソッドの引数はs.gsub(/\w+/)do...endブロックと解釈されているのだ。

それぞれ、分けて実行してみると、以下のようになる

pry(main)> puts s.gsub(/\w+/)
#<Enumerator:0x0000560d6a307a78>
=> nil
pry(main)> puts do
pry(main)*   s = 10
pry(main)* end

=> nil

なるほどこの2つが合わさっていたのか。

Rubyではブロックを取るメソッドをブロックを省略して書いた場合、Enumeratorオブジェクトを返す。 gsubの引数に正規表現パターンのみを与えた場合、ブロックを使っての置換の記法になるため、1つめはこれだろう。

2つめはなんだろうか。 チラッと調べてみた所、ブロックを取らないメソッド(内部にyieldがない)にブロックを渡した場合、ブロックは単に無視される、というが引っかかった。 多分これなんじゃないだろうか。こっちについてはもう少し確認する必要がありそうだけれども。

バージョン

$ ruby --version
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux]
=> nil 

参考

Enumerator とブロックの省略 - まめめも

ブロックをdo…endで書くか{…}で書くかにより挙動が変わる例 - Qiita

ブロックを与えない場合にEnumeratorを返すメソッドを作る - Qiita

Ubuntu 16.04 LTSに最新のrbenvを入れた

概要

手持ちのUbuntu 16.04 LTSにaptでrbenvを入れたのだが、バージョンが古くて2.4系のrubyがインストールできなかった。 どうしても2.4系が使いたい気持ちだったため、purgeして野良ビルドを試みた。 その時の記録。

参考

ほぼ上記の内容の通りなので、英語が読めるならこっちを読めばいい。

rbenvのビルド

# リポジトリをクローンしてくる
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv 
# rbenvを高速化するためにbash拡張を試みる。失敗しても別に気にしなくて良い
$ cd ~/.rbenv && src/configure && make -C src
# パスを通す。zshを使うなら~/.zshrcにリダイレクトする
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc

以上で完了。下記を実行して、

$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash

下のような表示が出ればうまくビルドできている。

Checking for `rbenv' in PATH: /usr/local/bin/rbenv
Checking for rbenv shims in PATH: OK
Checking `rbenv install' support: bash: line 114: : command not found ()
Counting installed Ruby versions: none
  There aren't any Ruby versions installed under `~/.rbenv/versions'.
  You can install Ruby versions like so: rbenv install 2.2.4
Checking RubyGems settings: OK
Auditing installed plugins: OK

ruby-buildのビルド

rbenv installコマンドを使えるようにするために、ruby-buildをインストールする。 rbenvのプラグインとしてruby-buildをインストールする。

# プラグイン用ディレクトリの作成
$ mkdir -p "$(rbenv root)"/plugins
# 先のディレクトリ内にリポジトリをクローンしてくる
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

インストール可能なrubyバージョンの確認

$ rbenv install --list

で確認できる。後は、希望のバージョンを

rbenv install 2.4.2

でインストールすれば良い。

group_collection_selectメソッドでのエラー[Ruby on Rails 5 アプリケーションプログラミング]

grouped_collection_selectメソッドでのエラー

最近「Ruby on rails 5 アプリケーションプログラミング」の本を読みながらrailsの勉強をしているのだが、本の記述と配布されているサンプルコード(2017/10/29時点)に誤りがあり、割と長い時間嵌ってしまった。 同じ問題に突き当たる人がいないとも限らないので、解決方法を置いて置く。

問題は「4.1.9 選択ボックスの選択をグループ化するーgrouped_collection_selectメソッド」で解説されているサンプルコード

<%= form_for(@review) do |f| %>
    レビュー対象書籍:
    <%= f.grouped_collection_select :book_id, @authors, :books, :name, :id, :title %>
<% end %>

についてのものだ。 本の手順通りに進めてこのテンプレートファイルを記述し(もちろん対応するルート定義と、コントローラーにメソッドが用意されている必要がある)、サーバーを立ち上げてアクセスすると、

undefined method 'books' for #<Author:~~~>

といったようなエラーに出くわし、ページへのアクセスができない。 これは、この時点でauthorモデルとbookモデルの間にアソシエーションを定義していないことに起因している。配布されているサンプルプログラムの方も同様の理由でエラーを吐く。

ここで問題になっているアソシエーションとはなんだろうか。少し調べた内容を置いておく。

アソシエーション

データベースのテーブル間の関係をrailsのモデル間の関係に落とし込んでrails側から操作できる用にするためのもの。データベースの基本的な用語についてはリンク参照。 テーブルの一つのレコードに対して別のテーブルの一つのレコードが結びついている場合を1:1の関係、別のテーブルのn個のレコードが結びついている場合を1:nの関係などと呼んだりする。

どうも、grouped_collection_selectメソッドはこのアソシエーションの情報を元に対応するbookモデルのパラメータを取得するはずだったのだが、記述がなかったので叶わなかった、ということみたいだ。

対処

そんなわけで、欠けているアソシエーションの情報を補ってやれば解決するということが分かった。今回実装したいauthorとbookの関係性は複数:複数の関係性で、このようなものは中間テーブルを介した表現が一般的らしい。 メソッドとしてはhas_and_belongs_to_manyを使い、下記の用になる。

.../railsbook/model/app/models/ 以下のbook.rbとauthor.rbにアソシエーションを記述する

class Book < ApplicationRecord
    has_and_belongs_to_many :authors #authorとのアソシエーションを追加
end
class Author < ApplicationRecord
    belongs_to :user
    has_and_belongs_to_many :books #booksとのアソシエーションを追加
end

has_and_belongs_to_manyメソッドは複数対複数のアソシエーションをモデルに追加するメソッド。対応するテーブルの関係に上下をつけない為、双方のモデルに記述する必要がある。

以上の変更を加えれば、/view/group_selectのページにアクセスできるようになる。

その他参考

https://teratail.com/questions/80528

テンプレートフレンド演算子の宣言方法

テンプレートクラスにフレンド演算子を定義しようとした時に嵌ったのでメモ。

新たに作ったテンプレートクラスに対する演算子を定義しようとする時、それらをフレンド演算子にすることはままあると思う。管理人もそのような場面に出くわし、素直に定義しようとしたところ思いの他嵌ってしまった。

結論から言うとテンプレートフレンド演算子を定義する時は、以下のようにする(他の方法があるかどうかは調べていない)。

#include <string>

template<typename T> class test_class; //下の定義でクラステンプレートを使用しているのでこちらも事前に定義しておく必要がある。
template<typename T> bool operator==(const test_class<T>, const test_class<T>); //メンバ演算子として演算子テンプレートを定義するので前方宣言が必要

template<typename T>
class test_class
{
  public:
    test_class(std::string string):str(string){}
    std::string get_string() const
    {
    return str;
    }

    friend bool operator==<T>(const test_class<T>, const test_class<T>);  //ここで定義されるのは演算子ではなく演算子テンプレートなのでコンパイラに知らせるために<T>が必要
 //上の一行は下記コードでも代用可能
    //friend bool operator==<>(const test_class<T>, const test_class<T>);
  private:
    std::string str;
};

template<typename T>
bool operator==(const test_class<T> one, const test_class<T> two)
{
    return one.str == two.str;
}

上記コードでコメントのある行はいずれものぞくとコンパイルエラーになる。コンパイラのバージョンは

$ clang++ -v  
Apple LLVM version 8.1.0 (clang-802.0.42) 

参考

stackoverflow.com

テンプレートクラスの演算子の多重定義 - C++ Builder / Turbo C++ 質問の木