【问题标题】:Dealing with unbalanced datasets in Spark MLlib在 Spark MLlib 中处理不平衡的数据集
【发布时间】:2016-01-27 03:38:02
【问题描述】:

我正在处理具有高度不平衡数据集的特定二进制分类问题,我想知道是否有人尝试使用 Spark 的 MLlib 在分类问题中实施特定技术来处理不平衡数据集(例如SMOTE)。

我正在使用 MLLib 的 Random Forest 实现,并且已经尝试过对较大类进行随机欠采样的最简单方法,但效果不如我预期。

如果您对类似问题的体验提供任何反馈,我们将不胜感激。

谢谢,

【问题讨论】:

  • SMOTEBoost 算法建议使用弱学习器算法训练数据集。你为什么不实现这样的东西:issues.apache.org/jira/browse/SPARK-1546
  • @eliasah,我的意思是我的数据集包含的正面示例与负面示例相比非常少(大约每 100 个中有 1 个)。经过训练的分类器偏向于大多数(负)类,该类具有比该类更高的预测精度,但比少数类具有较差的预测精度。 “没有按预期工作”意味着在进行 10 倍交叉验证测试时,分类器的精度约为 60-70%(即 60-70% 的阳性病例被正确分类)。
  • 你的积极课堂的联系和密集程度如何?特征是离散的还是连续的? RF 适用于具有本地连接的离散数据的集合上的离散数据。如果这些点是全局连接的(一大块),那么您可能会考虑 SVM、谱聚类,甚至 k-means。
  • @eliasah “二进制分类不受不平衡数据的影响”。您对此主张有任何参考吗?我并不是说这不是真的,但至少对我来说并不直观。
  • “二进制分类不受不平衡数据的影响”——这绝对不是真的。

标签: apache-spark machine-learning classification apache-spark-mllib


【解决方案1】:

@dbakr 你对不平衡数据集的偏见预测得到了答案吗?

虽然我不确定这是您最初的计划,但请注意,如果您首先按比例 r 对数据集的多数类进行二次抽样,那么,为了获得对 Spark 逻辑的无偏预测回归,您可以: - 使用 transform() 函数提供的 rawPrediction 并使用 log(r) 调整截距 - 或者您可以使用.setWeightCol("classWeightCol") 使用权重训练您的回归(请参阅引用here 的文章以找出必须在权重中设置的值)。

【讨论】:

    【解决方案2】:

    我使用了@Serendipity 的解决方案,但我们可以优化 balanceDataset 函数以避免使用 udf。我还添加了更改正在使用的标签列的功能。这是我最终得到的函数版本:

    def balanceDataset(dataset: DataFrame, label: String = "label"): DataFrame = {
      // Re-balancing (weighting) of records to be used in the logistic loss objective function
      val (datasetSize, positives) = dataset.select(count("*"), sum(dataset(label))).as[(Long, Double)].collect.head
      val balancingRatio = positives / datasetSize
    
      val weightedDataset = {
        dataset.withColumn("classWeightCol", when(dataset(label) === 0.0, balancingRatio).otherwise(1.0 - balancingRatio))
      }
      weightedDataset
    }
    

    我们按照他的说法创建分类器:

    new LogisticRegression().setWeightCol("classWeightCol").setLabelCol("label").setFeaturesCol("features")
    

    【讨论】:

      【解决方案3】:

      Spark ML 的类权重

      目前,随机森林算法的类权重仍在开发中(请参阅here

      但如果您愿意尝试其他分类器 - 此功能 has been already added to the Logistic Regression

      假设我们在数据集中有 80% 的正样本(标签 == 1),因此理论上我们希望对正样本进行“欠采样”。 逻辑损失目标函数应以较高的权重对待负类(标签 == 0)。

      这是一个在 Scala 中生成此权重的示例,我们为数据集中的每条记录在数据框中添加一个新列:

      def balanceDataset(dataset: DataFrame): DataFrame = {
      
          // Re-balancing (weighting) of records to be used in the logistic loss objective function
          val numNegatives = dataset.filter(dataset("label") === 0).count
          val datasetSize = dataset.count
          val balancingRatio = (datasetSize - numNegatives).toDouble / datasetSize
      
          val calculateWeights = udf { d: Double =>
            if (d == 0.0) {
              1 * balancingRatio
            }
            else {
              (1 * (1.0 - balancingRatio))
            }
          }
      
          val weightedDataset = dataset.withColumn("classWeightCol", calculateWeights(dataset("label")))
          weightedDataset
        }
      

      然后,我们创建一个分类器如下:

      new LogisticRegression().setWeightCol("classWeightCol").setLabelCol("label").setFeaturesCol("features")
      

      更多详情,请看这里:https://issues.apache.org/jira/browse/SPARK-9610

      - 预测能力

      您应该检查一个不同的问题 - 您的特征是否对您尝试预测的标签具有“预测能力”。如果在欠采样后精度仍然很低,这可能与您的数据集本质上不平衡这一事实无关。


      我会进行探索性数据分析 - 如果分类器的性能不如随机选择,则存在特征和类之间根本没有联系的风险。

      • 对带有标签的每个特征执行相关性分析
      • 为特征生成类特定的直方图(即,为给定的每个类绘制数据的直方图 同一轴上的特征)也可以是一个很好的方式来显示一个 特征可以很好地区分这两个类别。

      过度拟合 - 训练集上的低错误和测试集上的高错误可能表明您使用过度灵活的特征集进行了过度拟合。


      偏差方差 - 检查您的分类器是否存在高偏差或高方差问题。

      • 训练误差与验证误差 - 绘制验证误差和训练集误差,作为训练示例的函数(进行增量学习)
        • 如果线条似乎收敛到相同的值并且在末端很接近,那么您的分类器具有高偏差。在这种情况下,添加更多数据将无济于事。 将分类器更改为具有较高方差的分类器,或者只是降低当前分类器的正则化参数。
        • 另一方面,如果两条线相距甚远,并且您的训练集误差较低但验证误差较高,则说明您的分类器方差过高。在这种情况下,获取更多数据很可能会有所帮助。如果在获取更多数据后方差仍然过高,您可以增加正则化参数。

      【讨论】:

      • 感谢@Serendipity 的指点。我不知道 Spark ML 中的逻辑回归支持类权重。
      • @dbakr 你需要一个实现的例子吗?我刚刚试了一下。
      • 感谢@Serendipity!我注意到的一件事是,当分类器在加权数据集上进行训练时,输出概率(我需要实际概率而不是预测标签)没有得到很好的校准。这意味着生成的概率与原始数据集分布不匹配,而是根据加权数据集进行了调整。反过来,与手动对原始训练集进行欠采样并手动校准分类器输出概率相比,这会导致验证集上的对数损失度量更高。
      • 这很有帮助,谢谢。事实上,这在任何地方都没有记录,也没有示例等,而且您必须参考 GH PR 和 JIRA 任务,这让我大吃一惊。 ml 库中存在这样一个很棒的功能,而了解它的唯一方法是挖掘 GH PR/Spark 源代码/JIRAS。到目前为止,Spark 的文档更差,这太糟糕了。
      • @dbakr 想详细说明您要回答的评论,同时展示您如何手动欠采样和校准分类器?
      猜你喜欢
      • 2018-03-27
      • 1970-01-01
      • 2020-06-27
      • 2019-09-24
      • 2017-01-23
      • 2020-06-04
      • 2012-07-28
      • 2017-04-19
      • 2020-09-25
      相关资源
      最近更新 更多