TransWikia.com

CoPurchase Recommendation engine returns NaN

Stack Overflow Asked by NicoJuicy on January 13, 2021

My dataset contains about 100 k entries with 800 products. When i try to predict possible matches, it returns NaN for the most popular products sold ( so they should have the most entries).

I’m also transforming the ProductId/CoPurchaseProductId ( Guid) to string to use them.

Can anyone point out if i’m doing something wrong or if my dataset would be too small.

var mlContext = new MLContext();

IDataView traindata = mlContext.Data.LoadFromEnumerable(data: productEntries);

// Your data is already encoded so all you need to do is specify options for MatrixFactorizationTrainer with a few extra hyper parameters
// LossFunction, Alpha, Lambda and a few others like K and C as shown below and call the trainer. 
MatrixFactorizationTrainer.Options options = new MatrixFactorizationTrainer.Options();
options.MatrixColumnIndexColumnName = nameof(ProductEntry.ProductIdEncoded);
options.MatrixRowIndexColumnName = nameof(ProductEntry.CoPurchaseProductIdEncoded);
options.LabelColumnName = nameof(ProductEntry.Label);
options.LossFunction =  MatrixFactorizationTrainer.LossFunctionType.SquareLossOneClass;
options.Alpha = 0.01;
options.Lambda = 0.025;

// For better results use the following parameters
options.ApproximationRank = 100;
options.C = 0.00001;

var dataProcessLine = mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: nameof(ProductEntry.ProductIdEncoded), inputColumnName: nameof(ProductEntry.ProductId))
.Append(mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: nameof(ProductEntry.CoPurchaseProductIdEncoded), inputColumnName: nameof(ProductEntry.CoPurchaseProductId)));


// Step 4: Call the MatrixFactorization trainer by passing options.
var est = dataProcessLine.Append( mlContext.Recommendation().Trainers
.MatrixFactorization(options: options)) ;

// STEP 5: Train the model fitting to the DataSet
ITransformer model = est.Fit(input: traindata);


var predictionEngine = mlContext.Model.CreatePredictionEngine<ProductEntry, CoPurchasePrediction>(transformer: model);

//Manual test of the prediction
var allProducts = Products.Where(p => p.ActiveState > 0).ToList();
foreach (var popularProduct in mostPopularProducts.Take(5))
{
var product = allProducts.Where(p  => p.Id == popularProduct.Id ).FirstOrDefault();

var label = SplitByLanguageHelper.Split(product.Title);


var top5 = allProducts.Where(p => p.Id != product.Id)
    .Select(p => Prediction.GetPrediction(predictionEngine, product.Id, p.Id))
    .OrderByDescending(p => p.Score)
    .Take(5).ToList();
var result = top5.Select(prediction => new
{
    Score = prediction.Score,
    OrigProductIdLabel= SplitByLanguageHelper.Split(allProducts.Where(dl => dl.Id == prediction.ProductId).FirstOrDefault().Title),
    CoProductIdLabel = SplitByLanguageHelper.Split(allProducts.Where(dl => dl.Id == prediction.CoPurchaseProductId).FirstOrDefault().Title)

}).ToList();//all return a NaN score :(

result.Dump($"Predictions from {SplitByLanguageHelper.Split(product.Title)}");

}

public static class Prediction
{
    public static ProductCoPurchasePrediction GetPrediction(PredictionEngine<ProductEntry, CoPurchasePrediction> predictionEngine, Guid productId, Guid coPurchaseProductId)
{
        CoPurchasePrediction prediction = predictionEngine.Predict(
    new ProductEntry { ProductId = productId.ToString(), CoPurchaseProductId = coPurchaseProductId.ToString() });

        return new ProductCoPurchasePrediction
        {
            ProductId = productId,
            CoPurchaseProductId = coPurchaseProductId,
            Score = prediction.Score
    };
}
}


public class CoPurchasePrediction
{
/// <summary>
/// Gets or sets the score.
/// </summary>
/// <value>The score.</value>
public float Score { get; set; }
}

public class ProductEntry
{
/// <summary>
/// Gets or sets the co purchase product identifier.
/// </summary>
/// <value>The co purchase product identifier.</value>
//[KeyType(262111)]
//[NoColumn] 
public string CoPurchaseProductId { get; set; }

[KeyType(262111)]
public UInt32 CoPurchaseProductIdEncoded { get; set; }

public float Label { get; set; }

public string ProductId { get; set; }

[KeyType(262111)]
public UInt32 ProductIdEncoded { get; set; }

public override string ToString()
{
    return $"Prod: {ProductId}, CoPurchase: {CoPurchaseProductId}"; 
}
}

public class ProductCoPurchasePrediction
{

public Guid CoPurchaseProductId { get; set; }


public Guid ProductId { get; set; }

public float Score { get; set; }
}

public static class SplitByLanguageHelper
{
public static string Split(string text)
{
    if (string.IsNullOrEmpty(text)) return "";

    int firstChar = text.IndexOf("<NL>");
    int lastChar = text.IndexOf("</NL>");

    return text.Substring(firstChar + 4, lastChar - (firstChar + 4));
}

}

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP