Как улучшить результат моей рекомендации? Я использую неявный искровой ALS

Во-первых, у меня есть история использования пользовательского приложения.

Например:
пользователь1, приложение1, 3(время запуска)
пользователь2, приложение2, 2(время запуска)
пользователь3, приложение1, 1(время запуска)

У меня есть два основных требования:

  1. Порекомендуйте какое-нибудь приложение для каждого пользователя.
  2. Рекомендовать подобное приложение для каждого приложения.

Поэтому я использую ALS (неявный) MLLib на spark для его реализации. Сначала я просто использую исходные данные для обучения модели. Результат ужасен. Я думаю, что это может быть вызвано диапазоном времени запуска. И диапазон времени запуска от 1 до тысячи. Поэтому я обрабатываю исходные данные. Я думаю, что оценка может отражать истинную ситуацию и больше регуляризации.

оценка = lt / uMlt + lt / aMlt

score — результат процесса обучения модели.
lt — время запуска в исходных данных.
uMlt — среднее время запуска пользователем в исходные данные. uMlt(все времена запуска пользователя) / (количество приложений, когда-либо запущенных этим пользователем)
aMlt — среднее время запуска приложения в исходных данных. aMlt(все времена запуска приложения) / (количество пользователей, когда-либо запускавших это приложение)
Вот пример данных после обработки.

Рейтинг (95788,20992,0,14167073369026184)
Рейтинг (98696,20992,5,9236316809082)
(160020,11264,2261538505554199)
RATING. 0.13846154510974884)
Rating(201369,11264,1.7999999523162842)
Rating(180857,11264,2.2720916271209717)
Rating(217692,11264,1.3692307472229004)
Rating(186274,28672,2.4250855445861816)
Rating (120820,28672,0,4422124922275543)
Рейтинг(221146,28672,1,0074234008789062)

После того, как я сделал это и объединил приложения с другим именем пакета, результат кажется лучше. Но все же недостаточно хорошо.
Я считаю, что функции пользователей и продуктов настолько малы, и большинство из них отрицательные.

Вот 3-строчный пример характеристик продуктов, 10 параметров для каждой строки:

((CompactBuffer(com.youlin.xyzs.shoumeng, com.youlin.xyzs.juhe.shoumeng)), (-4.798973236574966E-7,-7.641608021913271E-7,6.040852440492017E-7,2.8268917716E11-574826748.5757626748.57 -7,1.815822798789668E-7,5.000047167413868E-7,2.0220664964654134E-7,6.386763402588258E-7,-4.289261710255232E-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) ) 5,2,934047643066151Э-6,2,296348611707799Э-5,3,8075613701948896Э-5,1,2197584510431625Э-5))

Вот 3-строчный пример пользовательских функций, 10 измерений для каждой строки:

(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))
})  

ОБНОВЛЕНИЕ :
Я нашел кое-что новое о своих данных после прочтения статьи («Совместная фильтрация наборов данных с неявной обратной связью»). Мои данные слишком скудны по сравнению с набором данных IPTV, описанным в документе.

Paper: 300 000 (пользователи) 17 000 (продукты) 32 000 000 (данные)
Mine: 300 000 (пользователи) 31 000 (продукты) 700 000 (данные)

Таким образом, матрица пользовательских элементов в наборе данных статьи была заполнена 0,00627 = (32 000 000 / 300 000 / 17 000). Коэффициент моего набора данных составляет 0,0000033. Я думаю, это означает, что моя матрица пользовательских элементов в 2000 раз меньше, чем в газете.
Должно ли это привести к плохому результату? И как его улучшить?


person yyforever1988    schedule 24.02.2016    source источник
comment
Были ли у вас какие-либо обновления по вашей проблеме? У меня аналогичная проблема.   -  person Mpizos Dimitris    schedule 01.04.2016


Ответы (1)


Есть две вещи, которые вы должны попробовать:

  1. Стандартизируйте свои данные, чтобы они имели нулевое среднее значение и единичную дисперсию на пользовательский вектор. Это обычный шаг во многих машинных обучениях. Это помогает уменьшить влияние выбросов, которые приводят к значениям, близким к нулю, которые вы видите.
  2. Удалите всех пользователей, у которых есть только одно приложение. Единственное, что вы узнаете от этих пользователей, — это немного лучшее «среднее» значение оценок приложения. Однако они не помогут вам научиться каким-либо значимым отношениям, чего вы действительно хотите.

Удалив пользователя из модели, вы потеряете возможность получить рекомендацию для этого пользователя непосредственно из модели, указав идентификатор пользователя. Тем не менее, у них в любом случае есть только один рейтинг приложения. Таким образом, вы можете вместо этого запустить поиск KNN по матрице продуктов, чтобы найти приложения, наиболее похожие на приложения пользователей = рекомендации.

person Ben Horsburgh    schedule 27.06.2017
comment
почему вы удаляете пользователей, у которых есть только одно приложение? не понимаю вашего обоснования - person enneppi; 04.10.2020
comment
Пользователи только с одним приложением (после стандартизации, как указано выше) будут иметь 100% или максимальное значение для одного столбца, а запись во всех остальных столбцах будет равна 0. Это не только увеличит разреженность, но и будет действовать как выбросы. Следовательно, в некотором смысле удаление этих пользователей устраняет шумы в вашем наборе данных, что приводит к лучшему обучению. - person Satyam; 10.01.2021