Python数据可视化之散点图(实战篇---从入门到精通)
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/simple2.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 第一次优化:解决重叠问题
当数据点很多时,你会发现点都挤在一起。这时候可以:
- 调整点的大小(
s参数) - 设置透明度(
alpha参数) - 使用边缘色(
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()