run_full.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """全时间段:15 分钟首周期特征 -> 自适应标签。"""
  2. from __future__ import annotations
  3. import json
  4. import sys
  5. from pathlib import Path
  6. import pandas as pd
  7. ROOT = Path(__file__).resolve().parents[1]
  8. if str(ROOT) not in sys.path:
  9. sys.path.insert(0, str(ROOT))
  10. from _tmp_cylinder_vibration import adaptive, config, data, features, labels, local_labels
  11. def extract_rows(metadata: list[dict], chunk_size: int, tag: str) -> list[dict]:
  12. rows: list[dict] = []
  13. total = len(metadata)
  14. for offset in range(0, total, chunk_size):
  15. chunk = metadata[offset:offset + chunk_size]
  16. samples = data.fetch_samples([int(item["id"]) for item in chunk], chunk_size=chunk_size)
  17. for item in chunk:
  18. signal = samples.get(int(item["id"]))
  19. if signal is None:
  20. continue
  21. feature = features.extract_features(
  22. signal,
  23. float(item.get("sample_frequency_hz") or 0),
  24. float(item.get("rpm") or 0),
  25. )
  26. if feature is None:
  27. continue
  28. row = dict(item)
  29. row.update(feature)
  30. rows.append(row)
  31. print(f"[{tag}] {min(offset + chunk_size, total):,}/{total:,} files, features={len(rows):,}", flush=True)
  32. return rows
  33. def load_or_extract(metadata: list[dict], path: Path, chunk_size: int, refresh: bool) -> list[dict]:
  34. if path.exists() and not refresh:
  35. print(f"[full] reuse {path}")
  36. return pd.read_csv(path).to_dict("records")
  37. rows = extract_rows(metadata, chunk_size, "full")
  38. if rows:
  39. pd.DataFrame(rows).to_csv(path, index=False)
  40. print(f"[full] wrote {path} ({len(rows):,})")
  41. return rows
  42. def main() -> None:
  43. import argparse
  44. parser = argparse.ArgumentParser()
  45. parser.add_argument("--refresh", action="store_true")
  46. parser.add_argument("--chunk-size", type=int, default=200)
  47. parser.add_argument("--limit-per-cylinder", type=int, default=0)
  48. args = parser.parse_args()
  49. metadata = data.fetch_metadata()
  50. if args.limit_per_cylinder > 0:
  51. limited = []
  52. for _, group in pd.DataFrame(metadata).groupby("point_name", sort=False):
  53. limited.extend(group.head(args.limit_per_cylinder).to_dict("records"))
  54. metadata = limited
  55. print(f"[full] running files={len(metadata):,}")
  56. features_path = config.OUTPUT_DIR / "vibration_features_full.csv"
  57. rows = load_or_extract(metadata, features_path, args.chunk_size, args.refresh)
  58. frame = labels.prepare_frame(rows, 15)
  59. baseline = labels.compute_baseline(frame)
  60. baseline_path = config.OUTPUT_DIR / "baseline_full.json"
  61. baseline_path.write_text(json.dumps(baseline, ensure_ascii=False, indent=2), encoding="utf-8")
  62. frame, point_labels, thresholds = local_labels.build_local_labels(frame)
  63. frame.to_csv(config.OUTPUT_DIR / "vibration_features_full_local.csv", index=False, date_format="%Y-%m-%d %H:%M:%S")
  64. point_labels_path = config.OUTPUT_DIR / "vibration_labels_full.csv"
  65. point_labels.to_csv(point_labels_path, index=False, date_format="%Y-%m-%d %H:%M:%S")
  66. intervals = adaptive.build_intervals(frame, point_labels, {})
  67. intervals_path = config.OUTPUT_DIR / "vibration_intervals_full.csv"
  68. intervals.to_csv(intervals_path, index=False, date_format="%Y-%m-%d %H:%M:%S")
  69. validation = adaptive.validate_events(intervals)
  70. validation_path = config.OUTPUT_DIR / "event_validation_full.csv"
  71. validation.to_csv(validation_path, index=False, date_format="%Y-%m-%d %H:%M:%S")
  72. summary = {
  73. "files": len(metadata),
  74. "feature_rows": len(frame),
  75. "point_labels": len(point_labels),
  76. "intervals": len(intervals),
  77. "confirmed_intervals": int(intervals["multi_feature_confirmed"].sum()) if not intervals.empty else 0,
  78. "event_validation": validation.to_dict("records"),
  79. "thresholds": thresholds,
  80. }
  81. (config.OUTPUT_DIR / "full_summary.json").write_text(
  82. json.dumps(summary, ensure_ascii=False, indent=2, default=str), encoding="utf-8"
  83. )
  84. print(json.dumps({k: summary[k] for k in ("files", "feature_rows", "point_labels", "intervals", "confirmed_intervals")}, ensure_ascii=False, indent=2))
  85. print(validation.to_string())
  86. if __name__ == "__main__":
  87. main()