引言:为什么需要数据可视化?
当你在电商网站爬取了10万条商品价格数据,或是从气象站抓取了3年的温度记录,面对密密麻麻的csv表格时,是否感到无从下手?这时候,数据可视化就像给数据装上了一副"透 视镜",能让你一眼看穿数据背后的规律。
本文将带你完成一个完整的数据可视化实战:从爬取某招聘网站的职位信息,到用matplotlib生成专业图表。不需要数学博士背景,只需跟着步骤操作,你就能做出让同事惊叹的可视化报告。
一、准备阶段:环境搭建与数据获取
1.1 基础环境配置
首先确保你的python环境已安装必要的库:
pip install matplotlib pandas requests beautifulsoup4
这四个库的分工很明确:
requests:负责发送http请求获取网页beautifulsoup4:解析html提取数据pandas:处理csv数据matplotlib:绘制可视化图表
1.2 爬取示例数据
以某招聘网站为例,我们爬取python开发岗位的薪资和城市分布数据:
import requests
from bs4 import beautifulsoup
import pandas as pd
def crawl_job_data():
headers = {'user-agent': 'mozilla/5.0'}
jobs = []
for page in range(1, 6): # 爬取前5页
url = f"https://example.com/jobs?page={page}&keyword=python"
response = requests.get(url, headers=headers)
soup = beautifulsoup(response.text, 'html.parser')
# 假设每个职位在class为'job-item'的div中
for item in soup.find_all('div', class_='job-item'):
title = item.find('h2').text.strip()
salary = item.find('span', class_='salary').text.strip()
city = item.find('span', class_='location').text.strip()
jobs.append({'title': title, 'salary': salary, 'city': city})
df = pd.dataframe(jobs)
df.to_csv('job_data.csv', index=false)
return df
data = crawl_job_data()提示:实际爬取时需遵守网站的robots协议,建议添加延迟(time.sleep(2))避免被封。
二、数据清洗:让数据"干净"起来
爬取的原始数据往往包含脏数据,比如薪资字段可能包含"15-20k/月"这样的文本。我们需要将其转换为数值:
def clean_salary(salary_str):
try:
# 提取数字部分,例如"15-20k/月"→[15,20]
parts = salary_str.replace('k', '').replace('/月', '').split('-')
if len(parts) == 2:
return (float(parts[0]) + float(parts[1])) / 2 # 取平均值
return float(parts[0])
except:
return none
data['salary'] = data['salary'].apply(clean_salary)
data = data.dropna(subset=['salary']) # 删除薪资为空的记录对于城市字段,我们可能需要统计每个城市的职位数量:
city_counts = data['city'].value_counts().head(10) # 取前10个城市
三、基础图表制作:柱状图与折线图
3.1 城市职位分布柱状图
柱状图最适合展示分类数据的对比:
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
city_counts.plot(kind='bar', color='#4c72b0')
plt.title('python岗位城市分布', fontsize=16)
plt.xlabel('城市', fontsize=12)
plt.ylabel('职位数量', fontsize=12)
plt.xticks(rotation=45) # 旋转x轴标签
plt.grid(axis='y', linestyle='--', alpha=0.7)
# 在柱子上方显示数值
for i, v in enumerate(city_counts):
plt.text(i, v + 50, str(v), ha='center')
plt.tight_layout() # 自动调整布局
plt.savefig('city_distribution.png', dpi=300)
plt.show()效果说明:
- 蓝色柱子高度代表职位数量
- 每个柱子上方显示具体数值
- 网格线辅助读数
- 图片保存为300dpi高清图
3.2 薪资趋势折线图
假设我们按经验要求分组统计平均薪资:
# 假设数据中有'experience'字段
exp_salary = data.groupby('experience')['salary'].mean()
plt.figure(figsize=(10, 5))
exp_salary.plot(kind='line', marker='o', color='#dd8452')
plt.title('不同经验要求的平均薪资', fontsize=14)
plt.xlabel('经验要求', fontsize=11)
plt.ylabel('平均薪资(k)', fontsize=11)
plt.grid(true, linestyle=':', alpha=0.6)
# 标记数据点
for x, y in zip(exp_salary.index, exp_salary):
plt.text(x, y, f'{y:.1f}k', ha='center', va='bottom')
plt.show()关键点:
- 橙色折线连接各数据点
- 每个数据点上方显示具体数值
- 虚线网格增强可读性
四、进阶图表:散点图与饼图
4.1 薪资与经验相关性散点图
探索薪资与工作经验是否相关:
# 假设我们随机生成一些经验年限数据
import numpy as np
np.random.seed(42)
data['experience_years'] = np.random.randint(1, 11, size=len(data))
plt.figure(figsize=(10, 8))
plt.scatter(data['experience_years'], data['salary'],
alpha=0.6, color='#55a868', s=50) # s控制点大小
plt.title('工作经验与薪资关系', fontsize=15)
plt.xlabel('工作经验(年)', fontsize=12)
plt.ylabel('薪资(k)', fontsize=12)
# 添加趋势线
z = np.polyfit(data['experience_years'], data['salary'], 1)
p = np.poly1d(z)
plt.plot(data['experience_years'], p(data['experience_years']),
"r--", linewidth=1)
plt.grid(true)
plt.show()解读:
- 绿色散点表示各个数据点
- 红色虚线为线性趋势线
- 透明度(alpha)设置避免点重叠
4.2 薪资范围饼图
展示不同薪资区间的职位占比:
# 创建薪资区间
bins = [0, 10, 15, 20, 30]
labels = ['10k以下', '10-15k', '15-20k', '20k以上']
data['salary_range'] = pd.cut(data['salary'], bins=bins, labels=labels)
range_counts = data['salary_range'].value_counts()
plt.figure(figsize=(8, 8))
plt.pie(range_counts, labels=range_counts.index,
autopct='%1.1f%%', startangle=90,
colors=['#c44e52', '#ccb974', '#64776d', '#798e87'])
plt.title('python岗位薪资分布', fontsize=15)
plt.tight_layout()
plt.show()技巧:
autopct显示百分比startangle控制起始角度- 自定义颜色让图表更美观
五、多图表组合:子图与仪表盘
5.1 创建包含多个图表的仪表盘
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('python岗位数据分析仪表盘', fontsize=18)
# 子图1:城市分布
axes[0,0].bar(city_counts.index, city_counts.values, color='#4c72b0')
axes[0,0].set_title('城市分布')
axes[0,0].tick_params(axis='x', rotation=45)
# 子图2:经验-薪资散点
axes[0,1].scatter(data['experience_years'], data['salary'],
alpha=0.5, color='#55a868')
axes[0,1].set_title('经验与薪资关系')
# 子图3:薪资范围饼图
axes[1,0].pie(range_counts, labels=none, autopct='%1.1f%%',
colors=['#c44e52', '#ccb974', '#64776d', '#798e87'])
axes[1,0].set_title('薪资分布')
# 子图4:经验要求折线图
exp_salary.plot(kind='line', marker='o', ax=axes[1,1], color='#dd8452')
axes[1,1].set_title('经验要求与平均薪资')
plt.tight_layout()
plt.subplots_adjust(top=0.92) # 调整标题位置
plt.savefig('dashboard.png', dpi=300)
plt.show()优势:
- 单张图片展示多个维度
- 适合放入分析报告
- 保持统一的风格
六、样式优化:让图表更专业
6.1 全局样式设置
plt.style.use('seaborn') # 使用seaborn样式
# 或自定义样式
plt.rcparams.update({
'font.family': 'microsoft yahei', # 中文支持
'axes.titlesize': 14,
'axes.labelsize': 12,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'figure.figsize': (10, 6),
'savefig.dpi': 300
})6.2 颜色搭配技巧
推荐使用以下配色方案:
- 分类数据:
['#4c72b0', '#55a868', '#c44e52', '#ccb974'] - 连续数据:
['#313695', '#4575b4', '#74add1', '#abd9e9']
可以使用在线工具coolors生成配色方案。
七、实际应用案例:电商价格监控
假设我们爬取了某电商平台的手机价格数据:
# 模拟数据
phone_data = {
'brand': ['apple']*5 + ['samsung']*5 + ['huawei']*5,
'model': ['iphone13']*3 + ['iphone13 pro']*2 +
['s22']*3 + ['s22 ultra']*2 +
['p50']*3 + ['mate50']*2,
'price': [5999, 6799, 5499, 8999, 9799,
4999, 5499, 6299, 7999, 8999,
4499, 4999, 5299, 6799, 7499],
'rating': [4.8, 4.9, 4.7, 4.9, 4.8,
4.6, 4.7, 4.8, 4.9, 4.8,
4.5, 4.6, 4.7, 4.8, 4.7]
}
df = pd.dataframe(phone_data)7.1 品牌价格对比箱线图
plt.figure(figsize=(10, 6))
df.boxplot(column='price', by='brand',
patch_artist=true,
boxprops=dict(facecolor='#4c72b0', color='black'),
medianprops=dict(color='white'))
plt.title('各品牌手机价格分布')
plt.suptitle('') # 去除自动生成的标题
plt.xlabel('品牌')
plt.ylabel('价格(元)')
plt.grid(true, linestyle='--', alpha=0.6)
plt.show()7.2 价格与评分散点图
plt.figure(figsize=(10, 6))
brands = df['brand'].unique()
colors = {'apple': '#4c72b0', 'samsung': '#55a868', 'huawei': '#c44e52'}
for brand in brands:
subset = df[df['brand'] == brand]
plt.scatter(subset['price'], subset['rating'],
s=100, label=brand, color=colors[brand])
plt.title('手机价格与评分关系')
plt.xlabel('价格(元)')
plt.ylabel('评分')
plt.legend()
plt.grid(true)
plt.show()常见问题q&a
q1:被网站封ip怎么办?
a:立即启用备用代理池,建议使用住宅代理(如站大爷ip代理),配合每请求更换ip策略。可以在requests请求中添加代理参数:
proxies = {
'http': 'http://your-proxy-ip:port',
'https': 'https://your-proxy-ip:port'
}
response = requests.get(url, headers=headers, proxies=proxies)q2:中文显示乱码如何解决?
a:在代码开头添加以下配置:
plt.rcparams['font.sans-serif'] = ['simhei'] # windows系统 plt.rcparams['axes.unicode_minus'] = false # 解决负号显示问题 # 或使用mac/linux的字体 # plt.rcparams['font.sans-serif'] = ['arial unicode ms']
q3:如何保存透明背景的图表?
a:使用savefig的transparent参数:
plt.savefig('transparent.png', dpi=300, transparent=true)q4:图表中的文字重叠怎么办?
a:可以尝试以下方法:
- 旋转x轴标签:
plt.xticks(rotation=45) - 调整图表大小:
plt.figure(figsize=(12, 6)) - 使用
tight_layout()自动调整 - 手动调整子图间距:
plt.subplots_adjust(wspace=0.4, hspace=0.6)
q5:如何实现动态图表?
a:可以使用matplotlib.animation模块创建动态图表,或导出为html使用plotly等库实现交互式可视化。
结语:数据可视化的价值
通过本文的实战,你应该已经掌握了从数据爬取到专业可视化的完整流程。记住,好的可视化不是追求花哨的效果,而是准确、清晰地传达数据背后的信息。下次当你面对一堆csv数据时,不妨先用matplotlib画几张图,往往能发现意想不到的洞察。
数据可视化就像给数据讲故事,而matplotlib就是你手中的画笔。现在,是时候用你爬取的数据,创作属于自己的数据故事了!
以上就是python使用matplotlib将爬取的csv数据变成直观图表的详细内容,更多关于python matplotlib将csv数据变成图表的资料请关注代码网其它相关文章!
发表评论