run_t0_fission_rate_realtime.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/env python3
  2. from pathlib import Path
  3. import sys
  4. import pandas as pd
  5. from odps_module import ODPSClient
  6. BASE = Path(__file__).resolve().parent
  7. CONFIGS = {
  8. "realtime_20260721": (
  9. BASE / "t0_fission_rate_realtime_20260721_apptype4_version1578.sql",
  10. BASE / "t0_fission_rate_realtime_20260721_apptype4_version1578.csv",
  11. ),
  12. "realtime_20260722_special_layer": (
  13. BASE / "t0_fission_rate_realtime_20260722_apptype4_version1578_no_qywx_filter_special_layer.sql",
  14. BASE / "t0_fission_rate_realtime_20260722_apptype4_version1578_no_qywx_filter_special_layer.csv",
  15. ),
  16. }
  17. MODE = next((arg for arg in sys.argv[1:] if not arg.startswith("--")), "realtime_20260721") if __name__ == "__main__" else "realtime_20260721"
  18. if __name__ == "__main__" and MODE not in CONFIGS:
  19. raise SystemExit("usage: python3 run_t0_fission_rate_realtime.py [realtime_20260721|realtime_20260722_special_layer]")
  20. SQL_FILE, OUTPUT_FILE = CONFIGS[MODE]
  21. def group_name(bucket):
  22. return "实验组(0、1)" if bucket in {"0", "1"} else "对照组(其余14桶)"
  23. def percent(value):
  24. return "" if pd.isna(value) else f"{value * 100:.4f}%"
  25. def main():
  26. data = ODPSClient().execute_sql(SQL_FILE.read_text(encoding="utf-8")).rename(columns={
  27. "stat_date": "时间",
  28. "app_type": "产品类型",
  29. "version_code": "版本号",
  30. "bucket": "尾号",
  31. "first_layer_uv": "首层UV",
  32. "fission_layer_uv": "裂变层UV",
  33. })
  34. data["时间"] = data["时间"].astype(str)
  35. data["产品类型"] = data["产品类型"].astype(str)
  36. data["版本号"] = data["版本号"].astype(str)
  37. data["尾号"] = data["尾号"].astype(str)
  38. data["行类型"] = "尾号明细"
  39. data["分组"] = data["尾号"].map(group_name)
  40. data["T0裂变率"] = data["裂变层UV"] / data["首层UV"].replace(0, pd.NA)
  41. data["T0裂变率相对对照组变化率"] = ""
  42. stat_dates = data["时间"].unique()
  43. app_types = data["产品类型"].unique()
  44. versions = data["版本号"].unique()
  45. if len(stat_dates) != 1 or len(app_types) != 1 or len(versions) != 1:
  46. raise ValueError(f"日期、产品或版本不唯一:dates={stat_dates}, app_types={app_types}, versions={versions}")
  47. stat_date, app_type, version = stat_dates[0], app_types[0], versions[0]
  48. mean_rows = []
  49. groups = [
  50. ("实验组(0、1)", {"0", "1"}, "2桶均值"),
  51. ("对照组(其余14桶)", set("23456789abcdef"), "14桶均值"),
  52. ]
  53. for group, buckets, bucket_label in groups:
  54. selected = data[data["尾号"].isin(buckets)]
  55. first_mean = selected["首层UV"].mean()
  56. fission_mean = selected["裂变层UV"].mean()
  57. mean_rows.append({
  58. "时间": stat_date,
  59. "产品类型": app_type,
  60. "版本号": version,
  61. "行类型": "每桶均值",
  62. "分组": group,
  63. "尾号": bucket_label,
  64. "首层UV": round(first_mean, 2),
  65. "裂变层UV": round(fission_mean, 2),
  66. "T0裂变率": fission_mean / first_mean if first_mean else pd.NA,
  67. "T0裂变率相对对照组变化率": "",
  68. })
  69. result = pd.concat([data, pd.DataFrame(mean_rows)], ignore_index=True)
  70. exp_idx = result.index[(result["行类型"] == "每桶均值") & (result["分组"] == "实验组(0、1)")][0]
  71. ctrl_idx = result.index[(result["行类型"] == "每桶均值") & (result["分组"] == "对照组(其余14桶)")][0]
  72. control_rate = result.loc[ctrl_idx, "T0裂变率"]
  73. if pd.notna(control_rate) and control_rate != 0:
  74. result.loc[exp_idx, "T0裂变率相对对照组变化率"] = percent(
  75. result.loc[exp_idx, "T0裂变率"] / control_rate - 1
  76. )
  77. result["T0裂变率"] = result["T0裂变率"].map(percent)
  78. detail_mask = result["行类型"] == "尾号明细"
  79. for column in ["首层UV", "裂变层UV"]:
  80. result[column] = result[column].astype(object)
  81. result.loc[detail_mask, column] = result.loc[detail_mask, column].map(lambda value: f"{value:.0f}")
  82. result.loc[~detail_mask, column] = result.loc[~detail_mask, column].map(lambda value: f"{value:.2f}")
  83. result = result[[
  84. "时间", "产品类型", "版本号", "行类型", "分组", "尾号",
  85. "首层UV", "裂变层UV", "T0裂变率", "T0裂变率相对对照组变化率",
  86. ]]
  87. result.to_csv(OUTPUT_FILE, index=False, encoding="utf-8-sig")
  88. print(f"[CSV] {OUTPUT_FILE}", flush=True)
  89. print(result.to_string(index=False), flush=True)
  90. if __name__ == "__main__":
  91. main()