推荐系统个人理解(实践部分)

前一篇文章简单介绍了推荐系统,并列出了常用的推荐算法,这篇主要就如何实现推荐做说明。本来最开始打算用movielens的电影数据来做推荐,数据集下载地址如下,http://grouplens.org/datasets/movielens/,我下的是1m左右的数据,用户6040个,电影3952个,我在构建用户相似度矩阵的时候居然从下午4:00一直跑到晚上2:30,用户相似度需要构建一个6040*6040的矩阵,并且用户与用户之间需要做3952次循环比较,所以时间很长,明显这个例子不适合在我的电脑上做demo。所以自己构建一个demo数据集,结构类似movielen的电影评分。

构造的数据集是这样一种场景,有8个用户对10家公司投递简历,并且有用户对公司投递简历的意愿(数值从1到5,5表示强烈的想去该公司上班)。

推荐思路:
首先根据原始数据集对数据进行预处理,构造一个用户-公司的二维矩阵,二维矩阵对应的值是用户对去该公司工作的意愿,本示例程序采用基于用户的推荐(基于item的推荐和基于用户的推荐思路一样)思路,根据用户-公司二维矩阵,计算用户之间的相似度,以上两个矩阵都可以直接保存成文件(在实际应用中会离线计算然后存数据库或其它存储介质),方便直接调用,根据以上两个矩阵,对用户做推荐。

对用户做推荐的逻辑是,首先找出目标用户没有投递简历的公司,再找出和目标用户相似度最高的5其他用户投简历的公司,并且是目标用户没有投过的,来计算目标公司,我们采用两种方式来实现,一种是返回topn,另外一种是根据工作意愿的评分。

如何判断两个用户相似,我们做如下定义:
A用户投了1,2,3,4
B用户投了2,3,4,5
AB相似度= 用户投了A也投了B/((A投的公司数*B投的公司数据)的平方根)
以上计算的结果AB的相似度为3/4=0.75,如果AB投的公司完全样,AB的相似度为1
相似度并不影响推荐结果。

用户-公司矩阵(横轴代表公司,纵轴代表用户)

用户相似度矩阵
推荐系统个人理解(实践部分)_第1张图片

用户相似度矩阵是个8*8的矩阵,行列都代表用户,对角线元素为0,1B表示的意思是第一个用户和第二个用户的相似度

运行结果如下:

调整用户相似度的数量会影响输出结果,并且采用topn和打分返回的结果也有不同。

相关代码:

#用户公司相关矩阵
def get_user_company_mat():
    user_job_data = load_demo.load_demo_data()
    user_job_mat = np.zeros((8,10))
    #logging.info("生成用户和公司相关矩阵开始")
    for idx, row in user_job_data.iterrows():
        user_id = row["UserID"]
        company_id = row["CompanyID"]
        rating = row["Rating"]
        user_job_mat[user_id-1,company_id-1] = rating
    return user_job_mat

#用户与用户相似性矩阵
def get_user_similarity_mat():
    user_company_mat = user_company.get_user_company_mat()
    user_length, company_length = user_company_mat.shape
    user_sim_mat = np.zeros((user_length, user_length))
    #logging.info("构建生成用户相似性矩阵,用户和用户比较")
    for m in range(0, user_length):
        user_m = user_company_mat[m, :]
        user_m_job_number = 0;
        for item_index in range(0, company_length):
            if user_m[item_index] > 0:
                user_m_job_number = user_m_job_number + 1
        #logging.info("当前用户" + str(m) + "投递的" + str(user_m_job_number) + "份简历")

        for n in range(0, user_length):
            #logging.info("第" + str(m) + "个用户和第" + str(n) + "个用户比较")
            if m == n:
                user_sim_mat[m, n] = 0
            else:
                similarity_item = 0
                user_n_job_number = 0
                user_n = user_company_mat[n, :]
                for i in range(0, company_length):
                    if user_n[i] > 0:
                        user_n_job_number = user_n_job_number + 1
                    if (user_m[i] > 0 and user_n[i] > 0):
                        similarity_item = similarity_item + 1
                #logging.info("当前用户" + str(n) + "投递的" + str(user_n_job_number) + "份简历")
                if (user_m_job_number == 0 or user_n_job_number == 0):
                    user_sim_mat[m, n] = 0
                    user_sim_mat[n, m] = 0
                else:
                    user_sim_mat[m, n] = similarity_item/math.sqrt(user_m_job_number*user_n_job_number)
                    user_sim_mat[n, m] = similarity_item/math.sqrt(user_m_job_number*user_n_job_number)
    #data_frame = pd.DataFrame(user_sim_mat)
    #data_frame.to_csv('user_similarity_mat.csv', index=False, header=False)
    #logging.info("构建生成用户相似性矩阵结束")
    return user_sim_mat

#返回的topN的结果(打分的代码类似)
def user_recommand_by_topn(user_id):
    print("根据TOPN推荐,当前用户ID为"+str(user_id))
    user_job_mat = user_company.get_user_company_mat()
    current_user_job_record = user_job_mat[user_id - 1, :]
    print("当前用户数据",current_user_job_record)
    un_rating_company = []
    for company_id, company_rating in enumerate(current_user_job_record):
        if company_rating == 0:
            un_rating_company.append(company_id + 1)
    print("未投递简历的公司为",un_rating_company)

    user_sim_mat = user_similarity.get_user_similarity_mat()
    current_user_sim = user_sim_mat[user_id - 1, :]

    user_sim_dic = {}
    for user_id, user_sim_value in enumerate(current_user_sim):
        user_sim_dic[user_id+1] = user_sim_value

    user_sim_dic = sorted(user_sim_dic.items(), key=lambda a: a[1], reverse=True)
    print("取和当前用户相似度最高的5个用户"+str(user_sim_dic[0:5]))
    #print(user_sim_dic)

    result_dic = {}
    for un_rating_company_id in un_rating_company:
        sim_company_similarity = 0
        sim_company_rating_total = 0
        sim_company_rating_item_num = 0
        for item in user_sim_dic[0:5]:
            sim_usr_id = item[0]
            sim_usr_val = item[1]
            sim_company_rating = user_job_mat[sim_usr_id - 1, un_rating_company_id - 1]
            if sim_company_rating > 0:
                sim_company_rating_total = sim_company_rating_total + sim_company_rating
                sim_company_rating_item_num = sim_company_rating_item_num + 1
        if sim_company_rating_item_num > 0:
            average_sim = sim_company_rating_total / sim_company_rating_item_num
            result_dic[demo_util.get_company_des(un_rating_company_id)] = average_sim

    result_dic = sorted(result_dic.items(), key=lambda a: a[1], reverse=True)
    print("返回推荐结果",result_dic)

你可能感兴趣的:(movielens)