Thursday, January 21st, 2010
一些MP3播放器(包括iphone、ipod、itouch、blackberry等)可以在播放mp3的时候显示专辑图片、歌词等信息而不需要额外的图片文件和歌词文件,仅仅一个mp3文件就搞定,比较有意思。除了用专门的软件(比如itunes)来制作这样的mp3,我们还可以用程序来批量生成。
查阅mp3头信息ID3V2的技术文档,发现可以往ID3信息里面加入歌词和图片信息(可以在页面上查找Lyrics、Attached picture就能发现相应的内容)。有了官方格式上的支持,我们要做的就是把歌词和图片加入到MP3文件中去。
测试一些开源的软件包,发现一个比较可靠的:eyeD3,由python语言编写,直接上代码:
#coding=utf-8
import eyeD3
import re
# mp3文件
mp3_file = '/path/to/foobar.mp3'
# lrc歌词文件
lrc_file = '/path/to/foobar.lrc'
# 专辑图片
pic_file = '/path/to/foobar.jpg'
# 实例化eyeD3
tag = eyeD3.Tag()
# 绑定到mp3文件
tag.link(mp3_file)
# 去掉原文件中可能存在的图片
tag.removeImage()
# 去掉原文件中可能存在的歌词
tag.removeLyrics()
# 设定编码,非常重要,否则不支持中文
tag.encoding = '\x01'
# 添加图片
tag.addImage(3, pic_file, u'')
# 添加歌词,注意要utf-8编码,去掉lrc中时间信息
tag.addLyrics(re.sub('(\[.*?\][\n]*)+', '', unicode(open(lrc_file, 'r')).read(), 'utf8')))
# 更新到文件
tag.update()
代码非常简单,需要注意的是设定编码,不然歌词就乱码了。有了eyeD3之后,可以写个爬虫,从网上抓下歌词和图片直接灌进MP3文件里面,剩下的就是享受了。
Posted in 默认分类 | 2 Comments »
Thursday, November 12th, 2009
从2亿个0~2,000,000,000之间的数字样本中找出不重复的记录总数,首先想到的是bloom filter,转念一想既然全都是数字,bloom filter有点太重,bitarray也许更有效,于是第一个版本出来,部分代码如下:
ba = bitarray(212**4)
cnt = 0
for i in data:
if (not ba[i]):
cnt += 1
ba[i] = True
print cnt
大概需要140s左右,觉得if (not ba[i]):这个比较费,改了第二版:
for i in data:
ba[i] = True
print ba.count()
速度有所提升,到了120s左右,开始打起多核运算的主意了,山寨了一个map-reduce,首先通过maper把数据按照除4得余分成4份:
def maper(data):
...
Posted in Python | 8 Comments »
Thursday, March 12th, 2009
这里测试的环境是:windows xp,office 2007,python 2.5.2,pywin32 build 213,原理是利用win32com接口直接调用office API,好处是简单、兼容性好,只要office能处理的,python都可以处理,处理出来的结果和office word里面“另存为”一致。
#!/usr/bin/env python
#coding=utf-8
from win32com import client as wc
word = wc.Dispatch('Word.Application')
doc = word.Documents.Open('d:/labs/math.doc')
doc.SaveAs('d:/labs/math.html', 8)
doc.Close()
word.Quit()
关键的就是doc.SaveAs('d:/labs/math.html', 8)这一行,网上很多文章写成:doc.SaveAs('d:/labs/math.html', win32com.client.constants.wdFormatHTML),直接报错:
AttributeError: class Constants has no attribute 'wdFormatHTML'
当然你也可以用上面的代码将word文件转换成任意格式文件(只要office 2007支持,比如将word文件转换成PDF文件,把8改成17即可),下面是office 2007支持的全部文件格式对应表:
wdFormatDocument = ...
Posted in Python | 3 Comments »
Tuesday, January 6th, 2009
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2009/01/slope-one-on-netflix-prize/
前段时间做了个slope one算法在Netflix Pirze上的测试,关于slope one算法可以参考我之前写的文章:Slope one:简单高效的推荐算法,Netflix Prize是DVD在线租赁商Netflix于2006年10月2日发起一项竞赛:任何组织或个人只要能够提交比它现有电影推荐系统Cinematch效果好10%的新方法,就可以获得100万美元的奖金。竞赛最多持续到2011年10月2日。同时,NetflixPrize还提供每年5万美元的年度进步奖。为什么是五万美元的年度进步奖呢?因为100万美元大奖存银行,每年的利息是5万美元,看来老外是挺有意思的。
Netflix Pirze采用RMSE作为评测的标准,RMSE中文的意思是均方根误差,计算的公式:
其中Ot是原始数据,Ft是预测数据,n是样本数。
目前最好的成绩是有BellKor in BigChaos创造的0.8598(2009.01.05数据),比官方数据提高9.63%,这样可以推算出官方的数据应该是0.9492左右,BellKor in BigChaos也是2008年度进步奖的获得者,他们更新数据的频率很高,如不出意外,最后的大奖应该是他们的。
目前的方向大多是SVD奇异值分解,可以参见BellKor in BigChaos他们的文章http://www.netflixprize.com/community/viewtopic.php?id=1193,这里有一个开源的项目nprize,也是一个SVD处理Netflix Prize的模型,大部分代码是Python的(国外很多用Python做数据挖掘和自然语言处理的案例),成绩到了0.9046,折算比官方数据要高4.70%,如果你想拿SVD热热手,可以看看这个开源项目,过些日子我会写一些SVD应用在推荐系统方面的文章,着急的可以阅读吴军的文章数学之美 系列十八 - 矩阵运算和文本处理中的分类问题。
由于对slope one算法比较熟悉,决定看看slope one算法在netflix pirze上的表现如何,netflix prize训练数据太大,大概有1亿多条的打分记录,OpenSlopeOne在运行效率方面不是很好,OpenSlopeOne处理几百万上千万的打分数据还是非常不错的,更多的话需要更多的机器水平扩展,如果有好的Mysql DBA可以尝试优化一下mysql server的参数,估计效果会很好,当然也需要有好的机器配合,我这里是用Python写的一个程序,多进程+多线程+手工Map-Reduce,需要源代码的话可以找我拿。
跑出来的结果不是很好,我的得分是0.9829,比官方数据差0.0337,大概差3.55%,分析原因可能是用户打分的数据普遍偏高,人们大多给自己喜欢的电影打分,对于不喜欢的数据打分就少很多了,下面是打分数据的分布情况:
mysql> select rating,count(*) as times from nf_log group by rating;
+--------+----------+
| rating | times |
+--------+----------+
| 1 | 4617904 |
| 2 | 10131945 |
| 3 | 28810978 |
| 4 | ...
Posted in Data Mining | 4 Comments »
Tuesday, December 23rd, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/12/python-thread-pool/
最近在做一些数据挖掘方面的工作,需要对海量的数据进行处理,在目前的硬件环境下,多进程+多线程的方式对运算时间的减少大有裨益,我用的是Python语言,开发效率高,运算效率也不低。
Python里面成型的线程池可以看以下http://www.chrisarndt.de/projects/threadpool/,看了一下API介绍,应该写的比较完备了,我这里想介绍的是Python线程池实现的原理以及一个简明的线程池代码实例。
我这里是用Queue这个包来实现的,Queue翻译成中文就是队列,全局的,我们把任务放进队列中去,然后开N个线程,每个线程都去队列中取一个任务,执行完了之后告诉系统说我执行完了,然后接着去队列中取下一个任务,直至队列中所有任务取空,退出线程。
这就是一般的线程池实现的原理,下面看一个实际的代码:
import time
import threading
import Queue
class Worker(threading.Thread):
def __init__(self, name, queue):
threading.Thread.__init__(self)
self.queue = queue
self.start()
def run(self):
# 著名的死循环,保证接着跑下一个任务
while True:
# 队列为空则退出线程
if self.queue.empty():
break
# 获取一个项目
foo = self.queue.get()
# 延时1S模拟你要做的事情
time.sleep(1)
# 打印
print self.getName(),':', foo
# 告诉系统说任务完成
self.queue.task_done()
# 队列
queue = ...
Posted in Python | No Comments »
Tuesday, August 26th, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/08/data-mining-with-python-orange-association_rule/
最近,趁着项目的间隙,折腾了一阵数据挖掘,在同事的帮助下,对新浪音乐用户的听歌记录进行了一个简易挖掘,希望能根据用户以往的听歌记录,推荐出用户可能感兴趣的其他歌曲。
Orange:
一个模块化的C++数据挖掘包,提供python接口(好像也只提供了python接口),网址是http://www.ailab.si/orange/
关联分析:
我这里用的是类似购物篮分析,每个用户的听歌id是一个事务,不熟悉关联分析的同学可以去搜一些相关方面的资料。
数据准备:
简单清洗掉一些“脏”数据(逻辑上有问题的数据,比如某个用户在5s听了200首歌),得到类似下面的数据
15615,355029,750367,762147,803787,805014,999712,999712,999712,1013641,1024215,1028429
871029,952779,962769
1023040,1024077,1024215,1025600
757946,873801,873801,873801
862257,873479
286056,286056,286056,286056,286056,286056,286056,286056,286056,286056
873801,873801,873801,873801,873801,947750,947750
473221,473537,504206,504206,504206,504206,504206,504206
947750,1005430,1005430
974748,1024215
873479,873479,873801,873801,947750,965748,999721,1024215,1024215,1024215,1024215,1024215
873801,873801,873801
每一行是一个用户的听歌记录,没有做去重处理(orange示例中也没有,是不是可能会增加歌曲的权重?不清楚,没有去阅读orange代码),注意文件名一定要以.basket为扩展名,程序中文件地址是d:/datamining/sample.basket。
程序:
# 导入orange包
import orange
# 导入数据,注意不需要后缀
data = orange.ExampleTable("d:/datamining/sample")
# 挖掘关联规则,输入最低支持度、最低置信度、最大项集数
rules = orange.AssociationRulesSparseInducer(data, support = 0.5, confidence = 0.6, maxItemSets = 1000000)
# 打印出规则来
for r in rules:
print "%5.3f %5.3f %s" % (r.support, r.confidence, r)
是不是非常的简单?Orange实现的是Apriori算法,由于Apriori算法的问题,一旦数据量非常大,你就等着你的内存消耗光吧,反正我这边要是把所有数据都导入进去的话,笔记本1.5G的的内存根本不够用,可以试试FP-tree算法,我这边参考文章利用sql改良构建fp-tree之技术,已经把fp-tree的前缀路径都找出来了,需要的朋友可以私下找我要,由fp前缀路径挖频繁集需要用到递归,用sql去处理就非常费劲了,所以后面的算法还需要自己去探索。
居于关联规则的挖掘就告一段落,因为算法的计算复杂度非常高,效果倒不是太好(因为对于音乐,用户可能听多遍,这样打分就不一样,可能用关联规则去挖电影类的数据比较好,因为电影一般最多就看一遍),现在研究的是协同过滤,如果不出意外的话,一个改良版的PHP+Mysql实现slope one算法过几天就要出来了,到时候我会开源出来的。
Posted in Data Mining, Python | 1 Comment »