处理Spark MLlib中的不平衡数据集

时间:2015-10-27 16:04:17

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

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

我正在使用MLLib的随机森林实现,并且已经尝试过对最大类进行随机抽样的最简单方法,但它并没有像我预期的那样有效。

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

谢谢,

3 个答案:

答案 0 :(得分:42)

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

- 预测能力

您应该检查的另一个问题 - 您的功能是否对您要预测的标签具有“预测能力”。在欠采样后仍然具有低精度的情况下,这可能与您的数据集本质上不平衡的事实无关。

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

  • 对包含标签的每个功能执行相关性分析
  • 为要素生成特定于类的直方图(即绘制给定每个类的数据的直方图) 在同一轴上的功能)也可以是一个很好的方式来显示a 特征在两个类之间有很好的区别。

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

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

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

答案 1 :(得分:1)

我使用@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")

答案 2 :(得分:0)

@dbakr您是否得到了对不平衡数据集的偏差预测的答案?

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