You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Pandas DataFrame的value_counts运行K-means聚类并可视化?

解决KMeans基于访问频次聚类IP的问题

你的问题核心在于KMeans只能处理数值型特征,而你的frq DataFrame里包含字符串类型的IP列,直接传入整个DataFrame会导致模型无法处理非数值数据。我们的目标是基于IP的访问频次(Frq列)来聚类,所以只需要用这一列数值数据进行聚类即可,之后再把聚类标签映射回每个IP。

步骤1:修正KMeans聚类代码

只传入Frq列的二维数值数组(sklearn要求输入是二维格式),代码如下:

from sklearn.cluster import KMeans
import pandas as pd

# 你的预处理代码(保持不变)
frq = pd.DataFrame.from_dict(presult["ClientIP"].value_counts().to_dict(), orient="index").reset_index()
frq.columns = ['IP', 'Frq']

# 仅基于Frq列进行聚类,注意用双括号[[ ]]保持二维结构
kmeans_model = KMeans(n_clusters=3, random_state=1).fit(frq[['Frq']])

# 添加聚类标签到原DataFrame
frq['kmean'] = kmeans_model.labels_

# 查看各聚类的IP数量
print(frq['kmean'].value_counts())
# 查看带标签的完整数据
print(frq.head())

这样就能成功运行了,因为我们只给模型传入了数值型的访问频次数据,IP列只是用来标识样本,不参与聚类计算。

步骤2:聚类结果可视化

接下来可以用几种方式可视化聚类结果,帮助你理解不同聚类的特征:

方式1:箱线图展示各聚类的频次分布

用箱线图可以直观看到每个聚类的访问频次范围、中位数等统计特征:

import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(10,6))
sns.boxplot(x='kmean', y='Frq', data=frq)
plt.title('IP访问频次的KMeans聚类分布')
plt.xlabel('聚类标签')
plt.ylabel('访问频次')
plt.show()

方式2:柱状图展示各聚类的IP数量和平均频次

如果想对比不同聚类的IP数量和平均频次,可以组合柱状图:

cluster_stats = frq.groupby('kmean').agg(
    IP数量=('IP', 'count'),
    平均频次=('Frq', 'mean')
).reset_index()

fig, ax1 = plt.subplots(figsize=(10,6))

# 左侧柱状图:IP数量
ax1.bar(cluster_stats['kmean'], cluster_stats['IP数量'], color='skyblue')
ax1.set_xlabel('聚类标签')
ax1.set_ylabel('IP数量', color='skyblue')
ax1.tick_params(axis='y', labelcolor='skyblue')

# 右侧折线图:平均频次
ax2 = ax1.twinx()
ax2.plot(cluster_stats['kmean'], cluster_stats['平均频次'], color='orange', marker='o', linewidth=2)
ax2.set_ylabel('平均访问频次', color='orange')
ax2.tick_params(axis='y', labelcolor='orange')

plt.title('各聚类的IP数量与平均访问频次')
plt.show()

方式3:散点图展示IP的聚类分布(按频次排序)

如果想看到每个IP的聚类归属,可以先按频次排序,再用散点图展示:

frq_sorted = frq.sort_values('Frq', ascending=False)

plt.figure(figsize=(12,6))
sns.scatterplot(x=range(len(frq_sorted)), y='Frq', hue='kmean', data=frq_sorted, palette='viridis')
plt.title('按访问频次排序的IP聚类分布')
plt.xlabel('IP排序(从高到低频次)')
plt.ylabel('访问频次')
plt.legend(title='聚类标签')
plt.show()

额外说明

  • 如果之后你想基于IP本身的特征(比如IP段)进行聚类,需要先把IP地址转换成数值型特征(比如拆分四段转成整数,或者用One-Hot编码、哈希编码等方式),但从你的需求来看,基于访问频次聚类已经足够解决问题。
  • 可以用肘部法则(Elbow Method)来选择最优的聚类数n_clusters,而不是固定为3:
inertias = []
for k in range(1, 10):
    kmeans = KMeans(n_clusters=k, random_state=1)
    kmeans.fit(frq[['Frq']])
    inertias.append(kmeans.inertia_)

plt.figure(figsize=(10,6))
plt.plot(range(1,10), inertias, marker='o')
plt.title('肘部法则选择最优聚类数')
plt.xlabel('聚类数k')
plt.ylabel('惯性值(Inertia)')
plt.show()

找到曲线的“肘部”点(惯性值下降明显变慢的位置),就是合适的聚类数。

内容的提问来源于stack exchange,提问作者wishi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:59:06