Wednesday, February 23, 2022

算法实验效果不好

 算法实验效果不好,先甩锅给工程。

对,你没看错。

工程的原因可能有下面几个。

1.实时特征一致性。典型的各种实时特征场景,你在离线日志解析出来的用户停留时长总比在线长那么半秒,而这个特征又是一个关键特征。仔细看看是不是落库的链路口径不一致。

2特征预处理没有考虑特殊情况线。广告场景的新I’d,离线建模的时候没有考虑过这个问题,在线上场景频繁见过新的东西,你是不是取错embedding到一个离谱的位置了。除了广告场景,NLP里的溢出词表词,可能也会给你几个颜色瞧瞧。

3.模型更新失败?上线的时候,一定检查下模型在线上的链路有没有生效,偷懒摸鱼一时爽,缓存还在火葬场。嗯,线上的模型一般都有buffer机制,两道保险也有两道坑,记得刷新。

4.实验配错了。包括不限于流量配错位,场景I’d和实际情况不一致等等低级问题。

当然,甩锅给工程都是一些初级的问题,容易发现,容易解决。要是你算法自己的锅,就没那么容易了。

** **

你自己的锅:

1.特征穿越了

是不是偷偷地用线上不可能产生的逻辑建模了,比如当天的PV和UV。你在离线的时候很美好,在线的时候,这一天还没过完呢,你统计出来的信息肯定是有穿越。好家伙,你做量化,怎么不把今天的收盘价也加进去。

2.建模的技术指标不合理

不要以为会看个AUC,logloss就万事大吉了。这些技术指标往往不是你okr上的关键。AUC高只能说明你模型拟合特征和标签还行。典型的比方说,你的场景是list view 里插的固定条目的广告。你要是用AUC,就不如用NDCG。

3.特征有bias

在建模的时候,debias是老生常谈的问题了,最最经典的问题就是position带来的bias。你把这个item放在推荐页的上面,你把这个query放在搜索联想的第一条,他本身也会因为近水楼台先得月而点击率偏高。

这时候你就得想办法debias了。

4.数据分布不一致

训练样本的分布往往不等于真实的分布。我们在处理离线建模数据的时候,往往会负采样。负样本弱水三千,只取一瓢。你取哪瓢就太有学问了。负样本太简单,模型学不到什么有价值的信息。在相近的类似正样本上分的就不会太好。这时候你的线下指标就失真了。比如推荐场景下,我们往往会选取展示未点击作为负样本的组成部分。

5.流量抢夺,链路纠缠

典型的比如在营销场景,你在前面的PUSH,短信,固定入口广告做优化,把好转化的用户都转化了。那么下游的IVR电销,人工电销一定就变难了。

这时候你离线用历史数据训练的模型可能离线指标提升了,线上也不会有太多的效果。

这种在一些瀑布流程的场景中更为常见,一定要关注实验的上下游变化,比较经典的方法是做MVP机制,一直维持着最优流量的AB测。这样相对提升是可以把握住的。即使小模块指标变得难看了也没关系,可能大盘整体还是变好的。

6.特殊时间点的漂移

双十一大促,过年放假,这些时间点一定要注意。最好跟往年同时间的复刻对比,谨慎实验。因为这时候的幺蛾子特别多,尤其是在一些时间序列的预测任务上,基本上都跑飞了。所以成熟的算法工程师从不让自己利于危墙之下。


Tuesday, December 15, 2020

Git commands

 Command №1: git diff

git-diff is the command for you if you need to check different commits or between commits and working tree. If you’re not familiar with the concept, the working tree is the directory associated with your repository on your system.

To analyze the status of a repo git diff command is often used in addition to git status and git log.

Usage

In general, git diff is used to get the difference between two “things.” These two things can be one of 6 options:

  1. It can be used to show changes within a local repo. That would be shown if some changes occurred anywhere in the repo’s file directory.
  2. It can be used to show the difference between local and remote repos. So, if you made changes on your local device and some on the Git repo, git diff can help you identify exactly what changed.
  3. Git-diff can also be used to identify differences between two commits of the repo in general.
  4. It also shows the difference between two specific files in two or more commits by showing the changes' line numbers.
  5. Show the difference between two local or remote branches.
  6. Show the difference between two tags of the repo. Tags are often used to refer to working versions of the repo. For example, you can use git diff to identify the differences between version 1.0.0 and version 1.1.0 or your application.

Command №2: git filter-branch

This command is used to rewrite your repo’s history. It does that by applying custom filters to each revision of the repo. The custom filters can change the working-tree or the commits' information, but it can’t change the commit times or merge information.

Usage

The general syntax for this command is git filter-branch <filters> branch_name . There are 7options of filters that you can use in this command to rewrite history for different aspects of the branch.

  1. subdirectory-filter: This filter only checks out a specific subdirectory or the branch.
  2. env-filter: This filter is often used to rewrite the environment information of a specific commit. For example, rewrite the author’s name, email, or time of the commit.
  3. tree-filter: This filter option is very powerful; you can use it to check out all commits to the branch. Which means it can change, remove, add, or even move or change files.
  4. index-filter: Similar to the tree-filter, but this one doesn’t check out the entire tree, only the indices of it. Hence it is much faster, especially for large repos.
  5. parent-filter: This option changes the parents' list of a commit.
  6. msg-filter: If you only want to change the commit messages, this filter is the way to go.
  7. tag-name-filter: If you want to edit the tags of your commits, use this command.

Command №3: git bisect

This is probably one of the most important Git commands — in my opinion. Bugs can kill your application, and sometimes debugging a repo is not an easy task. git bisect can be used to find bugs in a repo.

The entire idea behind git bisect is to perform a binary search in the commits history to find a particular regression bug — a regression bug is a problem resulting from an unrelated change in the code.

git bisect walks you through all recent commits, asking you if they are good or bad — that is, if the regressing bug is present in the commit or not. Doing so narrows down the options to the broken commit.

Command №4: git grep

Trying to find something in your repo? Want to search all your branches for a specific file? git grep is here to help you achieve this smoothly and with ease. git grep is basically used to search for a pattern in a working-tree.

You can use git grep to search for wither exact words or regex in the repo. There are various options you can use with this command. Assume we are looking for the doc in the repo; we can use one of these options:

  1. Search by line number git grep -n doc .
  2. Search only file namesgit grep -l doc .
  3. Search using a regex pattern git grep "f[^\s]\w" .
  4. Specify how many matches in files git grep -c doc .

git grep can also be used to search for multiple words using and/or relations. Moreover, it can search in a specific commit, branch, or find all the occurrences between two commits or tags in the repo.

Command №5: git blame

The git blame command is used to display the information of the author of each commit. It can be used to track bugs and find the commits the produced an error. On a higher level, git blame is used to inspect specific points in repo history and obtain information on who last committed and what they really changed.

git blame displays the last author that modified a line; you can even specify exact line numbers and get the commits that affected that line and who performed them.

Some people are often confused between git blame and git log. Although they may sound similar, if you just need to display the commits performed, what they changed, and when they were done, it’s troublesome to use get blame to achieve that. In this case, git log is the better option. However, if you only want to display the metadata of the person who performed the commit, then git blame should be your command of choice.


Thursday, October 8, 2020

Python sort() and sorted()

 The sort() function is actually an instance method of the list data type, such that the userage is list.sort()

The sorting operation byy sort() is in place and returns None. type(nums.sort())

sorted allows the argument to be a list of any other iterable objects

a lambda in Python is just an anonymous function that has one or more arguments, but only one expression.

sorted_activities = sorted(df, key=lambda x: x['col1'], reversed = True)

sorted_activities = sorted(df, key=lambda x: x'['col1', 'col2'], reversed = True)

from operator import itemgetter
sorted_activities = sorted(activities, key=itemgetter('day', 'activity'), reverse=True)

Tuesday, September 22, 2020

Recommendation ranking

 这篇文章主要讨论推荐系统的分析技巧,杜绝无脑调参,探讨如何靠简单无脑而且 low到爆的办法,快速搞一把,做到指标增长。

本来我想取一个高大上的题目:推荐系统0-1高速增长打法,这种互联网style强烈的题目,让我感觉我的格局大,ego也很大,所以算了,写一份实用分析手册,让我格局很小,ego也很小,比较符合我当前这种水平(实打实不玩虚的,作者👍)。
下面以问答形式解答一线的常见问题和技巧手段。

问:指标上不去,rank加特征能够提升吗?

答:这是一个常见的疑惑,大家指标卡在瓶颈的时候,很容易迷信大力出奇迹的方案。其实,rank并不是提升指标的工具,你加多少特征,本质只是方便 rank 更好地还原系统分布的工具,策略才是提供增长,带动系统往良性(黄赌毒方向)发展的利器。要分析系统的指标瓶颈是不是卡在rank缺特征上,就需要从各种角度去分析,常见的分析方案是考察带条件的copc。

分析办法:把rank分数分成若干区间,每个区间统计真实的ctr,更近一步,可以拆分成多个桶,比如按照某个特征拆分成 A,B两组,单独统计每组的真实ctr。

无非出现如下几种情况:
rank分数单调递增,ctr没有单调递增:这个原因多半是你线上线下分布不一致导致的,道理很简单,如果你的rank真的拟合好了分布,没理由高分数区间段的ctr会低于低分数区间。这个不一致,有可能是你特征没做好线上线下的统一,也有可能是你模型没拟合好线上的分布。总之这种情况,你先别急着加特征,先把线上线下特征梳理一下,看看分布是否一致,或者模型训练是不是有问题。
rank 分数单调递增,ctr 单调递增,但是增长非常慢:比如说0.9-1.0区间的ctr 仅仅比0.3-0.4区间的 ctr 高一丁点。这个原因才是你模型缺特征,尤其是缺乏活跃用户的特征,通常活跃用户,系统 rank 为了指标,会使用很重的行为画像作为特征,很容易放大历史点击记录,更加倾向于把他们排上去,如果你高估了该用户的点击倾向,就会导致分数给的很高,但是现实用户不怎么点的现象
这个也会触发新的问题,也就是常说的离线AUC很高,但是线上没效果,道理都一样,你模型仅仅是把正负样本的间隔拉开了,并没有真正改善用户看到的内容和布局,才导致高分段ctr不见增长。
rank分数单调递增,ctr也单调递增,但是 A,B两组的ctr比值差异过大:比如 A,B表示上午和下午,如果这两个时间段,同一个分数区间的ctr差异过大,说明模型对时间这个维度的建模不足,需要进一步改善。
数学很好证明:假设模型分布是q(y|A), q(y|B),真实的线上分布是 p(y|A),p(y|B),A,B处于同一个分数段,数学上等价于:q(y|A) = q(y|B),由于你假设你模型正确拟合了真实分布,也就是 q(y|A) = p(y|A), q(y|B) = p(y|B),但是现实上 A,B的ctr并不相等,P(y|A) != p(y|B),故此,你模型正确拟合A,B两个条件分布的假设不成立。
这种分组copc的技巧,是一种前期快速判断rank的不足之处,精准化打击系统,对于不见兔子不撒鹰的主,有理由推动对方更快地推进业务迭代
rank分数单调递增,ctr单调递增,各种维度分组下的ctr比值也接近平稳:恭喜你,到达这一步,表示你 rank 几乎没事情可做了,你剩下要做就是优化召回,在策略上引导你rank往新的产品思路上走,在更加高的层面带动系统往良性地方发展(黄赌毒方向)。

问:PV增大,但是CTR跌的很厉害

答:数学上,PV增加CTR就会跌,但一般都会是常数,如果PV增加CTR跌太厉害,你就需要警惕你的投放人群了。数学上来说,假设你有 A,B两个人群,A人群活跃喜欢点击,ctr高,B人群不太活跃,不怎么点击,ctr比较低。如果是随机投放,CTR一般来说都是比较平稳的。但是现实rank如果做的不好,都喜欢向A这种活跃人群投放大量同类内容,甚至高热内容,这些用户短时间内接受到大量同质的内容冲击后,A人群兴趣饱和,贡献的点击就会下降。然后,系统随后的收益都是B人群零零星星提供的,导致PV一直增加,但是点击数不见增长。
另外一种可能的情况是,你投放的用户注意力发生转移,比如同一个时间内,旁边还有活动位置啥的干扰用户,也会导致PV上去,点击不见增长。
如果老板要你不择手段保CTR,可以参考广告pacing思路,在短时间内,某个 item触达的优质用户达到一定峰值,就需要退场冷却一下,防止一直被rank推到高位,消费大量注意力和曝光坑位。但是这个办法指标不治本,毕竟为了粘性,人们喜欢点的还是要多推。

问:如何寻找快速提升指标的策略

答:有一些野路子可以提供,说其是野路子,着实是没法有通用的解法,每个人都有自己的一套特殊的秘方。其次,生产线大部分策略都是被动产生,比如修各种 bad case,或者紧急针对某个单一业务指标做提升,或者产品拍了脑袋找你改进样式啥的。主动寻找增量策略本身是一个比较老中医的方案。
一种做法是复制上下文环境:这种技巧需要花钱买教训收集一定的反馈。打个比方,你要提升用户点击视频的概率,前期你并不知道那些用户爱看视频,所以在不同时间点,人群和位置上,随机试投了一阵,收益当然不佳。然后你认为这些随机当中,还是有一些样本误打误撞到最佳的策略上的,于是你把用户分成A,B两组,A组用户特爱点视频(你认为他们爱点,是因为恰好蒙对了策略环境),B组用户不怎么点。
复制上下文环境就是说,给B人群营造A人群的环境。数学上来说,就是统计一下A组的环境s都是啥(比如说视频都在啥位置,一次性投放视频的数目,视频热度等),然后想办法把这些上下文迁移到B组人群身上。
迁移需要一定技巧去离线预估效益,以决定要不要上线该策略,比如说A用户上下文环境分布为p(s|A),B用户上下文环境分布为p(s|B),强行迁移A的环境分布到B上,得到的B组的预期收益为: 
其中min里面是带截断的IPS分数,如果离线评测凑合。上线以后就靠argmax p(s|A) 生成你的策略环境。
这种办法缺点在于,A,B两组很可能天生就是两批用户,以至于你给B人群营造A人群的环境,对方一样不鸟你。
第二种是增强关联:这种技巧抽象来说,就是溯源,找到影响某个指标,最有可能的特征A,然后强化该指标和该特征的关系,需要和rank配合着打。

问:如何统计曝光次数少的 item 的热度

答:一般来说,很多item的曝光次数可能只有数十次,高热度的item曝光可能是上万,甚至百万次,曝光过低的item,只要产生少数几次点击,其ctr就有可能非常高,甚至吊打高热item的点击率,统计学上针对这种问题,一般是采取 wilson ctr纠正,但是现实来说,wilson ctr非常不靠谱,曝光低的item,大概率是你精准投放人群导致的,并不满足wilson ctr随机投放的基本假设。确切来说,我们要分人群去统计相对的ctr,消除投放人群的bias。
方法:假设item A被投放给N个人,曝光200次,产生10次点击,同时,这N个人当中,高热item B给他们曝光了100000次,产生 900 次点击。所以,A和B 在同一批人群当中的 ctr 分别是:(10 / 200, 900 / 100000),一般我们认为高热的 item 都是无关个性化的,比如热点新闻,促销商品,黄色暴力内容,大家都爱点,高热item的点击率和投放人群的关系不是很大,几乎人人都会点,可以作为CTR本底。扣除这种ctr表示,相比大众货,用户更喜欢点那些item,用这种相对的ctr作为item热度的衡量。