【问题标题】:(ML.NET) How to train a dataset that doesn't contain labels(ML.NET) 如何训练不包含标签的数据集
【发布时间】:2020-01-13 05:25:57
【问题描述】:

对于网上商店,我想创建一个模型,根据某人的愿望清单上的内容提供建议:“某人的愿望清单上有 X,我们也推荐 Y”场景。问题是,由于缺少我的数据集中没有的适当标签或完全缺乏足够的数据,培训师无法工作。这会导致不准确的数据或 float.NAN 的预测分数(所有或大多数分数最终都是这样)

我拥有所有现有的心愿单以及随后的 ProfileId 和 ItemId(都是整数)。这些被分组在 ProfileID-ItemID 组合中(代表愿望清单上的一个项目,因此拥有 3 个项目的用户将有 3 个组合)。总的来说,我可以为 16.000 个用户和 50.000 个项目使用大约 150.000 种组合。仅出现在单个愿望清单上(或根本不出现)的项目或仅在其愿望清单中包含一个项目的用户将从训练数据中排除(上述数字已被过滤)。如果我愿意,我可以添加额外的数据列,表示项目所属的类别(玩具、书籍等)、价格和其他元数据。

我没有评级,因为网上商店不使用这些评级。因此,我不能用它们来表示“标签”

public class WishlistItem
{
    // these variables are either uint32 or a Single (float) based on the training algorithm.
    public uint ProfileId;
    public uint ItemId; 
    public float Label;
}

我认为我需要解决这个问题:

三者的组合或其中之一:

1) 我需要使用不同的教练。如果是这样,哪个最适合?

2) 我需要为 Label 变量插入不同的值。如果有,应该如何生成?

3) 我需要生成不同的“假”数据集来填充训练数据。如果有,应该如何生成?

对问题的解释以及解决问题的失败尝试

我尝试使用不同的训练器解析数据,以查看最适合我的数据集的方法:FieldAwareFactorizationMachineMatrixFactorizationMachineOLSTrainer时间>。我还尝试将 MatrixFactorizationMachine 用于 LossFunctionType.SquareLossOneClass,而不是插入愿望清单上 ItemIds 的 ProfileID-ItemID 组合。 (例如,存在 3 件商品的愿望清单中的 item1-item2、item2-item3、item1-item3)

这些机器基于其后续教程中的信息:

这是其中一个管道的示例,其他管道非常相似:

string profileEncoded = nameof(WishlistItem.ProfileId) + "Encoded";
string itemEncoded = nameof(WishlistItem.ItemId) + "Encoded";
// the Matrix Factorization pipeline
  var options = new MatrixFactorizationTrainer.Options {
                MatrixColumnIndexColumnName = profileEncoded,
                MatrixRowIndexColumnName = itemEncoded,
                LabelColumnName = nameof(WishlistItem.Label),
                NumberOfIterations = 100,
                ApproximationRank = 100
            };

            trainerEstimator = Context.Transforms.Conversion.MapValueToKey(outputColumnName: profileEncoded, inputColumnName: nameof(WishlistItem.ProfileId))
                       .Append(Context.Transforms.Conversion.MapValueToKey(outputColumnName: itemEncoded, inputColumnName: nameof(WishlistItem.ItemId)))
                            .Append(Context.BinaryClassification.Trainers.FieldAwareFactorizationMachine(new string[] { "Features" }));

为了缓解缺少标签的问题,我尝试了几种解决方法:

  • 将它们留空(0f 浮点值)
  • 使用 itemid、profileid 或两者组合的哈希码
  • 计算包含特定 itemid 或 profileid 的项目数量,还可以操纵该数字以创建更少的极端值,以防一个项目被表示数百次。 (使用平方根或对数函数,创建Label = Math.Log(amountoftimes);Label = Math.Ceiling(Math.Log(amountoftimes)
  • 对于 FieldAware 机器,其中 Label 是布尔值而不是浮点数,上面的计算用于确定浮点结果是高于平均值还是低于所有项目的平均值

在测试时,我使用以下 2 种可能的方法进行测试,以确定可以为项目“X”创建哪些建议“Y”:

  • 将 ItemID X 与所有现有项目与用户的 ProfileID 进行比较。

List<WishlistItem> predictionsForUser =  profileMatrix.DistinctBy(x => x.ItemID).Select(x => new WishlistItem(userId, x.GiftId, x.Label));

IDataView transformed = trainedModel.Transform(Context.Data.LoadFromEnumerable(predictionsForUser));

CoPurchasePrediction[] predictions = Context.Data.CreateEnumerable<CoPurchasePrediction>(transformed, false).ToArray();

IEnumerable<KeyValuePair<WishlistItem, CoPurchasePrediction>> results = Enumerable.Range(0, predictions.Length).ToDictionary(x => predictionsForUser[x], x => predictions[x]).Where(x => OrderByDescending(x => x.Value.Score).Take(10);


return results.Select(x => x.Key.GiftId.ToString()).ToArray();

  • 将 ItemID X 与其他人的愿望清单上的项目进行比较,其中 X 也存在。这个用于 FieldAware Factorization Trainer,它使用布尔值作为标签。
public IEnumerable<WishlistItem> CreatePredictDataForUser(string userId, IEnumerable<WishlistItem> userItems)
{
    Dictionary<string, IEnumerable<WishlistItem>> giftIdGroups = profileMatrix.GroupBy(x => x.GiftId).ToDictionary(x => x.Key, x => x.Select(y => y));
    Dictionary<string, IEnumerable<WishlistItem>> profileIdGroup = profileMatrix.GroupBy(x => x.ProfileId).ToDictionary(x => x.Key, x => x.Select(y => y));
            profileIdGroup.Add(userId, userItems);

    List<WishlistItem> results = new List<WishlistItem>();

    foreach (WishlistItem wi in userItems)
    {
       IEnumerable<WishlistItem> giftIdGroup = giftIdGroups[wi.GiftId];
       foreach(WishlistItem subwi in giftIdGroup)
       {
           results.AddRange(profileIdGroup[subwi.ProfileId]);
       }
    }

   IEnumerable<WishlistItem> filtered = results.ExceptBy(userItems, x => x.GiftId);

   // get duplicates
   Dictionary<string, float> duplicates = filtered.GroupBy(x => x.GiftId).ToDictionary(x => x.Key, x => giftLabelValues[x.First().GiftId]);
            float max = duplicates.Values.Max();

    return filtered.DistinctBy(x => x.GiftId).Select(x => new WishlistItem(userId, x.GiftId, duplicates[x.GiftId] * 2 > max));
}

但是,无论插入的项目如何,测试数据要么完全或部分不可用(float.NAN),要么总是创建相同的推荐结果(我们建议项目 X 的​​ Y 和 Z)。

使用 testdataview (DataOperationsCatalog.TrainTestData split = Context.Data.TrainTestSplit(data, 0.2)) 评估数据时,它要么以高精度显示有希望的结果,要么在各处显示随机值,并且与我得到的结果不符;高精度仍会导致 float.NAN 或“始终相同”

网上有人指出float.NAN可能是小数据集的结果。作为补偿,我尝试创建“假”数据集;根据现有的 profileid 和 itemid 随机生成的 profile-item 组合(标签为 0f 或 false,其余为 0f+ 或 true)。 (事先检查以排除这些随机的“负”数据不是偶然的“真实”组合集)。然而,这几乎没有效果。

【问题讨论】:

  • 如果你没有标签,那么我不相信任何有监督的机器学习算法会有任何用处。尝试一种无监督算法,例如使用 KMeans 进行聚类。
  • KMeans 似乎不是这样 - 如果我创建一个培训师并为其提供配置文件项目组合并创建 (amountofitems / 100) 集群,那么它仍然总是返回完全相同的数据,无论物品。有没有其他无监督学习算法可以解决这个问题?

标签: c# machine-learning ml.net


【解决方案1】:

我认为您尝试过的任何解决方案都不起作用,因为正如您所指出的,您没有任何标签数据。伪造标签数据也不起作用,因为 ML 算法将使用这个伪造的标签。

我相信您正在寻找的是一类矩阵分解算法。

您的“标签”或“分数”是隐含的——该项目在用户的愿望清单中的事实本身就表明该标签——用户对该项目感兴趣。一类矩阵分解使用这种隐式标签。

阅读这篇文章: https://medium.com/machinelearningadvantage/build-a-product-recommender-using-c-and-ml-net-machine-learning-ab890b802d25

【讨论】:

【解决方案2】:

您正在寻找的是经典的推荐系统解决方案。推荐系统习惯于丢失和稀疏的数据。有很多方法可以解决这个问题,我建议从article 开始。一般来说,推荐系统中有两种方法——基于模型的和基于内存的。根据我的经验,基于模型的方法比基于内存的方法执行得更好。关于不同的模型和解决方案,有一个很好的总结here。查看 Koren 和 Bell here 的矩阵分解解决方案,它在许多情况下都非常有效。

【讨论】:

  • 在我发这篇文章之前,我一直在使用你建议的所有系统; ML.NET 的推荐引擎一次预测一个项目(即使并行完成,这也太费时了),因此 Model.Transform 函数一次执行多个预测,因此使用它的原因。第二篇文章主要讨论的是我一直在使用的用户项目矩阵。最后一个讨论潜在因素方法和面向用户的邻域方法,我也使用过(参见测试部分,其中概述了它们的算法)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-09
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
  • 2016-08-26
相关资源
最近更新 更多