我的大学

这是一篇很诚实很man show但却毫无营养的自述文,慎入.

也许很少有高中同学知道,尽管成绩一向不错,但实际上我对数学充满了厌恶.高中3年机械式的训练,让我实在无法忍受,于是高考填报志愿时选了一个文科的方向,自以为从此天高云厚,憧憬着大学生活的我完全没有意识到此后的命运弄人带来的打击会有多大.

一分之差被选择了计算机专业,大学的傻逼生涯就此埋下了伏笔.整个大一都是在迷茫中度过,对于在大学第一学期,本应是最有干劲的新生来说,高等代数62分和数学分析60分已经足以说明了我的自暴自弃,虽然如此,此后的我居然一直没在数学之上挂科,这是很难想象的,唯一可能的答案也许是尚有一点点不甘吧.维系着成绩上的苟延残喘之余,所有的郁闷都被我发泄在读书上,我阅读了各种名人的传记,从曹操到希特勒,从艾森豪威尔到巴顿,从切格瓦拉到卡斯特罗,原来,所有人都在自己的方向一步步的努力,这个发现便是大一最大的收获了.

让人很苦的笑话
在拉格朗日下有一座微分方城,旁边有两条溪,
一条叫柯溪,一条叫数学分溪,两条溪又汇成了
解析几河,河边有棵线性代树,树上长满了傅里
叶,很多人就挂在上面了…

可惜的是,我找不到我的方向,在学习压力巨大的大二,我仍旧找不到前方.曾经的理想已经远去,未来的大门尚未敞开.这篇文章很好的记下了当时的想法.对于数学,我完全无爱,或许,它唯一能带给我快乐的也就只有右边的这个笑话了.我很想改变些什么,但却有心无力,每天浑浑噩噩,做一天和尚撞一天钟,痛苦,挣扎,便是大二全部的关键词.

上了大三,我恋爱了.正如2010总结所描述的那样,大三的前几个月,我终于找回了已经很久未曾体会过的幸福,逛街,看电影,每一天都是如此轻松,每一秒都是如此难忘,我连谈恋爱的时候都不够,又怎么顾得上去厌恶我的专业呢.沉浸,陶醉,如今回过头来想想,正是这几个月无拘无束的生活,让我对计算机系的感觉焕然一新.代码不再枯燥,编程不再无聊,甚至于,当我鬼使神差的捧起APUE时,细细咀嚼,竟然有了一种与巨匠前贤直面交谈的感觉,那一刻我爱上了Unix,我想这就是所谓的顿悟吧.自此之后,我着了魔,疯狂的想弄明白每一句代码背后的故事,地底三万尺,我愿意去深挖,我愿意去探险,这种感觉实在是太奇异了,我很享受在不同的层次间level up和level down,每一次思维上切换都能带来一种快感,如同高空坠落一般,真实,激烈,持久.

我入了门,虽然有点晚,但还不迟,毕竟better late than never.老丘说,努力就是了,于是,在接下来的几个月里,凭着初生牛犊的冲劲,我啃掉了Unix领域不少的经典图书,在此期间,还不忘回头把计算机,算法,网络等本该早已掌握的知识重新打牢,然后,因为无知,所以无畏,我去面试了.此后的事情如在眼前,我很幸运地得以在腾讯实习了4个多月,深感于才疏学浅,如今一直呆在学校里恶补,直到今天下午看到好友们对于毕业纷纷的感概,一时难以自已,便在这里写着这篇文章.

Thank you!!!

其实,现在想来,大学四年里我是相当幸运的.首先是学校,虽然我常常不怀好意的称其为中国山寨大学,但实际上,中大是很自由,很轻松的一所大学.即便是某次我很嚣张的质问为什么在google上搜索世界杯一共打多少场比赛都会被重置时,辅导员都没有大动肝火,不过是交份检讨,积极分子除名了事.正是因为学校如此轻松的学风,让我后来可以毫无顾忌的肆意逃课,一心一意学习Linux网络编程.我很幸运,还因为大一时某次邹大牛(yuhan童鞋,尽管你不知道,但就是你了!!)Q群上不经意地说到搞Linux不错,这才让我这菜鸟有了初步印象,时隔两年之后走上了后台开发的道路,而且很幸运地在wenhack童鞋和linuxayn师兄的指点下,找准了入门的方向,从APUE到UNP到TCP/IP到POSA,一路下来,没有经历过多少弯路就越过了门槛.现在想起来,确实有种鬼使神差的感觉.最后,非常感谢给了我实习机会的面试官leo,还有诲人不倦谆谆教诲的导师denny,我真是太幸运了!

我只想要当年那个姑娘
一个苦行僧在柴房修行,邻居的姑娘多加照顾,
两人暗生情愫..姑娘同僧人表白,僧人拒绝了,
因为他有更深的梦想.年复一年,姑娘为人妇为
人母为一抔土,僧人得道.佛祖问,你既已得道,
我满足你一个愿望.僧人默然许久,说:”我只想
要当年那个姑娘.”

如果一定要说在大学中学到了什么,好吧,是视野.以前我从不相信什么天才,但是,一个师弟,一个初中就写过带图形界面的操作系统,汇编,c,算法,网络编程无所不通身上爆发者各种闪光点的孩子让我彻底明白了,天才是存在的,而且就在我身边.无数次震撼极大的扩大了我的视野,天外有天,人外有人,深深愧疚于自己的不足的我,一定要努力,像某人说的那样,做一只癞蛤蟆,不做青蛙.

最后,我想起了右边那个故事,回首4年大学生活,曾经浪费的时光再也找不回,但实际上我没有什么后悔的,年少时的错误正是成长的代价,拒绝了错误,也就拒绝了成长.

I was broken.

爸爸妈妈吵架了.

回想起在家的这几天,沉重的气氛让人眩晕.肃静,冷清取代了往日的欢声笑语,孤独的夜,暴风雨暗暗积攒着能量,秋风刮出了多少感伤,天昏地暗间,一声吵骂打破了最后的安详,在毫无保留地释放着的,是填不平的怒火与绝望.曾经举案齐眉,如今仇深似海,黑白电影般参差破烂的画片,断断续续的在上演,吱嘎吱嘎,末了,一曲绝唱,几许苍凉.

世间再无比这更让人捶胸顿足,徒呼奈何的悲剧了.手心是爸,手背是妈,手心手背,血浓于水.父母,恨不得也说不得,再多的坚强也是徒劳,再多的努力也将付之东流.我的心,碎了,头皮发麻,四肢乏力,已然内伤.

天啊,我已看不清前方.

“Do not go gentle into that good night. Rage, rage against the dying of the light.” – Dylan Thomas

野鸡版delicious推荐系统

日子有点无聊,照着<Programming collective Intelligence>写了一个delicious推荐的小模型(代码),就当作是再学python的hello, world! :p 以后无聊了就跑一下代码,看看有什么值得看的, HoHo~

运行结果如下:

>>> from delicious import *
>>> table=initializeUserDict('programming')
>>> table['myself']={}
>>> fillItems(table) 考虑到国内的网络,冲杯咖啡先吧...
>>> from recommendations import *
# 对用户username推荐n条网页链接
>>> getRecommendations(table,"username")[0:n]
# 输出结果前者为推荐值,后者为链接
[(0.61988282180389409, 'http://html5boilerplate.com/mobile/')]
...

deliciousapi

deliciousapi是非官方的api,用于从delicious上拿数据,它的接口很简洁,作者博客上有相应的demo,这里不废话.

initializeUserDict and fillItems

initializeUserDict(tag, count)首先通过deliciousapi.DeliciousAPI().get_urls(‘tag’)获得某个tag下的count链接,然后通过.get_url(‘url’)获取该链接相关的信息,e.g. bookmarks,tags.最后收集bookmarks对应的用户到字典user_dict,将其返回.代码如下:

def initializeUserDict(tag, count=1):
   user_dict={}
   dapi = deliciousapi.DeliciousAPI()

   for url in dapi.get_urls(tag=tag)[0:count]:
      for item in dapi.get_url(url).bookmarks:
         user_dict[item[0]]={}
   return user_dict

fillIteams(user_dict)遍历字典user_dict,通过.get_user(user)获取user收集的bookmarks.如果某个url被所有user收藏,那么将user_dict[user][url]置位,否则清零.代码如下:

def fillItems(user_dict):
   all_items={}
   dapi = deliciousapi.DeliciousAPI()

   for user in user_dict:
      for i in range(3):
         try:
            posts=dapi.get_user(user)
            break
         except:
            print "Fail user "+user+", retrying"
            time.sleep(4)
      for item in posts.bookmarks:
      	 url=item[0]
      	 user_dict[user][url]=1.0
      	 all_items[url]=1

   for ratings in user_dict.values():
      for item in all_items:
         if item not in ratings:
         	ratings[item]=0.0

经过initializeUserDict()和fillItems()两步后,得到的user_dict形如:

{'username': {'http://url': 0.0}, {'http://lru': 1.0},
 'nameuser': {'http://url': 0.0}, {'http://lru': 1.0},
  ...
}

getRecommendations

现在看看最核心的推荐算法,其实很简单:

def sim_distance(prefs, person1, person2):
   si={}
   for item in prefs[person1]:
      if item in prefs[person2]:
           si[item]=1

   if len(si)==0: return 0


   sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item], 2)
                     for item in prefs[person1] if item in prefs[person2]])

   return 1/(1+sqrt(sum_of_squares))

# gets recommendations for a person by using a weighted average
# of every other user's rankings
def getRecommendations(prefs, person, similarity=sim_distance):
   totals={}
   simSums={}

   for other in prefs:
      if other==person: continue
      sim=similarity(prefs,person,other)

      if sim<=0: continue

      for item in prefs[other]:
         # only score those haven't seen yet
         if item not in prefs[person] or prefs[person][item]==0:
            #similarity * score
            totals.setdefault(item,0)
            totals[item]+=prefs[other][item]*sim
            # sum of similarities
            simSums.setdefault(item,0)
            simSums[item]+=sim

   #create the normolized list
   rankings=[(total/simSums[item],item) for item,total in totals.items()]

   # return the sorted list
   rankings.sort()
   rankings.reverse()
   return rankings

参数person表示被推荐人,而参数similarity表示计算Correlation and dependence的函数,默认值为sim_distance,其实也就是个Euclidean Distance.

Conclusion and next steps

小模型很简单,有空时可以完善一下算法.( 如果让C程序员看见如此大的稀疏矩阵,那得有多纠结 :( )