Add aggregation helper script

This commit is contained in:
2026-08-24 15:42:47 +08:00
parent f704fd1b18
commit c046d3f7f8
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""Aggregate SW Ads creative_breakdown JSON into product-level video metrics."""
import argparse, json
from pathlib import Path
def ratio(n, d): return n / d if d else None
def main():
p = argparse.ArgumentParser()
p.add_argument("input", type=Path)
p.add_argument("--product-id", action="append", dest="product_ids")
p.add_argument("--top", type=int, default=5)
a = p.parse_args()
data = json.loads(a.input.read_text(encoding="utf-8"))
cols = [c["name"] for c in data["columns"]]
idx = {name: i for i, name in enumerate(cols)}
required = {"external_creative_id","creative_identity_kind","creative_product_id","spend","gross_revenue","orders","product_impressions","product_clicks"}
missing = sorted(required - idx.keys())
if missing: raise SystemExit("missing required columns: " + ", ".join(missing))
selected, groups = set(a.product_ids or []), {}
for row in data["rows"]:
cid = str(row[idx["external_creative_id"]] or "")
pid = str(row[idx["creative_product_id"]] or "unknown")
if row[idx["creative_identity_kind"]] == "product_card" or cid.startswith("product_card:"): continue
if selected and pid not in selected: continue
g = groups.setdefault(pid,{"product_id":pid,"video_count":0,"spend":0.0,"gross_revenue":0.0,"orders":0.0,"product_impressions":0.0,"product_clicks":0.0,"videos":[]})
g["video_count"] += 1
for f in ("spend","gross_revenue","orders","product_impressions","product_clicks"): g[f] += row[idx[f]] or 0
v = {"external_creative_id":cid}
for f in ("external_creative_name","creative_creator_name"):
if f in idx: v[f] = row[idx[f]]
for f in ("spend","gross_revenue","orders","product_impressions","product_clicks"): v[f] = row[idx[f]] or 0
g["videos"].append(v)
out=[]
for g in groups.values():
g["video_ctr"] = ratio(g["product_clicks"],g["product_impressions"])
g["order_conversion_rate"] = ratio(g["orders"],g["product_clicks"])
g["roas"] = ratio(g["gross_revenue"],g["spend"])
g["cost_per_order"] = ratio(g["spend"],g["orders"])
g["videos"].sort(key=lambda v:(v["orders"],v["gross_revenue"],-v["spend"]),reverse=True)
g["top_videos"] = g.pop("videos")[:max(a.top,0)]; out.append(g)
out.sort(key=lambda g:(g["orders"],g["gross_revenue"]),reverse=True)
print(json.dumps({"products":out},ensure_ascii=False,indent=2))
if __name__ == "__main__": main()