Kmeans算法

聚类算法,目标是将数据集划分为 K 个预定义的不相交的簇(cluster),使得每个数据点都属于离它最近的簇的中心(称为“质心”)所代表的簇。
核心思想:物以类聚。通过迭代计算,不断更新簇的质心位置,最终使得簇内的点尽可能相似(距离小),簇间的点尽可能不同。

  1. 实现2D数据自动聚类,预测V1=80,v2=60的数据类别
  2. 计算预测准确率,完整结果矫正
  3. 采用KNN、Means算法,重复步骤1-2
import pandas as pd
import numpy as np
data = pd.read_csv('data.csv')
data.head()

在这里插入图片描述

X = data.drop(['labels'],axis=1)
y = data.loc[:,'labels']

pd.value_counts(y)

%matplotlib inline
from matplotlib import pyplot as plt
fig1 = plt.figure()
plt.scatter(X.log[:,'V1'],X.loc[:,'V2'])
plt.title("un-labled data")
plt.xlabel('V1')
plt.ylabel('V2')
plt.show()

在这里插入图片描述

fig1 = plt.figure()
#在二维平面上,用散点图绘制所有类别标签为 0 的样本,其中 x 坐标是 V1 特征的值,y 坐标是 V2 特征的值。
label0 = plt.scatter(X.loc[:,'V1'][y==0],X.loc[:,'V2'][y==0])
label1 = plt.scatter(X.loc[:,'V1'][y==1],X.loc[:,'V2'][y==1])
label2 = plt.scatter(X.loc[:,'V1'][y==2],X.loc[:,'V2'][y==2])

plt.title("labled data")
plt.xlabel('V1')
plt.ylabel('V2')
plt.legend((label0,label1,label2),('label0','label1','label2'))
plt.show()

在这里插入图片描述

print(X.shape,y.shape)

from sklearn.cluster import KMeans
KM = KMeans(n_clusters=3,random_state=0)
KM.fit(X)

#训练好模型,找出中心点
centers = KM.cluster_centers_
fig3 = plt.figure()
label0 = plt.scatter(X.loc[:,'V1'][y==0],X.loc[:,'V2'][y==0])
label1 = plt.scatter(X.loc[:,'V1'][y==1],X.loc[:,'V2'][y==1])
label2 = plt.scatter(X.loc[:,'V1'][y==2],X.loc[:,'V2'][y==2])

plt.title("labled data")
plt.xlabel('V1')
plt.ylabel('V2')
plt.legend((label0,label1,label2),('label0','label1','label2'))
plt.scatter(centers[:,0],centers[:,1])
plt.show()

在这里插入图片描述

#测试
y_predict_test = KM.predict([[80,60]])
print(y_predict_test)

y_predict = KM.predict(X)
print(pd.value_counts(y_predict),pd.value_counts(y))

from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y,y_predict)
print(accuracy)

电商客户细分

import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import make_blobs

# 企业级设置
plt.style.use('seaborn-v0_8')
np.random.seed(42)

class CustomerSegmentation:
    def __init__(self):
        self.scaler = StandardScaler()
        self.model = None
        
    def generate_enterprise_data(self, n_samples=1000):
        """生成模拟的企业级客户数据"""
        # 创建具有明显集群结构的数据
        centers = [[30000, 2000], [80000, 8000], [120000, 15000], [50000, 3000]]
        X, _ = make_blobs(n_samples=n_samples, centers=centers, 
                         cluster_std=[5000, 8000, 10000, 4000], random_state=42)
        
        # 添加一些噪声和异常值
        X = np.vstack([X, np.random.uniform(20000, 150000, (50, 2))])
        
        # 创建DataFrame
        df = pd.DataFrame(X, columns=['Annual_Income', 'Annual_Spending'])
        
        # 确保数据合理性
        df['Annual_Income'] = np.abs(df['Annual_Income'])
        df['Annual_Spending'] = np.abs(df['Annual_Spending'])
        
        return df
    
    def preprocess_data(self, df):
        """数据预处理"""
        # 处理异常值 - 使用IQR方法
        Q1 = df.quantile(0.25)
        Q3 = df.quantile(0.75)
        IQR = Q3 - Q1
        df = df[~((df < (Q1 - 1.5 * IQR)) | (df > (Q3 + 1.5 * IQR))).any(axis=1)]
        
        # 数据标准化
        scaled_data = self.scaler.fit_transform(df)
        return scaled_data, df.index
    
    def find_optimal_k(self, data, max_k=10):
        """使用肘部法则和轮廓系数确定最佳K值"""
        wcss = []  # 簇内平方和
        silhouette_scores = []
        k_range = range(2, max_k + 1)
        
        for k in k_range:
            kmeans = KMeans(n_clusters=k, init='k-means++', random_state=42, n_init=10)
            kmeans.fit(data)
            wcss.append(kmeans.inertia_)
            
            if k > 1:  # 轮廓系数需要至少2个簇
                score = silhouette_score(data, kmeans.labels_)
                silhouette_scores.append(score)
        
        # 绘制肘部法则图
        plt.figure(figsize=(15, 5))
        
        plt.subplot(1, 2, 1)
        plt.plot(k_range, wcss, 'bo-')
        plt.xlabel('Number of Clusters (K)')
        plt.ylabel('Within-Cluster Sum of Square (WCSS)')
        plt.title('Elbow Method for Optimal K')
        
        plt.subplot(1, 2, 2)
        plt.plot(range(2, max_k + 1), silhouette_scores, 'ro-')
        plt.xlabel('Number of Clusters (K)')
        plt.ylabel('Silhouette Score')
        plt.title('Silhouette Score for Different K Values')
        
        plt.tight_layout()
        plt.show()
        
        return k_range, wcss, silhouette_scores
    
    def train_model(self, data, n_clusters=4):
        """训练K-Means模型"""
        self.model = KMeans(n_clusters=n_clusters, init='k-means++', 
                           random_state=42, n_init=10)
        clusters = self.model.fit_predict(data)
        return clusters
    
    def analyze_clusters(self, original_df, clusters):
        """分析聚类结果"""
        df_with_clusters = original_df.copy()
        df_with_clusters['Cluster'] = clusters
        
        # 计算每个簇的统计信息
        cluster_stats = df_with_clusters.groupby('Cluster').agg({
            'Annual_Income': ['count', 'mean', 'std', 'min', 'max'],
            'Annual_Spending': ['mean', 'std', 'min', 'max']
        }).round(2)
        
        print("=== 客户分群统计 ===")
        print(cluster_stats)
        
        return df_with_clusters
    
    def visualize_results(self, original_df, clusters):
        """可视化聚类结果"""
        plt.figure(figsize=(12, 5))
        
        # 原始数据
        plt.subplot(1, 2, 1)
        plt.scatter(original_df['Annual_Income'], original_df['Annual_Spending'], 
                   alpha=0.6, s=30)
        plt.xlabel('Annual Income ($)')
        plt.ylabel('Annual Spending ($)')
        plt.title('Original Customer Data')
        
        # 聚类结果
        plt.subplot(1, 2, 2)
        scatter = plt.scatter(original_df['Annual_Income'], original_df['Annual_Spending'], 
                             c=clusters, cmap='viridis', alpha=0.7, s=40)
        plt.xlabel('Annual Income ($)')
        plt.ylabel('Annual Spending ($)')
        plt.title('Customer Segmentation with K-Means')
        plt.colorbar(scatter, label='Cluster')
        
        plt.tight_layout()
        plt.show()
    
    def get_cluster_profiles(self, df_with_clusters):
        """生成客户群画像"""
        profiles = {}
        for cluster_id in df_with_clusters['Cluster'].unique():
            cluster_data = df_with_clusters[df_with_clusters['Cluster'] == cluster_id]
            
            profile = {
                'size': len(cluster_data),
                'avg_income': cluster_data['Annual_Income'].mean(),
                'avg_spending': cluster_data['Annual_Spending'].mean(),
                'spending_ratio': (cluster_data['Annual_Spending'] / cluster_data['Annual_Income']).mean() * 100
            }
            
            # 根据特征定义客户类型
            if profile['avg_income'] > 80000 and profile['avg_spending'] > 10000:
                profile['type'] = '高价值客户'
            elif profile['avg_income'] > 80000 and profile['avg_spending'] <= 10000:
                profile['type'] = '潜力客户'
            elif profile['avg_income'] <= 80000 and profile['spending_ratio'] > 15:
                profile['type'] = '精明消费者'
            else:
                profile['type'] = '普通客户'
                
            profiles[cluster_id] = profile
        
        return profiles

# 企业级应用示例
def run_customer_segmentation():
    print("🚀 开始电商客户细分项目...")
    
    # 初始化
    segmentation = CustomerSegmentation()
    
    # 1. 生成企业数据
    print("📊 生成模拟客户数据...")
    customer_data = segmentation.generate_enterprise_data(1000)
    print(f"生成数据形状: {customer_data.shape}")
    
    # 2. 数据预处理
    print("🔧 数据预处理中...")
    processed_data, valid_indices = segmentation.preprocess_data(customer_data)
    valid_data = customer_data.loc[valid_indices]
    print(f"预处理后数据形状: {processed_data.shape}")
    
    # 3. 寻找最佳K值
    print("📈 寻找最佳聚类数量...")
    k_range, wcss, silhouette_scores = segmentation.find_optimal_k(processed_data, max_k=8)
    
    # 基于轮廓系数选择最佳K
    optimal_k = np.argmax(silhouette_scores) + 2  # +2 因为从K=2开始
    print(f"推荐聚类数量: {optimal_k}")
    
    # 4. 训练模型
    print("🤖 训练K-Means模型中...")
    clusters = segmentation.train_model(processed_data, n_clusters=optimal_k)
    
    # 5. 分析结果
    print("📋 分析聚类结果...")
    df_with_clusters = segmentation.analyze_clusters(valid_data, clusters)
    
    # 6. 可视化
    print("🎨 生成可视化结果...")
    segmentation.visualize_results(valid_data, clusters)
    
    # 7. 生成客户画像
    print("👥 创建客户群画像...")
    profiles = segmentation.get_cluster_profiles(df_with_clusters)
    
    for cluster_id, profile in profiles.items():
        print(f"\n集群 {cluster_id} ({profile['type']}):")
        print(f"  客户数量: {profile['size']}")
        print(f"  平均年收入: ${profile['avg_income']:,.0f}")
        print(f"  平均年消费: ${profile['avg_spending']:,.0f}")
        print(f"  消费收入比: {profile['spending_ratio']:.1f}%")
    
    return segmentation, df_with_clusters, profiles

# 运行项目
if __name__ == "__main__":
    model, results, profiles = run_customer_segmentation()

Mean-shift算法

与 K-Means 需要预先指定 K 不同,Mean-Shift 不需要指定簇的数量,它可以自动发现数据中的模式并确定簇的个数。
核心思想:想象特征空间是一个密度场。算法从每个数据点出发,朝着密度增加的方向(即点最密集的区域)不断移动,直到收敛。所有最终收敛到同一点的原始点被归为同一个簇。这个收敛点就是模式的中心(峰值)。

工作原理:

  • 算法会围绕每个数据点画一个半径为 带宽(bandwidth) 的圆(或超球体)。
  • 计算圆内所有点的均值,将圆心移动到这个均值点。
  • 重复步骤 2,直到圆心的移动非常小(收敛)。这个收敛的区域就是一个簇的质心。
  • 多个起点收敛到同一个质心的被合并为一个簇。
from sklearn.cluster import MeanShift,estimate_bandwidth
bw = estimate_bandwidth(X,n_samples=500)
print(bw)

ms = MeanShift(bandwidth=bw)
ms.fit(X)

y_predict_ms = ms.predict(X)
print(pd.value_counts(y_predict_ms))

网络安全异常检测

import numpy as np
import pandas as pd
from sklearn.cluster import MeanShift, estimate_bandwidth
from sklearn.preprocessing import StandardScaler, RobustScaler
from sklearn.metrics import silhouette_score, calinski_harabasz_score
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import seaborn as sns
from mpl_toolkits.mplot3d import Axes3D
from sklearn.decomposition import PCA

class NetworkSecurityMonitor:
    def __init__(self):
        self.scaler = RobustScaler()  # 使用RobustScaler处理异常值
        self.model = None
        
    def generate_network_data(self, n_samples=2000):
        """生成模拟的网络流量数据"""
        # 创建正常流量集群
        normal_centers = [
            [100, 50, 10, 5, 1000],    # 正常网页浏览
            [500, 200, 30, 15, 5000],   # 文件下载
            [50, 20, 5, 2, 200]         # API调用
        ]
        
        # 创建异常流量(攻击)
        anomaly_centers = [
            [5000, 3000, 500, 100, 10],  # DDoS攻击
            [10, 1000, 2, 500, 5],       # 端口扫描
            [1000, 50, 200, 5, 10000]    # 数据泄露
        ]
        
        # 生成正常数据(95%)
        X_normal, _ = make_blobs(
            n_samples=int(n_samples * 0.95),
            centers=normal_centers,
            cluster_std=[20, 50, 10],
            random_state=42
        )
        
        # 生成异常数据(5%)
        X_anomaly, _ = make_blobs(
            n_samples=int(n_samples * 0.05),
            centers=anomaly_centers,
            cluster_std=[100, 50, 200],
            random_state=42
        )
        
        # 合并数据
        X = np.vstack([X_normal, X_anomaly])
        y = np.array([0] * len(X_normal) + [1] * len(X_anomaly))
        
        # 创建DataFrame
        feature_names = [
            'Packet_Count', 'Connection_Count', 
            'Error_Rate', 'Port_Activity', 
            'Data_Volume'
        ]
        
        df = pd.DataFrame(X, columns=feature_names)
        df['Is_Anomaly'] = y
        
        # 添加一些随机噪声
        noise = np.random.normal(0, 10, (n_samples, 5))
        df[feature_names] += noise
        
        # 确保正值
        df[feature_names] = np.abs(df[feature_names])
        
        return df
    
    def preprocess_data(self, df):
        """数据预处理"""
        features = df.drop('Is_Anomaly', axis=1)
        
        # 使用RobustScaler处理异常值
        scaled_features = self.scaler.fit_transform(features)
        
        return scaled_features, df['Is_Anomaly']
    
    def estimate_optimal_bandwidth(self, data, quantile=0.2):
        """估计最佳带宽参数"""
        bandwidth = estimate_bandwidth(data, quantile=quantile, n_samples=500)
        print(f"估计的带宽: {bandwidth:.4f}")
        return bandwidth
    
    def train_mean_shift(self, data, bandwidth=None):
        """训练Mean-Shift模型"""
        if bandwidth is None:
            bandwidth = self.estimate_optimal_bandwidth(data)
        
        self.model = MeanShift(bandwidth=bandwidth, bin_seeding=True, n_jobs=-1)
        clusters = self.model.fit_predict(data)
        
        print(f"发现的集群数量: {len(np.unique(clusters))}")
        return clusters
    
    def analyze_clusters(self, data, clusters, true_labels):
        """分析聚类结果"""
        results = pd.DataFrame({
            'Cluster': clusters,
            'Is_Anomaly': true_labels
        })
        
        # 计算每个集群的异常比例
        cluster_stats = results.groupby('Cluster').agg({
            'Is_Anomaly': ['count', 'mean', 'sum']
        }).round(4)
        
        cluster_stats.columns = ['Total_Count', 'Anomaly_Ratio', 'Anomaly_Count']
        cluster_stats = cluster_stats.sort_values('Anomaly_Ratio', ascending=False)
        
        print("=== 集群异常分析 ===")
        print(cluster_stats)
        
        # 识别异常集群
        anomaly_clusters = cluster_stats[cluster_stats['Anomaly_Ratio'] > 0.7].index.tolist()
        print(f"识别出的异常集群: {anomaly_clusters}")
        
        return results, anomaly_clusters
    
    def evaluate_detection(self, true_labels, clusters, anomaly_clusters):
        """评估异常检测性能"""
        # 将属于异常集群的点标记为预测异常
        predicted_anomalies = np.isin(clusters, anomaly_clusters).astype(int)
        
        from sklearn.metrics import classification_report, confusion_matrix
        
        print("=== 异常检测性能 ===")
        print(classification_report(true_labels, predicted_anomalies, 
                                  target_names=['正常', '异常']))
        
        # 混淆矩阵
        plt.figure(figsize=(10, 4))
        cm = confusion_matrix(true_labels, predicted_anomalies)
        sns.heatmap(cm, annot=True, fmt='d', cmap='Reds',
                   xticklabels=['正常', '异常'], yticklabels=['正常', '异常'])
        plt.ylabel('真实标签')
        plt.xlabel('预测标签')
        plt.title('异常检测混淆矩阵')
        plt.show()
        
        return predicted_anomalies
    
    def visualize_results(self, data, clusters, true_labels, predicted_anomalies):
        """可视化结果"""
        # 使用PCA进行降维以便可视化
        pca = PCA(n_components=2)
        data_2d = pca.fit_transform(data)
        
        plt.figure(figsize=(18, 6))
        
        # 真实标签
        plt.subplot(1, 3, 1)
        scatter = plt.scatter(data_2d[:, 0], data_2d[:, 1], 
                             c=true_labels, cmap='coolwarm', alpha=0.7)
        plt.colorbar(scatter, label='真实标签 (0=正常, 1=异常)')
        plt.title('真实网络流量分布')
        plt.xlabel('PCA Component 1')
        plt.ylabel('PCA Component 2')
        
        # 聚类结果
        plt.subplot(1, 3, 2)
        scatter = plt.scatter(data_2d[:, 0], data_2d[:, 1], 
                             c=clusters, cmap='viridis', alpha=0.7)
        plt.colorbar(scatter, label='集群')
        plt.title('Mean-Shift 聚类结果')
        plt.xlabel('PCA Component 1')
        plt.ylabel('PCA Component 2')
        
        # 预测结果
        plt.subplot(1, 3, 3)
        colors = ['blue' if x == 0 else 'red' for x in predicted_anomalies]
        plt.scatter(data_2d[:, 0], data_2d[:, 1], c=colors, alpha=0.7)
        plt.title('预测的异常点 (红色=异常)')
        plt.xlabel('PCA Component 1')
        plt.ylabel('PCA Component 2')
        
        plt.tight_layout()
        plt.show()
        
        # 3D可视化(可选)
        if data.shape[1] >= 3:
            fig = plt.figure(figsize=(12, 8))
            ax = fig.add_subplot(111, projection='3d')
            
            pca_3d = PCA(n_components=3)
            data_3d = pca_3d.fit_transform(data)
            
            scatter = ax.scatter(data_3d[:, 0], data_3d[:, 1], data_3d[:, 2],
                               c=predicted_anomalies, cmap='coolwarm', alpha=0.6)
            
            ax.set_xlabel('PCA Component 1')
            ax.set_ylabel('PCA Component 2')
            ax.set_zlabel('PCA Component 3')
            plt.colorbar(scatter, label='预测标签 (0=正常, 1=异常)')
            plt.title('3D网络流量异常检测')
            plt.show()
    
    def feature_analysis(self, original_df, clusters):
        """特征分析"""
        df_analysis = original_df.copy()
        df_analysis['Cluster'] = clusters
        
        # 分析每个集群的特征统计
        cluster_features = df_analysis.groupby('Cluster').mean()
        
        plt.figure(figsize=(15, 10))
        sns.heatmap(cluster_features, annot=True, cmap='YlOrRd', fmt='.1f')
        plt.title('各集群特征均值热力图')
        plt.show()
        
        return cluster_features

# 企业级应用示例
def run_network_security():
    print("🚀 开始网络安全异常检测项目...")
    
    # 初始化
    security_monitor = NetworkSecurityMonitor()
    
    # 1. 生成网络数据
    print("📊 生成模拟网络流量数据...")
    network_data = security_monitor.generate_network_data(2000)
    print(f"异常流量比例: {network_data['Is_Anomaly'].mean():.3f}")
    
    # 2. 数据预处理
    print("🔧 数据预处理中...")
    scaled_data, true_labels = security_monitor.preprocess_data(network_data)
    
    # 3. 训练Mean-Shift模型
    print("🤖 训练Mean-Shift模型中...")
    clusters = security_monitor.train_mean_shift(scaled_data, quantile=0.15)
    
    # 4. 分析集群
    print("📋 分析聚类结果...")
    results, anomaly_clusters = security_monitor.analyze_clusters(
        scaled_data, clusters, true_labels
    )
    
    # 5. 评估检测性能
    print("📊 评估异常检测性能...")
    predicted_anomalies = security_monitor.evaluate_detection(
        true_labels, clusters, anomaly_clusters
    )
    
    # 6. 可视化结果
    print("🎨 生成可视化结果...")
    security_monitor.visualize_results(
        scaled_data, clusters, true_labels, predicted_anomalies
    )
    
    # 7. 特征分析
    print("📈 进行特征分析...")
    cluster_features = security_monitor.feature_analysis(
        network_data.drop('Is_Anomaly', axis=1), clusters
    )
    
    print("\n=== 异常集群特征分析 ===")
    for cluster_id in anomaly_clusters:
        print(f"\n异常集群 {cluster_id} 的特征均值:")
        print(cluster_features.loc[cluster_id])
    
    return security_monitor, network_data, results

# 运行项目
if __name__ == "__main__":
    monitor, data, results = run_network_security()

更多推荐