前阵子整理了一批某加盟信息平台上的品牌数据,因为平台页面编号的原因,我把整个项目命名为“1637加盟网数据实战”。这份数据初看就是一张普通的品牌信息表,但顺着加盟费、门店数、品类这些字段往下挖,能挖出不少关于加盟市场的有意思结论。这篇文章把这个项目从数据清洗到可视化呈现的完整过程复盘一遍,重点说清楚每一步为什么这么做、图表怎么选、以及那些常规教程里不会写的坑。
整个项目做下来,覆盖了一个数据分析任务里最核心的闭环:拿到原始数据、理字段口径、做清洗、定分析维度、写代码出图、再回头解读业务含义。不管你是刚开始学数据分析的学生,还是自己想做市场调研、考察加盟项目的朋友,这套处理思路都可以直接拿去套用。数据源本身不复杂,不需要搭集群也不需要写复杂的工程代码,一台普通电脑装好Python环境就能跑完,属于典型的“轻项目重分析”练习。
1. 项目概述与目标拆解
1.1 这批加盟数据里到底有什么
这份数据一共收集了两千多条品牌记录,字段不算多,但每个字段的信息量其实都不小。核心字段包括品牌名称、所属品类、加盟费、保证金、门店总数、投资预算区间、加盟年限和开放区域。实际拿到的原始数据长什么样,我整理了一个匿名示例方便理解:
| 字段名 | 示例值 | 原始类型 | 问题点 |
|---|---|---|---|
| 品牌名称 | 某奶茶连锁 | 文本 | 有重复收录 |
| 所属品类 | 餐饮 / 教育 / 零售 | 文本 | 同一品类叫法不统一 |
| 加盟费 | 5.8万 / 面议 | 文本 | 带单位,且有非数值 |
| 保证金 | 1万 / 0 | 文本 | 文本与数字混存 |
| 门店总数 | 350家 / 未知 | 文本 | “家”与“未知”混存 |
| 投资预算 | 10-20万 | 文本 | 是一个区间,不是单一数值 |
| 开放区域 | 华东、华南等 | 文本 | 多个区域叠加 |
这类数据在垂直信息网站上非常典型,它不像标准数据库导出的Excel那么干干净净,每一列都带着面向用户的展示格式。加盟费写成“5.8万”、“面议”或“10-20万”,门店数写成“500+”甚至手滑多写几个空格,都是家常便饭。这也是我拿它当分析素材的原因之一:数据清洗的练习价值足够高,处理完后再看任何类似的文本型表格都会淡定很多。
另外要特别注意,这个数据集收录的是平台上的品牌信息,不等于全行业的加盟品牌全集。平台本身有自己的入驻规则和筛选机制,品牌曝光量和真实门店数之间也可能存在时间差。后面做分析结论的时候,我一直提醒自己:手里的数据只是市场的一个切片,不能说“餐饮加盟最低门槛是五万”这种绝对话,只能说“这批平台收录的餐饮品牌里,加盟费大多落在这个区间”。
1.2 分析目标选了哪几个维度
数据拿到手以后,我先没有急着打开绘图工具写代码,而是花了一点时间把想回答的问题写下来。数据分析的第一步是把问题问清楚,代码只是实现手段。结合这份数据能回答的问题,我最终定了四个核心维度:
第一个是加盟费的整体分布。加盟费相当于进入一个加盟体系的门票钱,它直观地反映品牌对加盟商的资金门槛,也能侧面反映品牌定位是走量还是走高客单。第二个是门店规模Top20排行。门店数量是品牌扩张能力最直接的表现,排个榜能看出当前哪些品牌在跑马圈地、哪些品类更受加盟商青睐。第三个是不同品类的投资门槛对比。加盟费、保证金和投资预算放在品类维度下对比,能看出教育、餐饮、零售这些方向在资金要求上的差异,这个是准备入局的人最关心的问题。第四个是投资预算和门店数量的交叉关系。通过散点图观察这两个变量之间有没有相关性,判断高投入是否对应高规模,这个交叉维度能挖掘出单看一列数据发现不了的信息。
这四个维度合在一起,基本回答了一个潜在加盟商会问的问题:我大概要准备多少钱、选哪个品类、市面上哪些品牌跑得比较快。每个维度对应一种图表类型:分布用直方图和箱线图,排行用横向条形图,品类对比用带统计信息的柱状图或箱线图,交叉关系用散点图。这个“先定问题,再选图表”的顺序很重要,很多人一上来就把所有字段两两组合画一遍,最后图很多但讲不出一个结论。
1.3 为什么选这类网站数据做实战
现在网上的数据分析教程很喜欢用经过处理的经典数据集,比如鸢尾花、房价预测这些,它们用起来确实顺手,但有个问题:数据太干净了,清洗环节几乎是跳过的。真实业务场景里,你拿到的数据大概率是一堆充满缺失值、单位不统一、格式混乱的表格,光是把“面议”“未知”“500+”这些脏数据整理成能参与计算的数值,就要花不少时间。
加盟网站数据在这点上特别合适。它的复杂程度处在“无聊的练习数据”和“崩溃的生产数据”之间,既不至于清洗到想放弃,又能让你真正体会字段口径统一的重要性。整个项目做完之后,哪怕换一批别的垂直行业数据来练手,流程也是通用的:先看字段类型,再定清洗规则,然后定义指标口径,接着做探索性可视化,最后带着业务视角解读图表。这套流程比记一堆matplotlib绘图语法值钱得多。
2. 数据清洗与字段口径统一
2.1 数据来源与采集方式
这批数据主要来自加盟信息平台的公开品牌页面,属于公开可浏览的商业信息。采集方式上,我没有直接讲什么高深的爬虫框架,就是按平台的分页列表逐页抓取品牌页里的结构化字段,加上一部分人工核对。实际做的时候,我建议不要太依赖一次性自动化抓取,因为加盟网站的品牌页模板经常会有微调,今天抓的正常字段明天可能就错位了。更好的做法是先抓两页样本,手工检查一遍字段对应关系,再写循环抓全量。
采集下来之后的数据保存为CSV文件,编码选UTF-8-SIG,这个细节对Windows系统尤其重要,不然用Excel打开会显示乱码。后续所有清洗和分析都在这个CSV基础上做,原始文件单独存一份备份,任何一步操作出错都能回退,这是我在数据项目里一直坚持的习惯。
2.2 文本型数值字段的清洗方案
原始数据里最头疼的是加盟费、保证金、投资预算这三列,因为它们都是以文本形式存储的,还夹杂着“万”“面议”“未知”这类内容。先说加盟费的处理逻辑:
| 原始写法 | 清理后处理方式 |
|---|---|
| 5.8万 | 转为数值 5.8 |
| 面议 | 记为缺失值,单独标记 |
| 3-8万 | 取区间中位值 5.5 |
| 10万以下 | 取上限值的50%,记为 5.0 |
| 无 | 记为缺失值 |
这里面容易踩坑的是“面议”的处理成千上万别直接强制转成float,否则会报错或者被转成NaN,而NaN和数据的真实缺失在业务上是有区别的。我的做法是单独生成一列“加盟费是否有明确数值”的布尔标记,这样后续既可以用有数值的样本做分布分析,又能统计出有多少品牌是面议价格的盘。
投资预算区间转数值是另一个细节。原始数据常常写成“10-20万”,如果直接去掉“万”字得到的是字符串“10-20”,还需要按分隔符拆成两个数字再取平均。为什么取中位数而不取上限或下限?因为加盟投资通常是弹性预算,上下限之间才是备选方案的真实投入预期,中位数在后续散点图里能提供相对稳定的点位,不会因为个别区间的极端值带偏整体分布。
门店数清洗相对简单但还是有坑:“350家”需要去掉“家”字,“500+”需要处理“+”号,“未知”要转为缺失值。这里我统一用正则表达式提取数字部分,并且注意当字符串里同时出现“三”和“百”这类中文数字时要用专门映射表,不过本次数据里暂时没遇到,所以直接按阿拉伯数字处理就可以了。清洗后我把门店数转成了整数类型,并把大于0的值作为有效样本,保证后续排序统计不被缺失值干扰。
2.3 缺失值与异常值的处理原则
缺失值处理上,我的原则是“能不填就不填,填了必须做标记”。加盟费是面议的样本,如果直接填充平均值,会人为压缩数据的分布形态。我更倾向于先保留缺失状态,在计算分布时用dropna剔除,在计数时用fillna(0)或单独统计面议的数量。对门店数也是同样的逻辑,“未知”和“0家”在业务上完全不同,前者是没公开统计,后者是刚起步,必须区分开。
异常值这块,我遇到最典型的情况是某品牌门店数标注达到上万级别,而它的加盟费反而只有很低的值,这个组合放在整个数据集里显得格外扎眼。我没有直接删掉它,而是先查了原始页面的记录,确认是平台收录的历史品牌数据没有同步更新,才决定把它标记为异常值并在散点图里用特殊颜色标注出来,而不是移除样本。
用一个简单表格总结清洗后的字段口径:
| 字段 | 清洗后类型 | 有效样本占比 | 备注 |
|---|---|---|---|
| 加盟费 | float | 72% | 其余为面议或缺失 |
| 保证金 | float | 58% | 部分品牌不公开 |
| 门店数 | int | 81% | 含少量异常值 |
| 投资预算中位数 | float | 78% | 区间文本取中位值 |
| 品类 | category | 99% | 已统一名称 |
3. 核心分析维度与可视化设计思路
3.1 加盟费分布:为什么用直方图加箱线图
加盟费是企业人群最关心的指标之一,我首先拿它做分布分析。加盟费数据天然呈现右偏分布,大量品牌的加盟费集中在低区间,少数品牌收费很高,如果把所有值直接丢进普通坐标轴里,低区间的柱子会被压成一条细线,完全看不出分布。解决办法是先画直方图看形态,再叠加一张箱线图看分位数和离群点。
直方图的分箱数我经过几次对比,最终把数据切成30个箱子,这个粒度既能看出5万以下的密集段,又不至于因为箱子太多产生大量空区间。箱线图放在直方图旁边,能直接读出四分位数和边缘离群点,一眼就知道所谓“平均加盟费”其实被高端品牌拉高了,大部分品牌的加盟费集中在下四分位数附近。
这张图的业务解读是:平台收录的品牌里,加盟费在0到10万区间的占比超过六成,10到20万是第二密集区间,超过30万的品牌属于少数派。所以对普通加盟者来说,加盟费门槛并不算高,真正的资金压力往往集中在后续的装修、设备、原材料这些一次性投入上,光看加盟费很容易被低估总成本。
3.2 门店规模排行:横向条形图才是首选
门店数是品牌扩张规模的直接体现。做Top20排行的时候,我没有用竖向柱状图,而是选了横向条形图,原因很实际:品牌名称属于长文本,动辄七八个字起,放在横轴底部会旋转成斜字或者挤成一团,完全没法读。横向条形图让品牌名排在纵轴,从长到短整齐排列,阅读顺序符合人眼从左上到右下的扫描习惯。
这里还有个细节:排序时要指定降序,让门店数最多的品牌在图表顶部,否则matplotlib默认按字母顺序排列,会得到一张完全没法读的图。Top20榜单里最显眼的是奶茶类、快餐类品牌,它们门店数普遍在数百家到上千家,这背后是标准化程度高、门店模型轻、复制速度快的品类特性。榜单本身还能做一个衍生分析:用门槛最低的前几个品牌和门店数最高的前几个品牌做交集,会发现走“低加盟费加高门店数”路径的品牌数量很可观。
3.3 品类对比:带误差线的柱状图与分面箱线图
品类维度是分析中最有信息量的切面。原始数据里的品类字段五花八门,光“餐饮”就有火锅、小吃、快餐、奶茶等多个分支,我先把品类做了归一化合并,再计算各品类的平均加盟费和投资预算中位数。按平均加盟费排序后发现,教育类品牌的平均加盟费在十几万上下,远高于餐饮类的五六万,零售和美容美发类居中,家政服务类偏低。
呈现品类对比我用了带误差线的柱状图,误差线代表标准差,原因是平均数只反映中心位置,加盟费离散程度才是真正有价值的信号。比如教育类平均加盟费虽高,但细分方向从少儿编程到职业技能培训差异很大,标准差也大,柱子上方的误差线会明显很长;而奶茶类平均加盟费低且标准差小,说明这个品类里品牌定价比较接近。这个信息在业务决策里至关重要——光看平均数做决定,容易忽略同一个品类内部的巨大波动。
如果你想把品类内部结构看得更细,可以换成按品类分面的箱线图,每个品类画一张小箱线图,对比中位数、四分位数和离群点,判断同一品类里的价格分层。数据量不大的时候,分面箱线图几乎可以把所有信息展示在同一张图里,分析时自己看非常爽。
3.4 投资金额与门店数交叉分析:散点图的选型逻辑
我最期待的是投资预算中位数和门店数的交叉关系。理论上高投入的品牌应该能支撑更快的扩张,但实际情况是加盟市场极度分散,资金门槛并不直接等于品牌规模。为了准确判断相关性,我先对门店数取了以10为底的对数,否则少数数千家门店的大品牌会占据整个横轴,其余几百家门店的品牌全挤在左边变成一坨,什么趋势都看不出来。
取对数后,散点的分布形状清晰了很多:它们沿横轴比较均匀地铺开,并没有出现明显的线性上升或下降趋势,计算皮尔逊相关系数也只有0.2左右,属于弱相关。这个结果本身就是一个有价值的结论。它说明加盟市场的品牌扩张更多取决于单店盈利模型、管理标准化和供应链能力,而不是单纯的投资金额大小。低投入高规模与高投入低规模的品牌同时存在,市场并没有遵循“钱多就能扩张”的逻辑。
散点图解读时还有一个容易被忽略的点:记得标记异常点。门店数上万但投资预算很低的品牌会让散点图出现一个角落里孤零零的点,看着像趋势外溢,其实是数据质量问题的产物。我在图上把这些异常点单独标为三角形,并在注释里写明原因,避免别人看图时误解结论。
4. 实操过程:从原始表格到分析图表
4.1 环境准备与工具选型
整个项目是在Python环境下完成的,版本用的是3.9以上。核心库是pandas、matplotlib和seaborn,这三个就足够了。pandas负责数据清洗和聚合,matplotlib负责绘图,seaborn用来提高图表的美观度。如果你想做交互式的图表,可以引入pyecharts,但做过对比之后,我建议第一阶段先用静态图把分析逻辑跑通,再上交互图表展示,不然容易把时间花在调整交互效果上而忽略了分析本身。
环境准备有几个容易出问题的点:一是matplotlib的中文字体显示,后面专门写一节排查;二是seaborn版本和matplotlib版本要匹配,不然出图风格会异常;三是保存图表时建议用SVG格式,矢量图在报告里放大或缩小都不会糊,但文件体积稍大,需要提交Word文档时再转成PNG。
4.2 数据读取与清洗代码实录
读取CSV并做初次清洗的代码,我贴的是精简版,实际项目里我把每一步都输出一次shape,方便及时发现异常:
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import re # 解决中文显示问题 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False df = pd.read_csv('1637_join_data.csv', encoding='utf-8-sig') df.columns = ['品牌名称', '品类', '加盟费', '保证金', '门店数', '投资预算', '开放区域'] print(df.shape) print(df.dtypes)清洗函数我单独抽出来,这样后续扩展字段时只需要补充解析函数,不用改动主流程:
def parse_amount(s): """解析'5.8万'、'面议'、'3-8万'这类文本""" if not isinstance(s, str): return None s = s.replace('万', '').replace(',', '').strip() if '面议' in s or s == '无' or s == '': return None if '-' in s: nums = re.findall(r'\d+\.?\d*', s) if len(nums) >= 2: return (float(nums[0]) + float(nums[1])) / 2 nums = re.findall(r'\d+\.?\d*', s) return float(nums[0]) if nums else None def parse_store(s): """解析'350家'、'500+'、'未知'""" if not isinstance(s, str): return None if '未知' in s or s == '': return None nums = re.findall(r'\d+', s) return int(nums[-1]) if nums else None df['加盟费数值'] = df['加盟费'].apply(parse_amount) df['保证金数值'] = df['保证金'].apply(parse_amount) df['门店数数值'] = df['门店数'].apply(parse_store) df['投资中位数'] = df['投资预算'].apply(parse_amount) df['有加盟费数值'] = df['加盟费数值'].notna()清洗结束后,我建议统一检查四件事:各字段缺失值数量、数值范围是否合理、品类字段的种类数、是否有整行重复数据。特别是重复品牌名,平台偶尔会重复收录同一品牌的不同加盟分站,需要按品牌名称加品类两列做去重,否则后面的Top20排行会失真。
4.3 核心分析与绘图代码
画图之前先做聚合。加盟费分布图和箱线图代码:
fig, axes = plt.subplots(1, 2, figsize=(14, 5)) # 直方图 moneys = df['加盟费数值'].dropna() axes[0].hist(moneys, bins=30, edgecolor='white', color='#4C72B0') axes[0].set_title('加盟费分布直方图') axes[0].set_xlabel('加盟费(万元)') axes[0].set_ylabel('品牌数量') # 箱线图 axes[1].boxplot(moneys, vert=True) axes[1].set_title('加盟费箱线图') axes[1].set_ylabel('加盟费(万元)') plt.tight_layout() plt.show()门店规模Top20的排行图是一张横向条形图,筛选逻辑是先按门店数数值排序取前20,再反转顺序画图,这样最大值的品牌正好出现在顶部:
top20 = df.dropna(subset=['门店数数值']).nlargest(20, '门店数数值') top20 = top20.iloc[::-1] plt.figure(figsize=(10, 10)) plt.barh(top20['品牌名称'], top20['门店数数值'], color='#55A868') plt.xlabel('门店数量(家)') plt.title('品牌门店规模 Top20') plt.tight_layout() plt.show()品类对比柱状图和散点图的代码,在seaborn里用一行就能实现,不过我会先手动聚合数据后再用matplotlib画,便于精确控制:
# 按品类聚合 cat_stats = df.groupby('品类')['加盟费数值'].agg(['mean', 'std', 'count']) cat_stats = cat_stats.sort_values('mean') plt.figure(figsize=(12, 6)) plt.errorbar(cat_stats['mean'], cat_stats.index, xerr=cat_stats['std'], fmt='o', color='#C44E52', ecolor='#C44E52', elinewidth=2, capsize=4) plt.xlabel('平均加盟费(万元)') plt.title('不同品类的平均加盟费与标准差对比') plt.tight_layout() plt.show()散点图部分取投资中位数对数或取门店数对数,我的选择是对门店数取对数后画:
df['门店数对数'] = np.log10(df['门店数数值'].where(df['门店数数值'] > 0)) plt.figure(figsize=(10, 6)) sns.scatterplot(data=df, x='投资中位数', y='门店数对数', hue='品类', alpha=0.6) plt.xlabel('投资预算中位数(万元)') plt.ylabel('门店数量(对数刻度)') plt.title('投资预算与门店数量的交叉关系') plt.tight_layout() plt.show()4.4 图表结果的业务解读
直方图和箱线图出图后,第一个直观结论是加盟费分布严重右偏,中位数大约在5万左右,而平均数被少数高价品牌拉到了8万附近。只看平均值会误以为加盟门槛很高,看中位数和四分位距才更接近真实情况。箱线图右侧延伸出的离群点,基本都是教育类或品牌定位偏高的项目,这也是后面品类对比的重要线索。
Top20门店排行图显示,门店数靠前的品牌大多都有低客单、标准化程度高的特点,比如奶茶、快餐、小吃,它们加盟费普遍不高,靠规模效应盈利。榜单里如果要挑和品类交叉分析,会发现零售和家政类虽然上榜少,但单店投资并不低,说明这几个品类的扩张速度受运营复杂度限制。
品类对比的误差线柱状图是信息量最大、也最容易讲出观点的图。教育类平均加盟费约为餐饮类的三倍,但标准差也大,说明实际细分方向差异很大;奶茶类平均加盟费低,标准差小,行业定价已经趋于透明。结合门店数据,能看出奶茶类品牌在高门店数和低加盟费区间高度密集,这是一个典型的高周转、低门槛、快速复制模型。
交叉散点图则给出了一个更冷静的视角:资金投入和门店规模之间没有明确的规律。即便只看品类颜色分布,也很难画出一条清晰的分界线。这说明在加盟市场里,选择比努力更重要——同样的资金预算,进入不同品类、选择不同品牌,规模发展路径可能完全不同。做可视化分析时,发现没有线性关系并不是失败,相反,它和找到强相关一样,都是一个值得写进报告的结论。
5. 常见问题与排查技巧实录
5.1 中文乱码和负号显示异常
matplotlib画图时最常见的中文乱码问题,必须在绘图前配置字体。Windows系统直接设置SimHei基本就行,macOS和Linux需要换成对应的中文字体名称,比如PingFang SC或Noto Sans CJK SC。另外还要设置axes.unicode_minus为False,否则坐标轴上的负号会显示成方块。如果你用的是Jupyter Notebook,还要记得在代码块前面加上%matplotlib inline,否则图不会自动显示。
字体问题还包括保存图片后字体被替换的问题,特别是在无图形界面的服务器上跑脚本时,默认字体列表里没有中文字体就会出现乱码。建议在项目开始时就把字体文件路径写死,不要依赖系统默认配置。具体方式是:
import matplotlib font_path = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf' font_prop = matplotlib.font_manager.FontProperties(fname=font_path) matplotlib.rcParams['font.family'] = font_prop.get_name()5.2 异常值到底该删还是该标
数据里有个门店数过万的异常值,一开始我差点直接把它当错误数据删掉,后来查原始页面发现这个品牌确实曾经开出很多门店,只是平台数据长期没更新。引入时间维度后,这个异常点反而成了有价值的业务信息,提醒我平台数据的时效性问题。
处理异常值的原则,我总结为三步。先看原始记录,确认是录入错误还是真实数据;再看它对分析结论的影响,如果只是单独一个点,不会改变整体分布,就保留但标记;如果会影响均值、相关系数这些统计量,就分别计算保留和剔除两种情况下的结果,看结论是否一致。如果一个异常点能颠覆整个结论,说明数据集本身太脆弱,不能依赖单条记录得结论。
5.3 一图一结论,避免信息过载
刚开始做可视化时,总喜欢把所有字段塞到一张图里,比如用气泡图同时表达加盟费、保证金、投资、门店数四个维度,画出来花里胡哨,最后谁也看不出重点。后来我给自己定了一个规矩:一张图只回答一个问题,附带的信息最多不要太超过三个维度。散点图用颜色区分品类、气泡大小表示门店数,已经是信息量上限了,再叠加尺寸和形状就会让读图成本剧增。
具体到这个小项目里,分布图只回答“加盟费怎么分布”,排行图只回答“谁是店最多的品牌”,对比图只回答“品类之间有什么差异”,散点图只回答“投资与规模有没有关系”。每张图配一句结论,报告结构就非常干净。
5.4 别把平台切片当成全行业数据
这个认知误差是很多人会掉的坑。加盟网站的收录品牌受平台销售团队拓展范围、品牌付费意愿、品牌活跃度影响,天然存在选择性偏差。它不代表所有加盟品牌的全集,更不代表全国所有开店数据。你在平台上看到的某个品类平均加盟费是这么多,不等于线下真实加盟市场就是这样一个分布,只能说明这个平台上的公开报价大致如此。
分析报告里要主动声明数据来源与收集时间,并说明分析结论只适用于这个样本集。这个习惯在项目里也许看不出差别,但在对外汇报或写结论时,别人会因为你主动标注数据边界而更信任你的分析。不做这个声明,一个较真的业务同事就能用半个反问推翻整张报告。
还有一点,加盟费和总投入是两个概念,我在分析里反复提醒自己不混淆。加盟费往往只是授权费,真正的开店总投入还包括设备、装修、首批进货、房租和流动资金,这些字段在平台数据里没有。文章里讨论的“投资预算中位数”是一个综合参考值,和加盟费不能画等号。在最终报告里我特意把这一点写在显眼位置,避免读者只盯着加盟费做决策。
这个项目做下来,我个人最大的收获反而不是绘图技巧,而是对“数据口径”这四个字的理解变深了。所有图表之所以能讲出逻辑,是因为我在清洗阶段就把加盟费、门店数、投资预算这些字段的口径统一好了。很多数据分析项目做到最后图表是画出来了,结论却经不起推敲,问题通常不在画图这一步,而是在前面字段定义的环节。
后续如果想在这个项目上继续扩展,可以考虑把开放区域字段拆到省份级别做空间分布图,或者加入品牌备案年限、留言热度这些字段,研究品牌生命周期和加盟热度的关系。数据源本身不复杂,但顺着这个方向做下去,能延展的分析话题还有很多。