# douyin-analytics **Repository Path**: ghostroot/douyin-analytics ## Basic Information - **Project Name**: douyin-analytics - **Description**: - 项目性质 :FastAPI数据可视化项目 - 数据规模 :173万条抖音用户行为数据 - 技术栈 :前端ECharts+jQuery,后端FastAPI+Pandas - 功能规模 :26个图表,20+API接口,4个分析页面 - 部署特性 :一键部署脚本 - 适用场景 :数据分析可视化学习 - **Primary Language**: Python - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-23 - **Last Updated**: 2026-04-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 抖音数据分析大屏 —— 零基础到完整项目教程 > **设计原则:零跳跃学习** > > 传统路线的问题:知识点A → 知识点C(发现需要B,回头补B)→ 知识点D(发现需要前置知识X) > > 本路线的目标:知识点A → 知识点B(A的自然延伸)→ 知识点C(B的必然发展)→ 知识点D(C的合理进阶) ---     ## 目录 - [第1章 从问题出发——为什么需要数据分析大屏](#第1章-从问题出发为什么需要数据分析大屏) - [第2章 认识数据——理解我们的原材料](#第2章-认识数据理解我们的原材料) - [第3章 系统架构——从全局看项目](#第3章-系统架构从全局看项目) - [第4章 技术选型——为什么是这些工具](#第4章-技术选型为什么是这些工具) - [第5章 后端基础——搭建数据服务](#第5章-后端基础搭建数据服务) - [第6章 数据分析实战——从数据到洞察](#第6章-数据分析实战从数据到洞察) - [第7章 前端基础——HTML与CSS](#第7章-前端基础html与css) - [第8章 CSS组件化设计](#第8章-css组件化设计) - [第9章 JavaScript组件化架构](#第9章-javascript组件化架构) - [第10章 图表组件开发](#第10章-图表组件开发) - [第11章 页面组装与集成](#第11章-页面组装与集成) - [第12章 部署与运维](#第12章-部署与运维) --- # 第1章 从问题出发——为什么需要数据分析大屏 ## 1.1 什么是数据分析 想象你开了一家奶茶店。每天有几百个顾客来买奶茶,你脑子里会有很多问题: - 今天卖了多少杯? - 哪种口味最受欢迎? - 什么时间段客人最多? - 哪些客人经常来? 如果你只有一个小本子记录每天的订单,翻半天也找不到答案。**数据分析就是把杂乱的数据变成有用的信息的过程**。 在互联网时代,抖音每天产生海量的用户行为数据——谁看了什么视频、看了多久、有没有点赞、在哪个城市……这些数据如果只是一行行存在文件里,就像那本厚厚的订单本,毫无意义。只有通过**分析**和**可视化**,数据才能告诉我们:用户喜欢什么、什么时候最活跃、哪些内容质量高。 ## 1.2 为什么需要可视化 看两组信息,哪个更容易理解? **纯数字版本:** ``` 北京用户数:285,432 上海用户数:243,567 广州用户数:198,234 深圳用户数:176,890 杭州用户数:145,678 ``` **柱状图版本:** 一个简单的柱状图,北京最高,依次递减,一眼就能看出差距。 人类大脑处理图形的速度比处理文字快6万倍。**数据可视化就是把数字变成图形,让人类的大脑能"一眼看懂"**。 ## 1.3 什么是数据大屏 你可能在公司大堂、指挥中心、商场见过那种超大屏幕,上面有各种图表、数字、地图在实时跳动——这就是**数据大屏**。 数据大屏的特点: - **全屏展示**:占满整个屏幕,没有滚动条 - **多图表同时呈现**:一屏展示多个维度的数据 - **暗色主题**:深色背景减少视觉疲劳,适合长时间观看 - **实时或准实时更新**:数据变化时图表自动刷新 ## 1.4 本项目要解决什么问题 本项目是一个**抖音数据分析大屏**,要回答以下核心问题: | 问题 | 对应的分析维度 | |------|---------------| | 平台整体情况如何? | 概览仪表盘(用户数、视频数、点赞数、完播率) | | 用户有什么行为特征? | 用户分析(活跃用户、完播行为、时间模式) | | 内容质量怎么样? | 内容质量(音乐热度、作者影响力、时长分布) | | 用户和内容在空间时间上如何分布? | 时空分布(城市地图、时间趋势、工作日vs周末) | 这四个问题,对应大屏的四个页面。每个页面包含多个图表,从不同角度回答同一个大问题。 ```mermaid graph TD A[抖音数据] --> B[概览仪表盘] A --> C[用户分析] A --> D[内容质量] A --> E[时空分布] B --> B1[KPI卡片] B --> B2[每日点赞趋势] B --> B3[热门音乐排行] B --> B4[作者活跃度] B --> B5[渠道分布] B --> B6[城市分布] B --> B7[小时趋势] B --> B8[一周模式] C --> C1[活跃用户排名] C --> C2[完播行为] C --> C3[城市热力] C --> C4[时间模式] C --> C5[渠道偏好] C --> C6[行为雷达] D --> D1[音乐词云] D --> D2[音乐参与度] D --> D3[作者影响力] D --> D4[时长分布] D --> D5[渠道质量] D --> D6[点赞分布] D --> D7[完播质量] E --> E1[城市地图] E --> E2[城市-音乐桑基图] E --> E3[分钟级趋势] E --> E4[工作日vs周末] E --> E5[时间-城市热力] ``` --- # 第2章 认识数据——理解我们的原材料 ## 2.1 数据从哪里来 本项目的数据来自一个CSV文件:`data/douyin_dataset.csv`,包含约**173万条**用户行为记录。 CSV(Comma-Separated Values,逗号分隔值)是一种最简单的数据存储格式,就像一张Excel表格,每行一条记录,每列一个字段,列与列之间用逗号隔开。 ## 2.2 CSV文件格式解析 打开CSV文件,你会看到类似这样的内容: ```csv uid,user_city,item_id,author_id,item_city,channel,finish,like,music_id,duration_time,real_time,H,date 12345,110000,67890,54321,310000,1,1,0,88888,15,12.3,20,2024-01-15 67890,440100,11111,22222,110000,2,0,1,99999,8,7.5,14,2024-01-15 ``` 第一行是**表头**(字段名),后面的每一行是一条**记录**(一次用户行为)。 ## 2.3 逐字段理解数据集 数据集有14个字段,我们逐个理解: | 字段名 | 含义 | 数据类型 | 示例值 | 解读 | |--------|------|---------|--------|------| | `uid` | 用户ID | 整数 | 12345 | 唯一标识一个用户 | | `user_city` | 用户所在城市编码 | 整数 | 110000 | 110000=北京,440100=广州 | | `item_id` | 视频ID | 整数 | 67890 | 唯一标识一个视频 | | `author_id` | 视频作者ID | 整数 | 54321 | 唯一标识一个作者 | | `item_city` | 视频发布城市编码 | 整数 | 310000 | 视频作者所在城市 | | `channel` | 渠道编号 | 整数 | 1 | 视频所属的内容渠道 | | `finish` | 是否完播 | 0或1 | 1 | 1=看完整个视频,0=没看完 | | `like` | 是否点赞 | 0或1 | 0 | 1=点了赞,0=没点赞 | | `music_id` | 背景音乐ID | 整数 | 88888 | 视频使用的背景音乐 | | `duration_time` | 视频时长(秒) | 整数 | 15 | 视频总时长15秒 | | `real_time` | 实际观看时长(秒) | 浮点数 | 12.3 | 用户实际看了12.3秒 | | `H` | 观看小时 | 整数 | 20 | 晚上8点观看 | | `date` | 观看日期 | 字符串 | 2024-01-15 | 2024年1月15日 | ### 关键理解:每条记录代表什么? 每条记录代表**一个用户观看一个视频的行为**。它回答了: - **谁**看了?(uid) - **谁**发布的?(author_id) - 看了**什么**?(item_id) - 在**哪里**看的?(user_city) - 视频来自**哪里**?(item_city) - 通过什么**渠道**看到的?(channel) - **看完**了吗?(finish) - **点赞**了吗?(like) - 什么**音乐**?(music_id) - 视频多**长**?(duration_time) - 实际看了多**久**?(real_time) - 什么**时间**看的?(H、date) ## 2.4 数据能告诉我们什么 有了这些字段,我们可以回答很多问题: ```mermaid graph LR subgraph 原始字段 A1[uid] A2[user_city] A3[item_id] A4[author_id] A5[channel] A6[finish] A7[like] A8[music_id] A9[duration_time] A10[H] A11[date] end subgraph 可回答的问题 B1[有多少独立用户?] B2[哪些城市用户最多?] B3[哪些作者最活跃?] B4[哪个渠道最受欢迎?] B5[完播率是多少?] B6[总点赞数是多少?] B7[哪首音乐最火?] B8[视频时长分布?] B9[几点最活跃?] B10[每日趋势?] end A1 --> B1 A2 --> B2 A4 --> B3 A5 --> B4 A6 --> B5 A7 --> B6 A8 --> B7 A9 --> B8 A10 --> B9 A11 --> B10 ``` **关键洞察**:数据分析的本质就是**对原始字段进行聚合运算**——计数(count)、求和(sum)、平均(mean)、分组(groupby)。 --- # 第3章 系统架构——从全局看项目 ## 3.1 什么是前后端分离 在理解项目架构之前,先理解一个核心概念:**前后端分离**。 想象一家餐厅: - **后厨**(后端):负责处理食材,做出菜品。顾客看不到后厨的运作。 - **前厅**(前端):负责展示菜品,让顾客看到和选择。顾客只和前厅打交道。 - **服务员**(API接口):前厅告诉服务员要什么菜,服务员去后厨取,再端给前厅。 对应到我们的项目: - **后端**:Python程序,读取CSV数据,计算分析结果 - **前端**:网页,展示图表和数字 - **API接口**:后端提供的URL地址,前端通过它获取数据 ```mermaid sequenceDiagram participant 浏览器 as 前端(浏览器) participant API as 后端API(FastAPI) participant CSV as 数据文件(CSV) 浏览器->>API: 1. 请求 /api/overview API->>CSV: 2. 读取 douyin_dataset.csv CSV-->>API: 3. 返回原始数据 API->>API: 4. Pandas聚合计算 API-->>浏览器: 5. 返回JSON结果 浏览器->>浏览器: 6. ECharts渲染图表 ``` ## 3.2 本项目的架构设计 本项目采用经典的**三层架构**: ```mermaid graph TB subgraph 展示层["展示层(前端)"] direction TB HTML[HTML 页面结构] CSS[CSS 样式与布局] JS[JavaScript 交互逻辑] ECharts[ECharts 图表渲染] end subgraph 接口层["接口层(API)"] direction TB FastAPI[FastAPI 路由] CORS[CORS 跨域配置] Response[统一响应包装] end subgraph 数据层["数据层(后端)"] direction TB Pandas[Pandas 数据处理] CSV[CSV 文件存储] end 展示层 -->|AJAX请求| 接口层 接口层 -->|读取数据| 数据层 数据层 -->|JSON响应| 接口层 接口层 -->|JSON数据| 展示层 ``` ### 架构的关键决策 | 决策 | 选择 | 原因 | |------|------|------| | 数据存储 | CSV文件 | 无需数据库,简单直接 | | 数据处理 | 每次请求实时读取 | 数据不变,无需缓存 | | 前后端通信 | RESTful API + JSON | 标准化,前端易消费 | | 页面模式 | SPA单页应用 | 切换流畅,无页面刷新 | ## 3.3 数据流转全过程 从用户打开网页到看到图表,数据经历了完整的流转: ```mermaid flowchart TD A[用户打开浏览器] --> B[访问 http://localhost:8080] B --> C[FastAPI重定向到 /static/index.html] C --> D[浏览器加载HTML] D --> E[加载CSS样式文件] D --> F[加载JavaScript文件] E --> G[页面渲染完成] F --> G G --> H[PageNavigation初始化] H --> I[激活概览页面] I --> J[创建图表组件实例] J --> K[各组件发起AJAX请求] K --> L[FastAPI处理请求] L --> M[Pandas读取CSV] M --> N[Pandas聚合计算] N --> O[返回JSON数据] O --> P[前端接收数据] P --> Q[ECharts渲染图表] Q --> R[用户看到完整大屏] style A fill:#4d96ff,color:#fff style R fill:#6bcb77,color:#fff style K fill:#ffd93d,color:#333 style O fill:#ffd93d,color:#333 ``` ## 3.4 目录结构详解 ``` douyin-analytics/ ├── src/ # 后端代码目录 │ ├── __init__.py # Python包标识文件(空文件) │ └── main.py # 后端唯一入口:所有API路由 ├── data/ # 数据目录 │ └── douyin_dataset.csv # 数据源文件(173万条记录) ├── static/ # 前端静态资源目录 │ ├── index.html # SPA唯一入口HTML │ ├── css/ # 样式文件 │ │ ├── base.css # CSS变量、全局重置、动画 │ │ ├── layout.css # Grid/Flexbox布局 │ │ ├── components/ # 组件样式 │ │ │ ├── nav.css # 导航栏组件 │ │ │ └── loading.css # 加载动画组件 │ │ └── pages/ # 页面样式 │ │ ├── overview.css # 概览页 │ │ ├── user-analysis.css │ │ ├── content-quality.css │ │ └── spatiotemporal.css │ ├── js/ # JavaScript文件 │ │ ├── jquery.min.js # jQuery 4.0.0 │ │ ├── echarts.min.js # ECharts 6 │ │ ├── lib/ # 公共工具库 │ │ │ ├── page-navigation.js # 页面导航管理器 │ │ │ ├── loading-manager.js # 加载动画管理器 │ │ │ ├── resize-manager.js # 尺寸管理器 │ │ │ └── echarts-config.js # ECharts主题配置 │ │ ├── overview/ # 概览页图表 │ │ ├── user-analysis/ # 用户分析页图表 │ │ ├── content-quality/ # 内容质量页图表 │ │ └── spatiotemporal/ # 时空分布页图表 │ └── geo/ # 地图数据 │ └── china_full.json # 中国地图GeoJSON ├── douyin-analytics.service # systemd服务文件 ├── requirements.txt # Python依赖清单 ├── install.sh # 安装脚本 └── manage.sh # 管理脚本 ``` **目录设计原则**: - **按功能分层**:CSS分为base/layout/components/pages四层 - **按页面分模块**:JS图表按页面分目录,每个图表一个文件 - **公共代码抽取**:lib/存放所有页面共享的工具类 --- # 第4章 技术选型——为什么是这些工具 ## 4.1 Python与FastAPI **为什么用Python?** - 数据分析领域最流行的语言 - Pandas库让数据处理变得简单 - 语法简洁,适合初学者 **为什么用FastAPI而不是Flask/Django?** - 性能极高(基于异步ASGI) - 自动生成API文档 - 代码量少,一个文件就能写完所有接口 - 原生支持异步,适合数据密集型应用 ## 4.2 Pandas数据处理 Pandas是Python的数据分析库,核心概念是**DataFrame**——你可以把它想象成一张Excel表格: ```python # 读取CSV → 得到DataFrame(就像打开Excel) df = pd.read_csv('douyin_dataset.csv') # DataFrame的操作就像Excel的公式: df['uid'].nunique() # = COUNTA(去重uid列) df['like'].sum() # = SUM(like列) df.groupby('user_city').size() # = 数据透视表按城市计数 ``` ## 4.3 HTML/CSS/JavaScript 这是前端的三板斧: | 技术 | 作用 | 类比 | |------|------|------| | HTML | 页面结构 | 房子的骨架(墙、门、窗) | | CSS | 页面样式 | 房子的装修(颜色、大小、位置) | | JavaScript | 页面交互 | 房子的电器(开关、遥控) | ## 4.4 ECharts可视化 ECharts是百度开源的图表库,提供几十种图表类型。选择它的原因: - 中文文档完善 - 图表类型丰富(折线图、柱状图、饼图、地图、雷达图……) - 主题可定制 - 性能优秀,能处理大数据量 ## 4.5 jQuery与AJAX **为什么用jQuery?** - 简化DOM操作和AJAX请求 - 代码更简洁 - 本项目DOM操作不多,jQuery足够 **什么是AJAX?** AJAX(Asynchronous JavaScript And XML)让网页**不刷新就能从服务器获取数据**。就像你在餐厅坐着,服务员把菜端到你桌上,你不需要站起来去厨房。 ```mermaid sequenceDiagram participant 页面 as 网页 participant 服务器 as 后端服务器 页面->>页面: 用户点击"用户分析" 页面->>服务器: AJAX请求 /api/active_users Note over 页面: 页面不刷新,等待数据 服务器-->>页面: 返回JSON数据 页面->>页面: 用数据渲染图表 ``` --- # 第5章 后端基础——搭建数据服务 ## 5.1 FastAPI入门 FastAPI应用的最小骨架: ```python from fastapi import FastAPI app = FastAPI() @app.get("/") async def home(): return {"message": "Hello World"} ``` 就这么简单!`@app.get("/")`定义了一个路由——当用户访问根路径时,执行`home()`函数,返回JSON数据。 ## 5.2 第一个API:健康检查 健康检查是最简单的API,用于确认服务是否在运行: ```python @app.get("/health") async def health(): return {"message": "ok"} ``` **执行流程**: 1. 浏览器请求 `GET /health` 2. FastAPI匹配到这个路由 3. 执行`health()`函数 4. 返回 `{"message": "ok"}` ## 5.3 数据读取函数 所有API都需要读取CSV数据,所以抽取一个公共函数: ```python from pathlib import Path import pandas as pd def get_data(): src_dir = Path(__file__).parent data_file = src_dir.parent / "data" / "douyin_dataset.csv" df = pd.read_csv(data_file) return df ``` **逐行解析**: - `Path(__file__).parent`:获取当前文件(main.py)所在的目录(src/) - `src_dir.parent`:获取src的父目录(项目根目录) - `/ "data" / "douyin_dataset.csv"`:拼接路径到数据文件 - `pd.read_csv()`:Pandas读取CSV文件,返回DataFrame ## 5.4 统一响应格式 为了让前端处理更简单,所有API返回统一格式: ```python def success_response(data=None): return {"code": 200, "data": data} ``` 前端只需要检查: ```javascript if (response.code === 200 && response.data) { // 使用 response.data } ``` ## 5.5 CORS跨域配置 **什么是跨域问题?** 浏览器有一个安全策略:网页只能请求同源(同协议、同域名、同端口)的API。如果前端在`localhost:8080`,API也在`localhost:8080`,就没有跨域问题。但如果前端和后端在不同端口,就需要CORS配置。 ```python app.add_middleware( CORSMiddleware, allow_origins=["*"], # 允许所有来源 allow_credentials=True, # 允许携带凭证 allow_methods=["*"], # 允许所有HTTP方法 allow_headers=["*"], # 允许所有HTTP头部 ) ``` ## 5.6 静态文件服务 前端文件(HTML、CSS、JS)需要通过HTTP访问,FastAPI提供了静态文件挂载: ```python from starlette.staticfiles import StaticFiles app.mount("/static", StaticFiles(directory=BASE_DIR / "static"), name="static") ``` 这样,`static/index.html`就可以通过`/static/index.html`访问。 ## 5.7 首页重定向 用户访问根路径`/`时,自动跳转到静态首页: ```python from starlette.responses import RedirectResponse @app.get("/") async def home(): return RedirectResponse(url="/static/index.html") ``` ## 5.8 后端完整骨架 把以上所有部分组合起来,就是后端的完整骨架: ```mermaid graph TD A[FastAPI应用实例] --> B[CORS中间件] A --> C[静态文件挂载] A --> D[根路由重定向] A --> E[健康检查API] A --> F[数据读取函数] A --> G[统一响应函数] A --> H[业务API接口群] H --> H1["/api/overview"] H --> H2["/api/likes_by_date"] H --> H3["/api/user_city_distribution"] H --> H4["...更多接口"] F --> I["douyin_dataset.csv"] ``` --- # 第6章 数据分析实战——从数据到洞察 本章是整个教程的核心——我们从一个具体的分析问题出发,一步步写出后端API。 ## 6.1 Pandas基础操作 在写API之前,先掌握5个最常用的Pandas操作: | 操作 | 代码 | 含义 | 类比Excel | |------|------|------|-----------| | 读取 | `pd.read_csv()` | 读取CSV文件 | 打开文件 | | 计数 | `len(df)` | 总行数 | 看行号 | | 去重计数 | `df['uid'].nunique()` | 不重复的值有多少个 | 删除重复后计数 | | 求和 | `df['like'].sum()` | 某列求和 | SUM函数 | | 均值 | `df['finish'].mean()` | 某列平均值 | AVERAGE函数 | | 分组计数 | `df.groupby('city').size()` | 按某列分组后计数 | 数据透视表 | | 分组聚合 | `df.groupby('city').agg({...})` | 按某列分组后多种运算 | 数据透视表+公式 | ## 6.2 最简单的分析:24小时发布分布 **问题**:一天24个小时,每个小时有多少条视频被观看? **思路**:按`H`字段(0-23)分组,统计每组的记录数。 ```python @app.get("/api/hourly_distribution") async def hourly_distribution(): df = get_data() # 按小时分组计数 hourly = df.groupby('H').size() # 确保所有小时都有值(缺失的补0) hours = list(range(24)) counts = [int(hourly.get(h, 0)) for h in hours] return success_response({"hours": hours, "counts": counts}) ``` **执行流程**: ```mermaid flowchart LR A[原始数据] --> B["groupby('H')"] B --> C[".size()"] C --> D[补全0-23小时] D --> E[返回JSON] style A fill:#ff6b6b,color:#fff style E fill:#6bcb77,color:#fff ``` **为什么需要补0?** 如果凌晨3点没有人看视频,`groupby`结果中就没有3这个键。但前端需要24个数据点来画图,所以必须补0。 ## 6.3 聚合分析:概览KPI **问题**:平台的核心指标是什么? **思路**:4个KPI分别用不同的Pandas操作。 ```python @app.get("/api/overview") async def overview(): df = get_data() total_items = len(df) # 总记录数 total_users = df['uid'].nunique() # 去重用户数 total_likes = df['like'].sum() # 点赞总和 finish_rate = df['finish'].mean() * 100 # 完播率均值×100 return { "code": 200, "data": { "total_items": int(total_items), "total_videos": int(total_items), "total_users": int(total_users), "total_likes": int(total_likes), "finish_rate": round(finish_rate, 2) } } ``` **每个KPI的Pandas操作对应**: ```mermaid graph LR subgraph DataFrame DF[173万行数据] end DF -->|len| KPI1[总记录数: 1730000] DF -->|nunique| KPI2[独立用户数: 523891] DF -->|sum| KPI3[总点赞数: 842156] DF -->|mean × 100| KPI4[完播率: 45.67%] ``` ## 6.4 分组分析:城市分布 **问题**:哪些城市的用户最多? **思路**:按`user_city`分组,统计每组的记录数,取Top10。 ```python @app.get("/api/user_city_distribution") async def user_city_distribution(): df = get_data() # 按城市分组 → 计数 → 降序排列 → 取前10 city_data = df.groupby('user_city').size().sort_values(ascending=False).head(10) cities = [] counts = [] for city, count in city_data.items(): cities.append(str(city)) counts.append(int(count)) return success_response({"cities": cities, "counts": counts}) ``` **Pandas操作链**: ```mermaid flowchart LR A[DataFrame] --> B["groupby('user_city')"] B --> C[".size()"] C --> D[".sort_values(ascending=False)"] D --> E[".head(10)"] E --> F[Top10城市数据] style A fill:#ff6b6b,color:#fff style F fill:#6bcb77,color:#fff ``` ## 6.5 时间序列分析:每日点赞趋势 **问题**:每天的点赞数如何变化? **思路**:将`date`列转为日期类型,按日期分组,对`like`列求和。 ```python @app.get("/api/likes_by_date") async def likes_by_date(): df = get_data() # 关键:指定format参数加速解析! df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d') likes_by_date = df.groupby('date')['like'].sum().sort_index() dates = [] likes = [] for date, like in likes_by_date.items(): dates.append(date.strftime("%Y-%m-%d")) likes.append(int(like)) return success_response({"dates": dates, "likes": likes}) ``` **性能注意**:`pd.to_datetime`不指定`format`时,Pandas会逐行猜测日期格式,173万行数据会非常慢。指定`format='%Y-%m-%d'`后,解析速度提升10-100倍。 ## 6.6 关联分析:城市-音乐关联 **问题**:不同城市的用户喜欢什么音乐? **思路**:按城市和音乐组合分组,统计每组的记录数,取每个城市的Top5音乐。 ```python @app.get("/api/city_music_association") async def city_music_association(): df = get_data() # 取用户最多的Top10城市 top_cities = df.groupby('user_city').size().nlargest(10).index.tolist() # 筛选Top10城市的数据 df_top = df[df['user_city'].isin(top_cities)] # 按城市和音乐分组计数 grouped = df_top.groupby(['user_city', 'music_id']).size().reset_index(name='count') # 每个城市取Top5音乐 associations = [] music_ids_set = set() for city in top_cities: city_data = grouped[grouped['user_city'] == city].nlargest(5, 'count') for _, row in city_data.iterrows(): associations.append({ "city": str(row['user_city']), "music_id": str(row['music_id']), "count": int(row['count']) }) music_ids_set.add(str(row['music_id'])) return success_response({ "cities": [str(c) for c in top_cities], "music_ids": list(music_ids_set), "associations": associations }) ``` **分析流程**: ```mermaid flowchart TD A[173万条数据] --> B[取Top10城市] B --> C[筛选Top10城市数据] C --> D["groupby(city, music_id)"] D --> E[每个城市取Top5音乐] E --> F[构建关联数据] style A fill:#ff6b6b,color:#fff style F fill:#6bcb77,color:#fff ``` ## 6.7 深度分析:渠道质量评估 **问题**:不同渠道的内容质量如何? **思路**:按渠道分组,同时计算多个指标——视频数、平均点赞、完播率、平均时长。 ```python @app.get("/api/channel_quality_analysis") async def channel_quality_analysis(): df = get_data() # 使用agg一次性计算多个指标 channel_stats = df.groupby('channel').agg({ 'item_id': 'count', # 视频数 'like': 'mean', # 平均点赞 'finish': 'mean', # 完播率 'duration_time': 'mean' # 平均时长 }).reset_index() channels = channel_stats['channel'].tolist() counts = channel_stats['item_id'].tolist() avg_likes = channel_stats['like'].tolist() finish_rates = channel_stats['finish'].tolist() avg_durations = channel_stats['duration_time'].tolist() return success_response({ "channels": channels, "counts": [int(c) for c in counts], "avg_likes": [round(float(l), 4) for l in avg_likes], "finish_rates": [round(float(f), 4) for f in finish_rates], "avg_durations": [round(float(d), 2) for d in avg_durations] }) ``` **agg的威力**:一次分组,多个指标,避免重复遍历数据。 ## 6.8 所有API接口总览 | 接口 | Pandas核心操作 | 返回数据 | |------|---------------|---------| | `/api/overview` | len, nunique, sum, mean | 4个KPI数值 | | `/api/likes_by_date` | groupby+sum | 日期-点赞数对 | | `/api/user_city_distribution` | groupby+size+head | Top10城市 | | `/api/item_city_distribution` | groupby+size+head | Top10视频城市 | | `/api/channel_distribution` | groupby+size | 渠道占比 | | `/api/duration_distribution` | pd.cut+groupby | 时长区间分布 | | `/api/hourly_distribution` | groupby+size | 24小时分布 | | `/api/music_popularity` | groupby+size+head | Top20音乐 | | `/api/music_engagement` | groupby+agg | 音乐使用+点赞 | | `/api/author_productivity` | groupby+nunique+head | Top20作者 | | `/api/author_influence` | groupby+agg | 作者多维指标 | | `/api/minute_trend` | pd.cut+groupby | 144个时段 | | `/api/weekday_pattern` | groupby+size | 周一至周日 | | `/api/active_users` | groupby+size+head | Top50用户 | | `/api/user_completion_behavior` | groupby+agg | 用户完播行为 | | `/api/city_music_association` | groupby+nlargest | 城市-音乐关联 | | `/api/channel_quality_analysis` | groupby+agg | 渠道多维质量 | | `/api/city_analysis_deep` | groupby+agg | 城市深度分析 | | `/api/channel_quality_deep` | groupby+agg | 渠道深度分析 | --- # 第7章 前端基础——HTML与CSS ## 7.1 HTML文档结构 HTML是网页的骨架。我们的`index.html`结构如下: ```html