Aidemy Blog

株式会社アイデミーのブログです。機械学習・ディープラーニング関連技術の活用事例や実装方法をまとめる技術記事や、キャリア記事等を発信しています

ドラマの視聴率を予測してみる!

機械学習を使って何か予測してみたいなと考えたとき、ドラマの視聴率は予測できないのかなと思い実際にやってみることにしました。

 

今回はJupyter notebookを使って実装しました。

 

データセット

 

https://artv.info/ ここから2015年と2016年のドラマの視聴率を取ってきてcsvファイルにする テストデータとして2017年のデータを取ってくる

データの説明

データの総数:176 目的変数:ドラマの視聴率の平均 説明変数:放送された年、曜日、時間帯、テレビ局、1回目の視聴率とした

1回目の視聴率はドラマのタイトルや出演者、CMの量などが影響してきていると考えられるので、今回はデータとして含めることができないそうした要素を加味するために加えることにした。 また、ドラマの名前は日本語でそのままでは扱いずらいので削除した。

まず必要なライブラリーをまとめてインストールして、作ったcsvファイルをインポート

 

#必要になりそうなものをまとめてインストール
import pandas as pd
import numpy as np
import seaborn as sns
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.ensemble import RandomForestRegressor

 

# データをインポート
data = pd.read_csv('train.csv')
test=pd.read_csv("test2.csv")

#基本的な統計量を確認
data.describe()
year time 1 average
count 176.000000 176.000000 176.000000 176.000000
mean 14.920455 21.693182 10.503977 0.090645
std 0.824227 0.790775 3.527239 0.033990
min 14.000000 20.000000 2.700000 0.029300
25% 14.000000 21.000000 8.275000 0.069225
50% 15.000000 22.000000 10.100000 0.084500
75% 16.000000 22.000000 12.900000 0.107550
max 16.000000 23.000000 26.500000 0.229400
#データの相関を見る
data.corr() 
year time 1 average
year 1.000000 0.120151 -0.195264 -0.111665
time 0.120151 1.000000 -0.408886 -0.361273
1 -0.195264 -0.408886 1.000000 0.896363
average -0.111665 -0.361273 0.896363 1.000000
#可視化する
import seaborn as sns
plt.figure(figsize=(9,9))
sns.heatmap(data.corr(), annot=True, square=True, fmt='.2f')
plt.show()

sns.pairplot(data )
plt.show()

f:id:odnicesp:20180927171550p:plain

f:id:odnicesp:20180927171612p:plain

1回目の視聴率との相関がかなり高いことがわかります。(それはそうかな)

データの前処理

文字列のものはこのままでは学習できないので、ダミー変数化をします。

 

 #ダミー変数化
def dum(data,name):
dum=pd.get_dummies(data[name])
del(data[name])
data = pd.concat([data, dum], axis=1)
return data

data=dum(data,"season")
data=dum(data,"day")
data=dum(data,"TV")

同様にテストデータもダミー変数化する

 test=dum(test,"season")
test=dum(test,"day")
test=dum(test,"TV")

学習できるようにnumpyの形に変形

 

#学習データ作成
X_train=data.drop("average",axis=1).values
y_train=data.loc[:,"average"].values

#テストデータ作成

X_test=test.drop("average",axis=1).values
y_test=test.loc[:,"average"].values

学習

線形の重回帰をする

 # 線形回帰のモデルを学習させる
from sklearn.linear_model import LinearRegression
model_lin = LinearRegression()
model_lin.fit(X_train, y_train)

平均二乗平方誤差を求める

 

predict=model_lin.predict(X_test)

predict=pd.DataFrame(predict, columns=["predict"])
for i in range(len(predict)):
if predict.loc[i,"predict"]<0:
predict.loc[i,"predict"]=0
elif predict.loc[i,"predict"]>1:
predict.loc[i,"predict"]=1

np.sqrt(mean_squared_error(y_test,predict))

出力:0.013120566634344053

 

視聴率にして大体1%くらい予測がずれていことがわかります。

次に2次関数で回帰を試してみます。

     

 

quad = PolynomialFeatures(degree=2) 
quad_data= quad.fit_transform(X_train)
quad_test= quad.fit_transform(X_test)
# 線形回帰のインスタンスを生成
model_quad = LinearRegression()

model_quad.fit(quad_data, y_train)

予測すると、

 

predict=model_quad.predict(quad_test)

predict=pd.DataFrame(predict, columns=["predict"])
for i in range(len(predict)):
if predict.loc[i,"predict"]<0:
predict.loc[i,"predict"]=0
elif predict.loc[i,"predict"]>1:
predict.loc[i,"predict"]=1

np.sqrt(mean_squared_error(y_test,predict))

0.03321449872832119

誤差が少し増えてしまいました。 おそらく原因は1回目の視聴率と視聴率の平均の間に強い線形関係があったからだと思われます。

次に、少しアルゴリズムが異なる決定木を用いたモデルを試してみました。 今回はRandomForestを選択

#学習モデルの作成

rf=RandomForestRegressor(n_estimators=100)
rf.fit(X_train,y_train)
rf.score(X_test,y_test)
predict=rf.predict(X_test)
predict=pd.DataFrame(predict, columns=["predict"])
for i in range(len(predict)):
    if predict.loc[i,"predict"]<0:
        predict.loc[i,"predict"]=0
    elif predict.loc[i,"predict"]>1:
        predict.loc[i,"predict"]=1
np.sqrt(mean_squared_error(y_test,predict))

0.011895995071281513

線形回帰より少し精度のよい予測ができました。そこで、実際に予測結果を出力してみます。

y_train=test.loc[:,"average"]
result=pd.concat([y_train,predict],axis=1)
result

予測結果を出力してみるとこのような感じになります。

 average predict
0   0.0665  0.080544
1   0.1130  0.100812
2   0.0890  0.093390
3   0.1139  0.126772
4   0.0974  0.094629
5   0.0653  0.074575
6   0.0342  0.037060
7   0.0832  0.091118
8   0.0646  0.062421
9   0.0963  0.106813
10  0.0499  0.063101
11  0.1455  0.123757
12  0.0930  0.093373
13  0.0877  0.097061
14  0.1058  0.124737
15  0.1125  0.101169
16  0.0917  0.077444
17  0.1409  0.153647
18  0.0644  0.077785
19  0.0333  0.035912
20  0.0879  0.087770
21  0.0545  0.061309
22  0.0955  0.095583
23  0.1360  0.117685
24  0.0535  0.059104
25  0.0768  0.093071
26  0.1478  0.135021
27  0.0607  0.065102
28  0.1017  0.099923
29  0.1147  0.096129
30  0.1097  0.107221
31  0.1145  0.097105
32  0.0450  0.047390
33  0.0345  0.035188
34  0.0733  0.086210
35  0.0400  0.053883
36  0.0870  0.094185
37  0.0973  0.092584
38  0.0654  0.078296
39  0.0858  0.074088
40  0.0674  0.086991
41  0.0575  0.076933
42  0.0773  0.093607
43  0.1265  0.095393
44  0.2087  0.213110
45  0.0653  0.059748
46  0.0348  0.036104
47  0.1187  0.114391
48  0.0483  0.054790
49  0.0877  0.087007
50  0.1600  0.140068
51  0.0619  0.064881

1回目の視聴率があるとかなり予測しやすいので、1回目の視聴率を除いて予測してみます。

del data["1"]
del test["1"]

#学習データ作成
X_train=data.drop("average",axis=1).values
y_train=data.loc[:,"average"].values

#テストデータ作成


X_test=test.drop("average",axis=1).values
y_test=test.loc[:,"average"].values

まず、線形回帰モデルを試してみます。

# 線形回帰のモデルを学習させる
from sklearn.linear_model import LinearRegression
model_lin = LinearRegression()
model_lin.fit(X_train, y_train)

predict=model_lin.predict(X_test)

predict=pd.DataFrame(predict, columns=["predict"])
for i in range(len(predict)):
    if predict.loc[i,"predict"]<0:
        predict.loc[i,"predict"]=0
    elif predict.loc[i,"predict"]>1:
        predict.loc[i,"predict"]=1
np.sqrt(mean_squared_error(y_test,predict))

0.029758171793322862

誤差は視聴率にして3%程度であまりよくないです。

次に、2次関数で試してみます

quad = PolynomialFeatures(degree=2) 
quad_data= quad.fit_transform(X_train)
quad_test= quad.fit_transform(X_test)
# 線形回帰のインスタンスを生成
model_quad = LinearRegression()

model_quad.fit(quad_data, y_train)

predict=model_quad.predict(quad_test)

predict=pd.DataFrame(predict, columns=["predict"])
for i in range(len(predict)):
    if predict.loc[i,"predict"]<0:
        predict.loc[i,"predict"]=0
    elif predict.loc[i,"predict"]>1:
        predict.loc[i,"predict"]=1
np.sqrt(mean_squared_error(y_test,predict))

0.034900994501918164

さらに精度が落ちてしまいました。 ダミー変数化している特徴量が多いので精度が下がってしまったのかもしれないです。

最後にRandomForestを試してみます

#学習モデルの作成

rf=RandomForestRegressor(n_estimators=100)
rf.fit(X_train,y_train)
predict=rf.predict(X_test)
predict=pd.DataFrame(predict, columns=["predict"])
for i in range(len(predict)):
    if predict.loc[i,"predict"]<0:
        predict.loc[i,"predict"]=0
    elif predict.loc[i,"predict"]>1:
        predict.loc[i,"predict"]=1
np.sqrt(mean_squared_error(y_test,predict))

0.020205388662540902

誤差2%程度で、そこそこ予測できているが、今回は標準偏差が大きくないデータでの予測なので、あまり精度が良くないと思われます。実際に2017年の平均視聴率を予測して比較してみると

y_train=test.loc[:,"average"]
result=pd.concat([y_train,predict],axis=1)
result
      average    predict
0   0.0665  0.094750
1   0.1130  0.084270
2   0.0890  0.090770
3   0.1139  0.108972
4   0.0974  0.130336
5   0.0653  0.076118
6   0.0342  0.036407
7   0.0832  0.074656
8   0.0646  0.065642
9   0.0963  0.097014
10  0.0499  0.072753
11  0.1455  0.099682
12  0.0930  0.087231
13  0.0877  0.088673
14  0.1058  0.080945
15  0.1125  0.085320
16  0.0917  0.124294
17  0.1409  0.116720
18  0.0644  0.064154
19  0.0333  0.035253
20  0.0879  0.088994
21  0.0545  0.072029
22  0.0955  0.083854
23  0.1360  0.147650
24  0.0535  0.066186
25  0.0768  0.084481
26  0.1478  0.100631
27  0.0607  0.071729
28  0.1017  0.077674
29  0.1147  0.114791
30  0.1097  0.085149
31  0.1145  0.102019
32  0.0450  0.072888
33  0.0345  0.032152
34  0.0733  0.061983
35  0.0400  0.061864
36  0.0870  0.074883
37  0.0973  0.100981
38  0.0654  0.065103
39  0.0858  0.082320
40  0.0674  0.086221
41  0.0575  0.086326
42  0.0773  0.122406
43  0.1265  0.122159
44  0.2087  0.191780
45  0.0653  0.074801
46  0.0348  0.035069
47  0.1187  0.104266
48  0.0483  0.071953
49  0.0877  0.085039
50  0.1600  0.115844
51  0.0619  0.077719

まとめ

1回目の視聴率は平均視聴率に大きく関係していることがわかりました つまり、ドラマの視聴率を上げるためには、1回目の視聴率がかなり大切になってくる気がします。 そのために、ドラマが始まる前にたくさんCMを打つことは視聴率を上げるうえで効果がありそうだなと感じました。