2016-02-24 13 views
5

まず、私はユーザーのアプリケーションの使用履歴をいくつか持っています。例えば私の推薦結果を改善するには?私は暗黙のスパークALSを使用しています


USER1、APP1、3(起動時間)
USER2、APP2、2(起動時間)
USER3、APP1、1(起動時間)

私は基本的に持っています2つの要求:

  1. すべてのユーザーにおすすめのアプリです。
  2. すべてのアプリに似たアプリを推薦します。

私はそれを実装するためにsparkにMLLibのALS(暗黙的)を使用します。最初は、元のデータを使用してモデルをトレーニングしています。結果はひどいです。私はそれは打ち上げ時間の範囲によって引き起こされるかもしれないと思う。そして、打ち上げ時間は1から数千に及ぶ。だから私は元のデータを処理します。スコアは真の状況とより多くの正統化を反映していると思います。

スコア= LT/uMlt + LT/aMlt

モデルを訓練する処理結果であるスコア。
は元のデータの開始時刻です。
uMltは、元のデータのユーザーの平均起動時間です。 uMlt(ユーザーのすべての起動時間)/(このユーザーがこれまでに起動したアプリの数)
aMltは、元のデータのアプリの平均起動時間です。 aMlt(アプリケーションのすべての起動時間)/(このアプリを起動したユーザーの数)
処理後のデータの例を次に示します。

評価(95788,20992,0.14167073369026184)
評価(98696,20992,5.92363166809082)
評価(160020,11264,2.261538505554199)
評価(67904,11264,2.261538505554199)
評価(268430、 11264,0.13846154510974884)
評価(201369,11264,1.7999999523162842)
評価(180857,11264,2.2720916271209717)
評価(217692,11264,1.3692307472229004)
評価(186274,2867 2,2.4250855445861816)
評価(120820,28672,0.4422124922275543)
評価(221146,28672,1.0074234008789062)

私はこれを行って、異なるパッケージ名を持つアプリケーションを集約した後、結果が良さそうです。しかし、まだ十分ではありません。
ユーザーと製品の機能は非常に小さく、ほとんどがネガティブです。(

((CompactBuffer(com.youlin.xyzs.shoumeng、com.youlin.xyzs.juhe.shoumeng)):ここ

は、製品の機能、各ラインのための10件の寸法の3行の例であります-4.798973236574966E-7,7.641608021913271E-7,6.040852440492017E-7,2.82689171626771E-7,4.255948056197667E-7,1.815822798789668E-7,5.000047167413868E-7,2.0220664964654134E-7,6.386763402588258E-7,4.289261710255232 E-7))
((CompactBuffer(com.dncfcjaobhegbjccdhandkba.huojia))、( - 4.769295992446132E-5、-1.7072002810891718E-4,2.1351299074012786E-4,1.6345139010809362E-4、-1.4456869394052774E-4,2.3657752899453044E -4,4.508546771830879E-5,2.0895185298286378E-4,2.968782791867852E-4,1.9461760530248284E -4))
((CompactBuffer(com.tern.rest.pron))、( - 1.219763362314552E-5、-2.8371430744300596E-5,2.9869115678593516E-5,2.0747662347275764E-5、-2.0555471564875916E-5,2.632938776514493 E-5,2.934047643066151E-6,2.296348611707799E-5,3.8075613701948896E-5,1.2197584510431625E-5))

ここでは、各ラインのための10件の寸法ユーザー機能の3行の例である:

(96768、( - 0.0010857731103897095、-0.001926362863741815,0.0013726564357057214,6.345533765852451E-4、-9.048808133229613E-4、-4.1544197301846E-5,0.0014421759406104684、-9.77902309386991E-5,0.0010355513077229261、-0.0017878251383081079))
(97280、( - 0.0022841691970825195、-0.0017134940717369318,0.001027365098707378,9.437055559828877E-4、-0.0011165080359205604,0.0017137592658400536,9.713359759189188E-4,8.947265450842679E-4,0.0014328152174130082、-5.738904583267868E-4))
(97792、( - 0.0017802991205826402、-0.003464450128376484,0.002837196458131075,0.0015725698322057724、-0.0018932095263153315,9.185600210912526E-4,0.0018971719546243548,7.250450435094535E-4,0.0027060359716415405、-0.0017731878906488419))

私は機能のドット積を取得するときに、あなたはどのように小さな想像することができますユーザ項目行列の値を計算するためのベクトル。ここ

私の質問は:

  1. は、推薦結果を改善するための他の方法はありますか?
  2. 自分の機能が正しいように見えますか、何か問題がありますか?
  3. 元の起動時間を処理する私のやり方(スコアに変換)は正しいですか?

ここにいくつかのコードを入れました。これは絶対にプログラムの質問です。しかし、おそらく数行のコードで解決することはできません。

val model = ALS.trainImplicit(ratings, rank, iterations, lambda, alpha) 
print("recommendForAllUser") 
val userTopKRdd = recommendForAllUser(model, topN).join(userData.map(x => (x._2._1, x._1))).map { 
    case (uid, (appArray, mac)) => { 
    (mac, appArray.map { 
     case (appId, rating) => { 
     val packageName = appIdPriorityPackageNameDict.value.getOrElse(appId, Constants.PLACEHOLDER) 
     (packageName, rating) 
     } 
    }) 
    } 
} 
HbaseWriter.writeRddToHbase(userTopKRdd, "user_top100_recommendation", (x: (String, Array[(String, Double)])) => { 
    val mac = x._1 
    val products = x._2.map { 
    case (packageName, rating) => packageName + "=" + rating 
    }.mkString(",") 
    val putMap = Map("apps" -> products) 
    (new ImmutableBytesWritable(), Utils.getHbasePutByMap(mac, putMap)) 
}) 

print("recommendSimilarApp") 
println("productFeatures ******") 
model.productFeatures.take(1000).map{ 
    case (appId, features) => { 
    val packageNameList = appIdPackageNameListDict.value.get(appId) 
    val packageNameListStr = if (packageNameList.isDefined) { 
     packageNameList.mkString("(", ",", ")") 
    } else { 
     "Unknow List" 
    } 
    (packageNameListStr, features.mkString("(", ",", ")")) 
    } 
}.foreach(println) 
println("productFeatures ******") 
model.userFeatures.take(1000).map{ 
    case (userId, features) => { 
    (userId, features.mkString("(", ",", ")")) 
    } 
}.foreach(println) 
val similarAppRdd = recommendSimilarApp(model, topN).flatMap { 
    case (appId, similarAppArray) => { 
    val groupedAppList = appIdPackageNameListDict.value.get(appId) 
    if (groupedAppList.isDefined) { 
     val similarPackageList = similarAppArray.map { 
     case (destAppId, rating) => (appIdPriorityPackageNameDict.value.getOrElse(destAppId, Constants.PLACEHOLDER), rating) 
     } 
     groupedAppList.get.map(packageName => { 
     (packageName, similarPackageList) 
     }) 
    } else { 
     None 
    } 
    } 
} 
HbaseWriter.writeRddToHbase(similarAppRdd, "similar_app_top100_recommendation", (x: (String, Array[(String, Double)])) => { 
    val packageName = x._1 
    val products = x._2.map { 
    case (packageName, rating) => packageName + "=" + rating 
    }.mkString(",") 
    val putMap = Map("apps" -> products) 
    (new ImmutableBytesWritable(), Utils.getHbasePutByMap(packageName, putMap)) 
}) 

UPDATE:
私は紙(「暗黙のフィードバックデータセットのための協調フィルタリング」)を読んだ後、私のデータについて何か新しいことを発見しました。私のデータは、このペーパーで説明されているIPTVデータセットと比較して疎です。

紙30万(ユーザ)17000(製品)3200万(データ)
鉱山30万(ユーザ)31,000(製品)70万(データ)

中のSOユーザーアイテムマトリクス紙のデータセットは0で埋められています。00627 =(32,000,000/300,000/17,000)。データセットの比率は0.0000033です。私はそれが私のユーザアイテムマトリックスが2000年に紙のそれよりも疎であることを意味すると思います。
これは悪い結果につながるはずですか?それを改善する方法は?

+0

問題から何か更新しましたか?私にも同様の問題があります。 –

答えて

0

あなたは試してみてください二つのものがあります。

  1. は、ユーザベクトルあたり平均0、分散を持つようにあなたのデータを標準化。これは多くの機械学習の共通ステップです。これは、外れ値の影響を減らすのに役立ち、ゼロに近い値になります。
  2. アプリが1つしかないすべてのユーザーを削除します。あなたがこれらのユーザーから学ぶ唯一のことは、アプリスコアの「平均」価値がやや良いことです。彼らはあなたが本当に欲しいものである意味のある関係を学ぶのを助けません。

モデルからユーザーを削除すると、ユーザーIDを入力することでモデルから直接そのユーザーの推奨を得ることができなくなります。ただし、いずれにしても1つのアプリの評価しかありません。だから、製品マトリックス上でKNN検索を実行して、ユーザーのapps = recommendationと最も類似したアプリケーションを見つけることができます。

関連する問題