本コンペでは、YouTube APIとして公開されているメタデータを用いて、
動画の視聴回数予測にチャレンジしていただきます。
YouTubeは、2019年広告売上高150億ドル、月間アクセス 20億人に達するほど、
世界で最も普及した動画マーケティングツールです。
投稿動画の視聴回数を増やすには、動画コンテンツの質向上、SEO対策が重要といわれ、
日々多くのメディアでノウハウが紹介されております。
しかしながら、各取組みによりどれだけ視聴回数を伸ばすことができるのか、
定量データに基づいたノウハウ紹介は少なく、実際のところ何が効果的であるかはよく分かっておりません。
そこで本コンペティションでは、YouTube APIとして公開されているメタデータをインプットに、
視聴回数を予測するアルゴリズムを開発していただきます。
メタデータの中には、
動画コンテンツの質的指標となるlike/dislike・コメント数や、
SEOとして重要とされているタイトル名・説明文・タグ・投稿時間、といった情報が含まれております。
これら情報を分析することで、投稿動画の視聴回数を伸ばし、しいてはYouTuberとして活躍するためには、
どのような指標に心掛ける必要があるか、知見を可視化し、共有できればと思います。
1位:100,000円
データをダウンロードするにはログインまたはユーザー登録して下さい
コンペに使用するデータは3つに分けられます。
訓練データセットとテストデータセットにはそれぞれ19720レコードと29582レコードのサンプルが含まれています。
訓練データは、動画と再生回数の値が各レコードごとに記載されています。機械学習モデルの構築に使用してください。
テストデータセットでは、再生回数のデータは存在しません。テストデータセットを使用して、どの程度新しいデータに対してモデルが適合しているかを確認し、各動画の再生回数を予測してください。
また、提出ファイルの例に関しては、評価方法のタブを参照してください。
データセットのカラムは以下の通りになっています。
カラム名 | 説明 |
---|---|
video_id | 動画ごとに割り振られる一意なid |
title | 動画のタイトル |
publishedAt | 動画の投稿時間 |
channelId | 動画を投稿したチャンネルのid |
channelTitle | チャンネルのタイトル |
categoryId | 動画カテゴリのid |
collection_date | データレコードの収集日 |
tags | 動画に割り当てられたタグ` |
likes | 高評価の数 |
dislikes | 低評価の数 |
comment_count | コメント数 |
thumbnail_link | 動画のサムネへのリンク |
comments_disabled | コメントが許可されない動画であるか? Trueの場合にはcomment_count は0となる |
ratings_disabled | 高評価と低評価が許可されない動画であるか? Trueの場合にはlikes とdislikes は0となる |
description | 動画の説明文 |
y | 視聴回数 |
目標は、テストデータセットの動画の情報にもとづき、動画の視聴回数を予測することです。y(視聴回数)を実数値で予測してくだい。
$$
\sqrt{\frac{\sum_i( \log(y_{obs,i} + 1) - \log(y_{pred,i} + 1))^2}{n}}
$$
回答用のsubmission.csvを用意する(エントリーとヘッダー行を含む) 。
提出されたファイルに余分な行や列(idとy以外)が含まれていた場合はエラーとなります。
提出ファイルは以下の列のみを必ず含んでください:
id,y
1, 69000000
2, 90000000
3, 4500000
4, 7000000
本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。
コード公開後3週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。
レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。
開始日 2020/04/28 0:00 JST
終了日 2020/6/29 0:00 JST
エントリー締め切り なし
※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。
原則外部データ使用は禁止としておりますが、正解データの入手につながらない場合は、下記承認プロセスにより使用できることといたします
注)ただし、コンペ終了まで10日をきってからの申請は禁止とします
公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。
コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。
第1条(適用)
第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。
第3条(権利の帰属)
第4条(入賞者の義務)
第5条(禁止事項)
第6条(本コンペの変更、中断、終了等)
第7条(損害賠償)
第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。
第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。
(制定)2020年4月1日
可能です。チームページから作成いただけます。
こちらから作成いただけます。
コンペティション参加にはアカウント登録が必要となりますのでご注意ください。
Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認めています。
このチュートリアルでは、動画の鑑賞情報データに対して
を行います。
#環境確認
!python3 --version
print(pd.__version__)
print(np.__version__)
print(sklearn.__version__)
import matplotlib
print(matplotlib.__version__)
Python 3.7.7
0.25.3
1.17.4
0.22
3.1.1
まずはデータを読み込んで見ましょう。csvデータの読み込みは複数のやり方がありえますが、pandas
のread_csv
関数はその中でも機能が豊富で、扱いやすいためこれを使います。
これを使うと、csvデータを読み込み、pandas.DataFrame
にして返してくれます。
#データの読み込みと前処理
import pandas as pd
train_data = pd.read_csv("compe_data/train_data.csv", index_col='id')
print(train_data.shape)
(19720, 16)
また、DataFrame
には.head()
というメソッドが定義されており、これを呼び出すとDataFrame
の先頭の数行を確認できます。
train_data.head()
video_id | title | publishedAt | channelId | channelTitle | categoryId | collection_date | tags | likes | dislikes | comment_count | thumbnail_link | comments_disabled | ratings_disabled | description | y | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | ||||||||||||||||
1 | GDtyztIThRQ | [12] BGM Inazuma Eleven 3 - ~ライオコツト ダンジョン~ | 2011-01-09T05:50:33.000Z | UCQaNYC3dNvH8FqrEyK7hTJw | DjangoShiny | 20 | 20.01.02 | Inazuma|Eleven|Super|Once|bgm|ost|イナズマイレブン|Kyo... | 114 | 0 | 7 | https://i.ytimg.com/vi/GDtyztIThRQ/default.jpg | False | False | ~ライオコツト ダンジョン~Inazuma Eleven 3 BGM Complete (R... | 29229 |
2 | m4H9s3GtTlQ | ねごと - メルシールー [Official Music Video] | 2012-07-23T03:00:09.000Z | UChMWDi-HBm5aS3jyRSaAWUA | ねごと Official Channel | 10 | 20.08.02 | ねごと|ネゴト|メルシールー|Re:myend|リマインド|Lightdentity|ライデ... | 2885 | 50 | 111 | https://i.ytimg.com/vi/m4H9s3GtTlQ/default.jpg | False | False | http://www.negoto.com/全員平成生まれ、蒼山幸子(Vo&Key)、沙田瑞... | 730280 |
3 | z19zYZuLuEU | VF3tb 闇よだれvsちび太 (SEGA) | 2007-07-26T13:54:09.000Z | UCBdcyoZSt5HBLd_n6we-xIg | siropai | 24 | 20.14.01 | VF3|VF4|VF5|ちび太|闇よだれ|chibita|virtuafighter|seg... | 133 | 17 | 14 | https://i.ytimg.com/vi/z19zYZuLuEU/default.jpg | False | False | Beat-tribe cup finalhttp://ameblo.jp/siropai/ | 80667 |
4 | pmcIOsL7s98 | free frosty weekend! | 2005-05-15T02:38:43.000Z | UC7K5am1UAQEsCRhzXpi9i1g | Jones4Carrie | 22 | 19.22.12 | frosty | 287 | 51 | 173 | https://i.ytimg.com/vi/pmcIOsL7s98/default.jpg | False | False | I look so bad but look at me! | 34826 |
5 | ZuQgsTcuM-4 | トップ・オブ・ザ・ワールド | 2007-09-09T09:52:47.000Z | UCTW1um4R-QWa8iIfITGvlZQ | Tatsuya Maruyama | 10 | 20.08.01 | ギター|guitar|南澤大介|トップオブザワールド|トップ|オブ|ワールド|カーペンターズ... | 178 | 6 | 17 | https://i.ytimg.com/vi/ZuQgsTcuM-4/default.jpg | False | False | ソロギターのしらべより「トップオブザワールド」です。クラシックギターで弾いてます。Offic... | 172727 |
訓練データにおける視聴回数がどのような分布になっているか見てみましょう。各階級ごとの度数をヒストグラムを用いてプロットするのが以下のコードです。
%matplotlib inline
import matplotlib.pyplot as plt
plt.hist(train_data['y'], bins=20, log=True)
(array([1.9624e+04, 5.4000e+01, 1.3000e+01, 8.0000e+00, 6.0000e+00,
4.0000e+00, 4.0000e+00, 2.0000e+00, 0.0000e+00, 3.0000e+00,
0.0000e+00, 0.0000e+00, 1.0000e+00, 0.0000e+00, 0.0000e+00,
0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 1.0000e+00]),
array([2.00000000e+00, 1.07128023e+08, 2.14256043e+08, 3.21384064e+08,
4.28512085e+08, 5.35640106e+08, 6.42768126e+08, 7.49896147e+08,
8.57024168e+08, 9.64152188e+08, 1.07128021e+09, 1.17840823e+09,
1.28553625e+09, 1.39266427e+09, 1.49979229e+09, 1.60692031e+09,
1.71404833e+09, 1.82117635e+09, 1.92830437e+09, 2.03543240e+09,
2.14256042e+09]),
<a list of 20 Patch objects>)
ヒストグラムとしては、グラフエリアの左側に1本だけ棒状グラフが出力されました。
ほぼ全てのレコードの視聴回数が50,000,000
未満であり、一部の少数のレコードが50,000,000
近い値を取っているために、上記のように表示されました。
極端に他のレコードと値の異なるものは'外れ値'と言われ、回帰モデルに悪影響を及ぼす場合もあります。この'外れ値'をどのように扱うかは場合により異なります。
今回は、99%タイル以上のデータを除外します
import numpy as np
np.where(train_data["y"] >= np.percentile(train_data['y'], 99))
(array([ 18, 289, 518, 659, 667, 714, 855, 1000, 1040,
1060, 1215, 1303, 1663, 1730, 1862, 1880, 1958, 2114,
2251, 2499, 2579, 2590, 2616, 2728, 2855, 2910, 3030,
3053, 3247, 3543, 3555, 3596, 3623, 3638, 3640, 3667,
3680, 3690, 3852, 3877, 4045, 4134, 4407, 4485, 4507,
4554, 4600, 4686, 4713, 4836, 4854, 5180, 5231, 5232,
5240, 5321, 5479, 5587, 5709, 5894, 6093, 6101, 6162,
6269, 6287, 6462, 6547, 6648, 6688, 6782, 6793, 6847,
6881, 6913, 7284, 7308, 7732, 7779, 7782, 7784, 7850,
7967, 7980, 8029, 8087, 8138, 8362, 8394, 8591, 8674,
8688, 8724, 8943, 8988, 9127, 9270, 9539, 9626, 9892,
9984, 10232, 10251, 10287, 10441, 10448, 10485, 10500, 10553,
10588, 10601, 10684, 10695, 10699, 10857, 11333, 11417, 11445,
11792, 11854, 11893, 12003, 12069, 12128, 12172, 12216, 12218,
12371, 12672, 12681, 12891, 12894, 13023, 13170, 13196, 13272,
13337, 13377, 13401, 13422, 13434, 13469, 13880, 13897, 14044,
14078, 14271, 14379, 14474, 14538, 15618, 15644, 15806, 15819,
15868, 15966, 16100, 16178, 16197, 16311, 16366, 16372, 16447,
16565, 16578, 16579, 16587, 16632, 16701, 16741, 16886, 16915,
17085, 17220, 17247, 17293, 17401, 17490, 17545, 17558, 17587,
17773, 17820, 17882, 18026, 18119, 18382, 18745, 18781, 18926,
18968, 19070, 19109, 19170, 19288, 19359, 19589, 19616, 19637]),)
#外れ値除外
train_data = train_data[train_data["y"] < np.percentile(train_data['y'], 99)]
train_data.reset_index(drop=True)
plt.hist(train_data['y'], bins=20, log=True)
(array([1.684e+04, 1.220e+03, 5.270e+02, 2.360e+02, 1.710e+02, 1.070e+02,
8.000e+01, 6.300e+01, 6.100e+01, 3.600e+01, 2.700e+01, 3.800e+01,
2.900e+01, 1.200e+01, 1.900e+01, 1.100e+01, 1.600e+01, 4.000e+00,
1.100e+01, 1.400e+01]),
array([2.0000000e+00, 2.8219590e+06, 5.6439160e+06, 8.4658730e+06,
1.1287830e+07, 1.4109787e+07, 1.6931744e+07, 1.9753701e+07,
2.2575658e+07, 2.5397615e+07, 2.8219572e+07, 3.1041529e+07,
3.3863486e+07, 3.6685443e+07, 3.9507400e+07, 4.2329357e+07,
4.5151314e+07, 4.7973271e+07, 5.0795228e+07, 5.3617185e+07,
5.6439142e+07]),
<a list of 20 Patch objects>)
続いて、下記のコードを使用して使用するデータ全体の概観を確認します。
各項目について欠損値以外('non-null')の値がどの程度含まれているか把握できます。また、今回のデータでは欠損値が含まれていないようです.
train_data.isnull().sum(axis=0)
video_id 0
title 0
publishedAt 0
channelId 0
channelTitle 0
categoryId 0
collection_date 0
tags 1
likes 0
dislikes 0
comment_count 0
thumbnail_link 0
comments_disabled 0
ratings_disabled 0
description 312
y 0
dtype: int64
データの形式についてもここで見てみましょう。
train_data.dtypes
video_id object
title object
publishedAt object
channelId object
channelTitle object
categoryId int64
collection_date object
tags object
likes int64
dislikes int64
comment_count int64
thumbnail_link object
comments_disabled bool
ratings_disabled bool
description object
y int64
dtype: object
データの形式を見ると、数値についてはint64
型になっていることが確認できます。投稿日は視聴回数に関係がありそうな変数ですが、 object
型になっています. 投稿日をint64
型に変換します。
train_data['publishedAt'] = pd.to_datetime(train_data['publishedAt']).map(pd.Timestamp.to_julian_date)
続いて、数値データの正規化を行い、平均0、標準偏差1になるように変換を行います。
import numpy as np
l = ['likes', 'dislikes', 'comment_count', 'publishedAt']
for name in l:
mean = np.nanmean(train_data[name], axis=0)
std = np.nanstd(train_data[name], axis=0)
train_data[name] = (train_data[name] - mean)/std
train_data.describe()
publishedAt | categoryId | likes | dislikes | comment_count | y | |
---|---|---|---|---|---|---|
count | 1.952200e+04 | 19522.000000 | 1.952200e+04 | 1.952200e+04 | 1.952200e+04 | 1.952200e+04 |
mean | 7.645996e-14 | 15.910306 | 1.455881e-17 | 1.674263e-17 | 1.528675e-17 | 1.803871e+06 |
std | 1.000026e+00 | 8.684912 | 1.000026e+00 | 1.000026e+00 | 1.000026e+00 | 4.918672e+06 |
min | -1.605412e+00 | 1.000000 | -2.900779e-01 | -2.214770e-01 | -2.411631e-01 | 2.000000e+00 |
25% | -9.378234e-01 | 10.000000 | -2.872672e-01 | -2.195250e-01 | -2.398220e-01 | 6.824225e+04 |
50% | -2.145848e-02 | 17.000000 | -2.680869e-01 | -2.053736e-01 | -2.254058e-01 | 3.058175e+05 |
75% | 9.248891e-01 | 24.000000 | -1.403091e-01 | -1.302243e-01 | -1.342151e-01 | 1.255392e+06 |
max | 1.754030e+00 | 44.000000 | 2.605187e+01 | 3.817687e+01 | 3.574564e+01 | 5.643914e+07 |
.describe()
を使用して、基本統計量を確認できます。平均0、標準偏差1に正規化できていることを確認します
モデルに投入する目的変数(y),説明変数(X)を作成します
#使用する説明変数・目的変数を代入
model_input = train_data[['categoryId', 'likes', 'dislikes', 'comment_count', 'publishedAt', 'y']]
#説明変数・目的変数についてnull値を含むレコードを除外
model_input = model_input.dropna(how='any', axis=0)
# 目的変数と説明変数を代入
X = model_input[['categoryId', 'likes', 'dislikes', 'comment_count', 'publishedAt']]
y = np.log(model_input['y'])
このデータにはいくつかのカテゴリカルデータが含まれているので今のままでは機械学習モデルで扱いづらいです。そこで、カテゴリカルデータに対してget_dummies
関数を使いone-hot表現に変換することができます。
今回は、categoryId
のみone-hot表現に変換しました。drop_first=True
を使用することで、多重共線性を弱めることができます。categoryId
は数値データのためcolumns
で明示的に指定してone-hot表現に変換する必要があります。
# one hot表現へ変換
X = pd.get_dummies(X, columns=['categoryId'], drop_first=True)
いよいよ予測モデルの作成に入ります。model.fit('説明変数','目的変数')
と記述することでモデルの学習が可能となります。目的変数を説明変数の組み合わせで説明可能な回帰モデルを作成できます。
#scikit-learnライブラリをimport
import sklearn
from sklearn.linear_model import LinearRegression as LR
#線形回帰モデルのインスタンス化
model = LR()
#予測モデルの作成
model.fit(X, y)
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)
作成したモデルの係数と切片を見てみましょう。model.coef_
で係数の一覧、.intercept_
で切片を見ることができます。
#回帰モデルの評価
#切片
model.intercept_
12.623831394358584
#各説明変数の係数対応表
coeff = pd.DataFrame(X.columns)
coeff.columns = ['説明変数']
coeff['係数推定'] = model.coef_
print(coeff)
説明変数 係数推定
0 likes 0.579694
1 dislikes 0.363648
2 comment_count 0.051812
3 publishedAt 0.409643
4 categoryId_2 -0.512656
5 categoryId_10 0.370962
6 categoryId_15 -0.924757
7 categoryId_17 -0.400887
8 categoryId_19 -1.671840
9 categoryId_20 -0.051330
10 categoryId_22 -0.647365
11 categoryId_23 0.035074
12 categoryId_24 -0.064332
13 categoryId_25 -0.956726
14 categoryId_26 -0.516795
15 categoryId_27 -0.442606
16 categoryId_28 -1.333004
17 categoryId_29 -1.998885
18 categoryId_30 -6.530386
19 categoryId_44 1.004041
各説明変数の係数を比較することで、どの説明変数がどれほどの影響を与えていたか把握することができます。
各説明変数は、係数の値が正に大きいほど視聴回数に対して正の寄与をしており、反対に負に大きいほど視聴回数に対して負の寄与をしていると言えます。
テストデータに対する回帰モデルの当てはまりの良さの指標としては'決定係数'などの指標が用いられます。
決定係数の値は、.score
で確認が可能です。
1に近いほど回帰式で予測された値が実際のデータに当てはまることを表します。
#決定係数
model.score(X,y)
0.28001797307587306
今回作成したモデルの決定係数は0.28程度でした。
また、コンペの評価指標となるRMSLEについても出力が可能です。
今回は、sklearn.metrics
に含まれるmean_squared_log_error
メソッドを使用します。
RMSLEは平均化された誤差の値を示す指標であり、0に近いほど見積もられる予測誤差が小さく予測精度が高いことを表します。
モデルを元にした予測値は、model.predict('説明変数')
で表します。
# RMSE値の出力
from sklearn.metrics import mean_squared_log_error
y_true = model_input['y']
y_pred = np.exp(model.predict(X))
print(np.sqrt(mean_squared_log_error(y_true, y_pred)))
1.9462134377385298
今回作成したモデルのRMSLEは1.946程度でした。
最後に、作成したモデルを使用してテストデータでの視聴回数を予測します。
テストデータの説明変数については予め、上記でモデルに学習させたデータの説明変数と同様の前処理をする必要があります。
test_data = pd.read_csv("compe_data/test_data.csv", index_col='id')
test_data.head()
id | video_id | title | publishedAt | channelId | channelTitle | categoryId | collection_date | tags | likes | dislikes | comment_count | thumbnail_link | comments_disabled | ratings_disabled | description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | xU8UcB6RbLE | Frightened Rabbit - The Greys | 2007-09-26T11:00:07.000Z | UCOQ_j8Qg4-p0lGKBpXYENbg | Fatcat Records | 10 | 20.08.01 | Fatcat|Records|Frightened|Rabbit|The|Greys | 471 | 38 | 61 | https://i.ytimg.com/vi/xU8UcB6RbLE/default.jpg | False | False | Director: Fraser CampbellDate:2007Taken from F... |
2 | ENuB3qHCp0s | Eダンスアカデミー『EXダンス体操(EXILEのダンス体操)』 | 2016-05-27T15:00:00.000Z | UCip8ve30-AoX2y2OtAAmqFA | NHK | 24 | 20.09.02 | Eダンス|Eアカ|EXILE|EXダンス体操|ダンス体操|EX体操|エクササイズ、GENER... | 6797 | 666 | 0 | https://i.ytimg.com/vi/ENuB3qHCp0s/default.jpg | True | False | EXILEがダンスを楽しく分かりやすくレッスンする「Eダンスアカデミー」毎週金曜日に放送中!... |
3 | 2eIeMPhXhSQ | 『Lover Come Back To Me』 大西由希子×川口千里(Senri Kawag... | 2012-12-10T08:24:57.000Z | UCZyaEXqC4i3ni68duKOg6JA | atossinternational | 10 | 20.03.02 | 大西由希子|岩永真奈|川口千里|教則|長崎祥子|ジャズ|ユッコミラー|atossintern... | 3371 | 111 | 212 | https://i.ytimg.com/vi/2eIeMPhXhSQ/default.jpg | False | False | 教則DVD『アドリブ・サックス・パーフェクト・マスター』収録の究極のギャルバンによるスタジオ... |
4 | yXfmnY6QIOc | konnkonn雛たち大きくなりました☆ | 2012-02-27T05:23:46.000Z | UCyeDXVF4epn-ed3c3ckyhOQ | cpj54293 | 15 | 20.02.02 | オカメインコひな | 508 | 16 | 23 | https://i.ytimg.com/vi/yXfmnY6QIOc/default.jpg | False | False | オカメインコのひなたち約生後39日です鳴き声が変わりましたジィージィーの中にピィッ!ピィッ!... |
5 | dGbHHMKYGkw | Anouk - Everything, Live cover by RU kiddin me | 2007-11-24T15:18:04.000Z | UCnOICsYtfygl--dfI9kclVQ | Vinzarelli | 10 | 20.10.01 | Anouk|Everything|live|cover|tribute | 0 | 1 | 0 | https://i.ytimg.com/vi/dGbHHMKYGkw/default.jpg | False | False | Anouk tribute band RU kiddin me covers Everyth... |
test_data['publishedAt'] = pd.to_datetime(test_data['publishedAt']).map(pd.Timestamp.to_julian_date)
import numpy as np
l = ['likes', 'dislikes', 'comment_count', 'publishedAt']
for name in l:
mean = np.nanmean(test_data[name], axis=0)
std = np.nanstd(test_data[name], axis=0)
test_data[name] = (test_data[name] - mean)/std
test_data.describe()
publishedAt | categoryId | likes | dislikes | comment_count | |
---|---|---|---|---|---|
count | 2.958200e+04 | 29582.000000 | 2.958200e+04 | 29582.000000 | 2.958200e+04 |
mean | -1.052510e-13 | 15.863667 | -1.921554e-18 | 0.000000 | 6.725440e-18 |
std | 1.000017e+00 | 8.670842 | 1.000017e+00 | 1.000017 | 1.000017e+00 |
min | -1.611338e+00 | 1.000000 | -1.391489e-01 | -0.066808 | -1.563839e-01 |
25% | -9.275596e-01 | 10.000000 | -1.382193e-01 | -0.066395 | -1.557679e-01 |
50% | -2.663144e-02 | 17.000000 | -1.322320e-01 | -0.063919 | -1.485304e-01 |
75% | 9.177797e-01 | 24.000000 | -9.205591e-02 | -0.050053 | -1.052589e-01 |
max | 1.750811e+00 | 44.000000 | 6.588549e+01 | 136.986019 | 7.579106e+01 |
#使用する説明変数・目的変数を代入
model_input_test = test_data[['categoryId', 'likes', 'dislikes', 'comment_count', 'publishedAt']]
#説明変数・目的変数についてnull値を含むレコードを除外
model_input_test = model_input_test.dropna(how='any', axis=0)
# 目的変数と説明変数を代入
X_test = model_input_test
# one hot表現へ変換
X_test = pd.get_dummies(X_test, columns=['categoryId'], drop_first=True)
モデルで使うデータとテストデータのカラム数が違うとエラーが発生するので、モデルの説明変数について事前に工夫が必要です。
今回は、学習データとテストデータで重複する説明変数のみを利用して学習と予測を実施します。
また、下記のコードでは訓練データで学習させた説明変数の中で、テストデータに含まれないについても列名を出力しています。
#訓練データとテストデータで共通する列名のみに、モデルの説明変数を絞り込む
col_list = X.columns.tolist()
col_test_list = X_test.columns.tolist()
col_joint = col_list + col_test_list
col_dup = [x for x in set(col_joint) if col_joint.count(x) > 1]
#訓練データの説明変数の中で、テストデータと共通しない列名を抽出
col_list_p = [x for x in set(col_joint) if col_list.count(x) == 0]
print(col_list_p)
['categoryId_43']
categoryId_43
は、視聴回数に影響を及ぼす可能性がありますが、訓練データには含まれません。そのため、今回の予測ではテストデータからcategoryId_43
を除外しました。
その上で訓練データについて再度学習させて、モデルを作成します。
#共通の説明変数のみに学習、テストデータのカラムを統一
X_test =X_test.drop('categoryId_43', axis=1)
X_train_fix = X[col_dup]
X_test_fix = X_test[col_dup]
#予測モデルの作成
model.fit(X_train_fix, y)
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)
先ほど使用したmodel.predict('説明変数')
の'説明変数'にテストデータの値を代入することで、テストデータの予測値を算出することができます。
下記のようにして、提出用のsubmission.csv
を出力することが可能です。
#テスト結果の出力
test_predicted = np.exp(model.predict(X_test_fix))
submit_df = pd.DataFrame({'y': test_predicted})
submit_df.index.name = 'id'
submit_df.index += 1
submit_df.to_csv('submission.csv')
plt.hist(np.log(y_pred+1) - np.log(y_true+1), log=True, bins=20)
(array([3.200e+01, 8.820e+02, 5.119e+03, 7.204e+03, 3.960e+03, 1.487e+03,
5.660e+02, 1.920e+02, 5.900e+01, 1.400e+01, 3.000e+00, 0.000e+00,
2.000e+00, 0.000e+00, 0.000e+00, 1.000e+00, 0.000e+00, 0.000e+00,
0.000e+00, 1.000e+00]),
array([-5.95858436, -4.32620805, -2.69383174, -1.06145543, 0.57092088,
2.20329719, 3.8356735 , 5.46804981, 7.10042612, 8.73280243,
10.36517874, 11.99755505, 13.62993136, 15.26230767, 16.89468398,
18.52706029, 20.1594366 , 21.79181291, 23.42418922, 25.05656553,
26.68894184]),
<a list of 20 Patch objects>)
threshold = 14
以下は誤差の絶対値が14を超えるデータの一覧です。
wrong_idx_lower = np.where(np.log(y_pred+1) - np.log(y_true+1) > threshold)[0]
print(wrong_idx_lower)
[ 3361 4658 10206 16918]
train_data.loc[wrong_idx_lower, :]
video_id | title | publishedAt | channelId | channelTitle | categoryId | collection_date | tags | likes | dislikes | comment_count | thumbnail_link | comments_disabled | ratings_disabled | description | y | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | ||||||||||||||||
3361 | E1Nyg03z0pQ | H.R. GIGER | -1.429517 | UCT0R2PJweieLDNNJhyNx4HA | fuzzedoutmama | 1 | 19.30.12 | GIGER | -0.250120 | -0.206837 | -0.143602 | https://i.ytimg.com/vi/E1Nyg03z0pQ/default.jpg | False | False | giger | 349785 |
4658 | b-griRtKHLU | スチャダラパーとEGO-WRAPPIN' ミクロボーイとマクロガール(Official Mu... | 1.172165 | UCQZDh-m6a31o7rXJPuMiFbA | SPACE SHOWER MUSIC | 10 | 20.09.02 | スチャダラパー|schadaraparr|Bose|ANI|SHINCO|ラップグループ|今... | 0.219213 | 0.091808 | -0.023579 | https://i.ytimg.com/vi/b-griRtKHLU/default.jpg | False | False | スチャダラパーとEGO-WRAPPIN’によるコラボ曲「ミクロボーイとマクロガール」のミュー... | 2383295 |
10206 | PPJBp5naSf8 | [びじゅチューン!] 兵馬俑ウエディング | NHK | 1.272681 | UCip8ve30-AoX2y2OtAAmqFA | NHK | 24 | 20.09.02 | 井上涼|びじゅチューン!|びじゅチューン|アニメ|美術|兵馬俑ウエディング|兵馬俑|始皇帝|... | -0.251909 | -0.195614 | -0.241163 | https://i.ytimg.com/vi/PPJBp5naSf8/default.jpg | True | False | NHKサイトで全作公開中!どーがレージ>>https://www.nhk.or.jp/d-g... | 382571 |
16918 | Vw-6spTK3Us | flumpool 見つめていたい Music Video | 0.673300 | UCpKZrypRuFJQ2r5b1Zc88mA | flumpool | 22 | 20.08.02 | flumpool|見つめていたい | -0.224728 | -0.212693 | -0.223059 | https://i.ytimg.com/vi/Vw-6spTK3Us/default.jpg | False | False | The Best 2008-2014「MONUNEMT」2014.5.21Release!!... | 233291 |
視聴回数を過大に評価したデータは4つ。 過小に評価したデータはありませんでした。
コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。
第1条(適用)
第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。
第3条(権利の帰属)
第4条(入賞者の義務)
第5条(禁止事項)
第6条(本コンペの変更、中断、終了等)
第7条(損害賠償)
第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。
第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。
(制定)2020年4月1日