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

如何优化K-Means聚类结果的有序可视化实现方案?

Hey there! Your K-Means customer segmentation workflow is solid, but those nested conditionals and hardcoded legend logic can definitely be cleaned up to make the code more flexible and maintainable. Let's walk through optimizing each part step by step:

1. Simplify the order_cluster Function

Your original function works, but we can eliminate the merge step entirely by using a dictionary to map old cluster labels to their ordered ranks. This is faster and cleaner:

def order_cluster(cluster_field_name, target_field_name, df, ascending=True):
    # Calculate mean of the target metric for each cluster
    cluster_means = df.groupby(cluster_field_name)[target_field_name].mean()
    # Sort clusters by their mean target value and get the ordered cluster IDs
    ordered_clusters = cluster_means.sort_values(ascending=ascending).index
    # Create a mapping from original cluster ID to new ordered rank (0,1,2...)
    cluster_map = {old_cluster: new_rank for new_rank, old_cluster in enumerate(ordered_clusters)}
    # Apply the mapping to update the cluster field
    df[cluster_field_name] = df[cluster_field_name].map(cluster_map)
    return df

This does the same job as your original function but cuts out the intermediate dataframe merges and renames—much more efficient!

2. Dynamically Generate the Rank_ID Column

That nested if-else chain for creating Rank_ID is a maintenance nightmare when you change K. Instead, we can generate the group labels dynamically using string formatting and character manipulation. Since your Rank values are ordered from 0 (lowest TOTAL_SALES) to K-1 (highest), we can map them directly to Group_A (highest) down to Group_*:

k = 4  # Your chosen number of clusters
data['Rank_ID'] = data['Rank'].apply(lambda x: f"Group_{chr(ord('A') + (k-1 - x))}")

For example, with K=4:

  • Rank=3 (highest sales) → Group_A
  • Rank=2 → Group_B
  • Rank=1 → Group_C
  • Rank=0 → Group_D

This works for any K up to 26 (since we're using letters A-Z), and you never have to touch the code when changing cluster counts.

3. Eliminate the build_legend Function

You don't need a hardcoded function to generate the legend order—we can create it dynamically based on K, matching the Rank_ID labels we just generated:

legend_order = [f"Group_{chr(ord('A') + i)}" for i in range(k)]

This will produce exactly the ordered list of group labels you need, no matter what K you pick.

Full Optimized Code

Putting it all together, here's the streamlined version of your workflow:

import pandas as pd
from sklearn.cluster import KMeans
import seaborn as sns
import matplotlib.pyplot as plt

# Simplified cluster ordering function
def order_cluster(cluster_field_name, target_field_name, df, ascending=True):
    cluster_means = df.groupby(cluster_field_name)[target_field_name].mean()
    ordered_clusters = cluster_means.sort_values(ascending=ascending).index
    cluster_map = {old: new for new, old in enumerate(ordered_clusters)}
    df[cluster_field_name] = df[cluster_field_name].map(cluster_map)
    return df

# Sample data (matching your example)
data = pd.DataFrame({
    'CUSTOMER_ID': ['A','B','C','D','E','F','G','H'],
    'ORDERS_PLACED': [2,106,13,43,53,1,3,1],
    'UNITS_SOLD': [59,184,78,2034,582,6,60,1],
    'AVG_UNIT_PRICE': [21553.9,6295.9,14290,245.38,760.92,15000,967,1807],
    'TOTAL_SALES': [1271680,1158445.7,1114620,499102,442856,90000,58020,1807]
})

# K-Means clustering
k = 4  # Adjust this value as needed
kmeans = KMeans(n_clusters=k, random_state=42)  # Add random_state for reproducibility
data['Rank'] = kmeans.fit_predict(data[['ORDERS_PLACED','UNITS_SOLD','AVG_UNIT_PRICE','TOTAL_SALES']])

# Order clusters by TOTAL_SALES (ascending=True means 0 = lowest, k-1 = highest)
data = order_cluster('Rank','TOTAL_SALES',data,True)

# Dynamically generate Rank_ID labels
data['Rank_ID'] = data['Rank'].apply(lambda x: f"Group_{chr(ord('A') + (k-1 - x))}")

# Plotting with dynamic legend order
legend_order = [f"Group_{chr(ord('A') + i)}" for i in range(k)]
fig, ax = plt.subplots(figsize=(12,5))
plot = sns.scatterplot(
    x='ORDERS_PLACED', 
    y='TOTAL_SALES', 
    hue='Rank_ID', 
    size='Rank_ID', 
    hue_order=legend_order, 
    size_order=legend_order, 
    data=data, 
    ax=ax
)

# Format y-axis ticks
ytick = plot.get_yticks()
plot.set_yticklabels(['{:,.0f}'.format(x) for x in ytick])
plot.set_title('80/20 Customer Segmentation Using K-Means Clustering, Plot on Orders Placed & Total Sales',fontsize=12)
plt.legend(bbox_to_anchor=(1.05, 1), loc=2)
plt.show()

Key Improvements

  • Flexibility: Works for any number of clusters K without modifying hardcoded logic
  • Maintainability: No nested conditionals or hardcoded legend lists to update
  • Efficiency: Removed unnecessary dataframe merges in the cluster ordering step
  • Reproducibility: Added random_state to KMeans so your clustering results are consistent

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:15:42