工作点滴

工作后的记录

2012 年度盘点

从 2006 年开始每年写年度记录, 继续保持下吧.

先流水账记些大事:
一月, 公司年会, 蹭百度年会, 刷回家火车票, 暖气漏水
二月, 搬到静安中心五楼, 出去拓展
三月, 去围观了场婚礼
四月, 入手 X200 底座, 买了辆小折, 刷街, 奇怪的去了趟环铁
五月, yewen.us 续费, 换手机, 买 new iPad
六月, 伪球迷看欧洲杯, 正式刷了一次铁博
七月, 搬到静安中心二十五楼, 开搞新鲜事, 爸妈来京, 买 X200 电池, 恶意刷小米之家
八月, 新室友, 去深圳围观架构师大会, 买 M4
九月, 校招, 去泰山, 装了一堆新配件弄成整机带回家
十月, 宅家, 去武汉校招, 围观死猫让人压力山大的个性婚礼, 续租和中介折腾
十一月, 还是校招, 帮小强跑一些结婚材料, 又去围观了个婚礼
十二月, 校招终于结束了, 工作上有明显产出, 组织 PUZZLES 群聚, 滑雪, 入手 650D

关于生活, 最大的事情该算全家对喵的全面认可, 但是某喵那边还没搞定, 还死活不让我说, 但是我又想显摆, 所以全年有不少事情只能这样被隐藏掉, 简单的说就是 “笨狗热恋中, 还没结婚生娃, 很幸福”. 全年又围观了很多婚礼, 看很多人生娃, 果然都已经进入到结婚生子的年龄, 说到这还是不展开了, 参照前一句打引号部分好了. 另外今天回忆时发现, 原来今年是最近几年唯一没有搬家的一年, 暖气漏水折腾过一次, 到期续租时被中介坑过一把.

关于工作, 搞了半年, 基本上从广告抽出来, 留下一个还凑合的摊子. 很遗憾的发现, 在互联网, 只要不是在非常大的公司或垂直划分的很清楚的地方做别的, 还是比较难和钱绕开. 换到新鲜事上, 在年末最后一段时间效果飙上去, 有这样一群非常给力的同事和朋友, 真的很赞. 对数据的认识又更深刻一些, 驱动去弄了很多数据方面的事情. 校招占了今年下半年很大的工作比重, 见识了各种强人和奇葩, 最后抢人还是抢的很辛苦, 但为了保证持续产出, 人的质量一定要保证, 今年各种事情都再次验证了这个定理. 因为一些奇奇怪怪的原因进了人人的技术委员会, 参与职称评审, 出去参会, 看看不一样的事情其实挺好的. 团队今年在公司获得一人次季度之星, 一人次最佳新人, 一次最佳团队, 当奶妈补血当的应该还算不错.

个人习惯上, 今年看了不少杂书和技术方向的书, 也在自己记一些笔记, 过的勉勉强强, 不算上进, 但也没完全颓废. 写 blog 明显懒了很多, 有一些东西是不方便写, 有一些就完全是因为懒. 因为在公司每个月混电影票, 所以今年多去电影院看了几场电影, 算把生活品质提升了下吧. 最近给自己定在公开课学习/复习一些东西的目标, 希望能坚持下去, 不学习, 要完蛋.

身体方面, 年初和年末去滑过两次雪, 中间有段时间每天做操, 骑车没跑远路, 就刷街了, 全年体重在 64~66kg 之间波动, 果然没达到去年 YY 的体重 KPI, 不过体检也没啥毛病, 就这样吧.

全年在个人穿着方面几乎没花钱, 倒是还在折腾电子产品, 给自己/喵/老爸各换了台手机, 买了个 new iPad, 给 X200 买了底座换了电池加了 SSD, 基本上算新配了台电脑带回家, 2012 马上要过完时买了个 650D, 可惜顺丰这次不够给力, 本来想着今年最后一天到手的还没送到. 网络方面也还持续投入, 买 ssh 和 vpn 维持科学上网, 域名续了五年费, 家里网络终于升到 20M 光纤. 一开始对 iPad 和手机各种折腾越狱, 刷机, 到后来也还就是当个普通玩具来用, 平平淡淡也好.

还是略有点感伤和迷茫, 感觉偏混日子, 之所以把蹭百度年会都写到大事里去, 是因为当时齐秦唱外面的世界时, 突然像是被狠狠戳到心底最深处后就泪流满面, 看的喵直接吓傻了, 好久没这样毫无防备的痛哭, 发泄过后日子还是得继续, 那就还是这样继续吧. 自己有一些想法, 但是喵和妈妈都觉得不靠谱, 现在因为喵要工作的原因, 又带来些新要考虑的问题.

本来预留了今年最后这几天来好好展开写点什么, 但是感觉现在总没有那种少年意气风发, 青年锋芒毕露的锐气, 更多的都是默默, 平平淡淡写这么点也不想再去展开. 其实还是要更锐利一点的好, 有霸气才能有才气.

你好, 2013.

读书笔记: 探索推荐引擎内部的秘密

看到别人推荐的, 在 IBM 发布的几篇推荐引擎的介绍, 不少干货, 先记录下

探索推荐引擎内部的秘密,第 1 部分: 推荐引擎初探
http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy1/index.html?ca=drs-

探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 – 协同过滤
http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy2/index.html?ca=drs-

探索推荐引擎内部的秘密,第 3 部分: 深入推荐引擎相关算法 – 聚类
http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy3/index.html?ca=drs-

// 现在写 blog 越来越不勤快了, 最近重看了一遍 Python 的官方文档, 又查漏补缺了好多点, 但是没做笔记, 怕是又会忘, 除了零散乱看还是要勤写, 自己重述一遍才算把看过的东西好好理解了, 之前写机器学习的东西又挖坑没填

为什么通过前端 .js 记用户日志会丢数据

在这个数据驱动的时代, 做什么事情没有数据光凭感觉是不可能了, 今年夏天开始接手新鲜事的策略, 先推日志的丰富化和标准化, 关于点击日志, 解决方法无外乎这么三种:

1. 在点击 url 串上带上丰富信息, 然后在后续处理的前端 (比如 nginx 或 apache) 上打印请求日志, 把请求日志汇总过滤得到想要的
2. 做点击跳转, 用户点击后先跳到自己服务器上, 然后由自己的服务器做重定向, 并记录这一次请求
3. 前端 JavaScript 监控用户鼠标行为, 并及时上报到服务器

这三种方法也分别有各自的优缺点, 当时分析的是

1. 这个必须要保证点击后还是跳到自己的服务器上, 否则跳出去的点击无法跟踪. 不太可能丢日志, 只是过滤会多道工序. 目测 Facebook 曾经是这样干的
2. 绝对完整的记录. 不过需要新增服务器响应跳转请求, 并且如果跳转服务挂了会让用户压根到不了 url 指向的地方. 目前所有的广告服务都是这样 (而且点击串加密), Google 的网页搜索很早就是这样, 百度跟 360 干上后也换成了这种. 根据度厂员工在新浪微博上跟别人的讨论, 即使是百度网页搜索那么大的量, 算上灾备最多 50 台跳转服务器可以搞定 (根据公开资料, 百度每天网页搜索量在十亿这个量级, 按搜索引擎页面点击率 30% 算, 每天至少三亿次点击跳转请求)
3. 可记录的东西非常多, 不仅仅是点击, 而且还有一些页面上的其他 js 行为 (如悬浮, js 展开元素等), 但是会丢 15%~20% 的数据. 跟 360 干架前百度的网页搜索用的这种方式, 刚看了下 FB 也是这种了

其他的优缺点都比较容易明白, 但是 js 模式会丢 15%~20% 的数据这个非常难理解, 之前我只听到 20% 这个比例, 但是没人告诉我为什么, 昨天跟死猫君说日志的时候他也提到他们那边用 js 记的日志也有 15% 的丢失率, 但是他也只是听说这个比例而不明白原理.

今天跟前端同学讨论, 终于搞懂了为什么是这样. 后端的思维是每发生一次事件就打一条日志, 所以极难发生日志丢失的问题. 而前端不能每发生一次事件就向服务器发请求打一次日志, 这样会带来很大的网络开销并拖慢用户的浏览器, 所以前端都是把要纪录的行为在用户端先缓存, 等积累够若干条或过了若干秒后才向服务器汇总上报, 如果在这个上报条件触发前浏览器崩溃掉, 那日志就没了, 或者用户关掉浏览器也会丢掉这部分数据 (据说有一些方式可以响应关闭事件并上报日志, 但具体方式不了解, 另外前端同学反馈 IE6 下丢数据现象更严重). 所以丢数据这事其实是用户流畅度体验和数据完备性的一个平衡, 如果让用户卡一点那丢失比例就低一点. 另外接 js 汇报日志的服务器压力也是一个要考虑的点, 因为如果真用 js 汇报, 那一定就不止点击这点数据了, 鼠标滚轮, 悬停等事件显然是能有都有, 服务器不一定扛的过来.

一季招聘快结束时的找工杂谈

本文说给要找工作的毕业生听, 其他人可以围观看乐子

核心三句话: 该有的有, 该没的别有, 该出彩的最好出彩

简历要有, 基本联系方式要有, 如果不是漂亮妹子就不要放照片吓人了, 个人隐私身份证号家庭信息什么的反正我是不看的, 要有人闲的蛋疼觉得自己信息泄漏的还不够多写上凑个字数那也没人拦的了, 有竞赛/项目/实习经历那最好, 详细说明具体是个什么事, 你在中间扮演什么角色以及你有多重要. 核心目标是节省互相了解的时间, 不浪费口水, 而且写的时候应该没有当场说那么紧张吧

没有太牛逼的简历也没人给你担保那还是去下笔试吧, 比直接霸面还是靠谱点. 卷面整洁点好, 要涂涂改改可以在草稿纸上进行, 没带草稿纸可以在考场问监考的要, 有思路把思路写清楚, 要写代码什么的当然也是越清楚越好, 带注释那就完美透了, 免得遇上比你菜很多的改卷人因为看不懂而把你咔嚓了, 面试时也可以让面试官有个提前了解, 就不用拿菜题来让你感觉被羞辱了

面试时别迟到, 如果路上有状况提前打电话给 HR 告知, 否则很可能是你去了后因为打乱安排而被各种等, 流程好的公司会有很好的预案, 但是不是每个公司每个 HR 每个面试官都那么靠谱. 面试有啥说啥, 会的东西就不用藏者掖着了, 不会的也想办法说明自己为啥不会, 是有别的途径可以弥补这方面的不足, 还是怎样可以短时间内赶上给面试官一个正向的未来预期. 面试时别装逼, 一般面试官不会比你傻太多, 装失败了会有很大的负向影响, 装成功了也会让别人觉得你不好沟通, 礼貌待人在哪里都是适用的. 面试快完时可以就面试的公司做一些了解, 或者让面试官给一些建议, 不要问 “你觉得我这次面试怎么样” 这样的问题, 这种问题让人怎么说? 好的话你明显能看出来面试官也很 high, 不好的话人家也不好当面打击你对吧

后续跟进有必要, 对你是唯一的一次机会, 在公司看来你可能不过是万千人中普通的一个, 很可能会漏了或忘了, 但是如果人家告诉你还在跟进, 特别是还告知了大致进度后, 就不宜缠着死问了

最后吐槽一句话: 一天面试十几个人真不是人干的活, 这种面试强度下面试官的标准还有可靠性吗?

机器学习手记系列 3: 线性回归和最小二乘法

好几个月没再继续, 挖坑不填是不对的, 还是继续写手记.

线性回归

线性回归一般用来学习一维自变量和一维因变量之间的线性关系. 如果存在一维自变量 x, 同时还有一维因变量 y = f(x), 如果有一堆对不同 x 下 y 的观测值, 即 的观测对, 且如果 x, y 之间存在较明显的线性关系, 可以用 f(x) = a*x + b 这样的方程表示, 则可以用线性回归的方法学习出 a 和 b 的值, 同时估计这个拟合方法的误差 r.

扩展一下, 线性回归也可以指 y = a1*x1 + a2*x2 + ... + ak*xk + b 这样多维自变量和一维因变量之间的线性关系 (多项式里自变量的最高幂次都是 1), 同样也可以用回归的方式学出来里面不同的系数和常数项的值. 只有一维自变量的称之为一元线性回归, 否则是多元线性回归.

判断线性回归好坏, 一般就用平方误差和来描述, 其表达为 (f(x1)-y1)2 + (f(x2)-y2)2 + ... + (f(xk)-yk)2), 此值如果为 0 则说明自变量和因变量存在完全的线性关系, 否则是近似线性, 越小近似的越好. 这个东西看着有没有一点面熟? 其实就是机器学习手记系列 2: 离线效果评估里最后提到的 MSE 的非平均版本.

解方程法

假如输入样本存在绝对的线性关系, 即最后的误差为 0, 则问题变为解二元一次方程 (一元线性回归里的系数加常数) 或 N+1 元一次方程 (多元线性回归里 N 个自变量的系数加常数). 这没什么好说的, 直接对原输入直接求解就行了, 类似计算方法这样的课本上有的是解法, 做梯度下降或牛顿法乃至矩阵分解都可以解.

梯度下降法

考虑到绝大部分情况下不存在绝对的线性关系, 则问题可以变成怎么求平方误差和的最小值点. 如果是一元线性回归, 目标函数变为 g(a, b) = (f(x1)-y1)2 + (f(x2)-y2)2 + ... + (f(xk)-yk)2

我们的目标就是让这个目标函数值最小, 选定一组 的初始值, 然后求其梯度方向, 每次前进一个小步长, 再求梯度前进, 直到目标函数值不再下降, 说明我们已经走到了一个极值点附近, 终止迭代. 对一元线性回归, 梯度方向是对函数求偏导得到的向量方向.

另外需要注意的是, 梯度下降不一定能找到最优解, 可能会在某个局部最优解那陷进去就出不来了.

这部分更详细的推导请见参考资料里 “机器学习中的数学(1)” 一篇, 里面的公式和图做的很赞, 思路也比我清晰.

牛顿法

梯度下降一般遇到的问题迭代步长不好选, 选太小到极值点太慢, 搞太大又会在极值点附近时因为步长太大跳过去了.

牛顿法最大的贡献就是同时给出了梯度方向和迭代步长, 几乎是一步到位的求解. 方法同解方程一样, 对新的损失目标函数求解, 只是一次解可能还不够好, 需要多做几次迭代. 一般梯度下降可能需要上千轮的迭代, 而牛顿法几次迭代就能到极值点了.

最小二乘法

伟大的高斯同学提出并证明了最小二乘法是最好解答, 证明过程略… 直接看维基或百度百科上的原文吧 (数学不好伤不起).

应用

虽然这个方法看起来很简单粗暴, 但是很多时候变化确实就是线性的. 比如在很多论文和工业实践中, 大家认为同等质量的广告或搜索结果, 放在从上到下不同的位置上, 其点击率和位置的关系符合线性关系, 即 ctr(rank) = a*rank + b.

在六月的一次随笔杂记里, 提到了这样的问题:

如下式子里不同的阿拉伯数字只是一个符号, 实际表示的可能是其他数字
967621 = 3
797321 = 1
378581 = 4
422151 = 0
535951 = 1
335771 = 0

根据上述式子, 判断下式等于?
565441 = ?

假设每个式子最后做的都是加法, 并把字符 0~9 映射到 x0~x9, 则统计不同字母出现的次数就可以列线性返程, 可以将第一个式子表示为

x0*0 + x1*1 + x2*1 + x3*0 + x4*0 + x5*0 + x6*2 + x7*1 + x8*0 + x9*1 = 3

其他类推. 对这堆式子求解就可以得到不同数字对应的真实数值, 可以得到 565441 = 1. // 具体代码和方法下次给出

参考资料

* Wiki Least squares: http://en.wikipedia.org/wiki/Least_squares
* Wiki Mean Squared Error: http://en.wikipedia.org/wiki/Mean_squared_error
* 中文维基 最小二乘法: http://zh.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95
* 百度百科 线性回归: http://baike.baidu.com/view/449540.htm
* 百度百科 最小二乘法: http://baike.baidu.com/view/139822.htm
* 人人上的日志 幼儿园的题目和机器学习的关系: http://blog.renren.com/share/30314/13432269197
* 机器学习中的数学(1): http://www.cnblogs.com/LeftNotEasy/archive/2010/12/05/mathmatic_in_machine_learning_1_regression_and_gradient_descent.html

// 本文开写于 9.24, 拖到 10.26 才马马虎虎完成, 最后那个题的解也没写, 各种错乱后续再修改或补充吧

校招趣事

最近筛简历过校招候选人, 被北邮和中科院的人潮汹涌吓到了, 有些有意思或很苦逼的事, 说说

1. 收到的简历里北邮的数量似乎是最多的, 按北邮出来的人的说法, 北邮在找工季信息共享的很好 (byr 果然不是盖的), 然后很多人不管职位需求, 只要看有一点相关的就会去投. 这种筛的人很痛苦啊… 特别是有很多不了解的项目和实习, 一开始觉得好像很牛逼的样子, 后来看多了就发现怎么看都是个野鸡事

2. 去年参加校招面试的某狐狸, 说出去面试老能遇到北邮的人, 后来很 ws 的做了个实验, 出去面试碰到不认识的人就问 “你北邮的吧?”, 大部分情况下都命中, 屡试不爽 // 我能吐槽下恶趣味么…

3. 收到一份 00 级本科的简历, 本科武大物理, 然后在中科院念了五年的物理, 不过这个经历貌似没下文, 因为简历上最后的学习经历是计算机方向的硕士, 跟大家说了下, 都觉得应该是学物理太苦逼而且很难毕业没办法只能转方向了, 唉, 真心苦逼

4. 简历做的好不好在校招海投季节显得尤其重要. 有人的简历做的就让人看不下去, 两个人一天筛一千份简历的情况下, 八成会被直接无视; 有人简历一开始是大片大片的不知所云, 有亮点都放后面, 不知道怎么想的, 你们试试看在 Win7 的资源管理器里打开预览窗格, 然后看自己简历, 能不翻页情况下能看到多少内容? 我在筛实习生筛过后的简历时就这么筛的

5. 除了智商是硬伤, 感觉沟通更是硬伤. 有几个北大的妹子面的各种心情愉悦, 说什么都能很快跟上思路, 理解题目意思和跟上提醒都非常上道, 相比而言可能因为北邮人实在太多, 总能遇上那么一两个极品, 面试时各种沟通找虐, 你不明白他说什么, 他也不明白你说什么, 或者压根就不屑跟你说或想去理解你, 你都不屑了你还来个球啊 (摔), 刷小怪也认真点好么

2012全球架构师峰会参会简记

8.10 ~ 8.12 在深圳参加全球架构师峰会 (http://www.archsummit.com/), 回来也十来天了, 先把回来后记在 evernote 里的简记发下, 详细的后面跟着幻灯片展开下


公司定的机票时间都太晚了, 走的时候上飞机没晚点, 起飞晚了一个多小时, 到深圳都晚上十一点, 到酒店也半夜一点
住的略偏, 在小梅沙, 这酒店算一般水平吧, 可以理解成规模大点的农家乐
吃的凑合, 会务的自助餐还是挺不错的, 就是人太多, 要么早点要么晚点, 不然排队排死人. 茶点我就第一天提前去偷吃了点, 剩下的都懒得排队了
会场是万科的总部, 很多地方设计的很精妙, 但是大梅沙离市区还是太远太远了


组织的还是挺不错的, 就是有时候几个分会场都想去, 无法分身
同声传译很赞, 也没有很外行翻出莫名其妙的句子来, 前面坚持听了几场英文的, 最后一场借了个传译器果然还是听中文要顺畅很多
腾讯是主赞助商, 发的东西很多, 公仔和衣服没抽到和领到, 其他的资料倒是都拿点, 腾讯在这方面的宣传做的挺好, 给的东西也比较下血本
其他有很多硬件 (比如 SanDisk 的企业用 SSD) 或平台型 (比如云存储) 的赞助商, 我不懂, 就随便看了看展台. 倒是有很多开发平台的赞助商, 比如天翼, 还有海豚浏览器也是赞助商, 我还没怎么弄明白开发平台这个生态圈怎么玩, 果然落伍了


大会场的几个 topic, Pinterest 那个没赶上, 老外吐槽中国网络状况倒是吐的挺狠也挺实在的, 包括多网不通, 还有 GFW, 只是八线机房是个什么情况, 电信/联通/移动/教育网/还有四个有啥?
搜索那个 session 讲的都比较虚, 扯了些概念, 搜狗的提出抓别人的搜索结果 (参考资料: 孟学一有关暗网数据挖掘的书), 一淘讲了些干货, 不过总感觉也没啥特别的, 是因为别的人都没做过或看过这么大的搜索引擎, 所以觉得有很爽的干货么?
大数据那个 session 干货比较多, EMC 上来介绍了一些基于 Hadoop 或 Map/Reduce 的框架, 都很赞, Yahoo 的 Nova 自动化调度数据和任务也做的很好, LinkedIn 对数据的处理方式也非常值得参考, Pinterest 最后讲那个数据库分片, 真的是把简单做到极致, 能不复杂绝不复杂, 能用钱搞定的事情没必要省那几台服务器钱结果把系统搞的巨麻烦


Day1
All: http://vdisk.weibo.com/s/ajLUe

Day2
上午: http://vdisk.weibo.com/s/au-u-
下午主会场 (海量数据): http://vdisk.weibo.com/s/av8ue
下午分会场 1 (移动互联网): http://vdisk.weibo.com/s/aveIJ
下午分会场 2 (安全): http://vdisk.weibo.com/s/av5bn

Day3
All: http://vdisk.weibo.com/s/aAaQ3/1345032030

自吐 & 自勉

今天百度最高奖, 看了下, 最终入围的五个团队有三个自己呆过, 拿奖的仨也呆过俩, 好多认识的人, cong~ (附: 拿奖的新浪微博消息) 他们都做的很赞, 自己曾经在这么好的团队, 耐不住性子, 做不出东西, 因种种原因离开, 开花结果自然无份

现在么, 好好做事, 手头事情也很有搞头, 那就好好搞吧, 皇天不负有心人 :P

自吐部分开始, 曾经有一个帖再引用了以前的一个段子 (原文见: 被诅咒的 Snoopy)

Me 13:23:45
我从 b 家离职后不久, b 家的碳酸饮料就免费了
我从 g 家离职后不久, 餐补就直接发钱了, 等我开学, 上海也是自助餐了
小强 13:25:56
你快点离开武大
Me 13:26:16
why?
Me 13:26:23
这样师弟师妹的伙食就有希望了?
小强 13:26:57

小强 13:27:18
你离开acm acm就拿到金牌了
Me 13:28:20

我一定要把这个段子续下去:

* 2007 年夏离开武大 ACM 队, 该年秋天武大第一次拿区域赛金牌, 第一次进入世界总决赛
* 2008 年初进微软俱乐部, 该年夏令营活动被取消
* 2009 年初离开微软俱乐部, 该年夏令营活动恢复, 并增加 UCLA 夏令营
* 2009 年秋天回归百度, 过了一个月从普天搬西二旗, 自助碳酸饮料机被取消了
* 2011 年秋天离开百度, 半年后自己做废了的俩项目重新上线
* 2011 年秋天离开百度, 次年原团队拿百度最高奖

读完了数学之美

正如上一篇日志中提到的, 最近买了吴军博士数学之美并利用晚上的时间在看. 粗粗的过了一遍, 把以前很多没明白的东西给理顺了下, 具体的一些数学推导没来得及去验证. 书的后半部分感觉比较凌乱和随意, 不过还是值得购买去支持的, 如果大家都不买书, 那以后也会越来越难读到经典之作.

读的过程中用手机简单记了些简单的笔记, 现在回头想想, 再过一下:

方法论

1. 做事要简洁高效: 简单粗暴的方法, 只要是对的那就应该这么做, 与其花非常大的代价弄一个貌似完美的系统, 最后还不一定能保证结果, 还不如花很短的时间去做一个能达到 90% 性能的可用系统, 并用若干个 90% 性能的系统组合起来达到完美效果. 这一点也是我非常认可和坚持的, 在团队里也需要贯彻下去.

2. 凡事都需要可解释: 做策略做算法, 一定要对每个 case 给出合理的解释, 这样才能知道怎么去改进. 吴军在书里举的例子是说搜索, 一开始要用简单高效的系统和特征来保证鲁棒性和可调试性, 其实在计算广告和推荐系统里也是一样, 只是我们现在总会一上来就弄很多复杂的上去, 导致很难调试和追查, 最后就一把烂账怎么也算不清. 这点上自己一直做的不好, 要好好注意.

3. 真理应该拥有简单漂亮的描述: 自然真理的本质描述往往是很简单的很漂亮的, 如果搞的太复杂, 就不太对头, 多半是方向都错了. 书里的例子是说描述太阳系的行星运动, 地心说的模型需要用 40 层圆周修正, 日心说则可以降低到 8-10 个圆周修正, 但最后的真理却是一个椭圆方程就完美解释.

具体案例

1. 新闻/文本分类中的加权. 在做余弦相似度计算时, 需要考虑位置加权, 词性加权等影响. 对于位置加权, 一般的思路都是对树形结构做加权, 比如普通文章的标题/摘要等, 网页则一般是 HTML 语法树的加权, 实际上 Google 在很早之前就开始模拟网页渲染, 做物理位置的加权, 而这一套网页渲染的技术, 用来开发 Chrome 不是正好? 而且随着 Chrome 的市场占有率上升, 也可以逼迫高质量网站的网页代码会更标准, 至少是可以兼容 Chrome 的标准, 这样 Google 可以获得更准确的页面渲染效果并用于权重计算, 现在很多别的公司也开始关注浏览器, 但是不知道有没有想到这一层用法. 词性加权这又回到 NLP 的基础建设上, 果然做互联网, 要做精做深, NLP 是个绕不开的大坑, 就算数学模型如此优雅和有用, 但还是需要有基础数据才能去计算.

2. Logistic Regression 在工业界的广泛应用. 自己好像在生产环境中就用过这一种模型, 接触过线性回归和 Naive Bayes, 但是都没能去深入理解, 其他 boosting 和 SVM 等方法, 每次都是听了个大概, 一直没空去试. 根据自己的经验, 以及吴军的说法, LR 最大的优点是线性叠加, 皮实耐操以及水平扩展性好, 这几个都挺符合方法论的. 不过在点击率非常低的环境下, 要用好 LR 确实很难, 吴军说的是特征权重在 [-6, +6] 区间才有意义, 按 Sigmod 变换函数 1/(1+exp(-z)) 计算, -6 对应的也不过是 0.247%, 这个点击率在搜索广告以外的很多地方还是挺难达到的, 加上位置, beta0 等修正后可以让值很接近, 但是精度又受很大影响, 之前想过把某个小区间做放大处理, 但是一直没想清楚到底要怎么扩, 怎么能维持相对关系并可以还原, 求指点.

机器学习手记系列 2: 离线效果评估

上一次说到选特征的一个简单方法, 但是如果真的要评估一个方法或者一类特征的效果, 简单的相似度计算是不够的, 在上线实验之前, 还是需要有一些别的方式来做验证.

我遇到过的大部分机器学习问题, 最终都转成了二分类问题 (概率问题). 最直白的比如 A 是否属于集合 S (某照片中的人脸是否是人物 Z), 排序问题也可以转换为二分类问题, 比如广告点击率或推荐的相关度, 把候选集分为点击/不点击或接受推荐/不接受推荐的二分类概率. 那在上线之前, 可以用过一些分类器性能评估的方法来做离线评估.

分类器的正确率和召回率

前几天在无觅上看到有人分享了一篇 数据不平衡时分类器性能评价之ROC曲线分析, 把这个问题已经讲差不多了, 我这复述一下.

先说混淆矩阵 (confusion matrix). 混淆矩阵是评估分类器可信度的一个基本工具, 设实际的所有正样本为 P (real-Positive), 负样本为 N (real-Negative), 分类器分到的正样本标为 pre-Positive’, 负样本标为 pre-Negetive’, 则可以用下面的混淆矩阵表示所有情况:

              | real-positive       | real-negative
pre-positive' | TP (true positive)  | FP (false positive)
pre-negative' | FN (false negative) | TN (true negative)

通过这个矩阵, 可以得到很多评估指标:

FP rate = FP / N
TP rate = TP / P
Accuracy = (TP + TN) / (P + N)    # 一般称之为准确性或正确性
Precision = TP / (TP + FP)        # 另一些领域的准确性或正确性, 经常需要看上下文来判断
Recall = TP / P                   # 一般称之为召回率
F-score = Precision * Recall

在我接触过的大部分工作中, 大家都在关注 Precision 和 Recall. 同引用原文中提到的, 这样的分类评估性能只在数据比较平衡时比较好用 (正负例比例接近), 在很多特定情况下正负例是明显有偏的 (比如万分之几点击率的显示广告), 那就只能作为一定的参考指标.

分类器的排序能力评估

很多情况下我们除了希望分类器按某个阈值将正负样本完全分开, 同时还想知道候选集中不同条目的序关系. 比如广告和推荐, 首先需要一个基础阈值来保证召回的内容都满足基本相关度, 比如我一大老爷们去搜笔记本维修代理你给我出一少女睫毛膏的广告或推荐关注, 我绝对飙一句你大爷的然后开 AdBlock 屏蔽之. 在保证了基础相关性 (即分类器的正负例分开) 后, 则需要比较同样是正例的集合里, 哪些更正点 (其实说白了就是怎样才收益最大化). 一般来说, 如果分类器的输出是一个正例概率, 则直接按这个概率来排序就行了. 如果最终收益还要通过评估函数转换, 比如广告的 eCPM = CTR*Price, 或推荐里 rev = f(CTR), (f(x) 是一个不同条目的获益权重函数), 那么为了评估序是否好, 一般会再引入 ROC 曲线和 AUC 面积两个指标.

ROC 曲线全称是 Receiver Operating Characteristic (ROC curve), 详细的解释可以见维基百科上的英文词条 Receiver_operating_characteristic 或中文词条 ROC曲线. 我对 ROC 曲线的理解是, 对某个样本集, 当前分类器对其分类结果的 FPR 在 x 时, TPR 能到 y. 如果分类器完全准确, 则在 x = 0 时 y 就能到 1, 如果分类器完全不靠谱, 则在 x = 1 时 y 还是为 0, 如果 x = y, 那说明这个分类器在随机分类. 因为两个都是 Rate, 是 [0, 1] 之间的取值, 所以按此方法描的点都在一个 (0, 0), (1, 1) 的矩形内, 拉一条直线从 (0, 0) 到 (1, 1), 如果描点在这条直线上, 说明分类器对当前样本就是随机分的 (做分类最悲催的事), 如果描点在左上方, 说明当前分类器对此样本分类效果好过随机, 如果在右下方, 那说明分类器在做比随机还坑爹的反向分类. 引用维基百科上的一个图来说明:

ROC 曲线示例

其中 C’ 好于 A (都是正向的), B 是随机, C 是一个反效果 (跟 C’ 沿红线轴对称, 就是说把 C 的结果反过来就得到 C’).

如果我们有足够多的样本, 则对一个分类器可以在 ROC 曲线图上画出若干个点, 把这些点和 (0, 0), (1, 1) 连起来求凸包, 就得到了 AUC 面积 (Area Under Curve, 曲线下面积). 非常明显, 这个凸包的最小下面积是 0.5 (从 (0, 0) 到 (1, 1) 的这条线), 最大是 1.0 (整个矩形面积), AUC 值越大, 说明分类效果越好.

用 ROC 曲线定义的方式来描点计算面积会很麻烦, 不过还好前人给了我们一个近似公式, 我找到的最原始出处是 Hand, Till 在 Machine Learning 2001 上的一篇文章给出 [文章链接]. 中间的推导过程比较繁琐, 直接说我对这个计算方法的理解: 将所有样本按预估概率从小到大排序, 然后从 (0, 0) 点开始描点, 每个新的点是在前一个点的基础上, 横坐标加上当前样本的正例在总正例数中的占比, 纵坐标加上当前样本的负例在总负例数中的占比, 最终的终点一定是 (1, 1), 对这个曲线求面积, 即得到 AUC. 其物理意义也非常直观, 如果我们把负例都排在正例前面, 则曲线一定是先往上再往右, 得到的面积大于 0.5, 说明分类器效果比随机好, 最极端的情况就是所有负例都在正例前, 则曲线就是 (0, 0) -> (0, 1) -> (1, 1) 这样的形状, 面积为 1.0.

同样给一份 C 代码实现:

struct SampleNode {
  double predict_value;
  unsigned int pos_num;
  unsigned int neg_num;
};

int cmp(const void *a, const void *b)
{
   SampleNode *aa = (SampleNode *)a;
   SampleNode *bb = (SampleNode *)b;
   return(((aa->predict_value)-(bb->predict_value)>0)?1:-1);
}

double calcAuc(SampleNode samples[], int sample_num) {
  qsort(samples, sample_num, sizeof(SampleNode), cmp);

  // init all counters
  double sum_pos = 0;
  double sum_neg = 0;
  double new_neg = 0;
  double rp = 0;
  for (int i = 0; i < sample_num; ++i) {
    if (samples[i].neg_num >= 0) {
      new_neg += samples[i].neg_num;
    }

    if (samples[i].pos_num >= 0) {
      // calc as trapezium, not rectangle
      rp += samples[i].pos_num * (sum_neg + new_neg)/2;
      sum_pos += samples[i].pos_num;
    }
    sum_neg = new_neg;
  }

  return rp/(sum_pos*sum_neg);
}

分类器的一致性

如果分类器的概率结果就是最终结果序, 那 AUC 值基本可以当作最终效果来用. 但是实际应用中分类器的结果都要再做函数转换才是最终序, 则评估的时候需要将转换函数也带上去做 AUC 评估才行. 某些应用中这个转换函数是不确定的, 比如广告的价格随时会变, 推荐条目的重要性或收益可能也是另一个计算模型的结果. 在这种情况下, 如果我们可以保证分类器概率和实际概率一致, 让后续的转换函数拿到一个正确的输入, 那么在实际应用中才能达到最优性能.

为了评估分类器概率和实际概率的一致性, 引入 MAE (Mean Absolute Error, 平均绝对误差) 这个指标, 维基百科对应的词条是 Mean_absolute_error. 最终的计算方法很简单, 对样本 i, fi 是预估概率, yi 是实际概率, 则 i 上绝对误差是 ei, 累加求平均就是 MAE:

MAE 公式

MAE 的值域是 [0, +∞), 值越小说明分类器输出和实际值的一致性越好. 我个人认为如果 MAE 和实际概率一样大, 那这个分类器的波动效果也大到让预估近似随机了.

MAE 看起来和标准差有点像, 类似标准差和方差的关系, MAE 也有一个对应的 MSE (Mean Squared Error, 均方差?), 这个指标更多考虑的是极坏情况的影响, 计算比较麻烦, 一般用的也不多, 有兴趣的可以看维基百科上的词条 Mean_squared_error.

MAE 计算太简单, MSE 计算太纠结, 所以都不在这给出代码实现.