python数据挖掘作用_python 数据挖掘

python -- 面向程序员的数据挖掘指南-推荐系统入门-分类-005

在上几章中, 无论显示评价还是隐式评价, 我们都使用的是用户对物品的评价来进行推荐,这一章我们将使用物品本身的特征来进行推荐。

比如你购买了Phoenix专辑,购买过这张专辑的用户还会去购买Vampire的专辑,因此会把它推荐给你;我在Netflix上观看了Doctor Who,网站会向我推荐Quantum Leap,用的是同样的原理。

这一章我们来看另一种推荐方法。

以潘多拉音乐站举例,其实在播放界面上可以看到推荐理由:

“根据你目前告知的信息,我们播放的这首歌曲有着相似的旋律,使用了声响和电音的组合,即兴的吉他伴奏。” 潘多拉网站的推荐系统是基于一个名为音乐基因的项目。

他们雇佣了专业的音乐家对歌曲进行分类(提取它们的“基因”)。其实这些基因就是歌曲的特征。

特征值选取的重要性

你知道吗? 潘多拉网站为歌曲甄别出400多种特征。

假设潘多拉会用曲风和情绪作为歌曲特征,分值如下:

曲风:乡村1分,爵士2分,摇滚3分,圣歌4分,饶舌5分

情绪:悲伤的1分,欢快的2分,热情的3分,愤怒的4分,不确定的5分

比如James Blunt的那首You're Beautiful是悲伤的摇滚乐,用图表来展示它的位置便是:

比如一个叫Tex的用户喜欢You're Beautiful这首歌,我们想要为他推荐歌曲。

我们的歌曲库中有另外三首歌:歌曲1是悲伤的爵士乐;歌曲2是愤怒的圣歌;歌曲3是愤怒的摇滚乐。你会推荐哪一首?

也许你已经看出了这种算法中的不足,乡村和爵士的距离是1,乡村和摇滚的距离是2,悲伤的乐曲和快乐的乐曲是相近的等等。 即使调整了分值的分配,也不能解决问题。这就是没有选取好特征值的例子。

乡村、爵士、摇滚、圣歌、饶舌这些类型应该是等价的。因此我们将每种歌曲类型拆分成单独的特征,并对此进行打分:

“乡村(Country)”一栏的1分表示完全不是这个乐曲风格,5分则表示很相符。这样一来,评分值就显得有意义了。如果一首歌的“乡村音乐”特征是4分,另一首是5分,那我们可以认为它们是相似的歌曲。

其实这就是潘多拉所使用的特征抽取方法。每个特征都是1到5分的尺度,0.5分为一档。特征会被分到不同的大类中。通过这种方式,潘多拉将每首歌曲都抽象成一个包含400个数值元素的向量,并结合我们之前学过的距离计算公式进行推荐。

简单的示例

我们先来构建一个数据集,我选取了以下这些特征(可能比较随意),使用5分制来评分(0.5分一档):

使用钢琴的程度(Piano):1分表示没有使用钢琴,5分表示整首歌曲由钢琴曲贯穿;

使用美声的程度(Vocals):标准同上

节奏(Driving beat):整首歌曲是否有强烈的节奏感

蓝调(Blues infl.)

电音吉他(Dirty elec. Guitar)

幕后和声(Backup vocals)

* 饶舌(Rap infl.)

然后我们便可以使用距离计算公式了,比如要计算Dr. Dog的Fate歌曲和Phoenix的Lisztomania之间的曼哈顿距离:9

music = {"Dr Dog/Fate": {"piano": 2.5, "vocals": 4, "beat": 3.5, "blues": 3, "guitar": 5, "backup vocals": 4, "rap": 1},

"Phoenix/Lisztomania": {"piano": 2, "vocals": 5, "beat": 5, "blues": 3, "guitar": 2, "backup vocals": 1, "rap": 1},

"Heartless Bastards/Out at Sea": {"piano": 1, "vocals": 5, "beat": 4, "blues": 2, "guitar": 4, "backup vocals": 1, "rap": 1},

"Todd Snider/Don't Tempt Me": {"piano": 4, "vocals": 5, "beat": 4, "blues": 4, "guitar": 1, "backup vocals": 5, "rap": 1},

"The Black Keys/Magic Potion": {"piano": 1, "vocals": 4, "beat": 5, "blues": 3.5, "guitar": 5, "backup vocals": 1, "rap": 1},

"Glee Cast/Jessie's Girl": {"piano": 1, "vocals": 5, "beat": 3.5, "blues": 3, "guitar":4, "backup vocals": 5, "rap": 1},

"La Roux/Bulletproof": {"piano": 5, "vocals": 5, "beat": 4, "blues": 2, "guitar": 1, "backup vocals": 1, "rap": 1},

"Mike Posner": {"piano": 2.5, "vocals": 4, "beat": 4, "blues": 1, "guitar": 1, "backup vocals": 1, "rap": 1},

"Black Eyed Peas/Rock That Body": {"piano": 2, "vocals": 5, "beat": 5, "blues": 1, "guitar": 2, "backup vocals": 2, "rap": 4},

"Lady Gaga/Alejandro": {"piano": 1, "vocals": 5, "beat": 3, "blues": 2, "guitar": 1, "backup vocals": 2, "rap": 1}}

计算曼哈顿距离

def manhattan(rating1, rating2):

"""Computes the Manhattan distance. Both rating1 and rating2 are dictionariesof the form {'The Strokes': 3.0, 'Slightly Stoopid': 2.5}"""

distance = 0

total = 0

for key in rating1:

if key in rating2:

distance += abs(rating1[key] - rating2[key])

total += 1

return distance

找出最近的歌曲,并且推荐

def computeNearestNeighbor(username, users):

"""creates a sorted list of users based on their distance to username"""

distances = []

for user in users:

if user != username:

distance = manhattan(users[user], users[username])

distances.append((distance, user))

# sort based on distance -- closest first

distances.sort()

return distances

def recommend(username, users):

"""Give list of recommendations"""

# first find nearest neighbor

nearest = computeNearestNeighbor(username, users)[0][1]

recommendations = []

# now find bands neighbor rated that user didn't

neighborRatings = users[nearest]

userRatings = users[username]

for artist in neighborRatings:

if not artist in userRatings:

recommendations.append((artist, neighborRatings[artist]))

# using the fn sorted for variety - sort is more efficient

return sorted(recommendations, key=lambda artistTuple: artistTuple[1], reverse = True)

假设我有一个朋友喜欢Black Keys Magic Potion,我便可根据曼哈顿距离来进行推荐:

print(computeNearestNeighbor('The Black Keys/Magic Potion', music))

[(4.5, 'Heartless Bastards/Out at Sea'), (5.5, 'Phoenix/Lisztomania'), (6.5, 'Dr Dog/Fate'), (8.0, "Glee Cast/Jessie's Girl"), (9.0, 'Mike Posner'), (9.5, 'Lady Gaga/Alejandro'), (11.5, 'Black Eyed Peas/Rock That Body'), (11.5, 'La Roux/Bulletproof'), (13.5, "Todd Snider/Don't Tempt Me")]

这里我推荐的是Heartless Bastard的Out as Sea,还是很合乎逻辑的。

评分标准

评分标准不一是所有推荐系统的大敌!

举个有趣的例子。在婚恋网站上,我通过用户的年龄和收入来进行匹配:

可以看出,年龄的最大差异是28,而薪资的最大差异则是72,000。因为差距悬殊,薪水的高低基本决定了匹配程度。

如果单单目测,我们会将David推荐给Yun,因为他们年龄相近,工资也差不多。

但如果使用距离计算公式,那么53岁的Brian就会被匹配给Yun,这就不太妙了。

面对这样的问题,不用担心,我们可以使用标准化。

标准化

要让数据变得可用我们可以对其进行标准化,最常用的方法是将所有数据都转化为0到1之间的值。

拿上面的薪酬数据举例,最大值115,000和最小值43,000相差72,000,要让所有值落到0到1之间,可以将每个值减去最小值,并除以范围(72,000)。这样所有的薪酬都落到了0和1之间。

如果你学过统计学,会知道还有其他的标准化方法。

比如说标准分(z-score)——分值偏离均值的程度:

但是标准分也不是完美的,它也存在一些问题。

标准分的问题在于它会受异常值的影响。

比如说一家公司有100名员工,普通员工每小时赚10美元,而CEO一年能赚600万,那全公司的平均时薪为:

# 100个员工每小时10美元+ 一年52周,一周40小时

a = (100*10+6000000/40/52)/101

print(a)

38.46153846153846

结果是每小时38美元,看起来很美好,但其实并不真实。鉴于这个原因,标准分的计算公式会稍作变化。

修正的标准分

计算方法:将标准分公式中的均值改为中位数,将标准差改为绝对偏差。

绝对偏差是每个数与中位数的差值求和,然后再平均得到的。

首先将所有人按薪水排序,找到中位数,然后计算绝对偏差:

# 最后,我们便可以计算得出Yun的修正标准分:

print((75000-69500)/19125)

0.2875816993464052

是否需要标准化?

当物品的每个特征数值尺度不一时,就有必要进行标准化。

比如我想在新墨西哥圣达菲买一处宅子,下表是一些选择:

可以看到,价格的范围是最广的,在计算距离时会起到决定性作用;同样,有两间卧室和有二十间卧室,在距离的影响下作用也会很小。

需要进行标准化的情形:

我们需要通过物品特性来计算距离; 不同特性之间的尺度相差很大。

过分的使用标准化,反而会降低结果正确性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值