run_this.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import pandas as pd
  2. from datetime import datetime, timedelta
  3. import warnings
  4. import os
  5. warnings.filterwarnings('ignore')
  6. def read_cip_cycles(file_path="CIP_cycles_with_days.csv"):
  7. """
  8. 读取 CIP 周期 CSV 文件
  9. 返回 DataFrame: unit_id, cycle_start, cycle_end, cycle_days
  10. """
  11. file_path = os.path.join(os.path.dirname(__file__), file_path)
  12. df = pd.read_csv(file_path, parse_dates=['cycle_start', 'cycle_end'])
  13. df = df.sort_values(['unit_id', 'cycle_start']).reset_index(drop=True)
  14. return df
  15. def find_last_year_cycle(cip_df, unit_id, target_date, min_days=45, max_days=120):
  16. """
  17. 根据目标日期匹配去年 CIP 周期天数,并保证周期天数在[min_days, max_days]范围内
  18. 参数:
  19. cip_df: CIP 周期 DataFrame
  20. unit_id: 用户指定机组
  21. target_date: datetime 对象(今年日期)
  22. min_days: 最小周期天数
  23. max_days: 最大周期天数
  24. 返回:
  25. 对应去年周期天数 (int)
  26. """
  27. last_year = target_date.year - 1
  28. last_year_date = datetime(last_year, target_date.month, target_date.day)
  29. # 筛选该机组去年周期
  30. unit_df = cip_df[cip_df['unit_id'] == unit_id]
  31. last_year_df = unit_df[(unit_df['cycle_start'].dt.year <= last_year) &
  32. (unit_df['cycle_end'].dt.year >= last_year)]
  33. if last_year_df.empty:
  34. raise ValueError(f"机组 {unit_id} 去年没有 CIP 周期记录")
  35. # 先尝试匹配包含日期的周期,且在范围内
  36. for _, row in last_year_df.iterrows():
  37. if row['cycle_start'].date() <= last_year_date.date() <= row['cycle_end'].date():
  38. if min_days <= row['cycle_days'] <= max_days:
  39. return row['cycle_days']
  40. # 如果没有匹配,按距离排序找最近周期
  41. last_year_df['distance'] = last_year_df.apply(
  42. lambda r: min(abs((r['cycle_start'].date() - last_year_date.date()).days),
  43. abs((r['cycle_end'].date() - last_year_date.date()).days)),
  44. axis=1
  45. )
  46. # 按距离从小到大排序,依次找符合天数范围的周期
  47. last_year_df_sorted = last_year_df.sort_values('distance')
  48. for _, row in last_year_df_sorted.iterrows():
  49. if min_days <= row['cycle_days'] <= max_days:
  50. return row['cycle_days']
  51. # 如果都不符合,报错
  52. raise ValueError(f"机组 {unit_id} 去年没有符合 {min_days}-{max_days} 天的 CIP 周期")
  53. def depreciate_from_previous_year(last_year_days,
  54. membrane_life_years,
  55. final_reduction_rate,
  56. current_year,
  57. previous_year=None):
  58. """
  59. 根据去年的已折旧周期计算今年的周期(假设每年按线性增量缩短,最终累计为 final_reduction_rate)
  60. 参数:
  61. last_year_days: 去年观测到的周期天数(不是原始第1年的值)
  62. membrane_life_years: 膜总寿命(年)
  63. final_reduction_rate: 最后一年相对于原始的累计缩短率(例如 0.4)
  64. current_year: 膜的当前使用年份(从1开始)
  65. previous_year: 已有周期对应的膜使用年份索引(若为 None,则默认 previous_year = current_year - 1)
  66. 返回:
  67. 折旧后的周期天数(int)
  68. """
  69. if previous_year is None:
  70. previous_year = current_year - 1
  71. if previous_year < 1 or current_year < 1:
  72. raise ValueError("年份索引必须 >= 1")
  73. if membrane_life_years <= 1:
  74. raise ValueError("membrane_life_years 必须大于 1")
  75. # 每年的缩短比例(线性分摊到 membrane_life_years-1 年)
  76. annual_reduction = final_reduction_rate / (membrane_life_years - 1)
  77. # 去年、今年相对于原始的累计缩短率
  78. r_prev = annual_reduction * (previous_year - 1)
  79. r_curr = annual_reduction * (current_year - 1)
  80. # 安全检查,避免除以 0 或负值
  81. if (1 - r_prev) <= 0:
  82. raise ValueError("去年累计缩短率使得 (1 - r_prev) <= 0,无法反推原始值。检查参数。")
  83. if r_curr >= 1:
  84. raise ValueError("今年累计缩短率 >=100%,结果不合理。检查参数。")
  85. # 公式:D_current = D_prev * (1 - r_curr) / (1 - r_prev)
  86. current_days = last_year_days * (1 - r_curr) / (1 - r_prev)
  87. return int(round(current_days))
  88. def main(unit_id, reference_date=None):
  89. membrane_life_years = 5
  90. final_reduction_rate = 0.4
  91. current_year = 4 # 当前是第几年使用
  92. # 使用传入的参考日期,如果没有则使用当前时间
  93. today = reference_date if reference_date is not None else datetime.today()
  94. # 读取 CIP 周期数据
  95. cip_df = read_cip_cycles("CIP_cycles_with_days.csv")
  96. # 匹配去年周期天数(带 >=45 天的筛选逻辑)
  97. last_year_days = find_last_year_cycle(cip_df, unit_id, today, min_days=45)
  98. print(f"去年对应周期天数: {last_year_days}")
  99. # 计算折旧后的周期天数(基于“去年值 → 今年值”的公式)
  100. current_days = depreciate_from_previous_year(
  101. last_year_days=last_year_days,
  102. membrane_life_years=membrane_life_years,
  103. final_reduction_rate=final_reduction_rate,
  104. current_year=current_year
  105. )
  106. return current_days
  107. # ===== 主程序 =====
  108. if __name__ == "__main__":
  109. # 用户输入
  110. unit_id = int(input("请输入机组编号: "))
  111. # 计算折旧后的周期天数(基于“去年值 → 今年值”的公式)
  112. current_days = main(unit_id)
  113. print(f"膜折旧后的周期天数: {current_days}")