faultAnalyst.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import pandas as pd
  2. import os
  3. import plotly.graph_objects as go
  4. from algorithmContract.confBusiness import *
  5. from algorithmContract.contract import Contract
  6. from behavior.analystNotFilter import AnalystNotFilter
  7. from plotly.subplots import make_subplots
  8. class FaultAnalyst(AnalystNotFilter):
  9. """
  10. 风电机组故障分析
  11. """
  12. def typeAnalyst(self):
  13. return "fault"
  14. def selectColumns(self):
  15. # 这里的字段必须与数据库 _fault 表中的列名对应
  16. return [Field_DeviceName, Field_FaultTime, Field_FaultDetail]
  17. # 强制重写获取数据源类型的方法,防止因配置错误去查 _minute 表,强制代码去查 _fault 表
  18. def getTimeGranularitys(self, conf: Contract):
  19. return ["fault"]
  20. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  21. dictionary = self.processTurbineData(turbineCodes, conf, self.selectColumns())
  22. dataFrameMerge = self.userDataFrame(dictionary, conf.dataContract.configAnalysis, self)
  23. # 增加空数据保护
  24. if dataFrameMerge.empty:
  25. print("Warning: No fault data found for the selected turbines.")
  26. return pd.DataFrame()
  27. return self.get_result(dataFrameMerge, outputAnalysisDir, conf)
  28. def get_result(self, dataFrame: pd.DataFrame, outputAnalysisDir: str, conf: Contract):
  29. # 双重保险:如果数据为空直接返回
  30. if dataFrame.empty:
  31. return pd.DataFrame()
  32. #---------------整个风场维度统计故障时长与次数---------------------------
  33. # 统计各种类型故障出现的次数
  34. if Field_FaultDetail in dataFrame.columns:
  35. fault_detail_count = dataFrame[Field_FaultDetail].value_counts().reset_index()
  36. fault_detail_count.columns = [Field_FaultDetail, 'count']
  37. # 统计每个 fault_detail 的时长加和
  38. fault_time_sum = dataFrame.groupby(Field_FaultDetail)[Field_FaultTime].sum().reset_index()
  39. fault_time_sum.columns = [Field_FaultDetail, 'fault_time_sum']
  40. # 合并两个 DataFrame
  41. fault_summary = pd.merge(fault_detail_count, fault_time_sum, on=Field_FaultDetail, how='inner')
  42. fault_summary_sorted = fault_summary.sort_values(by='fault_time_sum', ascending=False)
  43. else:
  44. # 防御性代码:如果缺列
  45. fault_summary_sorted = pd.DataFrame()
  46. # -------------按风机分组统计故障情况------------------------------------------
  47. # 确保有设备名称列
  48. if Field_DeviceName not in dataFrame.columns:
  49. # 有时 Field_DeviceName 没取到,尝试用 DeviceCode 或其他
  50. groupby_col = dataFrame.columns[0]
  51. else:
  52. groupby_col = Field_DeviceName
  53. grouped = dataFrame.groupby(groupby_col)
  54. results= []
  55. for name, group in grouped:
  56. turbine_fault_summary = pd.DataFrame({
  57. Field_DeviceName: [name],
  58. 'count': [len(group)],
  59. 'fault_time': [group[Field_FaultTime].sum()]
  60. })
  61. results.append(turbine_fault_summary)
  62. # 合并所有风机的故障统计结果
  63. if results:
  64. turbine_fault_summary = pd.concat(results, ignore_index=True)
  65. turbine_fault_sorted = turbine_fault_summary.sort_values(by='fault_time', ascending=False)
  66. # 故障类型前十名
  67. # draw_results=turbine_fault_sorted.head(10) # 暂时没用到
  68. else:
  69. turbine_fault_sorted = pd.DataFrame()
  70. # 保存结果
  71. result_rows = []
  72. if not turbine_fault_sorted.empty:
  73. filePathOfturbinefault = os.path.join(outputAnalysisDir, f"turbine_fault_result{CSVSuffix}")
  74. turbine_fault_sorted.to_csv(filePathOfturbinefault, index=False,encoding='utf-8-sig')
  75. result_rows.append({
  76. Field_Return_TypeAnalyst: self.typeAnalyst(),
  77. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  78. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  79. Field_CodeOfTurbine: "total",
  80. Field_MillTypeCode:"turbine_fault_result",
  81. Field_Return_FilePath: filePathOfturbinefault,
  82. Field_Return_IsSaveDatabase: True
  83. })
  84. if not fault_summary_sorted.empty:
  85. filePathOftotalfault = os.path.join(outputAnalysisDir, f"total_fault_result{CSVSuffix}")
  86. fault_summary_sorted.to_csv(filePathOftotalfault, index=False,encoding='utf-8-sig')
  87. result_rows.append({
  88. Field_Return_TypeAnalyst: self.typeAnalyst(),
  89. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  90. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  91. Field_CodeOfTurbine: "total",
  92. Field_MillTypeCode:"total_fault_result",
  93. Field_Return_FilePath: filePathOftotalfault,
  94. Field_Return_IsSaveDatabase: True
  95. })
  96. result_df = pd.DataFrame(result_rows)
  97. return result_df