power_derating_for_chunlin.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import os
  2. import matplotlib
  3. import numpy as np
  4. from matplotlib import pyplot as plt
  5. matplotlib.use('Agg')
  6. matplotlib.rcParams['font.family'] = 'SimHei' # 或者 'Microsoft YaHei'
  7. matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 或者 ['Microsoft YaHei']
  8. import pandas as pd
  9. import chardet
  10. import warnings
  11. warnings.filterwarnings("ignore")
  12. # 获取文件编码
  13. def detect_file_encoding(filename):
  14. # 读取文件的前1000个字节(足够用于大多数编码检测)
  15. with open(filename, 'rb') as f:
  16. rawdata = f.read(1000)
  17. result = chardet.detect(rawdata)
  18. encoding = result['encoding']
  19. if encoding is None:
  20. encoding = 'gb18030'
  21. if encoding and encoding.lower() == 'gb2312' or encoding.lower().startswith("windows"):
  22. encoding = 'gb18030'
  23. return encoding
  24. def del_blank(df=pd.DataFrame(), cols=list()):
  25. for col in cols:
  26. if df[col].dtype == object:
  27. df[col] = df[col].str.strip()
  28. return df
  29. # 切割数组到多个数组
  30. def split_array(array, num):
  31. return [array[i:i + num] for i in range(0, len(array), num)]
  32. # 读取数据到df
  33. def read_file_to_df(file_path, read_cols=list(), header=0):
  34. try:
  35. df = pd.DataFrame()
  36. if str(file_path).lower().endswith("csv") or str(file_path).lower().endswith("gz"):
  37. encoding = detect_file_encoding(file_path)
  38. end_with_gz = str(file_path).lower().endswith("gz")
  39. if read_cols:
  40. if end_with_gz:
  41. df = pd.read_csv(file_path, encoding=encoding, usecols=read_cols, compression='gzip', header=header)
  42. else:
  43. df = pd.read_csv(file_path, encoding=encoding, usecols=read_cols, header=header,
  44. on_bad_lines='warn')
  45. else:
  46. if end_with_gz:
  47. df = pd.read_csv(file_path, encoding=encoding, compression='gzip', header=header)
  48. else:
  49. df = pd.read_csv(file_path, encoding=encoding, header=header, on_bad_lines='warn')
  50. else:
  51. xls = pd.ExcelFile(file_path)
  52. # 获取所有的sheet名称
  53. sheet_names = xls.sheet_names
  54. for sheet in sheet_names:
  55. if read_cols:
  56. now_df = pd.read_excel(xls, sheet_name=sheet, header=header, usecols=read_cols)
  57. else:
  58. now_df = pd.read_excel(xls, sheet_name=sheet, header=header)
  59. df = pd.concat([df, now_df])
  60. print('文件读取成功', file_path, '文件数量', df.shape)
  61. except Exception as e:
  62. print('读取文件出错', file_path, str(e))
  63. message = '文件:' + os.path.basename(file_path) + ',' + str(e)
  64. raise ValueError(message)
  65. return df
  66. def __build_directory_dict(directory_dict, path, filter_types=None):
  67. # 遍历目录下的所有项
  68. for item in os.listdir(path):
  69. item_path = os.path.join(path, item)
  70. if os.path.isdir(item_path):
  71. __build_directory_dict(directory_dict, item_path, filter_types=filter_types)
  72. elif os.path.isfile(item_path):
  73. if path not in directory_dict:
  74. directory_dict[path] = []
  75. if filter_types is None or len(filter_types) == 0:
  76. directory_dict[path].append(item_path)
  77. elif str(item_path).split(".")[-1] in filter_types:
  78. if str(item_path).count("~$") == 0:
  79. directory_dict[path].append(item_path)
  80. # 读取所有文件
  81. # 读取路径下所有的excel文件
  82. def read_excel_files(read_path):
  83. directory_dict = {}
  84. __build_directory_dict(directory_dict, read_path, filter_types=['xls', 'xlsx', 'csv', 'gz'])
  85. return [path for paths in directory_dict.values() for path in paths if path]
  86. class ContractPowerCurve(object):
  87. def __init__(self, df: pd.DataFrame, wind_velocity='风速', active_power='功率'):
  88. self.df = df
  89. self.wind_velocity = wind_velocity
  90. self.active_power = active_power
  91. # 创建路径
  92. def create_file_path(path, is_file_path=False):
  93. if is_file_path:
  94. path = os.path.dirname(path)
  95. if not os.path.exists(path):
  96. os.makedirs(path, exist_ok=True)
  97. def scatter(title, x_label, y_label, x_values, y_values, color='blue', size=10, save_file_path=''):
  98. if save_file_path:
  99. create_file_path(save_file_path, True)
  100. else:
  101. save_file_path = title + '.png'
  102. plt.figure(figsize=(8, 6))
  103. plt.title(title, fontsize=16)
  104. plt.xlabel(x_label, fontsize=14)
  105. plt.ylabel(y_label, fontsize=14)
  106. plt.scatter(x_values, y_values, s=size, c=color)
  107. plt.savefig(save_file_path)
  108. plt.close()
  109. def marker_active_power(contract_power_curve_class: ContractPowerCurve, df: pd.DataFrame, active_power='有功功率 kW均值',
  110. wind_velocity='风速 m/s均值'):
  111. """
  112. 标记有功功率为正的记录
  113. :param contract_power_curve_class: 合同功率曲线
  114. :param df: 原始数据
  115. :return: 标记有功功率为正的原始数据
  116. """
  117. contract_power_curve_df = contract_power_curve_class.df
  118. curve_wv = contract_power_curve_df[contract_power_curve_class.wind_velocity].values
  119. curve_ap = contract_power_curve_df[contract_power_curve_class.active_power].values
  120. df.dropna(subset=[active_power, wind_velocity], inplace=True)
  121. ap_gt_0_df = df[df[active_power] > 0]
  122. ap_le_0_df = df[df[active_power] <= 0]
  123. ap_le_0_df["marker"] = -1
  124. active_power_values = ap_gt_0_df[active_power].values
  125. wind_speed_values = ap_gt_0_df[wind_velocity].values
  126. ap_gt_0_in = [0] * ap_gt_0_df.shape[0]
  127. for i in range(len(ap_gt_0_in)):
  128. wind_speed = wind_speed_values[i]
  129. active_power = active_power_values[i]
  130. # if active_power >= 2200 - 200:
  131. # ap_gt_0_in[i] = 1
  132. # else:
  133. diffs = np.abs(curve_wv - wind_speed)
  134. # 找到差值最小的索引和对应的差值
  135. minDiff, idx = np.min(diffs), np.argmin(diffs)
  136. # 使用找到的索引获取对应的值
  137. closestValue = curve_ap[idx]
  138. if active_power - closestValue >= -100:
  139. ap_gt_0_in[i] = 1
  140. ap_gt_0_df['marker'] = ap_gt_0_in
  141. return pd.concat([ap_gt_0_df, ap_le_0_df])
  142. if __name__ == '__main__':
  143. wind_power_df = read_file_to_df(r"D:\中能智能\matlib计算相关\标记derating\PV_Curve.csv")
  144. all_files = read_excel_files(r"Z:\collection_data\1进行中\诺木洪风电场-甘肃-华电\清理数据\min-666")
  145. save_path = r"D:\trans_data\诺木洪\清理数据\min-666-derating"
  146. wind_power_df_class = ContractPowerCurve(wind_power_df)
  147. for file in all_files:
  148. name = os.path.basename(file).split("@")[0]
  149. try:
  150. df = read_file_to_df(file)
  151. df = marker_active_power(wind_power_df_class, df)
  152. df = df[df['marker'] == 1]
  153. # 保存筛选后数据
  154. name = name.replace('HD', 'HD2')
  155. df.to_csv(os.path.join(save_path, name + '.csv'), index=False, encoding='utf-8')
  156. # 使用scatter函数绘制散点图
  157. if not df.empty:
  158. scatter(name, x_label='风速均值', y_label='有功功率均值', x_values=df['风速 m/s均值'].values,
  159. y_values=df['有功功率 kW均值'].values, color='green',
  160. save_file_path=os.path.join(save_path, name + '均值.png'))
  161. except Exception as e:
  162. print(os.path.basename(file), "出错", str(e))
  163. raise e