この記事はTSG Advent Calendar 2021の1日目の記事です。
時が経つのははやい
気付けばもう12月ですね。もう2021年の91%が終わったそうですよ。
2021 is 91% complete. pic.twitter.com/yX1LBkYJo0
— Progress Bar 2021 (@ProgressBar202_) November 29, 2021
ところでこのProgress Barボット、たまにTLで流れてくるのを見かけますが、パーセンテージによって反応の大きさに差があるようです。こいつをリツイートするときというのは基本的に「もうそんなに経ったの!?」と感じた時だと思うのですが、人々は一年の何%が過ぎ去った時にこのボットをリツイートしたがるのか調べてみました。
データを収集する
Twitter APIは良く知らないので手元のDevToolsを使い気合いでスクレイピングします。
2021/12/01現在でのツイッター画面は、スクロールしていくと画面外に出たツイートのDOMは削除され、新しく表示するべきツイートのDOMが生成されるようです。そこでそのイベントを検知するスクリプトを実行し、手でスクロールしながら情報を収集していくことにします。
// <div area-label="タイムライン: Progress Bar 2021さんのツイート" class="css-1dbjc4n">
// この子ノードにツイートが詰められている
const elm = document.querySelector("#react-root > div > div > div.css-1dbjc4n.r-18u37iz.r-13qz1uu.r-417010 > main > div > div > div > div > div > div:nth-child(2) > div > div > div:nth-child(3) > section > div");
const tweets = new Set();
const observer = new MutationObserver((mutationList, _) => {
for (let record of mutationList) {
for (let node of record.addedNodes) {
if (node.innerText.includes("@ProgressBar202_")) {
// 例:"Progress Bar 2021\n@ProgressBar202_\n·\n11月18日\n2021 is 88% complete.\n115\n4,668\n2.8万"
const text = node.innerText;
tweets.add(text);
}
}
}
});
observer.observe(elm.children[0], {childList: true});
これをDevToolsで実行した後、気の済むまでスクロールします。今回は2018年の12月まで集めました。
そして
const tweetsArr = Array.from(tweets);
を実行して現れた配列を右クリックでコピーします。
可視化
ここからはPythonを使って可視化します。先ほどコピーした配列をPythonに持ってきます。
tweets = [
"Progress Bar 2021\n@ProgressBar202_\n·\n11月14日\n2021 is 87% complete.\n77\n4,427\n2.6万",
"Progress Bar 2021\n@ProgressBar202_\n·\n11月11日\n2021 is 86% complete.\n114\n4,444\n2.7万",
"Progress Bar 2021\n@ProgressBar202_\n·\n11月7日\n2021 is 85% complete.\n137\n7,648\n3.9万",
"Progress Bar 2021\n@ProgressBar202_\n·\n11月3日\n2021 is 84% complete.\n84\n4,693\n2.7万",
...
これをいい感じのregexで成形し、pandasで表にします。今回日本語環境で収集したので数に「万」が付いてしまっているのでこれにも気を付けます。
import re
import pandas as pd
table = {"year": [], "percent": [], "reply": [], "RT": [], "fab": []}
def parse(x):
if x[-1] == "万":
return int(float(x[:-1]) * 10000)
elif "," in x:
return int(x.replace(",",""))
else:
return int(x)
for tw in tweets:
m = re.search(r"(\d+).* is (\d+)%.*\n(.*)\n(.*)\n(.*)", tw)
table["year"].append(int(m[1]))
table["percent"].append(int(m[2]))
table["reply"].append(parse(m[3]))
table["RT"].append(parse(m[4]))
table["fab"].append(parse(m[5]))
df = pd.DataFrame(table)
実は2019年4月付近にツイートに誤植がある時期がありました。これを手で修正します。
"""
'Progress Bar 2021\n@ProgressBar202_\n·\n2019年4月2日\nApologies for my previous post. 2019 (Two thousand and *nineteen*) is 25% complete.\n114\n3,858\n1.2万',
'Progress Bar 2021\n@ProgressBar202_\n·\n2019年3月29日\n2018 is 24% complete.\n286\n3,160\n1.3万'
"""
df.iloc[269].year = 2019
結果を可視化して見ます
plt.figure(figsize=(15, 10))
plt.subplot(2,1,1)
for year in [2018, 2019, 2020, 2021]:
data = df[df.year == year].sort_values("percent")
plt.plot(data.percent, data.RT, ".-", label="%d"%year)
plt.legend()
plt.xlabel("%")
plt.xticks(range(0, 101, 10))
plt.title("# of RTs")
plt.subplot(2,1,2)
for year in [2018, 2019, 2020, 2021]:
data = df[df.year == year].sort_values("percent")
plt.plot(data.percent, data.fab, ".-", label="%d"%year)
plt.legend()
plt.xlabel("%")
plt.xticks(range(0, 101, 10))
plt.title("# of fabs")
plt.show()
ピークは
- 0%, 100% (元日)
- 10%
- 20%
- 25%
- 50%
- 69%
- 75%
- 80%
- 90%
- 99% (年末)
であり、50%は新年とおなじくらい盛り上がっていることが分かりました。
不思議ポイントとしてはなぜか70%ではなく69%(9月10日付近)でRT/fabが増えている点でしょうか。「1年の7割が過ぎた」ではなく「1年の7割が過ぎそう」であることの方が人々にとっては感慨深いようです。
まとめ
TwitterのProgress Barボット(ProgressBar202_)のRT/fab数をスクレイピングして人々がいつこれに反応しているのかを調べました。基本的にはキリのいい数字になった時か新年に盛り上がっているようですが、7割時点の場合のみ69%で反応が大きくなっているようでした。タイトルの結論は「1年の69%が経つと人々は時の流れの速さを感じる」ということにしようと思います。
--追記-- どうも海外にそういうミーム(下ネタ)があるっぽいです。的外れな考察をしてしまった...結論は50%に変えておきます。 解説:https://www.dailydot.com/unclick/69-nice-meme-twitter/ やたら反応の大きいChrome新バージョン告知:https://twitter.com/ChromiumDev/status/1037022478927912961