|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在当今数据驱动的时代,数据可视化已成为数据分析过程中不可或缺的一环。通过将复杂的数据转化为直观的图表,我们能够更快速地发现数据中的模式、趋势和异常。Python作为数据科学领域最受欢迎的编程语言之一,其pandas库不仅提供了强大的数据处理能力,还内置了便捷的数据可视化功能。本文将全面介绍如何利用pandas库实现从基础图表到高级可视化的各种技巧,帮助你快速掌握数据分析结果展示的方法。
pandas可视化基础
安装和设置
在开始使用pandas进行数据可视化之前,我们需要确保已安装必要的库。pandas的可视化功能实际上是基于Matplotlib构建的,因此我们通常需要同时安装pandas和Matplotlib。
- # 安装必要的库
- !pip install pandas matplotlib
- # 导入所需的库
- import pandas as pd
- import matplotlib.pyplot as plt
- import numpy as np
- # 设置matplotlib显示中文
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
- plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
- # 让matplotlib在Jupyter Notebook中内嵌显示
- %matplotlib inline
复制代码
pandas内置的plot方法
pandas的Series和DataFrame对象都内置了plot方法,这是进行数据可视化的最简单方式。plot方法实际上是Matplotlib的一个简单封装,让我们能够快速创建各种类型的图表。
- # 创建示例数据
- np.random.seed(42)
- df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
- df_cumsum = df.cumsum()
- # 使用plot方法绘制线图
- df_cumsum.plot(figsize=(10, 6))
- plt.title('简单线图示例')
- plt.xlabel('X轴')
- plt.ylabel('Y轴')
- plt.grid(True)
- plt.show()
复制代码
基础图表类型
线图
线图是最常用的图表类型之一,特别适合展示数据随时间变化的趋势。
- # 创建时间序列数据
- dates = pd.date_range(start='20230101', periods=100)
- ts = pd.Series(np.random.randn(100).cumsum(), index=dates)
- # 绘制线图
- plt.figure(figsize=(12, 6))
- ts.plot(color='green', linewidth=2, linestyle='-', marker='o', markersize=4)
- plt.title('股票价格模拟走势', fontsize=16)
- plt.xlabel('日期', fontsize=12)
- plt.ylabel('价格', fontsize=12)
- plt.grid(True, linestyle='--', alpha=0.7)
- plt.fill_between(ts.index, ts, 0, where=ts>0, facecolor='g', alpha=0.3)
- plt.fill_between(ts.index, ts, 0, where=ts<0, facecolor='r', alpha=0.3)
- plt.show()
复制代码
柱状图
柱状图适合比较不同类别的数据值大小。
- # 创建示例数据
- categories = ['A类', 'B类', 'C类', 'D类', 'E类']
- values = np.random.randint(10, 100, size=5)
- df_bar = pd.DataFrame({'类别': categories, '数值': values})
- # 绘制柱状图
- plt.figure(figsize=(10, 6))
- df_bar.plot(x='类别', y='数值', kind='bar', color='skyblue', legend=False)
- plt.title('各类别数值比较', fontsize=16)
- plt.xlabel('类别', fontsize=12)
- plt.ylabel('数值', fontsize=12)
- plt.xticks(rotation=0)
- # 在柱子上方添加数值标签
- for i, v in enumerate(values):
- plt.text(i, v + 1, str(v), ha='center')
-
- plt.grid(axis='y', linestyle='--', alpha=0.7)
- plt.tight_layout()
- plt.show()
复制代码
堆叠柱状图
堆叠柱状图可以同时展示总体和各部分的比例关系。
- # 创建示例数据
- years = ['2018', '2019', '2020', '2021', '2022']
- product_A = np.random.randint(100, 200, size=5)
- product_B = np.random.randint(100, 200, size=5)
- product_C = np.random.randint(100, 200, size=5)
- df_stack = pd.DataFrame({
- '年份': years,
- '产品A': product_A,
- '产品B': product_B,
- '产品C': product_C
- }).set_index('年份')
- # 绘制堆叠柱状图
- plt.figure(figsize=(10, 6))
- df_stack.plot(kind='bar', stacked=True, figsize=(10, 6))
- plt.title('各产品年度销量堆叠图', fontsize=16)
- plt.xlabel('年份', fontsize=12)
- plt.ylabel('销量', fontsize=12)
- plt.xticks(rotation=0)
- plt.legend(title='产品类别')
- # 添加总数值标签
- for i, total in enumerate(df_stack.sum(axis=1)):
- plt.text(i, total + 10, str(total), ha='center')
-
- plt.grid(axis='y', linestyle='--', alpha=0.7)
- plt.tight_layout()
- plt.show()
复制代码
散点图
散点图适合展示两个变量之间的关系。
- # 创建示例数据
- np.random.seed(42)
- N = 100
- x = np.random.rand(N)
- y = np.random.rand(N)
- colors = np.random.rand(N)
- sizes = 1000 * np.random.rand(N)
- df_scatter = pd.DataFrame({
- 'X值': x,
- 'Y值': y,
- '颜色': colors,
- '大小': sizes
- })
- # 绘制散点图
- plt.figure(figsize=(10, 8))
- scatter = plt.scatter(
- df_scatter['X值'],
- df_scatter['Y值'],
- c=df_scatter['颜色'],
- s=df_scatter['大小'],
- alpha=0.6,
- cmap='viridis'
- )
- plt.title('多维度散点图示例', fontsize=16)
- plt.xlabel('X值', fontsize=12)
- plt.ylabel('Y值', fontsize=12)
- plt.colorbar(scatter, label='颜色强度')
- plt.grid(True, linestyle='--', alpha=0.7)
- # 添加趋势线
- z = np.polyfit(df_scatter['X值'], df_scatter['Y值'], 1)
- p = np.poly1d(z)
- plt.plot(df_scatter['X值'], p(df_scatter['X值']), "r--", linewidth=2)
- plt.show()
复制代码
直方图
直方图适合展示数据的分布情况。
- # 创建示例数据
- np.random.seed(42)
- data = pd.DataFrame({
- '正态分布': np.random.normal(0, 1, 1000),
- '指数分布': np.random.exponential(1, 1000),
- '均匀分布': np.random.uniform(-1, 1, 1000)
- })
- # 绘制直方图
- plt.figure(figsize=(12, 8))
- data.plot(kind='hist', bins=30, alpha=0.5, figsize=(12, 8))
- plt.title('不同分布的直方图对比', fontsize=16)
- plt.xlabel('数值', fontsize=12)
- plt.ylabel('频数', fontsize=12)
- plt.grid(axis='y', linestyle='--', alpha=0.7)
- plt.legend()
- plt.show()
- # 分别绘制子图
- fig, axes = plt.subplots(1, 3, figsize=(18, 5))
- data['正态分布'].plot(kind='hist', bins=30, ax=axes[0], color='skyblue')
- axes[0].set_title('正态分布')
- data['指数分布'].plot(kind='hist', bins=30, ax=axes[1], color='salmon')
- axes[1].set_title('指数分布')
- data['均匀分布'].plot(kind='hist', bins=30, ax=axes[2], color='lightgreen')
- axes[2].set_title('均匀分布')
- for ax in axes:
- ax.set_xlabel('数值')
- ax.set_ylabel('频数')
- ax.grid(axis='y', linestyle='--', alpha=0.7)
- plt.tight_layout()
- plt.show()
复制代码
箱线图
箱线图可以展示数据的中位数、四分位数和异常值,是进行数据分布比较的有效工具。
- # 创建示例数据
- np.random.seed(42)
- data = pd.DataFrame({
- 'A组': np.random.normal(0, 1, 100),
- 'B组': np.random.normal(1, 1.5, 100),
- 'C组': np.random.normal(-1, 0.5, 100)
- })
- # 绘制箱线图
- plt.figure(figsize=(10, 6))
- data.plot(kind='box', figsize=(10, 6))
- plt.title('各组数据分布箱线图', fontsize=16)
- plt.ylabel('数值', fontsize=12)
- plt.grid(axis='y', linestyle='--', alpha=0.7)
- plt.show()
- # 添加小提琴图
- plt.figure(figsize=(10, 6))
- data.plot(kind='box', vert=False, positions=[1, 2, 3], widths=0.6)
- plt.yticks([1, 2, 3], ['A组', 'B组', 'C组'])
- plt.title('水平箱线图', fontsize=16)
- plt.xlabel('数值', fontsize=12)
- plt.grid(axis='x', linestyle='--', alpha=0.7)
- plt.show()
复制代码
自定义图表样式和美化技巧
颜色和样式设置
通过自定义颜色和样式,我们可以使图表更加美观和专业。
- # 创建示例数据
- dates = pd.date_range(start='20230101', periods=12)
- sales = pd.DataFrame({
- '产品A': np.random.randint(100, 200, size=12),
- '产品B': np.random.randint(100, 200, size=12),
- '产品C': np.random.randint(100, 200, size=12)
- }, index=dates)
- # 设置样式
- plt.style.use('ggplot') # 使用ggplot风格
- # 自定义颜色
- colors = ['#1f77b4', '#ff7f0e', '#2ca02c']
- # 绘制图表
- fig, ax = plt.subplots(figsize=(12, 6))
- sales.plot(ax=ax, color=colors, linewidth=2.5)
- # 添加标题和标签
- ax.set_title('2023年产品销售趋势', fontsize=16, pad=20)
- ax.set_xlabel('月份', fontsize=12)
- ax.set_ylabel('销售额', fontsize=12)
- # 自定义图例
- ax.legend(['产品A', '产品B', '产品C'], title='产品类别',
- frameon=True, fancybox=True, shadow=True)
- # 添加网格
- ax.grid(True, linestyle='--', alpha=0.7)
- # 添加数据标签
- for col in sales.columns:
- for i, value in enumerate(sales[col]):
- ax.annotate(f'{value}',
- xy=(i, value),
- xytext=(0, 5),
- textcoords='offset points',
- ha='center',
- va='bottom',
- fontsize=8)
- # 调整x轴刻度
- ax.set_xticks(range(len(sales.index)))
- ax.set_xticklabels([d.strftime('%m月') for d in sales.index])
- plt.tight_layout()
- plt.show()
复制代码
添加注释和标记
在图表中添加注释和标记可以帮助读者更好地理解数据的关键点。
- # 创建示例数据
- dates = pd.date_range(start='20230101', periods=24)
- values = pd.Series(np.random.randn(24).cumsum(), index=dates)
- # 找出最大值和最小值
- max_date = values.idxmax()
- max_value = values.max()
- min_date = values.idxmin()
- min_value = values.min()
- # 绘制图表
- plt.figure(figsize=(14, 7))
- values.plot(color='royalblue', linewidth=2.5, label='数值')
- # 标记最大值和最小值
- plt.scatter(max_date, max_value, color='red', s=100, zorder=5)
- plt.scatter(min_date, min_value, color='green', s=100, zorder=5)
- # 添加注释
- plt.annotate(f'最大值: {max_value:.2f}',
- xy=(max_date, max_value),
- xytext=(max_date, max_value + 2),
- arrowprops=dict(facecolor='red', shrink=0.05, width=1, headwidth=8),
- ha='center', fontsize=12)
- plt.annotate(f'最小值: {min_value:.2f}',
- xy=(min_date, min_value),
- xytext=(min_date, min_value - 2),
- arrowprops=dict(facecolor='green', shrink=0.05, width=1, headwidth=8),
- ha='center', fontsize=12)
- # 添加标题和标签
- plt.title('2023年数据趋势分析', fontsize=16, pad=20)
- plt.xlabel('日期', fontsize=12)
- plt.ylabel('数值', fontsize=12)
- plt.grid(True, linestyle='--', alpha=0.7)
- plt.legend()
- # 添加水平参考线
- plt.axhline(y=0, color='gray', linestyle='-', alpha=0.3)
- plt.tight_layout()
- plt.show()
复制代码
双轴图表
当需要同时展示两个不同量级或单位的数据时,双轴图表非常有用。
- # 创建示例数据
- dates = pd.date_range(start='20230101', periods=12)
- sales = pd.DataFrame({
- '销售额': np.random.randint(100, 200, size=12),
- '利润率': np.random.uniform(0.1, 0.3, size=12)
- }, index=dates)
- # 绘制双轴图表
- fig, ax1 = plt.subplots(figsize=(12, 6))
- # 绘制柱状图(销售额)
- color = 'tab:blue'
- ax1.set_xlabel('月份', fontsize=12)
- ax1.set_ylabel('销售额(万元)', color=color, fontsize=12)
- sales['销售额'].plot(kind='bar', ax=ax1, color=color, alpha=0.7, width=0.6)
- ax1.tick_params(axis='y', labelcolor=color)
- ax1.set_xticklabels([d.strftime('%m月') for d in sales.index], rotation=0)
- ax1.grid(axis='y', linestyle='--', alpha=0.7)
- # 创建第二个y轴
- ax2 = ax1.twinx()
- color = 'tab:red'
- ax2.set_ylabel('利润率', color=color, fontsize=12)
- sales['利润率'].plot(ax=ax2, color=color, marker='o', linewidth=2.5, markersize=8)
- ax2.tick_params(axis='y', labelcolor=color)
- ax2.set_ylim(0, 0.4)
- # 添加数据标签
- for i, v in enumerate(sales['销售额']):
- ax1.text(i, v + 5, f'{v}', ha='center', fontsize=9)
- for i, v in enumerate(sales['利润率']):
- ax2.text(i, v + 0.01, f'{v:.2%}', ha='center', fontsize=9, color=color)
- # 添加标题
- plt.title('2023年销售额与利润率双轴分析', fontsize=16, pad=20)
- fig.tight_layout()
- plt.show()
复制代码
高级可视化技巧
多子图绘制
在一个图形中展示多个子图可以方便地进行数据对比和分析。
- # 创建示例数据
- np.random.seed(42)
- dates = pd.date_range(start='20230101', periods=12)
- sales_data = pd.DataFrame({
- '产品A': np.random.randint(100, 200, size=12),
- '产品B': np.random.randint(100, 200, size=12),
- '产品C': np.random.randint(100, 200, size=12)
- }, index=dates)
- # 创建2x2的子图布局
- fig, axes = plt.subplots(2, 2, figsize=(15, 12))
- fig.suptitle('2023年产品销售数据分析', fontsize=20, y=1.02)
- # 子图1: 各产品月度销售趋势
- sales_data.plot(ax=axes[0, 0], linewidth=2.5)
- axes[0, 0].set_title('各产品月度销售趋势', fontsize=14)
- axes[0, 0].set_xlabel('月份')
- axes[0, 0].set_ylabel('销售额')
- axes[0, 0].grid(True, linestyle='--', alpha=0.7)
- axes[0, 0].legend()
- # 子图2: 月度总销售额柱状图
- monthly_total = sales_data.sum(axis=1)
- monthly_total.plot(kind='bar', ax=axes[0, 1], color='skyblue')
- axes[0, 1].set_title('月度总销售额', fontsize=14)
- axes[0, 1].set_xlabel('月份')
- axes[0, 1].set_ylabel('总销售额')
- axes[0, 1].set_xticklabels([d.strftime('%m月') for d in dates], rotation=0)
- axes[0, 1].grid(axis='y', linestyle='--', alpha=0.7)
- # 添加数据标签
- for i, v in enumerate(monthly_total):
- axes[0, 1].text(i, v + 10, f'{v}', ha='center')
- # 子图3: 产品销售占比饼图
- product_total = sales_data.sum()
- product_total.plot(kind='pie', ax=axes[1, 0], autopct='%1.1f%%',
- startangle=90, colors=['#1f77b4', '#ff7f0e', '#2ca02c'])
- axes[1, 0].set_title('产品销售占比', fontsize=14)
- axes[1, 0].set_ylabel('')
- # 子图4: 产品销售额箱线图
- sales_data.plot(kind='box', ax=axes[1, 1])
- axes[1, 1].set_title('产品销售额分布', fontsize=14)
- axes[1, 1].set_ylabel('销售额')
- axes[1, 1].grid(axis='y', linestyle='--', alpha=0.7)
- plt.tight_layout()
- plt.show()
复制代码
多变量数据可视化
当数据包含多个变量时,我们可以使用更复杂的可视化方法来展示变量之间的关系。
- # 创建示例数据
- np.random.seed(42)
- n_samples = 200
- data = pd.DataFrame({
- '变量A': np.random.normal(0, 1, n_samples),
- '变量B': np.random.normal(2, 1.5, n_samples),
- '变量C': np.random.normal(-1, 0.8, n_samples),
- '变量D': np.random.normal(1, 1.2, n_samples),
- '类别': np.random.choice(['类别1', '类别2', '类别3'], size=n_samples)
- })
- # 创建相关性矩阵图
- corr_matrix = data.iloc[:, :4].corr()
- plt.figure(figsize=(10, 8))
- plt.imshow(corr_matrix, cmap='coolwarm', vmin=-1, vmax=1)
- plt.colorbar(label='相关系数')
- plt.title('变量相关性矩阵', fontsize=16)
- # 添加相关系数标签
- for i in range(len(corr_matrix)):
- for j in range(len(corr_matrix)):
- plt.text(j, i, f'{corr_matrix.iloc[i, j]:.2f}',
- ha='center', va='center', color='white' if abs(corr_matrix.iloc[i, j]) > 0.5 else 'black')
- plt.xticks(range(len(corr_matrix)), corr_matrix.columns)
- plt.yticks(range(len(corr_matrix)), corr_matrix.columns)
- plt.tight_layout()
- plt.show()
- # 创建散点图矩阵
- pd.plotting.scatter_matrix(data.iloc[:, :4], figsize=(12, 10), alpha=0.6,
- diagonal='kde', marker='o', grid=True)
- plt.suptitle('多变量散点图矩阵', fontsize=16, y=1.02)
- plt.tight_layout()
- plt.show()
- # 创建平行坐标图
- from pandas.plotting import parallel_coordinates
- plt.figure(figsize=(12, 6))
- parallel_coordinates(data, '类别', colormap='viridis')
- plt.title('多变量平行坐标图', fontsize=16)
- plt.xlabel('变量')
- plt.ylabel('数值')
- plt.grid(True, linestyle='--', alpha=0.7)
- plt.legend(title='类别')
- plt.tight_layout()
- plt.show()
复制代码
时间序列数据可视化
时间序列数据有其特殊的可视化需求,pandas提供了专门的功能来处理这类数据。
- # 创建时间序列数据
- np.random.seed(42)
- dates = pd.date_range(start='20220101', end='20221231', freq='D')
- sales = pd.DataFrame({
- '销售额': np.random.randint(50, 200, size=len(dates)) +
- np.sin(np.arange(len(dates)) * 2 * np.pi / 365.25) * 50 + 100
- }, index=dates)
- # 按月重采样
- monthly_sales = sales.resample('M').sum()
- # 按季度重采样
- quarterly_sales = sales.resample('Q').sum()
- # 计算滚动平均
- rolling_avg = sales.rolling(window=30).mean()
- # 绘制时间序列图
- plt.figure(figsize=(14, 8))
- sales['销售额'].plot(alpha=0.5, label='日销售额')
- rolling_avg['销售额'].plot(linewidth=2, label='30天滚动平均')
- monthly_sales['销售额'].plot(marker='o', linewidth=2, label='月销售额')
- quarterly_sales['销售额'].plot(marker='s', linewidth=3, label='季度销售额')
- plt.title('2022年销售数据分析', fontsize=16)
- plt.xlabel('日期', fontsize=12)
- plt.ylabel('销售额', fontsize=12)
- plt.grid(True, linestyle='--', alpha=0.7)
- plt.legend()
- plt.tight_layout()
- plt.show()
- # 季节性分解
- from statsmodels.tsa.seasonal import seasonal_decompose
- # 确保数据频率一致
- sales_freq = sales.asfreq('D')
- # 执行季节性分解
- result = seasonal_decompose(sales_freq['销售额'], model='additive', period=30)
- # 绘制分解结果
- fig, axes = plt.subplots(4, 1, figsize=(14, 12), sharex=True)
- result.observed.plot(ax=axes[0], legend=False)
- axes[0].set_title('原始数据', fontsize=14)
- axes[0].grid(True, linestyle='--', alpha=0.7)
- result.trend.plot(ax=axes[1], legend=False)
- axes[1].set_title('趋势', fontsize=14)
- axes[1].grid(True, linestyle='--', alpha=0.7)
- result.seasonal.plot(ax=axes[2], legend=False)
- axes[2].set_title('季节性', fontsize=14)
- axes[2].grid(True, linestyle='--', alpha=0.7)
- result.resid.plot(ax=axes[3], legend=False)
- axes[3].set_title('残差', fontsize=14)
- axes[3].grid(True, linestyle='--', alpha=0.7)
- plt.suptitle('时间序列季节性分解', fontsize=16, y=1.02)
- plt.tight_layout()
- plt.show()
复制代码
地理数据可视化
地理数据可视化可以帮助我们理解数据在空间上的分布和关系。
- # 安装和导入地理可视化库
- !pip install geopandas folium
- import geopandas as gpd
- import folium
- from folium.plugins import HeatMap
- # 创建示例地理数据
- np.random.seed(42)
- cities = ['北京', '上海', '广州', '深圳', '成都', '杭州', '武汉', '西安']
- lats = [39.9042, 31.2304, 23.1291, 22.5431, 30.5728, 30.2741, 30.5928, 34.3416]
- lons = [116.4074, 121.4737, 113.2644, 114.0579, 104.0668, 120.1551, 114.3055, 108.9398]
- values = np.random.randint(50, 200, size=8)
- geo_data = pd.DataFrame({
- '城市': cities,
- '纬度': lats,
- '经度': lons,
- '数值': values
- })
- # 创建基础地图
- m = folium.Map(location=[35, 110], zoom_start=5)
- # 添加标记点
- for i, row in geo_data.iterrows():
- folium.CircleMarker(
- location=[row['纬度'], row['经度']],
- radius=row['数值'] / 10,
- popup=f"{row['城市']}: {row['数值']}",
- color='crimson',
- fill=True,
- fill_color='crimson'
- ).add_to(m)
- # 显示地图
- m
- # 创建热力图
- heat_data = [[row['纬度'], row['经度'], row['数值']] for i, row in geo_data.iterrows()]
- m_heat = folium.Map(location=[35, 110], zoom_start=5)
- HeatMap(heat_data).add_to(m_heat)
- # 显示热力图
- m_heat
复制代码
pandas与其他可视化库的结合
虽然pandas内置的可视化功能已经相当强大,但与其他专业可视化库结合使用可以实现更丰富的效果。
与Seaborn结合
Seaborn是基于Matplotlib的高级可视化库,提供了更美观的统计图表。
- # 安装seaborn
- !pip install seaborn
- import seaborn as sns
- # 创建示例数据
- np.random.seed(42)
- data = pd.DataFrame({
- '类别': np.random.choice(['A', 'B', 'C', 'D'], size=200),
- '数值1': np.random.normal(0, 1, size=200),
- '数值2': np.random.normal(1, 1.5, size=200),
- '分组': np.random.choice(['组1', '组2'], size=200)
- })
- # 设置Seaborn风格
- sns.set(style="whitegrid")
- plt.figure(figsize=(12, 6))
- # 绘制小提琴图
- sns.violinplot(x='类别', y='数值1', hue='分组', data=data, split=True)
- plt.title('不同类别和分组的数值分布', fontsize=16)
- plt.xlabel('类别', fontsize=12)
- plt.ylabel('数值', fontsize=12)
- plt.legend(title='分组')
- plt.tight_layout()
- plt.show()
- # 绘制成对关系图
- plt.figure(figsize=(10, 8))
- sns.pairplot(data, hue='类别', vars=['数值1', '数值2'], palette='viridis')
- plt.suptitle('多变量成对关系', y=1.02)
- plt.tight_layout()
- plt.show()
- # 绘制联合分布图
- plt.figure(figsize=(10, 8))
- sns.jointplot(x='数值1', y='数值2', data=data, kind='reg', hue='类别')
- plt.suptitle('两变量联合分布与回归', y=1.02)
- plt.tight_layout()
- plt.show()
复制代码
与Plotly结合
Plotly是一个交互式可视化库,可以创建动态、可交互的图表。
- # 安装plotly
- !pip install plotly
- import plotly.express as px
- import plotly.graph_objects as go
- from plotly.subplots import make_subplots
- # 创建示例数据
- dates = pd.date_range(start='20230101', periods=12)
- sales_data = pd.DataFrame({
- '月份': dates,
- '产品A': np.random.randint(100, 200, size=12),
- '产品B': np.random.randint(100, 200, size=12),
- '产品C': np.random.randint(100, 200, size=12)
- })
- # 转换为长格式
- sales_long = pd.melt(sales_data, id_vars=['月份'], var_name='产品', value_name='销售额')
- # 创建交互式线图
- fig = px.line(sales_long, x='月份', y='销售额', color='产品',
- title='2023年产品销售趋势',
- labels={'月份': '月份', '销售额': '销售额', '产品': '产品类别'},
- line_shape='linear')
- # 添加自定义样式
- fig.update_layout(
- title_font_size=20,
- xaxis_title_font_size=14,
- yaxis_title_font_size=14,
- legend_title_font_size=14,
- hovermode='x unified'
- )
- fig.show()
- # 创建交互式柱状图
- fig_bar = px.bar(sales_long, x='月份', y='销售额', color='产品',
- title='2023年产品销售柱状图',
- labels={'月份': '月份', '销售额': '销售额', '产品': '产品类别'},
- barmode='group')
- fig_bar.update_layout(
- title_font_size=20,
- xaxis_title_font_size=14,
- yaxis_title_font_size=14,
- legend_title_font_size=14
- )
- fig_bar.show()
- # 创建子图组合
- fig_sub = make_subplots(
- rows=2, cols=2,
- subplot_titles=('产品销售趋势', '产品销售占比', '月度总销售额', '产品销售额分布'),
- specs=[[{"secondary_y": False}, {"type": "pie"}],
- [{"secondary_y": False}, {"type": "box"}]]
- )
- # 添加线图
- for product in ['产品A', '产品B', '产品C']:
- fig_sub.add_trace(
- go.Scatter(x=sales_data['月份'], y=sales_data[product], name=product, mode='lines+markers'),
- row=1, col=1
- )
- # 添加饼图
- product_total = sales_data[['产品A', '产品B', '产品C']].sum()
- fig_sub.add_trace(
- go.Pie(labels=product_total.index, values=product_total.values, name="销售占比"),
- row=1, col=2
- )
- # 添加柱状图
- monthly_total = sales_data[['产品A', '产品B', '产品C']].sum(axis=1)
- fig_sub.add_trace(
- go.Bar(x=sales_data['月份'], y=monthly_total, name='月度总销售额'),
- row=2, col=1
- )
- # 添加箱线图
- for product in ['产品A', '产品B', '产品C']:
- fig_sub.add_trace(
- go.Box(y=sales_data[product], name=product),
- row=2, col=2
- )
- # 更新布局
- fig_sub.update_layout(
- title_text="2023年产品销售数据综合分析",
- title_font_size=20,
- showlegend=False,
- height=800
- )
- fig_sub.show()
复制代码
实际案例分析:从数据到可视化报告
让我们通过一个完整的案例,展示如何从原始数据到最终的可视化报告。
- # 步骤1: 数据准备
- import pandas as pd
- import numpy as np
- import matplotlib.pyplot as plt
- import seaborn as sns
- # 创建模拟销售数据
- np.random.seed(42)
- dates = pd.date_range(start='20220101', end='20221231', freq='D')
- products = ['产品A', '产品B', '产品C', '产品D']
- regions = ['华北', '华东', '华南', '西南', '西北']
- # 生成基础数据
- data = []
- for date in dates:
- for product in products:
- for region in regions:
- # 添加季节性因素
- seasonal_factor = 1 + 0.3 * np.sin(2 * np.pi * (date.dayofyear - 80) / 365)
-
- # 添加产品基础销量
- base_sales = {
- '产品A': 100,
- '产品B': 150,
- '产品C': 80,
- '产品D': 120
- }[product]
-
- # 添加区域因子
- region_factor = {
- '华北': 1.2,
- '华东': 1.5,
- '华南': 1.3,
- '西南': 0.9,
- '西北': 0.7
- }[region]
-
- # 计算最终销量
- sales = base_sales * seasonal_factor * region_factor * (0.8 + 0.4 * np.random.random())
-
- data.append({
- '日期': date,
- '产品': product,
- '区域': region,
- '销量': int(sales),
- '单价': np.random.randint(50, 200),
- '成本': np.random.randint(30, 150)
- })
- # 创建DataFrame
- df = pd.DataFrame(data)
- # 计算销售额和利润
- df['销售额'] = df['销量'] * df['单价']
- df['利润'] = df['销售额'] - (df['销量'] * df['成本'])
- # 步骤2: 数据分析
- # 按月汇总数据
- df['月份'] = df['日期'].dt.to_period('M')
- monthly_data = df.groupby(['月份', '产品', '区域']).agg({
- '销量': 'sum',
- '销售额': 'sum',
- '利润': 'sum'
- }).reset_index()
- # 步骤3: 创建可视化报告
- # 设置全局样式
- plt.style.use('seaborn')
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
- plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
- # 创建报告布局
- fig = plt.figure(figsize=(20, 25))
- fig.suptitle('2022年销售数据分析报告', fontsize=24, y=1.02)
- # 子图1: 月度总销售额趋势
- ax1 = plt.subplot(3, 2, 1)
- monthly_total = monthly_data.groupby('月份')['销售额'].sum()
- monthly_total.plot(ax=ax1, linewidth=3, marker='o', markersize=8, color='#1f77b4')
- ax1.set_title('月度总销售额趋势', fontsize=16)
- ax1.set_xlabel('月份', fontsize=12)
- ax1.set_ylabel('销售额(元)', fontsize=12)
- ax1.grid(True, linestyle='--', alpha=0.7)
- # 子图2: 产品销售额占比
- ax2 = plt.subplot(3, 2, 2)
- product_sales = monthly_data.groupby('产品')['销售额'].sum()
- product_sales.plot(kind='pie', ax=ax2, autopct='%1.1f%%', startangle=90,
- colors=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])
- ax2.set_title('产品销售额占比', fontsize=16)
- ax2.set_ylabel('')
- # 子图3: 区域销售额对比
- ax3 = plt.subplot(3, 2, 3)
- region_sales = monthly_data.groupby('区域')['销售额'].sum().sort_values(ascending=False)
- region_sales.plot(kind='bar', ax=ax3, color='skyblue')
- ax3.set_title('区域销售额对比', fontsize=16)
- ax3.set_xlabel('区域', fontsize=12)
- ax3.set_ylabel('销售额(元)', fontsize=12)
- ax3.grid(axis='y', linestyle='--', alpha=0.7)
- # 添加数据标签
- for i, v in enumerate(region_sales):
- ax3.text(i, v + region_sales.max() * 0.01, f'{v:,.0f}', ha='center')
- # 子图4: 产品月度销售趋势
- ax4 = plt.subplot(3, 2, 4)
- for product in products:
- product_monthly = monthly_data[monthly_data['产品'] == product].groupby('月份')['销售额'].sum()
- product_monthly.plot(ax=ax4, linewidth=2, label=product)
- ax4.set_title('产品月度销售趋势', fontsize=16)
- ax4.set_xlabel('月份', fontsize=12)
- ax4.set_ylabel('销售额(元)', fontsize=12)
- ax4.grid(True, linestyle='--', alpha=0.7)
- ax4.legend()
- # 子图5: 区域-产品热力图
- ax5 = plt.subplot(3, 2, 5)
- region_product = monthly_data.pivot_table(index='区域', columns='产品', values='销售额', aggfunc='sum')
- sns.heatmap(region_product, annot=True, fmt=',.0f', cmap='YlGnBu', ax=ax5)
- ax5.set_title('区域-产品销售额热力图', fontsize=16)
- ax5.set_xlabel('产品', fontsize=12)
- ax5.set_ylabel('区域', fontsize=12)
- # 子图6: 利润分析
- ax6 = plt.subplot(3, 2, 6)
- profit_data = monthly_data.groupby('月份').agg({
- '销售额': 'sum',
- '利润': 'sum'
- })
- profit_data['利润率'] = profit_data['利润'] / profit_data['销售额']
- # 创建双轴
- ax6_twin = ax6.twinx()
- # 绘制销售额柱状图
- profit_data['销售额'].plot(kind='bar', ax=ax6, color='skyblue', alpha=0.7, width=0.8)
- ax6.set_title('月度销售额与利润率分析', fontsize=16)
- ax6.set_xlabel('月份', fontsize=12)
- ax6.set_ylabel('销售额(元)', fontsize=12)
- ax6.set_xticklabels([str(m).split('-')[1] + '月' for m in profit_data.index], rotation=0)
- ax6.grid(axis='y', linestyle='--', alpha=0.7)
- # 绘制利润率线图
- profit_data['利润率'].plot(ax=ax6_twin, color='red', linewidth=3, marker='o', markersize=6)
- ax6_twin.set_ylabel('利润率', fontsize=12, color='red')
- ax6_twin.tick_params(axis='y', labelcolor='red')
- ax6_twin.set_ylim(0, 0.5)
- # 添加利润率标签
- for i, rate in enumerate(profit_data['利润率']):
- ax6_twin.text(i, rate + 0.01, f'{rate:.1%}', ha='center', color='red')
- plt.tight_layout()
- plt.savefig('sales_analysis_report.png', dpi=300, bbox_inches='tight')
- plt.show()
- # 步骤4: 生成分析结论
- print("=== 2022年销售数据分析结论 ===")
- print(f"\n1. 年度总销售额: {monthly_data['销售额'].sum():,.0f}元")
- print(f"2. 年度总利润: {monthly_data['利润'].sum():,.0f}元")
- print(f"3. 年度平均利润率: {(monthly_data['利润'].sum() / monthly_data['销售额'].sum()):.1%}")
- print("\n4. 产品销售排名:")
- product_ranking = monthly_data.groupby('产品')['销售额'].sum().sort_values(ascending=False)
- for i, (product, sales) in enumerate(product_ranking.items(), 1):
- print(f" 第{i}名: {product} - {sales:,.0f}元 ({sales/monthly_data['销售额'].sum():.1%})")
- print("\n5. 区域销售排名:")
- region_ranking = monthly_data.groupby('区域')['销售额'].sum().sort_values(ascending=False)
- for i, (region, sales) in enumerate(region_ranking.items(), 1):
- print(f" 第{i}名: {region} - {sales:,.0f}元 ({sales/monthly_data['销售额'].sum():.1%})")
- print("\n6. 销售额最高月份:")
- best_month = monthly_data.groupby('月份')['销售额'].sum().idxmax()
- best_month_sales = monthly_data.groupby('月份')['销售额'].sum().max()
- print(f" {best_month} - {best_month_sales:,.0f}元")
- print("\n7. 利润率分析:")
- profit_rate = monthly_data.groupby('月份').apply(lambda x: x['利润'].sum() / x['销售额'].sum())
- best_profit_month = profit_rate.idxmax()
- worst_profit_month = profit_rate.idxmin()
- print(f" 最高利润率月份: {best_profit_month} - {profit_rate.max():.1%}")
- print(f" 最低利润率月份: {worst_profit_month} - {profit_rate.min():.1%}")
复制代码
最佳实践和常见问题解决方案
最佳实践
1. 选择合适的图表类型时间序列数据:线图类别比较:柱状图分布情况:直方图、箱线图关系分析:散点图占比分析:饼图、堆叠柱状图
2. 时间序列数据:线图
3. 类别比较:柱状图
4. 分布情况:直方图、箱线图
5. 关系分析:散点图
6. 占比分析:饼图、堆叠柱状图
7. 保持图表简洁清晰避免过度装饰,专注于数据本身使用适当的颜色,确保对比度足够添加必要的标签和说明
8. 避免过度装饰,专注于数据本身
9. 使用适当的颜色,确保对比度足够
10. 添加必要的标签和说明
11. 注重数据准确性确保数据预处理正确检查异常值和缺失值验证计算结果
12. 确保数据预处理正确
13. 检查异常值和缺失值
14. 验证计算结果
15. 考虑受众需求根据受众调整技术细节的深度提供必要的背景信息和解释突出关键发现和结论
16. 根据受众调整技术细节的深度
17. 提供必要的背景信息和解释
18. 突出关键发现和结论
选择合适的图表类型
• 时间序列数据:线图
• 类别比较:柱状图
• 分布情况:直方图、箱线图
• 关系分析:散点图
• 占比分析:饼图、堆叠柱状图
保持图表简洁清晰
• 避免过度装饰,专注于数据本身
• 使用适当的颜色,确保对比度足够
• 添加必要的标签和说明
注重数据准确性
• 确保数据预处理正确
• 检查异常值和缺失值
• 验证计算结果
考虑受众需求
• 根据受众调整技术细节的深度
• 提供必要的背景信息和解释
• 突出关键发现和结论
常见问题及解决方案
- # 解决方案:设置中文字体
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
- plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
复制代码- # 解决方案:调整布局和边距
- plt.tight_layout() # 自动调整子图参数
- # 或者手动调整
- plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1, wspace=0.3, hspace=0.5)
复制代码- # 解决方案:自定义图例位置
- plt.legend(loc='best') # 自动选择最佳位置
- # 或者指定位置
- plt.legend(loc='upper right', bbox_to_anchor=(1.15, 1))
复制代码- # 解决方案:数据采样或聚合
- # 采样
- sampled_data = df.sample(frac=0.1) # 随机采样10%的数据
- # 聚合
- aggregated_data = df.groupby('category').agg({'value': 'mean'})
复制代码- # 解决方案:调整导出参数
- plt.savefig('chart.png', dpi=300, bbox_inches='tight', quality=95)
- # 导出为矢量图
- plt.savefig('chart.pdf', format='pdf', bbox_inches='tight')
复制代码
结论与展望
通过本文的全面介绍,我们深入了解了如何利用Python pandas库实现从基础图表到高级可视化的各种技巧。pandas作为一个强大的数据处理和分析工具,其内置的可视化功能为我们提供了快速探索数据的便捷途径。同时,结合Matplotlib、Seaborn、Plotly等专业可视化库,我们可以创建更加精美和专业的数据可视化作品。
数据可视化不仅是展示数据的手段,更是发现数据中隐藏模式和洞察的重要工具。随着数据量的不断增长和分析需求的日益复杂,数据可视化技术也在不断发展。未来,我们可以期待更多交互式、动态化和智能化的可视化工具的出现,这将使数据分析工作更加高效和直观。
掌握pandas数据可视化技能,将帮助你在数据分析、商业智能、科学研究等领域更好地展示你的发现和成果。希望本文能够成为你学习pandas数据可视化的有力参考,助你在数据之路上走得更远。
版权声明
1、转载或引用本网站内容(利用Python pandas库轻松实现数据可视化输出精美图片从基础图表到高级可视化技巧全面解析助你快速掌握数据分析结果展示)须注明原网址及作者(威震华夏关云长),并标明本网站网址(https://www.pixtech.cc/)。
2、对于不当转载或引用本网站内容而引起的民事纷争、行政处理或其他损失,本网站不承担责任。
3、对不遵守本声明或其他违法、恶意使用本网站内容者,本网站保留追究其法律责任的权利。
本文地址: https://www.pixtech.cc/thread-40984-1-1.html
|
|