グーグルフォームへのリンクはこちら
システムについての話も昨日のは貼っつけただけだったので、以下にまとめておきます。
なお昨日から少し変わってます。
ここおかしいだろ!って点あれば教えてください。
学習は下記のlearning関数です。
引数:iterは学習回数、learning_rateは学習率、dataはアンケート結果の行列で(i, j)が回答者(i)の曲(j)への評価。Rはdataに値が入ってるかどうかのブーリアン。featuresは(i, j)が特徴(i)を曲(j)がどれだけ持っているかのパラメタを意味する行列。thetaは(i, j)が回答者(i)の特徴(j)に対する好感度を意味する行列。lamは正規化項のパラメタ。
出力:学習後のthetaとfeatures、および各学習ごとの誤差関数の値が入ってるJ_list
predictはthetaとfeaturesの内積でつまりscoreの予測をする関数。
cost_funcは二乗誤差、delta_funcはthetaとfeatures各要素の偏微分を出力する関数。これが間違ってたら元も子もない。
---------------------------------------------------------------------------------
def learning(iter, learning_rate, data, features, R, theta, lam):
J_list=np.array([])
for i in range(iter):
prediction=predict(np.r_[np.ones(features.shape[1]).reshape(1, -1), features], theta)
J=cost_func(data, prediction, R, theta, lam)
delta_theta, delta_features=delta_func(data, prediction, np.r_[np.ones(features.shape[1]).reshape(1, -1), features], R, theta, lam)
theta=theta-learning_rate*delta_theta
features=features-learning_rate*delta_features
J_list=np.r_[J_list, J]
return theta, features, J_list
out=np.dot(theta, features)
return out
def cost_func(data, prediction, R, theta, lam):
sub=prediction-data
J=np.sum(sub*sub*R)/(np.sum(R)*2)+np.sum(theta*theta)/(np.sum(R)*2)*lam
return J
def delta_func(data, prediction, features, R, theta, lam):
delta_theta=np.dot((prediction-data)*R, features.T)/np.sum(R)
delta_theta[:, 1:]=delta_theta[:, 1:]+theta[:, 1:]*lam/np.sum(R)
delta_features=np.dot(theta.T, (prediction-data)*R)/np.sum(R)
delta_features=delta_features+features*lam/np.sum(R)
return delta_theta, delta_features[1:, :]
---------------------------------------------------------------------------------
これがちゃんと動作するかテストするためにデータセットを作る。
引数:sは回答者の数、mは曲数、categoryは曲数を何個のカテゴリにするか、maxは評価の最高点、tightnessはカテゴリ間でのcorrelationの強さを調整するパラメタとしてとりあえず3としています。
出力:scoreはs*mの行列で、(i, j)は回答者(i)の曲(j)への評価を示す。
favo_maskは各回答者の好きなカテゴリ、music_maskは各曲の属するカテゴリ、correlation_rateは各カテゴリ間での好き嫌い関係を意味するものです。make_half関数で、(i, j)と(j, i)が同じ値になるようにし、対角成分は0にします。
その後はscoreの各成分に対してcorrelationにそって増減および乱数ちょこっと加えた後、1からmaxに標準化して出力。
---------------------------------------------------------------------------------
def make_bigscore(s, m, category, max, tightness=3):
score=np.zeros(s*m).reshape(s, m)
favo_mask=np.random.randint(0, category, s)
music_mask=np.random.randint(0, category, m)
correlation_rate=make_half(np.random.randn(category, category))
for i in range(s):
for j in range(m):
score[i, j]=score[i, j]+correlation_rate[favo_mask[i], music_mask[j]]*tightness+np.random.randn(1)
score=(score-np.min(score))*max/np.max(score-np.min(score))+1
for i in range(score.shape[0]):
for j in range(score.shape[1]):
score[i, j]=math.floor(score[i, j])
return score
def make_half(matrix):
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
if i>j:
matrix[j, i]=matrix[i, j]
elif i==j:
matrix[i, j]=0
return matrix
---------------------------------------------------------------------------------
その後、scoreの一部を0でマスクしたdataと、dataで数値が入っているところを真、0になっているところを偽とした行列Rを出力する関数。
引数:上のscoreと、どれだけを0に置き替えるかのcover_size
出力:dataとR
---------------------------------------------------------------------------------
def make_data(score, cover_size):
data=score.copy()
data=data.reshape(-1)
mask=np.random.choice(data.size, cover_size)
data[mask]=0
data=data.reshape(score.shape)
R=(data!=0)
return data, R
---------------------------------------------------------------------------------
これで試した結果が以下になります。
まずはJ_listの推移は以下のとおり。学習回数多すぎなのは気にしてはいけない。
あとはR=Falseの値に対する予測値をみてみる。そもそもdataの作り方が「ルールに基づいてたくさんの人の全曲に対する評価」を作ったうえでちょこちょこゼロでマスクしたものなので、そのマスク前の値scoreを比較対象とします。
下記はR=0に対する結果。左から予測値、R(=0に決まっている)、予測値-元のscore。なお評価は1-5の5段階評価。
[[ 2.91048635 0. -0.08951365]
[ 3.22132161 0. 0.22132161]
[ 2.87064662 0. 0.87064662]
[ 1.12139268 0. 0.12139268]
[ 2.41326846 0. 1.41326846]
[ 3.55421757 0. 0.55421757]
[ 3.97669655 0. -0.02330345]
[ 2.7501173 0. 0.7501173 ]
[ 3.6383573 0. -1.3616427 ]
[ 3.64936787 0. -0.35063213]
[ 2.0244445 0. 0.0244445 ]
[ 3.84411781 0. -0.15588219]
[ 3.01835681 0. 0.01835681]
[ 1.89188363 0. 0.89188363]
[ 2.75051635 0. -1.24948365]
[ 2.32287718 0. -1.67712282]
[ 2.05562347 0. 0.05562347]
[ 0.90773748 0. -1.09226252]
[ 1.80391987 0. -1.19608013]
[ 2.674269 0. 1.674269 ]
[ 3.00672833 0. 0.00672833]
[ 1.58966497 0. 0.58966497]
[ 0.94116798 0. -1.05883202]
[ 0.74880779 0. -1.25119221]
[ 1.09310716 0. -0.90689284]
[ 2.51634842 0. 0.51634842]
[ 2.9827374 0. -0.0172626 ]
[ 2.64218652 0. 1.64218652]
[ 2.1911775 0. 0.1911775 ]
[ 2.74421011 0. 0.74421011]
[ 2.21623794 0. 0.21623794]
[ 1.89532806 0. -0.10467194]
[ 2.37408885 0. 0.37408885]
[ 3.39205366 0. -0.60794634]
[ 1.61236102 0. -0.38763898]
[ 2.11890973 0. 1.11890973]
[ 3.17744208 0. 1.17744208]
[ 3.08776717 0. -0.91223283]
[ 3.61529334 0. -0.38470666]
[ 1.35736046 0. -0.64263954]
[ 2.06968813 0. 1.06968813]
[ 1.95003957 0. -0.04996043]
[ 1.56540138 0. -0.43459862]
[ 1.97601405 0. -0.02398595]
[ 2.92261337 0. -1.07738663]
[ 4.09495721 0. 1.09495721]
[ 3.19551809 0. -0.80448191]
[ 3.04745553 0. 0.04745553]
[ 0.79817745 0. -1.20182255]
[ 1.54938092 0. -0.45061908]
[ 1.36258335 0. -0.63741665]
[ 1.70375735 0. -0.29624265]
[ 2.93756708 0. -0.06243292]
[ 2.87062359 0. -0.12937641]
[ 2.38004315 0. 0.38004315]
[ 2.78595807 0. 0.78595807]
[ 3.1983942 0. -0.8016058 ]
[ 0.96060024 0. -1.03939976]
[ 3.52827113 0. -1.47172887]
[ 2.28749893 0. 1.28749893]
[ 2.35833173 0. 0.35833173]
[ 2.74344353 0. -0.25655647]
[ 0.74420262 0. -1.25579738]
[ 1.00412291 0. -0.99587709]
[ 3.2490832 0. 1.2490832 ]
[ 3.14802348 0. 0.14802348]
[ 3.13892027 0. 1.13892027]
[ 3.13161889 0. -0.86838111]
[ 3.0564188 0. 1.0564188 ]
[ 2.75968977 0. -0.24031023]
[ 3.3187245 0. 0.3187245 ]
[ 2.48239435 0. 0.48239435]
[ 3.16379722 0. 1.16379722]
[ 3.32180745 0. -0.67819255]
[ 1.2453015 0. 0.2453015 ]
[ 2.51397865 0. -1.48602135]
[ 3.46314521 0. 1.46314521]
[ 2.16083479 0. 0.16083479]
[ 1.7728266 0. -0.2271734 ]
[ 3.00928758 0. 0.00928758]
[ 3.27487873 0. -0.72512127]
[ 3.34124152 0. 1.34124152]
[ 1.23691874 0. 0.23691874]
[ 1.4981296 0. -1.5018704 ]
[ 2.37196425 0. 0.37196425]
[ 2.13404779 0. -0.86595221]
[ 3.61207011 0. -0.38792989]
[ 2.59456333 0. -0.40543667]
[ 2.62133109 0. -0.37866891]
[ 3.71468802 0. 1.71468802]
[ 1.78221455 0. -0.21778545]
[ 1.96780433 0. 0.96780433]
[ 2.43415152 0. 0.43415152]
[ 2.97109701 0. 0.97109701]
[ 2.78323318 0. 0.78323318]
[ 2.23812096 0. 0.23812096]
[ 2.71397993 0. -1.28602007]
[ 2.7065102 0. -1.2934898 ]
[ 3.62644254 0. -0.37355746]
[ 2.99239456 0. 0.99239456]
[ 3.54316629 0. 0.54316629]
[ 1.11549732 0. -0.88450268]
[ 1.56349647 0. -0.43650353]
[ 1.71123396 0. 0.71123396]
[ 3.50872977 0. 1.50872977]
[ 3.22804646 0. 2.22804646]
[ 2.01647371 0. -0.98352629]
[ 1.73846621 0. -0.26153379]
[ 3.98571845 0. 0.98571845]
[ 4.08772161 0. 0.08772161]
[ 2.77270122 0. -0.22729878]
[ 2.02429106 0. 0.02429106]
[ 1.6524353 0. -0.3475647 ]
[ 1.86554884 0. -0.13445116]
[ 4.13661877 0. 1.13661877]
[ 1.92517157 0. -1.07482843]
[ 1.32741021 0. 0.32741021]
[ 1.49096309 0. 0.49096309]
[ 4.26649726 0. 0.26649726]
[ 1.30860914 0. 0.30860914]
[ 3.65556042 0. 1.65556042]
[ 2.83933612 0. -0.16066388]
[ 3.95311969 0. -0.04688031]
[ 3.33503986 0. 1.33503986]
[ 1.86988111 0. 0.86988111]
[ 1.6803569 0. -0.3196431 ]
[ 2.84351168 0. 0.84351168]
[ 2.21883433 0. 0.21883433]
[ 2.92736767 0. -0.07263233]
[ 1.94865114 0. 0.94865114]
[ 2.84451654 0. -0.15548346]
[ 2.50099697 0. -0.49900303]
[ 1.84460977 0. -1.15539023]
[ 2.25103711 0. 0.25103711]
[ 3.2031821 0. -1.7968179 ]
[ 2.96381569 0. -0.03618431]
[ 2.9374384 0. 0.9374384 ]
[ 2.75750475 0. 0.75750475]
[ 2.14479067 0. 1.14479067]
[ 1.58906309 0. -1.41093691]
[ 3.95424966 0. 0.95424966]
[ 3.27139735 0. -0.72860265]
[ 2.15821289 0. 1.15821289]
[ 1.46000776 0. -0.53999224]
[ 2.77400627 0. 1.77400627]
[ 2.5346113 0. 0.5346113 ]
[ 1.88058697 0. -0.11941303]
[ 2.21373431 0. 0.21373431]
[ 1.01169338 0. -0.98830662]
[ 3.12535171 0. 1.12535171]
[ 2.8508623 0. -0.1491377 ]
[ 1.71767132 0. 0.71767132]
[ 3.61548509 0. 0.61548509]
[ 2.28357741 0. 1.28357741]
[ 2.18370363 0. 1.18370363]
[ 3.68006173 0. 0.68006173]
[ 3.15995915 0. 0.15995915]
[ 2.06859758 0. 0.06859758]
[ 2.5563126 0. 0.5563126 ]
[ 0.809939 0. -0.190061 ]
[ 2.21540911 0. 0.21540911]
[ 3.11465735 0. 0.11465735]
[ 2.58270229 0. 1.58270229]
[ 1.1271192 0. -0.8728808 ]
[ 1.93800718 0. 0.93800718]
[ 1.82362349 0. -0.17637651]
[ 1.41837389 0. -0.58162611]
[ 1.66102766 0. -0.33897234]
[ 3.2908487 0. 1.2908487 ]
[ 2.72840305 0. -1.27159695]
[ 2.64000898 0. 1.64000898]
[ 3.41794859 0. 1.41794859]
[ 1.72408758 0. 0.72408758]
[ 2.2381923 0. 0.2381923 ]
[ 2.75377796 0. -1.24622204]
[ 1.70660727 0. 0.70660727]
[ 1.6848583 0. -0.3151417 ]
[ 2.41792414 0. -0.58207586]
[ 3.10820851 0. -0.89179149]
[ 2.10151184 0. 0.10151184]
[ 1.36604167 0. -0.63395833]
[ 2.17376358 0. 0.17376358]
[ 1.70217391 0. 0.70217391]
[ 1.52573658 0. -0.47426342]
[ 3.21757008 0. 1.21757008]
[ 3.4661244 0. -1.5338756 ]
[ 2.28811177 0. 1.28811177]
[ 3.00192349 0. 1.00192349]
[ 2.18814338 0. 1.18814338]
[ 2.82484159 0. 0.82484159]]
いくらかデータが集まったら、まずはtheta同士の二乗誤差が一番近い人の好きな曲をレコメンドとして送信予定です。
(5/21:追記)
matplotlibの使い方覚えるためにR=0に限った誤差関数もプロットしてみたら…
ぬっ……と少しびびったのだけれど、考えてみれば(prediction-data)の[R==0]の二乗誤差でやっててそれただの評価の平均や!となり、こっそりscoreも与えて(prediction-score)の[R==0]で二乗誤差をプロットしてもらうと、
よかった……。
(prediction-data)の[R==0]の場合に固定される位置は、prediction-dataの[R==0]の平均の2乗を2で割った値なので確かに((1+5)/2)^2/2で4.5前後になりそうね。一件落着。
現時点でも少し回答を頂けております。ご協力ありがとうございます。気長に続けて行きます。