Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
Ailearning
提交
3de44eac
A
Ailearning
项目概览
OpenDocCN
/
Ailearning
10 个月 前同步成功
通知
8
Star
36240
Fork
11272
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
Ailearning
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
3de44eac
编写于
9月 20, 2020
作者:
片刻小哥哥
提交者:
GitHub
9月 20, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #608 from jiangzhonglian/master
添加:AI常用函数说明
上级
86cd3f89
6a5b4f91
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
394 addition
and
0 deletion
+394
-0
AI常用函数说明.md
AI常用函数说明.md
+134
-0
README.md
README.md
+1
-0
tutorials/RecommenderSystems/rs_rating_demo.py
tutorials/RecommenderSystems/rs_rating_demo.py
+259
-0
未找到文件。
AI常用函数说明.md
0 → 100644
浏览文件 @
3de44eac
# AI常用函数说明
## numpy 相关
> from numpy import random, mat, eye
```
py
'''
# NumPy 矩阵和数组的区别
NumPy存在2中不同的数据类型:
1. 矩阵 matrix
2. 数组 array
相似点:
都可以处理行列表示的数字元素
不同点:
1. 2个数据类型上执行相同的数据运算可能得到不同的结果。
2. NumPy函数库中的 matrix 与 MATLAB中 matrices 等价。
'''
from
numpy
import
random
,
mat
,
eye
# 生成一个 4*4 的随机数组
randArray
=
random
.
rand
(
4
,
4
)
# 转化关系, 数组转化为矩阵
randMat
=
mat
(
randArray
)
'''
.I 表示对矩阵求逆(可以利用矩阵的初等变换)
意义: 逆矩阵是一个判断相似性的工具。逆矩阵A与列向量p相乘后,将得到列向量q,q的第i个分量表示p与A的第i个列向量的相似度。
参考案例链接:
https://www.zhihu.com/question/33258489
http://blog.csdn.net/vernice/article/details/48506027
.T 表示对矩阵转置(行列颠倒)
* 等同于: .transpose()
.A 返回矩阵基于的数组
参考案例链接:
http://blog.csdn.net/qq403977698/article/details/47254539
'''
invRandMat
=
randMat
.
I
TraRandMat
=
randMat
.
T
ArrRandMat
=
randMat
.
A
# 输出结果
print
(
'randArray=(%s)
\n
'
%
type
(
randArray
),
randArray
)
print
(
'randMat=(%s)
\n
'
%
type
(
randMat
),
randMat
)
print
(
'invRandMat=(%s)
\n
'
%
type
(
invRandMat
),
invRandMat
)
print
(
'TraRandMat=(%s)
\n
'
%
type
(
TraRandMat
),
TraRandMat
)
print
(
'ArrRandMat=(%s)
\n
'
%
type
(
ArrRandMat
),
ArrRandMat
)
# 矩阵和逆矩阵 进行求积 (单位矩阵,对角线都为1嘛,理论上4*4的矩阵其他的都为0)
myEye
=
randMat
*
invRandMat
# 误差
print
(
myEye
-
eye
(
4
))
```
> np.dot
```
py
import
numpy
as
np
a
=
np
.
array
([
2
,
3
])
b
=
np
.
array
([
4
,
5
])
np
.
dot
(
a
,
b
,
out
=
None
)
#该函数的作用是获取两个元素a,b的乘积
Out
[
1
]:
23
=
2
*
4
+
3
*
5
a
=
np
.
array
([
2
,
3
,
4
])
b
=
np
.
array
([
5
,
6
,
7
])
np
.
dot
(
a
,
b
,
out
=
None
)
#该函数的作用是获取两个元素a,b的乘积
Out
[
2
]:
56
=
2
*
5
+
3
*
6
+
4
*
7
```
> array sum/mean
```
py
import
numpy
as
np
# ---- sum ---- #
a
=
np
.
array
([[
2
,
3
,
4
],
[
2
,
3
,
4
]])
# 纵向求和: 0 表示某一列所有的行求和
a
.
sum
(
axis
=
0
)
Out
[
6
]:
array
([
4
,
6
,
8
])
# 横向求和: 1 表示某一行所有的列求和
a
.
sum
(
axis
=
1
)
Out
[
7
]:
array
([
9
,
9
])
# ---- mean ---- #
a
=
np
.
array
([[
2
,
3
,
4
],
[
12
,
13
,
14
]])
# 纵向求平均: 0 表示某一列所有的行求和
a
.
mean
(
axis
=
0
)
Out
[
13
]:
array
([
7.
,
8.
,
9.
])
# 横向求平均: 1 表示某一行所有的列求平均
a
.
mean
(
axis
=
1
)
Out
[
14
]:
array
([
3.
,
13.
])
```
> np.newaxis
*
numpy 添加新的维度: newaxis(可以给原数组增加一个维度)
```
py
import
numpy
as
np
In
[
59
]:
x
=
np
.
random
.
randint
(
1
,
8
,
size
=
(
2
,
3
,
4
))
In
[
60
]:
y
=
x
[:,
np
.
newaxis
,
:,
:]
In
[
61
]:
Z
=
x
[
:,
:,
np
.
newaxis
,
:]
In
[
62
]:
x
.
shape
Out
[
62
]:
(
2
,
3
,
4
)
In
[
63
]:
y
.
shape
Out
[
63
]:
(
2
,
1
,
3
,
4
)
In
[
64
]:
z
.
shape
Out
[
64
]:
(
2
,
3
,
1
,
4
)
```
## keras 相关
> from keras.preprocessing.sequence import pad_sequences
```
python
from
keras.preprocessing.sequence
import
pad_sequences
# padding: pre(默认) 向前补充0 post 向后补充0
# truncating: 文本超过 pad_num, pre(默认) 删除前面 post 删除后面
x
=
[[
1
,
2
,
3
,
4
,
5
]]
x_train
=
pad_sequences
(
x
,
maxlen
=
pad_num
,
value
=
0
,
padding
=
'post'
,
truncating
=
"post"
)
print
(
"--- "
,
x_train
[
0
][:
20
])
```
README.md
浏览文件 @
3de44eac
...
...
@@ -41,6 +41,7 @@
*
面试求职:
<https://www.ixigua.com/pseries/6822563009391493636/>
*
机器学习实战:
<https://www.ixigua.com/pseries/6822816341615968772/>
*
NLP教学视频:
<https://www.ixigua.com/pseries/6828241431295951373/>
*
**AI常用函数说明**
:
<https://github.com/apachecn/AiLearning/tree/master/AI常用函数说明.md>
## 1.机器学习 - 基础
...
...
src/py3.x/ml/16.RecommenderSystems/RS-sklearn-rating
.py
→
tutorials/RecommenderSystems/rs_rating_demo
.py
浏览文件 @
3de44eac
#!/usr/bin/python
# coding:utf8
from
__future__
import
print_function
import
sys
import
math
...
...
@@ -9,80 +8,126 @@ from operator import itemgetter
import
numpy
as
np
import
pandas
as
pd
from
scipy.sparse.linalg
import
svds
from
sklearn
import
cross_valida
tion
as
cv
from
sklearn
import
model_selec
tion
as
cv
from
sklearn.metrics
import
mean_squared_error
from
sklearn.metrics.pairwise
import
pairwise_distances
from
middleware.utils
import
TimeStat
,
Chart
"""
推荐系统: Item CF/User CF/SVD 对比
"""
def
splitData
(
dataFile
,
test_size
):
# 加载数据集
# 加载数据集
(用户ID, 电影ID, 评分, 时间戳)
header
=
[
'user_id'
,
'item_id'
,
'rating'
,
'timestamp'
]
df
=
pd
.
read_csv
(
dataFile
,
sep
=
'
\t
'
,
names
=
header
)
n_users
=
df
.
user_id
.
unique
().
shape
[
0
]
n_items
=
df
.
item_id
.
unique
().
shape
[
0
]
print
(
'Number of users = '
+
str
(
n_users
)
+
' | Number of movies = '
+
str
(
n_items
))
print
(
'>>> 本数据集包含: 总用户数 = %s | 总电影数 = %s'
%
(
n_users
,
n_items
)
)
train_data
,
test_data
=
cv
.
train_test_split
(
df
,
test_size
=
test_size
)
print
(
"
数据量: "
,
len
(
train_data
),
len
(
test_data
))
print
(
"
>>> 训练:测试 = %s:%s = %s:%s"
%
(
len
(
train_data
),
len
(
test_data
),
1
-
test_size
,
test_size
))
return
df
,
n_users
,
n_items
,
train_data
,
test_data
def
calc_similarity
(
n_users
,
n_items
,
train_data
,
test_data
):
# 创建用户产品矩阵,针对测试数据和训练数据,创建两个矩阵:
"""
line: Pandas(Index=93661, user_id=624, item_id=750, rating=4, timestamp=891961163)
"""
train_data_matrix
=
np
.
zeros
((
n_users
,
n_items
))
for
line
in
train_data
.
itertuples
():
train_data_matrix
[
line
[
1
]
-
1
,
line
[
2
]
-
1
]
=
line
[
3
]
test_data_matrix
=
np
.
zeros
((
n_users
,
n_items
))
for
line
in
test_data
.
itertuples
():
test_data_matrix
[
line
[
1
]
-
1
,
line
[
2
]
-
1
]
=
line
[
3
]
# 使用sklearn的pairwise_distances函数来计算余弦相似性。
print
(
"1:"
,
np
.
shape
(
train_data_matrix
))
# 行: 人,列: 电影
print
(
"2:"
,
np
.
shape
(
train_data_matrix
.
T
))
# 行: 电影,列: 人
print
(
"1:"
,
np
.
shape
(
train_data_matrix
))
# 行: 人 | 列: 电影
print
(
"2:"
,
np
.
shape
(
train_data_matrix
.
T
))
# 行: 电影 | 列: 人
# 使用sklearn的 pairwise_distances 计算向量距离,cosine来计算余弦距离,越小越相似
user_similarity
=
pairwise_distances
(
train_data_matrix
,
metric
=
"cosine"
)
item_similarity
=
pairwise_distances
(
train_data_matrix
.
T
,
metric
=
"cosine"
)
# print("<<< %s \n %s" % (np.shape(user_similarity), user_similarity) )
# print("<<< %s \n %s" % (np.shape(item_similarity), item_similarity) )
print
(
'开始统计流行item的数量...'
,
file
=
sys
.
stderr
)
item_popular
=
{}
# 统计
在所有的用户中,不同电影的总出现次数
# 统计
同一个电影,观看的总人数(也就是所谓的流行度!)
for
i_index
in
range
(
n_items
):
if
np
.
sum
(
train_data_matrix
[:,
i_index
])
!=
0
:
item_popular
[
i_index
]
=
np
.
sum
(
train_data_matrix
[:,
i_index
]
!=
0
)
# print "pop=", i_index, self.item_popular[i_index]
# save the total number of items
item_count
=
len
(
item_popular
)
print
(
'总共流行item数量 = %d'
%
item_count
,
file
=
sys
.
stderr
)
print
(
'总共流行 item 数量 = %d'
%
item_count
,
file
=
sys
.
stderr
)
return
train_data_matrix
,
test_data_matrix
,
user_similarity
,
item_similarity
,
item_popular
def
predict
(
rating
,
similarity
,
type
=
'user'
):
print
(
type
)
print
(
"rating="
,
np
.
shape
(
rating
))
print
(
"similarity="
,
np
.
shape
(
similarity
))
if
type
==
'user'
:
# 求出每一个用户,所有电影的综合评分(axis=0 表示对列操作, 1表示对行操作)
# print "rating=", np.shape(rating)
"""
:param rating: 训练数据
:param similarity: 向量距离
:return:
"""
print
(
"+++ %s"
%
type
)
print
(
" rating="
,
np
.
shape
(
rating
))
print
(
" similarity="
,
np
.
shape
(
similarity
))
if
type
==
'item'
:
"""
综合打分:
rating.dot(similarity) 表示:
某1个人所有的电影组合 X ·电影*电影·距离(第1列都是关于第1部电影和其他的电影的距离)中,计算出 第一个人对第1/2/3部电影的 总评分 1*n
某2个人所有的电影组合 X ·电影*电影·距离(第1列都是关于第1部电影和其他的电影的距离)中,计算出 第一个人对第1/2/3部电影的 总评分 1*n
...
某n个人所有的电影组合 X ·电影*电影·距离(第1列都是关于第1部电影和其他的电影的距离)中,计算出 第一个人对第1/2/3部电影的 总评分 1*n
= 人-电影-评分(943, 1682) * 电影-电影-距离(1682, 1682)
= 人-电影-总评分距离(943, 1682)
np.array([np.abs(similarity).sum(axis=1)]) 表示: 横向求和: 1 表示某一行所有的列求和
第1列表示:某个A电影,对于所有电影计算出A的总距离
第2列表示:某个B电影,对于所有电影的综出B的总距离
...
第n列表示:某个N电影,对于所有电影的综出N的总距离
= 每一个电影的总距离 (1, 1682)
pred = 人-电影-平均评分 (943, 1682)
"""
pred
=
rating
.
dot
(
similarity
)
/
np
.
array
([
np
.
abs
(
similarity
).
sum
(
axis
=
1
)])
elif
type
==
'user'
:
# 每个样本上减去数据的统计平均值可以移除共同的部分,凸显个体差异。
# 求出每一个用户,所有电影的综合评分
# 横向求平均: 1 表示某一行所有的列求平均
mean_user_rating
=
rating
.
mean
(
axis
=
1
)
# np.newaxis参考地址: http://blog.csdn.net/xtingjie/article/details/72510834
# print "mean_user_rating=", np.shape(mean_user_rating)
# print "mean_user_rating.newaxis=", np.shape(mean_user_rating[:, np.newaxis])
# numpy中包含的 newaxis 可以给原数组增加一个维度
rating_diff
=
(
rating
-
mean_user_rating
[:,
np
.
newaxis
])
# print "rating=", rating[:3, :3]
# print "mean_user_rating[:, np.newaxis]=", mean_user_rating[:, np.newaxis][:3, :3]
# print "rating_diff=", rating_diff[:3, :3]
# 均分 + 人-人-距离(943, 943)*人-电影-评分diff(943, 1682)=结果-人-电影(每个人对同一电影的综合得分)(943, 1682) 再除以 个人与其他人总的距离 = 人-电影综合得分
pred
=
mean_user_rating
[:,
np
.
newaxis
]
+
similarity
.
dot
(
rating_diff
)
/
np
.
array
([
np
.
abs
(
similarity
).
sum
(
axis
=
1
)]).
T
elif
type
==
'item'
:
# 综合打分: 人-电影-评分(943, 1682)*电影-电影-距离(1682, 1682)=结果-人-电影(各个电影对同一电影的综合得分)(943, 1682) / 再除以 电影与其他电影总的距离 = 人-电影综合得分
pred
=
rating
.
dot
(
similarity
)
/
np
.
array
(
[
np
.
abs
(
similarity
).
sum
(
axis
=
1
)])
# 均分 +
# 人-人-距离(943, 943)*人-电影-评分diff(943, 1682)=结果-人-电影(每个人对同一电影的综合得分)(943, 1682) 再除以 个人与其他人总的距离 = 人-电影综合得分
"""
综合打分:
similarity.dot(rating_diff) 表示:
第1列:第1个人与其他人的相似度 * 人与电影的相似度,得到 第1个人对第1/2/3列电影的 总得分 1*n
第2列:第2个人与其他人的相似度 * 人与电影的相似度,得到 第2个人对第1/2/3列电影的 总得分 1*n
...
第n列:第n个人与其他人的相似度 * 人与电影的相似度,得到 第n个人对第1/2/3列电影的 总得分 1*n
= 人-人-距离(943, 943) * 人-电影-评分(943, 1682)
= 人-电影-总评分距离(943, 1682)
np.array([np.abs(similarity).sum(axis=1)]) 表示: 横向求和: 1 表示某一行所有的列求和
第1列表示:第A个人,对于所有人计算出A的总距离
第2列表示:第B个人,对于所有人计算出B的总距离
...
第n列表示:第N个人,对于所有人计算出N的总距离
= 每一个电影的总距离 (1, 943)
pred = 均值 + 人-电影-平均评分 (943, 1682)
"""
pred
=
mean_user_rating
[:,
np
.
newaxis
]
+
similarity
.
dot
(
rating_diff
)
/
np
.
array
([
np
.
abs
(
similarity
).
sum
(
axis
=
1
)]).
T
return
pred
...
...
@@ -112,7 +157,7 @@ def evaluate(prediction, item_popular, name):
hit
+=
1
all_rec_items
.
add
(
item
)
#
计算用户对应的电影出现次数log值的sum
加和
#
popular_sum是对所有的item的流行度进行
加和
if
item
in
item_popular
:
popular_sum
+=
math
.
log
(
1
+
item_popular
[
item
])
...
...
@@ -120,10 +165,12 @@ def evaluate(prediction, item_popular, name):
test_count
+=
len
(
test_items
)
precision
=
hit
/
(
1.0
*
rec_count
)
# 召回率,相对于测试推荐集合的数据
recall
=
hit
/
(
1.0
*
test_count
)
# 覆盖率,相对于训练集合的数据
coverage
=
len
(
all_rec_items
)
/
(
1.0
*
len
(
item_popular
))
popularity
=
popular_sum
/
(
1.0
*
rec_count
)
print
(
'%s: precision=%.4f
\t
recall=%.4f
\t
coverage=%.4f
\t
popularity=%.4f'
%
(
print
(
'
---
%s: precision=%.4f
\t
recall=%.4f
\t
coverage=%.4f
\t
popularity=%.4f'
%
(
name
,
precision
,
recall
,
coverage
,
popularity
),
file
=
sys
.
stderr
)
...
...
@@ -135,19 +182,22 @@ def recommend(u_index, prediction):
reverse
=
True
)[:
10
]
test_items
=
np
.
where
(
test_data_matrix
[
u_index
,
:]
!=
0
)[
0
]
print
(
'原始结果: '
,
test_items
)
print
(
'推荐结果: '
,
[
key
for
key
,
value
in
pre_items
])
result
=
[
key
for
key
,
value
in
pre_items
]
result
.
sort
(
reverse
=
False
)
print
(
'原始结果(%s): %s'
%
(
len
(
test_items
),
test_items
)
)
print
(
'推荐结果(%s): %s'
%
(
len
(
result
),
result
)
)
if
__name__
==
"__main__"
:
def
main
()
:
global
n_users
,
train_data_matrix
,
test_data_matrix
# 基于内存的协同过滤
# ...
# 拆分数据集
# http://files.grouplens.org/datasets/movielens/ml-100k.zip
dataFile
=
'data/16.RecommenderSystems/ml-100k/u.data'
df
,
n_users
,
n_items
,
train_data
,
test_data
=
splitData
(
dataFile
,
test_size
=
0.25
)
path_root
=
"/Users/jiangzl/work/data/机器学习"
dataFile
=
'%s/16.RecommenderSystems/ml-100k/u.data'
%
path_root
df
,
n_users
,
n_items
,
train_data
,
test_data
=
splitData
(
dataFile
,
test_size
=
0.25
)
# 计算相似度
train_data_matrix
,
test_data_matrix
,
user_similarity
,
item_similarity
,
item_popular
=
calc_similarity
(
...
...
@@ -156,35 +206,54 @@ if __name__ == "__main__":
item_prediction
=
predict
(
train_data_matrix
,
item_similarity
,
type
=
'item'
)
user_prediction
=
predict
(
train_data_matrix
,
user_similarity
,
type
=
'user'
)
# 评估: 均方根误差
print
(
'Item based CF RMSE: '
+
str
(
rmse
(
item_prediction
,
test_data_matrix
)))
print
(
'User based CF RMSE: '
+
str
(
rmse
(
user_prediction
,
test_data_matrix
)))
# # 评估: 均方根误差
print
(
'>>> Item based CF RMSE: '
+
str
(
rmse
(
item_prediction
,
test_data_matrix
)))
print
(
'>>> User based CF RMSE: '
+
str
(
rmse
(
user_prediction
,
test_data_matrix
)))
# 基于模型的协同过滤
# ...
# 计算MovieLens数据集的稀疏度 (n_users,n_items 是常量,所以,用户行为数据越少,意味着信息量少;越稀疏,优化的空间也越大)
sparsity
=
round
(
1.0
-
len
(
df
)
/
float
(
n_users
*
n_items
),
3
)
print
(
'The sparsity level of MovieLen100K is '
+
str
(
sparsity
*
100
)
+
'%'
)
# 计算稀疏矩阵的最大k个奇异值/向量
u
,
s
,
vt
=
svds
(
train_data_matrix
,
k
=
15
)
print
(
'
\n
MovieLen100K的稀疏度: %s%%
\n
'
%
(
sparsity
*
100
))
# # 计算稀疏矩阵的最大k个奇异值/向量
# minrmse = math.inf
# index = 1
# for k in range(1, 30, 1):
# u, s, vt = svds(train_data_matrix, k=k)
# # print(">>> ", s)
# s_diag_matrix = np.diag(s)
# svd_prediction = np.dot(np.dot(u, s_diag_matrix), vt)
# r_rmse = rmse(svd_prediction, test_data_matrix)
# if r_rmse < minrmse:
# index = k
# minrmse = r_rmse
index
=
11
minrmse
=
2.6717213264389765
u
,
s
,
vt
=
svds
(
train_data_matrix
,
k
=
index
)
# print(">>> ", s)
s_diag_matrix
=
np
.
diag
(
s
)
svd_prediction
=
np
.
dot
(
np
.
dot
(
u
,
s_diag_matrix
),
vt
)
print
(
"svd-shape:"
,
np
.
shape
(
svd_prediction
)
)
print
(
'Model based CF RMSE: '
+
str
(
rmse
(
svd_prediction
,
test_data_matrix
))
)
"""
在信息量相同的情况下,矩阵越小,那么携带的信息越可靠。
所以: user-cf 推荐效果高于 item-cf; 而svd分解后,发现15个维度效果就能达到90%以上,所以信息更可靠,效果也更好。
item-cf: 1682
user-cf: 943
svd: 15
"""
r_rmse
=
rmse
(
svd_prediction
,
test_data_matrix
)
print
(
"+++ k=%s, svd-shape: %s"
%
(
index
,
np
.
shape
(
svd_prediction
))
)
print
(
'>>> Model based CF RMSE: %s
\n
'
%
minrmse
)
#
"""
#
在信息量相同的情况下,矩阵越小,那么携带的信息越可靠。
#
所以: user-cf 推荐效果高于 item-cf; 而svd分解后,发现15个维度效果就能达到90%以上,所以信息更可靠,效果也更好。
#
item-cf: 1682
#
user-cf: 943
#
svd: 15
#
"""
evaluate
(
item_prediction
,
item_popular
,
'item'
)
evaluate
(
user_prediction
,
item_popular
,
'user'
)
evaluate
(
svd_prediction
,
item_popular
,
'svd'
)
evaluate
(
svd_prediction
,
item_popular
,
'svd'
)
# 推荐结果
# recommend(1, item_prediction)
# recommend(1, user_prediction)
recommend
(
1
,
svd_prediction
)
if
__name__
==
"__main__"
:
main
()
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录