| File: RecommenderUtils.cs | Web Access |
| Project: src\src\Microsoft.ML.Recommender\Microsoft.ML.Recommender.csproj (Microsoft.ML.Recommender) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using Microsoft.ML.Data; using Microsoft.ML.Internal.Utilities; using Microsoft.ML.Runtime; namespace Microsoft.ML.Recommender { internal static class RecommenderUtils { /// <summary> /// Check if the considered data, <see cref="RoleMappedData"/>, contains column roles specified by <see cref="MatrixColumnIndexKind"/> and <see cref="MatrixRowIndexKind"/>. /// If the column roles, <see cref="MatrixColumnIndexKind"/> and <see cref="MatrixRowIndexKind"/>, uniquely exist in data, their <see cref="DataViewSchema.Column"/> would be assigned /// to the two out parameters below. /// </summary> /// <param name="data">The considered data being checked</param> /// <param name="matrixColumnIndexColumn">The schema column as the row in the input data</param> /// <param name="matrixRowIndexColumn">The schema column as the column in the input data</param> /// <param name="isDecode">Whether a non-user error should be thrown as a decode</param> public static void CheckAndGetMatrixIndexColumns(RoleMappedData data, out DataViewSchema.Column matrixColumnIndexColumn, out DataViewSchema.Column matrixRowIndexColumn, bool isDecode) { Contracts.AssertValue(data); CheckRowColumnType(data, MatrixColumnIndexKind, out matrixColumnIndexColumn, isDecode); CheckRowColumnType(data, MatrixRowIndexKind, out matrixRowIndexColumn, isDecode); } /// <summary> /// Returns whether a type is a U4 key of known cardinality, and if so, sets /// <paramref name="keyType"/> to a non-null value. /// </summary> private static bool TryMarshalGoodRowColumnType(DataViewType type, out KeyDataViewType keyType) { keyType = type as KeyDataViewType; return keyType?.Count > 0 && type.RawType == typeof(uint); } /// <summary> /// Checks whether a column kind in a <see cref="RoleMappedData"/> is unique, and its type /// is a <see cref="InternalDataKind.U4"/> key of known cardinality. /// </summary> /// <param name="data">The training examples</param> /// <param name="role">The column role to try to extract</param> /// <param name="col">The extracted schema column</param> /// <param name="isDecode">Whether a non-user error should be thrown as a decode</param> /// <returns>The type cast to a key-type</returns> private static KeyDataViewType CheckRowColumnType(RoleMappedData data, RoleMappedSchema.ColumnRole role, out DataViewSchema.Column col, bool isDecode) { Contracts.AssertValue(data); Contracts.AssertValue(role.Value); const string format2 = "There should be exactly one column with role {0}, but {1} were found instead"; if (!data.Schema.HasUnique(role)) { int kindCount = Utils.Size(data.Schema.GetColumns(role)); if (isDecode) throw Contracts.ExceptDecode(format2, role.Value, kindCount); throw Contracts.Except(format2, role.Value, kindCount); } col = data.Schema.GetColumns(role)[0]; // REVIEW tfinley: Should we be a bit less restrictive? This doesn't seem like // too terrible of a restriction. const string format = "Column '{0}' with role {1} should be a known cardinality U4 key, but is instead '{2}'"; KeyDataViewType keyType; if (!TryMarshalGoodRowColumnType(col.Type, out keyType)) { if (isDecode) throw Contracts.ExceptDecode(format, col.Name, role.Value, col.Type); throw Contracts.Except(format, col.Name, role.Value, col.Type); } return keyType; } /// <summary> /// The column role that is treated as column index in matrix factorization problem /// </summary> public static RoleMappedSchema.ColumnRole MatrixColumnIndexKind => "MatrixColumnIndex"; /// <summary> /// The column role that is treated as row index in matrix factorization problem /// </summary> public static RoleMappedSchema.ColumnRole MatrixRowIndexKind => "MatrixRowIndex"; } }