Add aggregation helper script
This commit is contained in:
@@ -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()
|
||||||
Reference in New Issue
Block a user