Spark ML处理样本类别不均衡问题

样本类别分布不均衡导致的危害?
  • 样本类别不均衡将导致样本量少的分类所包含的特征过少,并很难从中提取规律;
  • 即使得到分类模型,也容易产生过度依赖与有限的数据样本而导致过拟合问题,当模型应用到新的数据上时,模型的准确性会很差
解决类别不平衡数据
1 过采样代表性算法-SMOTE
1.1 算法思想
  • 为了解决随机过采样中造成模型过拟合问题,⼜能保证实现数据集均衡的⽬的,出现了过采样法代表性的算法SMOTE 算法。
  • SMOTE算法是对随机过采样⽅法的⼀个改进算法,由于随机过采样⽅法是直接对少数类进⾏重采⽤,会使训练集中有 很多重复的样本,容易造成产⽣的模型过拟合问题。
  1. SMOTE合成少数样本的思想:
  2. 先随机选定⼀个少数类样本i;
  3. 找出这个少数类样本i的K个近邻(假设K=5),5个近邻已经被圈出;
  4. 随机从这K个近邻中选出⼀个样本j;
  5. 在少数类样本i和被选中的这个近邻样本j之间的连线上,随机找⼀点。这个点就是⼈⼯合成的新的样本点(绿⾊正号标出)
1.2 spark实现
def generateSamples1(data: RDD[(Long, Vector)], k: Int, N: Int): RDD[Vector] = {
    // 1.k-neighbours: 先分组,再笛卡尔积,排除自己减少计算
    val groupedRDD = data.groupBy(_._1)
    val vecAndNeis: RDD[(Vector, Array[Vector])] = groupedRDD.flatMap { case (id, iter) =>
      val vecArr = iter.toArray.map(_._2)

      //2.对每个vector产生笛卡尔积
      val cartesianArr: Array[(Vector, Vector)] = vecArr.flatMap(vec1 => {
        vecArr.map(vec2 => (vec1, vec2))
      }).filter(tuple => tuple._1 != tuple._2)

      cartesianArr.groupBy(_._1).map { case (vec, vecArr) => {
        (vec, vecArr.sortBy(x => Vectors.sqdist(x._1, x._2)).take(k).map(_._2))
      }
      }
    }

    // 3.从这k个近邻中随机挑选一个样本,以该随机样本为基准生成N个新样本
    vecAndNeis.flatMap { case (vec, neighbours) =>
      (1 to N).map { i =>
        val rn = neighbours(Random.nextInt(k))
        val diff = rn.copy
        BLASUDF.axpy(-1.0, vec, diff)

        val newVec = vec.copy
        BLASUDF.axpy(Random.nextDouble(), diff, newVec)
        newVec
      }.iterator
    }
  } 
2 欠采样
2.1 算法思想
  1. 即从多数类S中随机选择⼀些样样本组成样本集E
  2. 然后将样本集从S中移除。新的数据集
2.2 spark实现
// 1 找出样本多的类别
val faudDF = creaditDf.where("Class=1")
val faudNumber = BigDecimal(faudDF.count())
val normalDF = creaditDf.where("Class=0")
val normalNumber = BigDecimal(normalDF.count())

// 2 按比例随机采样
val ratio = faudNumber./(normalNumber)
val sampleNormalDF = normalDF.sample(false, ratio.toDouble, 10)
val underDF = faudDF.union(sampleNormalDF)
//数据标准化
val vecUnder = new VectorAssembler()
	.setInputCols(Array("Amount"))
	.setOutputCol("vectorAmount")
	.transform(underDF)

val scaler = new StandardScaler()
	.setInputCol("vectorAmount")
	.setOutputCol("scaledAmount")
	.setWithStd(true)
	.setWithMean(false)

val scalerModel = scaler.fit(vecUnder)
val scaledUnder = scalerModel.transform(vecUnder).drop("vectorAmount")
### 基于 Spark 的词频统计实验常见问题与解决方案 #### 1. 数据倾斜 (Data Skew) 数据倾斜是指某些分区的数据量远大于其他分区,从而导致计算资源分配不均衡。这种情况在处理高频次单词时尤为明显。 - **原因**: 如果输入数据集中存在大量重复的高频词,则这些词会被映射到相同的分区上,造成该分区的任务执行时间过长。 - **解决方法**: 使用 `RangePartitioner` 来替代默认的哈希分区器可以有效缓解这一问题[^4]。通过采样来估算键值分布并合理划分范围,使得负载更加均匀分布在各个节点之间。 ```python rdd.repartition(new_num_partitions, partitionFunc=RangePartitioner(numPartitions=new_num_partitions)) ``` --- #### 2. 内存溢出 (Out of Memory Error) 当单个任务所需内存超出分配给它的最大堆大小时会发生 OOM 错误。 - **原因**: 处理大规模文本文件或者复杂操作(如 join 或 groupByKey)可能导致中间结果占用过多内存。 - **解决方法**: 调整垃圾回收机制参数以及增加 executor 和 driver 的内存设置;另外也可以考虑采用广播变量减少 shuffle 过程中的数据传输开销[^2]。 - 设置 spark 配置项: ```bash --conf "spark.executor.memory=8g" ``` --- #### 3. 文件读写失败 提交作业后发现标准输出日志显示正常完成,但实际上生成的结果为空白或者是错误路径下的产物。 - **原因**: 可能是因为程序结束前未等待所有异步 I/O 完成就终止运行,也可能是权限不足无法访问指定目录。 - **解决方法**: 确保最后一步保存动作完成后才退出应用,并检查是否有足够的权限去创建目标位置上的新文件夹结构。 - 修改命令行脚本以同步方式调用 API 方法直到其返回成功状态码为止: ```bash /usr/local/spark/bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master yarn-cluster \ ./path/to/jarfile.jar > output.log 2>&1 & wait $! echo Done. ``` --- #### 4. K-Means 文本聚类不稳定 如果尝试利用 k-means 对文档向量化后的特征矩阵做进一步分析,在多次试验间获得差异较大的分组情况。 - **原因**: 如前所述,KMeans 是一种依赖初始质心选取过程的启发式优化算法,因此即使保持其余条件不变也可能因为随机种子不同而得出不一样的结论[^3]。 - **解决方法**: 设定固定随机数发生器种子以便重现相同初始化步骤;同时适当增大迭代次数提高收敛精度。 - Python 示例代码如下所示: ```python from pyspark.ml.clustering import KMeans # 创建模型实例时传入 seed 参数控制伪随机序列生成行为 km_model = KMeans(k=k_value, maxIter=max_iterations, seed=fixed_seed).fit(dataframe_vectorized_features) predictions = km_model.transform(dataframe_vectorized_features) ``` --- #### 5. JSON 解析异常 加载外部源提供的非规范化格式化字符串作为记录字段内容导入过程中抛出了非法字符编码等问题提示信息。 - **原因**: 输入流中包含了不符合预期模式定义的部分片段,比如转义符遗漏、多余逗号等语法瑕疵都会引起解析失败[^1]。 - **解决方法**: 提前预览样本确认整体布局一致后再正式加载整个批次资料集;必要时候编写自定义函数清理脏数据再交给后续阶段继续加工处理。 - 清洗逻辑举例说明: ```python def clean_json_string(s):
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值