(Ruby) Hashの要素を非破壊的に削除する
こういう欲求に出くわすたびに一々調べて、思い出すのに割合時間を喰っている気がするので。 "Ruby"、"Hash"、"要素"、"非破壊的"、"削除"、でこの方法が引っかかる様にしたかったのが大きいです。
結論
reject
を使う。
[41] pry(main)> hash = {a: 1, b: 2, c: 3} => {:a=>1, :b=>2, :c=>3} [42] pry(main)> hash.reject {|key| key == :a} => {:b=>2, :c=>3} [43] pry(main)> hash => {:a=>1, :b=>2, :c=>3}
delete
は破壊的なので使いづらいですね。
ActiveSupportのHash#except
も手軽ですが、バニラなRubyだけで終わらせられると嬉しいこともあるので。
環境
[47] pry(main)> pry-version Pry version: 0.12.2 on Ruby 2.5.1.
tmuxでのコピー内容をMacのクリップボードに共有する[emacsキーバインド]
tmuxでコピーしたものをMacのクリップボードに流し込めると割合便利なことは多い。 ただ、いざこの方法を調べようとするとviキーバインドの場合の設定方法ばかり出てくるので、せっかくなので纏めて置くことにした。
- 必要なソフトをインストールする。
$ brew install reattach-to-user-namespace
- .tmux.confの設定をする。
# Setup 'C-@' to begin selection as in Emacs bind-key -T copy-mode C-@ send -X begin-selection bind-key -T copy-mode C-w send -X copy-pipe "reattach-to-user-namespace pbcopy" # Update default binding of `Enter` to also use copy-pipe unbind -T copy-mode Enter bind-key -T copy-mode Enter send -X copy-pipe "reattach-to-user-namespace pbcopy"
.tmux.confにはtmuxのバージョン2.3と2.4の間で互換性のない変更が入っているので、2.3以前の場合は別の方法で設定する必要がある(ググればすぐ出て来る)。
tmux -V
tmux 2.7
Macのバージョンは10.13.2。
参考
scipyによる3次スプライン補完
未知の関数に出会った時3次スプライン補完をしたいと思うのは人類の普遍的欲求です。 普遍的欲求はだいたいpythonのライブラリが満たしてくれるもので、今回のケースではscipyがその役割を担ってくれます。
scipyの3次スプライン補完についてはいくつか日本語解説ページがあるのですが、
ここで使われている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
出力グラフ
標準出力(コメント部分は後から追記)
[[ 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
バランスドネットワーク理論
「バランスドネットワーク」という言葉は、Computational Neurosience界隈では割とよく聞く言葉じゃないのかな、と思うのですが、日本語で検索をかけても引っかかる文献があまりないので、勉強がてらにメモを残すことにしました。下記の記事が綺麗にまとまっていそうだったので、その要約になっています。管理人はこの分野に関してほぼ素人なので、間違いなどありましたらご指摘いただけると幸いです。
Pierre Yger » The Balanced Network
背景
大枠として、in vivo実験で観察されるニューロンの不規則な発火をネットワークを介してモデリングしたい、という要求がある。 この際、天下り的にネットワークに確率的なinputを与えないとすると、ニューロンに大きな揺らぎを導入して不規則性を付与することになる。具体的には、興奮性ニューロンと抑制性ニューロンが重み付き結合を介して閾値を下回った状態で釣り合い、揺らぎが上振れした時に閾値を超えてスパイクする。
バランスドネットワークとは
integrate-and-fire modelのニューロンで形成されたスパースなネットワークのモデル。上記のような仕組みで不規則な発火を実現する。
- 興奮性ニューロンと抑制性ニューロンの二つの集団からなり、それぞれのニューロンは確率的に重みを持って結合している。
- 一般に、ニューロンは相互の結合以外にもいくつかのパラメータの影響を受ける。外部からのノイズを入力として受け取るケースなどがメジャー。
ネットワークの動態は、同期的/非同期的(ニューロン集団について)、規則的/不規則的(特定のニューロンについて)などの観点から分類することができる。
- 同期的/非同期的の分類は、特定集団での発火率が一定に近いかどうかで判定することができる。一定に近ければ非同期的で、振動していれば同期的。
- 規則的/不規則的の分類は、変動係数を用いて判定されることが多い。変動係数は、ポアッソン分布に基づく発火であれば1に近く、発火が規則的であればあるほど0に近づく。
in vivoでの発火計測では変動係数が1に近い値を示すことが多く、そのため、モデルも非同期現象の再現に焦点を当てることが多い。
上図はネットワークの動態を先の観点から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を用いている。 どなたかご存知でしたら教えてください。
20/2/3追記
id:ikngttyさんがコメントで下記のことを教えてくださいました。
- トップレベル(グローバルスコープ)に定義されたメソッドはObjectのprivateインスタンスメソッドとして定義される。
- トップレベルでの挙動は
self.test_func(args...)
に相当(selfはmainを指す)する。 - selfは省略可能なので、
method(:test_func)
でのオブジェクト化が可能。
ですので、上記を踏まえると以下の書き方が適切に思えます。
def test_func(a,b,c) p a + b + c end def test_func_func(func) func.call(1,2,3) end func = Object.new.method(:test_func) # メソッドの所属先を明示的に表記する場合 func = method(:test_func) # 簡潔に表記する場合 test_func_func(func)
id:ikngttyさんもおすすめされていますが、トップレベルでレシーバが省略されている時点Objectのメソッドであることは確定するので、selfを省略する書き方が個人的にもしっくりきます。メソッドの所属先を明示するためだけにObjectクラスのインスタンスを生成するのはかなり気が引けます。 また、こちらもid:ikngttyさんがおすすめされていますが、特にメソッドを使い回すなどしない場合であればラムダやProcが適切そうです。
いただいたコメントにとても丁寧な解説がありますので、そちらも是非ご覧下さい。
他参考:Ruby のトップレベルメソッドって結局なんなの - Qiita
20/2/25追記
id:ikngttyにいただいたコメントがMarkdown形式のものだったので、許可をいただき、コメントをそのままここに載せさせていただくことにしました。 大変丁寧な解説をありがとうございました。
以下コメントです。
取り敢えず余計な要素を持たないBasicObjectなんか適しているんじゃないだろうか、という推測のもとBasicObjectを用いている。
残念ながら、お望みの効果は得られていない状態になっています。
Object#method と Module#instance_method
Ruby には似たような役割を持つメソッドとして、Object#method
と Module#instance_method
があります。
# Object#method abs123 = -123.method(:abs) p abs123 # => #<Method: Integer#abs> p abs123.call # => 123 # Module#instance_method abs = Integer.instance_method(:abs) p abs # => #<UnboundMethod: Integer#abs> abs234 = abs.bind(-234) p abs234 # => #<Method: Integer#abs> p abs234.call # => 234
つまり、以下の2つが大体同じ関係になっています。
インスタンス.method(:name)
クラス.instance_method(:name)
これを混同して クラス.method(:name)
としてしまうと、以下のようになります。
abs = Integer.method(:abs) # => undefined method `abs' for class `#<Class:Integer>' (NameError)
本記事の
func = BasicObject.method(:test_func)
こちらも同様の構造です。
クラス.method(:name) では何が起きているのか
紛らわしい文章になりますが、クラスをインスタンスとして見た場合、それのクラスはClass
クラスです。
紛らわしいので、以下のコードを見た方がおそらく早いです。
class Foo end foo = Foo.new p foo.class # => Foo p Foo.class # => Class p BasicObject.class # => Class
なので BasicObject.method(:name)
は Class.instance_method(:name)
と意味合いが近いです。
p BasicObject.methods == Class.instance_methods # => true
これは BasicObject
に限らず全てのクラスについて言えます。
p Foo.methods == Class.instance_methods # => true
つまり、以下の2つのコードは同じということです。
func = BasicObject.method(:test_func)
func = Foo.method(:test_func)
この辺が「(BasicObject
を用いても)お望みの効果が得られてない」という根拠です。
「グローバルスコープに定義したメソッド」の正体
では改めて、何がレシーバーとして適切なのか。これは、「グローバルスコープに定義したメソッド」について詳しく調べることが近道となります。
main
オブジェクトについてのリファレンスに、この辺の挙動が詳しく書いてあります。
要約
トップレベルでの self を表すオブジェクトです。
main では参照できない事に注意してください。トップレベルで self から参照してください。
トップレベルで定義したメソッドは Object の private インスタンスメソッドと して定義されます。
(太字による強調はコメント主の私による)
例えば以下のコードで test_func
を呼べるのも、test_func
が「グローバルスコープ」だからなのではなく、 Foo
が Object
を継承してるから、というのが真相です。
def test_func(a,b,c) p a + b + c end class Foo def hoge test_func(2, 3, 4) end end Foo.new.hoge # => 9
また、BasicObject.method(:test_func)
がうまく動いたのも、Class
が Object
を継承しているからです。
余談ですが、p
や puts
などの多くの組み込み関数も似たような仕組みになっています。実はこれらは Kernel
クラスのメソッドとして定義されていて、 Object
はこの Kernel
を継承しています。なので、test_func
と同様に p
や puts
もいろんな場所から呼べるというわけです。
適切なレシーバーは何なのか
ここまでを踏まえてようやく本題です。
案1. BasicObject のインスタンス
とりあえず記事内での考えを延長して、以下のようなコードを考えたくなるかもしれません。しかしこれはエラーになります。
func = BasicObject.new.method(:test_func) # => undefined method `method' for #<BasicObject:0x00007f9c988641b0> (NoMethodError)
理由はもちろん、test_func
が Object
のメソッドだからであり、BasicObject
には含まれないからです。
案2. Object のインスタンス
じゃあ Object
なら動くのか。その通りです。
func = Object.new.method(:test_func) test_func_func(func) # => 6
案3. main オブジェクト(オススメ)
トップレベルで動かすのと全く同じ状態で渡したいなら、トップレベル(=main
オブジェクト)をレシーバーにするのが良いです。上で抜粋した通り、main
オブジェクトは self
で参照します。
func = self.method(:test_func) test_func_func(func) # => 6
なお、self
は省略できます。
func = method(:test_func) test_func_func(func) # => 6
なんと、「レシーバーなんて要らなかったんや!」というオチ。
案4. そもそもメソッドを使わない(一番オススメ)
レシーバーが必要なのはメソッドだからです。Proc
や lambda
を使えばレシーバー無しの「関数」が扱えます。
test_func = lambda { |a, b, c| p a + b + c } def test_func_func(func) func.call(1, 2, 3) end test_func_func(test_func) # => 6
ちなみに lambda
の代わりとして ->
という特殊なリテラル記法もあります。
test_func = ->(a, b, c) { p a + b + c }
以上、コメントで長々と書いてしまいましたが、参考になりましたら幸いです。
ブロック付き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
参考
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
でインストールすれば良い。