build_datasets.py 4.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/env python3
  2. """Build pressure model samples from the reconstructed pressure algorithm output."""
  3. from __future__ import annotations
  4. import argparse
  5. import shutil
  6. import sys
  7. from pathlib import Path
  8. sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
  9. from models.common import paths, queries
  10. from models.common import windowing
  11. from models.generalized import features_pressure, pressure_algorithm
  12. from models.common.constants import MIN_HOUR_COVERAGE
  13. def cycle_baseline(series, days=3):
  14. return windowing.cycle_baseline(series, days)
  15. def pressure_features(series, end_index, window):
  16. from models.common.constants import HOURLY_BASELINE_HOURS
  17. oil = [row["oil_avg"] for row in window]
  18. coverages = [row["运行覆盖率"] for row in window]
  19. baseline = windowing.median_value([row["oil_avg"] for row in window[:-1]])
  20. current = oil[-1]
  21. oil_mean, oil_min, oil_max = windowing.mean(oil), min(oil), max(oil)
  22. oil_range = windowing.value_range(oil)
  23. oil_slope = windowing.slope(oil)
  24. cycle_base = cycle_baseline(series)
  25. recent_center, _ = windowing.previous_baseline(series, end_index, "oil_avg", HOURLY_BASELINE_HOURS)
  26. return {
  27. "oil_mean": oil_mean, "oil_min": oil_min, "oil_max": oil_max, "oil_range": oil_range,
  28. "oil_slope": oil_slope,
  29. "oil_last_relative_to_window": (current / baseline - 1) if baseline else None,
  30. "oil_low_ratio_mean": windowing.mean([windowing.ratio(row["oil_low_count"], row["运行样本数"]) for row in window]),
  31. "oil_low_low_ratio_mean": windowing.mean([windowing.ratio(row["oil_low_low_count"], row["运行样本数"]) for row in window]),
  32. "running_coverage_mean": windowing.mean(coverages), "running_coverage_min": min(coverages),
  33. "oil_rel_cycle_mean": (oil_mean / cycle_base - 1) if cycle_base else None,
  34. "oil_rel_cycle_min": (oil_min / cycle_base - 1) if cycle_base else None,
  35. "oil_rel_cycle_last": (current / cycle_base - 1) if cycle_base else None,
  36. "oil_rel_recent_mean": (oil_mean / recent_center - 1) if recent_center else None,
  37. "oil_rel_recent_last": (current / recent_center - 1) if recent_center else None,
  38. "oil_slope_rel_cycle": (oil_slope / cycle_base) if cycle_base else None,
  39. "oil_decline_hours": windowing.decline_hours(series, end_index),
  40. "oil_drawdown_cycle": ((cycle_base - oil_min) / cycle_base) if cycle_base else None,
  41. "oil_range_rel_cycle": (oil_range / cycle_base) if cycle_base else None,
  42. }
  43. def main() -> None:
  44. parser = argparse.ArgumentParser(description="构建压力模型样本(窗口可配置)")
  45. parser.add_argument("--start", default="2025-01-01 00:00:00")
  46. parser.add_argument("--end", default="2026-09-01 00:00:00")
  47. parser.add_argument("--chunk-days", type=int, default=14)
  48. parser.add_argument("--window-hours", type=int, default=3)
  49. parser.add_argument("--output-dir", default=str(paths.PRESSURE_DATAS))
  50. parser.add_argument("--hourly-csv", default=str(paths.HOURLY_FULL))
  51. parser.add_argument("--units", nargs="+", default=None)
  52. args = parser.parse_args()
  53. output = Path(args.output_dir)
  54. if output.exists():
  55. shutil.rmtree(output)
  56. output.mkdir(parents=True)
  57. hourly_path = Path(args.hourly_csv)
  58. if hourly_path.is_file():
  59. print(f"复用小时中间表:{hourly_path}")
  60. rows = queries.load_hourly_csv(hourly_path)
  61. else:
  62. from models.common import db
  63. batch_to_unit = db.load_pks_batches()
  64. selected = sorted(batch_to_unit)
  65. configs = db.load_alarm_config({batch: batch_to_unit[batch] for batch in selected})
  66. start, end = queries.parse_dt(args.start), queries.parse_dt(args.end)
  67. rows = queries.fetch_all_hourly(start, end, args.chunk_days, batch_to_unit, configs, selected)
  68. scoped = [row for row in rows if not args.units or row["机组"] in set(args.units)]
  69. windowing.write_hourly(output / "hourly.csv", scoped)
  70. stages = windowing.stage_ranges(paths.PRESSURE_RESULTS / "润滑油压力小时阶段段.csv", "压力阶段")
  71. if args.units:
  72. stages = [stage for stage in stages if stage["unit"] in set(args.units)]
  73. samples = windowing.build_samples(scoped, "pressure", stages, args.window_hours, pressure_features)
  74. counts = windowing.write_samples(output, samples)
  75. print(f"pressure samples: {dict(counts)}")
  76. print(f"小时中间数据:{len(scoped):,} 行")
  77. print(f"样本输出目录:{output}")
  78. if __name__ == "__main__":
  79. main()