Skip to content


follow人,还是follow内容

天下大势,合久必分,分久必合。自从有了网站,数字信息就开始多了起来,直到我们拥有搜索引擎之前,这些信息都没有被很好地组织。自从有了feed流这个概念,信息突然又瞬间地膨胀了起来,在我们找到一个合适的工具之前,这些信息都没法被很好地推送到合适的人面前。一直以来,人们从没停止过要把各种如毛细血管般的流信息整合到一起。特别是一些已经远在墙外的优秀网站,做出了很多很好的解决方案,facebook之类的SNS网站试图通过现实朋友的关系来组织feed流,无所不包的friendfeed企图把所有的feed信息都归于一处(国内类似的有今年张教主写的kanrss),这两年成为新贵的twitter则使得流信息的产生更容易,接收更便捷,follow即所得。

上述对信息的解决方案都是通过follow人来实现,而follow内容无疑是另一条可行的路径。关于内容的分类组织已经有很多年的研究与实践,在郑昀的这篇关于Topic Engine的博客中有很详细的综述,而对这些分类内容的follow,以得到一个类别的信息更新,就我所知,还并不多见。比较知名的如google资讯与google快讯,前者属于对内容的分类组织,后者则属于对分类内容的订阅或者说follow。依托于google强大的搜索能力,信息的新颖性及广阔性很有保证,但由于产品的定位并非要作一个详细的内容分类,所以分类比较粗糙,只是一些如门户网站般的粗分类别而已。

最近上线的cutt.com则希望把这种分类信息推送做到极致,这是一家号称以语义网技术作为其底层分析引擎的公司。它的上线,首先要感谢国家,否则也许我们能早几个月看见它。因为谷文栋的介绍,我得以在早期就对这个有着很大野心但目前还不甚成熟的信息组织引擎有一定的使用体验。这是一个很有想法的新生儿,但现在有些地方也还不太成熟。

产品与交互方面:
一个由工程师主导的公司容易做出让人拍案叫绝的创意产品,却也容易暴露一些产品设计与交互上的毛病,这也许是因为聪明的工程师们总是很难让自己处身在大多数不知情用户的处境里。

cutt很好的一点是用户使用零成本,任何一个用户打开即可用,无需要注册,也无需进行任何信息填写。我在匿名状态下就能进行大部分的操作,没有注册没有登录情况下收藏的文章居然还能保存,很激动人心吧!但是可怕的事情来了,一旦我登录上去,会发现我之前以为已经记录下来的所有数据都不见了。好吧,我也许原以为它会自动地把匿名信息自动导入到我的帐号中。但后来想想,如果它这样做了,我肯定会更恐惧的。其实我的意思是:我没有得到任何提示的情况下,我不知道我刚刚还在的数据到哪去了。对于普通用户,可能还有一个困扰就是换个浏览器,这些数据也没了,用户不会觉得自己有错,他们只会认为是你们把他们的数据弄丢了。同样的情况是我写的文章反馈,写完后同样无影无踪,虽然我知道cutt的数据库中肯定还有记录,但大多用户同样会认为你把TA的数据弄丢了。虽然我不是做产品的,但我觉得这里有一个原则:用户贡献的数据TA一定还能找回来,否则后果绝不仅是TA不再愿意贡献那么简单。

另外就是内容方面的,由于是一个新生儿,内容频道还不足够完善,比如摄影器材方面的内容也没有,因为我最近关注这个,所以一下就看到了这个,但估计其它方面的频道还是有缺失。再比如,我发现cutt不喜欢娱乐,因为很多娱乐版面都还是空的:)。以内容为主打的网站的其中一个核心竞争力就是信息的更新速度,而cutt的信息更新的速度还有待提高,我晚上十点钟时看到的最新文章还是下午五点多的,不知道是受制于爬虫还是算法的处理速度。另外,展现方式也许还可以改进,简洁是一种方式,但如果仅仅只是以新闻作为主要载体的话,加入一些具有视觉力的元素可能会更吸引人。

技术方面:
预览:我很喜欢cutt的文章预览功能,这样我就不用点过去等整个页面加载了。但我不知道还能不能进行进一步的过滤,采用文本摘要技术,把主要内容以几句话就传递出来。对于现在快餐型的社会消费习惯,这无疑是一个很有竞争力的feature。我甚至考虑过由人来对这些摘要信息进行抽取,这也是群体智能的一部分。

来源:据我的观察,现在的cutt仍然以网页这种非结构化信息为主,来源也主要是一些大中型的门户或资讯网站。实际上在现在这个mashup的年代,网络上的RSS源很多,如果能充分利用博客及一些web2.0网站输出的RSS半结构化信息,信息的来源肯定会更丰富,可分析性肯定更强。当然我估计cutt肯定也有这方面的内容,只是还没有更多的放出来。

google reader:曾经我是一个google reader的重度用户,几乎每天必看,也订阅了大量感兴趣或半感兴趣的rss源,并煞有其事地把它们归类为算法、网络、科学、IT资讯、业余等等频道。但后来我已经越来越少地去看它,任由那1000+的未读永远地停留在左上角。究其原因,是因为follow的内容是死的,而follow的人是活的,是有感情因素在里面的,所以如果一个人没有更多的时间,TA会更倾向于刷自己的微薄,而非冷冰冰的内容。但信息的需求还是有的,所以我现在更多地在消费经过朋友过滤的信息。如果一个算法能有更好的过滤能力,我还是很乐意去使用的,特别是个性化的信息推荐。因为友邻推荐是给所有人的,而非专属你自己,而这方面,机器可以做的更好。

个性化信息推荐:虽然cutt现在还没有,但我知道将来肯定会有,现在只不过是要度过一个用户信息的冷启动期,贡献越多,收获越多。但信息个性化是一个比信息组织难的多的课题,除了考虑内容的语义与关系,现在再加进一层比内容要复杂得多的人的因素,解决好这个问题,任重而道远。

思想层面:
最后来点虚的。
集体智能的利用:不单是利用用户隐式的反馈数据加以社会化的推荐那么简单,它更重要地还包括用户显式地、自愿地贡献的内容。比如wikipedia的客观权威性居然来自于无数个网民自发的编辑行动,再比如语义网的标杆freebase的构建也是有赖于大量的志愿者对它的贡献。完全依靠用户的积极性显然不行,特别是在国内互联网环境中人们往往更乐于索取而非贡献,怎么能让用户快快乐乐地贡献自己的智慧是一个很难的设计问题。从另一个角度来思考,这个问题其实也并非那么地困难,我们简单地估计一下之前红透半边天的“开心农场”,有多少个网民在那上面花费了多少的时间,折合成被耗费的智慧时间,这该是多么庞大的一个数字!如果,我们在一个如此盛行的游戏中盛载了一定的智慧任务,而用户能在玩耍游戏的过程中就能帮助我们解决一个又一个的机器不能解决的智慧难题,这该是多么的激动人心啊!

事实上,在过去的日子里,已经有人作过这样的尝试,像我上述所提及的一类游戏有其名为Game ith a purpose,就是希望能透过游戏的方式,让人去解决一些人本身看来显而易见,但目前的机器学习方法仍然无法做好的问题,比如图片内容识别的问题。到目前为止,关于这种思想最著名的一个案例应该就是 reCAPTCHA,这个游戏曾经成功地帮助人们解决了印刷物扫描成电子物时某些内容无法识别的问题。这样的一种以人作为驱动的计算思想,国内有人译之为“人本计算”。

这个留待以后再专门论述。

Posted in Algorithm.


世界杯后记

已经过去近两周了,世界杯的热情在消退,四年前我全程地写下看球笔记,今年我一直懒于动手。后来想了想还是记一些东西吧,算是给这又一个人生驿站留下点回忆。

没有了四年前的激情澎湃,这一次,我大部分的场次,都是坐在那个10cm*15cm的网络直播窗口前,听着那一成不变的苍蝇声,看着时间静静地在球场每个角落流淌,看着岁月的痕迹划过卡纳瓦罗的眼眶亨利的额头,看着成熟与责任写满了C罗与梅西曾经青涩的脸庞。我们也在随着他们一个四年又一个四年地长大,变老。

我必须得很俗地冒用那句流行的网络用语:世界杯就是个大茶几,个别人得到洗具,大多数人只能得到杯具。让我们简单地回顾一下,这一个月的时间里,他们所演绎过的人生。这些人,存在于世界的每个角落,这些事,正在我们的身边发生。

亨利:即使奉献所有,组织也会毫不犹豫地把你抛弃

如果这个世界上有如果,亨利还会不会选择冒着搭上自己一世英名的风险,把法国队送到南非?他是个天才,他也很勤奋,只是他一直都生活在巨人的阴影下。直到某一天他认为自己可以当家作主了,才忽然发现,自己已经老了,老得即使你为集体牺牲了所有,集体也会毫不犹豫地把你牺牲掉。而自己忍辱负重所换来的,只是另一个更耻辱的结果,最可悲的是你只能眼睁睁地看着它发生,除了做一些场下的努力,然后被所有的人唾骂,你无能为力。前些天,亨利宣布退出国家队,同多梅内克一样,他的错误只是在于没有在合适的时间选择离开,同样情况的还有卡纳瓦罗,我们不能责怪他们,就在大家都在赞颂急流勇退的勇气的时候,他们心中只是仍有一些信念在坚持,这在足球场上很常见,一如大卫贝克汉姆。

科威尔:徘徊在宿命与挚爱的人

本来一次无可争议的判罚,却因为这个人背后的故事,而变得无比悲情,他可以坦然接受命运的判决,却无法释然地接受裁判的判罚。这是本届世界杯最触动我的一个人、一件事,我看到了一个科威尔身后千千万万个科威尔的身影。疾病几乎夺走了他的一切,除了他的追求,所以他的理想得以继续,直到他再一次倒在命运的嘲弄下,所谓造物弄人。为了保护我们脆弱的心灵,故事、电影,常会给我们美好的结局,然而这才是现实,他抗争了,但是他再一次失败了,如果他选择继续抗争,他也许还会继续失败下去,直到有一天,他松开那根死死缠着他的绳索。

马拉多纳:感性与理性的交集在哪里?

哪一名球员是世界杯上最耀眼的明星,这个问题可以众说纷纭,但如果问世界杯上谁最具有感染力,那毫无疑问就是马拉多纳。这个一生充满争议的天使与魔鬼的结合体,在一次0:4的惨败之后,也再一次深深地跌入到自己情绪的谷底。疯狂如马拉多纳,即使他失败,他的队员仍然愿意为他而继续战斗,他的国民仍然选择相信他。只是这一回,是彻底地倒在了理性、科学的德国人脚下,再无如二十年前那般争议的余地。当性感的探戈遭遇严肃的战车,失败的总是感性的舞者,更何况,现在这个舞者根本都无法轻盈地舞动。即使阿根廷人仍然会选择相信这个他们心中神一样的男人,相信他必定会找到一个感性与理性的交汇点,然而,二十多年前,阿根廷依靠的是马拉多纳,二十多年后,阿根廷依靠的还是马拉多纳,阿根廷足球和巴西足球的差距,也许就是一个不世出的天才与很多很多天才的差别。

苏亚雷斯:当童话发生在人间

比赛的最后一分钟,作为一名前锋的他,作出了排队运动员般的拦网动作,把必进球扑了出去,又在沮丧中目睹了自己球队从地狱到天堂的过程,自己则经历了从罪人到英雄的一幕,经此戏剧性的几分钟,谁能不动容。世界上无数人被这一幕感动了(非洲人民应该除外),这一刻,人们忘记了身边一切应当有的秩序,而只有时间去感叹:这是一件多么奇妙的事情啊!我想,这其实就是童话故事在有条不紊规规矩矩的世界中的呈现,就像多年前的黛安娜王妃,当灰姑娘出现在自己的世界,谁又能不感动。当丹麦童话、希腊神话在欧洲杯赛场上上演,你会知道,在足球场上,童话是会真真切切地发生的。那场比赛结束后,我曾发了一条广播调侃道:按照近年南美和欧洲轮流夺冠的规律,我猜乌拉圭进决赛,苏亚雷斯在决赛中以守门员身份出战,最后点球大战扑出对方5个点球,然后自己罚进最后一个球,成为一代传奇。奇迹真的会有的,童话真的会发生的,如果在你的生活中没有,那么,关注那个绿茵场吧。

巴拉克:你以为自己是属于她的,她却渐渐远离了你

虽然他没有来,虽然在足总杯的决赛中他被自己德国队的队友博阿腾的哥哥加纳的博阿腾铲伤而无法参加这也许是他最后的一次世界杯,但在很多人眼中,这些年的德国队与他已经难以分清,从他伤后到德国训练营探营,从他到南非看德国队的比赛,从拉姆说即使他回来自己也不会交出队长袖标,从他在半决赛前因为倍感冷落离开南非并坚持声称如果德国进了决赛还会回来,从德国结束所有比赛后施魏因施泰格说自己心中的队长只有巴拉克,谁又能区分德国队和巴拉克。随着德国足球风格从传统坚韧硬朗到现在华丽奔放的转变,他很有可能成为旧德国战车的最后一个代表性人物。当德阿大战中德国新13号托马斯穆勒大放异彩,解说员说如果镜头没有捕捉到巴拉克坐在观众席上,大家也许早已经忘记这位曾经的13号的主人。从来只见新人笑,哪里见得旧人哭,切尔西已经不再需要他,德国队也已经不再需要他,他一直在追求自己的巅峰时刻,却永远都只差一步,最后剩下来陪伴他的,也只是落寞。真的斗士,即使落寞如是,也会选择坚持下去。

又一个四年落下帷幕,又一个四年将揭开它神秘的面纱。面对着过去的和即将来到的一切,我们又将何去何从。我想,三四名比赛第92分钟所发生的就浓缩了世界杯关于结束的一切,当弗兰的任意球呼啸着击中横梁,裁判的哨声随即响起,在高潮中落幕,在紧张中分出了胜负,留给你无尽的想像,而你还未曾有时间从中走出来。

Posted in Life & Thinking.


可能是史上代码最少的协同过滤推荐引擎

自世界杯开幕以来,这是首次看不到球赛的两天,看不了球,就写篇博客吧,标题比较有噱头,实际上是用R实现的item-based CF推荐算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 读入数据,原数据是user-subject的收藏二元组
data = read.table('data.dat', sep=',', header=TRUE)
# 标识user与subject的索引
user = unique(data$user_id)
subject = unique(data$subject_id)
uidx = match(data$user, user)
iidx = match(data$subject, subject)
# 从二元组构造收藏矩阵
M = matrix(0, length(user), length(subject))
i = cbind(uidx, iidx)
M[i] = 1
# 对列向量(subject向量)进行标准化,%*%为矩阵乘法
mod = colSums(M^2)^0.5  # 各列的模
MM = M %*% diag(1/mod)  # M乘以由1/mod组成的对角阵,实质是各列除以该列的模
#crossprod实现MM的转置乘以MM,这里用于计算列向量的内积,S为subject的相似度矩阵
S = crossprod(MM)
# user-subject推荐的分值
R = M %*% S
R = apply(R, 1, FUN=sort, decreasing=TRUE, index.return=TRUE)
k = 5
# 取出前5个分值最大的subject
res = lapply(R, FUN=function(r)return(subject[r$ix[1:k]]))
# 输出数据
write.table(paste(user, res, sep=':'), file='result.dat', quote=FALSE, row.name=FALSE, col.name=FALSE)

除去注释,有效代码只有16行。其中大量运用了向量化的函数与处理方式,所以没有任何的显式循环结构,关于向量化更详细的叙述可看这里

注:该代码实现的只是最基本算法,仅作参考,不承诺在大规模与复杂数据环境下的实用性。

源数据文件data.dat的内容如下所列:

user_id,subject_id
1,1
1,3
1,7
1,13
2,2
2,5
2,6
2,7
2,9
2,10
2,11
3,1
3,2
3,3
3,4
3,7
3,9
3,10
5,13
6,1
6,3
6,4
6,5
6,8
6,10
8,1
8,2
8,3
8,5
8,6
8,7
8,8
9,13
10,12
11,2
11,3
11,4
11,6
11,8
11,9
11,13
12,12
13,3
13,6
13,7
15,4
15,12
15,13
16,2
16,3
16,4
16,7
16,8
17,2
17,3
17,4
17,5
17,6
17,7
17,8
17,9
17,10
17,11
18,2
18,3
19,2
19,3
19,5
19,6
19,9
19,10
19,11
19,12
20,1
20,3
20,4
20,7
20,13
21,1
21,6
21,8
21,9
21,11
21,12
21,13
22,6
23,2
23,4
23,9
23,12
24,1
24,5
24,9
25,2
25,6
25,10
25,11
26,2
26,3
26,8
27,3
27,6
27,12
27,13
28,1
28,2
28,3
28,5
28,7
28,9
28,10
28,11
28,12
28,13
29,1
29,2
29,3
29,4
29,5
29,6
29,7
29,8
29,9
29,10
30,6
30,7
30,9
30,13
31,6
31,11
32,1
32,5
33,2
33,13
34,3
34,7
34,8
34,9
34,10
34,13
35,3
35,4
35,5
35,6
35,7
36,2
36,3
36,4
36,6
36,7
36,8
36,9
36,11
36,12
36,13
38,5
41,1
41,3
41,4
41,5
41,6
41,7
41,11
42,2
42,3
42,7
42,8
42,9
42,10
42,11
43,2
43,6
43,10
43,11
43,12

Posted in Programming.

Tagged with , .


向量化与并行计算

应用场景决定知识的储备与工具的选择,反过来,无论你选择了什么样的工具,你一定会努力地把它改造成符合自己应用场景所需的那个样子。从这个道理来说,我选择了R作为数据挖掘人员手中攻城陷池的那把云梯,并努力地把它改造成自己希望的那个样子。

我最初接触到专门用于科学计算的工具,是大名鼎鼎的matlab,正如它帮助了无数中国学生顺利毕业的赫赫功劳一样,它是我对于向量化计算的启蒙老师。用过matlab的人都会对其循环结构的效率无法忍受,不知道是否有意而为之的这样的设计缺陷,迫使人们要想真正地用好它,就得接受它提供的向量化计算的思想,在掌握了这个专门为高效计算而设计的计算思想之后,你会发现自己获得的不单是计算效率上的极大提升,还有算法设计思想上高屋建瓴式的跨越。

毕竟matlab是更适合于研究领域的商业软件,而且是闭源的,毕业后不久,我就选择了R作为matlab的替代品,看中的正是R在向量化计算支持之余的灵活性及丰富的第三方库,似乎天生就是数据挖掘人员最趁手的那把刀。因为我需要的就是这样的一个计算环境,它不单是一门编程语言,也不必是一个已经很完备的工具。它就是这样的一个环境,拥有很多的各领域相关的工具包,我可以不必操心太多过于底层的或与工作主题没有直接关系的问题,同时当不满意时我又具有对它最自由的掌控。实际上,我寻求的就是matlab与C之间的一个平衡点。R是一个面向科学工程计算特别是统计计算的工具,与matlab一样,其循环结构的效率也无法让人满意,所以,我们必须利用向量化的编程范式,必要时采用并行/分布计算(因为,向量化本质上就是一种并行计算,也是我们通常理解那种并行计算的天然先驱)。而这一切,在R面前,都不是什么问题。

所谓向量化

wikipedia中的定义是:Vectorization is the more limited process of converting a computer program from a scalar implementation, which processes a single pair of operands at a time, to a vector implementation which processes one operation on multiple pairs of operands at once。向量化计算是一种特殊的并行计算的方式,相比于一般程序在同一时间只执行一个操作的方式,它可以在同一时间执行多次操作,通常是对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量。

像R和matlab这样的现代科学软件包,都会以向量化作为其计算的基本特点(即使python的numpy包也是如此),所以在R的基本运算中,随处可见向量化计算的影子,以下仅举几例,以让读者了解向量化是多么地简单和直观:

向量取值:V[1:10]  (把get操作应用于向量V的不同元素)

向量赋值:V[1:10] <- seq(1,10)  (把set操作应用于一个序列与向量V的对应元素)

apply系列:lapply(V, mean)  (跟python的map函数类似,是向量化最直接的表达形式)

矩阵运算:A + B;A %*% B  (矩阵的基本运算也是向量化的典型形式)

这些操作很常见,以致于我们都没有意识到这就是一种有助于提高计算性能的向量化计算,更忘了由此而把这样的思想扩展到我们算法设计的更多方面。熟练使用它,你获得不单是计算上的好处,还有对问题理解上的整体性。

向量化的处理方式是现代计算机的一个特点,无论硬件还是软件上,都提供了支持。

硬件上的支持:Intel’s MMX, SSE, and ARM’s NEON instruction sets support such vectorized loops.(摘自wikipedia:http://en.wikipedia.org/wiki/Vectorization_(computer_science))

软件上的支持:著名的线性代数运算包blas对矩阵运算的自动并行化。例如,在R里执行如下的简单命令,在不需要作任何额外工作的情况下,就可以自动地实现并行化(前提是你的机器安装了blas)。

1
2
M = matrix(5000*5000, 5000, 5000)  ## 生成一个5000*5000的矩阵
S = M %*% M    ## 作矩阵乘法,在多核并安装了blas的机器里,会自动并行

应用向量化的思维方式去解决问题:

当我们习惯了用C语言的单步循环的思想来思考问题的时候,要把思维切换到向量化的方式是件比较困难的事件,以下显示一个例子,看用向量化的思想是怎么去解决问题,这样的描述又是多么美。

任务:对于稀疏矩阵M,让其第i(i=1…m)行的各非零元素减去某个值w[i]。

正常的循环式思维的解决方案比较直观,作两层循环,让第i行非零元素减去w[i]即可,但这样的操作在脚本语言特别是像R这样的科学计算语言里执行效率不高,而当你面对的是一个稀疏矩阵时,问题又会变得复杂。

向量化的解决方案如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
## 利用向量化的计算范式设计算法
## 实例:稀疏矩阵不同行的各元素减去某个值
 
library(Matrix)
generate <- function(nr, nc, sr){
  L = nr*nc
  M = Matrix(data=0, nrow=nr, ncol=nc)
  idx = sample(1:L, as.integer(sr*L))
  val = rnorm(sr*L, mean=1)
  M[idx] = val
  return(M)
}
 
M = generate(10000, 5000, 0.1)  ## 生成稀疏矩阵
V = rnorm(10000)  ## 矩阵各行减去的值
N = M
N@x = 1  ## 复制并设置矩阵
A = Diagonal(nrow(N), V) %*% N  ## 把V的值放到新矩阵的各行非零单元中
M@x = M@x - A@x  # M = M-A

除去数据准备阶段,真正用于解决问题的只有第16到19行的4行命令,十分短小精悍,但需要一定的线性代数知识去理解这个过程。

从向量化到并行计算:

除了计算机硬件与科学计算包的支持外,向量化计算还是并行计算的天然先驱,如果你向量化后的算法效率仍然不佳,可以考虑把它并行化。

R那浩如烟海的第三方包里提供了大量支持并行计算的包,这里选择的是snowfall这个包,它可以简单地构建一个计算集群,把计算并行分布到集群的不同节点进行计算。以下通过一个例子比较循环,向量化以及并行三种方式在效率上的差异。

实战案例:for循环,apply,snowfall(并行)的比较。

任务:对一个矩阵每列排序并取回前10个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
library(snowfall)
 
mysort <- function(x){
#    replicate(2, sort(x))
    return(sort(x)[1:10])
}
 
do_for <- function(M){
    ans = matrix(0, 10, ncol(M))
    for(i in 1:ncol(M)){
        ans[,i] = sort(M)[1:10]
    }
}
 
do_apply <- function(M){
    return(apply(M, 2, mysort))
}
 
do_snowfall <- function(M, ncl){
    sfInit(parallel=TRUE, cpus=ncl)  ##初始化集群环境
    ans <- sfApply(M, 2, mysort)  ##把任务分发到各个slave
    sfStop()  ##关闭集群
    return(ans)
}
 
#M = matrix(rnorm(10000000), 100, 100000)
#system.time(ans <- do_for(M))
#system.time(ans <- do_apply(M))
#system.time(ans <- do_snowfall(M, 4))  ##用4个核并行

在我的服务器里运行的结果是这样的,do_for循环基本不可用,do_apply可以在一分钟内运算完毕,而do_snowfall的时间为do_apply的一半。当取消第4行的注释,即增加各个子任务的计算负荷后,do_apply与do_snowfall的计算时间都增加,而do_snowfall的时间变为do_apply的三分之一。

结论1:向量化的计算方式比起传统的循环计算有极大的性能优势。

结论2:由于并行的过程为:master把任务分解,分发到多个slave进行运算,slave返回结果到master。所以多核计算并不一定比最优的单核计算快,要看性能的瓶颈在slave还是在master上。

结论3:适合并行/分布计算的情景主要有两种:一是各slave的计算耗费为瓶颈,并行到多核能减少计算时间,越是slave耗时型的计算并行收益越大;二是一台机器的内存不足以进行整体的计算,分布到多台机器计算能把内存占用分开,这种情况下即使分布计算比单机慢也是可以接受的。

map-reduce扯扯关系:

Map-reduce是google三驾马车之一,试图把所有计算都转换为map和reduce两种基本的运算方式,而达到良好的可并行性,从而实现计算上的可扩展性。虽然并不是每个公司都能实现像map-reduce那样的巨型计算框架,但是如果你能熟练地使用向量化的思想设计你的算法,那其实就是一个map-reduce的超集。向量化计算这个编程范式比map-reduce要复杂,但本质上都是使用了两种基本的运算,如果你把apply想像为map,把矩阵或矢量的乘运算想像为reduce,它们就是一体的。你总可以把向量化的计算通过apply和矩阵运算来实现,如果有一天你拥有了一个类map-reduce的计算框架,根据它们的对应关系,你的算法迁移就会非常地方便,甚至,你可以在你已经实现的向量化算法集当中抽取出一些共性来搭建自己的map-reduce系统。

别忘了一切优化的终极准则:过早的优化是魔鬼。

并行计算或分布式计算是为数据量与计算量日益膨胀的情况下所必须考虑的,但它的逻辑结构与维护成本也要高得多,如果你的应用场景还没达到需要进行并行或者分布计算的程度,没必要淌这趟混水。但是,向量化计算的编程范式却是很重要的,一个用向量化计算方式实现的算法,不但在当时获得了效益,而且其可扩展性也必定是强悍的,因为正如前文所述,向量化计算就是并行计算的天然先驱。除此之外,经常用向量化的方式来思考你的问题,你一定能感受到一种整体之美。

后记:

以上内容是从我参加第三届中国R语言会议的讲稿中整理出来的,以讲向量化的思想为主,R语言为辅,当时的PPT可以从这里下载(PPT上内容比较少,可以下载下来看备注部分)。我一直认为,通过这样的讲演,除了布道,更重要的是能够对自己一段时间以来的思考与工作做一个总结,其间无论是从自身整理还是从他人的提问,自己从中都能有所收获。根据当场及事后一些听众的疑问,我后续整理了下面一些内容。

如果问题很难向量化怎么办:并不是说R中不能使用for式的循环,事实上只有一层的for循环,并且对性能没有太大的影响的话,是不需要作过多的优化的。如果是两层for循环,可以考虑用apply去掉一层,如果有三层的循环,那很有可能就是你的算法有问题了。如果你的问题确实很难转换成向量化的形式,又或者说你已经懒于这样去做,那么不妨把最难于转换的一部分用C来实现,然后给R做一个接口,剩下的再考虑向量化会简单很多。我提倡的是结合R自有函数与向量化思想进行编程,因为R的自有函数大多都是用底层语言实现好的,效率有保证。

有人疑问是不是所有算法都可以并行:非基本的算法或多或少都是可以并行的,像kmeans,虽然从整体来说是一个迭代依赖的非并行式算法,但在每一步的迭代中却是可以实施并行的。应用map-reduce框架基于这么一个假设,你的问题,总可以找到一种算法来实现,这种算法可以或大部分可以用map加reduce基本操作来实现。如果向量化能跟map-reduce对应起来,那么也可以认为,你的问题,总能找到一种可以用向量化思想表示的算法来完全或部分解决,如果有些部分很难向量化,参考上一个问题。

我选择的算法本身就很复杂:有这么一个说法,如果你的数据不足够多,信息不够完整,你会想出很多奇思怪招来从中获得结论,实际上很多科学上精巧而复杂的算法是基于这种情况而设计出来的。而在实际中如果你的数据急剧膨胀,信息与噪声都足够地多,你的问题焦点就变为如何用一个或一些简单有效算法或算法的组合来提取有价值的信息。如果你在小数据集的时候习惯了采用复杂的算法,当你的应用场景转变了,数据规模变了,却仍旧沿用原有的思维方式,是注定要尴尬的(仅针对工程应用环境,而非科学应用环境)。

本文链接:http://www.wentrue.net/blog/?p=945

Posted in 未分类.


写在世界杯前

足球曾带给我生命中很多的第一次,以及很多的朋友。人生有很多值得回忆的片段,就像生活的珠玑一般。如果这些珠玑有一根闪亮的丝线串联起来,就是一个完美的艺术品了。而这次的丝线,是世界杯。

最初接触到足球时,94年世界杯已经远去,所以我只能一次次地从队友的口中重温巴乔那落寞的背影。那时,即使失败那也是一种悲情的浪漫。

98法兰西之夏,战火初燃,正好赶上我在积极地备战中考,绿茵场上的球星们在努力地追逐着大力神杯,而我也正希冀着找回自己三年前失落的那所重点中学。天气很炎热,每天晚自习后,我都会走到学校门口的小店里,要一碗豆腐脑,顺便瞟几眼屏幕里已经稍有认识的球员,然后匆匆赶回宿舍休息或是夜战。那时,我的眼中其实只有中国国家队,97年的金州兵败,是我第一次体验了作为中国球迷的苦涩。记得那时我完整地看完的一场小组赛是阿根廷对日本,因为那时我认识巴蒂、奥特加,还有传球失误导致失利的日本天才中场中田英寿。当然,那时我最喜欢的是无所不能的外星人罗纳尔多(那时我们叫他朗拿度)。及至中考结束,在家里,我第一次熬夜看球,看着巴西杀入决赛,然后金杯旁落,我第一次体会到在足球场上,球星不并等同于胜利。我也开始明白,作为一个球迷或是一名球员,失意是一件随时都要准备面对的事情。那时,我正逐步走出自己的童话王国。

02日韩世界杯时,我已经在读大二。由于宿舍没有电视,当时网络看直播也不成熟,我和同学相约跑到隔壁邮科院的电影院去看球,因为电影院不放电影了,专门摆了一个电子屏幕放球赛。于是我第一次有了全场人一起欢呼一起叹息的团体看球体验。其实只去过一次,因为第一次聚众大屏幕看球的体验就是眼睁睁地看着阿根廷负于英格兰,后来小组出局。随后的我,就像生活中大多数时候的状态一样,再也找不到做一件事情的理由与目的。所以,那届世界杯,除了中国队的比赛,我看过的赛事只有寥寥几场,也许是看似空闲的大学光阴,被我挥霍到网络与游戏世界中去了吧,抛却了曾经的钟爱与梦想,去追逐一些虚拟的快乐。那段时间,是我人生的第一段黑暗时期。但是,德国人的顽强,让我看到了一丝力量。这个衰落中的帝国,这个近年来已经越来越难找到闪耀巨星的日耳曼战车,每一次的关键赛事,却总能勇往直前。

06年的德国世界杯是迄今为止我看过最完整的一届世界杯,基本上绝大部分的比赛我都通过直播或录像看过。当时正是研一的尾声,那通常也是一个中国学生在学校系统学习的最后一段时间。基本上,我可以静下心来,做一些自己想做的事了。那一次我才了解到,原来世界杯最精彩的不是决赛,而是小组赛。当全世界球迷的目光都聚焦在那个沸腾的国家,当所有人都还有希望还有期待的时候,才是最美好的时刻。当几家欢笑几家愁一幕幕上映,当一个个希望化为一张张回国的机票,这个全球球迷的嘉年华就只退化为那座金杯。虽然最后捧杯的是铜墙铁壁的意大利,但我同样记住了华丽的阿根廷,激情四射的克林斯曼,逆境还魂的法国与悲情谢幕的齐祖,甚至灵魂附体的黄健翔,还有很多很多,有了这些,对于我们大部分人来说,远比那座金杯更来得珍贵。那时,我开始明白世界杯的真正意义。也是那年,虽然仍旧磕磕碰碰,我却意气风发。一个事物之所以精彩,是因为它能给所有人以希望与快乐,而非它的结局。

2010,又会上演什么样的故事?

———————————————————————————————————-

一直觉得,踢球的孩子更容易长大,因为他们很快地就能找到自己的队友,并且一开始就得在场上学习寻找自己合适的位置,继而扮演好自己的角色。无论成功或者失败的体验,他们都能首先在球场上获得。

球场是人生舞台的一个剪影,曾经年轻的我们都幻想过有朝一日自己能成为顶级俱乐部的球星,国家队的栋梁之才,尽情的在广阔的绿茵场上奔跑,胜利了撒足狂奔,失败了悲情落泪。到今天,我们默默地奔跑在离自己距离最近的一支小球队中,追逐着最简单的快乐,即使有时泛起那么点功利心,跟以前相比也渺小得那么地不值一提。

———————————————————————————————————-

到目前为止的这个夏天已经带我们太多的悲喜剧,赛季初挥金如土的银河战舰在四大皆空的同时,凭借着自身输出的斯内德和罗本,把国米和拜仁送进了欧冠决赛,行为艺术家伊布拉同学,赛季前为了欧冠离开国米,然后国米收获了40多年来从未染指的欧冠奖杯。我们没有理由不期待接下来更多的精彩。

最后,不能免俗,谈谈我看好的几支球队吧。

巴西:一旦巴西务实起来,你没有理由不看好他。

西班牙:西班牙依然看上去很美,如果他夺冠,估计是大多数“真球迷”所乐意看到的。

英格兰:英格兰的阵容其实很大牌的,还有一个那么大牌的教练。足球鼻祖,那么多年了,再拿一回大家估计也可以接受。

德国:哎,悲情的巴拉克,强悍的德国战车。

阿根廷:支持阿根廷,马拉多纳你滚蛋吧!

Posted in Life & Thinking.


劝世一言

如果你想微笑,请务必抓紧时间,因为总有一天,你再也不会有那样的心情。

Posted in Life & Thinking.

Tagged with .