numpy高级教程之np.where和np.piecewise

欢迎关注“勇敢AI”公众号,更多python学习、数据分析、机器学习、深度学习原创文章与大家分享,还有更多电子资源、教程、数据集下载。勇敢AI,一个专注于人工智能AI的公众号。

==================================================================================

       关于numpy的教程,前面已经总结了不少文章,且前面已经写过了numpy的高级应用之select和choose,需要的同学可以看我的博客或者是在我博客里面的微信公众平台,对这两个函数有特别清晰的介绍。今天的文章主要是看一下np.where和np.piecewise,以及掩码数组。

一、np.where()函数详解

顾名思义,该函数所实现的也是类似于查找的功能,where即在哪里的意思,前面的select和choose即选择的意思,这有一些类似。实际上,where函数提供了“查找”的更高级的功能。

1、where函数的定义

numpy.where(condition[, xy])  

If only condition is given, return condition.nonzero().

Parameters:

condition : array_like, bool

When True, yield x, otherwise yield y.

x, y : array_like, optional

Values from which to choose. xy and condition need to be broadcastable to some shape.

Returns:

out : ndarray or tuple of ndarrays

If both x and y are specified, the output array contains elements of x where condition is True, and elements from y elsewhere.

If only condition is given, return the tuple condition.nonzero(), the indices where condition is True.

解释:

该函数可以接受一个必选参数condition,注意该参数必须是array型的,只不过元素是true或者是false

x,y是可选参数:如果条件为真,则返回x,如果条件为false,则返回y,注意condition、x、y三者必须要能够“广播”到相同的形状

返回结果:返回的是数组array或者是元素为array的tuple元组,如果只有一个condition,则返回包含array的tuple,如果是有三个参数,则返回一个array。后面会详细介绍。

总结:numpy实际上是条件操作的高度封装,可以说numpy.where函数是三元表达式x if condition else y的矢量化版本。定义一个布尔数组和两个值数组,它返回的结果实际上就是查找的元素的“位置”或者是“索引”或者是“坐标”。位置、索引、坐标是等价的意思,通俗的说就是返回的值就是元素到底在哪里。

2、只含有一个参数condition的实际案例

(1)condition是一维的

a = np.array([2,4,6,8,10])
a_where=np.where(a > 5)             # 返回索引,a>5得到的是array。
print(a_where)
print(a[np.where(a > 5)])        # 等价于 a[a>5],布尔索引

b=np.array([False,True,False,True,False])
print(np.where(b))

打印的结果为如下:

(array([2, 3, 4], dtype=int64),) #返回的2,3,4即对应于元素大于5(True)的元素的索引位置,即第3、4、5个元素,以array得形式返回
[ 6  8 10]
(array([1, 3], dtype=int64),)  #返回元素中为True的元素所对应的位置索引,即第2个和第4个元素,以array的形式返回。

(2)condition是二维的

a=np.array([[1,2,3,4,5],[2,3,4,5,6],[3,4,5,6,7],[4,5,6,7,8]])  #二维数组
a_where=np.where(a>3)
print(a_where)
print(a[a_where])

运行结果为:

(array([0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3], dtype=int64), array([3, 4, 2, 3, 4, 1, 2, 3, 4, 0, 1, 2, 3, 4], dtype=int64))
[4 5 4 5 6 4 5 6 7 4 5 6 7 8]

对于第一个返回的结果,我们可以看到,它返回的是一个元组tuple,元组的第一个元素是一个array,它的值来源于满足条件的元素的行索引,两个0行的,三个1行的,四个2行的,五个3行的;元祖的第二个元素也是一个array,它的值来源于满足条件的元素的列索引。

再看一个例子

b=np.where([[0, 3,2], [0,4, 0]])
print(b)

返回结果为:

(array([0, 0, 1], dtype=int64), array([1, 2, 1], dtype=int64))

#返回的依然是一个元组tuple,第一个元素是一个array,来源于行,第二个元素也是一个array,来源于列。注意,这一没有删选条件啊,因为where的参数就是b而不是什么,b>1,b>2之类的布尔表达式,那是怎么回事呢,实际上,它是经过进一步处理了的,将0元素看成是false,将大于0的全部当成是true,与下面的运行结果是完全等价的。

c=np.array([[False,True,True],[False,True,False]])
print(np.where(c))

输出结果为: (array([0, 0, 1], dtype=int64), array([1, 2, 1], dtype=int64)) #同上面完全一样

(3)condition是多维的——以三维为例

a=[
    [
        [1,2,3],[2,3,4],[3,4,5]
    ],
    [
        [0,1,2],[1,2,3],[2,3,4]
    ]
]
a=np.array(a)
print(a.shape)  #形状为(2,3,3)
a_where=np.where(a>3)
print(a_where)

运行结果为:

(array([0, 0, 0, 1], dtype=int64),

array([1, 2, 2, 2], dtype=int64),

array([2, 1, 2, 2], dtype=int64)) 

同上,返回的是一个元组,第一个元素是array类型,来源于第一个维度满足条件的索引,第二个元素是array类型,来源于第二个维度满足条件的索引,第三个元素是array类型,来源于第三个维度满足条件的索引。

总结:针对上面的讲述,where的作用就是返回一个数组中满足条件的元素(True)的索引,且返回值是一个tuple类型,tuple的每一个元素均为一个array类型,array的值即对应某一纬度上的索引。

在之给定一个参数condition的时候,np.where(condition)和condition.nonzero()是完全等价的。

3、包含三个参数condition、x、y 的实际案例

a = np.arange(10)
a_where=np.where(a,1,-1)
print(a_where)      

a_where_1=np.where(a > 5,1,-1)
print(a_where_1)

b=np.where([[True,False], [True,True]],    #第一个参数
             [[1,2], [3,4]],               #第二个参数
             [[9,8], [7,6]]                #第三个参数
            )             

print(b)

运行结果为:

[-1  1  1  1  1  1  1  1  1  1]
[-1 -1 -1 -1 -1 -1  1  1  1  1]
[[1 8]
 [3 4]]

对于第一个结果,因为只有第一个是0,即false,故而用-1替换了,后面的都大于0,即true,故而用1替换了

对于第二个结果,前面的6个均为false,故而用-1替换,后面的四个为true,则用1替换

对于第三个结果,

第一个True对应的索引位置为(0,0),true在第二个参数中寻找,(0,0)对应于元素1

第二个false对应的索引位置为(0,1),false在第三个参数中寻找,(0,1)对应于元素8

第三个True对应的索引位置为(1,0),true在第二个参数中寻找,(0,0)对应于元素3

第四个True对应的索引位置为(1,1),true在第二个参数中寻找,(0,0)对应于元素4

总结:在使用三个参数的时候,要注意,condition、x、y必须具有相同的维度或者是可以广播成相同的形状,否则会报错,它返回的结果是一个列表,同原始的condition具有相同的维度和形状。

总结:通过上面的讲述,已经了解到了np.where函数的强大之处,它的本质上就是选择操作,但是如果我们自己编写条件运算,使用if-else或者是列表表达式这样的语句,效率低下,故而推荐使用np.where。

二、np.piecewise函数详解

np.piecewise也和前面讲过的where、select、choose一样,属于高级应用,而且实现的功能也有类似的,即根据相关的条件,进行筛选,然后对漫步不同条件的元素进行相关的操作,这个操作可以来源与函数、lambda表达式等,并得到新的结果。

1、np.piecewise的定义

numpy.piecewise(xcondlistfunclist*args**kw)

Evaluate a piecewise-defined function.

Given a set of conditions and corresponding functions, evaluate each function on the input data wherever its condition is true.

Parameters:

x : ndarray or scalar

The input domain.

condlist : list of bool arrays or bool scalars

Each boolean array corresponds to a function in funclist. Wherever condlist[i] is True, funclist[i](x) is used as the output value.

Each boolean array in condlist selects a piece of x, and should therefore be of the same shape as x.

The length of condlist must correspond to that of funclist. If one extra function is given, i.e. iflen(funclist) == len(condlist) + 1, then that extra function is the default value, used wherever all conditions are false.

funclist : list of callables, f(x,*args,**kw), or scalars

Each function is evaluated over x wherever its corresponding condition is True. It should take a 1d array as input and give an 1d array or a scalar value as output. If, instead of a callable, a scalar is provided then a constant function (lambda x: scalar) is assumed.

args : tuple, optional

Any further arguments given to piecewise are passed to the functions upon execution, i.e., if called piecewise(..., ..., 1, 'a'), then each function is called as f(x, 1, 'a').

kw : dict, optional

Keyword arguments used in calling piecewise are passed to the functions upon execution, i.e., if calledpiecewise(..., ..., alpha=1), then each function is called as f(x, alpha=1).

Returns:

out : ndarray

The output is the same shape and type as x and is found by calling the functions in funclist on the appropriate portions of x, as defined by the boolean arrays in condlist. Portions not covered by any condition have a default value of 0.

参数一 x:表示要进行操作的对象

参数二:condlist,表示要满足的条件列表,可以是多个条件构成的列表

参数三:funclist,执行的操作列表,参数二与参数三是对应的,当参数二为true的时候,则执行相对应的操作函数。

返回值:返回一个array对象,和原始操作对象x具有完全相同的维度和形状

2、np.piecewise的实际案例

(1)案例一

x = np.arange(0,10)
print(x)
xx=np.piecewise(x, [x < 4, x >= 6], [-1, 1])
print(xx)

运行结果为:

[0 1 2 3 4 5 6 7 8 9]
[-1 -1 -1 -1  0  0  1  1  1  1]

即将元素中小于4的用-1替换掉,大于等于6的用1替换掉,其余的默认以0填充。其实这里的替换和填充就是function,这不过这里的function跟简单粗暴,都用同一个数替换了。实际上,上面的代码完全等价于下面的代码:

x = np.arange(0,10)

def func1(y):
    return -1

def func2(y):
    return 1
xxx=np.piecewise(x, [x < 4, x >= 6], [func1, func2])
print(xxx)

运行结果为:

 [-1 -1 -1 -1  0  0  1  1  1  1]  #同上面一样

(2)案例二——定义相关的操作函数

x = np.arange(0,10)

#元素进行平方
def func2(y):
    return 1ef func1(y):
    return y**2

#元素乘以100
def func2(y):
    return y*100
xxx=np.piecewise(x, [x < 4, x >= 6], [func1, func2])
print(xxx)

运行结果为:

[  0   1   4   9   0   0 600 700 800 900]

(3)案例三——使用lambda表达式

x = np.arange(0,10)

xxxx=np.piecewise(x, [x < 4, x >= 6], [lambda x:x**2, lambda x:x*100])
print(xxxx)

运行结果为:

[  0   1   4   9   0   0 600 700 800 900]

总结:piecewise的处理方法快捷方便,比自己编写循环和条件语句的执行效率高很多,推荐多使用。

 

import os import numpy as np from scipy.integrate import trapezoid import matplotlib.pyplot as plt from matplotlib.font_manager import findfont, FontProperties, fontManager import warnings from tqdm import tqdm import pandas as pd class RadiationCalculator: """辐射传热计算类,用于计算样本在不同温度条件下的辐射特性""" def __init__(self, emissivity_file=r"C:\Users\HP\OneDrive\桌面\样本1发射率.xlsx"): """初始化辐射计算器,配置字体物理常数""" # 配置中文字体 self._configure_fonts() # 物理常数 self.h = 6.626e-34 # 普朗克常数 (J·s) self.c = 2.998e8 # 光速 (m/s) self.k = 1.381e-23 # 玻尔兹曼常数 (J/K) # 计算参数 self.lambda_min = 0.3 # 积分下限 (μm) self.lambda_max = 25.0 # 积分上限 (μm) # 设置光谱发射率函数 self.set_surface_emissivity_from_excel(emissivity_file) self.set_atmosphere_emissivity(self.emissivity_a) # 温度设置 self.object_temp_range = (-50, 100) # 物体温度范围 (°C) self.object_temp_fixed = 25 # 物体固定温度 (°C) self.atmosphere_temp_range = (-50, 60) # 大气温度范围 (°C) self.atmosphere_temp_step = 10 # 大气温度步长 (°C) self.atmosphere_temp_c = 25 # 大气温度 (°C),用于物体温度变化模拟 self.temp_step = 10 # 温度步长 (°C),用于物体温度变化模拟 def _configure_fonts(self): """配置matplotlib的中文字体""" # 备选字体列表,按优先级排序 preferred_fonts = [ 'SimHei', # 黑体 - Windows/Linux 'WenQuanYi Micro Hei', # Linux 'Heiti TC', # macOS 'Microsoft YaHei', # Windows 'SimSun', # 宋体 - Windows/Linux 'Heiti TC', # macOS 'Arial Unicode MS', # 支持更多字符 'DejaVu Sans' # 支持更多字符 ] # 尝试指定的备选字体列表 for font in preferred_fonts: try: plt.rcParams["font.family"] = font # 测试字体是否能显示中文 test_text = "测试字体:一阶线性拟合" fig, ax = plt.subplots(figsize=(1, 1)) ax.text(0.5, 0.5, test_text, fontsize=12, ha='center') ax.axis('off') plt.close(fig) print(f"已成功设置中文字体: {font}") break except: continue else: # 如果没有找到中文字体,使用默认字体 plt.rcParams["font.family"] = ["sans-serif"] print("未找到系统中可用的中文字体,将使用默认字体。图表中的中文可能无法正确显示。") # 确保负号正确显示 plt.rcParams["axes.unicode_minus"] = False def blackbody_radiation(self, lambda_m, T): """计算黑体辐射强度 (W/(m²·sr·m))""" lambda_m = np.where(lambda_m <= 0, 1e-10, lambda_m) # 避免波长为零 exponent = self.h * self.c / (lambda_m * self.k * T) exponent = np.where(exponent > 709, 709, exponent) # 避免数值溢出 return (2 * self.h * self.c**2 / lambda_m**5) / (np.exp(exponent) - 1) # 大气光谱发射率函数 def emissivity_a(self, lambda_m): """大气的光谱发射率函数""" lambda_um = lambda_m * 1e6 emissivity = np.piecewise(lambda_um, [lambda_um < 0, (lambda_um >= 0) & (lambda_um < 8), (lambda_um >= 8) & (lambda_um <= 14), lambda_um > 14], [0, 1.0, 0.52, 1.0]) return emissivity def set_surface_emissivity_from_excel(self, file_path): """从Excel文件中设置物体表面的光谱发射率函数""" data = pd.read_excel(file_path) wavelengths = data['波长'].values * 1e-6 # 转换为米 emissivities = data['发射率'].values # 创建插值函数 self.surface_emissivity_func = lambda x: np.interp(x, wavelengths, emissivities, left=0, right=0) def set_atmosphere_emissivity(self, emissivity_func): """设置大气的光谱发射率函数""" self.atmosphere_emissivity_func = emissivity_func def calculate_radiation_power(self, T_s, T_a): """计算物体的辐射功率、吸收的大气辐射功率净辐射功率""" lambda_min_m = self.lambda_min * 1e-6 lambda_max_m = self.lambda_max * 1e-6 # 获取实际的波长范围内的数据点 data = pd.read_excel(r"C:\Users\HP\OneDrive\桌面\样本1发射率.xlsx") wavelengths_m = data['波长'].values * 1e-6 # 转换为米 emissivities = data['发射率'].values # 过滤掉不在积分范围内的数据点 mask = (wavelengths_m >= lambda_min_m) & (wavelengths_m <= lambda_max_m) wavelengths_m = wavelengths_m[mask] emissivities = emissivities[mask] if len(wavelengths_m) == 0: return 0, 0, 0 # 计算物体辐射功率 radiance_s = self.blackbody_radiation(wavelengths_m, T_s) P_rad = np.pi * trapezoid(radiance_s * emissivities, wavelengths_m) # 计算吸收的大气辐射功率 radiance_a = self.blackbody_radiation(wavelengths_m, T_a) emissivity_a = self.atmosphere_emissivity_func(wavelengths_m) P_atmosphere = np.pi * trapezoid(radiance_a * emissivity_a * emissivities, wavelengths_m) # 计算净辐射功率 P_net = P_rad - P_atmosphere return P_rad, P_atmosphere, P_net def run_simulation_object_temperature(self): """运行模拟过程,计算样本在不同物体温度下的辐射特性""" object_temp_min_k = self.object_temp_range[0] + 273.15 object_temp_max_k = self.object_temp_range[1] + 273.15 object_temps_k = np.arange(object_temp_min_k, object_temp_max_k + 1, self.temp_step) object_temps_c = object_temps_k - 273.15 atmosphere_temp_k = self.atmosphere_temp_c + 273.15 print(f"物体温度范围: {min(object_temps_c):.1f}°C 到 {max(object_temps_c):.1f}°C") print(f"大气温度固定为: {self.atmosphere_temp_c}°C") print(f"温度步长: {self.temp_step}°C") results = { 'object_temp_c': [], 'net_power': [] } total_iterations = len(object_temps_k) progress_bar = tqdm(total=total_iterations, desc="计算辐射功率") for T_s_k in object_temps_k: T_s_c = T_s_k - 273.15 _, _, P_net = self.calculate_radiation_power(T_s_k, atmosphere_temp_k) results['object_temp_c'].append(float(T_s_c)) results['net_power'].append(float(P_net)) progress_bar.update(1) progress_bar.close() return pd.DataFrame(results) def run_simulation_atmosphere_temperature(self): """运行模拟过程,计算样本在不同大气温度下的辐射特性""" atmosphere_temp_min_k = self.atmosphere_temp_range[0] + 273.15 atmosphere_temp_max_k = self.atmosphere_temp_range[1] + 273.15 atmosphere_temps_k = np.arange(atmosphere_temp_min_k, atmosphere_temp_max_k + 1, self.atmosphere_temp_step) atmosphere_temps_c = atmosphere_temps_k - 273.15 object_temp_k = self.object_temp_fixed + 273.15 print(f"大气温度范围: {min(atmosphere_temps_c):.1f}°C 到 {max(atmosphere_temps_c):.1f}°C") print(f"物体温度固定为: {self.object_temp_fixed}°C") print(f"温度步长: {self.atmosphere_temp_step}°C") results = { 'atmosphere_temp_c': [], 'net_power': [] } total_iterations = len(atmosphere_temps_k) progress_bar = tqdm(total=total_iterations, desc="计算辐射功率") for T_a_k in atmosphere_temps_k: T_a_c = T_a_k - 273.15 _, _, P_net = self.calculate_radiation_power(object_temp_k, T_a_k) results['atmosphere_temp_c'].append(float(T_a_c)) results['net_power'].append(float(P_net)) progress_bar.update(1) progress_bar.close() return pd.DataFrame(results) def run_simulation_double_temperature(self): """运行模拟过程,计算样本在不同物体温度大气温度组合下的辐射特性""" object_temp_min_k = self.object_temp_range[0] + 273.15 object_temp_max_k = self.object_temp_range[1] + 273.15 object_temps_k = np.arange(object_temp_min_k, object_temp_max_k + 1, self.temp_step) object_temps_c = object_temps_k - 273.15 atmosphere_temp_min_k = self.atmosphere_temp_range[0] + 273.15 atmosphere_temp_max_k = self.atmosphere_temp_range[1] + 273.15 atmosphere_temps_k = np.arange(atmosphere_temp_min_k, atmosphere_temp_max_k + 1, self.atmosphere_temp_step) atmosphere_temps_c = atmosphere_temps_k - 273.15 print(f"物体温度范围: {min(object_temps_c):.1f}°C 到 {max(object_temps_c):.1f}°C") print(f"大气温度范围: {min(atmosphere_temps_c):.1f}°C 到 {max(atmosphere_temps_c):.1f}°C") print(f"温度步长: {self.temp_step}°C {self.atmosphere_temp_step}°C") results = { 'object_temp_c': [], 'atmosphere_temp_c': [], 'net_power': [] } total_iterations = len(object_temps_k) * len(atmosphere_temps_k) progress_bar = tqdm(total=total_iterations, desc="计算辐射功率") for T_s_k in object_temps_k: for T_a_k in atmosphere_temps_k: T_s_c = T_s_k - 273.15 T_a_c = T_a_k - 273.15 _, _, P_net = self.calculate_radiation_power(T_s_k, T_a_k) results['object_temp_c'].append(float(T_s_c)) results['atmosphere_temp_c'].append(float(T_a_c)) results['net_power'].append(float(P_net)) progress_bar.update(1) progress_bar.close() return pd.DataFrame(results) def save_results_to_excel(self, results_obj_temp, results_atmo_temp, results_double_temp, file_path): """将结果保存到Excel文件的不同工作表中""" # 确保输出目录存在 output_dir = os.path.dirname(file_path) if not os.path.exists(output_dir): os.makedirs(output_dir) print(f"创建输出目录: {output_dir}") with pd.ExcelWriter(file_path) as writer: results_obj_temp.to_excel(writer, sheet_name='Object_Temperature_Change', index=False) results_atmo_temp.to_excel(writer, sheet_name='Atmosphere_Temperature_Change', index=False) results_double_temp.to_excel(writer, sheet_name='Double_Temperature_Change', index=False) print(f"结果已保存到 {file_path}") def plot_and_save_figures(self, results_obj_temp, results_atmo_temp, results_double_temp, output_folder): """绘制并保存图表""" # 确保输出目录存在 if not os.path.exists(output_folder): os.makedirs(output_folder) print(f"创建输出目录: {output_folder}") # 绘制物体温度变化图 plt.figure(figsize=(10, 6)) plt.scatter(results_obj_temp['object_temp_c'], results_obj_temp['net_power'], label='数据点') # 一次函数拟合 coeffs_obj_temp = np.polyfit(results_obj_temp['object_temp_c'], results_obj_temp['net_power'], 1) poly_fit_obj_temp = np.poly1d(coeffs_obj_temp) plt.plot(results_obj_temp['object_temp_c'], poly_fit_obj_temp(results_obj_temp['object_temp_c']), color='red', label=f'y={coeffs_obj_temp[0]:.2f}x+{coeffs_obj_temp[1]:.2f}') # 计算R²值 residuals_obj_temp = results_obj_temp['net_power'] - poly_fit_obj_temp(results_obj_temp['object_temp_c']) ss_res_obj_temp = np.sum(residuals_obj_temp**2) ss_tot_obj_temp = np.sum((results_obj_temp['net_power'] - np.mean(results_obj_temp['net_power']))**2) r_squared_obj_temp = 1 - (ss_res_obj_temp / ss_tot_obj_temp) # 计算绝对误差相对误差 abs_errors_obj_temp = np.abs(results_obj_temp['net_power'] - poly_fit_obj_temp(results_obj_temp['object_temp_c'])) rel_errors_obj_temp = abs_errors_obj_temp / np.abs(results_obj_temp['net_power']) * 100 # 相对误差转为百分比 # 计算平均绝对误差平均相对误差 mae_obj_temp = np.mean(abs_errors_obj_temp) mre_obj_temp = np.mean(rel_errors_obj_temp) # 计算均方根相对误差 (RMSRE) rmsre_obj_temp = np.sqrt(np.mean((rel_errors_obj_temp / 100) ** 2)) * 100 plt.xlabel('物体温度 (°C)') plt.ylabel('净辐射功率 (W/m²)') plt.title(f'在固定大气温度为25℃下不同物体温度对净辐射功率的影响\nR²={r_squared_obj_temp:.2f}, MAE={mae_obj_temp:.2f} W/m², MRE={mre_obj_temp:.2f}%, RMSRE={rmsre_obj_temp:.2f}%') plt.legend(loc='upper right') plt.grid(True) obj_temp_plot_path = os.path.join(output_folder, 'object_temperature_plot.svg') plt.savefig(obj_temp_plot_path, format='svg') plt.show() # 绘制物体温度变化图的绝对误差 plt.figure(figsize=(10, 6)) plt.scatter(results_obj_temp['object_temp_c'], abs_errors_obj_temp, label='绝对误差') plt.axhline(y=mae_obj_temp, color='green', linestyle='--', label=f'平均绝对误差 ({mae_obj_temp:.2f} W/m²)') plt.xlabel('物体温度 (°C)') plt.ylabel('绝对误差 (W/m²)') plt.title(f'在固定大气温度为25℃下不同物体温度对净辐射功率的绝对误差') plt.legend(loc='upper right') plt.grid(True) obj_abs_error_plot_path = os.path.join(output_folder, 'object_absolute_error_plot.svg') plt.savefig(obj_abs_error_plot_path, format='svg') plt.show() # 绘制物体温度变化图的相对误差 plt.figure(figsize=(10, 6)) plt.scatter(results_obj_temp['object_temp_c'], rel_errors_obj_temp, label='相对误差 (%)') plt.axhline(y=mre_obj_temp, color='red', linestyle='--', label=f'平均相对误差 ({mre_obj_temp:.2f}%)') plt.axhline(y=rmsre_obj_temp, color='purple', linestyle='-.', label=f'RMSRE ({rmsre_obj_temp:.2f}%)') plt.xlabel('物体温度 (°C)') plt.ylabel('相对误差 (%)') plt.title(f'在固定大气温度为25℃下不同物体温度对净辐射功率的相对误差') plt.legend(loc='upper right') plt.grid(True) obj_rel_error_plot_path = os.path.join(output_folder, 'object_relative_error_plot.svg') plt.savefig(obj_rel_error_plot_path, format='svg') plt.show() # 绘制大气温度变化图 plt.figure(figsize=(10, 6)) plt.scatter(results_atmo_temp['atmosphere_temp_c'], results_atmo_temp['net_power'], label='数据点') # 一次函数拟合 coeffs_atmo_temp = np.polyfit(results_atmo_temp['atmosphere_temp_c'], results_atmo_temp['net_power'], 1) poly_fit_atmo_temp = np.poly1d(coeffs_atmo_temp) plt.plot(results_atmo_temp['atmosphere_temp_c'], poly_fit_atmo_temp(results_atmo_temp['atmosphere_temp_c']), color='red', label=f'y={coeffs_atmo_temp[0]:.2f}x+{coeffs_atmo_temp[1]:.2f}') # 计算R²值 residuals_atmo_temp = results_atmo_temp['net_power'] - poly_fit_atmo_temp(results_atmo_temp['atmosphere_temp_c']) ss_res_atmo_temp = np.sum(residuals_atmo_temp**2) ss_tot_atmo_temp = np.sum((results_atmo_temp['net_power'] - np.mean(results_atmo_temp['net_power']))**2) r_squared_atmo_temp = 1 - (ss_res_atmo_temp / ss_tot_atmo_temp) # 计算绝对误差相对误差 abs_errors_atmo_temp = np.abs(results_atmo_temp['net_power'] - poly_fit_atmo_temp(results_atmo_temp['atmosphere_temp_c'])) rel_errors_atmo_temp = abs_errors_atmo_temp / np.abs(results_atmo_temp['net_power']) * 100 # 相对误差转为百分比 # 计算平均绝对误差平均相对误差 mae_atmo_temp = np.mean(abs_errors_atmo_temp) mre_atmo_temp = np.mean(rel_errors_atmo_temp) # 计算均方根相对误差 (RMSRE) rmsre_atmo_temp = np.sqrt(np.mean((rel_errors_atmo_temp / 100) ** 2)) * 100 plt.xlabel('大气温度 (°C)') plt.ylabel('净辐射功率 (W/m²)') plt.title(f'在固定物体温度为25℃下不同大气温度对净辐射功率的影响\nR²={r_squared_atmo_temp:.2f}, MAE={mae_atmo_temp:.2f} W/m², MRE={mre_atmo_temp:.2f}%, RMSRE={rmsre_atmo_temp:.2f}%') plt.legend(loc='upper right') plt.grid(True) atmo_temp_plot_path = os.path.join(output_folder, 'atmosphere_temperature_plot.svg') plt.savefig(atmo_temp_plot_path, format='svg') plt.show() # 绘制大气温度变化图的绝对误差 plt.figure(figsize=(10, 6)) plt.scatter(results_atmo_temp['atmosphere_temp_c'], abs_errors_atmo_temp, label='绝对误差') plt.axhline(y=mae_atmo_temp, color='green', linestyle='--', label=f'平均绝对误差 ({mae_atmo_temp:.2f} W/m²)') plt.xlabel('大气温度 (°C)') plt.ylabel('绝对误差 (W/m²)') plt.title(f'在固定物体温度为25℃下不同大气温度对净辐射功率的绝对误差') plt.legend(loc='upper right') plt.grid(True) atmo_abs_error_plot_path = os.path.join(output_folder, 'atmosphere_absolute_error_plot.svg') plt.savefig(atmo_abs_error_plot_path, format='svg') plt.show() # 绘制大气温度变化图的相对误差 plt.figure(figsize=(10, 6)) plt.scatter(results_atmo_temp['atmosphere_temp_c'], rel_errors_atmo_temp, label='相对误差 (%)') plt.axhline(y=mre_atmo_temp, color='red', linestyle='--', label=f'平均相对误差 ({mre_atmo_temp:.2f}%)') plt.axhline(y=rmsre_atmo_temp, color='purple', linestyle='-.', label=f'RMSRE ({rmsre_atmo_temp:.2f}%)') plt.xlabel('大气温度 (°C)') plt.ylabel('相对误差 (%)') plt.title(f'在固定物体温度为25℃下不同大气温度对净辐射功率的相对误差') plt.legend(loc='upper right') plt.grid(True) atmo_rel_error_plot_path = os.path.join(output_folder, 'atmosphere_relative_error_plot.svg') plt.savefig(atmo_rel_error_plot_path, format='svg') plt.show() # 绘制双温度变量的变化图 plt.figure(figsize=(10, 6)) sc = plt.scatter(results_double_temp['atmosphere_temp_c'], results_double_temp['object_temp_c'], c=results_double_temp['net_power'], cmap='viridis', s=50) plt.colorbar(sc, label='净辐射功率 (W/m²)', pad=0.01) plt.xlabel('大气温度 (°C)') plt.ylabel('物体温度 (°C)') plt.title('不同物体温度大气温度组合下的净辐射功率') plt.grid(True) double_temp_scatter_path = os.path.join(output_folder, 'double_temperature_scatter_plot.svg') plt.savefig(double_temp_scatter_path, format='svg') plt.show() # 线性拟合 X = np.column_stack((results_double_temp['atmosphere_temp_c'], results_double_temp['object_temp_c'])) coeffs_double_temp, residuals, rank, s = np.linalg.lstsq(X, results_double_temp['net_power'], rcond=None) # 打印系数以调试 print(f"拟合得到的系数: {coeffs_double_temp}") print(f"残差平方: {residuals}") print(f"秩: {rank}") print(f"singular values: {s}") # 确保 coeffs_double_temp 是一个 numpy 数组 coeffs_double_temp = np.array(coeffs_double_temp) if len(coeffs_double_temp) == 2: a, b = coeffs_double_temp c = 0 # 假设截距为0 elif len(coeffs_double_temp) == 3: a, b = coeffs_double_temp[:2] c = coeffs_double_temp[2] else: raise ValueError("拟合得到的系数数量不符合预期") # 计算预测值 predicted_values = a * results_double_temp['atmosphere_temp_c'].to_numpy() + b * results_double_temp['object_temp_c'].to_numpy() + c # 计算绝对误差相对误差 abs_errors_double_temp = np.abs(results_double_temp['net_power'] - predicted_values) rel_errors_double_temp = abs_errors_double_temp / np.abs(results_double_temp['net_power']) * 100 # 相对误差转为百分比 # 计算均方根相对误差 (RMSRE) rmsre_double_temp = np.sqrt(np.mean((rel_errors_double_temp / 100) ** 2)) * 100 # 筛选相对误差大于500%的点 mask_high_error = rel_errors_double_temp > 500 high_error_points = results_double_temp[mask_high_error] high_error_rel_errors = rel_errors_double_temp[mask_high_error] # 绘制绝对误差图 plt.figure(figsize=(10, 6)) # 正常点 plt.scatter( results_double_temp['atmosphere_temp_c'][~mask_high_error], results_double_temp['object_temp_c'][~mask_high_error], c=abs_errors_double_temp[~mask_high_error], cmap='coolwarm', s=50, label='相对误差 ≤ 500%' ) # 特殊点(相对误差 > 500%) plt.scatter( high_error_points['atmosphere_temp_c'], high_error_points['object_temp_c'], c='black', s=100, marker='x', label=f'相对误差 > 500% ({len(high_error_points)}个点)' ) plt.colorbar(label='绝对误差 (W/m²)', pad=0.01) plt.xlabel('大气温度 (°C)') plt.ylabel('物体温度 (°C)') plt.title(f'不同物体温度大气温度组合下的绝对误差\nRMSRE={rmsre_double_temp:.2f}%') plt.legend(loc='upper right') plt.grid(True) double_temp_abs_error_path = os.path.join(output_folder, 'double_temperature_absolute_error_plot.svg') plt.savefig(double_temp_abs_error_path, format='svg') plt.show() # 绘制相对误差图(使用更鲜明的红色调,限制颜色映射范围为0-500%) plt.figure(figsize=(10, 6)) # 创建更鲜明的红色调的colormap(使用_r反转以获得更暗的红色) red_cmap = plt.cm.get_cmap('Reds_r') # 正常点(限制颜色映射范围为0-500%,增加点大小) scatter = plt.scatter( results_double_temp['atmosphere_temp_c'][~mask_high_error], results_double_temp['object_temp_c'][~mask_high_error], c=np.clip(rel_errors_double_temp[~mask_high_error], 0, 500), cmap=red_cmap, s=60, # 增加点大小,提高可见性 alpha=0.8 # 增加不透明度,使颜色更鲜明 ) # 特殊点(相对误差 > 500%,增加点大小) plt.scatter( high_error_points['atmosphere_temp_c'], high_error_points['object_temp_c'], c='black', s=120, # 增加特殊点大小,使其更突出 marker='x', linewidth=2, # 增加线条宽度 label=f'相对误差 > 500% ({len(high_error_points)}个点)' ) # 添加颜色条,并设置为百分比格式 cbar = plt.colorbar(scatter, pad=0.01) cbar.set_label('相对误差 (%)', rotation=270, labelpad=20) # 设置标题标签 plt.xlabel('大气温度 (°C)') plt.ylabel('物体温度 (°C)') plt.title(f'不同物体温度大气温度组合下的相对误差\nRMSRE={rmsre_double_temp:.2f}%') plt.legend(loc='upper right') plt.grid(True, linestyle='--', alpha=0.6) # 优化网格线 # 保存并显示图表 double_temp_rel_error_path = os.path.join(output_folder, 'double_temperature_relative_error_plot.svg') plt.savefig(double_temp_rel_error_path, format='svg') plt.show() # 绘制拟合平面 xx, yy = np.meshgrid(np.linspace(min(results_double_temp['atmosphere_temp_c']), max(results_double_temp['atmosphere_temp_c']), 10), np.linspace(min(results_double_temp['object_temp_c']), max(results_double_temp['object_temp_c']), 10)) zz = a * xx + b * yy + c plt.figure(figsize=(10, 6)) ax = plt.axes(projection='3d') # 正常点 scatter = ax.scatter( results_double_temp['atmosphere_temp_c'][~mask_high_error], results_double_temp['object_temp_c'][~mask_high_error], results_double_temp['net_power'][~mask_high_error], c=results_double_temp['net_power'][~mask_high_error], cmap='viridis', s=50, label='相对误差 ≤ 500%' ) # 特殊点(相对误差 > 500%) ax.scatter( high_error_points['atmosphere_temp_c'], high_error_points['object_temp_c'], high_error_points['net_power'], c='black', s=100, marker='x', label=f'相对误差 > 500% ({len(high_error_points)}个点)' ) surface = ax.plot_surface(xx, yy, zz, alpha=0.5, cmap='coolwarm') ax.set_xlabel('大气温度 (°C)') ax.set_ylabel('物体温度 (°C)') ax.set_zlabel('净辐射功率 (W/m²)') ax.zaxis.labelpad = 20 ax.xaxis.labelpad = 20 ax.yaxis.labelpad = 20 ax.set_title(f'不同物体温度大气温度组合下的净辐射功率\n拟合方程: z={a:.2f}x + {b:.2f}y + {c:.2f}\nRMSRE={rmsre_double_temp:.2f}%') plt.colorbar(scatter, label='净辐射功率 (W/m²)', ax=ax, location='left') plt.colorbar(surface, label='拟合面', ax=ax, location='right') plt.legend(loc='upper right') plt.grid(True) double_temp_fit_path = os.path.join(output_folder, 'double_temperature_fit_plot.svg') plt.savefig(double_temp_fit_path, format='svg') plt.show() # 示例用法 if __name__ == "__main__": calculator = RadiationCalculator() # 运行模拟,计算物体温度变化的结果 results_obj_temp = calculator.run_simulation_object_temperature() # 运行模拟,计算大气温度变化的结果 results_atmo_temp = calculator.run_simulation_atmosphere_temperature() # 运行模拟,计算双温度变量变化的结果 results_double_temp = calculator.run_simulation_double_temperature() # 创建输出文件夹 output_folder = r"D:/代码/梯形法则实际状况" # 保存结果到Excel文件 excel_file_path = os.path.join(output_folder, 'radiation_results.xlsx') calculator.save_results_to_excel(results_obj_temp, results_atmo_temp, results_double_temp, excel_file_path) # 绘制并保存图表 calculator.plot_and_save_figures(results_obj_temp, results_atmo_temp, results_double_temp, output_folder)这个代码的计算模块计算是否出现问题了
最新发布
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值