ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

从零构建茶饮数据分析项目:Python+MySQL全流程实战

从零构建茶饮数据分析项目:Python+MySQL全流程实战 最近在辅导学员简历和面试时发现很多同学的项目经验部分比较单薄要么是“学生管理系统”要么是“电商平台”缺乏一些能体现数据分析思维和完整技术栈的实战项目。恰好新式茶饮行业数据公开且业务场景贴近生活非常适合作为数据分析的练手素材。本文将以“霸王茶姬”为分析对象带你从零开始完成一个涵盖数据获取、清洗、存储、分析到可视化的完整数据分析项目。这个项目不仅技术栈清晰Python MySQL 可视化库而且分析结论能直接体现你的业务洞察力做完完全可以写进简历为你的求职加分。我们将按照标准的数据分析流程进行首先模拟/获取数据并存入MySQL接着使用Python的Pandas进行数据清洗与探索性分析然后利用SQL进行多维数据查询最后通过Matplotlib和Pyecharts制作直观的可视化图表形成一份完整的分析报告。1. 项目背景与核心价值1.1 为什么选择茶饮行业数据分析新式茶饮行业是近年来消费领域的热点其数据具有以下特点非常适合数据分析学习数据维度丰富包含门店信息、订单数据、产品品类、销售时间、金额等便于进行多维分析。业务逻辑清晰涉及销量、客单价、复购率、热门产品等经典分析指标容易理解。贴近生活有代入感分析自己可能消费过的品牌能更好地理解数据背后的业务意义。技术栈通用用到的数据获取、处理、分析和可视化技术是数据分析师的通用技能。1.2 项目目标与产出通过本项目你将能够掌握一个完整的数据分析流程从数据到洞见的全链路实践。巩固Python数据分析核心库熟练使用Pandas进行数据操作使用Matplotlib/Seaborn/Pyecharts进行可视化。实践MySQL数据库操作包括建表、增删改查、复杂查询如分组聚合、多表连接。构建一份可展示的作品生成的分析报告和可视化图表可以直接用于证明你的数据分析能力。理解基础的业务分析指标如销售额趋势、产品贡献度、门店坪效等。1.3 技术栈介绍Python 3.8: 项目主要编程语言。Pandas NumPy: 用于数据清洗、处理和计算的核心库。Matplotlib Seaborn: 基础统计图表绘制。Pyecharts: 制作交互式、更美观的可视化图表可选但推荐用于报告。MySQL: 关系型数据库用于存储和管理我们的分析数据。SQLAlchemy / pymysql: Python连接MySQL的工具库。Jupyter Notebook / VSCode: 开发环境便于分步执行和展示。2. 环境准备与数据模拟2.1 开发环境搭建确保你的电脑上已经安装好以下软件Python环境推荐使用Anaconda管理Python环境和包避免依赖冲突。安装后创建本项目的专属环境。conda create -n tea_analysis python3.9 conda activate tea_analysisMySQL数据库从MySQL官网下载安装社区版。安装过程中记住你设置的root密码。也可以使用Docker快速部署一个MySQL实例。IDE/编辑器VSCode配合Python插件或PyCharm。数据分析前期探索强烈推荐使用Jupyter Notebook。2.2 安装必要的Python库在激活的虚拟环境中使用pip安装项目依赖。pip install pandas numpy matplotlib seaborn pyecharts pymysql sqlalchemy openpyxlopenpyxl是为了方便后续可能处理Excel格式的数据。2.3 模拟业务数据由于真实商业数据不易获得我们根据霸王茶姬的业务模式模拟生成一份数据集。这是数据分析中常见的步骤重点在于数据结构的合理性。我们主要模拟三张核心表门店信息表 (stores): 记录门店的基本属性。产品信息表 (products): 记录茶饮的产品信息。销售订单表 (orders): 记录每一笔交易这是事实表。以下Python代码用于生成模拟数据并保存为CSV文件方便后续导入数据库。import pandas as pd import numpy as np from datetime import datetime, timedelta # 设置随机种子保证结果可复现 np.random.seed(42) # 1. 生成门店信息 store_ids [fST{str(i).zfill(3)} for i in range(1, 21)] # 20家门店 cities [上海, 北京, 广州, 深圳, 杭州, 成都, 武汉, 南京] # 为门店分配城市一线城市门店多一些 store_cities np.random.choice(cities[:4], size15, replaceTrue).tolist() np.random.choice(cities[4:], size5, replaceTrue).tolist() np.random.shuffle(store_cities) stores_df pd.DataFrame({ store_id: store_ids, store_name: [f霸王茶姬{city}{i}店 for i, city in enumerate(store_cities, 1)], city: store_cities, open_date: pd.to_datetime(np.random.choice(pd.date_range(2022-01-01, 2023-01-01), 20)), area_sqm: np.random.randint(30, 100, 20) # 门店面积 }) print(门店信息样例) print(stores_df.head()) # 2. 生成产品信息 product_categories [原叶鲜奶茶, 清爽果茶, 芝士茗茶, 季节限定] products_data [] pid 1 for category in product_categories: for i in range(1, 4): # 每个品类3个产品 products_data.append({ product_id: fP{str(pid).zfill(3)}, product_name: f{category}{i}号, category: category, price: round(np.random.uniform(15, 25), 1) # 价格在15-25元之间 }) pid 1 products_df pd.DataFrame(products_data) print(\n产品信息样例) print(products_df.head()) # 3. 生成销售订单数据 (2023年全年) order_records [] order_id_base 10000 start_date datetime(2023, 1, 1) end_date datetime(2023, 12, 31) for day in range((end_date - start_date).days 1): current_date start_date timedelta(daysday) # 每天订单量有波动周末和节假日更多 is_weekend current_date.weekday() 5 daily_orders np.random.poisson(80 if is_weekend else 50) # 泊松分布模拟订单数 for _ in range(daily_orders): order_id order_id_base len(order_records) store_id np.random.choice(store_ids) product_id np.random.choice(products_df[product_id].values) # 查找产品价格 product_price products_df.loc[products_df[product_id] product_id, price].values[0] quantity np.random.randint(1, 4) # 每单购买1-3杯 # 订单时间在当天内随机 order_time current_date timedelta(hoursnp.random.randint(10, 22), minutesnp.random.randint(0, 60), secondsnp.random.randint(0, 60)) order_records.append({ order_id: order_id, store_id: store_id, product_id: product_id, quantity: quantity, unit_price: product_price, order_time: order_time }) # 控制数据量生成约3万条订单记录 if len(order_records) 30000: break orders_df pd.DataFrame(order_records) orders_df[total_amount] orders_df[quantity] * orders_df[unit_price] print(f\n共生成{len(orders_df)}条订单记录。) print(orders_df.head()) # 4. 保存模拟数据到CSV文件 stores_df.to_csv(simulated_stores.csv, indexFalse, encodingutf-8-sig) products_df.to_csv(simulated_products.csv, indexFalse, encodingutf-8-sig) orders_df.to_csv(simulated_orders.csv, indexFalse, encodingutf-8-sig) print(\n模拟数据已保存为CSV文件。)运行这段代码将在当前目录生成三个CSV文件simulated_stores.csv,simulated_products.csv,simulated_orders.csv。3. 数据库设计与数据入库3.1 MySQL数据库连接与创建首先登录MySQL创建一个新的数据库用于本项目。-- 登录MySQL (命令行或MySQL Workbench) -- mysql -u root -p -- 创建数据库 CREATE DATABASE IF NOT EXISTS royaltea_analysis DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 使用数据库 USE royaltea_analysis;3.2 数据表结构设计根据我们的数据模型设计三张表。注意选择合适的数据类型和约束。-- 1. 门店信息表 CREATE TABLE stores ( store_id VARCHAR(10) NOT NULL PRIMARY KEY COMMENT 门店编号, store_name VARCHAR(50) NOT NULL COMMENT 门店名称, city VARCHAR(20) NOT NULL COMMENT 所在城市, open_date DATE COMMENT 开业日期, area_sqm INT COMMENT 门店面积(平方米) ) COMMENT门店信息表; -- 2. 产品信息表 CREATE TABLE products ( product_id VARCHAR(10) NOT NULL PRIMARY KEY COMMENT 产品编号, product_name VARCHAR(50) NOT NULL COMMENT 产品名称, category VARCHAR(20) NOT NULL COMMENT 产品类别, price DECIMAL(8,2) NOT NULL COMMENT 单价 ) COMMENT产品信息表; -- 3. 订单销售表 (事实表) CREATE TABLE orders ( order_id INT NOT NULL PRIMARY KEY COMMENT 订单ID, store_id VARCHAR(10) NOT NULL COMMENT 门店编号, product_id VARCHAR(10) NOT NULL COMMENT 产品编号, quantity INT NOT NULL COMMENT 销售数量, unit_price DECIMAL(8,2) NOT NULL COMMENT 产品单价, total_amount DECIMAL(10,2) GENERATED ALWAYS AS (quantity * unit_price) STORED COMMENT 订单金额, -- MySQL 5.7 支持生成列 order_time DATETIME NOT NULL COMMENT 订单时间, INDEX idx_store_id (store_id), INDEX idx_product_id (product_id), INDEX idx_order_time (order_time), CONSTRAINT fk_orders_store FOREIGN KEY (store_id) REFERENCES stores (store_id), CONSTRAINT fk_orders_product FOREIGN KEY (product_id) REFERENCES products (product_id) ) COMMENT销售订单表;设计要点orders表中的total_amount使用了生成列确保金额由数量quantity和单价unit_price自动计算避免数据不一致。为orders表的外键字段和常用的查询字段如order_time创建了索引以提升查询性能。设置了外键约束保证数据的参照完整性。3.3 使用Python将CSV数据导入MySQL我们将使用pandas读取CSV并通过SQLAlchemy库将数据写入MySQL数据库。import pandas as pd from sqlalchemy import create_engine # 配置数据库连接信息 # 格式mysqlpymysql://用户名:密码主机:端口/数据库名 db_connection_str mysqlpymysql://root:your_passwordlocalhost:3306/royaltea_analysis engine create_engine(db_connection_str) # 读取CSV文件 stores_df pd.read_csv(simulated_stores.csv) products_df pd.read_csv(simulated_products.csv) orders_df pd.read_csv(simulated_orders.csv) # 将DataFrame写入MySQL对应的表 # if_existsreplace表示如果表存在则替换append表示追加 try: stores_df.to_sql(namestores, conengine, if_existsreplace, indexFalse) products_df.to_sql(nameproducts, conengine, if_existsreplace, indexFalse) # 注意orders表有生成列我们只导入基础列 orders_df[[order_id, store_id, product_id, quantity, unit_price, order_time]].to_sql( nameorders, conengine, if_existsreplace, indexFalse ) print(数据成功导入MySQL数据库) except Exception as e: print(f数据导入失败: {e})重要提示请将db_connection_str中的your_password和localhost:3306替换为你自己的MySQL密码和主机端口。4. 数据分析与SQL查询实践数据入库后我们可以开始进行分析。首先使用SQL进行一些基础的数据概览和聚合分析。4.1 基础数据概览-- 查看数据量 SELECT stores AS table_name, COUNT(*) AS row_count FROM stores UNION ALL SELECT products, COUNT(*) FROM products UNION ALL SELECT orders, COUNT(*) FROM orders; -- 查看订单金额统计 SELECT COUNT(*) AS order_count, SUM(total_amount) AS total_sales, AVG(total_amount) AS avg_order_value, MIN(order_time) AS first_order, MAX(order_time) AS last_order FROM orders;4.2 销售业绩分析-- 1. 总销售额趋势按月 SELECT DATE_FORMAT(order_time, %Y-%m) AS month, COUNT(*) AS order_count, SUM(total_amount) AS monthly_sales, AVG(total_amount) AS avg_order_value FROM orders GROUP BY DATE_FORMAT(order_time, %Y-%m) ORDER BY month; -- 2. 各城市销售额排名 SELECT s.city, COUNT(DISTINCT o.store_id) AS store_count, COUNT(*) AS order_count, SUM(o.total_amount) AS total_sales, SUM(o.total_amount) / COUNT(DISTINCT o.store_id) AS sales_per_store -- 店均销售额 FROM orders o JOIN stores s ON o.store_id s.store_id GROUP BY s.city ORDER BY total_sales DESC; -- 3. 门店销售额Top 10 SELECT s.store_id, s.store_name, s.city, COUNT(*) AS order_count, SUM(o.total_amount) AS total_sales FROM orders o JOIN stores s ON o.store_id s.store_id GROUP BY s.store_id, s.store_name, s.city ORDER BY total_sales DESC LIMIT 10;4.3 产品分析-- 1. 各类别产品销售额和销量占比 SELECT p.category, COUNT(*) AS sales_volume, SUM(o.quantity) AS cup_sold, SUM(o.total_amount) AS sales_amount, ROUND(SUM(o.total_amount) / (SELECT SUM(total_amount) FROM orders) * 100, 2) AS sales_ratio FROM orders o JOIN products p ON o.product_id p.product_id GROUP BY p.category ORDER BY sales_amount DESC; -- 2. 最畅销的单品Top 10 SELECT p.product_id, p.product_name, p.category, SUM(o.quantity) AS total_cup_sold, SUM(o.total_amount) AS total_sales_amount FROM orders o JOIN products p ON o.product_id p.product_id GROUP BY p.product_id, p.product_name, p.category ORDER BY total_cup_sold DESC LIMIT 10;4.4 利用Python进行更灵活的分析虽然SQL能完成很多聚合但更复杂的转换、计算和可视化仍需借助Python。下面我们将数据读入Pandas进行深入分析。import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sqlalchemy import create_engine plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号 # 重新连接数据库读取数据到DataFrame engine create_engine(mysqlpymysql://root:your_passwordlocalhost:3306/royaltea_analysis) # 使用SQL查询直接读取所需数据 sales_trend_sql SELECT DATE_FORMAT(order_time, %Y-%m) AS month, SUM(total_amount) AS monthly_sales FROM orders GROUP BY DATE_FORMAT(order_time, %Y-%m) ORDER BY month sales_trend_df pd.read_sql(sales_trend_sql, engine) city_sales_sql SELECT s.city, SUM(o.total_amount) AS total_sales FROM orders o JOIN stores s ON o.store_id s.store_id GROUP BY s.city ORDER BY total_sales DESC city_sales_df pd.read_sql(city_sales_sql, engine) product_sales_sql SELECT p.category, p.product_name, SUM(o.quantity) as cups_sold, SUM(o.total_amount) as sales_amt FROM orders o JOIN products p ON o.product_id p.product_id GROUP BY p.category, p.product_name product_sales_df pd.read_sql(product_sales_sql, engine) print(月度销售趋势数据) print(sales_trend_df.head()) print(\n城市销售数据) print(city_sales_df.head()) print(\n产品销售数据) print(product_sales_df.head())5. 数据可视化呈现可视化是数据分析结果呈现的关键。我们将使用Matplotlib/Seaborn制作静态图表并使用Pyecharts制作交互式图表。5.1 月度销售额趋势折线图# 使用Matplotlib plt.figure(figsize(12, 6)) plt.plot(sales_trend_df[month], sales_trend_df[monthly_sales], markero, linewidth2) plt.title(霸王茶姬2023年月度销售额趋势, fontsize15) plt.xlabel(月份) plt.ylabel(销售额元) plt.grid(True, linestyle--, alpha0.7) plt.xticks(rotation45) plt.tight_layout() plt.show() # 使用Pyecharts交互式 from pyecharts.charts import Line from pyecharts import options as opts line ( Line() .add_xaxis(sales_trend_df[month].tolist()) .add_yaxis(月度销售额, sales_trend_df[monthly_sales].round(2).tolist(), markpoint_optsopts.MarkPointOpts(data[opts.MarkPointItem(type_max)]), label_optsopts.LabelOpts(is_showFalse)) .set_global_opts( title_optsopts.TitleOpts(title霸王茶姬2023年月度销售额趋势), tooltip_optsopts.TooltipOpts(triggeraxis), xaxis_optsopts.AxisOpts(name月份, axislabel_optsopts.LabelOpts(rotate45)), yaxis_optsopts.AxisOpts(name销售额元), ) ) line.render_notebook() # 在Jupyter中显示 # line.render(monthly_sales_trend.html) # 保存为HTML文件5.2 城市销售额分布柱状图与饼图# 柱状图 - 城市销售额排名 plt.figure(figsize(10, 6)) bars plt.bar(city_sales_df[city], city_sales_df[total_sales], colorsns.color_palette(husl, len(city_sales_df))) plt.title(各城市销售额对比, fontsize15) plt.xlabel(城市) plt.ylabel(销售额元) plt.xticks(rotation45) # 在柱子上方显示数值 for bar in bars: height bar.get_height() plt.text(bar.get_x() bar.get_width()/2., height 0.1, f{height:,.0f}, hacenter, vabottom, fontsize9) plt.tight_layout() plt.show() # 饼图 - 销售额占比 (使用Pyecharts更美观) from pyecharts.charts import Pie pie_data [(row[city], row[total_sales]) for _, row in city_sales_df.iterrows()] pie ( Pie() .add(, pie_data, radius[30%, 70%]) .set_global_opts( title_optsopts.TitleOpts(title各城市销售额占比), legend_optsopts.LegendOpts(orientvertical, pos_top15%, pos_left2%), ) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c} ({d}%))) ) pie.render_notebook()5.3 产品类别销售贡献分析# 按产品类别聚合 category_summary product_sales_df.groupby(category).agg({ cups_sold: sum, sales_amt: sum }).sort_values(sales_amt, ascendingFalse).reset_index() # 绘制销售额与销量双轴图 fig, ax1 plt.subplots(figsize(10, 6)) color tab:blue ax1.set_xlabel(产品类别) ax1.set_ylabel(销售额元, colorcolor) bars ax1.bar(category_summary[category], category_summary[sales_amt], colorcolor, alpha0.6, label销售额) ax1.tick_params(axisy, labelcolorcolor) ax1.set_xticklabels(category_summary[category], rotation45) ax2 ax1.twinx() color tab:red ax2.set_ylabel(销量杯, colorcolor) line ax2.plot(category_summary[category], category_summary[cups_sold], colorcolor, markero, linewidth2, label销量) ax2.tick_params(axisy, labelcolorcolor) # 添加图例 lines, labels ax1.get_legend_handles_labels() lines2, labels2 ax2.get_legend_handles_labels() ax2.legend(lines lines2, labels labels2, locupper left) plt.title(各产品类别销售额与销量对比, fontsize15) fig.tight_layout() plt.show()5.4 门店坪效分析进阶指标坪效是零售业关键指标指每平方米面积产生的销售额。# 计算每家门店的总销售额和坪效 store_performance_sql SELECT s.store_id, s.store_name, s.city, s.area_sqm, COUNT(o.order_id) AS order_count, SUM(o.total_amount) AS total_sales, SUM(o.total_amount) / s.area_sqm AS sales_per_sqm FROM stores s LEFT JOIN orders o ON s.store_id o.store_id GROUP BY s.store_id, s.store_name, s.city, s.area_sqm ORDER BY sales_per_sqm DESC store_performance_df pd.read_sql(store_performance_sql, engine) print(门店坪效分析Top 10:) print(store_performance_df.head(10)) # 可视化坪效与面积的关系 plt.figure(figsize(10, 6)) scatter plt.scatter(store_performance_df[area_sqm], store_performance_df[sales_per_sqm], cstore_performance_df[total_sales], s100, alpha0.6, cmapviridis) plt.colorbar(scatter, label总销售额元) plt.xlabel(门店面积 (平方米)) plt.ylabel(坪效 (元/平方米)) plt.title(门店面积与坪效关系散点图气泡大小代表总销售额, fontsize14) plt.grid(True, linestyle--, alpha0.5) plt.tight_layout() plt.show()6. 项目总结与业务洞察通过以上完整流程我们不仅实践了技术还得出了一些有意义的业务结论销售趋势从月度趋势图可以清晰看到销售旺季和淡季例如夏季6-8月和节假日如10月可能出现销售高峰。这为库存管理和营销活动安排提供了依据。区域表现上海、北京等一线城市贡献了主要销售额但部分新一线城市如杭州、成都的单店销售效率坪效可能更高值得深入分析其运营模式。产品策略“原叶鲜奶茶”和“芝士茗茶”可能是核心营收品类而“季节限定”虽然单价高但销量占比可能较低需评估其营销价值。门店效率坪效分析有助于识别高效门店和低效门店。面积小的门店未必业绩差运营效率是关键。可对低坪效门店进行诊断优化产品组合或运营策略。7. 常见问题与排查思路在完成项目的过程中你可能会遇到以下问题问题现象可能原因解决思路连接MySQL失败提示Access denied1. 用户名或密码错误。2. 用户权限不足无法访问指定数据库。3. MySQL服务未启动。1. 检查连接字符串中的用户名和密码。2. 使用mysql -u root -p登录执行GRANT ALL PRIVILEGES ON royaltea_analysis.* TO your_userlocalhost;。3. 在服务中启动MySQL或使用sudo systemctl start mysql。pandas.to_sql写入速度慢默认是单条插入数据量大时效率低。使用if_existsreplace或append时可设置methodmulti或使用chunksize参数分块写入。对于大量数据考虑先用pd.to_csv导出再用MySQL的LOAD DATA INFILE命令导入。图表中文显示为方框系统或Matplotlib未配置中文字体。如本文代码所示在绘图前设置plt.rcParams[font.sans-serif]。也可以指定具体字体路径。外键约束错误无法插入订单数据订单中的store_id或product_id在对应的主表中不存在。确保先导入stores和products表的数据再导入orders表。检查模拟数据中ID的对应关系是否正确。Pyecharts图表在Jupyter中不显示Jupyter环境未正确配置或未调用render_notebook()。确保已安装pyecharts和jupyter。在Jupyter cell中直接调用图表对象的render_notebook()方法。常规脚本中则用render(“filename.html”)生成文件。查询速度慢特别是关联查询数据量增大后没有索引的列进行条件过滤或连接会变慢。如我们建表时所示为经常用于WHERE、JOIN、ORDER BY的字段创建索引如order_time,store_id。使用EXPLAIN语句分析查询计划。8. 最佳实践与项目扩展建议8.1 数据分析项目最佳实践数据备份在对原始数据进行任何清洗或转换操作前先备份。可以使用df.to_csv(‘backup.csv’)。代码可复现在脚本开头设置随机种子如np.random.seed(42)并使用版本控制Git管理代码和数据清洗步骤。模块化设计将数据获取、清洗、分析、可视化等功能写成独立的函数或类提高代码可读性和复用性。注释与文档在关键步骤和复杂逻辑处添加注释。可以编写一个README.md说明项目背景、运行方法和主要结论。环境隔离使用虚拟环境如conda, venv管理项目依赖避免包冲突。8.2 如何将本项目写入简历在简历的“项目经验”部分可以这样描述项目名称新式茶饮品牌霸王茶姬销售数据分析系统技术栈Python (Pandas, NumPy, Matplotlib, Pyecharts), MySQL, SQLAlchemy项目职责模拟生成包含门店、产品、订单的完整业务数据集设计并创建了规范的MySQL数据库表结构。使用Python进行数据清洗与预处理并通过SQL完成多维度业务查询如销售额趋势、城市排名、产品畅销榜。利用Matplotlib与Pyecharts构建可视化看板直观展示月度销售趋势、地域分布、产品贡献度及门店坪效等关键指标。基于分析结果提炼出“一线城市为营收主力”、“原叶鲜奶茶为核心品类”、“需关注门店坪效优化”等业务洞察形成分析报告。项目成果建立了一套从数据模拟到可视化分析的标准流程提升了通过数据驱动业务决策的能力。8.3 项目扩展方向提升难度要让项目经验更出彩可以尝试以下扩展实时数据编写一个简单的脚本每天定时模拟生成新增订单数据并更新到数据库和可视化看板中模拟实时数据看板。Web可视化使用Flask或Streamlit框架将分析结果和图表集成到一个简单的Web仪表盘中实现交互式查询。用户画像在订单数据中增加模拟的“用户ID”分析复购率、消费间隔、用户生命周期价值CLV等。预测模型使用时间序列模型如Prophet或ARIMA基于历史销售额预测未来一段时间的销量。关联分析使用Apriori或FP-growth算法分析订单中产品的关联规则如买了A产品的顾客很可能同时买B产品。
返回列表