在Spark MLlib中处理不平衡的数据集
apache-spark
classification
machine-learning
5
0

我工作在一个特定的二元分类问题具有高度不平衡的数据集,我想知道是否有人试图实现特定的技术来处理数据集不平衡(如SMOTE )的分类问题,用放电的MLlib。

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

对于您在类似问题上的经历,我们将不胜感激。

谢谢,

参考资料:
Stack Overflow
收藏
评论
共 2 个回答
高赞 时间 活跃

Spark ML的班级重量

到目前为止, Random Forest算法的类加权仍在开发中(请参阅此处

但是,如果您愿意尝试其他分类器,则此功能已添加到Logistic回归中

考虑一种情况,我们在数据集中有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的解决方案,但是我们可以优化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")
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号