|
@@ -30,6 +30,7 @@ from roi_control.reporting import (
|
|
|
AGENCY_SUMMARY_SHEETS,
|
|
AGENCY_SUMMARY_SHEETS,
|
|
|
DAILY_SHEETS,
|
|
DAILY_SHEETS,
|
|
|
SUMMARY_SHEETS,
|
|
SUMMARY_SHEETS,
|
|
|
|
|
+ _agency_summary_frame,
|
|
|
_daily_frame,
|
|
_daily_frame,
|
|
|
_summary_frame,
|
|
_summary_frame,
|
|
|
_visible_columns,
|
|
_visible_columns,
|
|
@@ -154,8 +155,8 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
self.assertEqual(date_window("20260722"), ("20260720", "20260722"))
|
|
self.assertEqual(date_window("20260722"), ("20260720", "20260722"))
|
|
|
run_id, _ = _run_identity("20260722", FISSION_PARAMETERS)
|
|
run_id, _ = _run_identity("20260722", FISSION_PARAMETERS)
|
|
|
self.assertIn("m8", run_id)
|
|
self.assertIn("m8", run_id)
|
|
|
- self.assertIn("p13", run_id)
|
|
|
|
|
- self.assertIn("r37", run_id)
|
|
|
|
|
|
|
+ self.assertIn("p15", run_id)
|
|
|
|
|
+ self.assertIn("r41", run_id)
|
|
|
|
|
|
|
|
def test_current_creative_status_only_reads_stop_decisions(self):
|
|
def test_current_creative_status_only_reads_stop_decisions(self):
|
|
|
rows = pd.DataFrame(
|
|
rows = pd.DataFrame(
|
|
@@ -227,7 +228,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
pool["阈值样本状态"].eq("进入三日渠道独立阈值样本池").all()
|
|
pool["阈值样本状态"].eq("进入三日渠道独立阈值样本池").all()
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- def test_self_stop_budget_uses_latest_cost_with_six_two_two_soft_allocation(self):
|
|
|
|
|
|
|
+ def test_self_stop_budget_uses_latest_cost_with_six_four_soft_allocation(self):
|
|
|
rows = []
|
|
rows = []
|
|
|
formal = [
|
|
formal = [
|
|
|
("formal-1", 0.10, 30.0),
|
|
("formal-1", 0.10, 30.0),
|
|
@@ -250,7 +251,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
[
|
|
[
|
|
|
row(ENTITY_SELF, "hard-1", DATES[-1], 0.05, uv=300, cost=20.0),
|
|
row(ENTITY_SELF, "hard-1", DATES[-1], 0.05, uv=300, cost=20.0),
|
|
|
row(ENTITY_SELF, "hard-2", DATES[-1], 0.10, uv=300, cost=200.0),
|
|
row(ENTITY_SELF, "hard-2", DATES[-1], 0.10, uv=300, cost=200.0),
|
|
|
- row(ENTITY_SELF, "rank-1", DATES[-1], 0.30, uv=600, cost=20.0),
|
|
|
|
|
|
|
+ row(ENTITY_SELF, "rank-1", DATES[-1], 0.05, uv=600, cost=20.0),
|
|
|
row(ENTITY_SELF, "rank-2", DATES[-1], 0.40, uv=600, cost=700.0),
|
|
row(ENTITY_SELF, "rank-2", DATES[-1], 0.40, uv=600, cost=700.0),
|
|
|
]
|
|
]
|
|
|
)
|
|
)
|
|
@@ -281,18 +282,17 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
self.assertAlmostEqual(float(self_threshold["实际关停成本占比"]), 0.05)
|
|
self.assertAlmostEqual(float(self_threshold["实际关停成本占比"]), 0.05)
|
|
|
self.assertEqual(self_threshold["关停成本预算状态"], "正常范围")
|
|
self.assertEqual(self_threshold["关停成本预算状态"], "正常范围")
|
|
|
self.assertAlmostEqual(float(self_threshold["三日基础预算成本"]), 60.0)
|
|
self.assertAlmostEqual(float(self_threshold["三日基础预算成本"]), 60.0)
|
|
|
- self.assertAlmostEqual(float(self_threshold["单日绝对低ROI基础预算成本"]), 20.0)
|
|
|
|
|
- self.assertAlmostEqual(float(self_threshold["单日高UV基础预算成本"]), 20.0)
|
|
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日基础预算成本"]), 40.0)
|
|
|
self.assertAlmostEqual(float(self_threshold["三日关停线"]), 0.20)
|
|
self.assertAlmostEqual(float(self_threshold["三日关停线"]), 0.20)
|
|
|
self.assertAlmostEqual(float(self_threshold["三日关停线分位点"]), 0.50)
|
|
self.assertAlmostEqual(float(self_threshold["三日关停线分位点"]), 0.50)
|
|
|
- self.assertAlmostEqual(float(self_threshold["单日绝对低ROI关停线"]), 0.05)
|
|
|
|
|
- self.assertAlmostEqual(float(self_threshold["单日高UV关停线"]), 0.30)
|
|
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日P10线"]), 0.05)
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日合并资格线"]), 0.05)
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日实际关停线"]), 0.05)
|
|
|
self.assertEqual(
|
|
self.assertEqual(
|
|
|
selected.groupby("关停规则")[f"成本_{DATES[-1]}"].sum().to_dict(),
|
|
selected.groupby("关停规则")[f"成本_{DATES[-1]}"].sum().to_dict(),
|
|
|
{
|
|
{
|
|
|
"三日持续低ROI": 60.0,
|
|
"三日持续低ROI": 60.0,
|
|
|
- "单日绝对低ROI": 20.0,
|
|
|
|
|
- "单日高UV低分位": 20.0,
|
|
|
|
|
|
|
+ "单日绝对低ROI且P10": 40.0,
|
|
|
},
|
|
},
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -339,7 +339,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
).all()
|
|
).all()
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- def test_unused_group_budget_rolls_to_remaining_low_roi_candidate(self):
|
|
|
|
|
|
|
+ def test_unused_one_day_budget_rolls_to_three_day_candidates(self):
|
|
|
rows = []
|
|
rows = []
|
|
|
formal = [
|
|
formal = [
|
|
|
("formal-roll-1", 0.10, 60.0),
|
|
("formal-roll-1", 0.10, 60.0),
|
|
@@ -359,7 +359,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
)
|
|
)
|
|
|
rows.extend(
|
|
rows.extend(
|
|
|
[
|
|
[
|
|
|
- row(ENTITY_SELF, "rank-roll-1", DATES[-1], 0.30, uv=600, cost=20),
|
|
|
|
|
|
|
+ row(ENTITY_SELF, "rank-roll-1", DATES[-1], 0.05, uv=600, cost=20),
|
|
|
row(ENTITY_SELF, "rank-roll-2", DATES[-1], 0.40, uv=600, cost=1000),
|
|
row(ENTITY_SELF, "rank-roll-2", DATES[-1], 0.40, uv=600, cost=1000),
|
|
|
]
|
|
]
|
|
|
)
|
|
)
|
|
@@ -384,7 +384,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
self.assertAlmostEqual(float(self_threshold["实际关停成本"]), 100.0)
|
|
self.assertAlmostEqual(float(self_threshold["实际关停成本"]), 100.0)
|
|
|
self.assertAlmostEqual(float(self_threshold["三日基础预算成本"]), 60.0)
|
|
self.assertAlmostEqual(float(self_threshold["三日基础预算成本"]), 60.0)
|
|
|
self.assertAlmostEqual(float(self_threshold["三日实际关停成本"]), 80.0)
|
|
self.assertAlmostEqual(float(self_threshold["三日实际关停成本"]), 80.0)
|
|
|
- self.assertAlmostEqual(float(self_threshold["单日高UV实际关停成本"]), 20.0)
|
|
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日实际关停成本"]), 20.0)
|
|
|
self.assertEqual(self_threshold["关停成本预算状态"], "正常范围")
|
|
self.assertEqual(self_threshold["关停成本预算状态"], "正常范围")
|
|
|
|
|
|
|
|
def test_creative_p80_scale_requires_ad_age_at_least_three_days(self):
|
|
def test_creative_p80_scale_requires_ad_age_at_least_three_days(self):
|
|
@@ -430,14 +430,14 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
self.assertEqual(target["日均首层UV"], 100)
|
|
self.assertEqual(target["日均首层UV"], 100)
|
|
|
self.assertTrue(candidates["广告id"].eq("latest-only").any())
|
|
self.assertTrue(candidates["广告id"].eq("latest-only").any())
|
|
|
|
|
|
|
|
- def test_one_day_supplement_requires_ad_age_over_three_days(self):
|
|
|
|
|
|
|
+ def test_one_day_rule_requires_absolute_low_roi_and_p10_and_age(self):
|
|
|
daily = self.build_daily()
|
|
daily = self.build_daily()
|
|
|
supplemental = [
|
|
supplemental = [
|
|
|
- row(ENTITY_SELF, "one-day-hard", DATES[-1], 0.2, uv=300, cost=10),
|
|
|
|
|
- row(ENTITY_SELF, "one-day-p30", DATES[-1], 0.5, uv=600, cost=10),
|
|
|
|
|
- row(ENTITY_SELF, "one-day-young", DATES[-1], 0.6, uv=600, cost=10),
|
|
|
|
|
- row(ENTITY_SELF, "one-day-mid", DATES[-1], 8.0, uv=600),
|
|
|
|
|
- row(ENTITY_SELF, "one-day-high", DATES[-1], 9.0, uv=600, cost=900),
|
|
|
|
|
|
|
+ row(ENTITY_SELF, "one-day-both", DATES[-1], 0.05, uv=300, cost=10),
|
|
|
|
|
+ row(ENTITY_SELF, "one-day-not-p10", DATES[-1], 0.15, uv=300, cost=10),
|
|
|
|
|
+ row(ENTITY_SELF, "one-day-young", DATES[-1], 0.01, uv=300, cost=10),
|
|
|
|
|
+ row(ENTITY_SELF, "one-day-mid", DATES[-1], 1.0, uv=300, cost=10),
|
|
|
|
|
+ row(ENTITY_SELF, "one-day-high", DATES[-1], 2.0, uv=300, cost=900),
|
|
|
]
|
|
]
|
|
|
daily = pd.concat([daily, pd.DataFrame(supplemental)], ignore_index=True)
|
|
daily = pd.concat([daily, pd.DataFrame(supplemental)], ignore_index=True)
|
|
|
ages = pd.concat(
|
|
ages = pd.concat(
|
|
@@ -446,8 +446,8 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
pd.DataFrame(
|
|
pd.DataFrame(
|
|
|
{
|
|
{
|
|
|
"广告id": [
|
|
"广告id": [
|
|
|
- "one-day-hard",
|
|
|
|
|
- "one-day-p30",
|
|
|
|
|
|
|
+ "one-day-both",
|
|
|
|
|
+ "one-day-not-p10",
|
|
|
"one-day-young",
|
|
"one-day-young",
|
|
|
"one-day-mid",
|
|
"one-day-mid",
|
|
|
"one-day-high",
|
|
"one-day-high",
|
|
@@ -460,33 +460,28 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
)
|
|
)
|
|
|
_, thresholds, summary = evaluate_rules(daily, DATES, ages)
|
|
_, thresholds, summary = evaluate_rules(daily, DATES, ages)
|
|
|
self_threshold = thresholds.set_index("entity_type").loc[ENTITY_SELF]
|
|
self_threshold = thresholds.set_index("entity_type").loc[ENTITY_SELF]
|
|
|
- self.assertEqual(int(self_threshold["单日高UV样本数"]), 8)
|
|
|
|
|
- self.assertAlmostEqual(float(self_threshold["t_one_day_stop"]), 0.5)
|
|
|
|
|
|
|
+ self.assertEqual(int(self_threshold["单日候选池样本数"]), 4)
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日P10线"]), 0.08)
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日合并资格线"]), 0.08)
|
|
|
targets = summary.set_index("广告id")
|
|
targets = summary.set_index("广告id")
|
|
|
- self.assertEqual(targets.loc["one-day-hard", "动作"], "关停")
|
|
|
|
|
- self.assertIn("绝对低ROI候选线", targets.loc["one-day-hard", "动作原因"])
|
|
|
|
|
- self.assertIn("启用单日补充规则", targets.loc["one-day-hard", "动作原因"])
|
|
|
|
|
- self.assertIn("最新日预测总效率ROI", targets.loc["one-day-hard", "动作原因"])
|
|
|
|
|
- self.assertIn("三日预测总效率ROI", targets.loc["one-day-hard", "动作原因"])
|
|
|
|
|
- self.assertIn("不参与本次单日判断", targets.loc["one-day-hard", "动作原因"])
|
|
|
|
|
- self.assertIn("广告age=4>3天", targets.loc["one-day-hard", "动作原因"])
|
|
|
|
|
- self.assertEqual(targets.loc["one-day-p30", "动作"], "关停")
|
|
|
|
|
- self.assertIn("单日高UV动态分位候选", targets.loc["one-day-p30", "动作原因"])
|
|
|
|
|
|
|
+ self.assertEqual(targets.loc["one-day-both", "动作"], "关停")
|
|
|
|
|
+ self.assertEqual(
|
|
|
|
|
+ targets.loc["one-day-both", "关停规则"],
|
|
|
|
|
+ "单日绝对低ROI且P10",
|
|
|
|
|
+ )
|
|
|
|
|
+ self.assertIn("同时满足", targets.loc["one-day-both", "动作原因"])
|
|
|
|
|
+ self.assertIn("ROI≤0.20", targets.loc["one-day-both", "动作原因"])
|
|
|
|
|
+ self.assertIn("P10", targets.loc["one-day-both", "动作原因"])
|
|
|
|
|
+ self.assertEqual(targets.loc["one-day-not-p10", "动作"], "观察")
|
|
|
|
|
+ self.assertIn("未进入后10%", targets.loc["one-day-not-p10", "动作原因"])
|
|
|
self.assertEqual(targets.loc["one-day-young", "动作"], "观察")
|
|
self.assertEqual(targets.loc["one-day-young", "动作"], "观察")
|
|
|
self.assertIn("广告age=3≤3天", targets.loc["one-day-young", "动作原因"])
|
|
self.assertIn("广告age=3≤3天", targets.loc["one-day-young", "动作原因"])
|
|
|
- self.assertEqual(targets.loc["one-day-mid", "动作"], "观察")
|
|
|
|
|
- self.assertIn(
|
|
|
|
|
- "未被5%成本软预算选中",
|
|
|
|
|
- targets.loc["one-day-mid", "动作原因"],
|
|
|
|
|
- )
|
|
|
|
|
creative_frame = _summary_frame(summary, ENTITY_SELF)
|
|
creative_frame = _summary_frame(summary, ENTITY_SELF)
|
|
|
creative_stops = creative_frame[
|
|
creative_stops = creative_frame[
|
|
|
creative_frame["建议动作"].eq("关停创意")
|
|
creative_frame["建议动作"].eq("关停创意")
|
|
|
]
|
|
]
|
|
|
- self.assertEqual(
|
|
|
|
|
- creative_stops["广告id"].tolist(),
|
|
|
|
|
- ["one-day-hard", "one-day-p30"],
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ self.assertIn("one-day-both", creative_stops["广告id"].tolist())
|
|
|
|
|
+ self.assertNotIn("one-day-not-p10", creative_stops["广告id"].tolist())
|
|
|
self.assertTrue(creative_stops["动作"].eq("关停").all())
|
|
self.assertTrue(creative_stops["动作"].eq("关停").all())
|
|
|
self.assertTrue(
|
|
self.assertTrue(
|
|
|
summary[
|
|
summary[
|
|
@@ -495,6 +490,43 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
]["广告age"].ge(4).all()
|
|
]["广告age"].ge(4).all()
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ def test_one_day_p10_without_absolute_low_roi_is_observe(self):
|
|
|
|
|
+ daily = self.build_daily()
|
|
|
|
|
+ supplemental = [
|
|
|
|
|
+ row(ENTITY_SELF, f"one-day-high-{index}", DATES[-1], roi, uv=300, cost=10)
|
|
|
|
|
+ for index, roi in enumerate([0.30, 0.40, 0.50, 0.60, 0.70])
|
|
|
|
|
+ ]
|
|
|
|
|
+ daily = pd.concat([daily, pd.DataFrame(supplemental)], ignore_index=True)
|
|
|
|
|
+ ages = pd.concat(
|
|
|
|
|
+ [
|
|
|
|
|
+ self.ages(),
|
|
|
|
|
+ pd.DataFrame(
|
|
|
|
|
+ {
|
|
|
|
|
+ "广告id": [f"one-day-high-{index}" for index in range(5)],
|
|
|
|
|
+ "广告age": [10] * 5,
|
|
|
|
|
+ }
|
|
|
|
|
+ ),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ignore_index=True,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ _, thresholds, summary = evaluate_rules(daily, DATES, ages)
|
|
|
|
|
+ self_threshold = thresholds.set_index("entity_type").loc[ENTITY_SELF]
|
|
|
|
|
+ target = summary[summary["广告id"].eq("one-day-high-0")].iloc[0]
|
|
|
|
|
+ self.assertGreater(float(self_threshold["单日P10线"]), 0.20)
|
|
|
|
|
+ self.assertAlmostEqual(float(self_threshold["单日合并资格线"]), 0.20)
|
|
|
|
|
+ self.assertEqual(target["动作"], "观察")
|
|
|
|
|
+ self.assertIn("高于绝对线0.20", target["动作原因"])
|
|
|
|
|
+
|
|
|
|
|
+ def test_three_day_formal_entity_never_reenters_one_day_rule(self):
|
|
|
|
|
+ daily = self.build_daily()
|
|
|
|
|
+ ages = self.ages()
|
|
|
|
|
+ _, _, summary = evaluate_rules(daily, DATES, ages)
|
|
|
|
|
+ target = summary[summary["广告id"].eq("creative-ad-0")].iloc[0]
|
|
|
|
|
+ self.assertEqual(target["阈值样本状态"], "进入三日渠道独立阈值样本池")
|
|
|
|
|
+ self.assertNotEqual(target["关停规则"], "单日绝对低ROI且P10")
|
|
|
|
|
+ self.assertNotIn("单日", target["动作原因"])
|
|
|
|
|
+
|
|
|
def test_daily_prediction_uses_same_day_t0_fission_revenue_once(self):
|
|
def test_daily_prediction_uses_same_day_t0_fission_revenue_once(self):
|
|
|
raw = pd.DataFrame([row(ENTITY_SELF, "formula", DATES[-1], 0)])
|
|
raw = pd.DataFrame([row(ENTITY_SELF, "formula", DATES[-1], 0)])
|
|
|
raw.loc[0, ["成本", "效率收入", "裂变效率收入"]] = [100, 50, 30]
|
|
raw.loc[0, ["成本", "效率收入", "裂变效率收入"]] = [100, 50, 30]
|
|
@@ -669,6 +701,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
)
|
|
)
|
|
|
self.assertIn("日均T0裂变率", frame.columns)
|
|
self.assertIn("日均T0裂变率", frame.columns)
|
|
|
self.assertNotIn("三日加权平均T0裂变率", _visible_columns(SUMMARY_SHEETS[ENTITY_SELF]))
|
|
self.assertNotIn("三日加权平均T0裂变率", _visible_columns(SUMMARY_SHEETS[ENTITY_SELF]))
|
|
|
|
|
+ self.assertIn("三日均值ROI", frame.columns)
|
|
|
self.assertIn("当日效率ROI", frame.columns)
|
|
self.assertIn("当日效率ROI", frame.columns)
|
|
|
self.assertIn("预测总效率ROI", frame.columns)
|
|
self.assertIn("预测总效率ROI", frame.columns)
|
|
|
visible = _visible_columns(SUMMARY_SHEETS[ENTITY_SELF])
|
|
visible = _visible_columns(SUMMARY_SHEETS[ENTITY_SELF])
|
|
@@ -681,8 +714,9 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
for removed in ("动作", "动作原因", "阈值样本状态", "执行状态", "执行结果"):
|
|
for removed in ("动作", "动作原因", "阈值样本状态", "执行状态", "执行结果"):
|
|
|
self.assertNotIn(removed, visible)
|
|
self.assertNotIn(removed, visible)
|
|
|
self.assertEqual(
|
|
self.assertEqual(
|
|
|
- visible[visible.index("当日效率ROI") : visible.index("建议说明") + 1],
|
|
|
|
|
|
|
+ visible[visible.index("三日均值ROI") : visible.index("建议说明") + 1],
|
|
|
[
|
|
[
|
|
|
|
|
+ "三日均值ROI",
|
|
|
"当日效率ROI",
|
|
"当日效率ROI",
|
|
|
"预测总效率ROI",
|
|
"预测总效率ROI",
|
|
|
"关停线",
|
|
"关停线",
|
|
@@ -702,6 +736,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
self.assertTrue(gzh_frame["扩量线(P80)"].isna().all())
|
|
self.assertTrue(gzh_frame["扩量线(P80)"].isna().all())
|
|
|
self.assertIn("是否低于三日关停线", frame.columns)
|
|
self.assertIn("是否低于三日关停线", frame.columns)
|
|
|
self.assertNotIn("关停线(P25)", frame.columns)
|
|
self.assertNotIn("关停线(P25)", frame.columns)
|
|
|
|
|
+
|
|
|
self.assertNotIn("整体实体等权P25关停线", frame.columns)
|
|
self.assertNotIn("整体实体等权P25关停线", frame.columns)
|
|
|
self.assertEqual(set(detail["dt"]), set(DATES))
|
|
self.assertEqual(set(detail["dt"]), set(DATES))
|
|
|
self.assertTrue((detail.groupby("广告id").size() == 3).all())
|
|
self.assertTrue((detail.groupby("广告id").size() == 3).all())
|
|
@@ -742,7 +777,11 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
)
|
|
)
|
|
|
for sheet_name in expected:
|
|
for sheet_name in expected:
|
|
|
self.assertEqual(workbook[sheet_name].freeze_panes, "H2")
|
|
self.assertEqual(workbook[sheet_name].freeze_panes, "H2")
|
|
|
- self.assertEqual(len(workbook[sheet_name].conditional_formatting), 2)
|
|
|
|
|
|
|
+ expected_rules = 3 if sheet_name in SUMMARY_SHEETS.values() else 2
|
|
|
|
|
+ self.assertEqual(
|
|
|
|
|
+ len(workbook[sheet_name].conditional_formatting),
|
|
|
|
|
+ expected_rules,
|
|
|
|
|
+ )
|
|
|
self.assertEqual(
|
|
self.assertEqual(
|
|
|
workbook[SUMMARY_SHEETS[ENTITY_SELF_AD]].sheet_state, "hidden"
|
|
workbook[SUMMARY_SHEETS[ENTITY_SELF_AD]].sheet_state, "hidden"
|
|
|
)
|
|
)
|
|
@@ -755,7 +794,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
for rules in creative_sheet.conditional_formatting._cf_rules.values()
|
|
for rules in creative_sheet.conditional_formatting._cf_rules.values()
|
|
|
for rule in rules
|
|
for rule in rules
|
|
|
]
|
|
]
|
|
|
- self.assertEqual(len(color_rules), 2)
|
|
|
|
|
|
|
+ self.assertEqual(len(color_rules), 3)
|
|
|
for rule in color_rules:
|
|
for rule in color_rules:
|
|
|
self.assertEqual(rule.type, "colorScale")
|
|
self.assertEqual(rule.type, "colorScale")
|
|
|
colors = [color.rgb[-6:] for color in rule.colorScale.color]
|
|
colors = [color.rgb[-6:] for color in rule.colorScale.color]
|
|
@@ -813,6 +852,12 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
creative_sheet.cell(2, creative_headers["广告age"]).number_format,
|
|
creative_sheet.cell(2, creative_headers["广告age"]).number_format,
|
|
|
"0",
|
|
"0",
|
|
|
)
|
|
)
|
|
|
|
|
+ self.assertEqual(
|
|
|
|
|
+ creative_sheet.cell(
|
|
|
|
|
+ 2, creative_headers["三日均值ROI"]
|
|
|
|
|
+ ).number_format,
|
|
|
|
|
+ "0.00",
|
|
|
|
|
+ )
|
|
|
self.assertEqual(
|
|
self.assertEqual(
|
|
|
creative_sheet.cell(
|
|
creative_sheet.cell(
|
|
|
2, creative_headers["当日效率ROI"]
|
|
2, creative_headers["当日效率ROI"]
|
|
@@ -856,7 +901,7 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
)
|
|
)
|
|
|
self.assertEqual(
|
|
self.assertEqual(
|
|
|
run_summary.cell(
|
|
run_summary.cell(
|
|
|
- summary_rows["小程序单日高UV关停线"], 2
|
|
|
|
|
|
|
+ summary_rows["小程序单日实际关停线"], 2
|
|
|
).number_format,
|
|
).number_format,
|
|
|
"0.00",
|
|
"0.00",
|
|
|
)
|
|
)
|
|
@@ -877,6 +922,29 @@ class RoiThreeDayRulesTest(unittest.TestCase):
|
|
|
)
|
|
)
|
|
|
self.assertGreater(len(ad_sheet.data_validations.dataValidation), 0)
|
|
self.assertGreater(len(ad_sheet.data_validations.dataValidation), 0)
|
|
|
|
|
|
|
|
|
|
+ def test_summary_latest_actual_roi_and_agency_score_use_latest_day(self):
|
|
|
|
|
+ rows = pd.DataFrame(
|
|
|
|
|
+ [
|
|
|
|
|
+ row(ENTITY_SELF, "score-window", dt, roi)
|
|
|
|
|
+ for dt, roi in zip(DATES, [1.0, 2.0, 3.0])
|
|
|
|
|
+ ]
|
|
|
|
|
+ )
|
|
|
|
|
+ rows.loc[rows["dt"].eq(DATES[-1]), "裂变效率收入"] = 100.0
|
|
|
|
|
+ ages = pd.DataFrame({"广告id": ["score-window"], "广告age": [10]})
|
|
|
|
|
+ _, _, summary = evaluate_rules(rows, DATES, ages)
|
|
|
|
|
+
|
|
|
|
|
+ internal = _summary_frame(summary, ENTITY_SELF).iloc[0]
|
|
|
|
|
+ agency = _agency_summary_frame(summary, ENTITY_SELF).iloc[0]
|
|
|
|
|
+ snapshot = summary.iloc[0]
|
|
|
|
|
+ latest_actual = float(snapshot[f"实际ROI_{DATES[-1]}"])
|
|
|
|
|
+ latest_predicted = float(snapshot[f"ROI_{DATES[-1]}"])
|
|
|
|
|
+
|
|
|
|
|
+ self.assertNotAlmostEqual(latest_actual, latest_predicted)
|
|
|
|
|
+ self.assertAlmostEqual(float(internal["三日均值ROI"]), float(snapshot["实际ROI"]))
|
|
|
|
|
+ self.assertAlmostEqual(float(internal["当日效率ROI"]), latest_actual)
|
|
|
|
|
+ self.assertAlmostEqual(float(internal["预测总效率ROI"]), float(snapshot["ROI"]))
|
|
|
|
|
+ self.assertAlmostEqual(float(agency["评分"]), latest_actual)
|
|
|
|
|
+
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if __name__ == "__main__":
|
|
|
unittest.main()
|
|
unittest.main()
|