機械学習-KMeansアルゴリズムの原理&& Sparkの実装

アルゴリズムを理解していないデータ開発者は、優れたアルゴリズムエンジニアではありません。大学院生のときにインストラクターが言ったデータマイニングアルゴリズムのいくつかを今でも覚えています。非常に興味がありましたが、仕事の後の連絡が少なかったのです。データエンジニアの軽蔑チェーン、モデル>リアルタイム>オフラインデータウェアハウス> ETLエンジニア> BIエンジニア(気に入らない場合)、現在行っている作業は主にオフラインデータウェアハウスです。もちろん、ETL作業もいくつか行っています。職業の長期的な発展のために、技術的な境界を広げます。リアルタイムとモデルを徐々に深める必要があるので、この記事から始めて、実際を学ぶためのFLAGもリストします。 -時間とモデル部分の詳細。

自分を変えるには、自分が苦手なことを改善することから始めます。

1.KMeans-アルゴリズムの概要

K-Meansアルゴリズムは、教師なしクラスタリングアルゴリズムであり、実装が比較的簡単で、優れたクラスタリング効果があるため、広く使用されています。

  • K-meansまたはK-meansとも呼ばれるK-meansアルゴリズムは、一般に、クラスタリングアルゴリズムをマスターするための最初のアルゴリズムとして使用されます。

  • ここで、Kは定数であり、事前に設定する必要があります。素人の用語では、アルゴリズムは、Kクラスターにラベル付けされていないM個のサンプルを反復的に集約します。

  • サンプルを収集するプロセスは、多くの場合、インデックスとしてサンプル間の距離で除算されます。

ファイル コア:K-meansクラスタリングアルゴリズムは、反復ソリューションクラスタリング分析アルゴリズムです。そのステップは、初期クラスター中心としてKオブジェクトをランダムに選択し、各オブジェクトと各シードクラスター中心の間の距離を計算することです。各オブジェクトを最も近いクラスター中心に割り当てます。それに。クラスターの中心とそれに割り当てられたオブジェクトは、クラスターを表します。サンプルが割り当てられるたびに、クラスターのクラスター中心は、クラスター内の既存のオブジェクトに基づいて再計算されます。このプロセスは、特定の終了条件が満たされるまで繰り返されます。終了条件は、オブジェクトの数が異なるクラスターに再割り当てされない(または最小数)、クラスター中心の数が再び変更されない(または最小数)、および誤差の二乗和が局所的に最小になることです。

2.KMeansアルゴリズムフロー

2.1ファイルを読み取り、データを準備し、データを前処理します

2.2最初の中心点としてK点をランダムに見つける

2.3データセットをトラバースし、各点から3つの中心までの距離を計算します。中心点は、その中心点に最も近いものです。

2.4新しい分類に基づいて新しい中心点を計算します

2.5新しい中心点を使用して次のサイクルを開始します(サイクルステップ2.3に進みます)

ループを終了するための条件

1.サイクル数を指定します

2.すべての中心点がほとんど移動しなくなりました(つまり、中心点によって移動された距離の合計が、指定された常熟よりも小さくなります(0.00001など))。

3.KMeansアルゴリズムの長所と短所

K値の選択:最終結果に対するk値の影響は非常に重要ですが、事前に指定する必要があります。kの適切な値を考えると、事前の知識が必要です。これは、薄い空気から推定するのが難しいか、結果が悪くなる可能性があります。

異常点の存在:K-meansアルゴリズムは、反復プロセスですべての点の平均値を新しい質量点(中心点)として使用します。クラスター内に異常点がある場合、平均偏差はより深刻になります。たとえば、クラスター内に2、4、6、8、および100の5つのデータがある場合、新しい質量点は24です。明らかに、この質量点はほとんどの点から遠く離れています。現在の状況では、中央値6を使用します。使用するよりも優れている可能性があります平均のアイデアが優れており、中央値を使用するクラスタリング方法は、K-Mediodsクラスタリング(K中央値クラスタリング)と呼ばれます

初期値の感度:K-meansアルゴリズムは初期値に敏感です。異なる初期値を選択すると、異なるクラスター分割ルールが発生する可能性があります。この感度による最終結果の異常を回避するために、初期ノードの複数のセットを初期化して異なる分類ルールを構築し、次に最適な構築ルールを選択することができます。これに対応して、2分割K-Meansアルゴリズム、K-Means ++アルゴリズム、K-Means ||アルゴリズム、キャノピーアルゴリズムなどから派生します。

シンプルな実装、モビリティ、および優れたスケーラビリティの利点により、クラスタリングで最も一般的に使用されるアルゴリズムの1つになっています。

4.KMeansアルゴリズムSparkの実装

4.1データのダウンロードと説明

リンク:https://pan.baidu.com/s/1FmFxSrPIynO3udernLU0yQ抽出コード:地獄このコンテンツをコピーした後、Baidu Netdisk携帯電話アプリを開くと、操作がより便利になります

アイリスフラワーデータセット、データセットには3種類の150キーデータが含まれ、各タイプには50データが含まれ、各レコードには4つの特徴が含まれます:がくの長さ、がくの幅、花びらの長さ、花びらの幅

これらの4つの機能の後、花をクラスター化し、Kが3に設定されていると仮定して、実際の結果との違いを確認します。

4.2実装

mlbライブラリを使用しませんが、scalaのネイティブ実装を使用します

package com.hoult.work

import org.apache.commons.lang3.math.NumberUtils
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession

import scala.collection.mutable.ListBuffer
import scala.math.{pow, sqrt}
import scala.util.Random

object KmeansDemo {

  def main(args: Array[String]): Unit = {

    val spark = SparkSession
      .builder()
      .master("local[*]")
      .appName(this.getClass.getCanonicalName)
      .getOrCreate()

    val sc = spark.sparkContext
    val dataset = spark.read.textFile("data/lris.csv")
      .rdd.map(_.split(",").filter(NumberUtils.isNumber _).map(_.toDouble))
      .filter(!_.isEmpty).map(_.toSeq)


    val res: RDD[(Seq[Double], Int)] = train(dataset, 3)

    res.sample(false, 0.1, 1234L)
      .map(tp => (tp._1.mkString(","), tp._2))
      .foreach(println)
  }

  // 定义一个方法 传入的参数是 数据集、K、最大迭代次数、代价函数变化阈值
  // 其中 最大迭代次数和代价函数变化阈值是设定了默认值,可以根据需要做相应更改
  def train(data: RDD[Seq[Double]], k: Int, maxIter: Int = 40, tol: Double = 1e-4) = {

    val sc: SparkContext = data.sparkContext

    var i = 0 // 迭代次数
    var cost = 0D //初始的代价函数
    var convergence = false   //判断收敛,即代价函数变化小于阈值tol

    // step1 :随机选取 k个初始聚类中心
    var initk: Array[(Seq[Double], Int)] = data.takeSample(false, k, Random.nextLong()).zip(Range(0, k))

    var res: RDD[(Seq[Double], Int)] = null

    while (i < maxIter && !convergence) {

      val bcCenters = sc.broadcast(initk)

      val centers: Array[(Seq[Double], Int)] = bcCenters.value

      val clustered: RDD[(Int, (Double, Seq[Double], Int))] = data.mapPartitions(points => {

        val listBuffer = new ListBuffer[(Int, (Double, Seq[Double], Int))]()

        // 计算每个样本点到各个聚类中心的距离
        points.foreach { point =>

          // 计算聚类id以及最小距离平方和、样本点、1
          val cost: (Int, (Double, Seq[Double], Int)) = centers.map(ct => {

            ct._2 -> (getDistance(ct._1.toArray, point.toArray), point, 1)

          }).minBy(_._2._1)  // 将该样本归属到最近的聚类中心
          listBuffer.append(cost)
        }

        listBuffer.toIterator
      })
      //
      val mpartition: Array[(Int, (Double, Seq[Double]))] = clustered
        .reduceByKey((a, b) => {
          val cost = a._1 + b._1   //代价函数
          val count = a._3 + b._3   // 每个类的样本数累加
          val newCenters = a._2.zip(b._2).map(tp => tp._1 + tp._2)    // 新的聚类中心点集
          (cost, newCenters, count)
        })
        .map {
          case (clusterId, (costs, point, count)) =>
            clusterId -> (costs, point.map(_ / count))   // 新的聚类中心
        }
        .collect()
      val newCost = mpartition.map(_._2._1).sum   // 代价函数
      convergence =  math.abs(newCost - cost) <= tol    // 判断收敛,即代价函数变化是否小于小于阈值tol
      // 变换新的代价函数
      cost = newCost
      // 变换初始聚类中心
      initk = mpartition.map(tp => (tp._2._2, tp._1))
      // 聚类结果 返回样本点以及所属类的id
      res = clustered.map(tp=>(tp._2._2,tp._1))
      i += 1
    }
    // 返回聚类结果
    res
  }

  def getDistance(x:Array[Double],y:Array[Double]):Double={
    sqrt(x.zip(y).map(z=>pow(z._1-z._2,2)).sum)
  }


}

完全なコード:https//github.com/hulichao/bigdata-spark/blob/master/src/main/scala/com/hoult/work/KmeansDemo.scala

結果のスクリーンショット:ファイルWu Xie、Xiao San Ye、バックグラウンドの小さな新人、ビッグデータ、人工知能。もっと注意してくださいファイル

おすすめ

転載: blog.csdn.net/hu_lichao/article/details/113101229