item_based之python实战

本文介绍了一种基于物品的协同过滤推荐算法的Python实现,对比了基于用户的算法,突出了基于物品算法的优势,如计算性能高、可预先计算保留等。通过具体步骤展示了如何从数据预处理到构建矩阵,最终计算出物品之间的相似度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

基于物品的协同过滤

python实现


基于物品的协同过滤

PS:
为什么不用基于用户的算法
1、冷启动问题,新用户没法推荐
2、用户量大,计算速度慢,并且稀疏矩阵
3、人是善变的,以前喜欢的现在不一定喜欢

基于物品的协同过滤优势! 

计算性能高,通常用户数量远大于物品数量 

可预先计算保留,物品并不善变 

 

python实现

基础数据处理,跟之前一样

不多说

import pandas as pd
import numpy as np
import time
import sqlite3

data_home = './'

triplet_dataset = pd.read_csv(filepath_or_buffer=data_home+'train_triplets.txt', 
                              sep='\t', header=None,nrows=100000 ,
                              names=['user','song','play_count'])

popular_songs = triplet_dataset[['song','play_count']].groupby('song').sum().reset_index()

conn = sqlite3.connect(data_home+'track_metadata.db')
cur = conn.cursor()
cur.execute("SELECT name FROM sqlite_master WHERE type='table'")
cur.fetchall()

track_metadata_df = pd.read_sql(con=conn, sql='select * from songs')
# 去掉重复的
track_metadata_df= track_metadata_df.drop_duplicates(['song_id'])

# 去掉无用的信息
del(track_metadata_df['track_id'])
del(track_metadata_df['artist_mbid'])
del(track_metadata_df['artist_id'])
del(track_metadata_df['duration'])
del(track_metadata_df['artist_familiarity'])
del(track_metadata_df['artist_hotttnesss'])
del(track_metadata_df['track_7digitalid'])
del(track_metadata_df['shs_perf'])
del(track_metadata_df['shs_work'])

# 将这份音乐信息数据和我们之前的播放数据整合到一起
tt = time.time()
triplet_dataset_merged = pd.merge(triplet_dataset, track_metadata_df, how='left', left_on='song', right_on='song_id')
print(time.time()-tt)
这里我们为了节省时间,只选取 nrows=100000

 

我们随机挑选一个用户来进行推荐 

#随机挑选一个用户,找到该用户听过的歌曲
user_data = triplet_dataset_merged[triplet_dataset_merged["user"] == 'b80344d063b5ccb3212f76538f3d9e43d87dca9e']
#找到该用户听过的所有歌曲
user_items = list(user_data['song_id'].unique())
#可以查看len(user_items)=104

#找出表中所有的歌曲
all_items = list(triplet_dataset_merged['song_id'].unique())
#可以查看len(all_items)=44458

我们的目的是找到所有歌曲里面跟用户听过的104首歌相似度最高的前10首歌

#选取用户听过的每首歌,并找出每首歌被哪些其他用户听过
user_songs_users = []        
for i in range(0, len(user_items)):
    item_data = triplet_dataset_merged[triplet_dataset_merged['song_id'] == user_items[i]]
    item_users = set(item_data["user"].unique())
    user_songs_users.append(item_users)

构建矩阵,行列分别为用户听过的歌曲数与数据集中全部歌曲数

cooccurence_matrix = np.matrix(np.zeros(shape=(len(user_items), len(all_items))), float)
cooccurence_matrix.shape=(104, 44458)

计算矩阵

for i in range(0,len(all_items)):
    #计算数据集中每一首歌曲被哪些人听过,找出每首歌用户集
    songs_i_data = triplet_dataset_merged[triplet_dataset_merged['song_id'] == all_items[i]]
    users_i = set(songs_i_data["user"].unique())


    for j in range(0,len(user_items)):       

        #找到上面计算的用户听过的每一首歌的用户集
        users_j = user_songs_users[j]

        #求用户听过的歌与数据集中每首歌的交集
        users_intersection = users_i.intersection(users_j)

        #计算 Jaccard 系数
        if len(users_intersection) != 0:
            #求用户听过的歌与数据集中每首歌的并集
            users_union = users_i.union(users_j)

            cooccurence_matrix[j,i] = float(len(users_intersection))/float(len(users_union))
        else:
            cooccurence_matrix[j,i] = 0
            
    if i%1000==0:
        print(i//1000,str(time.localtime( time.time() ).tm_hour)+":"+str(time.localtime( time.time() ).tm_min))

由于挨个遍历会花费比较长的时间,测算差不多要25分钟

计算数据集中每首歌的平均Jaccard 系数
c = cooccurence_matrix.sum(axis=0)/float(cooccurence_matrix.shape[0])
user_sim_scores = np.array(user_sim_scores)[0].tolist()
#建立索引并排序
sort_index = sorted(((e,i) for i,e in enumerate(list(user_sim_scores))), reverse=True)

建立一个新的dataframe

import pandas
columns = ['user_id', 'song', 'score', 'rank']
df = pandas.DataFrame(columns=columns)

找出前十的相似歌曲

rank = 1 
for i in range(0,len(sort_index)):
    user='b80344d063b5ccb3212f76538f3d9e43d87dca9e'
    if ~np.isnan(sort_index[i][0]) and all_items[sort_index[i][1]] not in user_items and rank <= 10:
        df.loc[len(df)]=[user,all_items[sort_index[i][1]],sort_index[i][0],rank]
        rank = rank+1

if df.shape[0] == 0:
    print("The current user has no songs for training the item similarity based recommendation model.")
    
else:
    print(df)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Andy_shenzl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值