Skip to content

Commit 8a62b3d

Browse files
Merge pull request #137 from jiangzhonglian/master
更新完成 SVD 物品的主要特征空间
2 parents 1dcdb32 + 482d4f8 commit 8a62b3d

6 files changed

Lines changed: 300 additions & 15 deletions

File tree

docs/13.利用PCA来简化数据.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ def pca(dataMat, topNfeat=9999999):
201201
return lowDDataMat, reconMat
202202
```
203203

204+
[完整代码地址](https://github.com/apachecn/MachineLearning/blob/master/src/python/13.PCA/pca.py): <https://github.com/apachecn/MachineLearning/blob/master/src/python/13.PCA/pca.py>
205+
204206
### 要点补充
205207

206208
```

docs/14.利用SVD简化数据.md

Lines changed: 202 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,114 @@ def loadExData2():
155155

156156
> 分析数据: 暂时不需要
157157
158-
> 使用算法: 通过调用 recommend() 函数进行推荐
158+
> 训练算法: 通过调用 recommend() 函数进行推荐
159+
160+
* 基于物品相似度(参考地址:http://www.codeweblog.com/svd-%E7%AC%94%E8%AE%B0/)
161+
162+
![基于物品相似度](/images/14.SVD/基于物品相似度.png)
163+
164+
```python
165+
# 基于物品相似度的推荐引擎
166+
def standEst(dataMat, user, simMeas, item):
167+
"""standEst(计算某用户未评分物品中,以对该物品和其他物品评分的用户的物品相似度,然后进行综合评分)
168+
169+
Args:
170+
dataMat 训练数据集
171+
user 用户编号
172+
simMeas 相似度计算方法
173+
item 未评分的物品编号
174+
Returns:
175+
ratSimTotal/simTotal 评分(0~5之间的值)
176+
"""
177+
# 得到数据集中的物品数目
178+
n = shape(dataMat)[1]
179+
# 初始化两个评分值
180+
simTotal = 0.0
181+
ratSimTotal = 0.0
182+
# 遍历行中的每个物品(对用户评过分的物品进行遍历,并将它与其他物品进行比较)
183+
for j in range(n):
184+
userRating = dataMat[user, j]
185+
# 如果某个物品的评分值为0,则跳过这个物品
186+
if userRating == 0:
187+
continue
188+
# 寻找两个用户都评级的物品
189+
# 变量 overLap 给出的是两个物品当中已经被评分的那个元素的索引ID
190+
# logical_and 计算x1和x2元素的真值。
191+
overLap = nonzero(logical_and(dataMat[:, item].A > 0, dataMat[:, j].A > 0))[0]
192+
# 如果相似度为0,则两着没有任何重合元素,终止本次循环
193+
if len(overLap) == 0:
194+
similarity = 0
195+
# 如果存在重合的物品,则基于这些重合物重新计算相似度。
196+
else:
197+
similarity = simMeas(dataMat[overLap, item], dataMat[overLap, j])
198+
# print 'the %d and %d similarity is : %f'(iten,j,similarity)
199+
# 相似度会不断累加,每次计算时还考虑相似度和当前用户评分的乘积
200+
# similarity 用户相似度, userRating 用户评分
201+
simTotal += similarity
202+
ratSimTotal += similarity * userRating
203+
if simTotal == 0:
204+
return 0
205+
# 通过除以所有的评分总和,对上述相似度评分的乘积进行归一化,使得最后评分在0~5之间,这些评分用来对预测值进行排序
206+
else:
207+
return ratSimTotal/simTotal
208+
```
209+
210+
* 基于SVD(参考地址:http://www.codeweblog.com/svd-%E7%AC%94%E8%AE%B0/)
211+
212+
![基于SVD.png](/images/14.SVD/基于SVD.png)
213+
214+
```python
215+
# 基于SVD的评分估计
216+
# 在recommend() 中,这个函数用于替换对standEst()的调用,该函数对给定用户给定物品构建了一个评分估计值
217+
def svdEst(dataMat, user, simMeas, item):
218+
"""svdEst(计算某用户未评分物品中,以对该物品和其他物品评分的用户的物品相似度,然后进行综合评分)
219+
220+
Args:
221+
dataMat 训练数据集
222+
user 用户编号
223+
simMeas 相似度计算方法
224+
item 未评分的物品编号
225+
Returns:
226+
ratSimTotal/simTotal 评分(0~5之间的值)
227+
"""
228+
# 物品数目
229+
n = shape(dataMat)[1]
230+
# 对数据集进行SVD分解
231+
simTotal = 0.0
232+
ratSimTotal = 0.0
233+
# 奇异值分解
234+
# 在SVD分解之后,我们只利用包含了90%能量值的奇异值,这些奇异值会以NumPy数组的形式得以保存
235+
U, Sigma, VT = la.svd(dataMat)
236+
237+
# # 分析 Sigma 的长度取值
238+
# analyse_data(Sigma, 20)
239+
240+
# 如果要进行矩阵运算,就必须要用这些奇异值构建出一个对角矩阵
241+
Sig4 = mat(eye(4) * Sigma[: 4])
242+
# 利用U矩阵将物品转换到低维空间中,构建转换后的物品(物品+4个主要的特征)
243+
xformedItems = dataMat.T * U[:, :4] * Sig4.I
244+
# 对于给定的用户,for循环在用户对应行的元素上进行遍历,
245+
# 这和standEst()函数中的for循环的目的一样,只不过这里的相似度计算时在低维空间下进行的。
246+
for j in range(n):
247+
userRating = dataMat[user, j]
248+
if userRating == 0 or j == item:
249+
continue
250+
# 相似度的计算方法也会作为一个参数传递给该函数
251+
similarity = simMeas(xformedItems[item, :].T, xformedItems[j, :].T)
252+
# for 循环中加入了一条print语句,以便了解相似度计算的进展情况。如果觉得累赘,可以去掉
253+
print 'the %d and %d similarity is: %f' % (item, j, similarity)
254+
# 对相似度不断累加求和
255+
simTotal += similarity
256+
# 对相似度及对应评分值的乘积求和
257+
ratSimTotal += similarity * userRating
258+
if simTotal == 0:
259+
return 0
260+
else:
261+
# 计算估计评分
262+
return ratSimTotal/simTotal
263+
```
264+
265+
排序获取最后的推荐结果
159266

160267
```python
161268
# recommend()函数,就是推荐引擎,它默认调用standEst()函数,产生了最高的N个推荐结果。
@@ -178,6 +285,9 @@ def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
178285
return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[: N]
179286
```
180287

288+
> 测试 和 使用 该算法,可以自行编写
289+
290+
[完整代码地址](https://github.com/apachecn/MachineLearning/blob/master/src/python/14.SVD/svdRecommend.py): <https://github.com/apachecn/MachineLearning/blob/master/src/python/14.SVD/svdRecommend.py>
181291

182292
#### 要点补充
183293

@@ -201,6 +311,97 @@ def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
201311

202312
### 项目案例: 基于 SVD 的图像压缩
203313

314+
> 收集 并 准备数据
315+
316+
将文本数据转化为矩阵
317+
318+
```python
319+
# 加载并转换数据
320+
def imgLoadData(filename):
321+
myl = []
322+
# 打开文本文件,并从文件以数组方式读入字符
323+
for line in open(filename).readlines():
324+
newRow = []
325+
for i in range(32):
326+
newRow.append(int(line[i]))
327+
myl.append(newRow)
328+
# 矩阵调入后,就可以在屏幕上输出该矩阵
329+
myMat = mat(myl)
330+
return myMat
331+
```
332+
333+
> 分析数据: 分析 Sigma 的长度个数
334+
335+
通常保留矩阵 80% ~ 90% 的能量,就可以得到重要的特征并取出噪声。
336+
337+
```python
338+
def analyse_data(Sigma, loopNum=20):
339+
"""analyse_data(分析 Sigma 的长度取值)
340+
341+
Args:
342+
Sigma Sigma的值
343+
loopNum 循环次数
344+
"""
345+
# 总方差的集合(总能量值)
346+
Sig2 = Sigma**2
347+
SigmaSum = sum(Sig2)
348+
for i in range(loopNum):
349+
SigmaI = sum(Sig2[:i+1])
350+
'''
351+
根据自己的业务情况,就行处理,设置对应的 Singma 次数
352+
353+
通常保留矩阵 80% ~ 90% 的能量,就可以得到重要的特征并取出噪声。
354+
'''
355+
print '主成分:%s, 方差占比:%s%%' % (format(i+1, '2.0f'), format(SigmaI/SigmaSum*100, '4.2f'))
356+
```
357+
358+
> 使用算法: 对比使用 SVD 前后的数据差异对比,对于存储大家可以试着写写
359+
360+
```python
361+
# 打印矩阵
362+
def printMat(inMat, thresh=0.8):
363+
# 由于矩阵保护了浮点数,因此定义浅色和深色,遍历所有矩阵元素,当元素大于阀值时打印1,否则打印0
364+
for i in range(32):
365+
for k in range(32):
366+
if float(inMat[i, k]) > thresh:
367+
print 1,
368+
else:
369+
print 0,
370+
print ''
371+
372+
373+
# 实现图像压缩,允许基于任意给定的奇异值数目来重构图像
374+
def imgCompress(numSV=3, thresh=0.8):
375+
"""imgCompress( )
376+
377+
Args:
378+
numSV Sigma长度
379+
thresh 判断的阈值
380+
"""
381+
# 构建一个列表
382+
myMat = imgLoadData('input/14.SVD/0_5.txt')
383+
384+
print "****original matrix****"
385+
# 对原始图像进行SVD分解并重构图像e
386+
printMat(myMat, thresh)
387+
388+
# 通过Sigma 重新构成SigRecom来实现
389+
# Sigma是一个对角矩阵,因此需要建立一个全0矩阵,然后将前面的那些奇异值填充到对角线上。
390+
U, Sigma, VT = la.svd(myMat)
391+
# SigRecon = mat(zeros((numSV, numSV)))
392+
# for k in range(numSV):
393+
# SigRecon[k, k] = Sigma[k]
394+
395+
# 分析插入的 Sigma 长度
396+
analyse_data(Sigma, 20)
397+
398+
SigRecon = mat(eye(numSV) * Sigma[: numSV])
399+
reconMat = U[:, :numSV] * SigRecon * VT[:numSV, :]
400+
print "****reconstructed matrix using %d singular values *****" % numSV
401+
printMat(reconMat, thresh)
402+
```
403+
404+
[完整代码地址](https://github.com/apachecn/MachineLearning/blob/master/src/python/14.SVD/svdRecommend.py): <https://github.com/apachecn/MachineLearning/blob/master/src/python/14.SVD/svdRecommend.py>
204405

205406
* * *
206407

images/14.SVD/基于SVD.png

14.2 KB
Loading
10.3 KB
Loading

input/14.SVD/0_5.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
00000000000000110000000000000000
2+
00000000000011111100000000000000
3+
00000000000111111110000000000000
4+
00000000001111111111000000000000
5+
00000000111111111111100000000000
6+
00000001111111111111110000000000
7+
00000000111111111111111000000000
8+
00000000111111100001111100000000
9+
00000001111111000001111100000000
10+
00000011111100000000111100000000
11+
00000011111100000000111110000000
12+
00000011111100000000011110000000
13+
00000011111100000000011110000000
14+
00000001111110000000001111000000
15+
00000011111110000000001111000000
16+
00000011111100000000001111000000
17+
00000001111100000000001111000000
18+
00000011111100000000001111000000
19+
00000001111100000000001111000000
20+
00000001111100000000011111000000
21+
00000000111110000000001111100000
22+
00000000111110000000001111100000
23+
00000000111110000000001111100000
24+
00000000111110000000011111000000
25+
00000000111110000000111111000000
26+
00000000111111000001111110000000
27+
00000000011111111111111110000000
28+
00000000001111111111111110000000
29+
00000000001111111111111110000000
30+
00000000000111111111111000000000
31+
00000000000011111111110000000000
32+
00000000000000111111000000000000

src/python/14.SVD/svdRecommend.py

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,22 @@ def svdEst(dataMat, user, simMeas, item):
150150
# 奇异值分解
151151
# 在SVD分解之后,我们只利用包含了90%能量值的奇异值,这些奇异值会以NumPy数组的形式得以保存
152152
U, Sigma, VT = la.svd(dataMat)
153+
154+
# # 分析 Sigma 的长度取值
155+
# analyse_data(Sigma, 20)
156+
153157
# 如果要进行矩阵运算,就必须要用这些奇异值构建出一个对角矩阵
154158
Sig4 = mat(eye(4) * Sigma[: 4])
155-
# 利用U矩阵将物品转换到低维空间中,构建转换后的物品
159+
160+
# 利用U矩阵将物品转换到低维空间中,构建转换后的物品(物品+4个主要的特征)
156161
xformedItems = dataMat.T * U[:, :4] * Sig4.I
157-
# 对于给定的用户,for循环在用户对应行的元素上进行遍历,
162+
print 'dataMat', shape(dataMat)
163+
print 'U[:, :4]', shape(U[:, :4])
164+
print 'Sig4.I', shape(Sig4.I)
165+
print 'VT[:4, :]', shape(VT[:4, :])
166+
print 'xformedItems', shape(xformedItems)
167+
168+
# 对于给定的用户,for循环在用户对应行的元素上进行遍历
158169
# 这和standEst()函数中的for循环的目的一样,只不过这里的相似度计算时在低维空间下进行的。
159170
for j in range(n):
160171
userRating = dataMat[user, j]
@@ -205,7 +216,41 @@ def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
205216
return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[: N]
206217

207218

219+
def analyse_data(Sigma, loopNum=20):
220+
"""analyse_data(分析 Sigma 的长度取值)
221+
222+
Args:
223+
Sigma Sigma的值
224+
loopNum 循环次数
225+
"""
226+
# 总方差的集合(总能量值)
227+
Sig2 = Sigma**2
228+
SigmaSum = sum(Sig2)
229+
for i in range(loopNum):
230+
SigmaI = sum(Sig2[:i+1])
231+
'''
232+
根据自己的业务情况,就行处理,设置对应的 Singma 次数
233+
234+
通常保留矩阵 80% ~ 90% 的能量,就可以得到重要的特征并取出噪声。
235+
'''
236+
print '主成分:%s, 方差占比:%s%%' % (format(i+1, '2.0f'), format(SigmaI/SigmaSum*100, '4.2f'))
237+
238+
208239
# 图像压缩函数
240+
# 加载并转换数据
241+
def imgLoadData(filename):
242+
myl = []
243+
# 打开文本文件,并从文件以数组方式读入字符
244+
for line in open(filename).readlines():
245+
newRow = []
246+
for i in range(32):
247+
newRow.append(int(line[i]))
248+
myl.append(newRow)
249+
# 矩阵调入后,就可以在屏幕上输出该矩阵
250+
myMat = mat(myl)
251+
return myMat
252+
253+
209254
# 打印矩阵
210255
def printMat(inMat, thresh=0.8):
211256
# 由于矩阵保护了浮点数,因此定义浅色和深色,遍历所有矩阵元素,当元素大于阀值时打印1,否则打印0
@@ -220,25 +265,30 @@ def printMat(inMat, thresh=0.8):
220265

221266
# 实现图像压缩,允许基于任意给定的奇异值数目来重构图像
222267
def imgCompress(numSV=3, thresh=0.8):
268+
"""imgCompress( )
269+
270+
Args:
271+
numSV Sigma长度
272+
thresh 判断的阈值
273+
"""
223274
# 构建一个列表
224-
myl = []
225-
# 打开文本文件,并从文件以数组方式读入字符
226-
for line in open('testData/testDigits/0_5.txt').readlines():
227-
newRow = []
228-
for i in range(32):
229-
newRow.append(int(line[i]))
230-
myl.append(newRow)
231-
# 矩阵调入后,就可以在屏幕上输出该矩阵
232-
myMat = mat(myl)
275+
myMat = imgLoadData('input/14.SVD/0_5.txt')
276+
233277
print "****original matrix****"
234278
# 对原始图像进行SVD分解并重构图像e
235279
printMat(myMat, thresh)
280+
236281
# 通过Sigma 重新构成SigRecom来实现
237282
# Sigma是一个对角矩阵,因此需要建立一个全0矩阵,然后将前面的那些奇异值填充到对角线上。
238283
U, Sigma, VT = la.svd(myMat)
239-
SigRecon = mat(zeros((numSV, numSV)))
240-
for k in range(numSV):
241-
SigRecon[k, k] = Sigma[k]
284+
# SigRecon = mat(zeros((numSV, numSV)))
285+
# for k in range(numSV):
286+
# SigRecon[k, k] = Sigma[k]
287+
288+
# 分析插入的 Sigma 长度
289+
analyse_data(Sigma, 20)
290+
291+
SigRecon = mat(eye(numSV) * Sigma[: numSV])
242292
reconMat = U[:, :numSV] * SigRecon * VT[:numSV, :]
243293
print "****reconstructed matrix using %d singular values *****" % numSV
244294
printMat(reconMat, thresh)

0 commit comments

Comments
 (0)