toshiのエンジニア日記

できるエンジニアを目指して勉強した内容を日々まとめていきます。

GridLayoutに動的にImageViewを生成して割り当てる(Android Studio 3.0.1、Kotlin)

等間隔のグリッド上にViewを配置できるLayoutとして、GridLayoutがあります。

GridLayoutに対して静的に要素を割り当てる方法(xmlに直接記入する方法)はWeb上で多く紹介されていましたが、動的に生成して割り当てる方法がわかりづらかったのでまとめます。

動的割り当て方法

以下のようにして、動的にImageViewを生成して割り当てることができます(GridLayoutのIDはtestGridLayout)。

for(i in 0..(testGridLayout.rowCount - 1)) {
    for(j in 0..(testGridLayout.columnCount - 1)) {
        // ImageViewの生成
        val imgview = ImageView(this)
        // GridLayout用のパラメータを設定
        val params = GridLayout.LayoutParams()
        params.width = 256
        params.height = 256
        params.rowSpec = GridLayout.spec(i)
        params.columnSpec = GridLayout.spec(j)
        imgview.setLayoutParams(params)
        // ImageViewへ画像を設定
        imgview.setImageResource(R.drawable.smartphone_app)
        // GridLayoutへImageViewを割り当て
        testGridLayout.addView(imgview)
    }
}

ポイントは、paramsというパラメータを設定するための変数を生成して、ImageViewに与えている点です。

実行結果

4*5のGridLayoutに動的割り当てを行った結果を示します。

f:id:ntoshi1900:20180121221528p:plain

生成できています。

画像ファイルをインポートする(Android Studio 3.0.1、Kotlin)

画像ファイルのインポート方法がわかりづらかったのでまとめます。

やりたいこと

アプリ上で使えるように画像ファイルをインポートしたい。

drawableフォルダの中にある画像がリソースとして扱われるが、直接drawableフォルダに画像突っ込んで使うとエラー吐く。

インポート方法

1.インポートしたい画像をクリップボードにコピー(ファイル選択してCtrl+CでOK)

2.Hierarchy Viewからdrawableフォルダ選択して貼り付け

3.いろいろウィンドウ出てくるので、基本OKで

f:id:ntoshi1900:20180121214007p:plain

インポートした画像ファイルを使う(Kotlin上)

コードから画像ファイルにアクセスする例として、ImageViewに画像を設定するコードを以下に示します。

imgview.setImageResource(R.drawable.smartphone_app)

このコードで、imgviewというImageViewに、smartphone_appという名前でインポートした画像が設定されます。

R.drawable.smartphone_app自体はリソースのインデックスを示しているため、型がIntであることに注意です。

アプリのタイトルバーを消す(Android Studio 3.0.1)

アプリのタイトルバーを消すのに少し苦戦したので、やり方をメモします。

消す対象

アプリ実行画面の上部に表示される青い帯状のタイトルバーです。

f:id:ntoshi1900:20180121210007p:plain

Web上ではandroidmanifest.xmlandroid:themeをタイトルバーなしのものに変える方法などが紹介されていますが、現行バージョンではRun時にクラッシュしてしまい、うまくいきませんでした。

消す方法

styles.xmlにタイトルバーを消すための設定を追加します。

styles.xmlはHierarchy Viewerから開けます。

f:id:ntoshi1900:20180121211910p:plain

styles.xmlに以下の設定を追記します。

<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>

styles.xmlは以下のようになります。

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>

        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>

</resources>

結果

消えました。

f:id:ntoshi1900:20180121212349p:plain

WindowsのAndroid StudioでKotlinを学ぶ - 導入編

こんにちは。 雑魚エンジニアToshiです。

先日Androidアプリをリリースしましたが、もっとちゃんと「Androidアプリ開発できます!」ってアピールするために、最近Android界隈で話題のKotlinを勉強してみることにしました。

本記事では、Windows上でのKotlinの導入手順などをまとめます。

なお、学習には日本Kotlinユーザグループが無料で公開してくださっている「Kotlin助走読本」を活用させていただく予定です。

kotlin-prior-learning-book.pdf - Google ドライブ

Android Studioのインストール

ここから、Windows用のAndroid Studioがインストールできます。

ダウンロードが完了すると、自動的にインストール手順を説明したページに遷移します。

説明にしたがって設定を行いましょう(まぁウィザードでぽちぽちするだけですが)。

Java環境の構築

Javaのインストールと設定をしましょう。

以下のTechAcademyの記事に従うと良いです。

Androidアプリの開発環境構築方法(Windows編)【初心者向け】 | TechAcademyマガジン

Kotlinプラグインのインストール

助走読本ではプラグインの導入に関して記述されていますが、Android Studio 3.0 以降のバージョンでは、最初からKotlinが導入されているようです。

新規プロジェクトの生成時に、ウィザード上で「Include Kotlin support」というチェックボックスにチェックをすればOKです。

Kotlinプロジェクトのつくり方などは以下の記事が参考になりました。

employment.en-japan.com

おわりに

以上で、KotlinでAndroidアプリ開発を行う環境構築ができました。

今後は、助走読本をベースにKotlinの勉強を進めていく予定です。

今年度中くらいに、Kotlin製のクソアプリをリリースしたいなぁ。

Androidアプリリリースしてみた

f:id:ntoshi1900:20180110212912p:plain

こんにちは。雑魚エンジニアのtoshiです。

約一ヶ月前に記事で書いてたスマホアプリですが、ついにリリースできました!

play.google.com

クリスマスを満喫するリア充どもを、様々な嫌がらせアイテムを投げつけて撃退するゲームです!

クリスマス当日にリリースしてましたが、そこから正月モードに入ってしまい、記事にするのをすっかり怠っていました;

15分くらいで全クリできるいい感じのクソゲーなので、お時間あれば遊んでみてください。

以下、リリース申請時の注意点などをまとめておきます。

Google Play Developer への登録

Androidアプリをリリースするためには、事前にGoogle Play Developer への登録が必要です。

以下のURLから登録申請が行えます。

https://play.google.com/apps/publish/signup/

登録には25ドルかかるので、事前にクレジットカード等を用意しておきましょう。

また、登録時にはポップアップが出てくるので、スマホからでは登録できません。PCから登録申請を行いましょう。

登録完了まで最大 48 時間かかるとのことですが、私はすぐに登録完了しました。

apkファイルの作成

Androidアプリをリリースする場合、もろもろのアプリ設定のほかに、Keystoreというデジタル署名用のファイルの生成が必要になります。

Unity上での生成の方法などは以下の記事が参考になります。

halcyonsystemblog.blog.fc2.com

Keystoreを紛失するとアプリのアップデート等ができなくなるそうなので、気をつけて管理しましょう。

ストアの掲載情報の入力

ストア上で表示されるもろもろの設定を行います。

f:id:ntoshi1900:20180110230613p:plain
アプリ一覧画面に表示される情報
f:id:ntoshi1900:20180110230607p:plain
アプリ詳細画面に表示される情報
f:id:ntoshi1900:20180110230602p:plain
アプリ詳細画面の下のほうに表示される情報

タイトル

アプリの顔、タイトルを入力します。

スマホでPlayストアを確認すると、アプリ一覧の画面ではタイトルの最初の全角20文字程度が見えるので、最初の20文字でゲームの内容が推測できるようにするといいかと思われます。

簡単な説明

かなり重要な項目です。

アプリをキーワードで検索したときに出てくるアプリ一覧画面では、タイトルとスクリーンショットのサムネイルと、この簡単な説明のみが表示されます。

基本的に、ここだけでアプリの魅力を伝えなければいけません。

最大全角80文字と限られた情報しか入力できないので、アプリの一番売りとなる内容を記述するようにしましょう。

ちなみに、改行を入れてしまうとアプリ一覧画面で1行目しか表示できなくなるようなので、1行で記述するようにするといいでしょう。

詳細な説明

実はあんまり優先度は高くないです。

というのも、スマホではアプリの詳細画面からさらに「詳細はこちら」というリンクをクリックしないと見えない部分だからです。

簡単な説明で記入したこと以外に伝えたいことがあれば記述すると良いと思います。

簡単な操作説明や、フリー素材のクレジット表記などを含めることが多いようです。

スクリーンショット

おそらく最も重要な項目になります。

アプリ一覧にも表示され、アプリの雰囲気をつかむために最も利用されるソースだと思います。 スクリーンショットで「面白そう!」と思わせれば勝ちです。

ゲーム画面に加えて、簡単な説明を付加した画像を生成するとわかりやすくていい感じです。

また細かいところになりますが、実際にゲームのプレイ中にいい感じのスクリーンショットを取るのは意外と難しかったりします。

スクリーンショット作成用の、敵とか弾とかが静止しているシーンを別途作成すると、楽でいい感じでした。

高解像度アイコン

タイトルと並ぶアプリの顔ですね。

アプリ自体に設定したアイコンと同じものを使うといいと思います。

ただ、512×512と、アイコンにしては本当に高解像度なので、Unity上でアイコンを設定する際も、512×512のアイコンをベースに作成するといいでしょう。

ヘッダー画像

これが意外と重要。

スマホでアプリの詳細画面を開いたときに、一番上にドーンと鎮座しています。 詳細を開いたときに一番最初に目にする部分なので、ここでインパクトを残せると大きいと思います。

プロモーション画像

これは良くわかりませんが、Google Play Store でオススメのアプリとして紹介されたときに表示される画像だそうです。

必須項目ではないですが、一応設定しておくとよいでしょう。

ちなみに私は面倒だったのでヘッダー画像を圧縮したやつを使いました。

プロモーション動画

Youtube上でのアプリ宣伝用の動画を載せられるみたいです。

本気でユーザ獲得を狙う場合は重要になるかもしれません。

ちなみに私はもちろん登録していません 笑

まとめ

Androidアプリのリリース作業は結構面倒くさい。

特に画像作成系が多いので、わりと時間とられます。

だけど、実際に自分の作品が世に出ることは、やっぱりうれしい!

できるだけ多くのプレイヤーにやってもらえるといいなーと願っております(まぁ紹介サイトに書くとかプロモーションなんもやってないので今回は厳しそうですが・・・)。

とりあえず一通りアプリ作成の手順はわかったので、今度はちゃんと面白いといえるゲームを作成していきたいです!

リモートもくもく会をやってみたらめっちゃ良かった

こんにちは、雑魚エンジニアのtoshiです。

最近、Unityを使ったスマホアプリ開発をはじめました!

もともとRPGツクールなんかを使ってちまちまとゲーム作りに励み、リアル友人たちにやってもらって喜んでいたのですが、どうせなら公開できるものを、と取り組み始めました。

ひとまず、評判のいい入門書として以下を購入、一通り実装してみました。

www.socym.co.jp

なにこれめっちゃ楽しい。NejikoRun超楽しい。

colliderなどの基礎をしっかり押さえた上でサンプルゲーム実装ができ、楽しく学べる良書でした。

さて、一通りサンプルアプリを作り終わったところで考えるのは、もちろんオリジナルゲーム!

……しかし、大きな壁が立ちはだかるのだった……!

やる気が出ない

設定を考え、ゲーム性を考え、さあ作るぞ!というとこまではいくのですが、いかんせんやる気が出ない。

のそのそと重い腰を上げ、コーディングを始めるのですが、クラスをひとつ作ったくらいで謎の達成感を覚え、気が付けばベッドで寝転びマンガを読んでいる。

いかん!これはいかん!いつまでたっても完成しない!!

そこで、開発をブーストするため、もくもく会というものを利用することにしました。

もくもく会とは?

f:id:ntoshi1900:20171127210420j:plain

もくもく会とは、共通の興味を持った人間がカフェやコラボレーティブスペースなどのひとつの場所に集まり、もくもくと作業をするという謎の会です。

決して、喫煙家が集まる不健康な会ではありません。

もくもく会のメリットとしては、

  • 人の目があるのでサボらない
  • 同じ興味の人が集まっているので分からないところがあったら質問できる
  • 成果発表を行うことで、目標感がある

などがあります。

とにかくサボってしまう私にとってはピッタリの会! ということで早速、Unity関連のもくもく会に参加してきました!

もくもく会参加の結果

結論から申し上げると、かなり作業は進みました

なにせサボれるベッドもないし、ちゃんと作業しないと「なんだあいつ」という冷たい視線が飛んでくる(という妄想)ので、サボることなく作業時間いっぱい開発ができました!

ただ。。。結構お金がかかる。

参加費自体は1000円程度で安かったのですが、東京までの交通費が結構かかる+外食で結構いいもの食べてしまう で、結果として6000円くらい吹っ飛んでいきました。

集中力は金で買えとも言うし、進み具合から言って損した気はしないのですが・・・頻繁に利用するにはちとお金が掛かりすぎる。

食費抑えろ?尤もな指摘ですが、難しい 笑

一日にかけたお金のうち、交通費が占める割合が高くなると、何か悔しくなっちゃうんですよね~ なので、せっかくだからといいものを食べ、結果お金がすっとんでいく・・・

そこで、何とかお金をかけずに開発をブーストできないかと考え、リモートもくもく会なるものを開催することにしました。

リモートもくもく会とは

f:id:ntoshi1900:20171127212949j:plain

もくもく会では物理的にひとつの場所に集まりますが、リモートもくもく会は音声通話やチャットアプリなどで、仮想的に集まります。

そのため、全員が自宅などで参加でき、交通費も移動時間もかけずに作業が開始できるというわけです。

取り合えずお試しということで、知り合いを4人ほど集め、Slack上で開催してみることにしました。

流れは以下のような感じです。

  1. 9:00 Slackにログイン。各自作業内容を宣言する。
  2. 9:00~12:30 各自作業。
  3. 12:30~13:00 各自休憩。お昼ごはんの内容と進捗状況を共有。
  4. 13:00~17:30 各自作業。
  5. 17:30~18:00 成果報告

仕事かっ!と突っ込みたくなるほどのガチ構成です(事前に参加者にアンケートとったらこのプランが一番人気だったんです・・・)笑

集中力が持つか心配でしたが、取り合えずものは試しということでこのプランでやってみることにしました。

その結果は・・・

めっちゃ良かった

すごい。すごい良かった。

まず「めんどくせ~」とかならずに、強制的に朝9時から作業が始められる。一番の壁である「やり始め」が超スムーズ。

さらに、報告会で報告する内容なくなったら困る、と思い、サボることもない。他の人にいい面するために必死こいてやる。

結果、めちゃくちゃ作業が進む!!しかも、無料!やばい!移動時間もなし!!何か無駄に豪勢な食事することもない!ステーキとか食べない!!

最高かよ・・・

ただし、いくつかリモートならではの問題点などもありました。

成果報告がちょっとグダグダ

成果報告もSlack上でチャットベースでやったのですが、成果報告のテンポが悪かったり、突然の来客でAFKしてなかなか戻ってこなかったりしました。

テンポに関しては、誰かが入力する → 待ってる間作業する → 作業しすぎて入力完了に気づくのが遅れる の連鎖で、かなりのグダグダ感。

チャットベースでリアルタイムで行うのは無謀でしたね・・・

あらかじめ入力して、各自読んでね!というスタイルにするか、成果報告だけでもSkype等で音声つなぐのが良さそうですね。

AFKに関しては、簡易でもいいので何か連絡してね、と取り決めるか、、、やっぱり音声つなぐのがいいですね。

個人的に作業中は音声つなぐ必要はないと思っているので、成果報告時のみ通話にするのが一番スマートにできる気がします。

作業内容が少し限定される節がある

今回、私はUnityのアプリ開発でしたが、他の方々は新しい分野を勉強をしている人もいました。

しかし、新規分野の勉強だと、「勉強しました!」くらいしかいうことがなく、成果報告時に報告する内容がほぼない、という状況に陥るようです。

デモシステムの構築くらいまで進めると成果として分かりやすいのですが、前準備なしに取り組むと基礎的な理論の理解だけで一日が終わってしまいます。

なので、成果報告でちゃんとモノを報告したい!となった場合には、新規分野をイチから学ぶのは少し厳しそうです。

あらかじめ基礎は理解して、実装部分をやる、等の工夫が必要そうです。

まあ、もくもく会なので、そこまで成果にこだわる必要はないとは思いますが・・・

まとめ

リモートもくもく会めっちゃ良い

この一言に限る。

ただし、成果報告は音声でやるのがオススメ。

あと新規分野やるときはある程度予習しとくのがオススメ。

以上!

とりあえずとてもとても素晴らしいので、

みなさんリモートもくもく会積極的にやりましょう

おまけ

リモートもくもく会で作ってたアプリを少し紹介します。

タイトル:Xmas Crusher ~リア充どものクリスマスを台無しにせよ!~

設定:寂しいクリボッチを味わう主人公。ついに我慢の限界を突破し、クリスマスを充実するリア充どもを殲滅するため、孤独な戦いに挑む!

f:id:ntoshi1900:20171128064021p:plain
タイトル画面。陰鬱な雰囲気が漂いますね・・・

f:id:ntoshi1900:20171128064937p:plain
戦闘画面。左右からワラワラとカップルが出てくるので様々なアイテムを投げつけて攻撃します

季節向けですが、完全なネタゲーです 笑

クリスマスまでに公開する予定なので、お楽しみに!

トランプ大統領と金正恩氏の類似度を潜在的意味解析で判定する その2

f:id:ntoshi1900:20171017202249p:plain 前回の記事では、wikipediaから各国の大統領の説明を取得しました。

今回は、このデータを使って潜在的意味解析を行い、トランプ大統領と金正恩氏の類似度を判定していきたいと思います。

以下の手順3からの再開です。

  1. wikipediaから各国の指導者一覧を取得
  2. 各国の指導者のwikipediaページから説明文を抽出
  3. 潜在的意味解析を用いて各指導者を潜在的空間に射影
  4. トランプ大統領と金正恩氏の類似度を判定する

3.潜在的意味解析で各指導者を潜在的空間に射影

まず、文書-単語行列を作成するために、RMeCabパッケージを使用できるようにします。

RMeCabのインストールは以下のページなどを参考にしてください。

RMeCab - RとLinuxと...

注意点としては、MeCabそのものもインストールを忘れないようにしてください。 RMeCabパッケージだけインストールして使用しようとすると、RStudioがエラー落ちしてしまいます。

さて、RMeCabが使えるようになったら、以下のコードで各指導者の文書-単語行列を作成します。

### 3. 潜在的意味解析を実行

# パッケージの読み込み
library("RMeCab")

## 各指導者の説明文から単語-文書行列を作成する

# 説明文が入ったファイルのあるディレクトリを指定
path.dir <- "./desc"

# 単語カウントの最低出現回数を指定
minF <- 2

# 単語-文書行列の作成(名詞と動詞と形容詞のみ使用)
# 重みとしてtf-idfを用い,正規化した値を出力する
docterm <- docMatrix(path.dir, minFreq=minF, 
                     pos = c("名詞", "形容詞"), weight = "tf*idf*norm")

# 先頭2行を削除
docterm.cut <- docterm[-(1:2),]
# minF個以上の文書にある語句のみピックアップ
docterm.select <- docterm.cut[which(apply(docterm.cut, 1, function(x) sum(x > 0) ) >= minF), ]

docMatrix関数でファイルの格納されたフォルダのパスを指定することで、文書-単語行列が生成されます。pos引数で使用する品詞を選択できるのですが、今回は名詞と形容詞のみを使用することとします。

また、weight引数で単語の重み付けのオプションを指定できます。今回はTF-IDFと正規化を指定しています。

TF-IDFは文書内での出現頻度と全体での出現頻度の割合を用いて、全体ではあまり出現しないが、特定の文書にだけ頻出する語句の重みを高くする手法です。これにより、文書をより特徴付ける単語の数値を大きくすることができます。

さて、得られた単語-文書行列の次元と、マトリクスの一部を確認してみましょう。

# 次元の確認
dim(docterm.select

# いくつか要素のの確認
print(docterm.select[1:10, 1:2])
> dim(docterm.select)
[1] 2341  273
> print(docterm.select[1:10, 1:2])
      docs
terms  アイスランド 首相 ビャルニ・ベネディクトソン.txt アイスランド 大統領 グズニ・ヨハンネソン.txt
  こと                                       0.06853151                                   0.03073494
  回復                                       0.18593731                                   0.00000000
  獲得                                       0.13186948                                   0.00000000
  議席                                       0.20001793                                   0.00000000
  月                                         0.09031433                                   0.01620163
  後                                         0.09847178                                   0.00000000
  首相                                       0.09794949                                   0.00000000
  進歩                                       0.36285404                                   0.00000000
  政権                                       0.08484629                                   0.00000000
  選挙                                       0.12390810                                   0.01852339

273個の文書に対し、2341種類の単語が存在していることがわかります。 また、各文書に対して単語が関連付けられていることが確認できます。「こと」や「月」などのどの文書にも含まれそうな単語が入っていますが、TF-IDFの効果もあり、重みは小さめになっていますね。

それでは、この文書-単語行列をSVDで低ランク近似しましょう。

## svdによる低ランク近似を実行
# 特異値の累積和が何割にいくまでを残すかのパラメータ
d.base <- 0.5

# svdを実行
svd.docterm <- svd(docterm.select)
# 低ランク近似
index <- which(cumsum(svd.docterm$d / sum(svd.docterm$d)) <= d.base)
svd.docterm.low <- NULL
svd.docterm.low$u <- svd.docterm$u[, index]
svd.docterm.low$v <- svd.docterm$v[, index]
svd.docterm.low$d <- svd.docterm$d[index]
rownames(svd.docterm.low$u) <- rownames(docterm.select)
rownames(svd.docterm.low$v) <- colnames(docterm.select)

SVDによる低ランク近似では、特異値の大きさが擬似的に潜在トピックの重要度を表すため、特異値の低いものは価値の低い潜在トピックとし、行列から取り除きます。 ここでは、どれくらいまで次元を落とすかという基準に、特異値の累積和が特異値全体の何割に到達するまでを残すかという基準を用います。

この値はハイパーパラメータになるため、本来は最適化すべき項目ですが、取り合えず0.5でやってみました。

では、低ランク近似後の行列の次元を確認してみましょう。

# 次元の確認
dim(svd.docterm.low$v)
> dim(svd.docterm.low$v)
[1] 273  82

2341次元あった単語ベクトルが、82次元まで削減できていますね。

では、この低ランク行列を保存して、余計な変数を削除しておきましょう。

# 低ランク行列の保存
save(svd.docterm.low, file="./svd_docterm_low.Rdata")

# 要らない変数を削除
rm(list=ls())
gc(); gc();

4.トランプ大統領と金正恩氏の類似度を判定する

ではついに!本題のトランプ大統領と金正恩氏の類似度を判定して見ましょう!

まずは、任意の2文書の全ての組み合わせでcosine類似度を計算します。

### 4. トランプ大統領と金正恩総書記の類似度を計算する

# 低ランク行列の読み込み
load("./svd_docterm_low.Rdata")

# cosine類似度の計算
mat.v <- t(svd.docterm.low$v)
matrix.cos <- apply(mat.v, 2, function(x){
  apply(mat.v, 2, function(y){
    crossprod(x, y) / (sqrt(crossprod(x) * crossprod(y)))
  })
})
diag(matrix.cos) <- NaN

これで、任意の組の類似度が得られるようになりました。

では、トランプ大統領と金正恩氏の類似度を出力してみましょう!

# トランプ大統領の番号を取得
index.trump <- which(rownames(svd.docterm.low$v) == "アメリカ合衆国 大統領 ドナルド・トランプ.txt")

# 金正恩総書記の番号を取得
index.kim <- which(rownames(svd.docterm.low$v) == "北朝鮮 朝鮮労働党委員長 金正恩.txt")

# トランプ大統領と金正恩総書記の類似度を出力
cat(matrix.cos[index.trump, index.kim])
> cat(matrix.cos[index.trump, index.kim])
0.05124007

んー、微妙ですね。

似ていない場合はマイナスの値をとるため、似ていないこともない、といったところでしょうか……

数値だけだとよくわからないので、トランプ類似度偏差値を求めてみます。

# トランプ大統領の類似度偏差値を計算
cos.trump <- matrix.cos[index.trump, ]
dev.trump <- (cos.trump - mean(cos.trump[-index.trump])) / sd(cos.trump[-index.trump]) * 10 + 50

# 金正恩総書記のトランプ偏差値を表示
print(dev.trump[index.kim])

# 金正恩総書記のトランプ順位の表示
trump.order <- dev.trump[order(-dev.trump)]
which(names(trump.order) == "北朝鮮 朝鮮労働党委員長 金正恩.txt")
> print(dev.trump[index.kim])
北朝鮮 朝鮮労働党委員長 金正恩.txt 
                          53.88065 
> which(names(trump.order) == "北朝鮮 朝鮮労働党委員長 金正恩.txt")
[1] 58

偏差値53.88……。とっても微妙ですね。

順位は273人中58位。悪くはないですが……期待したほどではない結果です。

では、トランプ大統領に最も似た指導者はいったい誰なのでしょうか?出力してみましょう。

# トランプ偏差値上位10人表示
print(trump.order[1:10])
> print(trump.order[1:10])
    フィリピン 大統領 ロドリゴ・ドゥテルテ.txt       パラグアイ 大統領 オラシオ・カルテス.txt 
                                     129.29781                                       94.31164 
                        韓国 大統領 文在寅.txt             ボツワナ 大統領 イアン・カーマ.txt 
                                      88.77724                                       84.07969 
      ベネズエラ 大統領 ニコラス・マドゥロ.txt キプロス 大統領 ニコス・アナスタシアディス.txt 
                                      77.19171                                       76.18902 
                バチカン 教皇 フランシスコ.txt                 日本 内閣総理大臣 安倍晋三.txt 
                                      73.40518                                       73.26178 
        ジンバブエ 大統領 ロバート・ムガベ.txt         カナダ 首相 ジャスティン・トルドー.txt 
                                      72.60202                                       71.23118 

なんと……類似度1位はフィリピンのドゥテルテ大統領で、なんとその偏差値129!!

大学受験とかで考えたらとんでもない化け物ですね!

そんなに似ているのか……とドゥテルテ大統領wikipediaページを見てみると、以下のような記述がありました。

選挙戦中は、同時期に進行していたアメリカ大統領選挙に立候補する共和党候補者を選出する予備選挙で過激な発言を行う人物として注目されていた共和党ドナルド・トランプになぞらえ、「フィリピンのトランプ」とも揶揄された。

まんま記述があるじゃないですか!

おそらく、この「トランプ」という単語とか、「大統領」という単語などが共通しているため、類似度が高くなったようですね。

それぞれの文書を特徴付ける上位10単語を確認してみましょう。

## 各指導者をもっとも特徴付ける単語を調べる

# 全指導者の文書-単語行列を低ランク行列で再現
docterm.app <- svd.docterm.low$u %*% diag(svd.docterm.low$d) %*% t(svd.docterm.low$v)

# トランプ大統領をもっとも特徴付ける単語を取得
term.trump <- docterm.app[,index.trump]

# トランプ偏差値トップの人をもっとも特徴付ける単語を取得
index.toptrumper <- which(rownames(svd.docterm.low$v) == names(trump.order)[1])
term.toptrumper <- docterm.app[,index.toptrumper]

# それぞれの特徴語の表示
print(term.trump[order(-term.trump)][1:10])
print(term.toptrumper[order(-term.toptrumper)][1:10])
> print(term.trump[order(-term.trump)][1:10])
  トランプ       中国     北朝鮮       こと       発言 フィリピン         者       米国     大統領         人 
0.34969567 0.20357833 0.17085699 0.13165502 0.12459490 0.10411936 0.10155474 0.09888835 0.09590375 0.09159767 
> print(term.toptrumper[order(-term.toptrumper)][1:10])
      中国   トランプ     大統領     北朝鮮         年 フィリピン       依存       発言       こと       政策 
0.18541337 0.15940956 0.11098858 0.08911449 0.07826024 0.07240096 0.06509865 0.06227812 0.06085533 0.05706989 

やはり、トランプ、大統領、といった単語が含まれていますね。

他には、中国、北朝鮮、といった単語が共通して出ており、体外的な交渉相手などが似ているということでしょうか。

まぁここに関しては、日本のwikipediaを解析しているため、日本から見た動きが記載されやすい、というバイアスは大きく受けている気はします。

実際に似ているかはともかく、日本から見た影響力の大きさ、という点では似ているのかもしれませんね。

おまけ:理想の指導者を探してみる

潜在的意味解析の面白いところは、文書の検索もできるところです。

任意の文書をクエリとして与え、そこに含まれる単語を潜在意味空間に射影することで、文書との距離を計算できるようになります。

では実際に、理想の指導者に最も類似する指導者を探してみましょう。

まずは、クエリを与えると、それに最も近い5つの文書を返す関数を定義しましょう。

## 理想の指導者を探してみる

# 理想の指導者検索関数の設定
searchLeader <- function(query, docterm){
  
  # 長さ1の文字列のみ受付
  if(mode(query) != "character") return(NULL)
  if(length(query) > 1) return(NULL)
  
  # 形態素解析
  query.term <- RMeCabC(query) %>% unlist()
  
  # 動詞,形容詞だけ取り出す
  query.term <- query.term[names(query.term) %in% c("名詞", "形容詞")]
  
  # 文書-単語行列に含まれるもののみを取り出し,ベクトルを生成
  term.list <- matrix(0, nrow=nrow(docterm$u))
  rownames(term.list) <- rownames(docterm$u)
  term.list[rownames(term.list) %in% query.term] <- 1
  
  # 使用される単語を確認
  cat("Using terms:\n")
  print(term.list[which(term.list[,1] == 1), ])
  
  # 文書-単語行列に全く一致する単語がない場合はNULLを返す
  if(sum(term.list) == 0) return(NULL)
  
  # 潜在意味空間中での質問文ベクトルを計算
  query.vec <- t(term.list) %*% docterm$u %*% solve(diag(docterm$d))
  query.vec <- as.vector(query.vec)
  
  # 潜在意味空間中でのcosine類似度を計算
  mat.v <- t(docterm$v)
  query.cos <- apply(mat.v, 2, function(x){
    crossprod(x, query.vec) / (sqrt(crossprod(x) * crossprod(query.vec)))
  })
  rank.leader <- round(sort(query.cos,de=T),3)
  
  return(rank.leader[1:5])
}

では、この関数を使用して、理想の指導者を探してみましょう。

以下のようなクエリを与えてみます。

# 指導者検索してみる
query <- "効果的な政策を実現することができ,経済の発展に貢献し,人々から賞賛され,尊敬を集める"

これが理想的な指導者かどうかは微妙ですが、すばらしい人物には違いないですね!

では検索してみましょう!

res <- searchLeader(query, svd.docterm.low)
print(res)
> res <- searchLeader(query, svd.docterm.low)
Using terms:
こと   的 経済 効果 貢献 実現 人々 政策 尊敬 発展 
   1    1    1    1    1    1    1    1    1    1 
> print(res)
  スリランカ 大統領 マイトリーパーラ・シリセーナ.txt     ジョージア 首相 ギオルギ・クヴィリカシヴィリ.txt 
                                               0.477                                                0.427 
ジョージア 大統領 ギオルギ・マルグヴェラシヴィリ.txt             インドネシア 大統領 ジョコ・ウィドド.txt 
                                               0.377                                                0.372 
    コスタリカ 大統領 ルイス・ギジェルモ・ソリス.txt 
                                               0.328 

スリランカの大統領が一番該当すると出てきました。

ちょっとどんな人物か良くわからないので、wikipediaページを見てみましょう。

マイトリーパーラ・シリセーナ - Wikipedia

んー、特別クエリに該当しているようには思えないんですが……

取り合えず文章が短めなので、出現する単語の種類が少なくなり、「政策」とか単語の重みが強くなったんでしょうか。

試しにほかのクエリでもやって見ます。

query <- "親日で日本が大好きで友好的"
res <- searchLeader(query, svd.docterm.low)
print(res)
> res <- searchLeader(query, svd.docterm.low)
Using terms:
  的 日本 友好 
   1    1    1 
> print(res)
    シンガポール 首相 リー・シェンロン.txt     パラオ 大統領 トミー・レメンゲサウ.txt 
                                     0.914                                      0.475 
モルディブ 大統領 アブドゥラ・ヤミーン.txt             日本 内閣総理大臣 安倍晋三.txt 
                                     0.457                                      0.320 
        ツバル 総督 イアコバ・イタレリ.txt 
                                     0.190 

最も親日な指導者はシンガポールの首相でした。

リーシェンロン首相はこんな人です。

リー・シェンロン - Wikipedia

うーん、また文章が短く、日本に関する記述が目立ちますね。

どうも、検索のような短いクエリと距離を計算すると、文書が短く、たまたまクエリに近い単語を含んでいる文書が上位に上がってきてしまうようです。

今回のような各文書に含まれる単語数が大きく違う場合は、一工夫必要そうです。

まとめ

今回は潜在的意味解析を用いて、トランプ大統領と金正日氏の類似度を判定してみました。

その結果、実はトランプ大統領が似ているのは金正日氏ではなく、ダントツでフィリピンのドゥテルテ大統領であることがわかりました(飽くまで今回の解析の結果です)。

今回は日本のwikipediaの文書を解析したため、日本の視点から見た行動、というバイアスのかかった結果になってしまいましたが、例えばTwitter上での指導者に対する意見を分析するなどすれば、世間からどう思われているかという点での類似度が計算できるかもしれません。

ちなみに潜在的意味解析の改良法で確率的潜在意味解析(PLSA)という手法もあるので、時間があれば勉強してみたいですね。