在c#中表示评级矩阵的最佳方式

本文关键字:最佳 方式 表示 | 更新日期: 2023-09-27 18:12:13

我正在尝试用c#构建一个推荐系统。我想知道什么是最好的方式来表示一个矩阵的评级。每行表示用户,每列表示电影。例如,第二行和第四列中的单元格将表示第二个用户对第四部电影的评分(例如,1到5星)。

值得一提的是,我将需要对数据进行一些矩阵代数运算,如乘法转置等。当然,矩阵也是稀疏的,因为不是所有的用户都会给所有的电影打分。

最明显的方法是一个包含用户名字符串的数组、一个包含电影的字符串数组和一个包含评分的2d整数数组:

string[] users = new string[5] { "David", "Matt", "Ben", "Chris", "Torri" };
string[] movies = new string[4] { "Titanic", "X-men", "Snatch", "Speed"};
ratings = new int[5, 4];

问题是什么是最好的数据结构?感谢所有!

在c#中表示评级矩阵的最佳方式

最好的方法是使用面向对象的编程方法:

// Note I'm going to use HashSet<T> everywhere because both movies and
// users should be unique in their respective collections
public class User 
{
    public sealed class UserEqualityComparer : IEqualityComparer<User>
    {
          public bool Equals(User a, User b)
          {
              return a != null && b != null && a.Name == b.Name;
          }
          public int GetHashCode(User some)
          {
              return some.Name.GetHashCode();
          }
    }

     public string Name { get; set; }
     // C# 6 expression bodied properties!!!!
     public HashSet<Movie> LikesMovies { get; set; } = new HashSet<Movie>(new Movie.MovieEqualityComparer());
}
public class Movie
{   
    public sealed class MovieEqualityComparer : IEqualityComparer<Movie>
    {
          public bool Equals(Movie a, Movie b)
          {
              return a != null && b != null && a.Name == b.Name;
          }
          public int GetHashCode(Movie some)
          {
              return some.Name.GetHashCode();
          }
    }
     public string Name { get; set; }
     // C# 6 expression bodied properties!!!!
     public HashSet<User> UsersWhoLikeIt { get; set; } = new HashSet<User>(new User.UserEqualityComparer());
}

现在如果你想表示一个叫John的人喜欢星际迷航你可以这样做:

HashSet<Movie> movies = new HashSet<Movie>(new Movie.MovieEqualityComparer())
{
    new Movie { Name = "Star Trek" },
    new Movie { Name = "Star Wars" }
};
HashSet<User> users = new HashSet<User>(new User.UserEqualityComparer())
{
    new User { Name = "John" },
    new User { Name = "Jack" }
};
// Now an user likes a movie:
Movie movie = movies.Single(some => some.Name == "Star Trek");
User user = users.Single(some => some.Name == "John");
// You need to associate both sides of the whole M-N association:
// A movie can be liked by many users and an user can like many movies...
movie.UsersWhoLikeIt.Add(user);
user.LikesMovies.Add(movie);

一旦你用对象填充了你的对象图,你只需要使用LINQ和它的许多扩展方法,以及自己的HashSet<T>有趣的方法,如交集。

使用OOP有一个很大的优势:你可以使用OR/M将这个域映射到一个关系数据库并存储你的数据,或者你可以直接将它存储在NoSQL数据库中。

请注意,我已经提供了一个实现like 的示例。评分将由其他实体 moviating 表示,您可以根据需要添加属性来表示您的评分系统。

如果你想做矩阵代数那么就像你有它一样但你不需要1-5等级的int

ratings = new byte[5, 4];

使用0表示非额定或字节?

你不能(很容易地)调整数组的大小
因此,以非矩阵方式在数据库中保存用户,电影和用户评级
然后调整数组的大小并从数据库中加载

ratingtable:    
int userID  PK   
int movieID  PK   
byte rating

在表中不存储null或0作为评级

我不确定矩阵是最好的方法,但我也在这里假设您只是存储评级。

我不确定最好的方法,但是表示用户电影评分的更好方法是分别对用户、电影和评分进行建模。之后,您可以选择将值序列化到文件中,或者与数据库接口,或者您可以找到的任何其他数据持久性解决方案。

public class User
{
    public string Name { get; set; }
}
public class Movie
{
    public string Title { get; set; }
}
public class Rating
{
    public User RatingUser { get; set; }
    public Movie RatingMovie { get; set; }
}

接下来,动态地将User、Movie和Rating模型添加到简单集合(如列表)中。您可以使用LINQ查询这些集合。此外,模型的可伸缩性也会更好(例如,将User的名字重构为姓和名,或者在Title中添加一个等级)。下面是一个使用列表的示例,并从您提供的代码中添加用户和电影值。

public List<User> UserList = new List<User>();
public List<Movie> MovieList = new List<Movie>();
public List<Ratings> RatingList = new List<Rating>();
UserList.Add(new User() { Name = "David"} );
UserList.Add(new User() { Name = "Matt"} );
UserList.Add(new User() { Name = "Ben"} );
UserList.Add(new User() { Name = "Chris"} );
UserList.Add(new User() { Name = "Torri"} );
MovieList.Add(new User() { Title = "Titanic"} );
MovieList.Add(new User() { Title = "X-men"} );
MovieList.Add(new User() { Title = "Snatch"} );
MovieList.Add(new User() { Title = "Speed"} );