早稲田大学の校歌の歌詞って水樹奈々さんのどの楽曲の歌詞に似ているの?
この記事は「早稲田大学 Advent Calendar 2016」23日目の記事です。
こんにちは、卒論がヤバいいっちーです。
今回は doc2vec を使って、早稲田大学の校歌が水樹奈々さんのどの楽曲の歌詞に似ているのかを類似度判定していきたいと思います。
なぜ水樹奈々さんなのか
好きだからです。
doc2vec とは
gensim という Python のライブラリのモジュールの1つです。
word2vec を応用して、単語だけではなく文章をベクトル表現化することができます。
word2vec の説明はこちらの記事(人工知能の今と一歩先を発信するメディア)が分かりやすかったです。
方法
こちらのブログ(おいしいとこはすこしだけ 文系出身SE見習いの備忘録。)を参考にさせていただきました。
手順1 : データを作る
- 水樹奈々さんの楽曲のタイトルと都の西北が改行区切りで入力されているテキストファイル(title.txt)
- 水樹奈々さんの楽曲と都の西北の歌詞を Mecab で分かち書きしたものが改行区切りで入力されているテキストファイル(lyric.txt)
※仕様上、タイトルと歌詞の行数が対応している必要があります。
手順2 : コードを書く
Gist にあげておきました。
チェック
1. Synchrogazer に似た歌詞を持つ楽曲を探してみます。
Synchrogazer-Aufwachen Form- は Synchrogazer の前奏をアレンジしただけの曲で歌詞は同じです。
歌詞が同じ曲で 類似度 0.999716699123。1 にならないのが気になりますが、ほぼ一致って感じですね。
2. ETERNAL BLAZE に似た歌詞を持つ楽曲を探してみます。
BRIGHT_STREAM や innocent_starter など 「魔法少女リリカルなのは」の楽曲が上位に来ています。
良い感じですね。
結果
それでは、都の西北の歌詞と類似度の高い水樹奈々さんの楽曲を探してみましょう。
うーん。
一番 類似度の高い曲でも 0.374414801598 ですか。。。
お世辞にも高い類似度とは言い難いですね。悲しい。
まとめ
残念ながら、都の西北と類似度の高い水樹奈々さんの楽曲は見つかりませんでした。
他のアーティストでも試して、都の西北と類似度の高い楽曲を探し出してみたいですね。
系属校、付属校の校歌でも試したいなと思ったのですが、卒論があるので解散です!
Template method パターン
Template method パターン
テンンプレートメソッドパターンは、「似たような流れの処理」をスーパークラスで共通化し、「固有の処理」をサブクラスにまかせることで、「処理のテンプレート」を作成するパターンです。
案件
とあるアイドル2人がいました。
彼女たちはLIVEでは同じように歌って、踊ります。しかし、人気には差があります。
1人はシングル曲の選抜メンバーに選ばれるほどの人気者(kojiharu)で、握手の列が大混雑。
もう1人は研究生で人気はまだまだ(asapon)。握手のレーンはまばらです。
ある日、2人はLIVEを行う事になりました。
LIVEは歌って、踊って、握手をします。
しかし、2人の人気に差があるので、歌って、踊りつつ、握手の対応だけ変えたいということになりました。
実装
// 2人のスーパークラス class Idol { func live() { sing() dance() shakeHand() } func sing() { print("歌う"); } func dance() { print("踊る"); } func shakeHand() { fatalError("オーバーライドしてね") } } // 握手の対応だけ変えます //人気な選抜メン class Senbatsu: Idol { override func shakeHand() { print("サクッと対応する") } } // 研究生 class Kenkyusei: Idol { override func shakeHand() { print("ゆっくりファンの人との会話を楽しむ") } } // kojiharu let kojiharu = Senbatsu() kojiharu.live() //歌う 踊る サクッと対応する //asapon let asapon = Kenkyusei() asapon.live() //歌う 踊る ゆっくりファンの人との会話を楽しむ
結果
処理の構造を変えずに、サブクラスで変えたい処理の内容を再定義することができました。
これは継承を使っていますが、委譲を使って同じことを実現するStrategyパターンもあるようなので、後日実装したいです。
継承を使うとスーパークラスの変更があった場合、サブクラスに影響が出るので、委譲を使ったほうがクラスと実装を疎結合にできそうな機運は高まってますね。
Swift Delegateを理解する
Delegate(委譲)とは
今回はデザパタからは一旦離れて、Delegateを理解します。
何故かと言うと、Adapterパターンの手法の中で「委譲」が出てきて、「そういえばDelegateって理解が曖昧だったかも〜」と思ったからですね。
ずばり、Delegateとは処理を任せるです。
なぜ、Delegateするのか
例えば、func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
メソッド
この関数はUITableVIewDelegateのメソッドでTableViewにどんなCellを表示するか
を指定するメソッドです。
なんでTableViewがこのメソッドをDelegateメソッドにしているかというと表示するCellはControllerに指定してもらったほうが良いからです。
Viewを担うTableViewが何を表示するか決めるようとするとModelと密結合になってしまったり、TabaleVIewの再利用性が低くなってしまいます。
案件
今回はこんなシチュエーションを想定します。
- Idolクラス(カメラマンにポーズを決めてもらいたい)
- IdolDelegate(「写真を取るときにポーズを指定してね」と教える)
- CameraManVIewController(アイドルの写真を撮る)
実装
IdolDelegate
Delegateするためには、処理を委譲してもらうクラスに、なにを実装すればいいかを教えるProtocolを使います。
import Foundation protocol IdolDelegate: NSObjectProtocol { func takePicture() -> String? }
Idol
Delegateしてもらうクラス
import Foundation class Idol :NSObject{ var delegate: IdolDelegate? func pose() { if let poseName = self.delegate?.takePicture() { print("アイドルは\(poseName)のポーズをした") } } }
CameraManViewController
アイドルのDelegateMethodを使ってポーズを決めます
import UIKit class CameraManViewController: UIViewController, IdolDelegate { var poseName: String? let idol = Idol() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.idol.delegate = self self.designatePose("ピース") idol.pose() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Private Method func designatePose(poseName: String) { self.poseName = poseName } // MARK: - Delegate Method func takePicture() -> String? { return self.poseName } }
結果
アイドル「ポーズを指定してね!!」
カメラマン「デュフっ、ピースして欲しいコポォ!!!」
アイドル「はい!(ピース)」
カメラマン「(パシャっ)」
って感じになりました。
swiftでデザインパターンを実装(Adapterパターン:委譲)
Adapterパターン:委譲
前回に引き続きAdapterパターンを実装していきます。 今回は委譲を使った手法です。 この手法はAdapterクラスがTargetクラスを継承し、メンバ変数にAdapteeクラスを持つことによって実現します。
案件
登場人物
- Adaptee(MizukiNana)
- 水樹奈々さん。既存のクラス。
今までどおり歌って、演技をしていきたい。
- 水樹奈々さん。既存のクラス。
- Target(Kohaku)
- 紅白歌合戦に出場するために継承しなければならないクラス。
kohaku()
が定義されている。
- 紅白歌合戦に出場するために継承しなければならないクラス。
- Adapter(NanaMizuki)
kohaku()
を継承した水樹奈々さん。
実装(Playground)
// Adaptee class MizukiNana { func perform() { print("演技する") } func sing() { print("歌う") } } // Target class Kohaku { func kohaku() { fatalError("サブクラスで使ってね") } } // Adapter class KohakuMizuki: Kohaku { private let mizukiNana = MizukiNana() override func kohaku() { mizukiNana.sing() //委譲 } func engi(){ mizukiNana.perform() } } let nana = KohakuMizuki() nana.kohaku() nana.engi()
結果
無事、奈々さんは普段通り演技もできて、紅白に出場するためのクラスを継承することができた。
感想
2回に分けてAdapterパターンを実装してきたわけですが、実装手法の「継承」や「委譲」は、
- AdapterクラスがAdapteeクラスを継承する
- AdapterクラスがAdapteeクラスに委譲する という文脈で使われていると気付きました。
次回はAdapterパターンのもう少し実践的な実装(紅白出場歌手を水樹奈々さんではなくラブライブに変更したい場合)やOSSでどのように使われているのかを調査したいと思います。
swiftでデザインパターンを実装(Adapterパターン:継承)
今回はAdapterパターンを実装します
- Adapterパターンとは?
既存のクラスに対して修正を加えることなく、インタフェースを変更することができる。
Adapterパターンは「継承」と「委譲」の2つの手法で実現できます。
今回は「継承」を用いた手法を実装してみます。
案件
登場人物
- Adaptee(MizukiNana)
- 水樹奈々さん。既存のクラス。
今までどおり歌って、演技をしていきたい。
- 水樹奈々さん。既存のクラス。
- Target(KohakuProtocol)
- 紅白歌合戦に出場するために実装しなければならないinterface。
kohaku()
が定義されている。
- 紅白歌合戦に出場するために実装しなければならないinterface。
- Adapter(NanaMizuki)
kohaku()
を実装した水樹奈々さん。
実装(Playground)
// Adaptee class MizukiNana { func perform() { print("演技する") } func sing() { print("歌う") } } // Target protocol KohakuProtocol { func kohaku() } // Adapter class KohakuNana: MizukiNana, KohakuProtocol { override func perform() { print("普段の水樹奈々の演技") } func kohaku() { super.sing() } } let nana = KohakuNana() nana.perform() nana.kohaku()
結果
無事、奈々さんは普段通り演技もできて、紅白に出場するためのinterfaceを実装することができた。
感想
今回はkohaku()
の中身がsing()
をラッピングするだけの形になり、ただ単にメソッド名が変わっただけになった。
collaboWithNishikawa()
みたいな他の機能も追加したくなった場合、どう実装していくのか調査していきたいです。
swiftでデザインパターンを実装(Iteratorパターン)
今回はIteratorパターンを実装します
参考: (株)オージス総研「事例で学ぶデザインパターン 第2回 Iteratorパターンの適用例を見て学ぼう」
参考: developers.IO 「[iOS 8] Swiftでデザインパターン No.2 Iterator」
Element
class Song { private var name: String init (name: String) { self.name = name } }
Aggreate
class Aggregate { func iterator() -> Iterator { fatalError("サブクラスで使ってね") } }
Iterator
class Iterator { func next() -> AnyObject { fatalError("サブクラスで使ってね") } func hasNext() -> Bool{ fatalError("サブクラスで使ってね") } }
ConcreateIterator
class SongIterator: Iterator { private var songAggregate: SongAggregate private var index = 0 init(songAgregate: SongAggregate) { self.songAggregate = songAgregate } override func next() -> AnyObject { return songAggregate.songAtIndex(index++) } override func hasNext() -> Bool { return songAggregate.countOfSongs() > index } }
ConcreateAggregate
class SongAggregate: Aggregate { private var songs = [Song]() override func iterator() -> Iterator { return SongIterator(songAgregate: self) } func addSong(song: Song) { songs.append(song) } func countOfSongs() -> Int { return songs.count } func songAtIndex(index: Int) -> Song { return songs[index] } }
使い方
var songAggregate = SongAggregate() songAggregate.addSong(Song(name: "POP MASTER")) songAggregate.addSong(Song(name: "ETERNAL BLAZE")) songAggregate.addSong(Song(name: "DISCOTIQUE")) let songIterator = songAggregate.iterator() while songIterator.hasNext() { let song = songIterator.next() as! Song print(song.name) }
swift固有の書き方
- SequenceTypeとGeneratorTypeを用いた実装方法があるみたいなので今度実装してみたいと思います。
感想
Iteratorを挟むことによって、Controller側がElement(Model)のことを気にせずにアクセスできています。 Modelに変更があった場合、Contorollerへの影響が少なくて済むのではないでしょうか Iteratorパターンが使われているOSSも探してみたいと思います。
swiftでデザインパターンを実装
デザインパターンって何
今回はシングルトンを実装、シングルトンとは?
- 今回はシングルトンパターンを実装していきます。
- シングルトンとはアプリ内でクラスのインスタンスを1つしか生成できないようにし、そのインスタンスに対してアプリのどこからでも参照できるようにする設計手法です。
シングルトンのコード
- シングルトンが管理するModel
class Song { var name: String var time: Int init(name: String, time: Int) { self.name = name self.time = time } }
- シングルトンのMizukiNanaクラスの実装
class SingletonMizukiNana { static let sharedInstance = SingletonMizukiNana() var songs: [Song] private init() { songs = [] } }
- 使い方
let nana = SingletonMizukiNana.sharedInstance nana.songs.append(Song(name: "POP MASTER", time: 240))
- モダンな書き方
class Singleton { static let sharedInstance: Singleton = { let instance = Singleton() // ここで初期値セットアップのコードを書きます。 return instance }() }