简介:课件围绕宏观经济学中“经济增长与经济周期”核心章节制作,面向经济学专业学生、考研备考生以及高校教师,既可用于课堂演示,也适合自主学习与考前梳理。资源共 1 个 PPTX 文件,压缩包大小约 342KB,内容以图文结合的方式呈现,结构清晰、重点突出,方便读者直接播放或按章节翻阅。
课件从经济周期的含义与繁荣、衰退、萧条、复苏四个阶段的特点入手,重点讲解实际 GDP、工业生产指数、就业率等衡量指标,并梳理基钦周期、朱格拉周期、康德拉季耶夫周期、熊彼特周期和库兹涅茨周期的不同时间尺度与划分依据。成因部分涵盖消费不足理论、投资过度论、货币因素论、心理周期理论、有效需求不足理论、创新理论与政治周期理论,最后引入乘数—加速数原理,结合美国经济波动、改革开放以来中国经济周期特点等图表数据,帮助读者从理论模型过渡到现实经济现象的理解。
目前已有 106 人学习,适合经济学基础课程配套使用,也能为后续宏观经济学专题研究提供框架性参考。
1. 把“经济增长与经济周期”做成PPT课件时,先弄明白三件事
像“第十三章经济增长与经济周期PPT课件.pptx”这样的文件名,在单位素材库、培训目录和内部知识管理系统里反复出现。它表面上是现成的教学材料,实际结构却比普通文档复杂:有标题文本,有统计表格,有嵌入的增长曲线图,图表背后还挂着一个Excel缓存工作簿。课件维护时最常见的翻车,是拿现成的幻灯片手动改数字,改完文字忘了改图,或者改了图数据没刷新,最后留下一套注释和数据对不上的“半成品”。更麻烦的是,这类课件往往按季度更新,新数据一到就要重新生成,所以处理它不能停留在“打开PPT改两页”的层面。
真正能长期用的做法,是把文字、图表、数据缓存当成一个整体来处理,用脚本拆包、提取、重绘、回写、体检。这样每次更新不是从零开始改版式,而是跑一遍固定流程,把人工校验集中在最后几十秒。后面章节按这条路径展开:先看压缩包内部结构,再把课件里的增长数据提出来,接着把新数据画成图并批量替换,最后在交付前做一轮技术检查。整个过程围绕Python生态里常用的几个库就能完成,不需要依赖完整安装的Office组件。
2. 拆开经济增长与经济周期课件:从pptx压缩包里取出图表与数据结构
PPTX的本质是Open XML压缩包,而不是普通文件夹。“第十三章经济增长与经济周期PPT课件.pptx”整个文件就是一个zip归档,所有文字、图片、图表和关系引用都以XML或二进制资源的形式存在固定路径下。文本写在ppt/slides/slideN.xml里,图表定义写在ppt/charts/chartN.xml里,图表引用的缓存数据放在ppt/embeddings/下,图片素材则散落在ppt/media/。
| 路径前缀 | 存放内容 | 处理工具 |
|---|---|---|
| ppt/slides/ | 每页正文、版式引用、形状树 | python-pptx / lxml |
| ppt/charts/ | 图表类型定义、类别与系列引用 | lxml 手工解析 |
| ppt/embeddings/ | 图表缓存用的Excel工作簿 | zipfile + pandas |
| ppt/media/ | 位图、矢量图、音频素材 | 单独提取做文件识别 |
先扫一遍包结构,后面提取、替换、重打包时就有了地图。用标准库zipfile就能完成这一步。
import zipfile path = "第十三章经济增长与经济周期PPT课件.pptx" with zipfile.ZipFile(path, "r") as z: for name in z.namelist(): print(name)这段代码把压缩包内的所有条目路径打印出来,重点看有没有ppt/slides/、ppt/charts/、ppt/embeddings/这几个前缀。zipfile不解析内容,只列文件名,所以执行速度极快。如果Windows控制台出现乱码,通常是控制台代码页不是UTF-8,改用PowerShell执行即可,不需要改代码。
2.1 从slide XML与python-pptx两条路径选工具
拆包之后,接下来是从每一页里取正文和图形清单。这里有个工具选择问题:直接用lxml解析slideN.xml可以拿到最原始的结构,但对形状类型、表格嵌套、图表占位符的判断要写很多分支;用python-pptx做高层封装则省事得多。常见做法是优先用python-pptx,只有遇到它没有暴露的属性时才退回lxml。
from pptx import Presentation from pptx.enum.shapes import MSO_SHAPE_TYPE prs = Presentation(path) for idx, slide in enumerate(prs.slides, 1): print(f"--- 第{idx}页 ---") for shape in slide.shapes: if shape.has_text_frame: text = "".join(run.text for para in shape.text_frame.paragraphs for run in para.runs).strip() if text: print(f"文本: {text[:60]}") elif shape.has_table: table = shape.table print(f"表格: {len(table.rows)}行 x {len(table.columns)}列") if shape.shape_type == MSO_SHAPE_TYPE.PICTURE: print(f"图片: {shape.name}")代码逻辑按形状类型做分支:has_text_frame判断文本框,has_table判断表格,shape_type判断图片。text切片到60个字符,避免控制台被整页定义挤满。这个清单导出来后,就能知道哪些页是概念说明、哪些页是数据图表,后续替换时可以直接按文本定位目标页。
2.2 课件里的增长曲线数据:图表对象和在XML中的位置
第13章课件里通常至少有一张增长曲线图、一张经济周期示意图。如果这两张图是用演示文稿原生图表功能做的,就可以用python-pptx把数据读出来。判断条件很简单:形状对象里有没有chart属性。
for shape in slide.shapes: if shape.has_chart: chart = shape.chart print("图表类型:", chart.chart_type) plot = chart.plots[0] print("分类轴:", tuple(plot.categories)[:20]) for series in plot.series: print("系列名:", series.name) print("数值:", tuple(series.values))这里的plots[0]取的是第一个绘图区。大多数单类型图表只有一个绘图区,plot.categories返回年份或季度文本,series.values对应每个时期的数值。分类轴和数值个数必须一致;如果不一致,说明图表里藏了辅助序列,这个时候不能直接替换数据,要先搞清楚辅助序列是什么。
2.3 图表缓存Excel直接按数取用
课件里嵌入的Excel工作簿往往是原始数据最全的地方,图表里展示的只是其中一部分。从压缩包里把缓存表提出来,用pandas读,比依赖图表XML更稳。
import zipfile import io import pandas as pd def read_embed_xlsx(pptx_path): with zipfile.ZipFile(pptx_path) as z: embeds = [ n for n in z.namelist() if n.startswith("ppt/embeddings/") and n.endswith((".xlsx", ".xls")) ] if not embeds: print("未发现嵌入工作簿") return None print("找到嵌入表:", embeds) raw = z.read(embeds[0]) return pd.read_excel(io.BytesIO(raw), header=None) sheet = read_embed_xlsx(path) if sheet is not None: print(sheet.head(12))代码逻辑是枚举ppt/embeddings/下的Excel文件,取第一个作为缓存表,读成pandas DataFrame。read_excel里显式传header=None,是因为缓存表经常是裸数据,第一行是年份而不是列名;如果让pandas自动把第一行当表头,年份值就变成了列名,后续没法用。embed列表里如果同时存在多个工作簿,要按chart XML里的引用编号去对,不能简单取第一个。
提示:嵌入Excel的读取只对“用原生图表插入的幻灯片”有效。如果作者把第三方统计软件画的图直接贴成图片,数据不会存在缓存里,只能按图片处理或手工重建序列。
3. 给经济周期课件补一组可复用的增长曲线
上一章把课件里原有数据拿了出来,这一章解决更核心的问题:当课件里的图不够用、或者数据已经过时,需要用外部数据重新绘图并回写进去。做这一步前,先把经济学口径对齐,否则图画出来会和教案讲的对不上。
3.1 先对表:复苏、繁荣、衰退、萧条在数据里是什么样子
经济周期课件里的阶段判断不能只看同比增速符号。比如某季度GDP同比从3.6%降到2.9%,课件里通常标成“增速回落”,不是“衰退”。所以画图前要定一个能翻译成代码的阶段口径。
| 周期阶段 | 典型的季度数据特征 | 课件里的对应表述 |
|---|---|---|
| 复苏 | 绝对水平止跌回升,增速由负转正 | 经济开始回暖 |
| 繁荣 | 增速持续上行,或产出缺口为正 | 经济偏向过热 |
| 衰退 | 增速从高点连续回落,仍可能高于0 | 经济增速放缓 |
| 萧条 | 增速转负,或GDP绝对水平下降 | 经济收缩 |
这个表的用途是把概念阶段映射成可写进图表代码的数据条件。实际做图时,不一定要把“衰退”“萧条”字样直接标在图上,而是用浅灰底色把特定区段标出来,让读者自己对应文字表述。阴影区间用matplotlib的axvspan就能实现。
3.2 用Hodrick-Prescott滤波拆出趋势与周期
要在一张图里同时体现“增长趋势”和“周期波动”,最常用的办法是Hodrick-Prescott滤波,也就是HP滤波。季度数据lambda取1600,年度取100,月度取14400。这个滤波的原理可以一句话讲清:在“趋势线尽量平滑”和“趋势线尽量贴合原序列”之间做一个带权重的折中,lambda就是那个权重。
import numpy as np import matplotlib.pyplot as plt def hp_filter(y, lamb=1600): y = np.asarray(y, dtype=float) T = len(y) I = np.eye(T) D = np.zeros((T - 2, T)) for i in range(T - 2): D[i, i] = 1 D[i, i + 1] = -2 D[i, i + 2] = 1 trend = np.linalg.solve(I + lamb * D.T @ D, y) return trend gdp_yoy = np.array([7.9, 7.1, 6.3, 5.8, 6.9, 7.5, 8.2, 7.8, 6.1, 4.9, 3.8, 2.1, 1.8, 4.5]) trend = hp_filter(gdp_yoy, lamb=1600) x = np.arange(len(gdp_yoy)) fig, ax = plt.subplots(figsize=(10, 5.5)) ax.plot(x, gdp_yoy, label="实际GDP同比增速", marker="o") ax.plot(x, trend, label="趋势增速", linestyle="--", color="gray") ax.axhline(0, color="black", linewidth=0.7) ax.set_xticks(x) ax.legend() plt.tight_layout()代码逻辑是先构造二阶差分矩阵D,把“趋势不平滑”的惩罚项写成二次型,然后解一个线性方程组。不用np.linalg.inv而用np.linalg.solve,是因为直接求逆在序列较长时数值稳定性差。lambda是唯一需要调整的参数:季度数据用1600,年度数据用100,月度数据用14400。lambda越大,趋势线越平滑,周期成分波动越明显;在做课件演示时不要随意改这个值,否则图上的“周期”可能是滤波参数带来的假象。
运行后得到两条线:实际增速和趋势增速,两者之差就是周期成分。课件里常说的“产出缺口为正”对应实际增速持续高于趋势增速的区段。这副图的数据范围只有14期,在课件讲解里够用;如果要做严谨分析,建议至少用16期以上季度数据,T太小时D矩阵的行数过少,滤波结果在首尾两端会明显失真。
3.3 把PNG插入目标页并控制位置与宽度
画好的图要放进具体某一页幻灯片。常见错误是写死页码,比如prs.slides[3],但课件改了版式后页码就漂了。更稳的做法是按文本特征定位目标页,比如找包含“经济增长”四个字的幻灯片。
from pptx import Presentation from pptx.util import Inches import io prs = Presentation(path) target = None for slide in prs.slides: for shape in slide.shapes: if shape.has_text_frame and "经济增长" in shape.text_frame.text: target = slide break if target is not None: break if target is None: raise RuntimeError("未找到目标页,请核对关键字") buf = io.BytesIO() fig.savefig(buf, format="png", dpi=200, bbox_inches="tight") buf.seek(0) target.shapes.add_picture(buf, Inches(0.5), Inches(1.6), width=Inches(9)) prs.save("第十三章经济增长与经济周期PPT课件_v2.pptx")代码逻辑是先在所有页里找到包含“经济增长”文本的第一张slide,再从内存里把PNG加进去。add_picture的第二个和第三个参数分别是左上角横纵坐标,第四个参数指定宽度,高度按图片比例自动计算。dpi=200保证文字在投影时不发虚;bbox_inches="tight"裁掉大片空白;width=Inches(9)适合16:9版心,如果原课件是4:3,改成7.5左右更安全。top避开标题区是1.4到1.8英寸之间,具体数值按原版式调整。
提示:这样插入的新图是独立图片,不会继承原课件图表的绘图区配色。如果希望新图和模板风格一致,用matplotlib设置与模板相同的主题色,标题用深蓝、网格线用浅灰,比插入后再调PPT更省事。
4. 季度数据更新后,用脚本批量重出第13章课件
课件维护的常态不是“画一次就好”,而是每个季度拿到新数据后再生成一份。只要上一章的绘图和插入逻辑固定下来,这次更新就只剩三步:读取数据、计算口径、替换图表。下面把完整流程写成一个可重复执行的脚本骨架。
4.1 从CSV读入季度序列并计算同比
数据源不管是金融终端导出的Excel,还是内部研究部门的台账,先统一另存成带统一编码的CSV,字段至少包含date和gdp_value两列。读入后要计算同比,因为第13章课件里展示的口径大多数是“同比增速”,而不是环比。
import pandas as pd df = pd.read_csv("macro_data.csv", encoding="utf-8") df["date"] = pd.to_datetime(df["date"]) df.sort_values("date", inplace=True) df["gdp_yoy"] = df["gdp_value"].pct_change(4) * 100 print(df.tail(12))代码里pct_change(4)表示用本期数值除以上一期对应数值再减1,对季度数据来说,差4期正好就是去年同期。月度数据要改成pct_change(12),这个参数最容易错,用错后曲线会呈现奇怪的锯齿。encoding="utf-8"解决从Windows导出的CSV默认GBK编码带来的中文乱码。sort_values保证时间顺序正确,CSV文件如果本身是倒序,不排序计算出来的同比全是错的。
4.2 用replace_data更新已有图表,而不是删掉重建
更新原有图表比新增一张图更讲方法。若把原图表删除再插新图,图表自带的数据标签、坐标轴单位、配色和动画全部丢失,工作量大且容易改出风格不统一。正确做法是在原chart对象上调用replace_data。
from pptx import Presentation from pptx.chart.data import CategoryChartData prs = Presentation("第十三章经济增长与经济周期PPT课件.pptx") slide = prs.slides[3] # 先按上一章文本匹配定位,这里为示例直接写页码 for shape in slide.shapes: if shape.has_chart: old = shape.chart data = CategoryChartData() data.categories = [d.strftime("%Y-%m") for d in df["date"].tail(16)] data.add_series("实际GDP同比", tuple(df["gdp_yoy"].tail(16).round(2))) old.replace_data(data) break prs.save("第十三章经济增长与经济周期PPT课件_更新.pptx")replace_data会重建图表内部的数据缓存,所以旧系列会被清空。如果原图有多条系列,比如“同比增速”和“趋势增速”两条线,就要按相同顺序逐个add_series,系列顺序反了会让图例会串。tail(16)取最近16个季度,正好覆盖横轴4年跨度;如果原课件横轴是5年,要改成tail(20)。round(2)把数值显示统一到两位小数,避免图表上出现一长串小数位。
4.3 替换前的长度与口径校验
替换前先做一道检查,防止硬伤数据进入课件。最常见的问题是序列长度不够,或者最新一期数值和权威发布的口径对不上。可以在脚本里加一个显式的校验块。
expected_len = 16 if len(df) < expected_len: raise ValueError( f"序列长度不足,当前{len(df)}期,至少需要{expected_len}期" ) last_val = df["gdp_yoy"].iloc[-1].round(1) print(f"最近一期同比增速: {last_val}%")如果序列长度不够就立刻报错,避免run完生成一个短一截的图,横轴尾部缺一块。print输出最近一期增速是给人工复核用的,发布前要和权威数据来源做一次核对,不能只信任脚本计算。这个校验块不replace,但它保住了后续两个动作的前提。
5. 课件交付前做一轮体检:XML、字体、动画与越界
数据替换完成后,直接双击打开可能一切正常,也可能弹“发现不可读取的内容”。与其到发布前才被提示,不如把检查脚本固化下来,在保存后立即跑一遍。最基础的检查是形状越界,也就是某些元素跑到画布外面去了,这种问题肉眼不容易看全。
from pptx import Presentation def check_out_of_slide(pptx_path): prs = Presentation(pptx_path) for i, slide in enumerate(prs.slides, 1): W, H = prs.slide_width, prs.slide_height for shape in slide.shapes: if shape.left < 0 or shape.top < 0: print(f"第{i}页: {shape.name} 越界(负坐标)") if shape.left + shape.width > W or shape.top + shape.height > H: print(f"第{i}页: {shape.name} 超出画布右侧或下侧") check_out_of_slide("第十三章经济增长与经济周期PPT课件_更新.pptx")遍历每个形状,判断左右上下四个边界。PPTX的内部长度单位是EMU,python-pptx已经转换好,直接参与判断不会失真。shape.left为负数表示图形有一部分超出画布左边缘,此时在放映模式会看到边缘被裁掉。这个脚本查不出“标题压住图”这种视觉问题,但可以覆盖位置字段层面的越界。
XML完整性是另一个高频问题。如果Office提示需要修复,多数原因在于rels关系失效,比如图表对应的rId指向了不存在的part。手动修复时尽量不要用压缩软件往现有包里塞一个XML,因为zip条目顺序一旦错乱,Office启动时会找不到[Content_Types].xml里的注册路径。常见做法是把整个包解压到临时目录,改完文件后用zipfile重新打包。
import zipfile import os def repack(src_dir, dst_pptx): with zipfile.ZipFile(dst_pptx, "w", zipfile.ZIP_DEFLATED) as zf: for root, _, files in os.walk(src_dir): for f in files: full = os.path.join(root, f) rel = os.path.relpath(full, src_dir) zf.write(full, rel)重打包时要保证[Content_Types].xml位于zip根路径下,且尽量避免把临时文件写进目录再一起打包。打包完成后用Presentation()再打开一次,python-pptx能读通,说明大部分关系没有被破坏。对于嵌入字体,可以看ppt/fonts/下有没有字体文件;动画顺序则检查slide XML里的p:timing节点,确认数据图表的出现时序和章节文字一致。放映设置里的自动换片循环也要逐页确认,避免更新后动画时间轴出现数据还没出现、讲稿已经翻页的错位。
本文还有配套的精品资源,点击获取