KeyError 反向 HashMap – Python 简单协同 KNN 模型

我的推荐系统在为某些啤酒推荐时运行得很好,但有时候会返回 KeyError。我不知道为什么会发生这种情况?

总是发生在尝试为同一项目推荐时,所以可能与 HashMap 代码或反向 HashMap 有关。

运行脚本时 KeyError 的图片

**图片的 **

代码

import osimport timeimport gcimport argparseimport pandas as pdfrom scipy.sparse import csr_matrixfrom sklearn.neighbors import NearestNeighborsfrom fuzzywuzzy import fuzzclass KnnRecommender:    """    这是一个基于项目的协同过滤推荐器,由 sklearn 实现 KNN    """    def __init__(self, path_beers, path_tastingprofiles):        """        推荐器需要数据路径:啤酒数据和品尝档案数据        参数        ----------        path_movies: str, 啤酒数据文件路径        path_ratings: str, 品尝档案数据文件路径        """        self.path_beers = path_beers        self.path_tastingprofiles = path_tastingprofiles        self.model = NearestNeighbors()    def set_model_params(self, n_neighbors, algorithm, metric, n_jobs=None):        """        为 sklearn.neighbors.NearestNeighbors 设置模型参数        参数        ----------        n_neighbors: int, 可选(默认 = 5)        algorithm: {'auto', 'ball_tree', 'kd_tree', 'brute'}, 可选        metric: string or callable, 默认 'minkowski', 或以下之一            ['cityblock', 'cosine', 'euclidean', 'l1', 'l2', 'manhattan']        n_jobs: int or None, 可选(默认=None)        """        if n_jobs and (n_jobs > 1 or n_jobs == -1):            os.environ['JOBLIB_TEMP_FOLDER'] = '/tmp'        self.model.set_params(**{            'n_neighbors': n_neighbors,            'algorithm': algorithm,            'metric': metric,            'n_jobs': n_jobs})    def _prep_data(self):        """        为推荐器准备数据        1. 啤酒-品尝档案 scipy 稀疏矩阵        2. 啤酒到啤酒-品尝档案 scipy 稀疏矩阵行索引的 HashMap        """        # 读取数据        df_beers = pd.read_csv(            os.path.join(self.path_beers),            usecols=['beerID', 'name', 'beertypeID'],            dtype={'beerID': 'int32', 'name': 'str', 'beerID': 'int32'})        df_tastingprofiles = pd.read_csv(            os.path.join(self.path_tastingprofiles),            usecols=['beerID', 'malty', 'sweet', 'sour', 'hoppy', 'bitter', 'fruity'],            dtype={'beerID': 'int32', 'malty': 'float32', 'sweet': 'float32', 'sour': 'float32', 'hoppy': 'float32', 'bitter': 'float32', 'fruity': 'float32'})        #过滤啤酒/移除未被评估的啤酒        df_beers_merged = pd.merge(df_tastingprofiles, df_beers, on='beerID')        df_beers = df_beers_merged.drop(['malty', 'sweet', 'sour', 'hoppy', 'bitter', 'fruity'], axis=1)        # 透视并创建品尝档案矩阵        df_tastingprofile_features = df_tastingprofiles.set_index('beerID')        # 创建从啤酒名称到索引的映射器        hashmap = {            beer: i for i, beer in            enumerate(list(df_beers.set_index('beerID').loc[df_tastingprofile_features.index].name)) # noqa        }        #将品尝档案特征转换为 scipy 稀疏矩阵        mat_tastingprofile_features = csr_matrix(df_tastingprofile_features.values)        # 清理        del df_beers, df_beers_merged        del df_tastingprofiles, df_tastingprofile_features        return mat_tastingprofile_features, hashmap    def _fuzzy_matching(self, hashmap, fav_beer):        """        通过模糊比率返回最接近的匹配。        如果没有找到匹配,返回 None        参数        ----------        hashmap: dict, 将啤酒名称映射到数据中啤酒的索引        fav_beer: str, 用户输入的啤酒名称        返回        ------        最接近匹配的索引        """        match_tuple = []        # 获取匹配        for name, idx in hashmap.items():            ratio = fuzz.ratio(name.lower(), fav_beer.lower())            if ratio >= 60:                match_tuple.append((name, idx, ratio))        # 排序        match_tuple = sorted(match_tuple, key=lambda x: x[2])[::-1]        if not match_tuple:            print('Oops! 未找到匹配')        else:            print('在我们的数据库中找到了可能的匹配: '                  '{0}\n'.format([x[0] for x in match_tuple]))            return match_tuple[0][1]    def _inference(self, model, data, hashmap,                   fav_beer, n_recommendations):        """        根据用户输入的啤酒返回前 n 个相似的啤酒推荐        参数        ----------        model: sklearn 模型, knn 模型        data: 啤酒-品尝档案矩阵        hashmap: dict, 将啤酒名称映射到数据中啤酒的索引        fav_beer: str, 用户输入的啤酒名称        n_recommendations: int, 前 n 个推荐        返回        ------        前 n 个相似啤酒推荐的列表        """        # 拟合        model.fit(data)        # 获取输入啤酒的索引        print('您输入的啤酒:', fav_beer)        idx = self._fuzzy_matching(hashmap, fav_beer)        # 推理        print('推荐系统开始进行推理')        print('......\n')        t0 = time.time()        distances, indices = model.kneighbors(            data[idx],            n_neighbors=n_recommendations+1)        # 获取推荐的原始索引列表        raw_recommends = \            sorted(                list(                    zip(                        indices.squeeze().tolist(),                        distances.squeeze().tolist()                    )                ),                key=lambda x: x[1]            )[:0:-1]        print('我的系统花了 {:.2f}s 进行推理 \n\              '.format(time.time() - t0))        # 返回推荐(movieId, distance)        return raw_recommends    def make_recommendations(self, fav_beer, n_recommendations):        """        进行前 n 个啤酒推荐        参数        ----------        fav_beer: str, 用户输入的啤酒名称        n_recommendations: int, 前 n 个推荐        """        # 获取数据        mat_tastingprofile_features, hashmap = self._prep_data()        # 获取推荐        raw_recommends = self._inference(            self.model, mat_tastingprofile_features, hashmap,            fav_beer, n_recommendations)        # 打印结果        reverse_hashmap = {v: k for k, v in hashmap.items()}        print('为 {} 的推荐:'.format(fav_beer))        for i, (idx, dist) in enumerate(raw_recommends):            #reverse_hashmap[idx]            print('{0}: {1}, 距离为 {2}'.format(i+1,reverse_hashmap[idx], dist))def parse_args():    parser = argparse.ArgumentParser(        prog="啤酒推荐器",        description="运行 KNN 啤酒推荐器")    parser.add_argument('--path', nargs='?', default='',                         help='输入数据路径')    parser.add_argument('--beer_filename', nargs='?', default='beer.csv',                        help='提供啤酒文件名')    parser.add_argument('--tastingprofile_filename', nargs='?', default='tastingprofile.csv',                        help='提供品尝档案文件名')    parser.add_argument('--beer_name', nargs='?', default='',                        help='提供您喜欢的啤酒名称')    parser.add_argument('--top_n', type=int, default=10,                        help='前 n 个啤酒推荐')    return parser.parse_args()    if __name__ == '__main__':    # 获取参数    args = parse_args()    data_path = args.path    beer_filename = args.beer_filename    tastingprofile_filename = args.tastingprofile_filename    beer_name = args.beer_name    top_n = args.top_n    # 初始化推荐系统    recommender = KnnRecommender(    os.path.join(data_path, beer_filename),    os.path.join(data_path, tastingprofile_filename))    recommender.set_model_params(20, 'brute', 'cosine', -1)    # 进行推荐    recommender.make_recommendations(beer_name, top_n)

回答:

我已经修复了它。我发现当我在 HashMap 中使用名称作为值时,重复项会自动被移除。所以 HashMap 比完整的数据库列表要小。我通过在推荐算法中使用数据之前从数据集中移除重复项来解决这个问题。

我将向您展示我使用 pandas Dataframes 合并和 drop_duplicates 的简单修复方法。

#从啤酒数据集中移除重复项        df_beers_noduplicates = df_beers.drop_duplicates(subset='name', keep='first', inplace=False)        df_beers_merged = pd.merge(df_tastingprofiles, df_beers_noduplicates, on='beerID')        df_beers = df_beers_merged.drop(['malty', 'sweet', 'sour', 'hoppy', 'bitter', 'fruity'], axis=1)        df_tastingprofiles = df_beers_merged.drop(['name'], axis=1)

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注