| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- from __future__ import annotations
- import sys
- import unittest
- from pathlib import Path
- import pandas as pd
- PROJECT_DIR = Path(__file__).resolve().parents[1]
- WORKSPACE_ROOT = PROJECT_DIR.parent
- for path in (PROJECT_DIR, WORKSPACE_ROOT):
- if str(path) not in sys.path:
- sys.path.insert(0, str(path))
- from scripts.build_report import group_summary
- from src.social_logic import aggregate_groups, aggregate_relationships
- from src.user_input import load_users
- FIXTURE_DIR = PROJECT_DIR / "fixtures" / "v2_220"
- SAMPLE_PATH = PROJECT_DIR / "samples" / "v2_220_20260810.csv"
- class OfflineRegressionTest(unittest.TestCase):
- @classmethod
- def setUpClass(cls) -> None:
- cls.users = load_users(SAMPLE_PATH, lookback_days=180)
- cls.behavior = pd.read_csv(FIXTURE_DIR / "user_detail.csv")
- cls.relationships = pd.read_csv(FIXTURE_DIR / "relationships.csv")
- cls.groups = pd.read_csv(FIXTURE_DIR / "social_group_features.csv")
- cls.expected_social = pd.read_csv(FIXTURE_DIR / "social_user_features.csv")
- def test_sample_contract(self) -> None:
- self.assertEqual(len(self.users), 220)
- self.assertEqual(self.users["mid"].nunique(), 220)
- self.assertTrue((self.users["window_end_dt"] < self.users["anchor_dt"]).all())
- counts = self.users.groupby(["user_type", "sub_category"]).size().to_dict()
- self.assertEqual(counts[("明确举报人", "明确举报人")], 7)
- self.assertEqual(counts[("审核人", "审核人")], 13)
- self.assertEqual(counts[("正常用户", "正常用户")], 100)
- suspected = sum(value for (group, _), value in counts.items() if group == "疑似举报人")
- self.assertEqual(suspected, 100)
- def test_long_retention_play_and_share_sources(self) -> None:
- builder = (PROJECT_DIR / "src" / "feature_sql.py").read_text(encoding="utf-8")
- dataworks = (
- PROJECT_DIR / "sql" / "dataworks_single_user_180d_all_in_one.sql"
- ).read_text(encoding="utf-8")
- for sql in (builder, dataworks):
- self.assertIn("loghubods.ods_video_play_log_day", sql)
- self.assertIn("s.topic = 'share'", sql)
- self.assertNotIn("LEFT JOIN loghubods.video_play_log p", sql)
- def test_social_aggregation_matches_saved_result(self) -> None:
- relationships = aggregate_relationships(self.users, self.relationships)
- groups = aggregate_groups(self.users, self.groups)
- actual = relationships.merge(groups, on="用户id", validate="one_to_one")
- expected = self.expected_social
- self.assertEqual(len(actual), 220)
- self.assertEqual(actual["用户id"].nunique(), 220)
- columns = [
- "社交关系点击次数",
- "风险来源点击次数",
- "同一卡片最大连续点击次数",
- "有效来源群数",
- "来源群访问UV合计",
- "来源群有效播放UV合计",
- ]
- merged = actual[["用户id", *columns]].merge(
- expected[["用户id", *columns]],
- on="用户id",
- suffixes=("_actual", "_expected"),
- validate="one_to_one",
- )
- for column in columns:
- pd.testing.assert_series_equal(
- pd.to_numeric(merged[f"{column}_actual"], errors="coerce").fillna(0),
- pd.to_numeric(merged[f"{column}_expected"], errors="coerce").fillna(0),
- check_names=False,
- )
- def test_population_group_facts(self) -> None:
- detail = self.behavior.merge(
- self.expected_social,
- on="用户id",
- how="left",
- validate="one_to_one",
- )
- summary = group_summary(detail).set_index("用户分类")
- expected = {
- "明确举报人": (7, 8, 149, 0),
- "审核人": (13, 2, 54, 19),
- "疑似举报人": (100, 316, 5560, 2543),
- "正常用户": (100, 310, 6404, 2760),
- }
- for group, values in expected.items():
- self.assertEqual(int(summary.at[group, "总人数"]), values[0])
- self.assertEqual(int(summary.at[group, "访问来源群数合计"]), values[1])
- self.assertEqual(
- int(summary.at[group, "来源群访问用户数合计(按群UV求和)"]),
- values[2],
- )
- self.assertEqual(
- int(summary.at[group, "来源群有效播放用户数合计(按群UV求和)"]),
- values[3],
- )
- if __name__ == "__main__":
- unittest.main()
|