尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python数据分析实战:辅导班市场调研全流程指南

Python数据分析实战:辅导班市场调研全流程指南 很多初入教育行业的人会以为辅导班市场无非是“机构 家长 学生”这么一条简单的链条调研起来应该是几份问卷、几场访谈就能讲清楚的事。但真正把数据铺开之后你会发现价格带、课程品类、区域分布、师资构成、营销渠道、续费逻辑全都在互相影响复杂度远超预期。如果靠手工整理几十家机构的信息很容易漏掉关键字段也很难形成可复用的分析框架。本文就把这套“辅导班市场调研”流程做成一个完整的 Python 数据分析实战项目从数据生成、清洗到可视化逐步拆解。无论你是想用技术手段做市场调研还是想掌握数据处理全流程都能直接参考。1. 背景与核心概念1.1 辅导班市场调研到底在调研什么辅导班市场调研并不是简单统计“哪家机构人数最多”而是一套围绕供给、需求、价格、师资、产品形态展开的综合分析。常见的调研维度包括机构基本信息名称、成立时间、规模、校区数量。课程产品信息课程类型学科辅导、素质教育、职业培训、兴趣班、班型一对一、小班、大班、价格区间。师资信息教师数量、全职/兼职比例、平均教龄。运营信息评价分数、招生渠道、续费情况。这些字段组合在一起才能看出不同细分市场的饱和度、价格分布和用户偏好。比如“学科辅导”和“少儿编程”的客单价分布完全不同如果放在同一个价格维度里去比较结论就会失真。1.2 为什么用技术手段做市场调研传统调研高度依赖人工记录、电话访谈和问卷回收数据量小、更新慢且很难做横向对比。用 Python 做市场调研可以把数据采集、存储、清洗、分析和可视化串联到一起自动化程度高可以定期更新数据。数据口径一致避免人工录入误差。复现性强换一个城市或品类只需要调整参数。方便后续建模比如用聚类分析划分价格带用回归分析找影响评分的关键因子。这篇教程不会去点评辅导班好坏而是把重点放在如何用数据处理技术完成一次结构化的市场调研。所有代码都基于公开的模拟数据演示真实场景中如果你需要采集真实机构信息请务必获得授权并遵守目标网站的 robots 协议和相关法律法规。1.3 核心技术与工具整个项目涉及以下核心库库作用requests发送 HTTP 请求获取网页或接口数据BeautifulSoup4解析 HTML 文档提取目标字段pandas数据清洗、处理、聚合和分析matplotlib绘制柱状图、饼图、箱线图等静态图表openpyxl将结果导出到 Excel 文件如果你只需要做离线数据分析也可以跳过 requests 和 BeautifulSoup直接读取 CSV、Excel 或数据库中的历史数据。本文会用模拟数据演示完整流程确保代码可以在本地直接运行。2. 环境准备与版本说明以 Python 3.8 及以上版本为例建议使用虚拟环境隔离项目依赖。搭建环境只需要三步2.1 准备 Python 环境如果你还没有安装 Python可以去 Python 官网下载稳定版本。安装时勾选“Add Python to PATH”然后在命令行中验证python --version如果看到类似Python 3.10.x的输出说明环境可用。2.2 创建虚拟环境在项目目录下执行mkdir tutor_market_research cd tutor_market_research python -m venv venv激活虚拟环境Windowsvenv\Scripts\activatemacOS / Linuxsource venv/bin/activate2.3 安装依赖库创建requirements.txt文件内容如下requests2.31.0 beautifulsoup44.12.3 pandas2.0.3 matplotlib3.7.2 openpyxl3.1.2然后执行pip install -r requirements.txt版本号可以根据你实际的环境调整如果遇到依赖冲突优先使用较新的稳定版本。下面所有代码示例都默认安装好上述依赖。3. 需求分析与方案设计3.1 业务问题拆解在写代码之前先把“辅导班市场调研”拆成一个个可计算的问题不同区域的机构数量分布如何课程主要分为哪几类占比是多少各类课程的价格区间和平均值是多少高评分机构在师资配置上有什么特点价格与评分之间是否存在明显相关性这些问题不需要构建复杂的机器学习模型用 pandas 分组聚合和 matplotlib 可视化就能完成。3.2 数据表设计为了便于统计我们设计一张宽表tutor_market.csv字段如下字段名含义org_name机构名称district所在区域course_type课程类型class_mode班型price平均客单价元/月teacher_count教师数量avg_teaching_years平均教龄年rating评分0-5student_count在读学员数量真实数据中你可能还需要增加“成立年份”“校区数量”“续费率”等字段。本文示例保留最核心的字段方便理解分析链路。3.3 技术方案流程整个流程可以用一张 ASCII 简图表示生成模拟数据 - 读取数据 - 数据清洗 - 聚合分析 - 可视化 - 输出报告每次分析前先检查数据是否存在缺失值、重复值和异常值。这是保证分析结论可靠的关键一步。4. 完整实战案例4.1 生成模拟数据为了演示完整流程我们先使用 Python 的random模块生成本地模拟数据。这一步是为了让你先掌握分析方法后期如果要接入真实爬虫只需要把“生成数据”这部分替换成爬虫解析逻辑即可。新建文件generate_data.py# 文件路径generate_data.py import random import csv random.seed(42) districts [海淀区, 朝阳区, 西城区, 东城区, 丰台区, 通州区] course_types [学科辅导, 少儿编程, 美术绘画, 音乐乐器, 体育体能, 语言培训] class_modes [一对一, 小班, 大班] def generate_org_name(index): prefixes [学而, 新东, 好未, 作业, 猿辅, 高途, 跟谁, 精锐, 卓越, 龙文] suffixes [教育, 学堂, 培训中心, 学习中心, 成长中心] return f{random.choice(prefixes)}{random.choice(suffixes)}_{index} def generate_data(num_rows600): rows [] for i in range(1, num_rows 1): district random.choice(districts) course_type random.choice(course_types) class_mode random.choice(class_modes) # 不同课程类型设置不同的价格范围 price_base { 学科辅导: 6000, 少儿编程: 4500, 美术绘画: 3500, 音乐乐器: 4000, 体育体能: 2500, 语言培训: 5000, } price int(price_base[course_type] random.uniform(-1000, 3000)) teacher_count random.randint(5, 80) avg_teaching_years round(random.uniform(1, 12), 1) rating round(random.uniform(3.0, 5.0), 2) student_count random.randint(50, 2000) rows.append([ generate_org_name(i), district, course_type, class_mode, max(price, 500), teacher_count, avg_teaching_years, rating, student_count, ]) with open(tutor_market.csv, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([org_name, district, course_type, class_mode, price, teacher_count, avg_teaching_years, rating, student_count]) writer.writerows(rows) if __name__ __main__: generate_data() print(模拟数据已生成tutor_market.csv)运行命令python generate_data.py运行后会在当前目录生成tutor_market.csv。这里使用utf-8-sig编码是为了让 Excel 直接打开时中文不乱码。4.2 数据读取与初步检查新建analysis.py先完成数据读取和基础检查# 文件路径analysis.py import pandas as pd df pd.read_csv(tutor_market.csv, encodingutf-8-sig) print(数据集形状, df.shape) print(\n前5行数据) print(df.head()) print(\n数据类型) print(df.dtypes) print(\n缺失值统计) print(df.isnull().sum()) print(\n描述性统计) print(df.describe())执行python analysis.py你会看到类似下面的输出数据集形状 (600, 9) 前5行数据 ... 缺失值统计 org_name 0 district 0 ... 描述性统计 price teacher_count ... count 600.0000 600.0000 ... mean 4792.3333 42.1200 ...如果某个字段存在缺失值需要根据具体情况处理。因为模拟数据没有缺失这里只是为了演示检查流程。4.3 数据清洗真实数据往往存在重复、格式不统一等问题。下面演示三种常见清洗操作。4.3.1 去重如果同一家机构被重复采集会导致统计结果失真# 检查重复机构名称 duplicate_mask df.duplicated(subset[org_name], keepFalse) print(存在重复的机构数量, duplicate_mask.sum()) # 去重保留第一条记录 df df.drop_duplicates(subset[org_name], keepfirst).reset_index(dropTrue)4.3.2 异常值处理价格、教师数量、评分都可能出现极端值。比如评分大于 5 或小于 0 的记录需要剔除价格明显低于市场正常水平的记录也值得怀疑# 过滤明显异常数据 df df[(df[rating] 0) (df[rating] 5)] df df[df[price] 0] df df[df[teacher_count] 0]4.3.3 标准化文本区域和课程类型可能存在前后空格、全半角不统一的问题df[district] df[district].str.strip() df[course_type] df[course_type].str.strip()4.4 数据聚合分析清洗完成后开始回答前面提出的业务问题。4.4.1 不同区域机构数量分布district_stats df[district].value_counts().reset_index() district_stats.columns [district, org_count] print(district_stats)4.4.2 课程类型占比course_stats df[course_type].value_counts() print(course_stats)4.4.3 各课程类型价格统计使用groupby聚合价格的平均值、中位数和四分位数price_group df.groupby(course_type)[price].agg([mean, median, min, max, count]) price_group price_group.round(2) print(price_group)这里mean是平均价格median是中位数。如果平均值明显大于中位数说明该课程类型存在少量高客单价机构拉高了整体均值。4.4.4 高评分机构画像筛选评分大于 4.5 的机构分析它们的师资配置high_rating df[df[rating] 4.5] high_rating_teacher high_rating[teacher_count].mean() all_teacher df[teacher_count].mean() print(f全部门店平均教师数{all_teacher:.1f}) print(f高评分机构平均教师数{high_rating_teacher:.1f})可以通过类似方式对比高评分机构和普通机构在教龄、学员数量上的差异。4.4.5 价格与评分的相关性使用 pandas 的corr方法计算相关系数corr_price_rating df[price].corr(df[rating]) print(f价格与评分相关系数{corr_price_rating:.3f})相关系数小于 0.2 时一般可以认为两者没有明显线性关系。这说明“贵不等于评分离”。4.5 数据可视化为了让分析结果更直观使用 matplotlib 生成三张核心图表。4.5.1 解决中文乱码首先需要配置中文字体否则图表中会出现方框。建议代码如下import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False不同操作系统可用的中文字体不同优先尝试SimHei如果没有可以换成Microsoft YaHei或PingFang SC。4.5.2 区域机构数量柱状图import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False district_order district_stats.sort_values(org_count, ascendingFalse) plt.figure(figsize(10, 6)) plt.bar(district_order[district], district_order[org_count], color#4C72B0) plt.title(各区域辅导班机构数量分布) plt.xlabel(区域) plt.ylabel(机构数量) plt.xticks(rotation45) plt.tight_layout() plt.savefig(district_bar.png, dpi150) plt.show()4.5.3 课程类型占比饼图plt.figure(figsize(8, 8)) plt.pie(course_stats.values, labelscourse_stats.index, autopct%.1f%%, startangle90) plt.title(辅导班课程类型占比) plt.axis(equal) plt.tight_layout() plt.savefig(course_pie.png, dpi150) plt.show()4.5.4 价格分布箱线图箱线图可以展示各课程类型价格的中位数和离散程度import matplotlib.pyplot as plt price_data [df[df[course_type] course][price].values for course in course_stats.index] plt.figure(figsize(12, 6)) plt.boxplot(price_data, labelscourse_stats.index, showmeansTrue) plt.title(不同课程类型价格分布) plt.xlabel(课程类型) plt.ylabel(价格元/月) plt.xticks(rotation30) plt.tight_layout() plt.savefig(price_boxplot.png, dpi150) plt.show()从箱线图中可以直观看到“体育体能”类课程价格低且集中而“学科辅导”类课程价格中位数高、离散程度大说明市场分层明显。4.6 导出分析报告最后把计算好的汇总表统一写入 Excel方便业务人员阅读with pd.ExcelWriter(market_report.xlsx, engineopenpyxl) as writer: df.to_excel(writer, sheet_name全量数据, indexFalse) district_stats.to_excel(writer, sheet_name区域分布, indexFalse) course_stats.to_excel(writer, sheet_name课程占比) price_group.to_excel(writer, sheet_name价格统计)运行后会在当前目录生成market_report.xlsx包含清洗后的全量数据和关键汇总表。5. 常见问题与排查思路5.1 常见报错现象问题现象常见原因解决思路读取 CSV 后中文乱码编码格式不匹配使用encodingutf-8-sig或先查看文件编码matplotlib 图表中文显示为方框系统缺少中文字体或未设置字体设置plt.rcParams[font.sans-serif]并确认字体已安装去重后数据量明显减少数据源本身存在重复记录检查重复字段是否选择合理避免误删不同校区groupby 聚合结果出现 NaN原始数据中存在缺失值先使用dropna或fillna处理缺失值boxplot 中文标签错乱字体配置未生效重启脚本并检查rcParams是否在创建图表前设置导出的 Excel 无法打开openpyxl 版本过低或文件被占用升级依赖关闭已打开的 Excel 文件5.2 数据量太大怎么处理如果调研范围覆盖多个城市数据量可能达到几十万行。pandas 虽然能处理中等规模数据但也会比较吃内存。建议按城市分表存储避免单文件过大。使用dtype参数指定字段类型减少内存占用。使用chunksize分块读取 CSV 文件。如果数据量达到百万级以上建议改用 DuckDB 或数据库存储。5.3 如何避免重复数据在生成数据或爬虫入库时给每个机构设置唯一业务主键。比如可以用“区域 机构名称 课程类型”作为联合主键看到新数据时先查重再写入。6. 最佳实践与工程建议6.1 合法合规采集数据如果你准备把模拟数据替换成真实数据一定要遵守以下原则只采集公开信息不触碰个人隐私。遵守目标网站的robots.txt协议。控制请求频率不要对目标服务器造成压力。如果目标网站有开放 API优先使用 API。数据仅用于个人学习和研究商业发布前必须获得授权。建议在爬虫代码中加入请求间隔import time import requests url https://example.com/api/org headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout10) time.sleep(1) # 控制请求频率6.2 形成可复用的分析工具不要把所有代码写在一个脚本里。建议按模块拆分project/ ├── data/ │ └── tutor_market.csv ├── src/ │ ├── data_clean.py │ ├── analysis.py │ └── visualize.py ├── output/ │ ├── market_report.xlsx │ └── *.png └── requirements.txt每个模块只做一件事后续想增加新分析维度时不需要改主流程。6.3 关注数据质量而非数据量市场调研结论是否可靠取决于数据质量。宁可数据量少也要保证每个字段口径一致。例如“价格”是月单价还是课包总价必须统一评分是综合评分还是教学质量评分也要明确。如果字段口径混乱再复杂的分析模型也救不回来。6.4 用多维度交叉验证结论单一维度很容易得到误导性结论。比如“某区域机构数量多”只能说明供给密集并不能说明市场竞争激烈因为还需要结合学员数量、客单价和机构规模来看。在做结论时尽量用两个以上维度交叉验证例如“高学员数量 低评分”可能意味着续费驱动型模式“高价格 高教师数”可能对应高端一对一服务。7. 总结与学习路线通过这次实战你已经掌握了一条完整的辅导班市场调研数据处理链路模拟数据生成、数据读取、数据清洗、聚合分析、可视化和报告导出。核心工具是 pandas 和 matplotlib这两者在数据分析领域应用极广。即使后续换一个行业、换一套业务字段这套处理思路依然适用。下一步可以继续深入研究用requestsBeautifulSoup采集真实公开数据把模拟数据替换成实际数据。使用pyecharts制作交互式地图按区域展示市场密度。用scikit-learn对机构做聚类分析自动划分高端市场、中端市场和低端市场。用statsmodels做回归分析探究评分、价格、教师数量之间的关系。在实际项目里最需要警惕的是数据口径不统一和采集过程不合规。建议每一次分析都保留原始数据副本并记录数据采集时间和来源。这样即使后续结论被挑战也能快速追溯。如果本文对你有帮助可以先收藏备用。后续需要接入真实网页采集时再按照 4.1 节的生成逻辑替换成对应的解析代码即可。
返回列表