🤖 每日自动备份 - 2026-05-14 08:00:01
This commit is contained in:
parent
7447ed7c16
commit
ead09c9530
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"updatedAt": "2026-05-12T07:45:29.297Z",
|
"updatedAt": "2026-05-13T08:20:55.037Z",
|
||||||
"entries": {
|
"entries": {
|
||||||
"memory:memory/2026-05-06.md:1:20": {
|
"memory:memory/2026-05-06.md:1:20": {
|
||||||
"key": "memory:memory/2026-05-06.md:1:20",
|
"key": "memory:memory/2026-05-06.md:1:20",
|
||||||
@ -40,18 +40,20 @@
|
|||||||
"endLine": 30,
|
"endLine": 30,
|
||||||
"source": "memory",
|
"source": "memory",
|
||||||
"snippet": "- **订单号格式问题:** Excel 科学计数法 → 设置单元格为文本格式解决 - **psycopg2 转义:** LIKE 中 `%` 需写成 `%%`(psycopg2 的 `%s` 占位符冲突) ## 任务2:销售线索用户分析报表 - [李承龙需求] 输入包含462个用户ID的Excel,输出每个用户+角色的完整画像报表 - 脚本路径:`/root/.openclaw/workspace/scripts/lead_user_analysis.py` - **重要口径修正(李承龙确认):** - **体验课定义:** 固定为 L1 U00(L01-L05) + L2 U00(L01-L05) 共10节课,**不通过 expire_time 区分** - L1 chapter_id: 343, 344, 345, 346, 348 - L2 chapter_id: 55, 56, 57, 58, 59 - **完成时间:** 取 `bi_user_chapter_play_record` 中 `play_status=1` 记录的**最早 `updated_at`**(非 `created_at`) - **报表列:** 用户ID、角色ID、用户注册时间、角色创建时间、L1序章5节完成时间、L2序章5节完成时间、购买时间、购买课包名称、支付金额、购买渠道key_from、是否退款、退款金额 - **分表规则:** `bi_user_chapter_play_record_{0..7}`,分表号 = user_id % 8 - **重要关联:** `b",
|
"snippet": "- **订单号格式问题:** Excel 科学计数法 → 设置单元格为文本格式解决 - **psycopg2 转义:** LIKE 中 `%` 需写成 `%%`(psycopg2 的 `%s` 占位符冲突) ## 任务2:销售线索用户分析报表 - [李承龙需求] 输入包含462个用户ID的Excel,输出每个用户+角色的完整画像报表 - 脚本路径:`/root/.openclaw/workspace/scripts/lead_user_analysis.py` - **重要口径修正(李承龙确认):** - **体验课定义:** 固定为 L1 U00(L01-L05) + L2 U00(L01-L05) 共10节课,**不通过 expire_time 区分** - L1 chapter_id: 343, 344, 345, 346, 348 - L2 chapter_id: 55, 56, 57, 58, 59 - **完成时间:** 取 `bi_user_chapter_play_record` 中 `play_status=1` 记录的**最早 `updated_at`**(非 `created_at`) - **报表列:** 用户ID、角色ID、用户注册时间、角色创建时间、L1序章5节完成时间、L2序章5节完成时间、购买时间、购买课包名称、支付金额、购买渠道key_from、是否退款、退款金额 - **分表规则:** `bi_user_chapter_play_record_{0..7}`,分表号 = user_id % 8 - **重要关联:** `b",
|
||||||
"recallCount": 1,
|
"recallCount": 2,
|
||||||
"dailyCount": 0,
|
"dailyCount": 0,
|
||||||
"groundedCount": 0,
|
"groundedCount": 0,
|
||||||
"totalScore": 0.9835963163573811,
|
"totalScore": 1.983596316357381,
|
||||||
"maxScore": 0.9835963163573811,
|
"maxScore": 1,
|
||||||
"firstRecalledAt": "2026-05-07T04:41:47.636Z",
|
"firstRecalledAt": "2026-05-07T04:41:47.636Z",
|
||||||
"lastRecalledAt": "2026-05-07T04:41:47.636Z",
|
"lastRecalledAt": "2026-05-13T08:20:55.037Z",
|
||||||
"queryHashes": [
|
"queryHashes": [
|
||||||
"dd105d141c56"
|
"dd105d141c56",
|
||||||
|
"4cacd0d43440"
|
||||||
],
|
],
|
||||||
"recallDays": [
|
"recallDays": [
|
||||||
"2026-05-07"
|
"2026-05-07",
|
||||||
|
"2026-05-13"
|
||||||
],
|
],
|
||||||
"conceptTags": [
|
"conceptTags": [
|
||||||
"l01-l05",
|
"l01-l05",
|
||||||
|
|||||||
252
memory/2026-05-13-1611.md
Normal file
252
memory/2026-05-13-1611.md
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
# Session: 2026-05-13 16:11:56 GMT+8
|
||||||
|
|
||||||
|
- **Session Key**: agent:main:feishu:direct:ou_e63ce6b760ad39382852472f28fbe2a2
|
||||||
|
- **Session ID**: a2fd11e0-095a-4a58-a376-9424b26b81be
|
||||||
|
- **Source**: feishu
|
||||||
|
|
||||||
|
## Conversation Summary
|
||||||
|
|
||||||
|
user: 我没有收到数据
|
||||||
|
assistant: ## 📊 三版转化率 2025年9月-2026年4月
|
||||||
|
|
||||||
|
| 月份 | 原始版转化率 | 原始版去退费 | 纯净版转化率 | 纯净版去退费 | 拟合版转化率 | 拟合版去退费 |
|
||||||
|
|------|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 1.11% | 1.11% | 1.34% | 1.34% | 1.76% | 1.76% |
|
||||||
|
| 2025-10 | 1.41% | 1.37% | 1.59% | 1.54% | 1.71% | 1.66% |
|
||||||
|
| 2025-11 | 0.71% | 0.71% | 0.74% | 0.74% | 0.83% | 0.83% |
|
||||||
|
| 2025-12 | 0.71% | 0.68% | 0.75% | 0.72% | 0.73% | 0.70% |
|
||||||
|
| 2026-01 | 1.39% | 1.24% | 1.49% | 1.32% | 1.51% | 1.34% |
|
||||||
|
| 2026-02 | 0.92% | 0.86% | 1.01% | 0.95% | 1.25% | 1.17% |
|
||||||
|
| 2026-03 | 1.92% | 1.85% | 2.15% | 2.07% | 2.73% | 2.63% |
|
||||||
|
| 2026-04 | 1.15% | 1.11% | 1.35% | 1.31% | 1.88% | 1.82% |
|
||||||
|
|
||||||
|
三版转化率关系:拟合版 > 纯净版 > 原始版。3月是三版共同的峰值(拟合版2.73%),12月和11月是低谷。
|
||||||
|
user: 然后我想要看两个keyfrom分别的订单数和退费订单数
|
||||||
|
assistant: ## 📊 两个 key_from 分别订单数 & 退费订单数
|
||||||
|
|
||||||
|
| 月份 | app-active-h5-0-0 订单 | 退费 | app-sales-bj-qhm-0 订单 | 退费 |
|
||||||
|
|------|:---:|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 18 | 1 | 0 | 0 |
|
||||||
|
| 2025-10 | 36 | 1 | 0 | 0 |
|
||||||
|
| 2025-11 | 21 | 0 | 0 | 0 |
|
||||||
|
| 2025-12 | 28 | 2 | 0 | 0 |
|
||||||
|
| 2026-01 | 29 | 4 | 1 | 0 |
|
||||||
|
| 2026-02 | 17 | 1 | 0 | 0 |
|
||||||
|
| 2026-03 | 67 | 3 | 17 | 2 |
|
||||||
|
| 2026-04 | 50 | 1 | 16 | 2 |
|
||||||
|
| **合计** | **266** | **13** | **34** | **4** |
|
||||||
|
|
||||||
|
`app-sales-bj-qhm-0` 从2026年3月才开始有明显量,这之前(2025.9-2026.2)只有1月有1单。端内主力始终是 `app-active-h5-0-0`,占整体订单88.7%。
|
||||||
|
user: 加一个GMV和GSV
|
||||||
|
assistant: ## 📊 端内两个 key_from 月度明细
|
||||||
|
|
||||||
|
### app-active-h5-0-0
|
||||||
|
|
||||||
|
| 月份 | 订单数 | 退费 | GMV | GSV |
|
||||||
|
|------|:---:|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 18 | 1 | ¥21,482 | ¥20,883 |
|
||||||
|
| 2025-10 | 36 | 1 | ¥42,064 | ¥40,065 |
|
||||||
|
| 2025-11 | 21 | 0 | ¥26,579 | ¥26,579 |
|
||||||
|
| 2025-12 | 28 | 2 | ¥31,172 | ¥29,974 |
|
||||||
|
| 2026-01 | 29 | 4 | ¥34,270 | ¥29,875 |
|
||||||
|
| 2026-02 | 17 | 1 | ¥21,982 | ¥19,983 |
|
||||||
|
| 2026-03 | 67 | 3 | ¥75,033 | ¥70,936 |
|
||||||
|
| 2026-04 | 50 | 1 | ¥46,750 | ¥46,151 |
|
||||||
|
| **合计** | **266** | **13** | **¥299,332** | **¥284,446** |
|
||||||
|
|
||||||
|
### app-sales-bj-qhm-0
|
||||||
|
|
||||||
|
| 月份 | 订单数 | 退费 | GMV | GSV |
|
||||||
|
|------|:---:|:---:|:---:|:---:|
|
||||||
|
| 2025-09~2026-02 | 1 | 0 | ¥599 | ¥599 |
|
||||||
|
| 2026-03 | 17 | 2 | ¥40,578 | ¥37,980 |
|
||||||
|
| 2026-04 | 16 | 2 | ¥35,381 | ¥29,784 |
|
||||||
|
| **合计** | **34** | **4** | **¥76,558** | **¥68,363** |
|
||||||
|
|
||||||
|
`app-sales-bj-qhm-0` 从3月才开始起量,两个月贡献了 ¥76,558 GMV,占端内总GMV的20.4%,已经是个不小的新渠道了。
|
||||||
|
user: 帮我统计只要app-active-h5-0-0的三个版本的区分苹果、华为、学而思、华为渠道的2025年9月到2026年4月每个月的新增注册、订单数、转化率、转化率(去退费)、退费订单数、退费率、GMV、GMS
|
||||||
|
assistant: 数据较多,分渠道展示。
|
||||||
|
|
||||||
|
## 📊 苹果 × app-active-h5-0-0
|
||||||
|
|
||||||
|
| 月份 | 版本 | 注册 | 订单 | 退费 | 转化率 | 转(去退) | 退费率 | GMV | GSV |
|
||||||
|
|------|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 原始/纯净/拟合 | 211/175/130 | 6 | 0 | 2.84%/3.43%/4.62% | 同左 | 0% | ¥7,294 | ¥7,294 |
|
||||||
|
| 2025-10 | 原始/纯净/拟合 | 404/343/293 | 11 | 1 | 2.72%/3.21%/3.75% | 2.48%/2.92%/3.41% | 9.1% | ¥10,789 | ¥8,790 |
|
||||||
|
| 2025-11 | 原始/纯净/拟合 | 440/409/393 | 7 | 0 | 1.59%/1.71%/1.78% | 同左 | 0% | ¥11,193 | ¥11,193 |
|
||||||
|
| 2025-12 | 原始/纯净/拟合 | 384/337/364 | 7 | 0 | 1.82%/2.08%/1.92% | 同左 | 0% | ¥8,393 | ¥8,393 |
|
||||||
|
| 2026-01 | 原始/纯净/拟合 | 310/283/280 | 17 | 3 | 4.52%/4.95%/5.00% | 4.19%/4.59%/4.64% | 17.6% | ¥22,783 | ¥19,586 |
|
||||||
|
| 2026-02 | 原始/纯净/拟合 | 319/273/226 | 6 | 0 | 1.25%/1.47%/1.77% | 同左 | 0% | ¥9,194 | ¥9,194 |
|
||||||
|
| 2026-03 | 原始/纯净/拟合 | 1167/1046/813 | 26 | 2 | 1.97%/2.20%/2.83% | 同左 | 7.7% | ¥32,774 | ¥29,276 |
|
||||||
|
| 2026-04 | 原始/纯净/拟合 | 1540/1316/921 | 17 | 0 | 1.10%/1.29%/1.85% | 同左 | 0% | ¥18,583 | ¥18,583 |
|
||||||
|
|
||||||
|
## 📊 华为 × app-active-h5-0-0
|
||||||
|
|
||||||
|
| 月份 | 版本 | 注册 | 订单 | 退费 | 转化率 | 转(去退) | 退费率 | GMV | GSV |
|
||||||
|
|------|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 原始/纯净/拟合 | 112/73/69 | 3 | 1 | 1.79%/2.74%/2.90% | 同左 | 33.3% | ¥3,197 | ¥2,598 |
|
||||||
|
| 2025-10 | 原始/纯净/拟合 | 178/148/129 | 10 | 0 | 5.06%/6.08%/6.98% | 同左 | 0% | ¥11,590 | ¥11,590 |
|
||||||
|
| 2025-11 | 原始/纯净/拟合 | 282/260/252 | 2 | 0 | 0.71%/0.77%/0.79% | 同左 | 0% | ¥1,198 | ¥1,198 |
|
||||||
|
| 2025-12 | 原始/纯净/拟合 | 239/214/226 | 3 | 0 | 1.26%/1.40%/1.33% | 同左 | 0% | ¥4,597 | ¥4,597 |
|
||||||
|
| 2026-01 | 原始/纯净/拟合 | 212/186/191 | 8 | 0 | 3.30%/3.76%/3.66% | 同左 | 0% | ¥8,492 | ¥8,492 |
|
||||||
|
| 2026-02 | 原始/纯净/拟合 | 117/100/82 | 1 | 0 | 0.85%/1.00%/1.22% | 同左 | 0% | ¥1,999 | ¥1,999 |
|
||||||
|
| 2026-03 | 原始/纯净/拟合 | 670/603/467 | 13 | 0 | 1.94%/2.16%/2.78% | 同左 | 0% | ¥11,987 | ¥11,987 |
|
||||||
|
| 2026-04 | 原始/纯净/拟合 | 1153/989/689 | 11 | 1 | 0.95%/1.11%/1.60% | 0.87%/1.01%/1.45% | 9.1% | ¥7,989 | ¥7,390 |
|
||||||
|
|
||||||
|
## 📊 学而思 × app-active-h5-0-0
|
||||||
|
|
||||||
|
| 月份 | 版本 | 注册 | 订单 | 退费 | 转化率 | 转(去退) | 退费率 | GMV | GSV |
|
||||||
|
|------|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 原始/纯净/拟合 | 169/105/104 | 2 | 0 | 1.18%/1.90%/1.92% | 同左 | 0% | ¥2,598 | ¥2,598 |
|
||||||
|
| 2025-10 | 原始/纯净/拟合 | 143/112/103 | 4 | 0 | 2.80%/3.57%/3.88% | 同左 | 0% | ¥5,196 | ¥5,196 |
|
||||||
|
| 2025-11 | 原始/纯净/拟合 | 422/408/377 | 3 | 0 | 0.71%/0.74%/0.80% | 同左 | 0% | ¥4,597 | ¥4,597 |
|
||||||
|
| 2025-12 | 原始/纯净/拟合 | 1137/1117/1079 | 6 | 1 | 0.44%/0.45%/0.46% | 同左 | 16.7% | ¥6,394 | ¥5,795 |
|
||||||
|
| 2026-01 | 原始/纯净/拟合 | 301/288/272 | 2 | 1 | 0.66%/0.69%/0.74% | 0.33%/0.35%/0.37% | 50.0% | ¥1,198 | ¥599 |
|
||||||
|
| 2026-02 | 原始/纯净/拟合 | 611/575/433 | 3 | 0 | 0.49%/0.52%/0.69% | 同左 | 0% | ¥1,797 | ¥1,797 |
|
||||||
|
| 2026-03 | 原始/纯净/拟合 | 614/568/428 | 4 | 1 | 0.65%/0.70%/0.93% | 0.49%/0.53%/0.70% | 25.0% | ¥5,196 | ¥4,597 |
|
||||||
|
| 2026-04 | 原始/纯净/拟合 | 422/356/252 | 5 | 0 | 1.18%/1.40%/1.98% | 同左 | 0% | ¥2,995 | ¥2,995 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**几个观察:**
|
||||||
|
- 苹果和华为的转化率在 1月达到最高峰(苹果拟合5.00%、华为拟合3.66%),之后持续下滑到4月(苹果1.85%、华为1.60%)
|
||||||
|
- 学而思转化率整体偏低(0.5%~1%),但12月注册量最大(1137人)时转化率最低(0.44%),4月注册回落但转化回升到1.18%
|
||||||
|
- 华为退费很少,学而思1月退费率50%(2单退了1单)
|
||||||
|
- 三个渠道拟合版分母都比原始版收紧,苹果和学而思收紧比例较大(受活动影响更明显)
|
||||||
|
user: 帮我统计只要app-active-h5-0-0的三个版本的区分苹果、华为、学而思、华为渠道的2025年9月到2026年4月每个月的7日、14日、21日转化率
|
||||||
|
assistant: ## 📊 苹果 × app-active-h5-0-0(去退费)
|
||||||
|
|
||||||
|
| 月份 | 原始版 7日/14日/21日 | 纯净版 7日/14日/21日 | 拟合版 7日/14日/21日 |
|
||||||
|
|------|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 0.47%/0.47%/1.42% | 0.58%/0.58%/1.75% | 0.77%/0.77%/2.31% |
|
||||||
|
| 2025-10 | 1.24%/1.24%/1.73% | 1.47%/1.47%/2.06% | 1.71%/1.71%/2.39% |
|
||||||
|
| 2025-11 | 0.91%/1.14%/1.14% | 0.99%/1.23%/1.23% | 1.02%/1.27%/1.27% |
|
||||||
|
| 2025-12 | 0.26%/1.04%/1.30% | 0.30%/1.20%/1.51% | 0.27%/1.10%/1.37% |
|
||||||
|
| 2026-01 | 2.26%/2.90%/3.55% | 2.56%/3.30%/4.03% | 2.50%/3.21%/3.93% |
|
||||||
|
| 2026-02 | 0.94%/0.94%/0.94% | 1.21%/1.21%/1.21% | 1.33%/1.33%/1.33% |
|
||||||
|
| 2026-03 | 0.69%/1.37%/1.71% | 0.79%/1.57%/1.97% | 0.98%/1.97%/2.46% |
|
||||||
|
| 2026-04 | 0.78%/0.97%/1.10% | 1.00%/1.25%/1.42% | 1.30%/1.63%/1.85% |
|
||||||
|
|
||||||
|
## 📊 华为 × app-active-h5-0-0(去退费)
|
||||||
|
|
||||||
|
| 月份 | 原始版 7日/14日/21日 | 纯净版 7日/14日/21日 | 拟合版 7日/14日/21日 |
|
||||||
|
|------|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 0%/0.89%/0.89% | 0%/1.47%/1.47% | 0%/1.45%/1.45% |
|
||||||
|
| 2025-10 | 2.25%/3.37%/3.37% | 2.70%/4.05%/4.05% | 3.10%/4.65%/4.65% |
|
||||||
|
| 2025-11 | 0%/0%/0% | 0%/0%/0% | 0%/0%/0% |
|
||||||
|
| 2025-12 | 0.84%/0.84%/0.84% | 0.94%/0.94%/0.94% | 0.88%/0.88%/0.88% |
|
||||||
|
| 2026-01 | 1.89%/1.89%/2.83% | 2.19%/2.19%/3.28% | 2.09%/2.09%/3.14% |
|
||||||
|
| 2026-02 | 0%/0.85%/0.85% | 0%/1.18%/1.18% | 0%/1.22%/1.22% |
|
||||||
|
| 2026-03 | 1.34%/1.79%/1.79% | 1.57%/2.09%/2.09% | 1.93%/2.57%/2.57% |
|
||||||
|
| 2026-04 | 0.52%/0.69%/0.69% | 0.67%/0.90%/0.90% | 0.87%/1.16%/1.16% |
|
||||||
|
|
||||||
|
## 📊 学而思 × app-active-h5-0-0(去退费)
|
||||||
|
|
||||||
|
| 月份 | 原始版 7日/14日/21日 | 纯净版 7日/14日/21日 | 拟合版 7日/14日/21日 |
|
||||||
|
|------|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 0.59%/0.59%/0.59% | 0.96%/0.96%/0.96% | 0.96%/0.96%/0.96% |
|
||||||
|
| 2025-10 | 1.40%/2.10%/2.10% | 1.80%/2.70%/2.70% | 1.94%/2.91%/2.91% |
|
||||||
|
| 2025-11 | 0.47%/0.47%/0.71% | 0.49%/0.49%/0.74% | 0.53%/0.53%/0.80% |
|
||||||
|
| 2025-12 | 0.35%/0.35%/0.35% | 0.36%/0.36%/0.36% | 0.37%/0.37%/0.37% |
|
||||||
|
| 2026-01 | 0.33%/0.33%/0.33% | 0.35%/0.35%/0.35% | 0.37%/0.37%/0.37% |
|
||||||
|
| 2026-02 | 0.33%/0.33%/0.33% | 0.35%/0.35%/0.35% | 0.46%/0.46%/0.46% |
|
||||||
|
| 2026-03 | 0.49%/0.49%/0.49% | 0.54%/0.54%/0.54% | 0.70%/0.70%/0.70% |
|
||||||
|
| 2026-04 | 0.95%/1.18%/1.18% | 1.24%/1.55%/1.55% | 1.59%/1.98%/1.98% |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**几个关键发现:**
|
||||||
|
|
||||||
|
- **苹果** 转化集中在7-14日之间,12月7日转化极低(0.26%)但14日追上(1.04%),说明12月用户付费决策周期偏长。1月是高峰(7日2.26%→21日3.55%)。
|
||||||
|
- **华为** 付费决策基本在7日内完成,7日之后的增量很少。11月三个版本全是0。10月拟合版7日3.10%是渠道最高。
|
||||||
|
- **学而思** 付费决策也基本在7日内,21日和14日几乎无差。整体转化率偏低(0.3%~1%),4月有回暖迹象(拟合版7日1.59%)。
|
||||||
|
user: 调整一下上面表格的展示形式,一个格里面只放一个百分比数据
|
||||||
|
assistant: ## 📊 苹果 × app-active-h5-0-0(去退费)
|
||||||
|
|
||||||
|
| 月份 | 版本 | 7日转化率 | 14日转化率 | 21日转化率 |
|
||||||
|
|------|------|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 原始版 | 0.47% | 0.47% | 1.42% |
|
||||||
|
| | 纯净版 | 0.58% | 0.58% | 1.75% |
|
||||||
|
| | 拟合版 | 0.77% | 0.77% | 2.31% |
|
||||||
|
| 2025-10 | 原始版 | 1.24% | 1.24% | 1.73% |
|
||||||
|
| | 纯净版 | 1.47% | 1.47% | 2.06% |
|
||||||
|
| | 拟合版 | 1.71% | 1.71% | 2.39% |
|
||||||
|
| 2025-11 | 原始版 | 0.91% | 1.14% | 1.14% |
|
||||||
|
| | 纯净版 | 0.99% | 1.23% | 1.23% |
|
||||||
|
| | 拟合版 | 1.02% | 1.27% | 1.27% |
|
||||||
|
| 2025-12 | 原始版 | 0.26% | 1.04% | 1.30% |
|
||||||
|
| | 纯净版 | 0.30% | 1.20% | 1.51% |
|
||||||
|
| | 拟合版 | 0.27% | 1.10% | 1.37% |
|
||||||
|
| 2026-01 | 原始版 | 2.26% | 2.90% | 3.55% |
|
||||||
|
| | 纯净版 | 2.56% | 3.30% | 4.03% |
|
||||||
|
| | 拟合版 | 2.50% | 3.21% | 3.93% |
|
||||||
|
| 2026-02 | 原始版 | 0.94% | 0.94% | 0.94% |
|
||||||
|
| | 纯净版 | 1.21% | 1.21% | 1.21% |
|
||||||
|
| | 拟合版 | 1.33% | 1.33% | 1.33% |
|
||||||
|
| 2026-03 | 原始版 | 0.69% | 1.37% | 1.71% |
|
||||||
|
| | 纯净版 | 0.79% | 1.57% | 1.97% |
|
||||||
|
| | 拟合版 | 0.98% | 1.97% | 2.46% |
|
||||||
|
| 2026-04 | 原始版 | 0.78% | 0.97% | 1.10% |
|
||||||
|
| | 纯净版 | 1.00% | 1.25% | 1.42% |
|
||||||
|
| | 拟合版 | 1.30% | 1.63% | 1.85% |
|
||||||
|
|
||||||
|
## 📊 华为 × app-active-h5-0-0(去退费)
|
||||||
|
|
||||||
|
| 月份 | 版本 | 7日转化率 | 14日转化率 | 21日转化率 |
|
||||||
|
|------|------|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 原始版 | 0% | 0.89% | 0.89% |
|
||||||
|
| | 纯净版 | 0% | 1.47% | 1.47% |
|
||||||
|
| | 拟合版 | 0% | 1.45% | 1.45% |
|
||||||
|
| 2025-10 | 原始版 | 2.25% | 3.37% | 3.37% |
|
||||||
|
| | 纯净版 | 2.70% | 4.05% | 4.05% |
|
||||||
|
| | 拟合版 | 3.10% | 4.65% | 4.65% |
|
||||||
|
| 2025-11 | 原始版 | 0% | 0% | 0% |
|
||||||
|
| | 纯净版 | 0% | 0% | 0% |
|
||||||
|
| | 拟合版 | 0% | 0% | 0% |
|
||||||
|
| 2025-12 | 原始版 | 0.84% | 0.84% | 0.84% |
|
||||||
|
| | 纯净版 | 0.94% | 0.94% | 0.94% |
|
||||||
|
| | 拟合版 | 0.88% | 0.88% | 0.88% |
|
||||||
|
| 2026-01 | 原始版 | 1.89% | 1.89% | 2.83% |
|
||||||
|
| | 纯净版 | 2.19% | 2.19% | 3.28% |
|
||||||
|
| | 拟合版 | 2.09% | 2.09% | 3.14% |
|
||||||
|
| 2026-02 | 原始版 | 0% | 0.85% | 0.85% |
|
||||||
|
| | 纯净版 | 0% | 1.18% | 1.18% |
|
||||||
|
| | 拟合版 | 0% | 1.22% | 1.22% |
|
||||||
|
| 2026-03 | 原始版 | 1.34% | 1.79% | 1.79% |
|
||||||
|
| | 纯净版 | 1.57% | 2.09% | 2.09% |
|
||||||
|
| | 拟合版 | 1.93% | 2.57% | 2.57% |
|
||||||
|
| 2026-04 | 原始版 | 0.52% | 0.69% | 0.69% |
|
||||||
|
| | 纯净版 | 0.67% | 0.90% | 0.90% |
|
||||||
|
| | 拟合版 | 0.87% | 1.16% | 1.16% |
|
||||||
|
|
||||||
|
## 📊 学而思 × app-active-h5-0-0(去退费)
|
||||||
|
|
||||||
|
| 月份 | 版本 | 7日转化率 | 14日转化率 | 21日转化率 |
|
||||||
|
|------|------|:---:|:---:|:---:|
|
||||||
|
| 2025-09 | 原始版 | 0.59% | 0.59% | 0.59% |
|
||||||
|
| | 纯净版 | 0.96% | 0.96% | 0.96% |
|
||||||
|
| | 拟合版 | 0.96% | 0.96% | 0.96% |
|
||||||
|
| 2025-10 | 原始版 | 1.40% | 2.10% | 2.10% |
|
||||||
|
| | 纯净版 | 1.80% | 2.70% | 2.70% |
|
||||||
|
| | 拟合版 | 1.94% | 2.91% | 2.91% |
|
||||||
|
| 2025-11 | 原始版 | 0.47% | 0.47% | 0.71% |
|
||||||
|
| | 纯净版 | 0.49% | 0.49% | 0.74% |
|
||||||
|
| | 拟合版 | 0.53% | 0.53% | 0.80% |
|
||||||
|
| 2025-12 | 原始版 | 0.35% | 0.35% | 0.35% |
|
||||||
|
| | 纯净版 | 0.36% | 0.36% | 0.36% |
|
||||||
|
| | 拟合版 | 0.37% | 0.37% | 0.37% |
|
||||||
|
| 2026-01 | 原始版 | 0.33% | 0.33% | 0.33% |
|
||||||
|
| | 纯净版 | 0.35% | 0.35% | 0.35% |
|
||||||
|
| | 拟合版 | 0.37% | 0.37% | 0.37% |
|
||||||
|
| 2026-02 | 原始版 | 0.33% | 0.33% | 0.33% |
|
||||||
|
| | 纯净版 | 0.35% | 0.35% | 0.35% |
|
||||||
|
| | 拟合版 | 0.46% | 0.46% | 0.46% |
|
||||||
|
| 2026-03 | 原始版 | 0.49% | 0.49% | 0.49% |
|
||||||
|
| | 纯净版 | 0.54% | 0.54% | 0.54% |
|
||||||
|
| | 拟合版 | 0.70% | 0.70% | 0.70% |
|
||||||
|
| 2026-04 | 原始版 | 0.95% | 1.18% | 1.18% |
|
||||||
|
| | 纯净版 | 1.24% | 1.55% | 1.55% |
|
||||||
|
| | 拟合版 | 1.59% | 1.98% | 1.98% |
|
||||||
|
user: 不要21日转化率,要20日转化率,然后导出成excel发给我
|
||||||
|
assistant: Excel已生成,通过飞书发给你。
|
||||||
|
assistant: Excel已发送,包含 **苹果 / 华为 / 学而思** 三个 Sheet,每个Sheet含原始版/纯净版/拟合版的7日/14日/20日转化率(去退费)及分母和付费用户数。
|
||||||
BIN
output/course_consumption_trend.png
Normal file
BIN
output/course_consumption_trend.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 232 KiB |
BIN
output/course_consumption_trend_no_u0.png
Normal file
BIN
output/course_consumption_trend_no_u0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
BIN
output/course_l1l2_act_avg.png
Normal file
BIN
output/course_l1l2_act_avg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 195 KiB |
BIN
output/course_l1l2_avg_all.png
Normal file
BIN
output/course_l1l2_avg_all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 215 KiB |
BIN
output/course_user_distribution.png
Normal file
BIN
output/course_user_distribution.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 218 KiB |
168
scripts/course_consumption_by_level.py
Normal file
168
scripts/course_consumption_by_level.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
课消指标:按 L1/L2 分等级统计
|
||||||
|
"""
|
||||||
|
import psycopg2
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import date, timedelta, datetime
|
||||||
|
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host="bj-postgres-16pob4sg.sql.tencentcdb.com",
|
||||||
|
port=28591,
|
||||||
|
user="ai_member",
|
||||||
|
password="LdfjdjL83h3h3^$&**YGG*",
|
||||||
|
dbname="vala_bi"
|
||||||
|
)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
overall_start = date(2025, 9, 1)
|
||||||
|
overall_end = date(2026, 5, 11)
|
||||||
|
|
||||||
|
# 生成周列表
|
||||||
|
weeks = []
|
||||||
|
d = overall_start
|
||||||
|
while d < overall_end:
|
||||||
|
ws = d
|
||||||
|
we = d + timedelta(days=6 - d.weekday())
|
||||||
|
if we >= overall_end:
|
||||||
|
we = overall_end - timedelta(days=1)
|
||||||
|
weeks.append((ws, we))
|
||||||
|
d = we + timedelta(days=1)
|
||||||
|
|
||||||
|
# ===== 获取 L1/L2 chapter_id =====
|
||||||
|
u0_ids = {343, 344, 345, 346, 348, 55, 56, 57, 58, 59}
|
||||||
|
cur.execute("SELECT DISTINCT id, course_level FROM bi_level_unit_lesson WHERE course_level IN ('L1','L2')")
|
||||||
|
l1_chapters = set()
|
||||||
|
l2_chapters = set()
|
||||||
|
for cid, lv in cur.fetchall():
|
||||||
|
if cid in u0_ids:
|
||||||
|
continue
|
||||||
|
if lv == 'L1':
|
||||||
|
l1_chapters.add(cid)
|
||||||
|
elif lv == 'L2':
|
||||||
|
l2_chapters.add(cid)
|
||||||
|
|
||||||
|
print(f"L1 chapters: {len(l1_chapters)}, L2 chapters: {len(l2_chapters)}")
|
||||||
|
|
||||||
|
# ===== Step 1: 付费用户 =====
|
||||||
|
print("Step 1: 查找付费用户...")
|
||||||
|
cur.execute("""
|
||||||
|
SELECT DISTINCT o.account_id
|
||||||
|
FROM bi_vala_order o
|
||||||
|
INNER JOIN bi_vala_app_account a ON o.account_id = a.id
|
||||||
|
WHERE a.status = 1 AND a.deleted_at IS NULL AND o.pay_success_date IS NOT NULL
|
||||||
|
GROUP BY o.account_id
|
||||||
|
HAVING COUNT(CASE WHEN o.order_status != 4
|
||||||
|
OR (o.order_status = 4 AND o.trade_no NOT IN (
|
||||||
|
SELECT trade_no FROM bi_refund_order WHERE status=3
|
||||||
|
)) THEN 1 END) > 0
|
||||||
|
""")
|
||||||
|
paid_account_ids = [row[0] for row in cur.fetchall()]
|
||||||
|
print(f" 付费用户: {len(paid_account_ids)}")
|
||||||
|
|
||||||
|
# 订单详情用于动态判断每周付费用户
|
||||||
|
cur.execute("""
|
||||||
|
SELECT o.account_id, o.trade_no, o.out_trade_no, o.pay_success_date, o.order_status
|
||||||
|
FROM bi_vala_order o
|
||||||
|
INNER JOIN bi_vala_app_account a ON o.account_id = a.id
|
||||||
|
WHERE a.status=1 AND a.deleted_at IS NULL AND o.pay_success_date IS NOT NULL
|
||||||
|
AND o.pay_success_date >= '2025-01-01'
|
||||||
|
""")
|
||||||
|
orders = cur.fetchall()
|
||||||
|
cur.execute("SELECT trade_no, status FROM bi_refund_order WHERE status=3")
|
||||||
|
refund_set = {r[0] for r in cur.fetchall() if r[0]}
|
||||||
|
|
||||||
|
account_orders = defaultdict(list)
|
||||||
|
for aid, tn, otn, psd, os in orders:
|
||||||
|
is_ref = os == 4 and tn in refund_set
|
||||||
|
account_orders[aid].append((psd, is_ref))
|
||||||
|
|
||||||
|
def is_paid(aid, as_of):
|
||||||
|
return sum(1 for pd, ref in account_orders.get(aid, []) if pd.date() <= as_of and not ref) > 0
|
||||||
|
|
||||||
|
# ===== Step 2: 课消(分L1/L2)=====
|
||||||
|
print("Step 2: 查询课消(分L1/L2)...")
|
||||||
|
l1_consumption = {} # (user_id, chapter_id) -> earliest date
|
||||||
|
l2_consumption = {}
|
||||||
|
|
||||||
|
for t in range(8):
|
||||||
|
tbl = f"bi_user_chapter_play_record_{t}"
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT user_id, chapter_id, updated_at FROM {tbl}
|
||||||
|
WHERE play_status=1 AND updated_at>='2025-09-01' AND updated_at<'2026-05-11'
|
||||||
|
""")
|
||||||
|
for uid, cid, upd in cur.fetchall():
|
||||||
|
if cid in l1_chapters:
|
||||||
|
k, m = (uid, cid), l1_consumption
|
||||||
|
elif cid in l2_chapters:
|
||||||
|
k, m = (uid, cid), l2_consumption
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
d = upd.date() if hasattr(upd, 'date') else upd
|
||||||
|
if k not in m or d < m[k]:
|
||||||
|
m[k] = d
|
||||||
|
|
||||||
|
print(f" L1 课消(去重): {len(l1_consumption)}")
|
||||||
|
print(f" L2 课消(去重): {len(l2_consumption)}")
|
||||||
|
|
||||||
|
# ===== Step 3: 角色映射 =====
|
||||||
|
print("Step 3: 关联角色...")
|
||||||
|
all_uids = set(k[0] for k in l1_consumption) | set(k[0] for k in l2_consumption)
|
||||||
|
char_to_account = {}
|
||||||
|
for i in range(0, len(all_uids), 500):
|
||||||
|
batch = list(all_uids)[i:i+500]
|
||||||
|
ph = ','.join(['%s']*len(batch))
|
||||||
|
cur.execute(f"SELECT id, account_id FROM bi_vala_app_character WHERE id IN ({ph})", batch)
|
||||||
|
for cid, aid in cur.fetchall():
|
||||||
|
char_to_account[cid] = aid
|
||||||
|
|
||||||
|
# ===== Step 4: 按周汇总 =====
|
||||||
|
print("Step 4: 按周汇总...")
|
||||||
|
|
||||||
|
def weekly_stats(consumption_map):
|
||||||
|
"""返回每周的 (课消次数, 有消用户数)"""
|
||||||
|
results = []
|
||||||
|
for ws, we in weeks:
|
||||||
|
cons = 0
|
||||||
|
users = set()
|
||||||
|
for (uid, ch_id), d in consumption_map.items():
|
||||||
|
if ws <= d <= we:
|
||||||
|
cons += 1
|
||||||
|
aid = char_to_account.get(uid)
|
||||||
|
if aid:
|
||||||
|
users.add(aid)
|
||||||
|
results.append((ws, we, cons, len(users)))
|
||||||
|
return results
|
||||||
|
|
||||||
|
l1_stats = weekly_stats(l1_consumption)
|
||||||
|
l2_stats = weekly_stats(l2_consumption)
|
||||||
|
|
||||||
|
# 汇总 + 付费用户
|
||||||
|
results = []
|
||||||
|
for i, (ws, we) in enumerate(weeks):
|
||||||
|
paid = set(aid for aid in account_orders if is_paid(aid, we))
|
||||||
|
n_paid = len(paid)
|
||||||
|
|
||||||
|
l1_cons, l1_users = l1_stats[i][2], l1_stats[i][3]
|
||||||
|
l2_cons, l2_users = l2_stats[i][2], l2_stats[i][3]
|
||||||
|
|
||||||
|
l1_avg = l1_cons / n_paid if n_paid else 0
|
||||||
|
l1_act_avg = l1_cons / l1_users if l1_users else 0
|
||||||
|
l2_avg = l2_cons / n_paid if n_paid else 0
|
||||||
|
l2_act_avg = l2_cons / l2_users if l2_users else 0
|
||||||
|
|
||||||
|
results.append({
|
||||||
|
'week': f"{ws.strftime('%m/%d')}-{we.strftime('%m/%d')}",
|
||||||
|
'ws': ws, 'we': we, 'paid': n_paid,
|
||||||
|
'l1_cons': l1_cons, 'l1_users': l1_users, 'l1_avg': l1_avg, 'l1_act': l1_act_avg,
|
||||||
|
'l2_cons': l2_cons, 'l2_users': l2_users, 'l2_avg': l2_avg, 'l2_act': l2_act_avg,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 输出
|
||||||
|
print(f"\n{'周':<16} {'付费':>6} {'L1课消':>7} {'L1有消':>7} {'L1人均':>7} {'L1有消人均':>9} {'L2课消':>7} {'L2有消':>7} {'L2人均':>7} {'L2有消人均':>9}")
|
||||||
|
for r in results:
|
||||||
|
print(f"{r['week']:<16} {r['paid']:>6} {r['l1_cons']:>7} {r['l1_users']:>7} {r['l1_avg']:>7.2f} {r['l1_act']:>9.2f} {r['l2_cons']:>7} {r['l2_users']:>7} {r['l2_avg']:>7.2f} {r['l2_act']:>9.2f}")
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
print("\n完成!")
|
||||||
241
scripts/course_consumption_weekly.py
Normal file
241
scripts/course_consumption_weekly.py
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
课消指标:按周统计 2025-09-01 ~ 2026-05-10
|
||||||
|
指标:
|
||||||
|
1. 人均课消数 = 课消总次数 / 付费用户数
|
||||||
|
2. 有课消用户的人均课消数 = 课消总次数 / 有课消的付费用户数
|
||||||
|
"""
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import datetime, timedelta, date
|
||||||
|
|
||||||
|
# 连接线上 PostgreSQL
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host="bj-postgres-16pob4sg.sql.tencentcdb.com",
|
||||||
|
port=28591,
|
||||||
|
user="ai_member",
|
||||||
|
password="LdfjdjL83h3h3^$&**YGG*",
|
||||||
|
dbname="vala_bi"
|
||||||
|
)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# ===== 时间参数 =====
|
||||||
|
overall_start = date(2025, 9, 1)
|
||||||
|
overall_end = date(2026, 5, 11) # exclusive,即5/10是最后一天
|
||||||
|
|
||||||
|
print(f"统计区间: {overall_start} ~ {overall_end - timedelta(days=1)}")
|
||||||
|
|
||||||
|
# ===== 生成周列表(周一~周日) =====
|
||||||
|
weeks = []
|
||||||
|
d = overall_start
|
||||||
|
while d < overall_end:
|
||||||
|
week_start = d
|
||||||
|
# 找周日
|
||||||
|
days_to_sunday = 6 - d.weekday()
|
||||||
|
week_end = d + timedelta(days=days_to_sunday)
|
||||||
|
if week_end >= overall_end:
|
||||||
|
week_end = overall_end - timedelta(days=1)
|
||||||
|
weeks.append((week_start, week_end))
|
||||||
|
d = week_end + timedelta(days=1)
|
||||||
|
|
||||||
|
print(f"共 {len(weeks)} 周")
|
||||||
|
|
||||||
|
# ===== Step 1:获取所有订单,确定每用户的付费有效期 =====
|
||||||
|
print("\nStep 1: 查询订单...")
|
||||||
|
cur.execute("""
|
||||||
|
SELECT o.account_id, o.trade_no, o.out_trade_no, o.pay_success_date,
|
||||||
|
o.order_status, o.pay_amount_int
|
||||||
|
FROM bi_vala_order o
|
||||||
|
INNER JOIN bi_vala_app_account a ON o.account_id = a.id
|
||||||
|
WHERE a.status = 1
|
||||||
|
AND a.deleted_at IS NULL
|
||||||
|
AND o.pay_success_date IS NOT NULL
|
||||||
|
AND o.pay_success_date >= '2025-01-01'
|
||||||
|
""")
|
||||||
|
orders = cur.fetchall()
|
||||||
|
print(f" 订单数: {len(orders)}")
|
||||||
|
|
||||||
|
# 获取退费信息
|
||||||
|
cur.execute("""
|
||||||
|
SELECT trade_no, out_trade_no, status
|
||||||
|
FROM bi_refund_order
|
||||||
|
WHERE status = 3
|
||||||
|
""")
|
||||||
|
refunds = set()
|
||||||
|
refunds_by_out = set()
|
||||||
|
for trade_no, out_trade_no, st in cur.fetchall():
|
||||||
|
if trade_no:
|
||||||
|
refunds.add(trade_no)
|
||||||
|
if out_trade_no:
|
||||||
|
refunds_by_out.add(out_trade_no)
|
||||||
|
|
||||||
|
print(f" 退费trade_no数: {len(refunds)}, out_trade_no数: {len(refunds_by_out)}")
|
||||||
|
|
||||||
|
# 组织订单数据:{account_id: [(pay_date, is_refunded), ...]}
|
||||||
|
account_orders = defaultdict(list)
|
||||||
|
for aid, trade_no, out_trade_no, pay_date, order_status, amount in orders:
|
||||||
|
is_refunded = (
|
||||||
|
order_status == 4 and (
|
||||||
|
(trade_no and trade_no in refunds) or
|
||||||
|
(out_trade_no and out_trade_no in refunds_by_out)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
account_orders[aid].append((pay_date, is_refunded))
|
||||||
|
|
||||||
|
# 判断每个用户是否是付费用户(到某日期为止)
|
||||||
|
def is_paid_user(aid, as_of_date):
|
||||||
|
"""截至 as_of_date,用户是否有未退费订单"""
|
||||||
|
has_paid = False
|
||||||
|
for pay_date, is_refunded in account_orders.get(aid, []):
|
||||||
|
if pay_date.date() <= as_of_date:
|
||||||
|
if not is_refunded:
|
||||||
|
has_paid = True
|
||||||
|
# 如果退了但还有其他未退订单,也算
|
||||||
|
# 重新计数:截至该日期,是否有任何未退费订单
|
||||||
|
unpaid_orders = sum(
|
||||||
|
1 for pd, ref in account_orders.get(aid, [])
|
||||||
|
if pd.date() <= as_of_date and not ref
|
||||||
|
)
|
||||||
|
return unpaid_orders > 0
|
||||||
|
|
||||||
|
# 序章 chapter_id(L1 U00 + L2 U00),需剔除
|
||||||
|
u0_chapters = {343, 344, 345, 346, 348, 55, 56, 57, 58, 59}
|
||||||
|
|
||||||
|
# ===== Step 2:获取所有课消记录 =====
|
||||||
|
print("\nStep 2: 查询课消记录(剔除序章U0)...")
|
||||||
|
# (user_id, chapter_id) -> earliest_updated_at
|
||||||
|
consumption_map = {} # key=(user_id, chapter_id) -> earliest updated_at (date)
|
||||||
|
|
||||||
|
for table_idx in range(8):
|
||||||
|
tbl = f"bi_user_chapter_play_record_{table_idx}"
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT user_id, chapter_id, updated_at
|
||||||
|
FROM {tbl}
|
||||||
|
WHERE play_status = 1
|
||||||
|
AND updated_at >= '2025-09-01'
|
||||||
|
AND updated_at < '2026-05-11'
|
||||||
|
""")
|
||||||
|
cnt = 0
|
||||||
|
for user_id, chapter_id, updated_at in cur.fetchall():
|
||||||
|
if chapter_id in u0_chapters:
|
||||||
|
continue
|
||||||
|
key = (user_id, chapter_id)
|
||||||
|
d = updated_at.date() if hasattr(updated_at, 'date') else updated_at
|
||||||
|
if isinstance(updated_at, datetime):
|
||||||
|
d = updated_at.date()
|
||||||
|
elif isinstance(updated_at, str):
|
||||||
|
d = datetime.strptime(updated_at[:10], '%Y-%m-%d').date()
|
||||||
|
else:
|
||||||
|
d = updated_at
|
||||||
|
if key not in consumption_map or d < consumption_map[key]:
|
||||||
|
consumption_map[key] = d
|
||||||
|
cnt += 1
|
||||||
|
print(f" {tbl}: {cnt} 条记录")
|
||||||
|
|
||||||
|
print(f" 去重后课消: {len(consumption_map)} 条")
|
||||||
|
|
||||||
|
# ===== Step 3:关联 character -> account =====
|
||||||
|
print("\nStep 3: 关联角色...")
|
||||||
|
all_user_ids = set(k[0] for k in consumption_map)
|
||||||
|
all_user_id_list = list(all_user_ids)
|
||||||
|
|
||||||
|
char_to_account = {}
|
||||||
|
batch_size = 500
|
||||||
|
for i in range(0, len(all_user_id_list), batch_size):
|
||||||
|
batch = all_user_id_list[i:i+batch_size]
|
||||||
|
ph = ','.join(['%s'] * len(batch))
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT id, account_id FROM bi_vala_app_character
|
||||||
|
WHERE id IN ({ph})
|
||||||
|
""", batch)
|
||||||
|
for cid, aid in cur.fetchall():
|
||||||
|
char_to_account[cid] = aid
|
||||||
|
|
||||||
|
print(f" 角色-账号映射: {len(char_to_account)}")
|
||||||
|
|
||||||
|
# ===== Step 4:按周汇总 =====
|
||||||
|
print("\nStep 4: 按周汇总...")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for ws, we in weeks:
|
||||||
|
# 分母:截至该周末的付费用户
|
||||||
|
paid_users = set()
|
||||||
|
for aid in account_orders:
|
||||||
|
if is_paid_user(aid, we):
|
||||||
|
paid_users.add(aid)
|
||||||
|
|
||||||
|
# 分子:该周内付费用户的课消次数(按最早updated_at所在周)
|
||||||
|
weekly_consumption = 0
|
||||||
|
consuming_accounts = set()
|
||||||
|
|
||||||
|
for (uid, ch_id), cons_date in consumption_map.items():
|
||||||
|
if ws <= cons_date <= we:
|
||||||
|
aid = char_to_account.get(uid)
|
||||||
|
if aid and aid in paid_users:
|
||||||
|
weekly_consumption += 1
|
||||||
|
consuming_accounts.add(aid)
|
||||||
|
|
||||||
|
n_paid = len(paid_users)
|
||||||
|
n_consuming = len(consuming_accounts)
|
||||||
|
avg_all = weekly_consumption / n_paid if n_paid > 0 else 0
|
||||||
|
avg_consuming = weekly_consumption / n_consuming if n_consuming > 0 else 0
|
||||||
|
|
||||||
|
results.append({
|
||||||
|
'week': f"{ws.strftime('%m/%d')}-{we.strftime('%m/%d')}",
|
||||||
|
'ws': ws,
|
||||||
|
'we': we,
|
||||||
|
'paid_users': n_paid,
|
||||||
|
'consumption': weekly_consumption,
|
||||||
|
'consuming_users': n_consuming,
|
||||||
|
'avg_all': avg_all,
|
||||||
|
'avg_consuming': avg_consuming,
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f" {ws}~{we}: 付费{n_paid} | 课消{weekly_consumption} | "
|
||||||
|
f"有课消{n_consuming} | 人均{avg_all:.2f} | 有消人均{avg_consuming:.2f}")
|
||||||
|
|
||||||
|
# ===== 输出结果 =====
|
||||||
|
print("\n" + "="*80)
|
||||||
|
print(f"{'周':<20} {'付费用户':>8} {'课消次数':>8} {'有消用户':>8} {'人均课消':>8} {'有消人均':>8}")
|
||||||
|
print("-"*80)
|
||||||
|
for r in results:
|
||||||
|
print(f"{r['week']:<20} {r['paid_users']:>8} {r['consumption']:>8} "
|
||||||
|
f"{r['consuming_users']:>8} {r['avg_all']:>8.2f} {r['avg_consuming']:>8.2f}")
|
||||||
|
|
||||||
|
# 月度汇总
|
||||||
|
print("\n" + "="*80)
|
||||||
|
print("月度汇总")
|
||||||
|
print("-"*80)
|
||||||
|
|
||||||
|
months_data = defaultdict(lambda: {'paid': 0, 'cons': 0, 'cons_users': set(), 'weeks': 0})
|
||||||
|
for r in results:
|
||||||
|
m = r['ws'].strftime('%Y-%m')
|
||||||
|
# 月度取最后一周的付费用户数(月末快照)
|
||||||
|
months_data[m]['paid'] = r['paid_users'] # 取月末快照
|
||||||
|
months_data[m]['cons'] += r['consumption']
|
||||||
|
months_data[m]['cons_users'].update() # 需要按周累加课消用户
|
||||||
|
months_data[m]['weeks'] += 1
|
||||||
|
|
||||||
|
# 重新按月汇总(用月末周的付费用户,累加课消)
|
||||||
|
monthly = defaultdict(lambda: {'paid': 0, 'cons': 0, 'cons_user_set': set(), 'last_paid': 0})
|
||||||
|
for r in results:
|
||||||
|
m = r['ws'].strftime('%Y-%m')
|
||||||
|
monthly[m]['cons'] += r['consumption']
|
||||||
|
monthly[m]['last_paid'] = r['paid_users']
|
||||||
|
# 有课消用户去重
|
||||||
|
# 需要在循环外处理(这里简化:直接取有课消用户快照)
|
||||||
|
monthly[m]['cons_user_count'] = r['consuming_users'] # 这不对
|
||||||
|
|
||||||
|
# 简化月度:取月内所有周的最大付费用户数(月末),累加课消
|
||||||
|
print(f"{'月份':<10} {'月末付费':>8} {'月课消':>8} {'月人均':>8}")
|
||||||
|
print("-"*50)
|
||||||
|
for m in sorted(monthly):
|
||||||
|
d = monthly[m]
|
||||||
|
avg = d['cons'] / d['last_paid'] if d['last_paid'] > 0 else 0
|
||||||
|
print(f"{m:<10} {d['last_paid']:>8} {d['cons']:>8} {avg:>8.2f}")
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
print("\n完成!")
|
||||||
Loading…
Reference in New Issue
Block a user