# ML碎碎念

ML碎碎念

[对偶学习：一种新的机器学习范式](http://weibo.com/ttarticle/p/show?id=2309404050111117306404)

## 正负样本不均衡

比如训练集中90%都是正类样本，（这尼玛要是所有的都测为正类，准确率也有90%），这样会容易导致模型会认为全部都是正类？因为错分惩罚太小？

解决：\
1\. 采样，采出均衡的样本\
2\. 加权，对分错加权？对负类样本加权？

知乎上观点：\
机器学习的训练数据不是看它分布均不均衡，而是看它符不符合原来的分布。如果符合原来的分布，那么训练误差最小化也就意味着整体分布误差的最小化，也就没有必要进行均衡。

["处理不均衡数据 (机器学习)"](https://zhuanlan.zhihu.com/p/24814085)\
[从重采样到数据合成：如何处理机器学习中的不平衡分类问题？](https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==\&mid=2650724464\&idx=1\&sn=1f34358862bacfb4c7ea17c864d8c44d)

1. 更多数据 &#x20;

   更换评价方式，比如F1 &#x20;

   重组数据，使之平衡。比如重采样，或者砍掉多的那类数据   &#x20;

   使用其他算法，比如决策树  &#x20;

   修改算法，比如sigmoid的阈值 &#x20;

## 分类器的评估

评估标准有：分类精度，信息检索领域的recall和precision。\
但是在ML中常遇到样本分布不均衡，于是提出了新的评价模型：ROC

### recall和precision

对于数据测试结果有下面4种情况：

* TP: 预测为正， 现实为正 &#x20;
* FP: 预测为正， 现实为负 &#x20;
* FN: 预测为负， 现实为正 &#x20;
* TN: 预测为负， 现实为负 &#x20;

精准率precision： TP/ (TP+FP)\
召回率recall： TP/(TP + FN)

$$\text{F1 score} = \frac{ 2 \times recall \times precision}{ recall + precision}$$

### ROC

[ROC和AUC介绍以及如何计算AUC](http://alexkong.net/2013/06/introduction-to-auc-and-roc/) （感谢此人，写的如此清晰）\
[ROC曲线-阈值评价标准](http://blog.csdn.net/abcjennifer/article/details/7359370)

> 在一个二分类模型中，对于所得到的连续结果，假设已确定一个**阀值**，比如说 0.6，大于这个值的实例划归为正类，小于这个值则划到负类中。如果减小阀值，减到0.5，固然能识别出更多的正类，也就是提高了识别出的正例占所有正例 的比类，即TPR,但同时也将更多的负实例当作了正实例，即提高了FPR。为了形象化这一变化，在此引入ROC，
>
> ROC曲线可以用于评价一个分类器。

Roc曲线和lift曲线。\
Lift曲线侧重于命中率，而不是广撒网，拼命中数。因为的广撒网的广告成本很高。

### AUC

AUC （area under curves） 指的是 ROC （receiver operating characteristic）曲线下的面积，该指标能很好的概括不平衡样本分类器的性能。ROC曲线的横轴是FPR （false positive rate 假阳性率，即判断为正例但实际为负例的比例），纵轴是TPR（true positive rate 真阳性率，即判断为正例且实际也为正例的比例）。ROC曲线只对二分分类问题有效。

对某个分类器，我们可以根据其在测试样本上的表现得到一个TPR和FPR点对，构成ROC平面上的一点。调整这个分类器使用的阈值，这样就可以得到一个经过（0，0）， （1，1）的曲线，这就是分类器的ROC曲线。其通常的AUC的值介于0.5到1.0之间，较大的AUC代表了较好的performance 。

阀值：比如logistic 回归输出是\[0,1]之间的连续值，这个值表示用户点击某广告的概率，这里就涉及一个取舍问题了，这个概率值大于多少归为正类。假如确定一个阀值，比如说 0.6，大于这个值的实例划归为正类，小于这个值则划到负类中，那么根据这个阈值0.6能算出一对TPR和FPR来。

重要一点，AUC跟wilcox-mann-witney test是等价的。假设分类器的输出是样本属于正类的score（置信度），则AUC的物理意义是，任取一对（正负）样本，模型把这一对都区分正确（正样本的预估值比负样本大就算对了）的概率,(正样本的score大于负样本的score的概率?)。具体做法是统计下所有的M\_N(M为正类样本的数目，N为负类样本的数目) 个正负样本对中，有多少组中正类样本的score大于负类样本的score。当二元组中正负样本的score相等的时候按照0.5计算。然后除以M\_N 。

还有个复杂度小点的算法。先按score对样本排序，然后令最大score对应的样本的rank为n （n=M+N），第二大的score对应的样本的rank为n-1 ,以此类推，那么对于正样本中rank最大的样本，rank\_max，有M-1个其他正样本比他的score小，那么就有(rank\_max-1)-(M-1) 个负样本比他的score小。则所有正样本的score大于负样本score的个数为sum(正样本的rank) – M(M+1)/2，最后得到的正样本score大于负样本的概率为(sum(正样本的rank) – M(M+1)/2)/(M\*N)。

#### 详细过程

M为正类样本的数目，N为负类样本的数目\
按score降序排列，但是第一个，即score最大的rank记为n，则最后一个，即score最小的rank记为1.

最大的正例样本rank为rank\_max ,则其后还有rank\_max-1个位置，则有(rank\_max-1)-(M-1) 个负样本比他的score小。\
则该正例样本可以和其后的(rank\_max-1)-(M-1) 个负样本组成 (rank\_max-1)-(M-1) 个 正样本score大于负样本序对。

score第二大的正例样本rank为rank\_NO2 ,则其后还有rank\_NO2-1个位置，则有(rank\_NO2-1)-(M-2) 个负样本比他的score小。同理，可以得到(rank\_NO2-1)-(M-2) 个正样本score大于负样本序对。

依次类推，总正样本score大于负样本序对数为：

$$
(rank\_max-1)-(M-1) + \\
(rank\_NO2-1)-(M-2) + \\
(rank\_NO3-1)-(M-3) + \\
... + \\
(rank\_min-1) + \\
\= sum(rank\_i) - M - M(M-1)/2 \\
\= sum(rank\_i) - M(M+1)/2
$$

总的样本对： $$C\_M^1 \* C\_N^1 = M*N$$\
故AUC值就是：$$(sum(rank\_i) - M(M+1)/2) / (M*N)$$

从这个细节可以看出，这就是**文档对的排序**。所以xgboost使用AUC最为分类的loss function时，用的是pairwise。

如何理解AUC等价于 一对正负样本，正样本大于负样本的概率

![](/files/-M7DeRiXK40GDKrNrAVy)

> 图来自张方宇

**AUC与Gini系数的关系**

$$Gini=2×AUC−1$$

![](/files/-M7DeRiYOFxZJ-K11VNw)

> 图来自欧阳若飞

### 直接使用AUC作为分类的优化目标

```
#!/usr/local/bin/python  

def scoreAUC(labels,probs):  
    i_sorted = sorted(range(len(probs)),key=lambda i: probs[i], reverse=True)  
    auc_temp = 0.0  
    TP = 0.0  
    TP_pre = 0.0  
    FP = 0.0  
    FP_pre = 0.0  
    P = 0;  
    N = 0;  
    last_prob = probs[i_sorted[0]] + 1.0  

    for i in range(len(probs)):  
        if last_prob != probs[i_sorted[i]]:   
            auc_temp += (TP+TP_pre) * (FP-FP_pre) / 2.0          
            TP_pre = TP  
            FP_pre = FP  
            last_prob = probs[i_sorted[i]]  
        if labels[i_sorted[i]] == 1:  
            TP = TP + 1  
        else:  
            FP = FP + 1  
    auc_temp += (TP+TP_pre) * (FP-FP_pre) / 2.0  
    auc = auc_temp / (TP * FP)  
    return auc  

def read_file(f_name):  

    f = open(f_name)  
    labels = []  
    probs = []  
    for line in f:  
        line = line.strip().split()  
        try:  
            label = int(line[2])  
            prob = float(line[3])  
        except ValueError:  
            # skip over header  
            continue  
        labels.append(label)  
        probs.append(prob)  
    return (labels, probs)  


def main():  
    import sys  
    if len(sys.argv) != 2:  
        print("Usage: python scoreKDD.py file")  
        sys.exit(2)  
    labels, probs = read_file(sys.argv[1])  

    auc = scoreAUC(labels, probs)  
    print("%f" % auc)  
if __name__=="__main__":  
    main()
```

> 代码来自 [auc指标含义的理解](http://blog.csdn.net/dinosoft/article/details/43114935) ，或者用 scikit-learn/sklearn/metrics/ranking.py 。

[机器学习和统计里面的auc怎么理解？](https://www.zhihu.com/question/39840928)\
[One-Pass AUC Optimization](http://cs.nju.edu.cn/zhouzh/zhouzh.files/publication/aij16opauc.pdf)

[机器学习模型评价(Evaluating Machine Learning Models)-主要概念与陷阱](http://blog.csdn.net/heyongluoyao8/article/details/49408319)\
[分类之性能评估指标](http://blog.csdn.net/dream_angel_z/article/details/50867951)

[ROC Analysis](http://mlwiki.org/index.php/ROC_Analysis)

如果目标数据只有轻微的不平衡，用roc等，但是极端不平衡，可以用SMOTE采样稍微均衡下。

### 需要多少训练样本

当训练样本的数量与模型参数数量的比率达到10:1之后，模型得分基本稳定在0.85，该比率便可以作为良好性能模型的一种定义。\
[数据模型需要多少训练数据](http://www.afenxi.com/post/5559)

### 交叉检验和AB测试

调参数需要用预测效果来比较还坏，有人可能会问，那该如何测试才能比较客观的检验参数甚至模型的有效性？达观数据的测试方法主要有两种：离线测试和在线测试。离线测试时我们只有训练数据，一般会采用学术界常用的交叉验证方法。如图9所示，我们将训练数据平均分为n份，在这n份数据上进行n次循环，每次取其中一份作为检验集（Validation Set），其他n-1份作为训练集（Training Set）。最后对n次预测的结果求平均，以平均得分来对比不同的参数和模型。n一般取5、10或者20。

离线测试得到满意的性能提升之后，就可以进行在线测试。离线测试效果好，并不意味着上线就能取得满意效果。在线测试采用工业界广泛使用的AB测试，首先我们会从线上切一小部分流量（B流量）给新模型、新参数，将效果和使用原先的模型和参数的主流量（A流量）进行对比，如果效果有所提升，再增加B流量的比例。测试通过了就可以全流量上线。

<http://11031509.blog.51cto.com/11021509/1726995/>

<https://zhuanlan.zhihu.com/p/24825503> 【机器学习】Cross-Validation（交叉验证）详解


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://json007.gitbook.io/svm/mlsui_sui_nian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
