AttributeError: 'Individual' object has no attribute 'misc'
时间: 2025-07-04 08:21:26 浏览: 2
你遇到的新错误:
```
AttributeError: 'Individual' object has no attribute 'misc'
```
说明你在尝试访问 `sol.misc["extra"]` 时,`pymoo` 的 `Individual` 对象并没有这个属性。
---
## ❓ 问题根源
在 `pymoo` 中,当你使用 `res.opt` 获取最优解集时,这些是最优的个体(`Individual` 类型),但它们**不会自动携带你在 `_evaluate()` 中定义的 `out["extra"]` 数据**。
虽然你可以通过 `res.pop` 来获取整个种群,并从中提取 `extra` 数据,但 `res.opt` 是一个经过非支配排序筛选后的最优前沿解集,它需要手动从 `res.pop` 中匹配。
---
## ✅ 正确的做法:从 `res.pop` 中提取所有结果,并筛选出满足约束的解
我们不再依赖 `res.opt`,而是遍历整个种群 `res.pop`,找到目标函数和约束值,并筛选出符合约束条件的解。
---
## ✅ 修改后的完整代码如下(重点部分已标注):
```python
import numpy as np
import pickle
import time
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from pymoo.core.problem import ElementwiseProblem
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
from pymoo.core.population import Population
from pymoo.core.variable import Real, Integer
from pymoo.core.mixed import MixedVariableMating, MixedVariableSampling, MixedVariableDuplicateElimination
from pymoo.operators.mutation.pm import PolynomialMutation
from pymoo.operators.crossover.sbx import SBX
class OptimProblem(ElementwiseProblem):
def __init__(self):
# 定义变量边界(48个变量,移除了x44/x47/x49)
self.vars = {
"x01": Real(bounds=(1538, 1870)), # S101-M
"x02": Real(bounds=(20148, 24544)), # S104-M
"x03": Real(bounds=(1827.5, 2179.5)), # S108-M
"x04": Real(bounds=(7863.51, 9538.54)), # S112-M
"x05": Real(bounds=(299.604, 364.467)), # S201-M
"x06": Real(bounds=(84837.5, 103471)), # S313-M
"x07": Real(bounds=(13.0821, 15.9591)), # S313-T
"x08": Real(bounds=(426.6, 521.4)), # S313-P
"x09": Real(bounds=(18857.3, 22984.1)), # H101-M
"x10": Real(bounds=(288.71, 350.558)), # H101-COT
"x11": Real(bounds=(18040.6, 21986.5)), # H102-M
"x12": Real(bounds=(540.196, 659.749)), # H102-COT
"x13": Real(bounds=(10632, 12973)), # H201-M
"x14": Real(bounds=(288.167, 351.655)), # H201-HOT
"x15": Real(bounds=(14517.8, 17590.1)), # H301-M
"x16": Real(bounds=(58.271, 70.9577)), # H301-HOT
"x17": Real(bounds=(72029.7, 87790.8)), # H302-M
"x18": Real(bounds=(57.225, 69.1627)), # H302-COT
"x19": Real(bounds=(6685.61, 8148.55)), # H303-M
"x20": Real(bounds=(-9.29859, -7.62888)), # H303-HOT
"x21": Real(bounds=(900.657, 1098.62)), # RE101-C
"x22": Real(bounds=(9.02238, 10.8986)), # RE101-H
"x23": Real(bounds=(1.35287, 1.64148)), # RE101-D
"x24": Real(bounds=(910.653, 1101.31)), # RE102-C
"x25": Real(bounds=(7.2783, 8.7985)), # RE102-H
"x26": Real(bounds=(0.722521, 0.876798)), # RE102-D
"x27": Real(bounds=(1351.32, 1647.75)), # RE103-C
"x28": Real(bounds=(7.22507, 8.77916)), # RE103-H
"x29": Real(bounds=(1.38167, 1.61998)), # RE103-D
"x30": Real(bounds=(1.80656, 2.19881)), # RE201-P
"x31": Real(bounds=(6.31061, 7.6632)), # RE201-L
"x32": Real(bounds=(0.453803, 0.549121)), # RE201-D
"x33": Real(bounds=(1.80579, 2.19799)), # F201-P
"x34": Real(bounds=(135.366, 164.98)), # F201-T
"x35": Real(bounds=(1.75542, 2.14253)), # AB301-P1
"x36": Integer(bounds=(11, 14)), # AB301-N
"x37": Real(bounds=(0.0930186, 0.113473)), # R301-P1
"x38": Real(bounds=(1.81906, 2.21977)), # R301-R
"x39": Real(bounds=(5889250, 6683890)), # R301-QN
"x40": Real(bounds=(0.757167, 0.923944)), # R302-P1
"x41": Real(bounds=(-71041.4, -58147.9)), # R302-Q1
"x42": Integer(bounds=(7, 8)), # R301-N
"x43": Real(bounds=(0.108235, 0.130973)), # V301-P
# "x44": Integer(bounds=(8, 9)), # R301-FEEDS
"x45": Integer(bounds=(7, 8)), # R302-N
"x46": Real(bounds=(0.772167, 0.941046)), # V302-P
# "x47": Integer(bounds=(8, 9)), # R302-FEEDS
"x48": Real(bounds=(1.78042, 2.17364)), # V303-P
# "x49": Integer(bounds=(12, 15)), # AB301-FEEDS
"x50": Real(bounds=(58, 71)), # F301-T
"x51": Real(bounds=(1.98292, 2.37614)), # F301-P
}
# 预加载模型
self.models = {
'TAC': pickle.load(open("TAC.dat", "rb")),
'CO2R': pickle.load(open("CO2R.dat", "rb")),
'HD': pickle.load(open("HD.dat", "rb")),
'C1C2R': pickle.load(open("C1C2R.dat", "rb")),
'RE101Y': pickle.load(open("RE101Y.dat", "rb")),
'RE102Y': pickle.load(open("RE102Y.dat", "rb")),
'RE103Y': pickle.load(open("RE103Y.dat", "rb")),
'RE201Y': pickle.load(open("RE201Y.dat", "rb"))
}
super().__init__(vars=self.vars, n_obj=3, n_constr=5)
def _evaluate(self, x, out, *args, **kwargs):
input_vector = self._construct_input_vector(x)
TAC = self.models['TAC'].predict(input_vector.reshape(1, -1))[0]
CO2R = self.models['CO2R'].predict(input_vector.reshape(1, -1))[0]
HD = self.models['HD'].predict(input_vector.reshape(1, -1))[0]
C1C2R = self.models['C1C2R'].predict(input_vector.reshape(1, -1))[0]
RE101Y = self.models['RE101Y'].predict(input_vector.reshape(1, -1))[0]
RE102Y = self.models['RE102Y'].predict(input_vector.reshape(1, -1))[0]
RE103Y = self.models['RE103Y'].predict(input_vector.reshape(1, -1))[0]
RE201Y = self.models['RE201Y'].predict(input_vector.reshape(1, -1))[0]
# 设置目标函数:[TAC, HD, -CO2R]
out["F"] = np.array([
TAC,
HD,
-CO2R
])
# 设置约束:g <= 0
tolerance = 1e-6
out["G"] = np.array([
0.90 - C1C2R + tolerance,
0.90 - RE101Y + tolerance,
0.90 - RE102Y + tolerance,
0.90 - RE103Y + tolerance,
0.90 - RE201Y + tolerance
])
# 存储原始值用于后续输出 ✅ 新增部分
out["extra"] = {
"TAC": TAC,
"CO2R": CO2R,
"HD": HD,
"C1C2R": C1C2R,
"RE101Y": RE101Y,
"RE102Y": RE102Y,
"RE103Y": RE103Y,
"RE201Y": RE201Y
}
def _construct_input_vector(self, x):
base = np.array([x[f"x{k:02}"] for k in range(1, 52) if f"x{k:02}" in self.vars])
x44_val = x["x42"] + 1
x47_val = x["x45"] + 1
x49_val = x["x36"] + 1
return np.insert(base, [43, 46, 48], [x44_val, x47_val, x49_val])
def setup_algorithm(pop_size=200):
return NSGA2(
pop_size=pop_size,
sampling=MixedVariableSampling(),
crossover=SBX(prob=0.85, eta=20),
mutation=PolynomialMutation(prob=0.7, eta=30),
mating=MixedVariableMating(eliminate_duplicates=MixedVariableDuplicateElimination()),
eliminate_duplicates=MixedVariableDuplicateElimination()
)
if __name__ == "__main__":
start_time = time.time()
problem = OptimProblem()
algorithm = setup_algorithm()
res = minimize(problem, algorithm, ('n_gen', 100), seed=42, save_history=True, verbose=True)
# 提取所有个体信息
all_vars = []
all_objs = []
all_extra = []
for ind in res.pop:
all_vars.append(ind.X)
all_objs.append(ind.F)
all_extra.append(ind.CV_dict["out"]["extra"]) # ✅ 从 ind.CV_dict 中提取 extra
all_vars = np.array(all_vars)
all_objs = np.array(all_objs)
all_extra = np.array(all_extra)
# 筛选满足约束的解(G <= 0)
feasible_mask = np.all(res.G <= 0, axis=1)
feasible_vars = all_vars[feasible_mask]
feasible_objs = all_objs[feasible_mask]
feasible_extra = all_extra[feasible_mask]
if len(feasible_objs) == 0:
print("没有满足约束的解。")
else:
# 自动推荐最优解
ideal_point = np.min(feasible_objs, axis=0)
distances = np.linalg.norm(feasible_objs - ideal_point, axis=1)
best_idx = np.argmin(distances)
print("\n==== 推荐解 ====")
print("索引:", best_idx)
print("变量配置:")
for name, val in zip(problem.vars.keys(), feasible_vars[best_idx]):
print(f" {name}: {val:.4f}")
print("\n对应目标函数值:")
print(f" TAC: {feasible_extra[best_idx]['TAC']:.2f}")
print(f" HD: {feasible_extra[best_idx]['HD']:.2f}")
print(f" CO2R: {feasible_extra[best_idx]['CO2R']:.4f}")
print("\n对应约束值:")
print(f" C1C2R: {feasible_extra[best_idx]['C1C2R']:.4f}")
print(f" RE101Y: {feasible_extra[best_idx]['RE101Y']:.4f}")
print(f" RE102Y: {feasible_extra[best_idx]['RE102Y']:.4f}")
print(f" RE103Y: {feasible_extra[best_idx]['RE103Y']:.4f}")
print(f" RE201Y: {feasible_extra[best_idx]['RE201Y']:.4f}")
# 保存结果
np.savetxt("optimal_variables.csv", feasible_vars, delimiter=",", header=",".join(problem.vars.keys()), comments='')
np.savetxt("optimal_objectives.csv", feasible_objs, delimiter=",", header="TAC,HD,-CO2R", comments='')
# 可视化
fig, ax = plt.subplots(1, 1, figsize=(8, 6))
scatter = ax.scatter(feasible_objs[:, 0], feasible_objs[:, 1], c=-feasible_objs[:, 2], cmap="viridis")
ax.set_title("TAC vs HD (color=CO2R)")
ax.set_xlabel("TAC")
ax.set_ylabel("HD")
plt.colorbar(scatter, ax=ax)
plt.tight_layout()
plt.savefig("pareto_TAC_vs_HD.png", dpi=900)
plt.show()
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(feasible_objs[:, 0], feasible_objs[:, 1], -feasible_objs[:, 2], c='teal', s=40)
ax.set_xlabel('TAC')
ax.set_ylabel('HD')
ax.set_zlabel('CO2R')
ax.set_title('3D Pareto Front: TAC vs HD vs CO2R')
plt.tight_layout()
plt.savefig("pareto_3d_TAC_HD_CO2R.png", dpi=900)
plt.show()
```
---
## ✅ 总结修改点
| 原代码 | 错误原因 | 修改后 |
|--------|----------|--------|
| `sol.CV_dict["extra"]` | `CV_dict` 并不存在于 `res.opt` | 改为从 `res.pop` 中提取 `ind.CV_dict["out"]["extra"]` |
| 使用 `res.opt` | 不包含 `extra` 信息 | 改用 `res.pop` 和过滤机制 |
---
##
阅读全文
相关推荐


















