4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Python】真剣にM-1必勝法を考えてみる。

Posted at

1. 内容

  • 毎年盛り上がっているM-1グランプリだが、毎年楽しく見させていただいている。芸人さんにとってその後のキャリアを大きく左右する重要なグランプリであることもよく分かる。
  • でも毎年見ていてちょっと気になることがある。ブッチ切りな候補が優勝する年もあるものの、僅差でとあるコンビが制する年もあり、やはりこの場合審査員の好みが色濃く出ていると感じられることがある。
  • もともと、お笑い芸人の技量について絶対的なモノサシなんか存在しないだろうし、だからこそ審査員との相性が重要となってくるのではないかと思うことがある。
  • そうなればこそ、どうしても審査員の好みに合わせてウケにいって効率よく点数を稼ぐ方法があるのではないかと考えてしまう。
  • なお僕はお笑いには特別詳しくなく、バラエティでよく見る芸人さんについては知っている程度である。詳細なお笑い論で間違っていることを主張していたらごめんなさい。

2. 今年のM-1のデータ

  • 安定のWikipediaさんを参照しました。(https://ja.wikipedia.org/wiki/M-1%E3%82%B0%E3%83%A9%E3%83%B3%E3%83%97%E3%83%AA)

  • ||kaminuma|matsumoto|reiji|tomizawa|shiraku|hanawa|kyojin|
    |:--|--:|--:|--:|--:|--:|--:|--:|
    |milkboy|98|97|96|97|97|99|97|
    |kamaitachi|95|95|94|93|95|95|93|
    |pekopa|96|94|92|94|91|94|93|
    |wagyu|92|92|93|91|96|96|92|
    |mitorizu|94|91|93|91|94|92|94|
    |karashi|94|90|93|90|89|90|93|
    |ozuwarudo|94|90|94|91|89|89|91|
    |suwe|92|89|91|90|92|91|92|
    |indians|94|88|92|90|87|89|92|
    |newyork|90|82|88|88|90|91|87|

  • コピペして使いたい方は以下をどうぞ。

2019年M-1データ
data = pd.DataFrame([[98,97,96,97,97,99,97],
                     [95,95,94,93,95,95,93],
                     [96,94,92,94,91,94,93],
                     [92,92,93,91,96,96,92],
                     [94,91,93,91,94,92,94],
                     [94,90,93,90,89,90,93],
                     [94,90,94,91,89,89,91],
                     [92,89,91,90,92,91,92],
                     [94,88,92,90,87,89,92],
                     [90,82,88,88,90,91,87]],
                   columns=['kaminuma','matsumoto','reiji','tomizawa','shiraku','hanawa','kyojin'],
                   index=['milkboy','kamaitachi','pekopa','wagyu','mitorizu','karashi','ozuwarudo','suwe','indians','newyork'])

3. データ概観

平均と標準偏差

data.describe()
kaminuma matsumoto reiji tomizawa shiraku hanawa kyojin
count 10.000000 10.000000 10.0000 10.00000 10.000000 10.000000 10.000000
mean 93.900000 90.800000 92.6000 91.50000 92.000000 92.600000 92.400000
std 2.233582 4.184628 2.1187 2.54951 3.366502 3.306559 2.503331
min 90.000000 82.000000 88.0000 88.00000 87.000000 89.000000 87.000000
25% 92.500000 89.250000 92.0000 90.00000 89.250000 90.250000 92.000000
50% 94.000000 90.500000 93.0000 91.00000 91.500000 91.500000 92.500000
75% 94.750000 93.500000 93.7500 92.50000 94.750000 94.750000 93.000000
max 98.000000 97.000000 96.0000 97.00000 97.000000 99.000000 97.000000
  • 一応平均を見てみると、上沼の93.9が最高、松本の90.8が最低となっていますが、これ自体はあまり意味をなす数字ではありません。みんなに高い点数をつける人から高い点数をもらったところでライバルとの差がつかないからです。
  • 標準偏差(表中の'std')は、松本の4.18が最高、礼二の2.12が最低となっています。これは松本にハマるとライバルに差をつけやすい一方で、礼二にハマっても差がつきにくいというように解することができます。

相関係数

sns.heatmap(data.corr(), annot=True)
plt.show()

save.png

  • どうも上沼と志らくは好みがだいぶ違う方向性を向いているようで、相関係数はかなり低いということが見て取れます。
data.corr().sum(axis=0)
審査員 相関係数合計
kaminuma 5.251470
matsumoto 5.876156
reiji 5.272178
tomizawa 5.791959
shiraku 4.487326
hanawa 5.002257
kyojin 5.535278
  • 松本と富澤は他の審査員と同じような好き嫌いをしているようです。言い換えれば、他の審査員の評価と整合性が取れるような評価ばかりで、独自の視点を打ち出してくるタイプではないようです。
  • 一方で志らくや塙は自分独自のモノサシに従って点数をつけてくるせいか、他の審査員との相関はそこまで高くありません。

ペアプロット

sns.pairplot(data)
plt.show()

save.png

  • 相関係数の数字と概ね整合性が取れる内容となっています。
  • 例えば最上行の上沼の評価を見ると、他の審査員が高評価をつければだいたい上沼も高い点数を付与しているものの、志らくと塙との評価ではだいぶバラツキがあって、好みがだいぶ異なっているであろうことが見て取れます。

4. モデル

戦略

  • ここまでで、独自の視点を持っているであろう審査員がいること、多くの審査員は他の審査員と似たような評価をつけがちであることが分かった。
  • となれば次に気になるのはどの審査員に気に入られにいくのが最も効率的に点数を稼ぐことができるか、という点である。
  • まず考えたのが、通常の線形回帰。例えば、上沼と松本の評価について、
    $\qquad Score_{matsumoto}=\beta Score_{kaminuma}+\epsilon_{kaminuma}, \quad \epsilon_{kaminuma} \sim N(0,\sigma_{kaminuma}^2)$
    という形に回帰してやれば、
    $\qquad \Delta Score_{matsumoto}=\beta \Delta Score_{kaminuma}$
    となって、上沼のスコアを1単位上げにいくことで、それに伴って松本のスコアがどれくらい上がると期待できるかをモデル化できるのではないかと考えた。
  • ただ、ここで気になったのがこれを複数の審査員に拡大した時に、$\epsilon_{person}$が互いに独立と仮定していいかという点である。すなわち、上沼へのハマり具合から松本と礼二のスコアを推定する上で、上沼は気にしないが松本と礼二が重視する何かしらの尺度が存在して、$\epsilon_{matsumoto}$と$\epsilon_{reiji}$が同方向の数値となりがちな傾向が存在しないかどうかということである。
  • これを捕捉するために、線形回帰をした際の残差の分散についても分析することとした。
    $\qquad Var(X+Y)=Var(X)+Var(Y)+2Cov(X,Y)$
    $\qquad Cov(X+Y,Z)=Cov(X,Z)+Cov(Y,Z)$
    であることを踏まえれば、
    $\qquad \sum_{person}Score_{person}=\sum_{person}\beta_{person}Score_{kaminuma}+\epsilon_{all}, \quad \epsilon_{all} \sim N(0,\sigma_{all}^2)$
    $\qquad where \quad \sigma_{all}^2 = \sum_{person}Var(residual_{person}) + \sum_{person_1}\sum_{person_2}Cov(residual_{person_1},residual_{person_2})$
    となる。

実装

  • 実際に分析に用いたコードは以下の通りである。
回帰分析のコード
from sklearn.linear_model import LinearRegression
X = data.values
coefs = np.zeros((7,7))
V = np.zeros(7)
model = LinearRegression()
for i in range(X.shape[1]):
    residuals = np.zeros((6,10))
    coef = np.zeros(6)
    x = X[:,i].reshape(-1,1)
    y = np.delete(X, i, 1)
    for j in range(y.shape[1]):
        y_ = y[:,j].reshape(-1,1)
        model.fit(x, y_)
        coef[j] = model.coef_
        residuals[j,:] = (model.predict(x) - y_).flatten()
    coef = np.insert(coef, i, 1)
    coefs[i,:] = coef
    cov_mat = np.cov(residuals, bias=True)
    V[i] = cov_mat.sum()

簡単に説明を加えておくと、

  • for i in ...のところでは、上沼のスコアを元に他の審査員のスコアを回帰分析し、次に松本のスコアを元に・・・というループを回している。
  • for j in ...のところで、例えば上沼のスコアを元に、松本のスコアを回帰、礼二のスコアを回帰というループを回している。また回帰の係数(上の数式で$\beta_{person}$にあたる)をcoefという配列に保存している。また、回帰の残差をresidualsという配列に保存している。
  • for j in ...のループが終わったところで、np.insertによって、例えば上沼から上沼への回帰の係数は1であるというところを処理している。また、coefをcoefsという配列に保存している。
  • 残差の分散の和をVという配列に保存している。residuals共分散行列の和がそれに当たる。

結果

  • 各審査員のスコアに対する他の審査員の感応度である$\beta_{person}$については以下のようになった。データは行ごとに入っていて、上沼のスコアに対する他の審査員の感応度が1行目となっている。
coefs_df = pd.DataFrame(coefs, 
                        columns=['kaminuma','matsumoto','reiji','tomizawa','shiraku','hanawa','kyojin'],
                        index=['kaminuma','matsumoto','reiji','tomizawa','shiraku','hanawa','kyojin'])
sns.heatmap(coefs_df, annot=True)
plt.title('regression coefficient')
plt.show()

save.png

  • また、残差の標準偏差は以下のようになった。
std_df = pd.DataFrame(pow(V,0.5),
                      columns=['residual std'],
                      index=['kaminuma','matsumoto','reiji','tomizawa','shiraku','hanawa','kyojin'])
residual std
kaminuma 9.332082
matsumoto 4.644780
reiji 9.057326
tomizawa 5.586553
shiraku 10.673552
hanawa 8.872448
kyojin 7.665711

5. 考察

  • どの審査員の好感度を狙いに行くのが最も効率的を考えるにあたって、ある審査員から追加で1点もらったときに他の審査員からの点数がどうなるかを考えるよりも、審査員ごとにスコアの標準偏差が異なっていたことを考えると、追加的に1標準偏差($1\sigma$)分の点数をもらったときに他の審査員からの点数がどうなるかを考えたほうがよいと思われる。
sensitivity_df = pd.DataFrame(data.std(axis=0)*coefs.sum(axis=1), columns=['sensitivity'])
sensitivity_df = pd.concat([sensitivity_df, std_df], axis=1)
sensitivity residual std
kaminuma 14.714779 9.332082
matsumoto 17.009344 4.644780
reiji 14.904319 9.057326
tomizawa 16.691662 5.586553
shiraku 13.664036 10.673552
hanawa 15.027370 8.872448
kyojin 15.747906 7.665711
  • これを見る限りでは、松本のウケを狙うと他の審査員からのスコアアップも期待できやすく、最も効率的に点数を稼ぐことができそうであることがわかる。
  • 一方で残差の標準偏差は松本が最も小さく、志らくが最も大きくなっている。志らくにハマっても他の審査員は別の視点から評価をしており全体的なスコアアップに直結しにくいが、他の審査員の別の尺度にハマるかどうかでスコアがブレやすく、残差の標準偏差が大きくなっていると解することができる。
  • 以上よりまずは松本好みの漫才に寄せて評点全体の底上げをした上で、余裕があるなら志らくに引っかかる要素を織り交ぜてライバルとの差別化を図るのがM-1を制する一助となるのではないかと考えられる。

6. まとめ

  • 2019年の1回戦のみに限っていえば、松本の好みに寄せた漫才をするのが1回戦を制する鍵になるのではないかという示唆が得られた。
  • 松本の好む漫才がどのような漫才かという点については具体的な指摘はできません。お笑い素人の限界です。
  • 他の年や決勝についても似たような分析をすることで面白いインプリケーションが得られそうである。
  • まあこのような小手先の戦略がワークする局面があったとしても、余程の僅差である場合に限られるでしょう。難しいこと考えずに気楽に見て笑うのが一番の楽しみ方だと思います。
4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?