1前書き

このチュートリアルでは、Javaのhttps://en.wikipedia.org/wiki/Slope__One[Slope One]アルゴリズムについてすべて学びます。

また、Collaborative Filtering(CF)(推奨システムで使用される機械学習手法)の問題に対する実装例も示します。

これは、たとえば、特定の項目に対するユーザーの関心を予測するために使用できます。


2協調フィルタリング

Slope Oneアルゴリズムは、アイテムベースの協調フィルタリングシステムです。

これは完全にユーザーアイテムのランキングに基づいていることを意味します。オブジェクト間の類似性を計算するときには、コンテンツ自体ではなく、ランキングの履歴のみがわかります。次に、この類似性を使用して、データセットに存在しないユーザーとアイテムのペアに対する潜在的なユーザーのランク付けを予測します。

下記のhttps://commons.wikimedia.org/wiki/File:Collaborative__filtering.gif[image]は、特定のユーザーの評価を取得して計算する完全なプロセスを示しています。

リンク:/uploads/Collaborative

filtering

new.gif[]

最初に、ユーザーはシステム内のさまざまな項目を評価します。次に、アルゴリズムは類似度を計算します。その後、システムは、ユーザーがまだ評価していないユーザー項目の評価を予測します。

協調フィルタリングのトピックの詳細については、https://en.wikipedia.org/wiki/Collaborative__filtering[Wikipediaの記事]を参照してください。


3スロープワンアルゴリズム

Slope Oneは、格付けに基づく自明ではないアイテムベースの協調フィルタリングの最も単純な形式として名付けられました。同じアイテムを評価したすべてのユーザーからの情報と、同じユーザーによって評価された他のアイテムからの情報の両方を考慮して、類似性マトリックスが計算されます。

この単純な例では、ストア内のアイテムに対するユーザーのランキングを予測します。

私たちの問題とドメインに対する単純なJavaモデルから始めましょう。


3.1.

Javaモデル


私たちのモデルには二つの主要なオブジェクトがあります – アイテムとユーザーです。

Item

クラスはアイテムの名前を含みます。

private String itemName;

一方、

User

クラスにはユーザー名が含まれています。

private String username;

最後に、データを初期化するために使用される

InputData

クラスがあります。ストアに5つの異なる商品を作成するとしましょう。

List<Item> items = Arrays.asList(
  new Item("Candy"),
  new Item("Drink"),
  new Item("Soda"),
  new Item("Popcorn"),
  new Item("Snacks")
);

さらに、0.0〜1.0のスケールを使用して上記の一部をランダムに評価する3人のユーザーを作成します。0は無関心、0.5は何らかの興味、1.0は完全に興味を表します。データの初期化の結果として、ユーザーのアイテムランキングデータを含む

Map

が得られます。

Map<User, HashMap<Item, Double>> data;


3.2.

違いと頻度行列


利用可能なデータに基づいて、アイテム間の関係とアイテムの出現数を計算します。ユーザーごとに、アイテムの評価を確認します。

for (HashMap<Item, Double> user : data.values()) {
    for (Entry<Item, Double> e : user.entrySet()) {
       //...
    }
}

次のステップでは、アイテムが私たちの行列に存在するかどうかをチェックします。これが初めての場合は、マップに新しいエントリを作成します。

if (!diff.containsKey(e.getKey())) {
    diff.put(e.getKey(), new HashMap<Item, Double>());
    freq.put(e.getKey(), new HashMap<Item, Integer>());
}

最初の行列は、ユーザーの評価の違いを計算するために使用されます。値の値は正または負である可能性があり(評価の差が負になる可能性があるため)、

Double

として格納されます。一方、頻度は

Integer

値として格納されます。

次のステップでは、すべての商品の評価を比較します。

for (Entry<Item, Double> e2 : user.entrySet()) {
    int oldCount = 0;
    if (freq.get(e.getKey()).containsKey(e2.getKey())){
        oldCount = freq.get(e.getKey()).get(e2.getKey()).intValue();
    }

    double oldDiff = 0.0;
    if (diff.get(e.getKey()).containsKey(e2.getKey())){
        oldDiff = diff.get(e.getKey()).get(e2.getKey()).doubleValue();
    }

    double observedDiff = e.getValue() - e2.getValue();
    freq.get(e.getKey()).put(e2.getKey(), oldCount + 1);
    diff.get(e.getKey()).put(e2.getKey(), oldDiff + observedDiff);
}

誰かが以前にアイテムを評価した場合は、頻度カウントを1つ増やします。さらに、アイテムの評価の平均差を確認し、新しい

observedDiff

を計算します。


  • oldDiff



    observedDiff

    の合計をアイテムの新しい値として入れることに注意してください。

最後に、行列内の類似度を計算します。

for (Item j : diff.keySet()) {
    for (Item i : diff.get(j).keySet()) {
        double oldValue = diff.get(j).get(i).doubleValue();
        int count = freq.get(j).get(i).intValue();
        diff.get(j).put(i, oldValue/count);
    }
}

主なロジックは、計算されたアイテムの評価の違いをその発生数で割ることです。そのステップの後、私たちは私たちの最終的な相違マトリックスをプリントアウトすることができます。


3.3.

予測


Slope Oneの主要部分として、既存のデータに基づいて、不足しているすべての評価を予測します。そのためには、ユーザーアイテムの評価と前の手順で計算した差分マトリックスを比較する必要があります。

for (Entry<User, HashMap<Item, Double>> e : data.entrySet()) {
    for (Item j : e.getValue().keySet()) {
        for (Item k : diff.keySet()) {
            double predictedValue =
              diff.get(k).get(j).doubleValue() + e.getValue().get(j).doubleValue();
            double finalValue = predictedValue **  freq.get(k).get(j).intValue();
            uPred.put(k, uPred.get(k) + finalValue);
            uFreq.put(k, uFreq.get(k) + freq.get(k).get(j).intValue());
        }
    }
   //...
}

その後、以下のコードを使用して「きれいな」予測を準備する必要があります。

HashMap<Item, Double> clean = new HashMap<Item, Double>();
for (Item j : uPred.keySet()) {
    if (uFreq.get(j) > 0) {
        clean.put(j, uPred.get(j).doubleValue()/uFreq.get(j).intValue());
    }
}
for (Item j : InputData.items) {
    if (e.getValue().containsKey(j)) {
        clean.put(j, e.getValue().get(j));
    } else {
        clean.put(j, -1.0);
    }
}

より大きいデータセットで考慮するトリックは、大きい頻度値を持つ項目エントリのみを使用することです(たとえば、> 1)。予測が不可能な場合、その値は-1になります。

  • 最後に、非常に重要な注意

    私たちのアルゴリズムが正しく機能した場合、

    ユーザーが評価しなかったアイテムの予測だけでなく、彼が評価したアイテムの繰り返し評価も受け取るはずです** 。これらの繰り返し評価は変更されるべきではありません、そうでなければそれはあなたのアルゴリズムの実装にバグがあることを意味します。


3.4.

ヒント


Slope Oneアルゴリズムに影響を与える主な要因はほとんどありません。精度と処理時間を向上させる方法はいくつかあります。

  • 大規模データの場合は、DB側でユーザーアイテムの評価を取得することを検討してください。

セット
** 人々の興味に応じて、評価フェッチのための時間枠を設定する

時間の経過とともに変化する – 処理に必要な時間も短縮されます
入力データ
** 大きなデータセットを小さなデータセットに分割 – 計算する必要はありません

毎日すべてのユーザーのための予測。ユーザーが予測したアイテムと対話したかどうかを確認してから、翌日の処理キューにユーザーを追加または削除できます。


4結論

このチュートリアルでは、Slope Oneアルゴリズムについて学ぶことができました。

さらに、商品推薦システムのための協調フィルタリング問題を紹介した。

このチュートリアルの完全な実装はhttps://github.com/eugenp/tutorials/tree/master/algorithms-miscellaneous-2[GitHubプロジェクト]にあります。