简介:这份胶粘剂行业研究报告面向行业分析师、企业决策者与市场研究人员,围绕胶粘剂的定义、分类与组成成分展开,系统梳理其在建筑、汽车、包装、制鞋、新能源等领域的应用场景,并深入解析产业链上中下游结构、市场规模变化与未来发展趋势,同时结合重点企业的经营情况,提供竞争情报参考。资源包内含1个PDF文件,压缩包约1.31MB,篇幅集中、结构完整,目录依次覆盖行业概述、产业链解析、市场分析、重点企业分析与行业发展趋势五大模块,适合作为行业概览与市场研判的入门资料。报告中按用途、固化方式、化学成分等标准对胶粘剂做了分类说明,并给出下游应用市场分布与需求增长判断,便于读者快速建立行业认知框架。目前已有64人学习下载,适合需要一份轻量、成体系胶粘剂行业材料的读者参考使用。
1. 胶粘剂行业研究报告为什么值得用工程流水线来做
多数人接到“胶粘剂行业研究报告”这个题目,第一反应是搜几篇现成的 PDF,把产能、产量、下游占比的数字抄进一张 PPT。真跑一轮就会发现两个绕不开的坑:口径打架,同一年的国内产量在不同来源之间能差出两成,差别只在统计范围含不含胶粘带、含不含建筑用的粉料类瓷砖胶;版本失效,三个月前写好的胶粘剂行业分析报告,拿醋酸乙烯和丙烯酸丁酯的最新价格把价差重算一遍,结论可能直接反过来。
落到工程视角,这件事就是一条数据流水线:海关、统计、价格、上市公司公告几路数据落进同一套表结构,口径写成 config 而不是写成脚注,每月更新只换数据不重写逻辑。适合做产业研究、投研、化工品期现和供应链的人,也适合想拿一个真实行业练数据工程的开发者。下面按数据源、指标模型、流水线编排、滚动预测四段往下推,代码都给到能直接跑的程度。
2. 胶粘剂行业的数据源与分类口径:从 HS 编码到上市公司公告
2.1 先定分类口径,再决定去哪找数据
做胶粘剂行业研究最常见的返工,是先抓数据再想分类,结果发现抓来的产量里混着胶带、混着建筑粉料,跟价格数据的品种对不上。正确的顺序是先定一套稳定的分类骨架,再按骨架去找对应的数据源。行业里比较通用的一级骨架是按分散介质和固化方式切,二级再按化学体系切,这样既能跟海关编码挂上,也能跟上市公司的主营结构挂上。
| 大类 | 典型体系 | 主要原料 | 主要下游 | 常用观察口径 |
|---|---|---|---|---|
| 水性胶 | VAE 乳液、丙烯酸乳液、PVA | 醋酸乙烯、丙烯酸丁酯 | 纸包装、木工、建筑 | HS 3506.91 子目 + 3905 乳液 |
| 溶剂型 | 氯丁橡胶、溶剂型聚氨酯 | 甲苯、丁酮、氯丁橡胶 | 制鞋、汽车内饰 | HS 3506.91 子目 |
| 热熔胶 | EVA 基、聚烯烃基、APAO | EVA 树脂、石油树脂、蜡 | 卫材、包装、标签 | HS 3506.91 子目 |
| 反应型 | 环氧、无溶剂 PU、有机硅 | MDI/TDI、环氧树脂、DMC | 新能源、电子、汽车结构 | HS 3506.91 + 3910 硅酮 |
| 胶粘带 | BOPP、PET 基材 + 压敏胶 | 丙烯酸酯、橡胶 | 包装、电子模切 | HS 3919 自粘塑料膜片 |
这张表的用法是“对口径”,不是“抄数字”。海关那边 3506 这一章下面还会细分到零售包装净重不超过 1 公斤、以橡胶或塑料为基本成分、其他三类,粒度越细,历史序列被重新归类打断的概率越高。我的做法是 4 位章和 6 位子目两级都留,做趋势看 6 位,做长周期回看 4 位,序列断裂的地方在报告里标出来。
2.2 海关数据的清洗与入库:一条能跑的 Python
海关的月度进出口明细一般是从官方统计平台按编码和月份导 CSV,量级不大,单品类五年的数据几万行,用 SQLite 完全够。真正费时间的是三件事:编码要补齐成固定位数才能做前缀匹配,数量单位有千克也有吨,均价要用数量加权而不是简单算术平均。
import pandas as pd, numpy as np, sqlite3 RAW = "customs_3506_2020_2024.csv" df = pd.read_csv(RAW, dtype={"hs_code": str, "month": str}) # 1) 编码补齐到 10 位,避免 "3506910000" 被读成 int 丢掉前导零 df["hs_code"] = df["hs_code"].str.strip().str.zfill(10) df["hs4"] = df["hs_code"].str[:4] df["hs6"] = df["hs_code"].str[:6] # 2) 月份统一成 YYYY-MM 字符串,方便和价格台账面 join df["month"] = pd.to_datetime(df["month"], format="%Y%m").dt.to_period("M").astype(str) # 3) 数量统一到吨,均价按数量加权,除零用 where 兜住 df["qty_t"] = df["qty_kg"] / 1000.0 df["usd_per_t"] = np.where(df["qty_t"] > 0, df["usd_amt"] / df["qty_t"], np.nan) df = df[df["qty_t"] > 0].dropna(subset=["usd_per_t"]) con = sqlite3.connect("adhesive.db") df.to_sql("customs_flow", con, if_exists="replace", index=False) con.execute("CREATE INDEX IF NOT EXISTS idx_cf ON customs_flow(hs6, month, trade_type)") con.commit()这段代码的关键在三个参数位:zfill(10)决定前缀匹配能否成立,编码少了前导零,后面所有按章聚合的 SQL 都会静默少统计一批数据;to_period("M")把日期压到月粒度,避免月底月初两笔报关被算进不同月份;均价用usd_amt / qty_t而不是对每一笔的单价求平均,否则小批量高单价的样品单会把均价整体拉高。跑完之后建议顺手查一次月度行数和金额合计,和海关页面上的合计数对一下,差得超过千分之一就说明有编码没抓全。
2.3 价格、产能与公司数据的台账化
价格数据是这份报告里最贵也最脆的一环。第三方资讯机构(卓创、隆众、生意社这类)的日度价格通常不能直接抓,授权导出或人工录入更现实,所以表结构要设计得能承接手工录入。核心是一张长表,主键是(品种代码,日期),另外带单位、来源和置信度三个字段,置信度用来标记哪些点是插值补的。
产能数据靠两条线交叉:一是行业协会和资讯机构的产能台账,二是上市公司公告里的在建工程和募投项目。前者给你全行业分母,后者给你可验证的分子。上市公司这块,回天新材、硅宝科技、康达新材、集泰股份、高盟新材、晶华新材、斯迪克这一类名字会反复出现,年报里的“主要产品产能、产量、销量”三列就是现成的装置级数据。
| 数据源 | 更新频率 | 主要口径风险 | 落地方式 |
|---|---|---|---|
| 海关进出口明细 | 月 | 归类调整、保税区流转 | CSV 导入 + 编码前缀聚合 |
| 国家统计口径产量 | 月/年 | 是否含胶带、是否含粉料 | 手工台账 + 口径备注字段 |
| 资讯机构价格 | 日/周 | 牌号与交割地不一致 | 长表录入 + 来源字段 |
| 上市公司年报 | 半年/年 | 并表范围变化 | 手工抽取到 company_series |
| 行业协会统计 | 年 | 发布滞后、抽样口径 | 作为校准基准而非主序列 |
2.4 三路数据合表时最容易踩的坑
第一个坑是汇率口径。进口均价是美元/吨,国内价格是元/吨,把两者画在一张图上必须统一,而且汇率要选月末值还是月均值会直接影响价差的拐点判断。我的习惯是固定用月均汇率,并在 config 里写死来源,换口径就换版本号。
第二个坑是重复统计。保税区流转、复出口、加工贸易的货值有时会在不同贸易方式里各出现一次,按贸易方式求和会虚高。处理办法是明细表里始终保留trade_type,聚合时显式列出要含哪几种,绝不写SUM不带条件。
第三个坑是单位不一致,产能按万吨、产量按吨、进口按千克,三层嵌套换算最容易错一个零。统一到吨之后,在建模层再乘系数,不要让原始表出现两种单位。
第四个坑是时间对齐。价格是日频,海关是月频,产能是季度或年度,合表时统一往月频靠,日频取月均值,年度值平摊到 12 个月只用于画图,做同比计算时必须回到原始频率,否则会把季节性抹平。
3. 胶粘剂行业分析报告的核心指标:表观消费、开工率与原料价差
3.1 供需平衡表怎么搭
供需平衡表是整份报告的骨架,三个公式撑起全部:表观消费量 = 国内产量 + 进口量 − 出口量;开工率 = 产量 ÷ 有效产能;净进口依赖度 =(进口 − 出口)÷ 表观消费量。前两个决定行业景气判断,第三个决定价格弹性。用 SQL 一次算完,比在 Excel 里每月手工拉一遍可靠得多。
WITH trade AS ( SELECT month, SUM(CASE WHEN trade_type = 'import' THEN qty_t ELSE 0 END) AS imp_t, SUM(CASE WHEN trade_type = 'export' THEN qty_t ELSE 0 END) AS exp_t FROM customs_flow WHERE hs6 IN ('350610','350691','350699') -- 只取调制胶三个子目 GROUP BY month ) SELECT t.month, p.output_t, t.imp_t, t.exp_t, p.output_t + t.imp_t - t.exp_t AS apparent_demand_t, ROUND(p.output_t / NULLIF(c.capacity_t, 0) * 100, 1) AS util_pct, ROUND((t.imp_t - t.exp_t) / NULLIF(p.output_t + t.imp_t - t.exp_t, 0) * 100, 1) AS net_import_pct FROM trade t JOIN domestic_output p ON p.month = t.month LEFT JOIN capacity_monthly c ON c.month = t.month WHERE p.output_t > 0 ORDER BY t.month;几个参数要固定住:hs6的集合必须和上一章的分类骨架一致,加一个子目就等于改了统计范围,改一次要重跑全部历史;NULLIF防的是产能缺失月份除零,返回 NULL 比返回 0 好,画图时能一眼看出断点;capacity_monthly里的产能是有效产能,不是铭牌产能,停产和长期检修的装置要扣掉,否则开工率会被系统性低估。这张表跑出来以后,我一般先看三件事:开工率有没有连续三个月下滑,净进口依赖度有没有突然跳变,表观消费的同比和下游几个行业(包装、地产竣工、汽车产量)的同比对不对得上。
3.2 按配方权重算原料成本指数
胶粘剂的价格传导是这份报告里最有价值的部分,因为配方成本能算得比较准。做法是给每个大类配一份 BOM 权重,权重来自行业里公开的典型配方和上市公司披露的原材料占比,两者有出入时以能对上年报成本结构的那个为准。
BOM = { "VAE_white_glue": {"VAM": 0.42, "BA": 0.06, "water_aux": 0.10, "pack": 0.08, "energy": 0.06}, "hotmelt_EVA": {"EVA_resin": 0.45, "petro_resin": 0.30, "wax": 0.12, "antiox": 0.02, "energy": 0.05}, "solvent_PU": {"polyol": 0.35, "MDI": 0.18, "solvent": 0.22, "aux": 0.06, "energy": 0.04}, } def cost_index(price_row, bom, base_month): """price_row: 某月各原料均价 dict;base_month: 基期该品类的成本,用于指数化""" out = {} for prod, weights in bom.items(): cost = sum(w * price_row[k] for k, w in weights.items() if k in price_row) out[prod] = round(cost / base_month[prod] * 100, 2) return outBOM里的权重加起来不必等于 1,剩下的是人工、折旧和利润,这部分随行情波动小,放在指数之外更稳。基期的选择很关键,我一般取最近一轮价格平稳的季度均值,而不是取某一年年初,避免基期本身处在暴涨暴跌里。算完成本指数之后再和产品市场价做差,得到的价差序列才是真正能看出利润扩张收缩的指标。需要注意的是,水性胶的原料里有相当比例是水,价格几乎不动,权重给高了会把整个指数钝化,所以water_aux这类项我通常只保留 0.10 上下的权重。
3.3 下游需求权重的确定
需求侧最容易拍脑袋。包装占多少、建筑占多少,不同报告给的数字能差十几个点,原因多半是统计里含不含胶带。我的处理是不追求一个“真值”,而是做两套权重:一套按行业协会口径,一套按上市公司营收结构反推,两套都在报告里给出来,并且把两套权重下算出的需求增速差作为不确定性区间。
反推的逻辑是:把样本公司的营收按产品线拆,再按产品线映射到下游,得到一组相对权重,最后用行业总量校准到绝对值。这个过程在company_series表里做,字段是公司、期间、产品线、营收、毛利率、产能,产品线到下游的映射单独建一张字典表,字典表改动要记版本,因为它是主观判断最集中的地方。
4. 把胶粘剂行业研究报告做成可复现的流水线
4.1 目录结构与环境
到这一步,表格和代码已经能跑通,接下来要解决的是“下个月还能跑”。目录结构按输入、规则、输出三段切,配置单独放,任何口径参数都不写在脚本里。
adhesive_report/ ├── config/caliber.yaml # 口径参数:HS 集合、BOM 权重、基期、汇率来源 ├── data/raw/ # 原始 CSV,只进不改 ├── data/warehouse/adhesive.db # SQLite 仓库 ├── rules/checks.py # 数据校验规则 ├── report/template.md.j2 # 报告模板 └── run.py # 编排入口# config/caliber.yaml version: "2024Q4-v3" hs6_set: ["350610", "350691", "350699"] base_period: ["2023-07", "2023-09"] fx_source: "monthly_average" bom: hotmelt_EVA: {EVA_resin: 0.45, petro_resin: 0.30, wax: 0.12, antiox: 0.02, energy: 0.05} checks: max_month_gap: 1 max_mom_jump_pct: 35version字段是整套流水线的锚点,报告页脚引用它,任何人问某个数字怎么来的,回到这个版本就能复现。max_mom_jump_pct是异常阈值,环比跳超过 35% 的数据点必须人工确认,通常是编码调整或者录入错误,不是真实行情。
4.2 数据校验规则
校验不要写成事后检查,要写成断言,跑不过就中断,让脏数据进不了报告。
import pandas as pd, sqlite3, yaml cfg = yaml.safe_load(open("config/caliber.yaml", encoding="utf-8")) con = sqlite3.connect("data/warehouse/adhesive.db") def month_gaps(series_month, max_gap): d = pd.to_datetime(pd.Series(series_month) + "-01").sort_values() gap = (d.diff().dt.days.dropna() / 30.0).round(0) return gap[gap > max_gap].tolist() def mom_outliers(df, col, threshold): r = df[col].pct_change().abs() * 100 return df.loc[r > threshold, ["month", col]] flow = pd.read_sql("SELECT month, qty_t FROM customs_flow WHERE hs6='350691' AND trade_type='import'", con) assert not month_gaps(flow["month"], cfg["checks"]["max_month_gap"]), "进口序列出现月份断档" bad = mom_outliers(flow, "qty_t", cfg["checks"]["max_mom_jump_pct"]) assert bad.empty, f"存在环比异常点:{bad.to_dict('records')}"month_gaps抓的是断档,海关数据偶尔会有一个月没导全,画出来的曲线会是一条假的下探;mom_outliers抓的是跳变,返回具体月份方便回查原始报关单。阈值不要设太紧,化工品单月环比波动 20% 到 30% 是正常的,设到 15% 会天天报警,最后没人看。
4.3 出图与 Markdown 渲染
出图和渲染拆开,图只负责画,模板只负责引用,这样换风格不用改数据逻辑。
import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt from jinja2 import Template def plot_multi(df, x, y, group, out, title): fig, ax = plt.subplots(figsize=(9, 4)) for key, sub in df.groupby(group): ax.plot(sub[x], sub[y], label=key, linewidth=1.4) ax.set_title(title) ax.legend(ncol=3, fontsize=8) fig.tight_layout() fig.savefig(out, dpi=150) plt.close(fig) tpl = Template(open("report/template.md.j2", encoding="utf-8").read()) markdown = tpl.render(version=cfg["version"], util_chart="figs/util.png", tables=tables) open("report/out.md", "w", encoding="utf-8").write(markdown)模板里所有数字都从变量取,不写死。这样改口径只动caliber.yaml,改版式只动模板,两者互不干扰。跑完一次完整流水线的时间通常在几分钟量级,主要开销在 matplotlib 的中文字体加载上,服务器上记得显式指定字体文件,否则图里的中文会变成方块。
5. 让报告滚动起来:预测、敏感性与版本回溯
静态报告的寿命大概一个季度。想让它滚动,最有性价比的两件事是短周期预测和原料敏感性。预测用 SARIMAX 做四个月的滚动外推就够用,模型复杂了反而不好解释。
import pandas as pd from statsmodels.tsa.statespace.sarimax import SARIMAX s = pd.read_sql("SELECT month, apparent_demand_t FROM v_apparent_demand ORDER BY month", con, index_col="month", parse_dates=True).asfreq("MS") y = s["apparent_demand_t"].interpolate() model = SARIMAX(y, order=(1, 1, 1), seasonal_order=(0, 1, 1, 12), enforce_stationarity=False).fit(disp=False) fc = model.get_forecast(steps=4).summary_frame(alpha=0.2)order=(1,1,1)对应自回归、差分、移动平均各一阶,差分阶数取 1 是因为表观消费有明显的年度趋势;seasonal_order的最后一个 12 是月粒度下的年度周期,季节性差分和移动平均各取一阶;alpha=0.2给出 80% 置信区间,比点预测更有用,报告里我一般只放区间不放点。
敏感性分析回答的是“原料涨 10%,哪个品类最难受”,按原料逐项冲击,看各品类的成本抬升幅度。
def cost_shock(base_price, bom, raw_key, shock=0.10): rows = [] for prod, w in bom.items(): if raw_key not in w: continue cost = sum(v * base_price[k] for k, v in w.items() if k in base_price) delta = w[raw_key] * base_price[raw_key] * shock rows.append({"product": prod, "raw": raw_key, "cost_up_pct": round(delta / cost * 100, 2)}) return pd.DataFrame(rows).sort_values("cost_up_pct", ascending=False)热熔胶对 EVA 树脂、水性胶对醋酸乙烯的弹性差异,用这张表一眼能看出来,比文字描述“成本压力较大”有用得多。
最后一步是回溯。把每次发布时对当期的预测值和三个月后的实际值存成一张 backtest 表,每季度算一次平均绝对百分比误差:
back = pd.read_csv("data/report_backtest.csv", parse_dates=["target_month", "made_at"]) back["ape"] = (back["pred"] - back["actual"]).abs() / back["actual"] print(back.groupby(back["made_at"].dt.to_period("Q"))["ape"].mean().round(4))误差连续两个季度扩大,说明口径或模型该动了,这时候回看caliber.yaml的版本历史,基本能定位到是哪次口径调整带来的偏差。把 config 文件的哈希写进报告页脚,下次有人质疑某个数字,顺着哈希就能找到那次运行的完整快照。
本文还有配套的精品资源,点击获取