「最近のあなたが好んでいるもの」を見つける (DLsite Voice Utils / VoiceStat2)
開発::util
序
この記事は題材としてアダルトコンテンツに関わる内容を多分に含む。
本記事はDLsite Voice Utilsの開発であるが、どちらかというと私がやろうとしている研究の端緒であるという理解のほうが良い。
話の流れとしては以前DLsite Voice Utilsにstat機能を追加したが、ここで
実際、私は「そのサークルをフォローして新作を買うようにしていたが、今ではフォローを外してそのサークルの作品を避けている」というものもある。
理由は、気に入った作品があったから期待値が高かったが、いまいちな作品が続いて期待値を消費しきってしまった、という場合もあるし、サークルが変化したことで好まなくなったという場合もある。
サークルの評価が下がって結果買わなくなった、という場合、与えられた情報をもとにするとそのサークルは評価が高い状態になってしまう。 例えば
[5, 5, 5, 5, 4, 4, 1, 1]
だとすると、このサークルの評価はかなり高い。 が、実際はそのサークルをブロックしている可能性すらある。少なくとも「サークルに対して低い評価をつけた状態で途絶している」ということは判定したほうが良い。 だが、その適切な判定方法はかなり難しい。
好みの分析に「後のものほどウェイトを重くする」という方法もあるが、直近にたまたま駄作が続いたというケースでもそれを回復するのが難しくなる。
という話をしている。
私がやろうとしている研究では “not now” をいかに適切扱うかという目標があるが、割とVoicestatは「意図とはなんか違う」問題を持っていた。
Voicestatは本筋の研究のほうで考えている手法とは根本的に違う形(よりシンプルな方法)で実現しようとしているのだが、「過去の自分の累積」と「今の自分の好み」をどう表現するか、というのが問題として立ちはだかっていたのだ。
だが、私は気づいた。 「別にひとつにする必要はない」。
今回の場合、そのままデータを見せるのだから、それぞれ別のデータとして見せれば良いのだ。
そもそも実装が乱暴すぎるVoicestatの改善も兼ねて新しく作り直したが、とにかく思いついたことを形にしたかったので、ロジック面でも実装面でも課題が大量に残っているが、とりあえずはアイディアのたたき台という理解にしておいて欲しい。
「標準偏差」と「偏差値」の採用
いつも言っているが私は学がなく、数学のできない人間である。
もちろん、新しいことをやろうとしている以上、すべてが今までのものの模倣であっては意味がない。 だが、かといって何もかもが違うというというのも正しくはない。 何もかもが違えば、違う結果が出たところでそれが何に由来するのか非常に不明瞭になってしまう。
検証・証明したい焦点以外は標準的な手法に寄せたほうが良い。 私の作るものは数学的要素を(数学を知らないがために無駄な苦労をして)再発明することで知られているが、今回はちゃんと普通に数学要素を使った。偏差値である。
作品に対するレーティングは、普通の人なら中央値は最頻値になるのではないかという期待ができる。なので、ちょっと短絡的かもしれないが、偏差値は割と現実的な指標だと思う。
評価対象にできるのはキャスト別、サークル別、タグ別の3種類だ。 評価対象にできる値は累計スコアか平均スコアだろう。
あとキャスト別にするとして、全体のデータは全作品か、集計された作品かという問題もある。
例えばキャストAの出演作品が1作品だけしかない場合、傾向を判断する上ではノイズになってしまうためにBasicDB::MEAN_MINIMUM
を下回る場合は集計しないことにしている。
だが、それが1要素でしかないのであれば集計に加えてもいいわけだ。
今回は両方ともやった。 キャスト平均値別の偏差値を出すときは、キャスト平均値だけを使って算出しているが、影響力を出すときは全作品のスコアを使っている。
ただ、ちゃんと偏差値計算を導入した割には今回はあんまり使っていない。
基本的な考え方
おそらく最も重要になるのは、「全体平均と直近平均」だと思う。
私の実データに基づくと、柚木つばめさんは評価済み11作品の平均が4.0だが、直近評価済み6作品の平均は4.5である。
これは言葉に直せば、「全体的な印象として柚木つばめさんの出演作を高く評価しているが、最近購入した作品では全体の印象以上に良いと感じている」という意味になる。
「今アツい」を表現するのに最近評価が高い以外に何かあるか。 それはやはり、購入頻度だろう。
直近の購入で購⼊している数が高いのは、今ハマっていると考えていいのではないだろうか。
これについてはおおまかに2つのアプローチがある。 「全体の購入数に対して最近の購入数が多い」という評価か、「最近の購入の中で登場頻度が高い」という評価かだ。
とりあえず私は後者を採用し、btime
ベースで直近15%の登場頻度にアドバンテージを与えるようにした。
これはキャストデータさえ埋まっていれば判定できるため、評価済み作品に限定していない。
なお、当たり前だが作品数が多ければ多いほど頻出するため、この方法では陽向葵ゅかさんゆ涼花みなせさんのスコアは絶対に高くなる運命にある。 増減の判定を使うのはこれを避けるためだが、あまり意味はなさそうだったので単純に直近の購⼊を見ることにした。
影響力
従来から懸念していたのが、「項目の評価が他の項目との関連性に引っ張られる」である。
以前の記事で次のように述べている:
まず、サークルは起用するキャストにある程度の偏りがあるものであり、これによってサークルの評価が出演者の評価に大きな影響を与える場合がある。
また、キャラ付けという問題があるため、特定のシリーズにおけるこの人が演じるキャラクターが好き、というパターンもあり、必ずしもその人の出演作全般が好きとは限らない。
さらに、作風によって合う合わないの問題から好みが割れてしまうこともある。 例えば、お姉さん役が多い人で、その人のお姉さん役は好きだが、子供っぽい役は好きではない、などだ。
この影響力を計算するのは難しく、そもそも与えられている情報が断片的だというのもある。
だが、明確に与えられている情報で、影響を与えることが明らかなものもある。 サークルとキャストの関係だ。
ここが唯一偏差値をちゃんと使っている要素になっている。
キャストの場合で言うと、キャストの出演作品のサークル項目を当該サークルの平均スコアに置き換える。そして、その平均スコア配列の平均の偏差値が45-55の範囲を逸脱するのであれば、サークルの影響が強いものとしてスコアの高い低いに対する影響を軽減する。1 これは全体データは評価済み全作品を対象にする。
例として私の実データの涼花みなせさんを見てみよう。 評価済みは6作品で、評価は次のとおりである。
{"涼花みなせ"=>[4, 5, 5, 4, 5, 4]}
この6作品のサークルのスコアは以下である。
[4.166666666666667, 4.166666666666667, 4.166666666666667, 3.4285714285714284, 4.166666666666667, 4.166666666666667]
となっている。 まぁ、ここから推測できるように、評価済み6作品中5作品は同一サークルの作品である。
この6作品のサークルの平均スコアは4.0436507936507935
である。
偏差値は51.20994665378309
である。
これを見て、キャストの評価が極端にサークルに引っ張られているということはない、と見ることができる。
なお、「尺度が違うのでは」ということがあると思うが、対象スコアは全作品の中からピックアップされるものではあるので、「影響を受けているかどうか」程度の判定なら間違いにはなりづらいだろう。
「平均スコア帯」というアイディアは活用できず
これを始めるときに考えていたのが、「平均スコア帯を設定し、その上下に多く分布している場合は評価が安定していないという特徴を持っているので、短期的なスコアの高い低いの影響を小さくする」というものだ。
だが、平均スコア帯の設定自体はしたものの、結局使わなかった。
理由は、作品別のスコアが5種類しかないためだ。 このため、3桁精度の小数で帯を設定しても有効なスコアは1つだけとかいうことになって、本当に意味がない。
このアイディアはもっと細かなスコアがつくもののときにとっておこうと思う。
Voice Stat (Maybe you like) と比較する
「全体で高く評価していることと今アツいは連動していないのか?」という疑問が最も重要なところなので、実際に旧来のVoice Statの全体評価と今回の評価を比較してみる。
ますは、VoiceStatのキャストMaybe you like:
========== Maybe you like ==========
柚木つばめ
陽向葵ゅか
こやまはる
逢坂成美
涼花みなせ
スコアの詳細はこんな感じ。
[{:name=>"柚木つばめ", :score=>2603.3054607824283, :length=>11, :mean=>4.0},
{:name=>"陽向葵ゅか", :score=>1283.1429815190477, :length=>12, :mean=>4.0},
{:name=>"こやまはる", :score=>1110.2322364018457, :length=>13, :mean=>3.8461538461538463},
{:name=>"逢坂成美", :score=>853.1487257110714, :length=>9, :mean=>4.111111111111111},
{:name=>"涼花みなせ", :score=>235.94498356270336, :length=>6, :mean=>4.5},
{:name=>"紅月ことね", :score=>74.03725491472005, :length=>7, :mean=>3.5714285714285716},
{:name=>"天知遥", :score=>50.59509321079357, :length=>5, :mean=>4.2},
{:name=>"コトザ", :score=>50.59509321079357, :length=>5, :mean=>4.2},
{:name=>"みもりあいの", :score=>32.791618676664136, :length=>5, :mean=>4.0},
{:name=>"夏野こおり", :score=>31.270369486808345, :length=>4, :mean=>4.25},
{:name=>"乙倉ゅい", :score=>11.703139012673972, :length=>4, :mean=>3.75},
{:name=>"秋野かえで", :score=>8.00578065003284, :length=>4, :mean=>3.5},
{:name=>"御子柴泉", :score=>6.899956679248527, :length=>3, :mean=>3.6666666666666665},
{:name=>"餅梨あむ", :score=>5.731942014651179, :length=>3, :mean=>3.3333333333333335},
{:name=>"ツナうどん", :score=>5.294371095162799, :length=>3, :mean=>3.3333333333333335},
{:name=>"秋山はるる", :score=>3.2053480873535674, :length=>3, :mean=>3.0}]
一方、VoiceStat2のHot Castはこちら。
-*-*-*-*-*-*- HOT Cast -*-*-*-*-*-*-
柚木つばめ [6.68]
涼花みなせ [6.68]
陽向葵ゅか [6.13]
逢坂成美 [5.94]
夏野こおり [5.74]
共通点はあるが、違いも大きい。 「作品が多く平均も高い」は有利要素なので必然的に上位にくるわけだが、ベースになるのが「直近平均」であるならば出演作が多いことはマイナスに働く可能性もそれなりにある。
ただ、結果を見るとどちらもかなり納得感がある。 出演者目当てで買ったもののいまいちパッとしなかった作品の印象がある人はMaybe you likeでは伸びていなかったりするし、Hot castはちゃんと最近好印象だった人が入ってきている。
というか正直なところ、想定よりもうまく行き過ぎた。 本当はもっと考慮しようと思っていた要素はいっぱいある(あと4つくらい考えていた)のだが、これだけでとても納得できる結果が出てしまったので、一旦保留して様子を見ることにした。
これだけのことでいいのなら、非常にシンプルな道理ということになって万々歳だ。
それにしても、「直近作品の平均スコアに、直近の評価と全体評価の比較で係数をかける」ということしかしていないのだが……………………
数の問題
現時点で総作品数は459、うち評価済みは127である。
結構がんばって埋めてるつもりなのだが、サンプル数の足りないキャスト、サークルがかなりあって厳しいと感じている。
キャストの作品数と評価数を見てみると
========== TOP CAST ==========
陽向葵ゅか: 51 [12]
涼花みなせ: 33 [6]
秋野かえで: 32 [4]
柚木つばめ: 29 [11]
こやまはる: 24 [13]
紅月ことね: 22 [7]
天知遥: 22 [5]
逢坂成美: 17 [9]
乙倉ゅい: 16 [4]
みもりあいの: 14 [5]
餅梨あむ: 12 [3]
伊ヶ崎綾香: 11 [1]
御子柴泉: 11 [3]
一之瀬りと: 10 [0]
ということで、データ不足で全然反映できていない状態だ。
また、結構な作品数があるとは思うのだが、30サンプルを越えているのは3名だけ。 1000作品に到達してもまだまだ部分的にしか反映できないと思われるため、個人の特性を分析するのは精度を上げるのがかなり難しい感じがする。
あと、最近情報を埋めることを意識してわざわざ購⼊することが増えているのは良くないと思うので改善したい。