import pickle import math def calc(book1, book2):#将每个tag看作一个独立的维度,存在置1,否则为0;计算两部作品 tag 向量的余弦值。 cos = 0 book1 = set(book1["tags"]) book2 = set(book2["tags"]) if (math.sqrt(len(book1)) * math.sqrt(len(book2))) != 0: cos = len(book1 & book2)/(math.sqrt(len(book1)) * math.sqrt(len(book2))) else: cos = 0 return cos print("Loading...") with open("ehdataset",'rb') as file:#加载数据集 dataset = pickle.load(file) while True: print('Please enter gid:') gid = input() sample = [item for item in dataset if str(item["gid"]) == gid] if len(sample) == 0: print("Invaild gid! The dataset maximum gid is {0}".format(dataset[-1:][0]["gid"])) continue for i in dataset: i["cos"] = calc(sample[0], i) dataset.sort(key=lambda x:x["cos"], reverse=True) for i in dataset[0:20]: if i["title_jpn"]: print("{0} gid:{1} like:{2} rate:{3}".format(i["title_jpn"],i["gid"],i["Favorited"],i["rating"])) else: print("{0} gid:{1} like:{2} rate:{3}".format(i["title"],i["gid"],i["Favorited"],i["rating"]))
代码中 gid 为 e-hentai 的作品 ID,是唯一的。两部作品在空间中 tag 向量的夹角越小,相似度越高,其夹角余弦值则越大。这段代码实现了在数据集中通过 gid 任选一部作品,通过判断 tag 向量夹角余弦值,推荐相似度最高的 20 部作品。
还可以考虑自己手动键入多个 tag,计算相似度并作推荐,代码我就懒得写了,有兴趣请自行发挥。另外计算向量余弦的时候没有使用 numpy,主要是因为 tag 的总量很大,约 10 万种(绝大部分 tag 出现次数极少)。若生成为 10 万维向量再求值,会浪费大量内存空间,故采取了模拟手算的方法,仅需考虑有效维。
进一步思考,为了提升推荐算法的效果,还可以考虑修改不同 tag 的权重,起到增强偏好、过滤多语言版本等效果。