動画タグネットワーク分析を用いた...
-
Upload
yusuke-fukasawa -
Category
Entertainment & Humor
-
view
1.827 -
download
0
Transcript of 動画タグネットワーク分析を用いた...
動画タグネットワーク分析を用いたニコニコ動画における萌芽文化発見の試み~”ゆっくり関連タグ”を例として~
Yusuke Fukasawa(@fukka1225)2015/10/21
本スライドで用いたゆっくり霊夢などの画像はニコニ・コモンズ (nc105190)よりお借りしました
自己紹介Yusuke Fukasawa(@fukka1225)
東京大学大学院工学系研究科シス創・ TMI(副専攻 )の修士
普段は、はてなブックマークの大喜利を見ていたり ライターをしていたりします (http://credo.asia/author/yusuke/)
本業は経済現象に関するマルチエージェントシミュレーション
ニコニコ動画とはそれなりの付き合い (プレミアム会員 4年目 )
1.仮説や前提、先行研究の紹介前置きだよ!
前提昨今、ニコニコ動画はつまらなくなったと言われております
今まであった文化と今現在の大勢を占めている”ニコニコ動画的でない“文化 (ゲーム実況者のアイドル化現象など )のぶつかり合い
「マリオメーカー問題」という言葉も出来るほどに
そんなぶつかり合いなどないし、懐古厨が騒いでいるだけという意見ももちろんありますが、今回はニコニコ動画がかつて持っていた文化が廃れているのでは、という前提に立ちます
仮説これまでの文化が廃れつつあるならば、それに対して反発するのではなく今ある“ニコニコ的な文化”に注目することも大事なのでは
今回、“ニコニコ的な文化”として注目するのは“ゆっくり”
東方キャラクターはニコニコ動画との付き合いが長い投稿者の匿名性を保ちながらも、動画に分かりやすいモチー
フを与える重要な役割を果たしている
“ ゆっくり”文化を動画タグネットワークで俯瞰・分析するとともに、今はまだ文化として定着していないが、ネットワーク構造的に定着してもおかしくない文化を動画タグで見つけることを試みる
なぜ動画タグなのか? “ 動画タグ”とは、各動画に投稿者及び視聴者がその動画を表現するものとしてつける
だいたい動画タグを見れば内容が推測できる時もある
これらタグをノードとして捉えることでネットワークとして表現
各タグごとに平均再生回数やコメント数など動画に関する情報も取得できる
http://www.nicovideo.jp/watch/sm6857306 もはや歴史的資料となった「ごちうさ」第一羽
先行研究の紹介 _1大規模学術論文データの共著ネットワーク分析に基づく萌芽領域の中心研究者予測に関する研究 (東京大学 ,森純一郎 ,2015)
論文を一緒に書いたことがある人:共著者の関係をネットワーク上で表現し、そのネットワークを用いて萌芽領域の中心研究者を機械学習で予測する、というもの
???
なにいってるんだこいつ
先行研究の紹介 _2つまるところこんな感じだと思われる
著者A
著者B
著者C
著者D
著者G
著者F
著者H
著者E
著者I
1. 次数の大きいノードが影響力の高い研究者であると考えそれらを正例、次数の小さいノードを負例として考える
2. 機械学習で分類器を作成
3. 今はまだ共著者数が多くないが、ネットワークの構造指標的に次数が多くなるだろうと予測されるノード(研究者 )を抽出する
正例
負例
新たに見つけたノード
あくまでもイメージ図です
今回の手法 _1先行研究ではネットワークの次数を指標にトレーニングセットを作成していたが、今回の分析では「タグ毎の平均再生回数・コメント数・マイリスト数から計算されるランキングポイント」を指標とする
“ ランキングに近いほど文化として定着しているタグである”と考え、今回の分析で” まだそれほどランキングポイントを獲得できてはいないがネットワーク構造的にいつランキング入りするほど文化
として定着してもおかしくないタグ” を発掘したい
今回の手法 _2分類に用いる学習器には SVM(R:e1071パッケージ )を用いる
SVMの勉強も兼ねてます
ランダムフォレストで各種変数の重要度も一応計算しますが、今回はその結果を用いてパラメータを選別はしませんでした
分類器による結果をノード属性に反映し、 Gephi上で可視化して分析するところまでをゴールとしました
(参考 )Gephiとはなんぞや
(参考 )Gephiとはなんぞやグラフ形式ファイルから csvまで幅広く読み込んでネットワーク描写をしてくれるオープンソースソフトウェア
各種統計量もボタン一つで計算してくれます
“ グラフの Photoshop”とも呼ばれているそうな
重すぎて CPUがフィーンと鳴ります
Cytoscape派の方々ごめんなさい
2.SVMで使うデータセットのためネットワーク特徴量を求める
機械学習で分類する前の下準備!
データを集めてくるニコニコ動画スナップショット検索 APIで、”ゆっくり”を含むタグを持つ動画を取得します (http://github/dichika/niconico で公開されているラッパーを使用しました。 )
選んだタグは動画数が 1000以上あるものAPIの関係上、取得できるサイズは 100が限界でした。全部で 28個のタグで検索し、 2800個の動画情報を取得し、一つのデータへrequire(niconico)require(igraph)
# ゆっくりに関連したタグで検索をかけるs1<-getSearch(query = "ゆっくり実況プレイ ", size = 100, type = "tag")s2<-getSearch(query = “ゆっくり実況” , size = 100, type = “tag”)〜中略〜s27<-getSearch(query = "ホラーゆっくり実況 ", size = 100, type = "tag")s28<-getSearch(query = "ゆっくり生活 ", size = 100, type = "tag")
処理前のデータ
タグは空白区切り
ネットワーク形式へ _1このあとまとめてきた動画情報に含まれるタグの部分からタグの共起関係を抽出してグラフ表現に直さなくてはなりません
しかし、先ほどの状態から Rだけで処理を完結させる方法が思いつかなかったので再現性は保てませんがエクセルで処理を行いました
こういう要素列であれば、次のように変換することで隣接行列形式にすることが出来る関数を見つけましたので、それを利用します (a,b,c)
(b,c)(c)
1 1 10 1 10 0 1
処理後のデータ
seed.csvとしてこいつを保存します
ネットワーク形式へ _2この状態から次の関数 (https://
gist.github.com/peccu/4328957)で隣接行列形式に変換しますadjacency <- function(n){
## 出力行列の初期化mydata <- diag(0,length(colnames(n)))## 行,列に名前を付けるcolnames(mydata) <- colnames(n)rownames(mydata) <- colnames(n)## rは列番号for(r in 1:length(colnames(n))){## r行目に,縦方向に合計したものを代入
mydata[r,] <- colSums(## r列目が 1になっている行を対象にして
n[n[,r] == 1,])
}mydata
}関数使わせていただきましたありがとうございました
ネットワーク形式へ _3先ほどの関数を用いて変換し、 igraphの書き出し機能で Gephiで読み込めるフォーマット” gml”にします
わざわざ Gephiで計算させるのは、ネットワークオブジェクトはGephiで扱う癖が抜けないため
もっと Rと仲良くならねばなりません
seed<-read.csv("seed.csv",fileEncoding="cp932")
adj<-adjacency(seed)g <- graph.adjacency(adj,weighted=TRUE)write.graph(g,"taggraph.gml","gml")
多分 igraphで全部計算できましたね
各種統計量を計算するGephiではネットワーク分析に必要なほとんどの指標をすぐに計算できます
ローデータのままだと分析が難しいので次数が 9以下のノードは全て削除してから処理します
今回はネットワークの特徴量として特に選り好みすることなく全部計算してもらって、 csvを出力しました
タグごとに動画に基づく属性を与える吐き出された csvにはノードごとの統計量が付与されているので、ここに各タグごとの平均再生回数・コメント数・投稿日時・再生時間・マイリスト数を計算して新たに付与します
新たに付与した属性Gephiで計算したネットワーク統計量
3.SVMでの分類を試みる
作成したデータから分類器を作って分類させます!
トレーニングセット (学習・テスト )の作成_1
モデルを学習させるデータとその精度をテストするデータに分けないといけない
本当はチューニング用のデータもあるべきですが、 Rでモデルを作った後別データでチューニングする方法を知らないのです
(http://techlife.cookpad.com/entry/2015/09/30/170015)
今回トレーニングセットを選ぶのに用いた指標 :ランキング総合ポイント ランキング総合ポイント=(総合ポイント=再生数+(コメント数×補正値 )+マイリスト数×15)
補正値=(再生数+マイリスト数 )/(再生数+コメント数+マイリスト数 )
広告ポインヨは今回無視しています
トレーニングセット (学習・テスト )の作成_2
ランキング総合ポイントで上位 100、下位 100くらいになるようにデータを選別して半々に分けます
# 予め作成したノードリストを読み込むset<-read.csv(“taggraph_nodes.csv”,fileEncoding = “CP932”)#再生数などの情報は既にポイントで反映していると考え削除しておく。計算結果を最終的に setに貼って出力し Gephiでまた使うset1<-set[,c(-2,-3,-10,-17,-18,-19)]plus<-subset(set1,set1$Points>2.5*mean(set1$Points))minus<-subset(set1,set1$Points<0.05*mean(set1$Points))plus$culture<-as.factor(1)minus$culture<-as.factor(0)# チューニング用とテスト用に分けるplus1<-plus[c(1:47),]plus2<-plus[c(48:93),]minus1<-minus[c(1:46),]minus2<-minus[c(47:93),]learning<-data.frame(rbind(plus1,minus1))test<-data.frame(rbind(plus2,minus2))
実際には 100じゃなくて93ですが
トレーニングセット (学習・テスト )の作成_3
データ型をそれぞれ適したものにしつつ整形していきますApply型関数で一気にやるべきですほんとはHubと Authorityは値が同じだったので Authorityのみ残します
# 日付型は使えないので numericに。あと、 Hubは削除。set1$ave_starttime<-as.numeric(set1$ave_starttime)set1$Authority<-as.numeric(set1$Authority)learning1<-learning[,c(-1,-5,-16)]learning1$ave_starttime<-as.numeric(learning1$ave_starttime)learning1$Authority<-as.numeric(learning1$Authority)test1<-test[,c(-1,-5,-16)]test1$ave_starttime<-as.numeric(test1$ave_starttime)test1$Authority<-as.numeric(test1$Authority)
分類器の作成
# SVMによる学習とチューニングを行いますpresvm<-svm(culture~.,learning1,cross=8)summary(presvm)
Parameters:## SVM-Type: C-classification ## SVM-Kernel: radial ## cost: 1 ## gamma: 0.07692308 ## Number of Support Vectors: 52## ( 26 26 )## Number of Classes: 2 ## Levels: ## 1 0## 8-fold cross-validation on training data:## Total Accuracy: 84.04255 ## Single Accuracies:## 81.81818 83.33333 100 83.33333 63.63636 91.66667 91.66667 75
分類器のチューニング _1
# ここからはチューニング。一回目。gammaRange = 10^(-5:5)costRange = 10^(-2:2)t <- tune.svm(culture ~ ., data = learning1, gamma=gammaRange, cost=costRange, tunecontrol = tune.control(sampling="cross", cross=8))cat(“- best parameters:\n”)
cat("gamma =", t$best.parameters$gamma, "; cost =", t$best.parameters$cost, ";\n")cat("accuracy:", 100 - t$best.performance * 100, "%\n\n")
plot(t, transform.x=log10, transform.y=log10)
分類器のチューニング _2
ベストパラメータはcost=10^2,gamma=10^(-
2)で正解率が 90.43561%でした
分類器のチューニング _3#二回目のチューニング。色が濃いところにグリッドサーチを絞るgamma <- 10^(-1)cost <- 10^(1)gammaRange <- 10^seq(log10(gamma)-1,log10(gamma)+1,length=11)[2:10]costRange <- 10^seq(log10(cost)-1 ,log10(cost)+1 ,length=11)[2:10]t <- tune.svm(Species ~ ., data = iris, gamma=gammaRange, cost=costRange, tunecontrol = tune.control(sampling="cross", cross=8))cat("gamma =", t$best.parameters$gamma, "; cost =", t$best.parameters$cost, ";\n")
cat("accuracy:", 100 - t$best.performance * 100, "%\n\n")
plot(t, transform.x=log10, transform.y=log10)
分類器のチューニング _4
ベストパラメータはcost= 6.309573,gamma= 0.03981072で正解率が 97.36842 %でした→過学習気味?
分類器のチューニング _5何はともあれ高い値を出しているので、こいつでいくことにテストデータで精度を確認する精度は低いが…今回は結局このまま突っ走りましたgamma <- t$best.parameters$gammacost <- t$best.parameters$costmodel <- svm(culture ~ ., data = learning1, gamma=gamma, cost=cost,probability = TRUE)#テストデータで精度を確認するpred <- predict(model, test1)table(pred, test1[,14])
pred 1 0## 1 34 12## 0 13 33
うわっ…私の学習器の精度低すぎ (約 72%)…?
低いです
ノード属性に確率を与えて csvで吐き出す
トレーニングセットに使ったものにはフラグをつけて可視化の際に邪魔にならないよう確率を 0にしました
(参考 )ランダムフォレストで算出した各変数の重要度 _1
ランダムフォレストで計算できる特徴量の重要度 (ジニ係数減少量 )を求めてみます
# 蛇足だとは思いますが一応チューニングtuneRF(learning1[,-14],learning1[,14],doBest=T)
決定木の分割する木の数を最適化しています
(参考 )ランダムフォレストで算出した各変数の重要度 _2
mtry=6が最適らしいので
# mtry=6が最適な模様importance<-randomForest(culture~.,learning1,mtry=6,importance = TRUE)knitr::kable(importance(importance))
ggplot2で横棒グラフにしてみました
(参考 )ランダムフォレストで算出した各変数の重要度 _3
平均動画時間の圧倒的強さ
4.結果の確認いろいろな見方で結果を確認してまいります!
色々な対応で散布図を描いてみる _1
次数
…
色々な対応で散布図を描いてみる _2
……
色々な対応で散布図を描いてみる _3
やはり重要度が低い特徴量には殆ど関連性が見えない
色々な対応で散布図を描いてみる _4
ネットワーク特徴量として最も重要度が大きかった固有ベクトル中心性でもこの程度である
色々な対応で散布図を描いてみる _5
ランキング総合ポイントで分類器を作っているので当然ですが動画メタ情報はそれなりに反応します
色々な対応で散布図を描いてみる _6
色々な対応で散布図を描いてみる _7
マイリストと確率との相関性が薄かったのが意外なところ前二つに比べて回帰直線が見えにくいです
色々な対応で散布図を描いてみる _8
動画平均再生時間はランキング総合ポイントとは関係なかったのに非常に相関性が強いのは何故なんだ
色々な対応で散布図を描いてみる _9
平均動画投稿日時とは関係がなさそう
Gephiで見る動画タグネットワーク _1出来上がった動画タグネットワークを見ていくコーナー
Modurarity Classで分割してみていきます
全体図ですが何が何やらですね
Gephiで見る動画タグネットワーク _2コミュニティ 1…ゲーム実況
“ ゲーム”や“ゆっくり実況プレイ”などのタグが多く含まれるコミュニティ
Gephiで見る動画タグネットワーク _3コミュニティ 2…東方
ゆっくり霊夢などの元ネタだが、それでもゲーム実況コミュニティよりは小さい
Gephiで見る動画タグネットワーク _4コミュニティ 3…ゆっくり・解説系
独立したキャラクターとしてゆっくり霊夢などを扱うタグ科学系と結びつきが強いというかグループ分けが難しい
Gephiで見る動画タグネットワーク _5コミュニティ 4…科学系
科学系の動画ではゆっくり霊夢などで解説を読み上げる場合が多い
Gephiで見る動画タグネットワーク _6コミュニティ 5,6…歌うゆっくりシリーズ
ゆっくりに歌わせたりVOCALOIDと一緒に歌っていたりなど
Gephiで見る動画タグネットワーク _7コミュニティ 7…料理動画
ゆっくり料理動画のコミュニティ “てってってー”があったりします
Gephiで見る動画タグネットワーク _8コミュニティ 8…その他のタグ
その他のカテゴリを問わないタグは大きいネットワーク周辺に存在している模様
Gephiでネットワークが成長する様子を見てみよう _1
2008年〜
最初は特に大きな繋がりはない状態です
Gephiでネットワークが成長する様子を見てみよう _2
2009年〜 2010年ごろ
東方コミュニティが出現します
東方コミュニティ
Gephiでネットワークが成長する様子を見てみよう _3
2012年ごろまで
東方コミュニティの周辺あたりでネットワークが成長
実況系のコミュニティ自体は既にあるがまだ東方コミュニティの周辺でしかなかった
科学系コミュニティ歌に関連するコミュニティ
“ ゆっくり・解説”コミュニティ
Gephiでネットワークが成長する様子を見てみよう _4
2012年を超えるあたりから
実況コミュニティが急速に成長します
さながらビッグバンのような成長ぶり
Gephiでネットワークが成長する様子を見てみよう _5
〜 2015年
ゲーム実況の急速な成長以降大きな変化はない模様
Gephiでネットワークが成長する様子を見てみよう
まず 2009年から 2010年にかけて「東方」コミュニティが出現
その後、周辺のコミュニティとして「歌うゆっくり」や「その他タグ」が成長していく
2012年ごろから「ゲーム実況コミュニティ」が急速に大きくなり、他を飲み込んでいる印象
→タグネットワークの成長は止まっている状態とも言えるか
仕事を選べない私たち
5.“ ゆっくり文化”の再発見文化というか定着しつつあるタグというか
“ 文化”として定着しつつある“ゆっくり”関連タグとは _1
見つかればいいなあくらいの感覚で
SVMで算出した確率に基づいて、”今後定着するであろう”タグを探してみる
分類器の精度が悪かったので、 95%以上のものについてのみ注目する
出来ればあまり大きくないコミュニティから見つけたい
まず全体を通して高い確率を示すもの、次に主要コミュニティごとに見ていく
“ 文化”として定着しつつある“ゆっくり”関連タグとは _2
これだけじゃわからんぜ
確率が高いものを Gephi上で青くしてみたのがこちら
“ 文化”として定着しつつある“ゆっくり”関連タグとは _3
全体のネットワークにおいて高いものから表にしてみた
ここはほぼゲーム実況か東方コミュニティ
nameave_view
ave_comment
ave_mylist
ave_length
modify_probability
まんじゅうこわい 24930.5 511.5 433.5 1504.0 99.691%ACE2 34896.0 1517.5 81.5 1658.0 99.529%ウルヲイ 52591.5 4787.5 154.5 1327.5 99.524%綺麗な我様 11705.0 497.0 56.0 1632.0 99.493%紡がれ続けた物語の終わり 11705.0 497.0 56.0 1632.0 99.493%タイトルに偽り無し 11705.0 497.0 56.0 1632.0 99.493%物語は紡ぎ紡がれていく 11705.0 497.0 56.0 1632.0 99.493%聞くだけ動画 23658.5 422.5 431.0 1054.0 99.197%壷算 13365.0 231.0 55.0 1212.0 99.161%へうげもの 13365.0 231.0 55.0 1212.0 99.161%化け物つかい 15909.0 409.0 60.0 2112.0 99.125%ハロワ 15909.0 409.0 60.0 2112.0 99.125%変態包囲網 51482.0 2326.0 123.0 1429.0 99.026%ツーリング 51482.0 2326.0 123.0 1429.0 99.026%
“ 文化”として定着しつつある“ゆっくり”関連タグとは _4
「まんじゅうこわい」が一番高い確率を叩き出す
解せぬ
nameave_view
ave_comment
ave_mylist
ave_length
modify_probability
まんじゅうこわい 24930.5 511.5 433.5 1504.0 99.691%ACE2 34896.0 1517.5 81.5 1658.0 99.529%ウルヲイ 52591.5 4787.5 154.5 1327.5 99.524%綺麗な我様 11705.0 497.0 56.0 1632.0 99.493%紡がれ続けた物語の終わり 11705.0 497.0 56.0 1632.0 99.493%タイトルに偽り無し 11705.0 497.0 56.0 1632.0 99.493%物語は紡ぎ紡がれていく 11705.0 497.0 56.0 1632.0 99.493%聞くだけ動画 23658.5 422.5 431.0 1054.0 99.197%壷算 13365.0 231.0 55.0 1212.0 99.161%へうげもの 13365.0 231.0 55.0 1212.0 99.161%化け物つかい 15909.0 409.0 60.0 2112.0 99.125%ハロワ 15909.0 409.0 60.0 2112.0 99.125%変態包囲網 51482.0 2326.0 123.0 1429.0 99.026%ツーリング 51482.0 2326.0 123.0 1429.0 99.026%
“ 文化”として定着しつつある“ゆっくり”関連タグとは _5
「まんじゅうこわい」周辺のネットワークを確認する
ゆっくりに物語を喋らせているのが多い印象
“ 文化”として定着しつつある“ゆっくり”関連タグとは _6
「”ゆっくり ,科学系解説”コミュニティ」で確率が高いタグ
解説系では定番の反応ですね
name ave_viewave_comment
ave_mylist
ave_length
modify_probability
動画には本文を書けばどうか 4662 170 26 578 93.746%ひらがなでしゃべらせて 4662 170 26 578 93.746%分からんということが分かった . 40737.5 898.7 151.8 720.5 93.602%FMEAutomator 13267 417 420 372 92.169%ニコ生 13267 417 420 372 92.169%FME 13267 417 420 372 92.169%ニコ生講座 13267 417 420 372 92.169%ヤンデレ 58156.8 4258.8 173.4 820.2 91.928%AxisPowers ヘタリア 6369.5 191 29.5 463 91.315%がんばりましょう 6369.5 191 29.5 463 91.315%
“ 文化”として定着しつつある“ゆっくり”関連タグとは _7
「動画には本文を書けばどうか」周辺のネットワークを確認する
解説系という感じなぜヘタリアもあるんだろう
考察まとめ
ぐぬぬ
以上のコミュニティ以外では確率が著しく下がるため、今回は分析を見送りました
個人的には、”既に文化として定着している感のあるタグ”しか確率が高いものとして出てこなかった印象
ランキングポイントをトレーニングセットの基準にする以外の方法で”文化として根付いているタグ”を選別するやり方を見つけないといけない
あるいはもう、”ゆっくり”に関連するタグでは新たな文化は生み出されないのかもしれない
今後は VOICELOID(結月ゆかり )などを対象にするべきかも
今後の技術的課題や展望
もっと精進せねば
処理の途中で文字化けしてしまい、判別困難なタグができてしまったのが残念
ネットワーク分析ではデータが膨大になりがちなので、メモリを増設しないと
今回の先行研究は非常に応用範囲が広い (レコメンドなど )ので、今後も色々実践していきたいと思っております
今回の処理ログなど
お役に立てれば幸いです
全ノードのデータ (文字化けがあります )…http://github.com/fufufukakaka/niconico_analysis/blob/master/taggraph_dynamic%20%5BNodes%5Dmmmmm.csv
Rのログ (全部で 3つあります )…https://github.com/fufufukakaka/niconico_analysis/blob/master/niconico_tag_network(_2,3).Rmd