tensorflow で rnn を動かしてみる

tensorflow の rnn のチュートリアルはちょっと複雑で何をやってるのかパッとはわからないので、簡単なやつを作って動かしてみたい

そもそもRNNとは?

出力をまた入力に使うらしい。よくこんな図を見るけど具体的に何が起きているのか?

深層学習による自然言語処理 という本だと、

ということなので、1層で入力も出力も2個のときは、下図っぽい感じになるはず。

任意の長さの入力 (今回は入力素子が2個なので長さ4なら [ [3,2], [4,4], [1,0], [9,9] ] みたいな感じ) について、
最後の入力(上の例では [9,9])が渡されたときの出力(にsoftmaxとかかけたもの)で誤差関数の値を計算して、それを最小化するようにWを調整していくことで学習していく。
(必要なら各入力に対する出力を保存しておいてそれらで誤差関数を計算してもいいみたい)

入力の素子数が1つで活性化関数がreluとかなら、Wを全部1にしてbを全部0にすれば任意の長さの正の数の和が計算できそうなので、それを実装してみようと思う。

実装してみる


とりあえず、セルというものが必要らしいのでこれを作成する。
今回は1層だけだけどL層に重ねたりするときは、各層でWとかが存在するので、それぞれの層をひとまとめで表すものがセルなんだと思う。
今回は BasicRNNCell を利用する。

In [1]: import tensorflow as tf

In [2]: sess = tf.Session()

In [3]: size = 1

In [4]: rnn_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=size, activation=tf.nn.relu)

BasicRNNCell は上で図示した感じの最も単純なネットワークのセル。
出力の素子数(num_units)と、利用する活性化関数(activation)を指定できる。

dynamic_rnn を使うとこれより先の処理を自分で書かなくてもよくなるっぽいけど、何が起こっているのか知りたいのでまずはdynamic_rnnを使わずに実装してみる。

各層の出力を入力として使うんだけど、一番最初の入力を渡すときは各層の出力(初期状態)は無いので何らかの値を指定しないと計算ができない。

セルの設定ごとに必要な初期状態のデータの形は変わるけどセル自体に初期状態のデータを出力する機能があるので、これを利用する

In [5]: n_batch = 1

In [6]: initial_state = rnn_cell.zero_state(n_batch, tf.float32)

In [7]: type(initial_state)
Out[7]: tensorflow.python.framework.ops.Tensor


ここまで来ると、任意の入力に対して出力を計算できるようになる

In [32]: x = tf.placeholder(tf.float32, shape=[None, n_batch, size])

In [47]: def inference(x, max_len):
    ...:     state = initial_state
    ...:     for i in range(max_len):
    ...:         (output, state) = rnn_cell(x[i], state)
    ...:     return tf.squeeze(output)
    ...: 

ほんとはxの長さでループを回したいんだけど上手いやり方がわからなかったので、とりあえず長さ固定でやることにする...

次に、誤差の計算をする

In [82]: max_len = 3

In [83]: output = inference(x, max_len)

In [84]: y = tf.placeholder(tf.float32, shape=[])    

In [85]: loss = tf.reduce_mean(tf.square(y - output))

誤差関数を最小化するための、optimizerを作る

In [86]: optimizer = tf.train.GradientDescentOptimizer(0.01)

In [88]: train_step = optimizer.minimize(loss)
In [89]: xs = [ [[[1]],[[2]],[[3]]],
    ...:        [[[2]],[[2]],[[2]]],
    ...:        [[[5]],[[4]],[[3]]],
    ...:        [[[7]],[[7]],[[7]]],
    ...:        [[[9]],[[8]],[[7]]] ]
    ...:        

In [95]: ys = [6, 6, 12, 21, 24]

In [96]: init = tf.global_variables_initializer()

In [97]: sess.run(init)

In [106]: for i in range(len(ys)):
     ...:     sess.run(train_step, feed_dict={x: xs[i], y: ys[i]})
     ...:     


やったー 学習させることに成功しました。

一応結果を確認してみます。

In [111]: print(sess.run(rnn_cell.variables[0])) # RNNのウェイトを表示してみる
[[-4.94734144]
 [-8.36993599]]

In [112]: loss.eval(session=sess, feed_dict={x:[[[1]],[[1]],[[1]]], y:3})
Out[112]: 9.0

学習データが大分少ないので全然誤差がでかいですが、とりあえず動かすことができたのでここまで

tensorflowの初歩の初歩

tensorのshape/dimension

一般的には m行n列の行列は m×n行列 と表記すると思うけど

m = tf.Variable([2,3])

とかしたときは2行3列なのか??とかちゃんとわかってないので確認したい

constantで確認する

In [12]: c1 = tf.constant([[1,2,3], [2,3,4]])

In [13]: c2 = tf.constant([[2,2], [3,3], [4,4]])

In [14]: sess.run(tf.matmul(c1, c2))
Out[14]: 
array([[20, 20],
       [29, 29]], dtype=int32)

In [15]: sess.run(tf.matmul(c2, c1))
Out[15]: 
array([[ 6, 10, 14],
       [ 9, 15, 21],
       [12, 20, 28]], dtype=int32)

In [16]: c1.shape
Out[16]: TensorShape([Dimension(2), Dimension(3)])

In [17]: c2.shape
Out[17]: TensorShape([Dimension(3), Dimension(2)])

ということで、constantでは shape(2, 3) は 2行3列 の行列を表すっぽい

では、縦ベクトル、横ベクトルはどうか?

In [18]: v1 = tf.constant([1,2,3])

In [19]: v2 = tf.constant([[2],[2],[2]])

In [21]: sess.run(tf.matmul(v1, v2))

...(略)
~/dev/tf-train/tf-env/lib/python3.6/site-packages/tensorflow/python/framework/common_shapes.py in _call_cpp_shape_fn_impl(op, input_tensors_needed, input_tensors_as_shapes_needed, require_shape_fn)
    689       missing_shape_fn = True
    690     else:
--> 691       raise ValueError(err.message)
    692 
    693   if missing_shape_fn:

ValueError: Shape must be rank 2 but is rank 1 for 'MatMul_2' (op: 'MatMul') with input shapes: [3], [3,1].

... rank が 2じゃなきゃいけないらしい

In [23]: v1.shape
Out[23]: TensorShape([Dimension(3)])

In [24]: v2.shape
Out[24]: TensorShape([Dimension(3), Dimension(1)])

https://www.tensorflow.org/programmers_guide/tensors

rank は 0がscalar, 1がvector, 2がmatrix らしい

逆に、縦ベクトルも横ベクトルも[1,2,3]みたいに書くべきなのか?

In [25]: v1 = tf.constant([1,2,3])

In [26]: v2 = tf.constant([2,2,2])

In [27]: sess.run(tf.matmul(v1, v2))
...(略)

~/dev/tf-train/tf-env/lib/python3.6/site-packages/tensorflow/python/framework/common_shapes.py in _call_cpp_shape_fn_impl(op, input_tensors_needed, input_tensors_as_shapes_needed, require_shape_fn)
    689       missing_shape_fn = True
    690     else:
--> 691       raise ValueError(err.message)
    692 
    693   if missing_shape_fn:

ValueError: Shape must be rank 2 but is rank 1 for 'MatMul_6' (op: 'MatMul') with input shapes: [3], [3].

やっぱりだめ 内積を計算したければ、ベクトルであっても1×n と n×1 の行列で表さなければならないみたい

In [31]: v1 = tf.constant([[1,2,3]])

In [32]: v2 = tf.constant([[2],[2],[2]])

In [33]: sess.run(tf.matmul(v1, v2))
Out[33]: array([[12]], dtype=int32)

In [34]: v1.shape
Out[34]: TensorShape([Dimension(1), Dimension(3)])

In [35]: v2.shape
Out[35]: TensorShape([Dimension(3), Dimension(1)])
shape part2

触りだしたらやっぱり理解があやふやだったので、再確認

shape [1,2,3] と shape [3,2,1] はどう違うのか?

左からi番目は外側からi番目の[]に入ってる要素の数、みたいに考えれば良さそう

In [12]: tf.constant([  [ [1,1,1], [2,2,2] ] ])
Out[12]: <tf.Tensor 'Const_4:0' shape=(1, 2, 3) dtype=int32>

shape [1, ...] なので 一番外側のに入っている要素は1つ

-> [ [...] ]

shape [1, 2, ...] なので 次のに入っている要素は2つ

-> [ [ [...], [...] ] ]

shape [1, 2, 3] なので 次の[]に入っている要素は3つ

-> [ [ [1,1,1], [2,2,2] ] ]

みたいな

逆に shape [3,2,1] なら

[ [...], [...], [...] ]

  • > [ [ [...], [...] ], [ [...], [...] ], [ [...], [...] ] ]
  • > [ [ [1], [2] ], [ [5], [6] ], [ [9], [0] ] ]

みたいな


あと c[1, :, 1] みたいな ':' をつかった操作もあんまり自信がないので確認

In [26]: c1 = tf.constant([[ [1,3,5], [2,4,6] ]])

In [27]: c2 = tf.constant([ [[1], [2]], [[5], [6]], [[9], [0]] ])

c1[0, :, 1] だと [ [3], [4] ]

c2[:, 1, :] だと [ [2], [6], [0] ]

c2[:, 1, 0] だと [2, 6, 0]

となるみたい

In [28]: sess.run(c1[0,:,1])
Out[28]: array([3, 4], dtype=int32)

In [29]: sess.run(c2[:,1,:])
Out[29]: 
array([[2],
       [6],
       [0]], dtype=int32)

In [30]: sess.run(c2[:,1,0])
Out[30]: array([2, 6, 0], dtype=int32)
scope

サンプルとか見ると

with tf.variable_scope("conv1"):
    ....

とかあるけどこれは何???

https://www.tensorflow.org/programmers_guide/variables

を読むと、同じ名前でget_variableを複数回呼ぶと変数を再利用するのか新規に作るのか判別できないけど、variable_scopeで区切っておけば別のvariable_scope内の変数は再利用しない、みたいなことらしい

In [37]: v1 = tf.get_variable('the_var', [2,3])

In [38]: v2 = tf.get_variable('the_var', [2,3])
... 略
ValueError: Variable the_var already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:

  File "<ipython-input-37-ce1950cb36a3>", line 1, in <module>
    v1 = tf.get_variable('the_var', [2,3])
  File "/home/shuhei/dev/tf-train/tf-env/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2910, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "/home/shuhei/dev/tf-train/tf-env/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2850, in run_ast_nodes
    if self.run_code(code, result):

やはり同名の変数を get_value しようとすると "Variable the_var already exists,"のエラーが起こるらしい
(reuse=Trueとかすれば再利用できるらしい)

これを、variable_scopeで囲っておくと別のスコープで定義された変数は無視して新しく作ってくれるらしい

In [39]: with tf.variable_scope('scope1'):
    ...:     v1 = tf.get_variable('scoped_var', [1,2])
    ...:     

In [40]: with tf.variable_scope('scope2'):
    ...:     v2 = tf.get_variable('scoped_var', [1,2])
    ...:     

In [41]: v1.name
Out[41]: 'scope1/scoped_var:0'

In [42]: v2.name
Out[42]: 'scope2/scoped_var:0'

面白いバラエティ番組に共通しているスタッフが作っている番組もきっと面白いんじゃないかと思って調べた

お笑い番組がすごく好きで昔からよく見ていたのですが、最近、"タレント☆名鑑も水曜日のダウンタウン藤井健太郎という人がつくっているのか!"、とか、"ゴットタンでもキングちゃんでも佐久間Pが出てきてるな〜"、とか思うことがあったので、"出演者よりも、作ってる人に着目したほうが好みの番組が探せるのでは?"と思い立って調べてみました。

僕が好きな番組は以下。


水曜日のダウンタウン
ゴッドタン
くりぃむナンチャラ
そんなバカなマン
さまぁ〜ず
NEO決戦バラエティ キングちゃん
バナナ炎
あらびき団
クイズ☆タレント名鑑
中井正広のブラックバラエティ
働くおっさん劇場
野性爆弾のザ・ワールド チャネリング


誰かが(特に設楽が)指示を出して何かやらせる系(そんなバカなマンのパシフィック・ヒムとか、神さまぁ〜ずのインスタント女王様決定戦とか、バナナ炎の悪者オーディションとか、キングちゃんのエキストラプロデュース王とか)がすごく好きhです。

上記の番組の中の複数の番組の制作に関わっている人というのは僕が好きそうな番組を作ってる人なのだろうから、その人が作っている他の番組を探していけば適当に探すより好きな番組に辿り着きやすいはず!、ということで、まず"上記の番組の中の複数の番組の制作に関わっている人"を調べてみました。

上記の番組のスタッフ一覧をWikipediaから持ってきて、雑なプログラムで重複している人の一覧を出してみました。コードは末尾に。

雑なので会社名とかも入ってしまっていますが、それはそれで"この会社が関わっている番組は面白い"みたいな見方ができるかもとおもってそのままにしています。


出力した結果は以下です。

スウィッシュジャパン ['水曜日のダウンタウン:ロケ技術', 'くりぃむナンチャラ:協力', 'NEO決戦バラエティ キングちゃん:技術協力', 'バナナ炎:協力', 'あらびき団:技術協力', 'クイズ☆タレント名鑑:ロケ技術']
大井洋一 ['水曜日のダウンタウン:構成', '神さまぁ〜ず:構成', 'NEO決戦バラエティ キングちゃん:構成', 'クイズ☆タレント名鑑:構成', '働くおっさん劇場:構成']
興津豪乃 ['水曜日のダウンタウン:構成', 'バナナ炎:構成', 'あらびき団:構成', 'クイズ☆タレント名鑑:構成']
成瀬正人 ['水曜日のダウンタウン:構成', 'ゴッドタン:構成', '神さまぁ〜ず:構成']
大西右人 ['水曜日のダウンタウン:構成', 'ゴッドタン:構成', 'そんなバカなマン:構成']
石川良則 ['水曜日のダウンタウン:音効', 'あらびき団:音効', 'クイズ☆タレント名鑑:音響効果']
小山陽介 ['水曜日のダウンタウン:宣伝', 'あらびき団:PR', 'クイズ☆タレント名鑑:宣伝']
水口健司 ['水曜日のダウンタウン:ディレクター', 'そんなバカなマン:ディレクター', 'クイズ☆タレント名鑑:ディレクター']
吉本興業 ['水曜日のダウンタウン:制作協力', 'あらびき団:制作協力', '働くおっさん劇場:制作']
TBS ['水曜日のダウンタウン:製作著作', '神さまぁ〜ず:製作', 'あらびき団:製作']
渡辺真也 ['水曜日のダウンタウン:構成', 'くりぃむナンチャラ:構成', 'クイズ☆タレント名鑑:構成']
オークラ ['ゴッドタン:構成', 'そんなバカなマン:構成', 'バナナ炎:構成']
永井ふわふわ ['ゴッドタン:構成', 'NEO決戦バラエティ キングちゃん:構成', 'バナナ炎:構成']
斉藤崇 ['ゴッドタン:ディレクター', 'そんなバカなマン:ディレクター', 'NEO決戦バラエティ キングちゃん:演出']
塩谷泰孝 ['ゴッドタン:ディレクター', 'そんなバカなマン:総合演出', '神さまぁ〜ず:ディレクター']
麻布プラザ ['そんなバカなマン:編集,MA', 'NEO決戦バラエティ キングちゃん:技術協力', '中井正広のブラックバラエティ:技術協力']
五十嵐陽 ['NEO決戦バラエティ キングちゃん:カメラ', 'バナナ炎:CAM', 'あらびき団:CAM']
服部潤 ['水曜日のダウンタウン:ナレーション', 'ゴッドタン:ナレーション']
高須光聖 ['水曜日のダウンタウン:構成', '働くおっさん劇場:構成']
矢野了平 ['水曜日のダウンタウン:構成', 'クイズ☆タレント名鑑:構成']
坂口司 ['水曜日のダウンタウン:TD', 'クイズ☆タレント名鑑:TD']
渋谷康治 ['水曜日のダウンタウン:照明', 'クイズ☆タレント名鑑:照明']
関美幸 ['水曜日のダウンタウン:編集', 'クイズ☆タレント名鑑:編集']
伊藤佳加 ['水曜日のダウンタウン:TK', 'クイズ☆タレント名鑑:TK']
新貝元章 ['水曜日のダウンタウン:AP', 'クイズ☆タレント名鑑:キャスティングP']
竹井晶子 ['水曜日のダウンタウン:AP', 'クイズ☆タレント名鑑:AP']
田中良憲 ['水曜日のダウンタウン:ディレクター', 'クイズ☆タレント名鑑:ディレクター']
佐々木卓也 ['水曜日のダウンタウン:ディレクター', 'クイズ☆タレント名鑑:ディレクター']
池田哲也 ['水曜日のダウンタウン:ディレクター', 'NEO決戦バラエティ キングちゃん:ディレクター']
藤井健太郎 ['水曜日のダウンタウン:演出', 'クイズ☆タレント名鑑:演出,プロデューサー']
山口智広 ['水曜日のダウンタウン:美術プロデューサー', 'クイズ☆タレント名鑑:美術プロデューサー']
齊藤傑 ['水曜日のダウンタウン:デザイン', 'クイズ☆タレント名鑑:美術デザイン']
宮本稔久 ['水曜日のダウンタウン:制作プロデューサー', 'あらびき団:プロデューサー']
森俊平 ['水曜日のダウンタウン:制作進行', 'NEO決戦バラエティ キングちゃん:ディレクター']
高田脩 ['水曜日のダウンタウン:ディレクター', 'クイズ☆タレント名鑑:ディレクター']
三枝浩史 ['水曜日のダウンタウン:ディレクター', 'NEO決戦バラエティ キングちゃん:ディレクター']
相澤昇 ['ゴッドタン:構成', 'NEO決戦バラエティ キングちゃん:構成']
小田切暁 ['ゴッドタン:音響効果', 'そんなバカなマン:音響効果']
魚田英孝 ['ゴッドタン:番宣', 'NEO決戦バラエティ キングちゃん:番宣']
テクノマックス ['ゴッドタン:技術協力', 'あらびき団:技術協力']
テレビ東京アート ['ゴッドタン:美術,照明協力', 'あらびき団:技術協力']
美濃部遥香 ['ゴッドタン:AP', 'そんなバカなマン:AP']
双津大地郎 ['ゴッドタン:ディレクター', 'そんなバカなマン:ディレクター']
高井翔太朗 ['ゴッドタン:ディレクター', 'そんなバカなマン:ディレクター']
廣田彰大 ['ゴッドタン:ディレクター', 'そんなバカなマン:ディレクター']
佐久間宣行 ['ゴッドタン:プロデューサー,演出', 'NEO決戦バラエティ キングちゃん:プロデューサー']
シオプロ ['ゴッドタン:制作協力', 'そんなバカなマン:制作協力']
テレビ東京 ['ゴッドタン:製作著作', 'NEO決戦バラエティ キングちゃん:製作著作']
北本かつら ['ゴッドタン:構成', 'くりぃむナンチャラ:構成']
山田かつら ['ゴッドタン:メイク', 'そんなバカなマン:メイク']
小室良太 ['ゴッドタン:演出補', 'そんなバカなマン:プロデューサー']
IMAGICA ['くりぃむナンチャラ:協力', '働くおっさん劇場:技術協力']
加用裕紀 ['そんなバカなマン:ディレクター', 'バナナ炎:ディレクター']
フジテレビ ['そんなバカなマン:制作著作', '働くおっさん劇場:制作']
松井光太郎 ['そんなバカなマン:CAM', '神さまぁ〜ず:カメラ']
安藤雄郎 ['そんなバカなマン:LD', '神さまぁ〜ず:照明']
橋本竜也 ['NEO決戦バラエティ キングちゃん:EED', '中井正広のブラックバラエティ:編集']
柳沼修 ['バナナ炎:VE', 'あらびき団:VE']
蓮田貴志 ['あらびき団:編集', 'あらびき団:VTR編集']
鈴木建介 ['あらびき団:編集', 'あらびき団:編集']

2番組以上に関わっている人は60人いました。
気になった人たちを少し調べて見ました。

スウィッシュジャパン

https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%A6%E3%82%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%83%BB%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3

'水曜日のダウンタウン:ロケ技術',
'くりぃむナンチャラ:協力',
'NEO決戦バラエティ キングちゃん:技術協力',
'バナナ炎:協力',
'あらびき団:技術協力',
'クイズ☆タレント名鑑:ロケ技術'

12番組中半分の6番組に関わっていた制作会社。Wikipediaの記事をみると、めちゃくちゃいろんな番組に関わっているようなのでこの結果にも納得です。
キングちゃんに東野幸治が出たときに"あらびき団のカメラマンだった人じゃないですか!"みたいな事を言っていたけどもしかしたらこの会社の人なのかも?と思いました。制作会社が何をする会社なのかわかってないので、カメラマンとか全然関係なかったらごめんなさい。

大井洋一

https://ja.wikipedia.org/wiki/%E5%A4%A7%E4%BA%95%E6%B4%8B%E4%B8%80

'水曜日のダウンタウン:構成',
'神さまぁ〜ず:構成',
'NEO決戦バラエティ キングちゃん:構成',
'クイズ☆タレント名鑑:構成',
'働くおっさん劇場:構成'

個人では最多の5番組に関わっていた放送作家の方。
"コレってアリですか?"という番組はみたことがなかったのでDVDを探してみようと思います。

興津豪乃

https://ja.wikipedia.org/wiki/%E8%88%88%E6%B4%A5%E8%B1%AA%E4%B9%83

'水曜日のダウンタウン:構成',
'バナナ炎:構成',
'あらびき団:構成',
'クイズ☆タレント名鑑:構成'

4番組は全体で3番目、個人では2番目。
"有吉弘行のダレトク!?"とか"金曜★ロンドンハーツ"とか、調査しなかったけど好きな番組に関わっている方のようです。
"チェンジ3"という番組は今もやっているようなので見てみます。

水口健司

https://twitter.com/mizukenji

'水曜日のダウンタウン:ディレクター',
'そんなバカなマン:ディレクター',
'クイズ☆タレント名鑑:ディレクター'

上位の方は構成の方が多かったのですが、こちらのかたはディレクターのようです。
"とんぱちオードリー", "万年B組ヒムケン先生", "芸人キャノンボール"など、気になるタイトルの番組にも関わっているようなので、これらも見てみようと思います。
次の塩谷泰孝という方が社長をやっているシオプロという会社の方のようです。


塩谷泰孝

https://ja.wikipedia.org/wiki/%E3%82%B7%E3%82%AA%E3%83%97%E3%83%AD

'ゴッドタン:ディレクター',
'そんなバカなマン:総合演出',
'神さまぁ〜ず:ディレクター'

"インスタンス女王様とパシフィックヒムはやっぱり同じ人が作っていたんだ!"と思いました(実際は違うのかもしれません)。
"クレイジージャーニー"ってみたことなかったですが見てみようと思います。
あと、AbemaTVで"フジモンのやりたい10のこと"という番組もやっているようなのでそちらも気になります。

感想

いくつか気になる番組がみつかったので良かったです。
他にも気になった人がいたのですが、他にどんな番組に関わっているかの情報が見つけられなかった人がいたので残念でした。
水曜日のダウンタウンとタレント名鑑とか、ゴッドタンとそんなバカなマンとか、結構重複している人がおおかったので、やっぱりチームで作ってる感じなんだろうなと思いました。

コード
# coding: utf-8

import re

staffs = {'野性爆弾のザ・ワールド チャネリング': '''脚本:佐藤篤志
音楽:石崎勝巳
撮影:今井裕二
証明:大町昌路
録音:古茂田耕吉
美術:山崎輝
装飾:佐藤希、阿久津桂
持道具:中村麻理子
衣装:村島恵子、山下由
ヘアメイク:高橋亮
特殊メイク:百武朋
助監督:後藤ヨシチカ
音響効果・編集:渕野由美
整音・MA:藤本淳
撮影助手:吉田太一
照明助手:二枝史子
特殊メイク助手:並河学
制作主任:大石淳也
制作応援:赤瀬一紀
演出部見習い:半沢和樹
スチール:大蔵俊介、橋本悠平
助監督:谷口仁則
AP:斎木綾乃
プロデューサー:大沼知朗、服巻泰三、上野遼平''',
'水曜日のダウンタウン': '''ナレーション:服部潤
構成:高須光聖、興津豪乃、大井洋一、矢野了平、成瀬正人、飯塚大悟、大西右人
TM:小澤義春
TD:廣田雅之、坂口司
CAM:中野真悟
VE:高橋康弘
音声:中村全希
照明:渋谷康治
ロケ技術:SWISH JAPAN
音効:石川良則
美術プロデューサー:中西忠司
デザイン:松田エリザベス玲子
美術制作:桂誉和
装置:坂本進
電飾:荒谷奏子
装置操作:牧ヶ谷純二
アクリル装飾:井上惠介
小道具:田村健治
持道具:小松絵里子
編集:関美幸、高橋雄人
MA:市川徹
衣裳:岩崎孝典
スタイリスト:高堂のりこ、北田あつ子
メイク:Office MAKISE、岡葵
機材協力:東京オフラインセンター
協力:BACK-UP MEDIA
曲:PUNPEE
CG:ODD JOB
TK:伊藤佳加
リサーチ:亀田貴誠、ジーワン
編成:高橋智大[注 16]
宣伝:小山陽介
デスク:松崎由美
AP:新貝元章、菊池絢子、竹井晶子、宮里良子、近藤陽子、真壁正彦
ディレクター:横井雄一郎、田中良憲、町田有史 / 水口健司、佐々木卓也、久野公嗣、高畑忠司、池田哲也、村中良輔、角田瞬、田村裕之、小林悦子
制作プロデューサー:田井中皓介(以前はAP)、今瀧陽介
監修:柳岡秀一
MP(マネージメントプロデューサー):渡辺英樹[注 17]
演出:藤井健太郎(以前はプロデューサー兼務)
プロデューサー:坂本義幸(以前は担当プロデューサー)
制作協力:吉本興業
製作著作:TBS
構成:渡辺真也[注 18]
TM:山下直、丹野至之
音声:稲津貴之
音効:丹羽さやか、古賀香澄
美術プロデューサー:山口智広
デザイン:齊藤傑
美術制作:川崎光紘
アクリル装飾:相澤香織、井上大華
持道具:寺澤麻由美
MA:新田領
メイク:梅原恵里
曲:パソピー(水曜日のダウソタウソ)
編成:田口健介、中井芳彦、辻有一
宣伝:奥住達也
制作プロデューサー:宮本稔久、谷垣和歌子
制作進行:森俊平
AP:織田直也、花田真志、古川亜希子
ディレクター:高柳健人、須藤駿、高田脩、日野智文、杉本真宣、三枝浩史
制作プロデューサー:山田貢
MP(マネージメントプロデューサー):中川通成、中鉢功
プロデューサー:福田健太郎(以前は編成)
EP:安田淳''',
'ゴッドタン': '''ナレーション:服部潤[注 27]
構成:オークラ、相澤昇、くらなり、成瀬正人、永井ふわふわ[注 28]、大西右人[注 29]
技術:丸山真平(テレビ東京、以前はカメラ)
映像:入江俊之(テレビ東京)
カメラ:風間誠
照明:曽我秀樹
音声:永久保仁志
デザイン:金森明日香(以前は美術進行)
美術進行:仙田拓也
大道具:工藤義昭
小道具:山下正美
メイク:蔵本優花
EED:落合勇(CC Factory〈旧TDKコア〉)
MA:長瀬貴広
音響効果:小田切暁(278→NAP)
タイトル:上田大樹(&FICTION!)
番宣:魚田英孝(テレビ東京、以前はディレクター、一時離脱→復帰)
技術協力:テクノマックス
美術・照明協力:テレビ東京アート
演出補:岡千尋
AP:美濃部遥香(以前は演出補)
ディレクター:田村育 / 今村光宏、斉藤崇、双津大地郎、塩谷泰孝、高井翔太朗(高井→以前は演出補、一時離脱→復帰)、廣田彰大、土屋佳弘(土屋→以前は演出補、一時離脱)(以上シオプロ)
プロデューサー:露木寛子(一時離脱→復帰)(テレビ東京)
プロデューサー / 演出:佐久間宣行(テレビ東京)
協力:ナカムラ綜美
制作協力:シオプロ(2010年10月6日 - )
製作著作:テレビ東京
タイトルコール:INCREDIBLE BEATBOX BAND
プロデューサー:伊藤隆行(初期)・五箇公貴( - 2007年7月18日)・石井成臣(3人共テレビ東京)/志岐誠(NAVI、 - 2010年9月29日)
アシスタントプロデューサー(AP):みうらさなえ( - 2009年5月13日)
構成:北本かつら / 堀田延( - 2010年9月29日)
技術:菊池裕介、野瀬一成(野瀬→以前はカメラ)、吉田健吾(テレビ東京)
映像:佐藤誠二、葛西雅弘、細井昭宏、宮本裕美子、北村宏一、佐久間元貴(テレビ東京)
カメラ:近藤剛史(テレビ東京)
照明:小林瑞雪、宮尾淳一
音声:大津幹弘、斉藤孝行
美術:小越敏彦
小道具:植田幸奈
メイク:山田かつら
ビジュアルフォーマット:松本哲也(CC Factory〈旧TDKコア〉)
EED:神保和則
音響効果:林正貴(278)
番宣:保科啓・小林教子・大塚淳・野上次郎・井上健二・岡仁・大城博章(テレビ東京)
デスク:海野和可奈・露木彩乃(テレビ東京)
ディレクター:小石重蔵、姫野善行(姫野→以前は演出補)、桑原宏次・水野亮太・藤枝彰・田中晋也・板川侑右(テレビ東京)
演出補:篠原裕明(テレビ東京)、亀川匡、小室良太、秋山博明
制作協力:NAVI( - 2010年9月29日)''',
'くりぃむナンチャラ': '''ナレーション:佐藤賢治
構成:渡辺真也、町田裕章、北本かつら、樅野太紀
カメラ:門倉秀樹
音声:田原裕太
照明:吉岡駿
美術:井磧伸介
デザイン:山下高広
美術進行:山本和記
大道具:小宮山博章
ヘアメイク:川口かつら
CG:南治樹、真栄城樹
音効:加藤つよし
編集:小野坂智
MA:宝月健
編成:瀧川恵
宣伝:高橋夏子
TK:吉条雅美
デスク:相馬恵美
協力:テレビ朝日クリエイト、SWISH JAPAN、IMAGICA
AD:金山将世、渡辺直哉
ディレクター:藤本達也、宮本大輔、大野剛史、土井功輔、山本健矢
プロデューサー:小田隆一郎、三藤豊
ゼネラルプロデューサー:畔柳吉彦
制作著作:テレビ朝日
TM:大島秀一
デザイン:濱野恭平、飛田幸
美術進行:入江大介、廣澤陽子
大道具:後藤貴弘
ヘアメイク:小川和美
編集:久保田和樹
編成:高橋正輝、大沢解都
AD:田中晋平
AP:吉田奈央
ゼネラルプロデューサー:藤井智久''',
'そんなバカなマン': '''構成:酒井健作、オークラ、宮森亮(かわら)●
ナレーション:梶裕貴、内田彩
TP:小林錦司●
SW:竹内弘佳●
CAM:古俣智則●
VE:澤田将人
AUD:元山拓己(巳)●
照明:黒井宏行●
音響効果:小田切暁
TK:斉藤裕里
美術プロデューサー:三竹寛典
デザイン:鈴木賢太
美術進行:中村秀美●
大道具制作:山本和成(特番時→大道具操作)
アクリル装飾:相原加奈
メイク:山田かつら
CG:星野安規(Kitty)、三重の人●(kitty)
音楽:the zombies
技術協力:fmt
編集:早川徹哉、前島神奈(前島→以前は編集・MA、一時離脱→復帰)(共に●)
MA:河村大樹●
広報:片山正康●
デスク:市川亜季
Webデザイナー:星野倫美●
AD:佐々木博基、寺本文子(共に●)
AP:美濃部遥香
ディレクター:中西正太、水口健司、高井翔太朗(高井→●)/双津大地郎、斉藤崇、加用裕紀、廣田彰大
プロデューサー:小室良太(シオプロ)
チーフプロデューサー:飯村徹郎(フジテレビ)
総合演出:塩谷泰孝(シオプロ、特番時→演出)
制作協力:シオプロ
制作著作:フジテレビ
構成:大西賢一●、大西右人
TD:若林茂人
SW:浜島一雄
CAM:涌田尚孝、松井光太郎
AUD:絹山幸広
LD:安藤雄郎
美術進行:平山雄大
大道具制作:前田かなこ
メイク:岡田美喜子●
イラスト:大野そら
編集・MA:麻布プラザ、岡田秀夫、林仁美、松阪史高(岡田〜松阪→●)
スペシャルサンクス:野上翔、八代拓、東内マリ子、秋林優花
広報:清田美智子
Webマスター:中山直人●
Webディレクター:藁谷憲幸●
AD:宇田川雄大、備前慎悟、榎本萌菜、柴田千尋●、倉知瑠一●、岡田直美●、馬庭広明●、武藤勇次●
ディレクター:栗坪隆平
チーフプロデューサー:明松功''',
'神さまぁ〜ず': '''企画:大竹一樹 (2008年4月 - 9月)
ナレーション: 中村正 → チェン・チュー → 中村英香(DVDのナレーションも担当)
構成: 大井洋一、成瀬正人、中野恵介、如月聖也
カメラ: 松井光太郎
音声: 谷川宏輝
照明: 安藤雄郎
メイク: 福田祐子
音効: 村松聡・谷脇和正(佳夢音)
技術協力: 八峯テレビ、アンサーズ、FLT、東京タワースタジオ
AP: 高橋利一郎、増岡曲子
ディレクター: 塩谷泰孝、ちのうあい
演出: 水野達也
プロデューサー: 飯沼美佐子
製作: G-yama 、TBS''',
'NEO決戦バラエティ キングちゃん': '''ナレーション:朝倉崇
構成:相澤昇、川上テッペイ、大井洋一(大井→2017年4月10日-)、永井ふわふわ
カメラ:五十嵐陽
音声:織部佳和
美術:丹野ありさ(2017年4月10日-)
EED:森岡佑次、佐々木智司、曽根徹、小森佑輔、北浦美夫、増田功紀、森嶋亮、望月浩久、岩品博之、石上淳、坪野陽季、安田裕禎、山中健司、今坂勇介、藤河優、大場浩二、中島功二、篠崎孝徳、橋本竜也、曽根隼一
MA:長谷川真哉、大野健志、岡崎穣、中尾和博
音響効果:遠藤治朗
タイトル:前川陽介
番宣:魚田英孝(テレビ東京、一時離脱→復帰)
技術協力:スウィッシュ・ジャパン、麻布プラザ
美術協力:フジアール、.movs
演出補:渋谷優介、三浦奈々(三浦→2017年4月10日-)、小林孔治
AP:森友絵(2017年4月10日-)
ディレクター:三枝浩史、橋本詳吾、森俊平
演出:斉藤崇
制作プロデューサー:碓氷容子
プロデューサー:佐久間宣行(テレビ東京)
制作協力:HYBRID FACTORY
製作著作:テレビ東京
美術:内藤佳奈子、円城寺一平
音響効果:千本洋
編成:森本泰介(テレビ東京)
番宣:福井静(テレビ東京)
技術協力:デジタルサーカス
演出補:泉澤康智、上野直人、宮城さんご
ディレクター:池田哲也''',
'バナナ炎': '''総合演出:椎葉宏治
ナレーター:落合隼亮
構成:オークラ、寺田智和、興津豪乃、永井ふわふわ
TD:石毛雄己
CAM:五十嵐陽
VE:柳沼修
AUD:目野智子
PA:橋本淳志
美術プロデューサー:関口美千代
美術進行:佐藤政之
デザイン:ヨシマルシン
スタイリスト:渡辺光
ヘアメイク:ファーストステップ
編集:真野公宏
MA:杉山勉
音効:上口昭雄
AP:妹尾こずえ
協力:ソニー・ミュージックエンタテインメント、ホリプロコム、スウィッシュ・ジャパン、ミッククリエーション、シアターエンジニアリング、トゥミックス
ディレクター:鳥越一夫、好田康智、加用裕紀
プロデューサー:北詰由賀、相沢直、扇京子
エグゼクティブプロデューサー:宮原匡彦
企画:テレバイダー・エンタテインメント[注釈 11]
製作著作:バナナ炎パートナーズ''',
'あらびき団': '''総合演出:原田浩司
構成:中野俊成、松本真一、興津豪乃、遠藤敬、岸本浩二、森、柴田健太郎、今井太郎
CAM:五十嵐陽
AUD:渡辺拓
VE:柳沼修
照明:翁美希子
美術進行:佐藤研英
美術デザイン:松井夢壮、姉川たく(カニカピラ)、田中利明
ヘアメイク:TEES
スタイリスト:山岡かおり
編集:蓮田貴志、鈴木大知、鈴木建介
MA:中村裕子
音効:石川良則
CG:長澤剛史
PR:小山陽介
AD:尾崎まなみ、高橋尚史、伊藤竜太、山村勇介、佐藤国秀
ディレクター:相澤雄、齋藤慎一郎、大森千代美、岩津匡洋、一場孝夫
AP:中野加奈子(NET WEB)、森俊和(よしもとクリエイティブ・エージェンシー)
制作プロデューサー:村田聡子・中塚大悟(NET WEB)
プロデューサー:江間浩司(NET WEB)、宮本稔久(よしもとクリエイティブ・エージェンシー)
技術協力:スウィッシュ・ジャパン、テクノマックス、三雅、ザ・チューブ、テレビ東京アート、SPOT、VOXEL
制作協力:吉本興業
製作:NET WEB、TBS
総合演出:渡辺剛(NET WEB)
AD:石川千成、由茅奈保美、ナオミヤユガ(ケニア)(美女)、沖島新菜、濱田禮徳、田中雄大
ディレクター:川向涼子、本間和美、木村亮
AP:山下征志・土屋達彦・城下拓也・中原隆二・沖本翔子(よしもとクリエイティブ・エージェンシー)、八木愛子
編成:山田康裕
PR:國重希理佳
編集:鈴木建介
MA:伊藤慎吾
VTR編集:蓮田貴志''',
'クイズ☆タレント名鑑': '''ナレーション:銀河万丈
構成:興津豪乃、大井洋一、矢野了平、田中淳也、村上洋賢、梶谷直人/渡辺真也
TM:金澤健一
TD:坂口司
カメラ:中島文章
VE:青木孝憲
音声:渡邉学
照明:渋谷康治
ロケ技術:スウィッシュ・ジャパン
美術プロデューサー:山口智広
美術デザイン:齊藤傑
美術制作:五十川弘一
装置:森田正樹
操作:今野貴司
装飾:森田琴衣
メカシステム:庄子泰広
電飾:梅本孝
持道具:岩本美徳
衣裳:君和田悦子
ヘアメイク:市川温子、佐野優美子
スタイリスト:渡辺浩司
編集:遠藤毅、関美幸
MA:宮嶌宏道
音響効果:石川良則、沢井隆志
タイトルデザイン:草野剛
OPアニメ:シャシャミン&ケイト・アロー(ODDJOB)
CG:Rimo from mocrock&Dr.Ueno(ODDJOB、タイムライン)
TK:伊藤佳加
デスク:椿美貴子
編成:藤原麻知
宣伝:小山陽介
AP:竹井晶子/鈴木愛子
キャスティングP:新貝元章
ディレクター:有田武史、柳信也、水口健司、前島隆昭、佐々木卓也、高田脩、林博史/岡宗秀吾
プロデューサー:西川永哲
演出・プロデューサー:藤井健太郎
CP:合田隆信
制作:TBSテレビ
脚本協力:楠野一郎(GO!ピロミ殺人事件)
VE:宇都宮勝
音声:藤井勝彦
美術制作:小杉理紗
装飾:深山健太郎
電飾:安島美次
持道具:貞中照美
編成:平田さおり(パイロット版)
宣伝:嵯峨一孝
ディレクター:田中良憲(パイロット版)''',
'中井正広のブラックバラエティ': '''構成 : クリタヤスシ、はっしー橋本、とちぼり元
リサーチ : てれすこ、フォーミュレーション
TM : 石塚功
SW : 村松明
CAM : 村上和正
MIX : 今野健
音声 : 山田値久、亘美千子、藤岡絵里子
VE : 石野太一、矢田部昭、鈴木昭博、山口考志
照明 : 平田丈、森田恵太郎、山内圭
美術 : 三浦昭彦
デザイン : 道勧英樹
タイトル : 安居院一展
編集 : 橋本竜也、川口達也、名雪健太郎、望月恵太、村田充、平池優太、朝日豊
MA : 佐藤卓也、大田将一
音効 : 花岡英夫
TK : 恩田明子
デスク : 濱村吏加
広報 : 西室由香里(一時離脱していたが復帰)
美術・照明協力 : 日本テレビアート
技術協力 : NiTRO、ヌーベルバーグ、MIDGET、東京藤田工業、麻布プラザ
スタイリスト : 富岡祥寿
ヘアメイク : 山内勝博
AP : 内田佳与子
AD : 石橋浩二、遠藤隼人、柳川雄洋、小林裕樹、佐藤亮介、澤江智由喜、長富紗良、岡山眞也
ディレクター : 瀬戸口晃、深沢博信、二神新、坂仲久恵、武藤和也、馬杉光
演出 : 中谷聡、さとうしゅう
総合演出 : 村上和彦
プロデューサー : 小澤太郎/ 杉田文彦、磯和伸明、岡村光洋
チーフプロデューサー : 安岡喜郎
協力 : ジャニーズ事務所
制作協力 : いまじん、えすと、ビショップ
製作著作 : 日本テレビ
TM : 牛山雅博、勝見明久、伊東俊哉
CAM : 中川昭生
照明 : 中瀬有紀、小川勉
キャラクターデザイン : 山本峰規子
デスク : 大黒紫
広報 : 神山喜久子
美術 : 林健一
リサーチ : FULLTIME.CO.LTD.
調査 : 松崎郁子
スタイリスト : 伊藤紫
ヘアメイク : 諏訪部留美
AP : 糸井聖一、青木かおる
AD : 先崎真耶
ディレクター : 篠幸生、久木野大、岩佐学、林芳昌、齋藤雅美、石田直人
プロデューサー : 環真吾、村手武治、行方久司
チーフプロデューサー : 政橋雅人、染井将吾、鈴江秀樹''',
'働くおっさん劇場': '''企画:松本人志
構成:高須光聖、渡辺鐘、大井洋一
美術制作:大坊雄二
美術進行:林勇
カメラ:遠山康之
VE:齋藤雄一
音声:杉山直樹
編集:太田友康
MA:円城寺暁
音響効果:高田智彰
TK:菅原洋子
プロデューサー:江本薫(フジテレビ)、高畑正和(吉本興業)
チーフプロデューサー:佐々木将(フジテレビ)
演出・プロデュース:伊藤征章(フジテレビ)
技術協力:ニユーテレス、IMAGICA
制作:フジテレビ、吉本興業'''
}

def split(line):
    line = line.replace('スウィッシュ・ジャパン', 'スウィッシュジャパン') \
               .replace('SWISH JAPAN', 'スウィッシュジャパン') \
               .replace('チェン・チュー', 'チェンチュー') \
               .replace(':', ':') \
               .replace('、', ',') \
               .replace('・', ',') \
               .replace('→', ',') \
               .replace('/', ',') \
               .replace('/', ',') \
               .replace('(', '(') \
               .replace(')', ')') \
               .replace('●', '') \
               .replace(' ', '')
    line = re.sub(r'\(.+?\)', '', line)
    line = re.sub(r'\[.+?\]', '', line)
    role = line.split(':')[0]
    names = line.split(':')[1].split(',')
    return names, role

result = dict()

for title in staffs:
    lines = staffs[title].split('\n')
    for line in lines:
        names, role = split(line)
        for name in names:
            if name not in result:
                result[name] = []
            if title not in result[name]:
                result[name].append(title + ':' + role)


for (name, titles) in sorted(result.items(), key=lambda x: -len(x[1])):
    if (len(titles) > 1):
        print(name, titles)
    

ScalaTest がよくわからなかったので調べた

Scalaの勉強をしていて下記のようなコードが出てきた

https://dwango.github.io/scala_text/test.html#fn_3

import org.scalatest._

class CalcSpec extends FlatSpec with DiagrammedAssertions {

  val calc = new Calc

  "sum関数" should "整数の配列を取得し、それらを足し合わせた整数を返すことができる" in {
    assert(calc.sum(Seq(1, 2, 3)) === 6)
    assert(calc.sum(Seq(0)) === 0)
    assert(calc.sum(Seq(-1, 1)) === 0)
    assert(calc.sum(Seq()) === 0)
  }
}

文字列 should 文字列 in { } ってなんなのか?

とりあえずIDEでコードを書いて should の定義へジャンプしてみると...

https://github.com/scalatest/scalatest/blob/3.0.x/scalatest/src/main/scala/org/scalatest/words/ShouldVerb.scala#L144

    def should(right: String)(implicit svsi: StringVerbStringInvocation): ResultOfStringPassedToVerb = {
      svsi(leftSideString, "should", right, pos)
    }

※ FlatSpec が FlatSpecLike を継承していて、
FlatSpec が ShouldVerb (とかいろいろ) を継承しているのでShouldVerbにアクセス出来ている

カリー化

まず、def should(right)(svsi): ResultOfStringPassedToVerb = {} というのはカリー化

https://sites.google.com/site/scalajp/home/documentation/scala-by-example/chapter5/section2

scala> def func(a: Int)(b: Int): Int = (a + 3) * b

scala> func(3)(4)
res1: Int = 24

scala> val f3 = func(3)(_)
f3: Int => Int = <function1>

scala> f3(5)
res3: Int = 30

上記のように func(a: Int)(b: Int) みたいな感じで定義した関数は func(3)(4) のような形で呼び出すことができる

また、 val f3 = func(3)(_) とすると、1つめの引数を3としたうえで、2つめの引数だけを受け取る関数にすることができる

したがってf3(5) は func(3)(5) と同じ結果になる

shouldはこのように should(foo)(bar) のような形で呼び出すことができる関数らしい

ドットとカッコの省略

scalaではメソッド呼び出しの時の'.'を省略できるらしい (hoge.func() は hoge func()とかける)

引数が1つだけのメソッドを呼び出すときはカッコを省略できるらしいが、このときはかならずドットも省略しておかなければならないらしい (hoge func 3 はOKだけど hoge.func 3 はだめ)

引数が1つだけのメソッドを呼び出すときは() の代わりに {} をつかってもいいらしい

http://qiita.com/tag1216/items/d0c5970f840c9ff30925

scala> class Foo {
     |   def func1(a: Int): Int = a * 3
     |   def func2(a: Int)(b: Int): Int = (a + 3) * b
     | }
defined class Foo

scala> val foo = new Foo()
foo: Foo = $iwC$$iwC$Foo@4bdd6fe0

scala> foo.func1(2)
res9: Int = 6

scala> foo func1(2)
res10: Int = 6

scala> foo func1 2
res11: Int = 6

scala> foo.func1 2
<console>:1: error: ';' expected but integer literal found.
       foo.func1 2
                 ^
scala> foo.func1 { 4 }
res0: Int = 12

scala> foo func1 { 4 }
res1: Int = 12




scala> foo.func2(3)(4)
res12: Int = 24

# func2ではこの手の省略はだめらしい

scala> foo func2(3)(4)
<console>:23: error: Int(3) does not take parameters
              foo func2(3)(4)
                          ^
scala> foo func2(3) 4
<console>:1: error: ';' expected but integer literal found.
       foo func2(3) 4
                    ^

scala> foo func2 3 4
<console>:1: error: ';' expected but integer literal found.
       foo func2 3 3
暗黙の型変換

後ろのほうはあとで考えるとして、 文字列 should ... というのは "abc".should のドットを省略しているのだろう

でもStringにshouldなんてメソッドはない

scalaでは暗黙の型変換というものが利用できるらしい

https://dwango.github.io/scala_text/implicit.html

scala> class MyString(s: String) {
     |   def twice(): String = s + s
     | }
defined class MyString

scala> implicit def convertToMyString(s: String): MyString = new MyString(s)
warning: there were 1 feature warning(s); re-run with -feature for details
convertToMyString: (s: String)MyString

scala> "def".twice()
res3: String = defdef

上記のようにimplicitをつけて関数を定義しておくと、引数の型のオブジェクトを必要に応じて変換してくれる

ここでは"def"という文字列をMyString型にこっそり変換してくれるのでString型でtwiceというメソッドがあるように見えるようになる

これと同様の変換がshouldの前の文字列に対しても行われているのでは?とおもって探したら下記が見つかった

https://github.com/scalatest/scalatest/blob/3.0.x/scalatest/src/main/scala/org/scalatest/words/ShouldVerb.scala#L231

  implicit def convertToStringShouldWrapperForVerb(o: String)(implicit position: source.Position): StringShouldWrapperForVerb =
    new StringShouldWrapperForVerb {
      val leftSideString = o.trim
      val pos = position
    }
  }

Stringを受け取って、shouldが定義してあった StringShouldWrapperForVerb へ変換するimplicitな関数なので多分間違いないが、(implicit position: source.Position) が気になる

implicitな引数

http://qiita.com/tagia0212/items/f70cf68e89e4367fcf2e#2-3-implicit%E5%BC%95%E6%95%B0%E3%81%A8implicit%E5%A4%89%E6%95%B0

引数にimplicitを付けておくと、その引数を渡さなくても予めimplicitをつけておいた変数をその引数としてつかってくれるらしい

scala> implicit val num: Int = 123
num: Int = 123

scala> def impargFunc(implicit a: Int): Int = a * 2
impargFunc: (implicit a: Int)Int

scala> impargFunc(3)
res4: Int = 6

scala> impargFunc()
<console>:27: error: not enough arguments for method impargFunc: (implicit a: Int)Int.
Unspecified value parameter a.
              impargFunc()
                        ^

scala> impargFunc
res6: Int = 246

implicitな引数を利用するときはカッコごと省略しなければならないらしい

先ほどの implicit def convertToStringShouldWrapperForVerb(o: String)(implicit position: source.Position): StringShouldWrapperForVerb も source.Position な変数がどこかでimplicitをつけて定義されているはずだ

implicitな引数に具体的な値を渡さなかった場合,コンパイラはimplicitが付いている値・関数から型の合うものを探し,渡してくれる。(探す範囲はその呼び出しのスコープ内からです。)

なので変数でなくてもいいらしい

ShouldVerb.scala からimportされている箇所をさがすとどうやら

https://github.com/scalatest/scalatest/blob/3.0.x/scalactic/src/main/scala/org/scalactic/source/Position.scala#L57

がimplicitなPositionとして利用されるらしい

implicit def here: Position = macro PositionMacro.genPosition

内容まではよくわからないが一旦、ここで定義されているPositionが利用されるらしい、ということにしてこれについては切り上げよう

ここまでのまとめ

shouldの正体を追いかけて

def should(right: String)(implicit svsi: StringVerbStringInvocation): ResultOfStringPassedToVerb

はStringを暗黙の型変換でStringShouldWrapperForVerbに変換し、そのメソッドとして呼び出されているようだ、ということがわかった

うえのほうでほったらかしていたが、svsiもimplicitな引数なのでどこかでimplicitな値 or 関数が定義されていてそれが利用されるのだろう

ということで、

文字列 should 文字列 in { }

の2つめの文字列までについては
文字列.should(文字列) であり、この型は ResultOfStringPassedToVerbであることがわかった

ということで、次の in は多分 ResultOfStringPassedToVerbのメソッドなのだろう

これについて見ていく

in

inの定義にジャンプしてみたらResultOfStringPassedToVerbではなく、InAndIgnoreMethods というクラスで定義されていた

https://github.com/scalatest/scalatest/blob/3.0.x/scalatest/src/main/scala/org/scalatest/FlatSpecLike.scala#L1397

一瞬面食らったが、よくみたら暗黙の型変換が行われていた

protected implicit def convertToInAndIgnoreMethods(resultOfStringPassedToVerb: ResultOfStringPassedToVerb): InAndIgnoreMethods =
    new InAndIgnoreMethods(resultOfStringPassedToVerb)

ということで、改めてinの定義をみてみる

    def in(testFun: => Any /* Assertion */)(implicit pos: source.Position): Unit = {
      registerTestToRun(verb.trim + " " + rest.trim, "in", List(), testFun _, pos)
    }

posについてはshouldの時と全く同じ

testFun の型は => Any となっている

これはjavaでいうところのSupplier(つまり引数をとらず、戻り値を返す関数)なのかなと思ったがどうも違うらしい

http://www.ne.jp/asahi/hishidama/home/tech/scala/def.html#h_call_by_name

scala> def func(f: => Any) = f
func: (f: => Any)Any

scala> func({ 123 })
res7: Any = 123

scala> func(222)
res8: Any = 222

scala> func({ val a = 123; val b = "abc"; 333 })
res10: Any = 333

"名前渡しにすると、関数(関数リテラル)も渡せるし、普通の値も渡せるようになる。
名前渡しした関数は、実際に使われるまで評価(実行)されない。"

ということらしい

まとめ

長々と書いたが

文字列 should 文字列 in { }

文字列.should(文字列).in({})

だった

慣れればこういうのを見てもどれがメソッド呼び出しでどれが引数なのか、とかすっとわかるようになるのかしら

Google Python Style Guide を読んだ時のメモ

https://google.github.io/styleguide/pyguide.html を読んだ時のメモ

Imports

パッケージかモジュール単位でのみimportをする

Packages

モジュールはフルパスを指定してインポートする

# Reference in code with complete name.
import sound.effects.echo

# Reference in code with just module name (preferred).
from sound.effects import echo

Nested/Local/Inner Classes and Functions

Nested/local/inner なクラスや関数を利用する

List Comprehensions

リスト内包表記は複雑にならない時は利用する

Default Iterators and Operators

リストや辞書、ファイルなどdefault iteratorsやoperatorsをサポートしている型では、それらを利用する

Yes:  for key in adict: ...
      if key not in adict: ...
      if obj in alist: ...
      for line in afile: ...
      for k, v in dict.iteritems(): ...
No:   for key in adict.keys(): ...
      if not adict.has_key(key): ...
      for line in afile.readlines(): ...

Generators

ジェネレータは必要に応じて利用する

Lambda Functions

1行で収まるならOK

Conditional Expressions

1 if cond else 2 みたいなやつ
1行で収まるならOK

Default Argument Values

基本的にOK
ただし、mutableなオブジェクトはデフォルト値として渡すべきではない
また、b=time.time() みたいなのもモジュールがロードされた時にしか評価されないので注意

Properties

TODO

True/False evaluations

0, None,, {}, '' をbooleanとして評価するとFalseになる
基本的に if foo !=
: より if foo: という書き方をする

その他の注意

- None みたいなシングルトンと比較するときに == や != は使わずis や is not を使う
- デフォルト値がNoneの変数/引数xがNoneかどうかのチェックでif x is not None: という意味で if x: と書くときは注意が必要 値が指定されたけどそれが空文字や空リストだと if x: だとfalseと判定されてしまう
- x == False みたいな比較はしない するなら not x. NoneとFalseを区別したいなら if not x and x is not None
- integerの場合は0が暗黙的にFalseとなることを利用するより明示的に == 0としたほうが良い

Lexical Scoping

利用してOK

Function and Method Decorators

明確な利点がある時のみ利用する

Threading

組み込み型のatomicityに頼らない

Power Features

メタクラスバイトコードへのアクセス、on-the-flyコンパイル、動的継承、object reparenting(?)、インポートハック、リフレクション、modification of system internals(?) とかは使わない

Semicolons

行の末尾にセミコロンは使わない
複数のコマンドを1行に収める目的でも使わない

Line length

80文字までにする
ただし、importが長くなった時やコメント中のURLについてはOKとする

Parentheses

不要ならカッコは書かない

Shebang Line

直接実行されるファイル以外には記載しない

Comments

TODO

Classes

親クラスがないときは objectを明示的に継承する

Strings

  1. じゃなくて formatか%で文字列を組み立てる

ファイル中では"をつかうのか'を使うのかを統一する
ただし、エスケープを回避するのに一部異なるのはOK

Imports formatting

1つのimportでインポートするのは1つ

Yes: import os
     import sys

No:  import os, sys

Configuring your Project

Initial Files

プロジェクトに必要なファイル

setup.py

最重要ファイル
プロジェクトのルートディレクトリに配置する
サンプル

2つの重要な機能を提供

1. プロジェクトの設定を記載する
setup()という関数が含まれていて、この関数に渡す引数でプロジェクト名とかの設定をする
2. パッケージングに関する様々なコマンドを起動するためのCLIを提供

setup.cfg

setup.py で利用するオプションを含むiniファイル

README.rst

必須ではないけど、README

MANIFEST.in

省略

LICENSE.txt

省略

必須ではないが、プロジェクト名と同じか非常に近い名前のパッケージをプロジェクトのルート直下に一つ作り、その下に自分のpythonモジュールやパッケージを配置するのが一般的

setup() args

name
name='sample',

プロジェクトの名前
PyPIのリストに記載されるときにも利用される

version
version='1.2.0',

プロジェクトのバージョン

Choosing a versioning scheme も参照

description
description='A sample Python project',
long_description=long_description,

プロジェクトの説明

url

省略

author

省略

license

省略

classifiers

省略

keywords

省略

packages
packages=find_packages(exclude=['contrib', 'docs', 'tests*']),

プロジェクトにインクルードするパッケージのリスト
手動で列挙してもいいけど、setuptools.find_packagesを使えば自動でできる
(その際、テスト等のインストールやリリースが不要なパッケージはexcludeで指定しておく)

install_requires
install_requires=['peppercorn'],

プロジェクトに必要なパッケージを記載しておく

install_requires vs Requirements files も参照

python_requires
python_requires='>=3',

pythonのバージョンを指定する

package_data

省略

data_files

省略

scripts

これじゃなくて、console_scriptsを使うのが推奨らしい

entry_points
entry_points={
    'console_scripts': [
        'sample=sample:main',
    ],
},

console_scripts
"console_scripts"というエントリポイントを利用して、スクリプトのインタフェースを登録できる
上記の例だと、sampleというコマンドが実行できるようになって、実行するとsample:mainが呼び出される

Automatic Script Creationも参照

Choosing a versioning scheme

Standards compliance for interoperability

Pythonのプロジェクトは PEP440で定義されている public version schemeに従うことが求められる

以下は省略

Working in "Development Mode"

必須ではないが、プロジェクトでの作業中に"editable"モード または "develop"モードでプロジェクトをローカルにインストールするのが一般的

これによって、プロジェクトをインストールした状態で編集が可能になる

プロジェクトのルートディレクトリで下記を実行する

pip install -e .
  • e は --editableの省略した形

このコマンドを実行すると "install_requires"で指定した依存パッケージや、"console_scripts"で指定したスクリプトもインストールされます

依存しているパッケージも編集可能な状態でインストールしたいときは

-e .
-e git+https://somerepo/bar.git#egg=bar

依存しているパッケージをインストールしたくない時は

pip install -e . --no-deps

Packaging your Project

省略

Uploading your Project to PyPI

省略

pandasの使い方とか

普段pythonもpandasもscikit-learnも使ってないのでチートシート的にまとめておきたい

随時更新していく

ファイルの読み込み

train = pd.read_csv('train.csv')

欠損値の確認

total = train.isnull().sum().sort_values(ascending=False)
ratio = total / train.shape[0]
missing = pd.concat([total, ratio], axis=1, keys=['total', 'ratio'])

列の除去

あまりにも欠損値が多い列を消す時とか

train2 = train.drop(['Cabin'], axis=1)
# trainを上書きしてしまっていいなら下記でも良い
train.drop(['Cabin'], axis=1, inplace=True)

条件を満たす行の除去

学習データで数行だけ欠損値があって学習時にそれらを無視したい時とか

train = train.drop(train.loc[train['Embarked'].isnull()].index)

locの使い方

列名、行名(index) か、列のboolean, 行のboolean でDataFrameの一部を取得できる df.loc[行, 列]

# 行(index指定)
train.loc[19]

# 行(index複数指定)
train.loc[[9, 19]]

# 条件 (行)
train.loc[train['Embarked'].isnull()]

# 列名
train.loc[:, 'Name']

# 列名(複数)
train.loc[:, ['Name', 'Age']]

カテゴリカル -> ダミー変数 への変換

dummy_sex = pd.get_dummies(train.Sex, drop_first=True)

train2 = pd.merge(train, dummy_sex, left_index=True, right_index=True)

列名の変更

train.rename(columns={'Q': 'Embarked_Q', 'S': 'Embarked_S'}, inplace=True)

バリデーション用のデータを分ける

from sklearn.model_selection import train_test_split
x_train, x_valid, y_train, y_valid = train_test_split(x_train, y_train, test_size=0.1, random_state=0)

パラメータのグリッドサーチ

from sklearn.ensemble import RandomForestClassifier
from sklearn.grid_search import GridSearchCV

tune_params = {
    'n_estimators': [1, 10, 50, 100, 500, 1000],
    'random_state': [100]
}

clf = GridSearchCV(
    RandomForestClassifier(), # 識別器
    tune_params, # 最適化したいパラメータセット 
    cv=5, # 交差検定の回数
    scoring='accuracy' ) 

clf.fit(x_train, y_train)

# 確認
clf.grid_scores_

バリデーション用データで評価してみる

clf.best_estimator_.score(x_valid, y_valid)

正規化

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(x_train) # ホントはx_combined的なものでfitさせたほうが良さそう
x_train_scaled = scaler.transform(x_train)

Stackingについて

https://mlwave.com/kaggle-ensembling-guide/

を読んでも意味がわからなかったけど、やっとわかったのでメモとして残す。

意味がわからなかったのは、Stacked generalizationの部分で、

・Split the train set in 2 parts: train_a and train_b
・Fit a first-stage model on train_a and create predictions for train_b
・Fit the same model on train_b and create predictions for train_a
・Finally fit the model on the entire train set and create predictions for the test set.
・Now train a second-stage stacker model on the probabilities from the first-stage model(s).

訳してみると

・学習データをtrain_aとtrain_bの2つに分ける
・first-stageモデルをtrain_aで学習させ、train_bの予測をする
・同じモデルをtrain_bで学習させ、train_aの予測をする
・最後に、学習データ全体でモデルを学習させ、テストデータの予測をする
・ここで、second-stage stackerモデルをfirst-stageモデルから得られた確率で学習させる

で、とくに最後の"Now train a second-stage stacker model on the probabilities from the first-stage model(s)."が何を言っているのかさっぱりわからなかった。

https://www.kaggle.com/rcasellas/ensemble-stacking-with-et-script/codehttps://github.com/MLWave/Kaggle-Ensemble-Guide/blob/master/blend_proba.py をみたらなんとなく理解できた

身長と体重から男か女かを求める、みたいな問題を考える。

学習データとして6人分の身長体重と男か女かが与えられ、テストデータとして3人分の身長体重が与えられたとしよう。

x_train = np.array([[170, 64], [158, 49], [162, 53], [165, 58], [149, 50], [178, 80]])
y_train = np.array([1, 0, 0, 1, 0, 1]) # 1: 男性, 0:女性
x_test = np.array([[181, 83], [168, 52], [170, 60]])

x_trainとy_trainでなんらかのモデルを学習させてx_testをそのモデルに渡せばx_testのそれぞれが男なのか女なのか?の予測をしてはくれるが、ここでやりたいのは、複数のモデルを組み合わせてより精度の良い予測をすることである。(実際にモデルを組み合わせたからといって必ず精度が良くなるわけではない)

SVCとLogisticRegressionを組み合わせてみる

from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression

model_svc = SVC(C=0.025, kernel='linear', probability=True)
model_lr = LogisticRegression(C=1e5)

それぞれのモデルで、

1. 3~6人目のデータでモデルを学習させ、1人目と2人目の予測値を出す
2. 1,2,5,6人目のデータでモデルを学習させ、3人目と4人目の予測値を出す
3. 1~4人目のデータでモデルを学習させ、5人目と6人目の予測値を出す

という作業をまず行う

# 3~6人目のデータで学習し、1人目と2人目を予測する
train_idx = [2,3,4,5]
test_idx=[0,1]
model_svc.fit(x_train[train_idx], y_train[train_idx])
model_svc.predict_proba(x_train[test_idx])

=> array([[ 0.43256083,  0.56743917],
       [ 0.60936777,  0.39063223]])

# 1,2,5,6人目のデータで学習し、3人目と4人目を予測する
train_idx = [0,1,4,5]
test_idx=[2,3]
model_svc.fit(x_train[train_idx], y_train[train_idx])
model_svc.predict_proba(x_train[test_idx])

=> array([[ 0.57525104,  0.42474896],
       [ 0.5       ,  0.5       ]])

# 1~4人目のデータで学習し、5人目と6人目を予測する
train_idx = [0,1,2,3]
test_idx=[4,5]
model_svc.fit(x_train[train_idx], y_train[train_idx])
model_svc.predict_proba(x_train[test_idx])

=> array([[ 0.82079699,  0.17920301],
       [ 0.04084148,  0.95915852]])



これが、

・学習データをtrain_aとtrain_bの2つに分ける
・first-stageモデルをtrain_aで学習させ、train_bの予測をする
・同じモデルをtrain_bで学習させ、train_aの予測をする

の作業に相当する。この結果、SVCでは、

[0.43256083, 0.60936777, 0.57525104, 0.5, 0.82079699, 0.0408414]

という結果が得られたことになる

同様の作業をLinearRegressionでも行うと、

[0.0, 1.0, 9.99998480e-01,  9.30289544e-01, 0.95117108, 0.0]

という結果が得られる

これらを組み合わせると、

[ 
  [0.43256083, 0.0],
  [0.60936777, 1.0],
  [0.57525104, 9.99998480e-01],
  [0.5,        9.30289544e-01],
  [0.82079699, 0.95117108],
  [0.0408414,  0.0]
]

というデータを作ることができる。

・Now train a second-stage stacker model on the probabilities from the first-stage model(s).

がいうところのthe probabilities from the first-stage model(s)がこのデータに相当する。

これを学習データとして、男か女か?を判断してみようというのがstackingの肝なんだと思う。
今回はこのデータを学習させるのもSVCをとりあえず使った。

st_train = np.array([ 
  [0.43256083, 0.0],
  [0.60936777, 1.0],
  [0.57525104, 9.99998480e-01],
  [0.5,        9.30289544e-01],
  [0.82079699, 0.95117108],
  [0.0408414,  0.0]
])
model_svc_for_stack = SVC(C=0.025, kernel='linear', probability=True)
model_svc_for_stack.fit(st_train, y_train)

このモデルに、テストデータを渡してpredictを実行したいけどテストデータは身長と体重の形式なので渡せるデータに変換しなければならない。

そこで

・Finally fit the model on the entire train set and create predictions for the test set.

の作業が必要になる。

model_svc.fit(x_train, y_train)
model_svc.predict_proba(x_test)

=> array([[ 0.08281354,  0.91718646],
       [ 0.56683773,  0.43316227],
       [ 0.4093662 ,  0.5906338 ]])

model_lr.fit(x_train, y_train)
model_lr.predict_proba(x_test)

=> array([[  0.00000000e+00,   1.00000000e+00],
       [  1.00000000e+00,   4.45860798e-19],
       [  1.20908600e-05,   9.99987909e-01]])

よって

[ [0.08281354, 0.0],
  [0.56683773, 1.0],
  [0.4093662, 1.20908600e-05]
]

を先ほどのmodel_svc_for_stackに渡してやれば、最終的な予測を行うことができる

st_test = np.array([ [0.08281354, 0.0],
  [0.56683773, 1.0],
  [0.4093662, 1.20908600e-05]])

model_svc_for_stack.predict_proba(st_test)
=> array([[ 0.4850637 ,  0.5149363 ],
       [ 0.50555437,  0.49444563],
       [ 0.48761824,  0.51238176]])

話としては以上。

以下補足。

補足1

https://www.kaggle.com/rcasellas/ensemble-stacking-with-et-script/code
では、st_testを作るのに、"# 1,2,5,6人目のデータで学習し、3人目と4人目を予測する"とかで得られたそれぞれのモデルでx_testを予測してその平均を使ってた

補足2

http://qiita.com/TomHortons/items/2a05b72be180eb83a204
とかだと、たぶんst_trainとy_trainでもう1回今回でいうところのmodel_svcとmodel_lrを使ってst_train_2的なデータを作ったうえで、それをxgbでまとめているみたい