YouTuber同士の繋がりを可視化する

最近ある YouTuber に急にハマった。その人は音楽系やゲーム系などいろんな YouTuber たちとコラボしていて、誰と誰が繋がっているのか把握するのが難しかったので、図にしてみようと思った。

方法

YouTuber 同士の繋がりやコラボレーションを可視化しているプロジェクトはいくつかあったので、参考になる方法がないか探してみた。

おすすめチャンネル欄を使う

www.gugelproductions.de

この記事では、あるチャンネルが別のチャンネルをおすすめチャンネル欄で紹介していれば、そこに繋がりがあると判定して、その繋がりを可視化していた。

こういうやつ

けれどおすすめ欄には大抵サブチャンネルやグループのメンバーのチャンネルくらいしか入っておらず、逐一コラボ相手を載せる人は少ないので、この方法では不十分そうだった。

Twitter を使う

datalion.com

ここに載っているネットワーク図の例では、YouTuber の Twitter 上でのコミュニケーションを辿ることによって人間関係を可視化している。

確かに Twitter は人間関係の把握に適していそうだけど、私の好きな YouTuber は度重なる凍結によって過去のデータが消されているので、この方法も使えなかった。

顔認識・声認識を使う

Collaborations on YouTube: From Unsupervised Detection to the Impact on Video and Channel Popularity や、その続編の Detection and Analysis of Content Creator Collaborations in YouTube Videos using Face- and Speaker-Recognition では、YouTuber 同士のコラボレーションを検出するために顔認識と声認識を使っていた。

技術的にはすごいけど、ここまで本格的なことをやる根気はないし、そもそも YouTube の動画のダウンロードは規約違反なはずなので却下した。

動画の概要欄を使う

上記の方法が全部使えないので、結局自分で方法を考えた。

コラボした動画ではコラボ相手へのリンクを概要欄に貼るという慣習があるようなので、それを利用して、「互いに相手のチャンネルや動画へのリンクを貼っていればコラボ済み」と見なすことにした。

こういうやつ

  1. 中心となる YouTuber を一人決める
  2. その人の動画の概要欄を全部取得して、チャンネルや動画のリンクを一つ一つ取り出す
  3. リンク先の人の動画の概要欄も同様に取得して、リンク返しをされていれば、その2人はコラボしたと見なす

というふうに辿っていって、そのデータを D3.js でネットワークとして可視化した。

また、それぞれのジャンル(音楽、ゲームなど)の YouTuber たちがどういうふうに関わり合っているかも見たいので、チャンネルに紐付けられている topicIds からジャンルを推定して色分けしてみた。

結果

こういう図ができた。

f:id:YaaMaa:20210731151152p:plain
大きい緑のノードが、このグラフの中心となった YouTuber。

今回中心に据えた人は音楽系(緑)だったので、周りも音楽系の人が多い。その中でも、右の方は音楽を通して笑いを提供するチャンネル、左の方は真面目に演奏するチャンネルというふうに固まっていたのが面白かった。

ネットワークの右半分を占めるエンタメ(ピンク)や生活系(黄)は、YouTuber の代表格のようなジャンル。よく仲の良さをアピールしているというイメージがあったけど、それに違わずコラボの密度も高かった。

左上のゲーム系(水色)は、ゲーマー同士でゆるく固まりつつ、エンタメ系や生活系とも適度にコラボしていそう。

左下にちょっと固まっているのは VTuber の人たちだった。そういえば VTuber の人が実体のある YouTuber とコラボしているところを見たことがない気がしたので、実際どうなんだろうと思って、有名 VTuber を中心としたグラフも出してみた。

キズナアイ(A.I.Channel)を起点として描いたグラフ。高画質版

きれいに分断されていた。

追記: 上の図のキャプションがわかりにくい表現だったので書き直しました。

追記: 中心の人から直接繋がっていない YouTuber に関しては、チャンネル登録者数が100万人を超える人のみ表示しています。

YouTube の URL

動画の概要欄で言及されている YouTube チャンネルを抜き出すためには、貼られた URL からチャンネル情報を取得する必要があったんだけど、URL にはいろいろ種類があってややこしかった。調べた範囲では以下のようなものがあった。

  • チャンネル ID が入った URL
    • 形式: https://www.youtube.com/channel/{channel_id}
    • チャンネル情報の取得方法: Channels: listid からチャンネルを取得
  • ユーザー名 が入った URL
    • 形式: https://www.youtube.com/user/{username}
    • チャンネル情報の取得方法: Channels: listforUsername からチャンネルを取得
  • チャンネルのカスタム URL
    • 形式: https://www.youtube.com/c/{custom_name}
    • チャンネル情報の取得方法: Search: listq にカスタム URL を入れてヒットするチャンネル一覧を取得し、その詳細情報を Channels: list で取得した上で、カスタム URL がマッチするものを絞り込む*1
  • 動画の URL
    • 形式: https://www.youtube.com/watch?v={video_id}
    • チャンネル情報の取得方法: Videos: listid から動画を取得し、その snippet.channelId を使って Channels: list からチャンネルを取得
  • 動画の URL(短縮版)
    • 形式: https://youtu.be/{video_id}
    • チャンネル情報の取得方法: 同上

このうちカスタム URL からチャンネル情報を取得する方法については、API の quota を一気に100も消費する高級エンドポイントを使う必要があるので、実装しなかった。それでもやっぱり1日分の quota では全然足りないので、4日間くらいかけてちまちまデータを取得していた。

*1:この記事によると、この方法は小さいチャンネルでは機能しないらしい。

フリースタイルリブレで血糖値トラッキング

最近、食事中に寝落ちてしまうことがたまにある。目が覚めるとご飯やパスタの残りがカピカピになっているので、切ないし困る。

食後の眠気は、食事によって血糖値が急激に上がってから反動で急降下する「血糖値スパイク」が原因であることが多いらしい。私は食べるのが遅いので、ちょっと食べるのを休んでいる間に血糖値の下降が始まってしまい、途中で寝落ちしてしまうのだろうと考えた。

測定

本当に血糖値スパイクが起こっているのかを調べるために、フリースタイルリブレという測定器を買った。体に刺しておくと、血糖値に近似した値*1を常時測っててくれるすごいやつ。グラフも表示してくれる。

普段通りに食事を摂ってみると、予想通り元気よくスパイクしていた。

f:id:YaaMaa:20210516032655p:plain
退勤即就寝するので夕食が変なタイミングになっている

LibreView というデータ管理システムと連携すると、そこに計測データが送られて、LibreView のウェブサイトから計測履歴の CSV ファイルをダウンロードすることもできる。

可視化

せっかく CSV ファイルが手に入るので、BigQuery に入れてクエリしたり Data Studio で可視化したりした。

BigQuery に入れるときは

  • Header rows to skip: 2
  • Allow quoted new lines: true

と設定するとちゃんと読み込んでくれる。

f:id:YaaMaa:20210516143420p:plain
食べてからの血糖値のピークと、2時間後・3時間後の値

↑を出すために書いたクエリ

f:id:YaaMaa:20210516080327p:plain
食べる量(赤)は減らさずに、血糖値(青)を上げない食べ方をだんだん習得していく様子

血糖値スパイク対策

血糖値スパイクを抑えるためにいろんな食べ方を試した。

白米を普通に食べる 白米を一口食べる度に腹筋10回 白米を食べながら歩く 野菜ジュースを飲んでから白米
普通にスパイクが起こる めっちゃ疲れたけど効果なし 逆効果 やさいすごい

これからは何か食べる前に野菜ジュースを飲もうと思った。

もちろん「炭水化物の前に野菜を摂りましょう」っていうのはあちこちで言われていることなんだけど、それを実際自分の体で試して、効果があることを数字で確認できるのがすごく良い。リブレ買ってよかった。

*1:実際に測っているのは間質液中のグルコース濃度。

LINEスタンプ作った

LINEスタンプ無料で作れるらしいので試してみたいなってずっと思ってて、ゴールデンウィークにやっと作れた。

f:id:YaaMaa:20210501001343p:plain
動物とか歯の絵を頑張って描いた

申請

販売のための申請方法は複数あって、それぞれで機能や設定できる項目が違ってややこしかった。

申請場所

LINE Sticker Maker (アプリ) LINE Creators Market (Web)
流れ スタンプ画像の作成 → 詳細情報の登録 詳細情報の登録 → スタンプ画像のアップロード
収益化 するかどうか選べる 選ぶところが見当たらないので、強制的に収益化されそう?
メイン画像やタブ画像 作ったスタンプの中からしか選べない 個別に画像をアップロードできる
その他機能 画像編集機能がいろいろついてる それぞれのスタンプにタグを付与できたり、設定項目が豊富

LINE Sticker Maker は以前は LINE Creators Studio って名前で、その時代は収益化する設定ができなかったらしい? よくわからんけど歴史が複雑。ここに書いた情報もすぐに古くなりそう。

収益化設定

収益化する 収益化しない
売り上げの分配金 一部もらえる もらえない
自分で入手するとき 買わないといけない 無料でダウンロード可能

私はとりあえず自分で使ってみたいだけだったので、収益化しない方を選んだ。

シミュレーション

スタンプがLINEの画面で実際どういう感じに見えるかをシミュレートさせてくれるスタンプシミュレータっていうのがあって、便利。

背景の着せ替えは3つしか用意されてないので、もっといろんな背景色や背景画像で試したかったら JS とかでなんとかする。

// 背景色設定
document.querySelector('.sticker-simulator section').style.backgroundColor = 'red';

// 背景画像設定
document.querySelector('.sticker-simulator section').style.backgroundImage = 'url("画像URL")';

使いどころなさそうなのができあがったけど、とりあえず家族だけ買ってくれた。

store.line.me

歯のイラストを描いたらその日に自分の歯が欠けたので怖かった。

CSS の Container Queries おためし

CSS に、コンテナクエリという機能があるらしい。

メディアクエリでは画面全体の大きさに応じて要素のスタイルを変えることができたけど、コンテナクエリを使うと当該要素の親の大きさに応じてスタイルを変えられる。

/* メディアクエリの例 */
/* 画面幅が 400px 以下だったら、div を赤くする */
@media screen and (max-width: 400px) {
  div {
    background-color: red;
  }
}

/* コンテナクエリの例 */
/* div の親要素の幅が 400px 以下だったら、div を赤くする */
@container (max-width: 400px) {
  div {
    background-color: red;
  }
}

その機能が Google Chrome Canary で使えるようにされたと聞いたので、使ってみた。

こういうのを作った↓

これは HTML/CSS だけでできていて、幅に応じて顔を変えるところはコンテナクエリを使って以下のように書かれている。

.cell-content {
  border-radius: 50px;
  background-color: #ffd3b4; /* オレンジ */
  background-image: url("./images/face-large.svg");
}

@container (max-width: 250px) {
  .cell-content {
    border-radius: 25px;
    background-color: #d5ecc2; /* 緑 */
    background-image: url("./images/face-medium.svg");
  }
}

@container (max-width: 150px) {
  .cell-content {
    border-radius: 10px;
    background-color: #a3e4d2; /* 青 */
    background-image: url("./images/face-small.svg");
  }
}

ここにも埋め込んでみた。Google Chrome Canary で「Enable CSS Container Queries」フラグを有効にしたら上記の gif のように動くはず。

実際使うには親要素に contain プロパティをつけたりする必要があるので、試したい方は以下のリポジトリのソースコードを参照するかもっとちゃんとした記事を読んでください。また、実験的機能なので今後仕様が変わるかもしれません。

github.com

コードベースのどのへんを触ったことがあるかを一覧する

今所属してるチームに入ってから1年が経った。開発してるサービスのコードベースの中でも、「このへんはわりと土地勘がついてきたな」という場所と「ここはまだ全然わからん」という場所が混在している感じになってきた。

自分がまだ触ったことないのはどのあたりかを知りたかったので、今までの自分のコミット数をファイルごとに見れるようにしてみようと思った。調べてもそういうツールは見つからなかったので、作った。

ファイルの履歴

ファイルのコミット履歴を出力する:

git log ファイル名

リネーム前の履歴も欲しい:

git log --follow ファイル名

しかし --follow つけると、ファイルをコピーしてからちょっと編集したやつも同一ファイルと見做されてしまうので、それをなるべく避ける*1:

git log --follow --find-renames=100% ファイル名

そのコミット履歴をユーザーごとに集計して出力する:

git log --follow --find-renames=100% ファイル名 | git shortlog --summary

知らないオプションがどんどん出てきてすごかった。

.mailmap

上記の方法で集計してみたら、人が複数に分裂してカウントされていることがわかった。異なるユーザ名やメールアドレスを使ってコミットされたものは別々に集計されるからだった。

一人の人が会社のメールアドレスと @gmail.com@users.noreply.github.com でコミットしていたり、名前も戸籍ネームとはてな ID と GitHub のアカウント名が混在していたりして、めちゃくちゃだった。

.mailmap ファイルを作ることで正規化してもらえるとのことだったので、

git shortlog -se | sed -r 's/[[:space:]]+[[:digit:]]+\t//' > .mailmap

で初期状態の .mailmap を作ってあとは目視で同一人物をマージしていくという方法で頑張った。


こうやってやっとファイルごとのコミット数の集計ができた。React を使って可視化してみるとこういう感じ。

f:id:YaaMaa:20210417085333p:plain
これは一人プロジェクトなので、当然全てのファイルに触ったことがある

当初は他の人にも使ってもらえる形で作れればいいなと思っていたけど、

  • .mailmap 書くの大変すぎる
  • 集計にものすごい時間がかかる(全ての現存するファイルに対して素朴に git shortlog しているので⋯)

という理由で実用的でないので、一人で楽しむためだけに使おうと思う。

github.com

*1:できればリネームは追うけどコピーは追わない、という設定にしたかったけど、これを読む限り難しそうだった。

Water Sort Puzzle のレベル105は難しい

広告で見かけた Water Sort Puzzle というパズルゲームにはまってしまった。ハノイの塔の亜種みたいなゲーム。

f:id:YaaMaa:20210401010950p:plain

基本的にはさくさく進められるんだけど、レベル105が急に難しくて、何度やっても詰んでしまう。あまりに無理だったので、敗北感を覚えつつも YouTube で解法動画を検索して見てしまった。

けれどこのままでは悔しいので、レベル105が他のレベルと比べてどれくらい難しいのかを計測したい。


難易度の指標としては、「何も考えずに動かせるところを動かしていったとき、どれくらいの確率でクリアできるか」というのが使えると思う。私自身があんまり何も考えずにプレイしているから*1

なので、まずは「動かせるところを総当たりで動かす」というプログラムを作った。

f:id:YaaMaa:20210331210307p:plain
総当たりの様子。矢印の左が現在の状態、右がそこから一手進めたときのパターンの列挙。

愚直に総当たりすると、同じ状態からの展開を計算する処理が大量に行われることになって、ものすごい時間がかかる。

f:id:YaaMaa:20210402010728p:plain

下のようなグラフ構造にすることで計算を節約できた。

f:id:YaaMaa:20210402010308p:plain

グラフが完成したら、矢印をランダムにいけるところまで辿るというのを何度も繰り返して、どれくらいの割合でクリアできたかを計測する。10,000回に設定したらレベル105は一度もクリアできなかったので、100,000回にした。

あと、YouTube の解法動画の再生回数*2がパズルの難易度と連動しているかどうかにも興味があるので、それも合わせて見てみる。

レベル1〜30

f:id:YaaMaa:20210331210345p:plainf:id:YaaMaa:20210331210405p:plain

序盤はどれも簡単。レベル11で一旦動画の再生回数が跳ね上がってるけど、それ以降はユーザーも慣れたのか、同じような難易度であっても動画はそんなに見られていない。

レベル31〜60

f:id:YaaMaa:20210331210418p:plainf:id:YaaMaa:20210331210431p:plain

レベル50がすごい。たしかに難しかった記憶ある。

レベル61〜90

f:id:YaaMaa:20210331210449p:plainf:id:YaaMaa:20210331210504p:plain

このへんは平坦な感じ。

レベル91〜120

f:id:YaaMaa:20210331210519p:plainf:id:YaaMaa:20210331210533p:plain

レベル105がランダムで解けるのは0.001%! つまり10万回に1回。そりゃなかなか解けへんよな、と納得できた。レベル107もかなり手強そう。

あと、難易度と動画の再生回数があからさまに連動してておもしろい。


一覧で見てみると、レベルの数字とパズルの難しさは比例しておらず、簡単なのと難しいのが交互に出てきているのがわかる。そうやっていい感じに緩急がついているせいで、なかなか飽きることができない…。

*1:そもそも正常な判断力があるときはこのアプリを開かない。

*2:同じような内容の動画がいろんなチャンネルから投稿されているので、とりあえず Mobile gamesMobile Games から投稿されている動画の合計再生回数を使った。2021年3月末時点のデータ。

クエリパラメータで設定できるペイントツール

黒背景で正方形のイラストをいっぱい描きたいことがあったんだけど、大抵のオンラインペイントツールは白背景で長方形のキャンバスで初期化されるので、毎回キャンバス設定の変更から始めないといけなくて面倒だった。

キャンバスの設定とかをクエリパラメータで指定できたら楽でいいのになと思ったけれど、需要がないのかそういうツールは探しても見つからなかったので、作ろうと思った。

dev.to

↑この記事で React + Canvas でのペイントアプリの作り方が解説されていたので、ほとんどこれを真似させてもらった。

f:id:YaaMaa:20210228232035p:plain

できた。

ここにあります。

?width=400&height=400&initial_pen_color=ffffff&background_color=000000

ってつけると初期状態が正方形・白ペン・黒背景になるので便利。