Python 根據打分數據對某用戶進行推薦
代碼倉庫:https://github.com/SKPrimin/PythonCrawler/tree/master/%E7%94%B5%E5%BD%B1%E6%8E%A8%E8%8D%90
編寫程序,生成數據模擬(也可以使用網上爬取的真實數據)多人對多部定影的打分(1~5分),然后根據這些數據對某用戶A進行推薦。
推薦規則為:在已有的數據中選擇與該用戶A的愛好最相似的用戶B,然后從最相似的用戶B已看過但用戶A還沒看過的電影中選擇B打分最高的電影推薦給用戶A。其中,相似度的計算標准:
(1)兩個用戶共同打分過的電影越多,越相似;
(2)兩個用戶對共同打分的電影的打分越接近,越相似。
實現
生成數據模擬
import random
from openpyxl import Workbook
user = ['用戶1', '用戶2', '用戶3', '用戶4', '用戶5', '用戶6', '用戶7', '用戶8',
'用戶9', '用戶10', '用戶11', '用戶12', '用戶13', '用戶14', '用戶15']
# 實例化
wb = Workbook()
# 激活 worksheet
ws = wb.active
# 設置表頭
ws.append(['用戶', '電影1', '電影2', '電影3', '電影4', '電影5', '電影6', '電影7', '電影8', '電影9', '電影10'])
# i 為用戶數 j為電影數
for i in range(15):
numscore = []
numscore.append(user[i])
for j in range(10):
# 生成電影j的分數
numscore.append(random.randint(0, 5))
# 生成第i行數據
ws.append(numscore)
wb.save('電影用戶評價信息.xlsx')
通過這種方式,我們可以一個隨機出來的打分表
用戶 | 電影1 | 電影2 | 電影3 | 電影4 | 電影5 | 電影6 | 電影7 | 電影8 | 電影9 | 電影10 |
---|---|---|---|---|---|---|---|---|---|---|
用戶1 | 0 | 4 | 4 | 0 | 5 | 2 | 0 | 3 | 1 | 5 |
用戶2 | 1 | 1 | 1 | 4 | 5 | 4 | 1 | 3 | 3 | 0 |
用戶3 | 3 | 4 | 2 | 3 | 2 | 4 | 5 | 2 | 2 | 2 |
用戶4 | 3 | 5 | 5 | 0 | 4 | 2 | 2 | 1 | 2 | 2 |
用戶5 | 2 | 0 | 1 | 2 | 1 | 3 | 0 | 5 | 5 | 1 |
用戶6 | 1 | 0 | 0 | 0 | 0 | 1 | 5 | 1 | 4 | 5 |
用戶7 | 5 | 1 | 0 | 0 | 4 | 3 | 1 | 2 | 1 | 1 |
用戶8 | 0 | 5 | 2 | 1 | 3 | 2 | 4 | 5 | 5 | 4 |
用戶9 | 3 | 3 | 2 | 3 | 0 | 0 | 0 | 4 | 5 | 3 |
用戶10 | 2 | 2 | 3 | 1 | 0 | 5 | 3 | 4 | 3 | 4 |
用戶11 | 2 | 0 | 1 | 1 | 5 | 3 | 1 | 0 | 5 | 3 |
用戶12 | 5 | 1 | 2 | 1 | 3 | 3 | 4 | 4 | 3 | 4 |
用戶13 | 5 | 2 | 5 | 5 | 4 | 3 | 3 | 1 | 0 | 3 |
用戶14 | 2 | 4 | 5 | 0 | 3 | 2 | 0 | 2 | 4 | 0 |
用戶15 | 2 | 1 | 4 | 2 | 5 | 1 | 0 | 5 | 4 | 4 |
數據分析推薦
讀取數據
- 讀取excel表格數據,並存放於一個字典中
from openpyxl import load_workbook
# 打開文件及表
wb = load_workbook('電影用戶評價信息.xlsx')
ws = wb["Sheet"]
'''使用演員作為鍵,使用包含該演員參演電影名稱的集合作為“值”'''
fimeDict = dict()
i = 0
# 遍歷Excel文件中的所有行
for index, row in enumerate(ws.rows):
# 跳過表頭,對於每一行有效數據,獲取每一行的電影名稱和演員清單,
if index == 0:
continue
# 獲取電影名稱和演員列表
user = row[0].value
fimescore = [row[i].value for i in range(1, 11)]
# 得到評分字典,評價用戶作為鍵,評分列表作為值
fimeDict[user] = fimescore
print("評分字典:{}".format(fimeDict))
評分字典:{'用戶1': [0, 4, 4, 0, 5, 2, 0, 3, 1, 5], '用戶2': [1, 1, 1, 4, 5, 4, 1, 3, 3, 0],...
用戶A讀入
# 假設來了個新用戶
username = "用戶A"
user = [4, 0, 4, 4, 0, 0, 2, 0, 0, 5]
print(f"新來的用戶為{username}:{user}")
共同打分過的電影多的用戶
- 先找出第一個最高分用戶
filmSamenum = 0 # 共同打分的數目
filmSameNumDict = {}
for key, value in fimeDict.items():
# 共同打分的電影分析
filmiswatch = []
for i in range(len(user)):
# 如果雙方都看了 ,便為True
filmiswatch.append(bool(value[i]) & bool(user[i]))
# 統計True的個數,即雙方都看的個數
filmSamenum = filmiswatch.count(True)
# 將此用戶名用戶名與共同觀看個數放入字典
filmSameNumDict[key] = filmSamenum
print(filmSameNumDict)
# 調用max函數找出最大值對應的鍵 但此方法只會找到返回一個值
keyName = max(filmSameNumDict, key=filmSameNumDict.get)
print("第一個最高匹配人為:{}".format(keyName))
# 再次遍歷查看有沒有其他的用戶觀看次數一樣
userSame = []
maxScore = filmSameNumDict[keyName]
for key, value in filmSameNumDict.items():
# 如果觀看次與最大值相同添加進列表
if value == maxScore:
userSame.append(key)
print("共同打分過的電影多的用戶為:{}".format(userSame))
第一個最高匹配人為:用戶3
- 根據最高分找出其他觀看次數一樣的用戶
# 再次遍歷查看有沒有其他的用戶觀看次數一樣
userSame = []
maxScore = filmSameNumDict[keyName]
for key, value in filmSameNumDict.items():
# 如果觀看次與最大值相同添加進列表
if value == maxScore:
userSame.append(key)
print("共同打分過的電影多的用戶為:{}".format(userSame))
共同打分過的電影多的用戶為:['用戶3', '用戶10', '用戶11', '用戶12', '用戶13']
打分越接近的用戶
# 開始對相同次數的用戶進行第二輪推薦
userScoreDifferentDict = {}
for username in userSame:
score = 0
for index, userscore in enumerate(fimeDict[username]):
# 計算兩個用戶的打分差距
if userscore != 0 and user[index] != 0:
score += abs(userscore - user[index])
# 將計算出的
userScoreDifferentDict[username] = score
print("相似用戶的得分字典為:{}".format(userScoreDifferentDict))
相似用戶的得分字典為:{'用戶3': 10, '用戶10': 8, '用戶11': 11, '用戶12': 9, '用戶13': 6}
轉換出電影名
# 統計出其觀看電影的清單fimeName = ['電影1', '電影2', '電影3', '電影4', '電影5', '電影6', '電影7', '電影8', '電影9', '電影10']
selectefimeName = []
selecteName = min(userScoreDifferentDict, key=userScoreDifferentDict.get)
for index, fime in enumerate(fimeDict[selecteName]):
if fime != 0:
selectefimeName.append(fimeName[index])
print("最高匹配人為:{0},他所觀看的電影為{1}".format(selecteName, selectefimeName))
最高匹配人為:用戶13,他所觀看的電影為['電影1', '電影2', '電影3', '電影4', '電影5', '電影6', '電影7', '電影8', '電影10']
找出用戶未看過的電影
# 求出用戶觀看的電影列表
userfimeName = []
for index, fime in enumerate(user):
if fime != 0:
userfimeName.append(fimeName[index])
# 轉成集合求差集
selectefimeName = set(selectefimeName)
userfimeName = set(userfimeName)
finallFimeName = selectefimeName.difference(userfimeName)
print("推薦的電影如下:{}".format(finallFimeName))
推薦的電影如下:{'電影6', '電影5', '電影8', '電影2'}
推薦評分最高電影
# 求出這些電影中評分最高的一個
finallScore = 0
finallFime = ""
for fime in finallFimeName:
# 找到這個電影的索引
index = fimeName.index(fime)
# 根據索引找到分數
score = fimeDict[selecteName][index]
# 比較哪那個高
if finallScore < score:
finallScore = score
finallFime = fime
# 如果是最高評分則無需繼續查找了
if score == 5:
break
print("最終推薦的電影為:{}".format(finallFime))
最終推薦的電影為:電影5
本次模擬的推薦算法是當今社會常見的算法應用,平台的大數據推薦在我們生活中屢見不鮮。本次我在計算標准的指引下,也親身實際設計了一次大數據推薦算法,本次生成的數據先保存至excel表格,用戶作為行,電影名稱作為列,實現了評分的存儲。在數據讀取時,通過同樣的方式,以用戶名作為鍵,評分列表作為值進行讀取,這也與我們實際應用中的表單傳值使用的json數據有異曲同工之處,都是字典搭配列表。讀取時首先要統計其他用戶與用戶A共同打分過的電影數,這里我采用的bool的方式,進行&運算,便得到了一個是否都打過分的布爾列表,然后統計True的個數便可以得出。接下來第二輪比較評分差異時,便通過雙循環算出各用戶與用戶A打分之差,統計時需要將有人未看的電影去除。在最后的找出要推薦的電影階段,先是通過索引找出對應的電影名稱,再將列表轉為集合求出差集,最后再次根據索引去查找分數,找出其打分最高的那個電影。