1. 为什么选择散点图?

散点图是数据分析中最基础也最实用的可视化工具之一。我第一次接触散点图是在分析电商用户行为时,当时需要找出用户年龄和消费金额之间的关系。散点图就像是一个放大镜,能让你一眼看出数据中隐藏的模式。

举个例子,假设你手上有1000条用户数据,包含年龄和月消费金额。用Excel表格看这些数字,你可能会头晕眼花。但把这些数据点画在散点图上,立刻就能发现:25-35岁的用户消费最活跃,形成明显的密集区域;而50岁以上用户的点则分散在较低位置。这种直观的洞察,是表格数据永远给不了的。

2. 环境准备与数据生成

2.1 三件套安装指南

工欲善其事必先利其器,我们先搞定三个必备工具:

  • NumPy:数据生成的瑞士军刀
  • Pandas:数据处理的全能选手
  • Matplotlib:可视化界的扛把子

安装命令很简单:

pip install numpy pandas matplotlib

如果你遇到安装慢的问题,可以试试国内镜像源:

pip install numpy pandas matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple

2.2 创建模拟数据集

让我们生成一份更接近真实场景的数据。假设我们要分析某电商平台的用户数据:

import numpy as np
import pandas as pd

# 设置随机种子保证结果可复现
np.random.seed(42)

# 生成1000个18-70岁的用户年龄
ages = np.random.randint(18, 70, size=1000)

# 生成消费金额:年龄越大消费越低,但存在随机波动
consumption = 3000 - ages * 20 + np.random.normal(0, 500, size=1000)

# 创建DataFrame
df = pd.DataFrame({'Age': ages, 'Consumption': consumption})

# 查看前5行
print(df.head())

这份数据的特点是:

  • 年龄范围:18-70岁
  • 消费金额与年龄呈负相关
  • 加入了随机噪声模拟真实情况

3. 基础散点图绘制

3.1 你的第一个散点图

让我们用最简单的代码画出散点图:

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
plt.scatter(df['Age'], df['Consumption'])
plt.title('Age vs Consumption')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')
plt.grid(True)
plt.show()

这段代码虽然简单,但已经包含了散点图的核心要素:

  • figsize:控制图形大小,10×6是比较适合报告的尺寸
  • scatter:核心绘图函数
  • title/xlabel/ylabel:让图表更易读
  • grid:添加网格线方便观察数据分布

3.2 第一次优化:解决重叠问题

当数据点很多时,你会发现点都挤在一起。这时候可以:

  1. 调整点的大小(s参数)
  2. 设置透明度(alpha参数)
  3. 使用边缘色(edgecolor)

改进后的代码:

plt.figure(figsize=(10, 6))
plt.scatter(df['Age'], df['Consumption'], 
            s=20, alpha=0.6, edgecolor='white')
plt.title('Age vs Consumption (Optimized)')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')
plt.grid(True, alpha=0.3)
plt.show()

4. 进阶技巧:添加分类维度

4.1 按性别分类着色

假设我们新增了性别数据:

# 随机生成性别数据
genders = np.random.choice(['Male', 'Female'], size=1000)
df['Gender'] = genders

现在可以用不同颜色区分性别:

colors = {'Male': 'blue', 'Female': 'red'}

plt.figure(figsize=(10, 6))
for gender in ['Male', 'Female']:
    subset = df[df['Gender'] == gender]
    plt.scatter(subset['Age'], subset['Consumption'],
               color=colors[gender], label=gender,
               s=20, alpha=0.6)
    
plt.title('Age vs Consumption by Gender')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

4.2 添加趋势线

要更清楚地看到年龄和消费的关系,可以添加趋势线:

from scipy.stats import linregress

# 计算线性回归
slope, intercept, r_value, p_value, std_err = linregress(df['Age'], df['Consumption'])

plt.figure(figsize=(10, 6))
plt.scatter(df['Age'], df['Consumption'], s=20, alpha=0.6)
plt.plot(df['Age'], intercept + slope * df['Age'], 
        'r', label=f'Y = {intercept:.1f} + {slope:.1f}X')
plt.title('Age vs Consumption with Trendline')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

5. 专业级美化技巧

5.1 使用Seaborn风格

Matplotlib的默认样式比较简陋,可以改用Seaborn风格:

import seaborn as sns

sns.set_style("whitegrid")

plt.figure(figsize=(10, 6))
sns.scatterplot(data=df, x='Age', y='Consumption', 
               hue='Gender', palette=['blue', 'red'],
               alpha=0.6, s=50)
plt.title('Professional Style with Seaborn')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')
plt.show()

5.2 添加边际分布图

想要同时看到单变量分布?试试边际分布图:

sns.set_style("whitegrid")

g = sns.JointGrid(data=df, x='Age', y='Consumption', height=8)
g.plot_joint(sns.scatterplot, hue=df['Gender'], 
            palette=['blue', 'red'], alpha=0.6)
g.plot_marginals(sns.histplot, kde=True)
plt.suptitle('Age vs Consumption with Marginal Distributions')
plt.tight_layout()
plt.show()

6. 实战案例:用户分群分析

6.1 识别高价值用户

假设我们定义:

  • 高价值用户:消费 > 2500元
  • 普通用户:消费 ≤ 2500元
df['User_Type'] = np.where(df['Consumption'] > 2500, 'High Value', 'Normal')

plt.figure(figsize=(10, 6))
for user_type in ['High Value', 'Normal']:
    subset = df[df['User_Type'] == user_type]
    plt.scatter(subset['Age'], subset['Consumption'],
               label=user_type, alpha=0.6)
    
plt.axhline(y=2500, color='gray', linestyle='--', alpha=0.5)
plt.title('Identifying High Value Users')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

6.2 添加注释标记

想要突出显示特定数据点:

highlight = df.nlargest(3, 'Consumption')

plt.figure(figsize=(10, 6))
plt.scatter(df['Age'], df['Consumption'], alpha=0.4)
plt.scatter(highlight['Age'], highlight['Consumption'], 
           color='red', s=100, label='Top 3')

for i, row in highlight.iterrows():
    plt.annotate(f"{row['Consumption']:.0f}元", 
                (row['Age'], row['Consumption']),
                textcoords="offset points",
                xytext=(0,10), ha='center')

plt.title('Highlighting Top Spenders')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')
plt.legend()
plt.show()

7. 导出与分享

7.1 保存高清图片

plt.figure(figsize=(10, 6))
plt.scatter(df['Age'], df['Consumption'], alpha=0.6)
plt.title('Final Version for Report')
plt.xlabel('Age')
plt.ylabel('Monthly Consumption (CNY)')

# 保存为高清PNG
plt.savefig('age_consumption.png', dpi=300, bbox_inches='tight')

7.2 交互式探索

如果你需要交互功能,可以试试Plotly:

import plotly.express as px

fig = px.scatter(df, x='Age', y='Consumption', 
                color='Gender', hover_data=['User_Type'],
                title='Interactive Scatter Plot')
fig.show()
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐