階層式分群演算法構建樹狀結構展現資料點相似性,適用於探索資料結構但在大規模資料集上效能受限。Bisecting K-Means 則透過反覆二元分裂,兼顧效率與群組大小平衡。PySpark 提供機器學習工具,方便實作這兩種分群演算法。利用 VectorAssemblerNormalizer 進行特徵處理,並以 ClusteringEvaluator 計算 Silhouette 分數評估分群品質。迭代測試不同 K 值並繪製 Silhouette 分數圖表,有助於找出最佳分群數量,提升模型效能。程式碼範例涵蓋資料讀取、型別轉換、缺失值填補、模型訓練、預測與評估,提供完整實作流程。

階層式分群與 Bisecting K-Means 分群技術解析

階層式分群(Hierarchical Clustering)是一種重要的無監督學習技術,用於根據資料點之間的相似性將其分組。它不需要事先指定群組數量,這是其相較於非階層式分群方法(如 K-Means)的一大優勢。

階層式分群的運作原理

階層式分群透過計算資料點之間的距離來構建一個樹狀結構(Dendrogram),展示資料點如何逐步合併成群組。常見的距離計算方法包括:

  • Centroid Linkage:使用群組中心點之間的距離來決定群組間的距離。
  • Ward’s Method:根據變異數,旨在最小化群組內部的變異數,同時最大化不同群組之間的變異數。

階層式分群的優缺點

雖然階層式分群具有不需要預先指定群組數量的優點,但其計算複雜度較高,尤其是在處理大規模資料時,其時間和空間複雜度為 O(n^2 log(n)),這可能導致運算速度變慢。

Bisecting K-Means 分群技術

Bisecting K-Means 是一種混合了階層式分裂分群和非階層式分群的方法。它從一個包含所有資料的單一群組開始,透過 K-Means 方法反覆分裂,直到達到預定的群組數量。

Bisecting K-Means 的運作步驟

  1. 初始狀態:所有資料點位於一個群組中。
  2. 第一次分裂:使用 K-Means 將資料分裂成兩個群組。
  3. 計算 SSE:計算每個群組內資料點到其中心點的距離平方和(SSE),SSE 越高,表示該群組的異質性越大。
  4. 選擇 SSE 最大的群組進行分裂:重複此過程,直到達到預定的群組數量。

Bisecting K-Means 的優點

  • 低計算成本:相比於傳統的階層式分群,Bisecting K-Means 的計算效率更高。
  • 產生相似大小的群組:與 K-Means 相比,Bisecting K-Means 更傾向於產生大小相近的群組。

實作範例:使用 PySpark 進行 Bisecting K-Means 分群

以下是一個使用 PySpark 對信用卡資料集進行 Bisecting K-Means 分群的範例:

# 讀取資料
file_location = "cluster_data.csv"
file_type = "csv"
infer_schema = "false"
first_row_is_header = "true"
df = spark.read.format(file_type)\
    .option("inferSchema", infer_schema)\
    .option("header", first_row_is_header)\
    .load(file_location)

# 列印資料結構
df.printSchema()

# 資料型別轉換
from pyspark.sql.types import *
float_vars = list(set(df.columns) - set(['CUST_ID']))
for column in float_vars:
    df = df.withColumn(column, df[column].cast(FloatType()))

# 資料填補
from pyspark.ml.feature import Imputer
input_cols = list(set(df.columns) - set(['CUST_ID']))
imputer = Imputer(
    inputCols=input_cols,
    outputCols=["{}_imputed".format(c) for c in input_cols])
df_imputed = imputer.fit(df).transform(df)
df_imputed = df_imputed.drop(*input_cols)
new_column_name_list = list(map(lambda x: x.replace("_imputed", ""), df_imputed.columns))
df_imputed = df_imputed.toDF(*new_column_name_list)

# 資料準備
from pyspark.ml.feature import VectorAssembler

內容解密:

  1. 讀取資料:使用 spark.read.format() 方法讀取 CSV 檔案,並設定是否推斷結構和是否將第一行作為標題。
  2. 列印資料結構:使用 printSchema() 方法顯示 DataFrame 的結構。
  3. 資料型別轉換:將非 CUST_ID 的欄位轉換為 FloatType,以確保數值運算的正確性。
  4. 資料填補:使用 Imputer 對缺失值進行填補,以避免因缺失值導致的分群結果偏差。
  5. 資料準備:使用 VectorAssembler 將多個欄位組合成一個特徵向量,供後續的分群演算法使用。

無監督學習與推薦演算法:聚類別分析實戰

在無監督學習中,聚類別分析是一種重要的技術,能夠幫助我們發現資料中的隱藏模式和結構。本章節將探討兩種常見的聚類別演算法:Bisecting K-Means 和 K-Means,並使用 PySpark 實作這些演算法。

資料預處理

首先,我們需要對資料進行預處理,包括匯入必要的函式庫、讀取資料、轉換資料型別等。

# 匯入必要的函式庫
from pyspark.sql import SparkSession
from pyspark.ml.feature import VectorAssembler, Normalizer
from pyspark.ml import Pipeline
from pyspark.ml.clustering import BisectingKMeans, KMeans
from pyspark.ml.evaluation import ClusteringEvaluator
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# 建立 SparkSession
spark = SparkSession.builder.appName("Clustering").getOrCreate()

# 讀取資料
file_location = "cluster_data.csv"
file_type = "csv"
infer_schema = "false"
first_row_is_header = "true"
df = spark.read.format(file_type)\
    .option("inferSchema", infer_schema)\
    .option("header", first_row_is_header)\
    .load(file_location)

# 轉換資料型別
float_vars = list(set(df.columns) - set(['CUST_ID']))
for column in float_vars:
    df = df.withColumn(column, df[column].cast(FloatType()))

內容解密:

  1. 建立 SparkSession:使用 SparkSession.builder.appName("Clustering").getOrCreate() 建立一個 SparkSession,這是使用 PySpark 的第一步。
  2. 讀取資料:使用 spark.read.format() 方法讀取 CSV 檔案,並指定相關選項,如是否推斷 Schema 和是否將第一行視為標題。
  3. 轉換資料型別:將相關欄位轉換為 FloatType,以確保後續運算的正確性。

Bisecting K-Means 聚類別分析

Bisecting K-Means 是一種層次聚類別演算法,它透過不斷地二分聚類別來達到最終的聚類別結果。

# 資料預處理
ignore = ['CUST_ID']
assembler = VectorAssembler(inputCols=[x for x in df.columns if x not in ignore], outputCol='features')
normalizer = Normalizer(inputCol="features", outputCol="normFeatures", p=1.0)
pipeline = Pipeline(stages=[assembler, normalizer])
transformations = pipeline.fit(df)
df_updated = transformations.transform(df)

# Bisecting K-Means 模型訓練
bkm = BisectingKMeans().setK(2).setSeed(1)
model = bkm.fit(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))

# 預測與評估
predictions = model.transform(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))
evaluator = ClusteringEvaluator()
silhouette = evaluator.evaluate(predictions)
print("Silhouette with squared euclidean distance = " + str(silhouette))

# 列印聚類別中心
print("Cluster Centers: ")
centers = model.clusterCenters()
for center in centers:
    print(center)

內容解密:

  1. 資料預處理:使用 VectorAssembler 將多個欄位合併成一個向量欄位,並使用 Normalizer 對資料進行標準化處理。
  2. Bisecting K-Means 模型訓練:設定 K 值為 2,並訓練 Bisecting K-Means 模型。
  3. 預測與評估:對資料進行預測,並使用 Silhouette 分數評估聚類別效果。
  4. 列印聚類別中心:列印出每個聚類別的中心點。

選擇最佳 K 值

為了選擇最佳的 K 值,我們可以計算不同 K 值下的 Silhouette 分數,並繪製成圖表。

# 計算不同 K 值下的 Silhouette 分數
sil_coeff = []
num_clusters = []
for iter in range(2, 8):
    bkm = BisectingKMeans().setK(iter).setSeed(1)
    model = bkm.fit(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))
    predictions = model.transform(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))
    evaluator = ClusteringEvaluator()
    silhouette = evaluator.evaluate(predictions)
    sil_coeff.append(silhouette)
    num_clusters.append(iter)
    print("Silhouette with squared euclidean distance for " + str(iter) + " cluster solution = " + str(silhouette))

# 繪製 Silhouette 分數圖表
df_viz = pd.DataFrame(zip(num_clusters, sil_coeff), columns=['num_clusters', 'silhouette_score'])
sns.lineplot(x="num_clusters", y="silhouette_score", data=df_viz)
plt.title('Bisecting k-means : Silhouette scores')
plt.xticks(range(2, 8))
plt.show()

內容解密:

  1. 計算 Silhouette 分數:對不同的 K 值計算 Silhouette 分數,以評估不同聚類別數量的效果。
  2. 繪製圖表:使用 Seaborn 繪製 Silhouette 分數隨 K 值變化的折線圖,以視覺化方式選擇最佳 K 值。

K-Means 聚類別分析

K-Means 是另一種常見的聚類別演算法,它透過迭代更新聚類別中心來達到最終的聚類別結果。

# K-Means 模型訓練
kmeans = KMeans().setK(3).setSeed(1)
model = kmeans.fit(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))

# 預測與評估
predictions = model.transform(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))
evaluator = ClusteringEvaluator()
silhouette = evaluator.evaluate(predictions)
print("Silhouette with squared euclidean distance = " + str(silhouette))

# 列印聚類別中心
print("Cluster Centers: ")
centers = model.clusterCenters()
for center in centers:
    print(center)

內容解密:

  1. K-Means 模型訓練:設定 K 值為 3,並訓練 K-Means 模型。
  2. 預測與評估:對資料進行預測,並使用 Silhouette 分數評估聚類別效果。
  3. 列印聚類別中心:列印出每個聚類別的中心點。

無監督學習中的K-Means分群與LDA主題模型

在無監督學習領域中,K-Means分群和LDA(Latent Dirichlet Allocation)主題模型是兩種極具代表性的技術。本文將探討這兩種技術的原理、實作方法及其在實際應用中的價值。

K-Means分群實作

K-Means是一種廣泛使用的分群演算法,能夠根據資料的特徵將其劃分為K個不同的群組。以下是一個使用PySpark進行K-Means分群的範例:

from pyspark.ml.feature import Imputer, VectorAssembler, Normalizer
from pyspark.ml import Pipeline
from pyspark.ml.clustering import KMeans
from pyspark.ml.evaluation import ClusteringEvaluator

# 資料預處理:填補缺失值
input_cols = list(set(df.columns) - set(['CUST_ID']))
imputer = Imputer(inputCols=input_cols, outputCols=["{}_imputed".format(c) for c in input_cols])
df_imputed = imputer.fit(df).transform(df)

# 將原始欄位替換為填補後的欄位
df_imputed = df_imputed.drop(*input_cols)
new_column_name_list = list(map(lambda x: x.replace("_imputed", ""), df.columns))
df_imputed = df_imputed.toDF(*new_column_name_list)

# 特徵工程:將所有特徵組合成一個向量並進行正規化
ignore = ['CUST_ID']
assembler = VectorAssembler(inputCols=[x for x in df.columns if x not in ignore], outputCol='features')
normalizer = Normalizer(inputCol="features", outputCol="normFeatures", p=1.0)
pipeline = Pipeline(stages=[assembler, normalizer])
transformations = pipeline.fit(df_imputed)
df_updated = transformations.transform(df_imputed)

# 訓練K-Means模型
kmeans = KMeans().setK(2).setSeed(1003)
model = kmeans.fit(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))
predictions = model.transform(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))

# 評估模型:計算Silhouette分數
evaluator = ClusteringEvaluator()
silhouette = evaluator.evaluate(predictions)
print("Silhouette with squared euclidean distance = " + str(silhouette))

# 顯示群中心
centers = model.clusterCenters()
print("Cluster Centers: ")
for center in centers:
    print(center)

內容解密:

  1. 資料預處理:使用Imputer填補缺失值,確保資料完整性。
  2. 特徵工程:透過VectorAssembler將多個特徵組合成一個向量,並使用Normalizer進行正規化,使資料尺度統一。
  3. K-Means模型訓練:設定K值為2,並訓練K-Means模型。
  4. 模型評估:使用Silhouette分數評估分群效果,分數越接近1,表示分群效果越好。
  5. 結果展示:輸出群中心,幫助理解每個群的特徵。

選擇最佳K值

為了獲得最佳的分群效果,需要選擇適當的K值。以下是一個迴圈測試不同K值的範例:

sil_coeff = []
num_clusters = []
for iter in range(2, 8):
    kmeans = KMeans().setK(iter).setSeed(1003)
    model = kmeans.fit(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))
    predictions = model.transform(df_updated.select('normFeatures').withColumnRenamed('normFeatures', 'features'))
    evaluator = ClusteringEvaluator()
    silhouette = evaluator.evaluate(predictions)
    sil_coeff.append(silhouette)
    num_clusters.append(iter)
    print("Silhouette with squared euclidean distance for " + str(iter) + " cluster solution = " + str(silhouette))

# 繪製Silhouette分數圖表
df_viz = pd.DataFrame(zip(num_clusters, sil_coeff), columns=['num_clusters', 'silhouette_score'])
sns.lineplot(x="num_clusters", y="silhouette_score", data=df_viz)
plt.title('k-means : Silhouette scores')
plt.xticks(range(2, 8))
plt.show()

內容解密:

  1. 迴圈測試:測試K值從2到7的不同分群效果。
  2. Silhouette分數記錄:記錄每個K值對應的Silhouette分數。
  3. 視覺化:透過折線圖展示不同K值的Silhouette分數,幫助選擇最佳K值。

LDA主題模型

LDA是一種用於從檔案中提取潛在主題的統計模型。以下是一個LDA的示意圖及其原理說明:

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title LDA主題模型

rectangle "α" as node1
rectangle "θ" as node2
rectangle "β" as node3
rectangle "φ" as node4

node1 --> node2
node2 --> node3
node3 --> node4

@enduml

圖表翻譯: 此圖展示了LDA模型的生成過程。首先,透過Dirichlet分佈(引數為α和β)生成主題和詞語的分佈。然後,根據這些分佈生成檔案。

內容解密:

  1. Dirichlet分佈:LDA使用Dirichlet分佈來建模主題和詞語的分佈。
  2. 主題生成:根據Dirichlet分佈(引數為α),生成每個檔案的主題分佈(θ)。
  3. 詞語生成:根據Dirichlet分佈(引數為β),生成每個主題的詞語分佈(φ)。
  4. 檔案生成:結合主題和詞語的分佈,生成最終的檔案。