|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
Pandas是Python数据分析的核心库,它提供了强大的数据处理和分析功能。然而,仅仅有准确的数据分析结果是不够的,如何将这些结果以清晰、美观的方式呈现出来,同样重要。一份专业的数据分析报告不仅能准确传达信息,还能通过良好的视觉设计提升报告的说服力和专业度。本文将全面介绍Pandas美化输出的各种技巧,从基础的表格格式设置到高级的数据可视化,帮助你打造专业级的数据分析报告。
基础表格美化
基本显示设置
Pandas提供了一些基本的显示设置选项,可以让我们更好地控制数据的显示方式。首先,让我们创建一个示例数据集:
- import pandas as pd
- import numpy as np
- # 创建示例数据
- data = {
- '姓名': ['张三', '李四', '王五', '赵六', '钱七'],
- '年龄': [25, 30, 35, 40, 45],
- '工资': [8000, 12000, 15000, 18000, 20000],
- '部门': ['技术部', '市场部', '财务部', '技术部', '市场部'],
- '入职日期': pd.to_datetime(['2020-01-15', '2019-03-22', '2018-07-10', '2017-11-05', '2021-02-28'])
- }
- df = pd.DataFrame(data)
复制代码
默认情况下,Pandas会显示所有列,但可能会截断长文本或只显示部分行。我们可以通过以下设置来控制显示行为:
- # 设置显示的最大行数
- pd.set_option('display.max_rows', 100)
- # 设置显示的最大列数
- pd.set_option('display.max_columns', 50)
- # 设置列宽
- pd.set_option('display.max_colwidth', 50)
- # 设置显示精度
- pd.set_option('display.precision', 2)
- # 显示所有列(不省略)
- pd.set_option('display.expand_frame_repr', False)
复制代码
基本样式设置
Pandas的style属性提供了丰富的表格样式设置选项。以下是一些基本的样式设置方法:
- # 设置表格标题
- styled_df = df.style.set_caption('员工信息表')
- # 设置表格对齐方式
- styled_df = df.style.set_properties(**{'text-align': 'center'})
- # 隐藏索引
- styled_df = df.style.hide_index()
- # 设置列名格式
- styled_df = df.style.set_table_styles([
- {'selector': 'th', 'props': [('font-size', '12pt'), ('background-color', '#f7f7f9')]}
- ])
- # 应用多个样式
- styled_df = df.style.set_caption('员工信息表').set_properties(**{'text-align': 'center'}).hide_index()
复制代码
条件格式化
条件格式化可以根据数据值自动应用不同的样式,使数据中的模式和趋势更加明显:
- # 高亮最大值
- styled_df = df.style.highlight_max(axis=0)
- # 高亮最小值
- styled_df = df.style.highlight_min(axis=0)
- # 高亮指定范围的值
- styled_df = df.style.highlight_between(left=10000, right=15000, subset=['工资'])
- # 使用颜色渐变表示数值大小
- styled_df = df.style.background_gradient(cmap='Blues', subset=['年龄', '工资'])
- # 使用条形图表示数值大小
- styled_df = df.style.bar(subset=['工资'], color='#5fba7d')
- # 自定义条件格式
- def highlight_high_salary(val):
- color = 'red' if val > 15000 else 'black'
- return f'color: {color}'
- styled_df = df.style.applymap(highlight_high_salary, subset=['工资'])
复制代码
进阶表格美化
复杂样式设置
除了基本的样式设置,Pandas还支持更复杂的样式定制:
- # 创建一个更复杂的示例数据集
- np.random.seed(42)
- dates = pd.date_range('20230101', periods=10)
- companies = ['公司A', '公司B', '公司C', '公司D', '公司E']
- multi_index = pd.MultiIndex.from_product([dates, companies], names=['日期', '公司'])
- data = np.random.randn(50, 4)
- columns = ['开盘价', '收盘价', '最高价', '最低价']
- df_stock = pd.DataFrame(data, index=multi_index, columns=columns)
- # 重置索引以便于演示
- df_stock = df_stock.reset_index()
- # 应用复杂样式
- def style_function(df):
- # 添加标题
- styles = df.style.set_caption('股票价格数据表')
-
- # 设置数值格式
- styles = styles.format({
- '开盘价': '{:.2f}',
- '收盘价': '{:.2f}',
- '最高价': '{:.2f}',
- '最低价': '{:.2f}'
- })
-
- # 高亮收盘价大于开盘价的行
- def highlight_positive_change(row):
- if row['收盘价'] > row['开盘价']:
- return ['background-color: #d4edda'] * len(row)
- else:
- return ['background-color: #f8d7da'] * len(row)
-
- styles = styles.apply(highlight_positive_change, axis=1)
-
- # 添加条形图
- styles = styles.bar(subset=['最高价', '最低价'], color=['#ff9999', '#99ccff'])
-
- # 设置表格样式
- styles = styles.set_table_styles([
- {'selector': 'th', 'props': [('background-color', '#40466e'), ('color', 'white'), ('font-weight', 'bold')]},
- {'selector': 'td', 'props': [('text-align', 'center')]},
- {'selector': 'caption', 'props': [('caption-side', 'top'), ('font-size', '16pt'), ('font-weight', 'bold')]}
- ])
-
- return styles
- styled_df_stock = style_function(df_stock)
复制代码
使用Styler对象
Pandas的Styler对象提供了更多高级功能,如导出样式、应用自定义函数等:
- # 创建Styler对象
- styler = df.style
- # 应用自定义样式函数
- def color_negative_red(val):
- """
- 将负值变为红色
- """
- color = 'red' if val < 0 else 'black'
- return f'color: {color}'
- def highlight_max(s):
- """
- 高亮最大值
- """
- is_max = s == s.max()
- return ['background-color: yellow' if v else '' for v in is_max]
- # 应用样式
- styler = styler.applymap(color_negative_red, subset=['工资'])
- styler = styler.apply(highlight_max, subset=['年龄', '工资'])
- # 添加数据条
- styler = styler.bar(subset=['工资'], align='mid', color=['#d65f5f', '#5fba7d'])
- # 设置精度
- styler = styler.format({'工资': '¥{:.2f}', '年龄': '{:.0f}岁'})
- # 显示样式
- styled_df = styler
复制代码
导出样式化表格
样式化的表格可以导出为多种格式,便于在报告或演示中使用:
- # 导出为HTML
- html = styled_df.to_html()
- # 保存HTML文件
- with open('styled_table.html', 'w', encoding='utf-8') as f:
- f.write(html)
- # 导出为Excel(保留样式)
- styled_df.to_excel('styled_table.xlsx', engine='openpyxl')
- # 导出为LaTeX
- latex = styled_df.to_latex()
- print(latex)
复制代码
数据可视化基础
Pandas内置绘图功能
Pandas内置了基于Matplotlib的绘图功能,可以快速创建基本图表:
- # 创建示例数据
- np.random.seed(42)
- df_sales = pd.DataFrame({
- '月份': pd.date_range('20230101', periods=12, freq='M'),
- '产品A': np.random.randint(100, 500, 12),
- '产品B': np.random.randint(200, 600, 12),
- '产品C': np.random.randint(150, 550, 12)
- })
- df_sales.set_index('月份', inplace=True)
- # 折线图
- ax = df_sales.plot(figsize=(10, 6), title='月度销售趋势')
- ax.set_ylabel('销售额')
- ax.set_xlabel('月份')
- ax.grid(True)
- # 柱状图
- ax = df_sales.plot(kind='bar', figsize=(10, 6), title='月度销售对比')
- ax.set_ylabel('销售额')
- ax.set_xlabel('月份')
- ax.grid(True, axis='y')
- # 堆叠柱状图
- ax = df_sales.plot(kind='bar', stacked=True, figsize=(10, 6), title='月度销售构成')
- ax.set_ylabel('销售额')
- ax.set_xlabel('月份')
- ax.grid(True, axis='y')
- # 饼图
- df_sales.sum().plot(kind='pie', figsize=(8, 8), autopct='%1.1f%%', title='产品销售占比')
- # 箱线图
- df_sales.plot(kind='box', figsize=(10, 6), title='销售数据分布')
- # 面积图
- df_sales.plot(kind='area', figsize=(10, 6), title='月度销售趋势')
复制代码
基本图表美化
我们可以通过添加各种元素来美化基本图表:
- import matplotlib.pyplot as plt
- # 设置中文显示
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
- plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
- # 创建更美观的折线图
- plt.figure(figsize=(12, 6))
- # 绘制多条线
- for column in df_sales.columns:
- plt.plot(df_sales.index, df_sales[column], marker='o', label=column)
- # 添加标题和标签
- plt.title('2023年月度销售趋势', fontsize=16, pad=20)
- plt.xlabel('月份', fontsize=12)
- plt.ylabel('销售额(元)', fontsize=12)
- # 设置刻度
- plt.xticks(df_sales.index, [f'{i+1}月' for i in range(12)], rotation=45)
- plt.yticks(fontsize=10)
- # 添加网格
- plt.grid(True, linestyle='--', alpha=0.7)
- # 添加图例
- plt.legend(fontsize=12, frameon=True, fancybox=True, shadow=True)
- # 添加数据标签
- for column in df_sales.columns:
- for i, value in enumerate(df_sales[column]):
- plt.text(df_sales.index[i], value, f'{value}', ha='center', va='bottom', fontsize=8)
- # 调整布局
- plt.tight_layout()
- # 显示图表
- plt.show()
复制代码
高级图表类型
除了基本图表,Pandas还可以创建更复杂的图表类型:
- # 创建示例数据
- np.random.seed(42)
- categories = ['电子产品', '服装', '食品', '家居', '图书']
- quarters = ['Q1', 'Q2', 'Q3', 'Q4']
- data = np.random.randint(100, 1000, size=(len(categories), len(quarters)))
- df_category = pd.DataFrame(data, index=categories, columns=quarters)
- # 热力图
- plt.figure(figsize=(10, 8))
- plt.imshow(df_category, cmap='YlGnBu')
- plt.colorbar()
- plt.xticks(range(len(quarters)), quarters)
- plt.yticks(range(len(categories)), categories)
- plt.title('各类别季度销售热力图', fontsize=16, pad=20)
- # 添加数据标签
- for i in range(len(categories)):
- for j in range(len(quarters)):
- plt.text(j, i, df_category.iloc[i, j], ha='center', va='center', color='white')
- plt.tight_layout()
- plt.show()
- # 散点图矩阵
- from pandas.plotting import scatter_matrix
- df_scatter = pd.DataFrame({
- 'X': np.random.randn(100),
- 'Y': np.random.randn(100),
- 'Z': np.random.randn(100)
- })
- scatter_matrix(df_scatter, alpha=0.5, figsize=(10, 10), diagonal='kde')
- plt.suptitle('变量关系散点图矩阵', fontsize=16)
- plt.tight_layout()
- plt.show()
- # 平行坐标图
- from pandas.plotting import parallel_coordinates
- df_parallel = pd.DataFrame({
- '类别': np.random.choice(['A', 'B', 'C'], 100),
- '特征1': np.random.randn(100),
- '特征2': np.random.randn(100),
- '特征3': np.random.randn(100),
- '特征4': np.random.randn(100)
- })
- plt.figure(figsize=(12, 6))
- parallel_coordinates(df_parallel, '类别', colormap='viridis')
- plt.title('平行坐标图', fontsize=16)
- plt.grid(True, linestyle='--', alpha=0.5)
- plt.tight_layout()
- plt.show()
复制代码
高级数据可视化
结合Matplotlib和Seaborn
Seaborn是基于Matplotlib的高级可视化库,提供了更美观的默认样式和更复杂的图表类型:
- import seaborn as sns
- # 设置Seaborn样式
- sns.set_style("whitegrid")
- sns.set_context("notebook", font_scale=1.2)
- # 创建示例数据
- np.random.seed(42)
- tips = sns.load_dataset("tips")
- # 创建更美观的散点图
- plt.figure(figsize=(12, 8))
- scatter = sns.scatterplot(
- x="total_bill", y="tip",
- hue="day", size="size",
- data=tips, alpha=0.7,
- palette="viridis", sizes=(20, 200)
- )
- # 添加标题和标签
- plt.title('餐厅账单与小费关系', fontsize=16, pad=20)
- plt.xlabel('总账单(美元)', fontsize=12)
- plt.ylabel('小费(美元)', fontsize=12)
- # 添加回归线
- sns.regplot(x="total_bill", y="tip", data=tips, scatter=False, color='red')
- # 添加图例
- plt.legend(title='星期', title_fontsize=12, fontsize=10)
- # 调整布局
- plt.tight_layout()
- plt.show()
- # 创建更美观的箱线图
- plt.figure(figsize=(12, 8))
- boxplot = sns.boxplot(
- x="day", y="total_bill",
- hue="sex", data=tips,
- palette="pastel", width=0.6
- )
- # 添加标题和标签
- plt.title('不同日期和性别的账单分布', fontsize=16, pad=20)
- plt.xlabel('星期', fontsize=12)
- plt.ylabel('总账单(美元)', fontsize=12)
- # 添加图例
- plt.legend(title='性别', title_fontsize=12, fontsize=10)
- # 调整布局
- plt.tight_layout()
- plt.show()
- # 创建热力图
- plt.figure(figsize=(12, 8))
- corr = tips.corr()
- heatmap = sns.heatmap(
- corr, annot=True, fmt=".2f",
- cmap='coolwarm', vmin=-1, vmax=1,
- linewidths=0.5, cbar_kws={"shrink": 0.8}
- )
- # 添加标题
- plt.title('变量相关性热力图', fontsize=16, pad=20)
- # 调整布局
- plt.tight_layout()
- plt.show()
复制代码
复杂图表组合
有时我们需要在一个图表中组合多种类型的可视化:
- # 创建示例数据
- np.random.seed(42)
- dates = pd.date_range('20230101', periods=24, freq='M')
- df_combined = pd.DataFrame({
- '日期': dates,
- '销售额': np.random.randint(1000, 5000, 24),
- '成本': np.random.randint(500, 2500, 24),
- '利润': np.random.randint(200, 2000, 24),
- '客户数': np.random.randint(50, 200, 24)
- })
- df_combined.set_index('日期', inplace=True)
- # 创建组合图表
- fig, axes = plt.subplots(3, 1, figsize=(12, 15), sharex=True)
- # 第一个子图:销售额和成本折线图
- axes[0].plot(df_combined.index, df_combined['销售额'], marker='o', label='销售额', color='#1f77b4', linewidth=2)
- axes[0].plot(df_combined.index, df_combined['成本'], marker='s', label='成本', color='#ff7f0e', linewidth=2)
- axes[0].set_title('销售额与成本趋势', fontsize=14, pad=10)
- axes[0].set_ylabel('金额(元)', fontsize=12)
- axes[0].legend(loc='upper left')
- axes[0].grid(True, linestyle='--', alpha=0.7)
- # 第二个子图:利润柱状图
- axes[1].bar(df_combined.index, df_combined['利润'], color='#2ca02c', alpha=0.7)
- axes[1].set_title('利润趋势', fontsize=14, pad=10)
- axes[1].set_ylabel('利润(元)', fontsize=12)
- axes[1].grid(True, linestyle='--', alpha=0.7, axis='y')
- # 第三个子图:客户数折线图
- axes[2].plot(df_combined.index, df_combined['客户数'], marker='^', label='客户数', color='#d62728', linewidth=2)
- axes[2].set_title('客户数趋势', fontsize=14, pad=10)
- axes[2].set_ylabel('客户数', fontsize=12)
- axes[2].set_xlabel('日期', fontsize=12)
- axes[2].legend(loc='upper left')
- axes[2].grid(True, linestyle='--', alpha=0.7)
- # 设置x轴刻度
- axes[2].set_xticks(df_combined.index[::2])
- axes[2].set_xticklabels([f'{date.year}年{date.month}月' for date in df_combined.index[::2]], rotation=45)
- # 调整布局
- plt.tight_layout()
- plt.show()
复制代码
使用FacetGrid创建分面图
Seaborn的FacetGrid允许我们根据分类变量创建多个子图:
- # 创建示例数据
- np.random.seed(42)
- df_facet = pd.DataFrame({
- '产品': np.random.choice(['A', 'B', 'C'], 200),
- '地区': np.random.choice(['东部', '西部', '南部', '北部'], 200),
- '月份': np.random.choice(['1月', '2月', '3月', '4月', '5月', '6月'], 200),
- '销售额': np.random.randint(1000, 10000, 200),
- '利润': np.random.randint(100, 3000, 200)
- })
- # 创建分面图
- g = sns.FacetGrid(df_facet, col="地区", row="产品", margin_titles=True, height=4, aspect=1.2)
- g.map(sns.scatterplot, "销售额", "利润", alpha=0.7)
- # 添加标题
- g.fig.suptitle('不同地区和产品的销售额与利润关系', y=1.05, fontsize=16)
- # 调整布局
- plt.tight_layout()
- plt.show()
- # 创建更复杂的分面图
- g = sns.FacetGrid(df_facet, col="地区", hue="产品", height=5, aspect=1, col_wrap=2)
- g.map(sns.lineplot, "月份", "销售额", marker="o", ci=None)
- g.add_legend(title="产品")
- # 添加标题
- g.fig.suptitle('各地区不同产品的月度销售额趋势', y=1.05, fontsize=16)
- # 调整布局
- plt.tight_layout()
- plt.show()
复制代码
交互式可视化
使用Plotly创建交互式图表
Plotly是一个强大的交互式可视化库,可以创建美观且具有交互功能的图表:
- import plotly.express as px
- import plotly.graph_objects as go
- from plotly.subplots import make_subplots
- # 创建示例数据
- np.random.seed(42)
- df_plotly = pd.DataFrame({
- '日期': pd.date_range('20230101', periods=12, freq='M'),
- '产品A': np.random.randint(1000, 5000, 12),
- '产品B': np.random.randint(1500, 6000, 12),
- '产品C': np.random.randint(800, 4000, 12)
- })
- # 创建交互式折线图
- fig = px.line(
- df_plotly.melt(id_vars=['日期'], var_name='产品', value_name='销售额'),
- x='日期', y='销售额', color='产品',
- title='产品月度销售额趋势',
- labels={'销售额': '销售额(元)', '日期': '日期'},
- line_shape='linear'
- )
- # 更新布局
- fig.update_layout(
- title_font_size=20,
- title_x=0.5,
- xaxis_title_font_size=14,
- yaxis_title_font_size=14,
- legend_title_font_size=14,
- font=dict(family="SimHei", size=12),
- hovermode='x unified'
- )
- # 添加注释
- fig.add_annotation(
- x=df_plotly['日期'][5],
- y=df_plotly['产品A'][5],
- text="峰值",
- showarrow=True,
- arrowhead=2,
- arrowsize=1,
- arrowwidth=2,
- arrowcolor="#636363"
- )
- # 显示图表
- fig.show()
- # 创建交互式散点图
- np.random.seed(42)
- df_scatter = pd.DataFrame({
- 'X': np.random.randn(100),
- 'Y': np.random.randn(100),
- '类别': np.random.choice(['A', 'B', 'C'], 100),
- '大小': np.random.randint(10, 100, 100)
- })
- fig = px.scatter(
- df_scatter, x='X', y='Y',
- color='类别', size='大小',
- title='交互式散点图',
- labels={'X': 'X轴', 'Y': 'Y轴'},
- hover_data=['大小']
- )
- # 更新布局
- fig.update_layout(
- title_font_size=20,
- title_x=0.5,
- xaxis_title_font_size=14,
- yaxis_title_font_size=14,
- legend_title_font_size=14,
- font=dict(family="SimHei", size=12)
- )
- # 显示图表
- fig.show()
- # 创建交互式子图
- fig = make_subplots(
- rows=2, cols=2,
- subplot_titles=('销售额', '利润', '客户数', '市场份额'),
- specs=[[{"secondary_y": False}, {"secondary_y": False}],
- [{"secondary_y": False}, {"secondary_y": False}]]
- )
- # 添加子图
- fig.add_trace(
- go.Scatter(x=df_plotly['日期'], y=df_plotly['产品A'], name='产品A销售额'),
- row=1, col=1
- )
- fig.add_trace(
- go.Bar(x=df_plotly['日期'], y=df_plotly['产品B'], name='产品B利润'),
- row=1, col=2
- )
- fig.add_trace(
- go.Scatter(x=df_plotly['日期'], y=df_plotly['产品C'], name='产品C客户数'),
- row=2, col=1
- )
- fig.add_trace(
- go.Pie(labels=['产品A', '产品B', '产品C'],
- values=[df_plotly['产品A'].sum(), df_plotly['产品B'].sum(), df_plotly['产品C'].sum()],
- name="市场份额"),
- row=2, col=2
- )
- # 更新布局
- fig.update_layout(
- title_text="业务指标综合展示",
- title_font_size=20,
- title_x=0.5,
- font=dict(family="SimHei", size=12),
- showlegend=False,
- height=800
- )
- # 显示图表
- fig.show()
复制代码
使用Altair创建声明式可视化
Altair是一个基于Vega-Lite的声明式统计可视化库,语法简洁直观:
- # 安装altair:pip install altair
- import altair as alt
- # 创建示例数据
- np.random.seed(42)
- df_altair = pd.DataFrame({
- 'x': np.random.randn(100),
- 'y': np.random.randn(100),
- 'category': np.random.choice(['A', 'B', 'C'], 100)
- })
- # 创建散点图
- scatter = alt.Chart(df_altair).mark_circle(size=60).encode(
- x='x',
- y='y',
- color='category',
- tooltip=['x', 'y', 'category']
- ).properties(
- title='Altair散点图示例',
- width=600,
- height=400
- ).interactive()
- # 显示图表
- scatter
- # 创建更复杂的组合图表
- # 创建时间序列数据
- np.random.seed(42)
- dates = pd.date_range('20230101', periods=12, freq='M')
- df_time = pd.DataFrame({
- '日期': dates,
- '销售额': np.random.randint(1000, 5000, 12),
- '成本': np.random.randint(500, 2500, 12),
- '利润': np.random.randint(200, 2000, 12)
- })
- # 创建基础图表
- base = alt.Chart(df_time).encode(
- x=alt.X('日期:T', axis=alt.Axis(title='日期', format='%Y-%m'))
- )
- # 创建销售额折线图
- line = base.mark_line(color='steelblue').encode(
- y=alt.Y('销售额:Q', axis=alt.Axis(title='销售额(元)', titleColor='steelblue'))
- )
- # 创建成本柱状图
- bar = base.mark_bar(color='orange').encode(
- y=alt.Y('成本:Q', axis=alt.Axis(title='成本(元)', titleColor='orange'))
- )
- # 组合图表
- combined = alt.layer(line, bar).resolve_scale(
- y='independent'
- ).properties(
- title='销售额与成本对比',
- width=800,
- height=400
- )
- # 显示图表
- combined
复制代码
使用Bokeh创建交互式仪表板
Bokeh是一个强大的交互式可视化库,特别适合创建复杂的仪表板:
- # 安装bokeh:pip install bokeh
- from bokeh.plotting import figure, show
- from bokeh.models import ColumnDataSource, HoverTool, Div
- from bokeh.layouts import column, row
- from bokeh.io import output_notebook
- # 在Jupyter中显示
- output_notebook()
- # 创建示例数据
- np.random.seed(42)
- df_bokeh = pd.DataFrame({
- 'x': np.random.randn(100),
- 'y': np.random.randn(100),
- 'size': np.random.randint(5, 50, 100),
- 'color': np.random.choice(['red', 'green', 'blue'], 100)
- })
- # 转换为ColumnDataSource
- source = ColumnDataSource(df_bokeh)
- # 创建散点图
- p1 = figure(title="Bokeh散点图", width=500, height=400, tools="pan,wheel_zoom,box_zoom,reset,hover,save")
- p1.circle('x', 'y', size='size', color='color', alpha=0.6, source=source)
- # 添加悬停工具
- hover = HoverTool()
- hover.tooltips = [
- ("X值", "@x"),
- ("Y值", "@y"),
- ("大小", "@size"),
- ("颜色", "@color")
- ]
- p1.add_tools(hover)
- # 创建时间序列数据
- dates = pd.date_range('20230101', periods=12, freq='M')
- df_time = pd.DataFrame({
- '日期': dates,
- '销售额': np.random.randint(1000, 5000, 12),
- '成本': np.random.randint(500, 2500, 12)
- })
- # 转换为ColumnDataSource
- source_time = ColumnDataSource(df_time)
- # 创建折线图
- p2 = figure(title="Bokeh折线图", width=500, height=400, x_axis_type="datetime")
- p2.line('日期', '销售额', source=source_time, line_width=2, color="blue", legend_label="销售额")
- p2.line('日期', '成本', source=source_time, line_width=2, color="red", legend_label="成本")
- p2.legend.location = "top_left"
- # 添加标题
- title = Div(text="<h1>Bokeh交互式仪表板示例</h1>")
- # 创建布局
- layout = column(title, row(p1, p2))
- # 显示仪表板
- show(layout)
复制代码
报告生成与导出
使用Jupyter Notebook创建交互式报告
Jupyter Notebook是创建数据分析报告的理想工具,可以结合代码、文本和可视化:
- # 在Jupyter Notebook中,我们可以使用Markdown单元格添加标题和说明
- """
- # 销售数据分析报告
- ## 摘要
- 本报告分析了2023年上半年的销售数据,包括销售额、成本和利润等关键指标。
- ## 数据概览
- 首先,让我们查看数据的基本情况:
- """
- # 在代码单元格中显示数据
- print(df_time.head())
- # 继续使用Markdown单元格添加说明
- """
- ## 销售趋势分析
- 接下来,我们分析销售额和成本的趋势:
- """
- # 在代码单元格中创建可视化
- plt.figure(figsize=(12, 6))
- plt.plot(df_time['日期'], df_time['销售额'], marker='o', label='销售额')
- plt.plot(df_time['日期'], df_time['成本'], marker='s', label='成本')
- plt.title('销售额与成本趋势')
- plt.xlabel('日期')
- plt.ylabel('金额(元)')
- plt.legend()
- plt.grid(True)
- plt.show()
- # 继续使用Markdown单元格添加分析
- """
- ## 分析结论
- 从上图可以看出,销售额呈现上升趋势,而成本相对稳定,这表明公司的盈利能力在提升。
- """
复制代码
使用Pandas Profiling生成数据报告
Pandas Profiling可以快速生成数据概览报告:
- # 安装pandas-profiling:pip install pandas-profiling
- from pandas_profiling import ProfileReport
- # 创建示例数据
- np.random.seed(42)
- df_profile = pd.DataFrame({
- '年龄': np.random.randint(18, 65, 1000),
- '收入': np.random.normal(5000, 1500, 1000),
- '支出': np.random.normal(3000, 1000, 1000),
- '性别': np.random.choice(['男', '女'], 1000),
- '教育程度': np.random.choice(['高中', '本科', '硕士', '博士'], 1000),
- '地区': np.random.choice(['东部', '西部', '南部', '北部'], 1000)
- })
- # 生成报告
- profile = ProfileReport(df_profile, title="数据概览报告", explorative=True)
- # 显示报告(在Jupyter中)
- profile
- # 保存报告为HTML文件
- profile.to_file("data_profile_report.html")
复制代码
使用ReportLab创建PDF报告
ReportLab是一个强大的PDF生成库,可以创建专业的PDF报告:
- # 安装reportlab:pip install reportlab
- from reportlab.lib.pagesizes import letter, A4
- from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image
- from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
- from reportlab.lib.units import inch
- from reportlab.lib import colors
- from reportlab.graphics.shapes import Drawing
- from reportlab.graphics.charts.lineplots import LinePlot
- from reportlab.graphics.charts.barcharts import VerticalBarChart
- from reportlab.graphics.widgets.markers import makeMarker
- import io
- import matplotlib.pyplot as plt
- # 创建PDF文档
- doc = SimpleDocTemplate("sales_report.pdf", pagesize=A4)
- styles = getSampleStyleSheet()
- story = []
- # 添加标题
- title_style = ParagraphStyle(
- 'CustomTitle',
- parent=styles['Heading1'],
- fontSize=24,
- spaceAfter=30,
- alignment=1 # 居中
- )
- story.append(Paragraph("销售数据分析报告", title_style))
- story.append(Spacer(1, 12))
- # 添加摘要
- story.append(Paragraph("摘要", styles['Heading2']))
- story.append(Paragraph("本报告分析了2023年上半年的销售数据,包括销售额、成本和利润等关键指标。", styles['Normal']))
- story.append(Spacer(1, 12))
- # 添加数据表格
- story.append(Paragraph("数据概览", styles['Heading2']))
- # 准备表格数据
- table_data = [['日期', '销售额', '成本', '利润']]
- for i in range(min(5, len(df_time))):
- table_data.append([
- df_time['日期'].iloc[i].strftime('%Y-%m-%d'),
- f"{df_time['销售额'].iloc[i]:,.0f}",
- f"{df_time['成本'].iloc[i]:,.0f}",
- f"{df_time['利润'].iloc[i]:,.0f}"
- ])
- # 创建表格
- table = Table(table_data)
- table.setStyle(TableStyle([
- ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
- ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
- ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
- ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
- ('FONTSIZE', (0, 0), (-1, 0), 14),
- ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
- ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
- ('GRID', (0, 0), (-1, -1), 1, colors.black)
- ]))
- story.append(table)
- story.append(Spacer(1, 12))
- # 添加图表
- story.append(Paragraph("销售趋势分析", styles['Heading2']))
- # 创建Matplotlib图表
- plt.figure(figsize=(8, 4))
- plt.plot(df_time['日期'], df_time['销售额'], marker='o', label='销售额')
- plt.plot(df_time['日期'], df_time['成本'], marker='s', label='成本')
- plt.title('销售额与成本趋势')
- plt.xlabel('日期')
- plt.ylabel('金额(元)')
- plt.legend()
- plt.grid(True)
- # 保存图表到内存
- img_buffer = io.BytesIO()
- plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
- plt.close()
- img_buffer.seek(0)
- # 添加图表到PDF
- story.append(Image(img_buffer, width=6*inch, height=3*inch))
- story.append(Spacer(1, 12))
- # 添加结论
- story.append(Paragraph("分析结论", styles['Heading2']))
- story.append(Paragraph("从上图可以看出,销售额呈现上升趋势,而成本相对稳定,这表明公司的盈利能力在提升。", styles['Normal']))
- story.append(Spacer(1, 12))
- # 生成PDF
- doc.build(story)
复制代码
使用Dash创建交互式Web应用
Dash是一个基于Flask、React和Plotly的框架,用于创建交互式Web应用:
- # 安装dash:pip install dash
- import dash
- from dash import dcc, html, Input, Output
- import plotly.express as px
- # 创建示例数据
- np.random.seed(42)
- df_dash = pd.DataFrame({
- '日期': pd.date_range('20230101', periods=12, freq='M'),
- '产品A': np.random.randint(1000, 5000, 12),
- '产品B': np.random.randint(1500, 6000, 12),
- '产品C': np.random.randint(800, 4000, 12)
- })
- # 初始化Dash应用
- app = dash.Dash(__name__)
- # 定义应用布局
- app.layout = html.Div([
- html.H1("销售数据分析仪表板", style={'textAlign': 'center'}),
-
- html.Div([
- html.Label("选择产品:"),
- dcc.Dropdown(
- id='product-dropdown',
- options=[
- {'label': '产品A', 'value': '产品A'},
- {'label': '产品B', 'value': '产品B'},
- {'label': '产品C', 'value': '产品C'}
- ],
- value='产品A',
- multi=True
- )
- ], style={'width': '48%', 'display': 'inline-block'}),
-
- html.Div([
- html.Label("选择图表类型:"),
- dcc.RadioItems(
- id='chart-type',
- options=[
- {'label': '折线图', 'value': 'line'},
- {'label': '柱状图', 'value': 'bar'}
- ],
- value='line',
- labelStyle={'display': 'inline-block'}
- )
- ], style={'width': '48%', 'float': 'right', 'display': 'inline-block'}),
-
- dcc.Graph(id='sales-chart'),
-
- html.Div([
- html.H3("数据表格"),
- html.Table(id='data-table')
- ])
- ])
- # 定义回调函数
- @app.callback(
- [Output('sales-chart', 'figure'),
- Output('data-table', 'children')],
- [Input('product-dropdown', 'value'),
- Input('chart-type', 'value')]
- )
- def update_chart(selected_products, chart_type):
- if not selected_products:
- selected_products = ['产品A']
-
- # 准备图表数据
- df_chart = df_dash[['日期'] + selected_products].melt(id_vars=['日期'], var_name='产品', value_name='销售额')
-
- # 创建图表
- if chart_type == 'line':
- fig = px.line(df_chart, x='日期', y='销售额', color='产品', title='产品销售趋势')
- else:
- fig = px.bar(df_chart, x='日期', y='销售额', color='产品', title='产品销售对比')
-
- # 准备表格数据
- table_header = [html.Thead(html.Tr([html.Th(col) for col in ['日期'] + selected_products]))]
- table_body = [html.Tbody([
- html.Tr([
- html.Td(df_dash['日期'].iloc[i].strftime('%Y-%m-%d'))
- ] + [html.Td(f"{df_dash[product].iloc[i]:,.0f}") for product in selected_products])
- for i in range(len(df_dash))
- ])]
-
- return fig, table_header + table_body
- # 运行应用
- if __name__ == '__main__':
- app.run_server(debug=True)
复制代码
实战案例:完整的数据分析报告美化流程
让我们通过一个完整的案例,展示如何从原始数据到专业报告的全过程:
- # 步骤1:数据准备和清洗
- import pandas as pd
- import numpy as np
- import matplotlib.pyplot as plt
- import seaborn as sns
- import plotly.express as px
- from datetime import datetime, timedelta
- # 创建模拟销售数据
- np.random.seed(42)
- start_date = datetime(2023, 1, 1)
- dates = [start_date + timedelta(days=i) for i in range(365)]
- # 创建基础数据
- df_sales = pd.DataFrame({
- '日期': dates,
- '产品': np.random.choice(['A', 'B', 'C', 'D'], 365),
- '地区': np.random.choice(['东部', '西部', '南部', '北部'], 365),
- '渠道': np.random.choice(['线上', '线下'], 365),
- '销售量': np.random.randint(10, 200, 365),
- '单价': np.random.uniform(10, 100, 365)
- })
- # 计算销售额
- df_sales['销售额'] = df_sales['销售量'] * df_sales['单价']
- # 添加季节性因素
- df_sales['月份'] = df_sales['日期'].dt.month
- seasonal_factor = pd.DataFrame({
- '月份': range(1, 13),
- '季节性因子': [0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.3, 1.2, 1.1, 0.9, 0.8]
- })
- df_sales = df_sales.merge(seasonal_factor, on='月份')
- df_sales['销售额'] = df_sales['销售额'] * df_sales['季节性因子']
- # 添加成本和利润
- df_sales['成本'] = df_sales['销售额'] * np.random.uniform(0.4, 0.7, 365)
- df_sales['利润'] = df_sales['销售额'] - df_sales['成本']
- # 步骤2:数据分析和聚合
- # 按月份聚合
- df_monthly = df_sales.groupby(df_sales['日期'].dt.to_period('M')).agg({
- '销售额': 'sum',
- '成本': 'sum',
- '利润': 'sum',
- '销售量': 'sum'
- }).reset_index()
- df_monthly['日期'] = df_monthly['日期'].dt.to_timestamp()
- # 按产品和地区聚合
- df_product_region = df_sales.groupby(['产品', '地区']).agg({
- '销售额': 'sum',
- '利润': 'sum'
- }).reset_index()
- # 按渠道聚合
- df_channel = df_sales.groupby('渠道').agg({
- '销售额': 'sum',
- '利润': 'sum',
- '销售量': 'sum'
- }).reset_index()
- # 步骤3:创建可视化图表
- # 设置中文字体
- plt.rcParams['font.sans-serif'] = ['SimHei']
- plt.rcParams['axes.unicode_minus'] = False
- # 创建月度趋势图
- plt.figure(figsize=(12, 6))
- plt.plot(df_monthly['日期'], df_monthly['销售额'], marker='o', label='销售额', linewidth=2)
- plt.plot(df_monthly['日期'], df_monthly['成本'], marker='s', label='成本', linewidth=2)
- plt.plot(df_monthly['日期'], df_monthly['利润'], marker='^', label='利润', linewidth=2)
- plt.title('2023年月度销售趋势', fontsize=16)
- plt.xlabel('月份', fontsize=12)
- plt.ylabel('金额(元)', fontsize=12)
- plt.grid(True, linestyle='--', alpha=0.7)
- plt.legend(fontsize=12)
- plt.xticks(df_monthly['日期'], [f'{date.month}月' for date in df_monthly['日期']], rotation=45)
- plt.tight_layout()
- plt.savefig('monthly_trend.png', dpi=300, bbox_inches='tight')
- plt.close()
- # 创建产品和地区热力图
- pivot_table = df_product_region.pivot(index='产品', columns='地区', values='销售额')
- plt.figure(figsize=(10, 8))
- sns.heatmap(pivot_table, annot=True, fmt='.0f', cmap='YlGnBu', linewidths=0.5)
- plt.title('各产品在不同地区的销售额', fontsize=16)
- plt.xlabel('地区', fontsize=12)
- plt.ylabel('产品', fontsize=12)
- plt.tight_layout()
- plt.savefig('product_region_heatmap.png', dpi=300, bbox_inches='tight')
- plt.close()
- # 创建渠道对比图
- fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
- # 销售额对比
- ax1.bar(df_channel['渠道'], df_channel['销售额'], color=['#1f77b4', '#ff7f0e'])
- ax1.set_title('不同渠道的销售额对比', fontsize=14)
- ax1.set_ylabel('销售额(元)', fontsize=12)
- ax1.grid(True, axis='y', linestyle='--', alpha=0.7)
- # 利润率对比
- df_channel['利润率'] = df_channel['利润'] / df_channel['销售额'] * 100
- ax2.bar(df_channel['渠道'], df_channel['利润率'], color=['#2ca02c', '#d62728'])
- ax2.set_title('不同渠道的利润率对比', fontsize=14)
- ax2.set_ylabel('利润率(%)', fontsize=12)
- ax2.grid(True, axis='y', linestyle='--', alpha=0.7)
- plt.tight_layout()
- plt.savefig('channel_comparison.png', dpi=300, bbox_inches='tight')
- plt.close()
- # 步骤4:创建交互式图表
- # 创建交互式月度趋势图
- fig_monthly = px.line(
- df_monthly, x='日期', y=['销售额', '成本', '利润'],
- title='2023年月度销售趋势(交互式)',
- labels={'value': '金额(元)', 'variable': '指标'},
- line_shape='linear'
- )
- fig_monthly.update_layout(
- title_font_size=16,
- legend_title_font_size=12,
- font=dict(family="SimHei", size=12),
- hovermode='x unified'
- )
- fig_monthly.write_html('monthly_trend_interactive.html')
- # 创建交互式产品和地区图表
- fig_product_region = px.bar(
- df_product_region, x='地区', y='销售额', color='产品',
- title='各产品在不同地区的销售额(交互式)',
- labels={'销售额': '销售额(元)'},
- barmode='group'
- )
- fig_product_region.update_layout(
- title_font_size=16,
- legend_title_font_size=12,
- font=dict(family="SimHei", size=12)
- )
- fig_product_region.write_html('product_region_interactive.html')
- # 步骤5:创建样式化表格
- # 创建月度数据样式化表格
- styled_monthly = df_monthly.style.set_caption('2023年月度销售数据').format({
- '销售额': '¥{:,.2f}',
- '成本': '¥{:,.2f}',
- '利润': '¥{:,.2f}',
- '销售量': '{:,}'
- }).background_gradient(cmap='Blues', subset=['销售额', '利润']).bar(
- subset=['利润'], align='mid', color=['#d65f5f', '#5fba7d']
- ).set_table_styles([
- {'selector': 'th', 'props': [('background-color', '#40466e'), ('color', 'white'), ('font-weight', 'bold')]},
- {'selector': 'td', 'props': [('text-align', 'center')]},
- {'selector': 'caption', 'props': [('caption-side', 'top'), ('font-size', '16pt'), ('font-weight', 'bold')]}
- ])
- # 保存样式化表格为HTML
- with open('monthly_data_styled.html', 'w', encoding='utf-8') as f:
- f.write(styled_monthly.to_html())
- # 步骤6:生成完整报告
- # 创建HTML报告
- html_report = """
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>2023年销售数据分析报告</title>
- <style>
- body {
- font-family: Arial, sans-serif;
- line-height: 1.6;
- margin: 0;
- padding: 20px;
- color: #333;
- }
- .container {
- max-width: 1200px;
- margin: 0 auto;
- padding: 20px;
- background-color: #f9f9f9;
- border-radius: 10px;
- box-shadow: 0 0 10px rgba(0,0,0,0.1);
- }
- h1 {
- color: #2c3e50;
- text-align: center;
- margin-bottom: 30px;
- }
- h2 {
- color: #3498db;
- border-bottom: 2px solid #3498db;
- padding-bottom: 10px;
- }
- .chart-container {
- margin: 20px 0;
- text-align: center;
- }
- .chart-container img {
- max-width: 100%;
- height: auto;
- border: 1px solid #ddd;
- border-radius: 5px;
- }
- .table-container {
- margin: 20px 0;
- overflow-x: auto;
- }
- .conclusion {
- background-color: #e8f4fc;
- padding: 15px;
- border-radius: 5px;
- margin: 20px 0;
- }
- .interactive-chart {
- margin: 20px 0;
- height: 500px;
- }
- </style>
- </head>
- <body>
- <div class="container">
- <h1>2023年销售数据分析报告</h1>
-
- <h2>1. 执行摘要</h2>
- <p>本报告分析了2023年全年的销售数据,包括销售额、成本、利润等关键指标。通过对数据的深入分析,我们发现了一些重要的趋势和模式,这些发现将有助于制定未来的销售策略。</p>
-
- <h2>2. 月度销售趋势</h2>
- <div class="chart-container">
- <img src="monthly_trend.png" alt="月度销售趋势">
- </div>
- <p>从上图可以看出,销售额在年中达到峰值,这可能与季节性因素有关。成本相对稳定,而利润随着销售额的增加而增加。</p>
-
- <div class="interactive-chart">
- <iframe src="monthly_trend_interactive.html" width="100%" height="100%" frameborder="0"></iframe>
- </div>
-
- <h2>3. 产品和地区分析</h2>
- <div class="chart-container">
- <img src="product_region_heatmap.png" alt="产品和地区热力图">
- </div>
- <p>热力图显示了各产品在不同地区的销售额表现。可以看出,产品A在东部地区的销售额最高,而产品C在北部地区表现最佳。</p>
-
- <div class="interactive-chart">
- <iframe src="product_region_interactive.html" width="100%" height="100%" frameborder="0"></iframe>
- </div>
-
- <h2>4. 渠道对比</h2>
- <div class="chart-container">
- <img src="channel_comparison.png" alt="渠道对比">
- </div>
- <p>从渠道对比图可以看出,线上渠道的销售额高于线下渠道,但线下渠道的利润率更高。这表明线下渠道虽然销售额较低,但盈利能力更强。</p>
-
- <h2>5. 详细数据</h2>
- <div class="table-container">
- <iframe src="monthly_data_styled.html" width="100%" height="400px" frameborder="0"></iframe>
- </div>
-
- <h2>6. 结论和建议</h2>
- <div class="conclusion">
- <h3>主要发现:</h3>
- <ul>
- <li>销售额呈现明显的季节性波动,年中达到峰值</li>
- <li>产品A在东部地区表现最佳,应加大在该地区的推广力度</li>
- <li>线下渠道虽然销售额较低,但利润率更高,值得进一步投资</li>
- </ul>
-
- <h3>建议:</h3>
- <ul>
- <li>在销售淡季推出促销活动,以平衡季节性波动</li>
- <li>针对不同地区制定差异化的产品策略</li>
- <li>优化线下渠道运营,提高销售额</li>
- </ul>
- </div>
- </div>
- </body>
- </html>
- """
- # 保存HTML报告
- with open('sales_analysis_report.html', 'w', encoding='utf-8') as f:
- f.write(html_report)
- print("报告生成完成!")
复制代码
总结:提升职场竞争力的关键点
通过本文的学习,我们掌握了从基础表格到专业展示的数据可视化全流程。这些技能不仅能提升数据分析报告的专业度,还能在职场中带来显著的竞争优势:
1. 数据呈现的专业性:掌握Pandas美化输出技巧,可以让你的数据分析报告看起来更加专业,给同事和领导留下深刻印象。
2. 信息传达的效率:良好的数据可视化能够更高效地传达信息,帮助决策者快速理解数据背后的含义,从而做出更明智的决策。
3. 故事讲述的能力:通过精心设计的图表和报告,你可以将枯燥的数据转化为引人入胜的故事,增强报告的说服力和影响力。
4. 技术栈的完整性:掌握从Pandas基础表格到交互式可视化的全流程,展示了你作为数据分析师或数据科学家的全面技能。
5. 自动化报告生成:学会使用工具自动生成报告,可以大大提高工作效率,让你有更多时间专注于数据分析和洞察。
数据呈现的专业性:掌握Pandas美化输出技巧,可以让你的数据分析报告看起来更加专业,给同事和领导留下深刻印象。
信息传达的效率:良好的数据可视化能够更高效地传达信息,帮助决策者快速理解数据背后的含义,从而做出更明智的决策。
故事讲述的能力:通过精心设计的图表和报告,你可以将枯燥的数据转化为引人入胜的故事,增强报告的说服力和影响力。
技术栈的完整性:掌握从Pandas基础表格到交互式可视化的全流程,展示了你作为数据分析师或数据科学家的全面技能。
自动化报告生成:学会使用工具自动生成报告,可以大大提高工作效率,让你有更多时间专注于数据分析和洞察。
在实际工作中,建议你根据具体需求选择合适的技术和工具。对于简单的日常分析,Pandas的基础样式和Matplotlib可能就足够了;而对于重要的客户报告或管理层汇报,可以考虑使用Plotly或Dash创建交互式可视化;如果需要定期生成标准化报告,可以探索自动化报告生成的解决方案。
记住,好的数据可视化不仅是技术的展示,更是沟通的艺术。通过不断实践和学习,你将能够创建出既美观又有效的数据可视化作品,从而在职场中脱颖而出。 |
|