新闻中心
香港置地2025年置慧杯:商业综合体能耗预测基线
香港置地2025年“置慧杯”商业综合体能耗预测大赛,响应“双碳”战略,旨在通过建模实现标准化能耗估值。大赛提供2025年8月至2025年3月相关数据,要求预测特定时段公共及商户用电。基线用LSTM模型,基于能耗数据预测,优化空间大,有相应赛程、奖金及参赛要求。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

1. 大赛介绍
1.1 大赛背景
香港置地积极响应国家“碳达峰碳中和”双碳战略,致力于提高建筑的能耗效率,以降低成本并减少排放。降本减排需要一条最优的能耗估值,问题在于如何获得最优的能耗估值?
常规做法是由能耗顾问基于专业经验与历史数据进行估计,但这种做法强依赖于顾问的专业能力与公司的历史数据,无法实现标准化。
本次比赛诚邀社会各界开发者、商业体能耗专家从业者、企业研发人员和教育科研机构人员等以个人或团队形式报名参赛,希望各位参赛选手基于主办方提供的真实业务场景数据,完成模型的开发与优化,支持标准化能耗数据预测工作的开展,助力香港置地优化商业运营能耗。
1.2 大赛信息
比赛页面:香港置地2025年置慧杯:商业综合体能耗预测
-
比赛赛程:
时间 赛程 2025/4/1 00:00 飞桨平台开放报名通道,开放答疑通道 2025/4/18 10:00 开放数据下载通道 2025/4/25 10:00 开放A榜测评通道,评测4.1日-4.7日的预测数据 2025/5/7 18:00 关闭A榜测评通道,开启入围赛评测通道 2025/5/11 18:00 关闭入围赛评测通道 2025/5/16 18:00 基于入围赛榜单与代码审查结果,决出TOP10队伍 2025/5/20 18:00 线上答辩,决出TOP5队伍 2025/5/25 09:30 线下答辩,决出最终排名 -
奖金设置:
名称 数量 奖金 一等奖 1 5万元RMB/队+荣誉证书与奖杯 二等奖 1 2万元RMB/队+荣誉证书与奖杯 三等奖 1 1万元RMB/队+荣誉证书与奖杯 鼓励奖 2 5千元RMB/队+荣誉证书与奖杯 -
参赛要求:
本次竞赛面向全社会开放,不限年龄、身份、国籍,相关领域的个人、高等院校、科研机构、企业单位、初创团队等均可报名参赛;
大赛主办单位中有机会提前接触赛题和数据的人员不得参加比赛,其他员工可以参与比赛排名,但不可领取任何奖项。
支持以个人或团队形式参赛,允许跨单位自由组队,但每人只能参加一支队伍;
参赛选手报名须保证所提供的个人信息真实、准确、有效。
2. 数据内容
2.1 数据介绍
2025 年 8 月 1 日 - 2025 年 3 月 31 日的商场能耗数据
商业体基础信息基础资料;
-
时间数据:
- 大面积改造时间
- 特殊时间段(疫情等)
- 法定节假日(包括不限于商场运营调整)
客流量;
室外气象站数据以及室内环境监测系统数据;
其他源头数据的使用:在比赛过程中,选手也可以使用一些免费公开的数据,比如天气信息等,如对公开数据有疑问可咨询主办方。
2.2 数据集文件目录
Datasets.xlsx:原始的完整数据文件
能耗汇总结构.xlsx:Datasets.xlsx 中能耗的结构关系
数据上传格式20250423.csv:提交文件示例
2.3 数据详解
-
Datasets.xlsx 表格中包含非常多种的数据,其中最重要的是如下三张表格,它们收录了具体的能耗数据,而其他表格则是一些其他来源的数据(比如:天气 / 人流量等等),可供辅助使用:
1.1 t_meter_info:传感器相关信息
1.3 t_research_energyitem:区域相关信息
1.4 data_servicedata_1d:能耗相关信息
-
这三张表格的逻辑关系如下:
-
换用人话来讲:
首先 1.4 data_servicedata_1d 这个表格的每一行记录了每个传感器每天的能耗值
接下来通过任意一行能耗值中对应的传感器 id(即 meter)可以在 1.1 t_meter_info 这个表格中找到这个传感器安装的具体位置区域 id(即 energy_item_id)
然后可以通过 1.3 t_research_energyitem 这个表格查询具体位置区域 id (对应其中的 c_logic_id)的父节点 id(即 c_parent)
-
当然父节点也有自己的父节点,不断嵌套,类似下面这样:
美图云修
商业级AI影像处理工具
50
查看详情
c_logic_id c_name c_parent EI1001 总能耗 -1 EI101001 光环中心A座 EI1001 EI101030102001 办公公区(办公) EI101001 EI101030103001 暖通空调(办公) EI101030102001 EI101030303001 动力设备(办公) EI101030102001 通过“能耗 -> 传感器 id -> 区域 id -> 父节点区域 id -> ... -> 根节点 id(-1)”这样的逻辑链条,就可以把每个传感器每天的能耗值汇总到每个具体的区域中
-
各个区域的能耗计算逻辑如下:
- 总能耗 = 光环A座 + 光环B座 + 光环购物广场 + 超市
- 光环A座 = 光环A座(公区各分项+租区分项)
- 光环B座 = 光环B座(公区各分项+租区分项)
- 光环购物广场 = 光环A座(公区各分项+租区分项)
-
公共用电和商户用电计算逻辑如下(根据 1.3 t_research_energyitem 这个表格中的 c_order 值对应的区域):
- 公共用电 = (c_order=2) + (c_order=31) + (c_order=72)
- 商户用电 = (c_order=29) + (c_order=58) + (c_order=60) + (c_order=124)
3. 目标任务
3.1 任务说明
给定(2025.8.1-2025.3.31)的商场能耗数据,建立精确的能耗预测模型
预测未来一段时间(2025.4.1-2025.4.7 / 2025.4.18-2025.4.24)的商场能耗数据
具体的预测内容分两项:公共用电和商户用电,具体的计算逻辑参考上一节的内容
3.2 提交内容
-
A 榜的提交文件格式为 csv,具体内容如下:
c_order,c_logic_id,c_name,c_parent,2025/4/1,2025/4/2,2025/4/3,2025/4/4,2025/4/5,2025/4/6,2025/4/7998,998,公共用电,998,0,0,0,0,0,0,0999,999,商户用电,999,0,0,0,0,0,0,0
3.3 评审规则
-
评估指标:
-
本次比赛的能耗预测结果的评估指标采用平均百分比误差(MAPE):
-
-
评分标准:
ECS = (公共用电 MAPE + 商户用电 MAPE) / 2
ECS 能耗模型对应得分MS(百分制):
4. 基线算法
本基线项目中使用到的模型和数据较为简单
能耗预测本质上属于时间序列预测问题
在模型层面上,使用了一个非常经典的循环神经网络模型 LSTM(Long Short-Term Memory),这个模型可以很好的处理时间序列问题
在数据层面上,只使用了最基础的能耗数据,即使用前几天各个传感器的历史能耗数据来预测未来一天各个传感器的能耗数据
5. 代码实现
5.1 构建数据结构
- 为了方便的读取和计算能耗数据,构建一个简单的节点数据结构来储存每个区域的数据
import jsonimport numpy as npfrom datetime import dateclass Node:
def __init__(self, _id, parent_id, dates, mode, name=None, order=None):
'''
创建节点
参数:
_id: 节点 id
parent_id:父节点id
dates:日期列表
mode:'node' / 'meter'
name:节点名称
order:节点序号
'''
self._id = _id
self.parent_id = parent_id
self.name = name
self.order = order
self.dates = dates
self.mode = mode
self.values = [0] * len(dates)
self.parent = None
self.children = [] def add_child(self, node):
'''
添加子节点
参数:
node:子节点
'''
if node not in self.children:
self.children.append(node)
node.parent = self def get_values(self):
'''
获取节点能耗数据
返回:
节点能耗数据
'''
sum_values = [self.values] for child in self.children:
sum_values.append(child.get_values()) return np.asarray(sum_values).sum(0).tolist()
def set_value(self, date, value):
'''
设置指定日期的 meter 节点能耗数据
参数:
date:日期
value:能耗数据
'''
assert se
lf.mode=='meter'
self.values[self.dates.index(date)] += value def set_values(self, values):
'''
设置 meter 节点能耗数据
参数:
values:能耗数据
'''
assert self.mode=='meter'
assert len(values) == len(self.dates)
self.values = values
def reset_dates(self, dates):
'''
重设日期
参数:
dates:日期
'''
self.dates = dates
self.values = [0] * len(dates) for child in self.children:
child.reset_dates(dates) def meters(self):
'''
获取所有 meter
返回:
所有 meter
'''
if self.mode == 'meter': return [self] else:
meters = [] for child in self.children:
meters += child.meters() return meters def nodes(self):
'''
获取所有 node
返回:
所有 node
'''
if self.mode == 'meter': return [] else:
nodes = [self] for child in self.children:
nodes += child.nodes() return nodes
def __repr__(self):
'''
获取节点信息
返回:
节点信息
'''
if self.mode == 'meter': return json.dumps({ 'mode': 'meter', 'meter_id': self._id, 'logic_id': self.parent_id, 'values': self.values,
}, indent=4, ensure_ascii=False) else: return json.dumps({ 'mode': 'node', 'logic_id': self._id, 'parent_id': self.parent_id, 'name': self.name, 'order': self.order, 'values': self.get_values(), 'children': {child._id: json.loads(child.__repr__()) for child in self.children}
}, indent=4, ensure_ascii=False) def dump(self, json_file):
'''
保存节点
参数:
json_file:json 文件
'''
with open(json_file, 'w', encoding='UTF-8') as f:
f.write(self.__repr__())
@staticmethod
def load(json_file, dates):
'''
加载节点
参数:
json_file:json 文件
dates:日期
返回:
节点
'''
with open(json_file, 'r', encoding='UTF-8') as f:
node_info = json.load(f) return Node.create_node(node_info, dates) @staticmethod
def create_node(node_info, dates):
'''
创建节点
参数:
node_info:节点信息
dates:日期
返回:
节点
'''
if node_info['mode'] == 'node':
node = Node(node_info['logic_id'], node_info['parent_id'], dates, 'node', node_info['name'], node_info['order']) for child_info in node_info['children'].values():
node.add_child(Node.create_node(child_info, dates)) else:
node = Node(node_info['meter_id'], node_info['logic_id'], dates, 'meter')
node.values = node_info['values'] return node
5.2 读取数据
因为原始文件很大,处理起来比较耗时,所有这里直接加载预先处理完成的数据
-
使用如下代码重新生成数据文件,详细的处理流程可以参考该脚本文件
$ python gen_root.py
# 根节点数据data_json = 'root.json'# 生成日期序列dates = [ str(date.fromordinal(i).strftime("%Y%m%d000000")) for i in range(date(2025, 8, 1).toordinal(), date(2025, 3, 31).toordinal() + 1)
]# 加载根节点数据root = Node.load(data_json, dates)# 打印节点信息print({ 'name': root.name, # 节点名称
'order': root.order, # 节点序号
'id': root._id, # 节点 id
'parent_id': root.parent_id, # 父节点 id
'children_ids': [child._id for child in root.children], # 子节点 id}){'name': '总能耗', 'order': 0, 'id': 'EI1001', 'parent_id': '-1', 'children_ids': ['EI5201314083', 'EI5201314084', 'EI5201314085', 'EI101001']}
5.3 构建数据集
In [3]# 获取所有传感器meters = root.meters()# 获取所有传感器能耗数据meters_values = []for meter in meters:
meters_values.append(meter.get_values())
meters_values = np.asarray(meters_values).transpose(1, 0)# 切分数据集split_num = 21 # 验证集大小train_dataset = meters_values[0: -split_num, :]
val_dataset = meters_values[-split_num: , :]
train_num = train_dataset.shape[0]
val_num = val_dataset.shape[0]# 数据预处理max_value = train_dataset.max()
train_dataset /= max_value
val_dataset /= max_value
5.4 模型构建和配置
In [ ]import paddleimport paddle.nn as nnfrom paddle.optimizer import Adam# 构建 LSTM 模型net = nn.LSTM(626, 626, num_layers=1, direction='forward')# 配置 Adam 优化器opt = Adam(parameters=net.parameters(), learning_rate=0.0001)# 配置训练参数batch_size = 256 # 批处理大小steps = 20000 # 迭代次数days = 7 # 时间窗口log_iter = 20 # log 步幅keep_iter = 999999999 # 停止迭代步幅min_loss = 9999999999 # 最小 lossbest_step = 0 # 最佳迭代次数submit_csv = 'submit.csv' # 提交文件best_model = 'best_model.pdparams' # 最佳模型文件
5.5 模型训练和评估
In [5]for step in range(steps): # 数据采样
input_datas = []
label_datas = [] for _ in range(batch_size):
start = np.random.randint(0, train_num - days - 1)
end = start + days
input_datas.append(train_dataset[start: end, :])
label_datas.append(train_dataset[end, :])
input_datas = paddle.to_tensor(input_datas, dtype='float32')
label_datas = paddle.to_tensor(label_datas, dtype='float32') # 前向计算
h = net(input_datas)[1][0][-1] # 计算损失
loss = nn.functional.mse_loss(h, label_datas) # 反向传播
loss.backward() # 优化模型
opt.step() # 清除梯度
opt.clear_grad() # 模型评估
if step % log_iter == 0:
net.eval() with paddle.no_grad():
input_datas = paddle.to_tensor([train_dataset[-days:,: ]], dtype='float32')
predicts = [] for _ in range(val_num):
h = net(input_datas)[1][0][-1].clip(0)
predicts.append(h)
input_datas = paddle.concat([input_datas[:, 1:, :], h[None,...]], 1)
predicts = paddle.concat(predicts, 0)
label_datas = paddle.to_tensor(val_dataset, dtype='float32')
loss = nn.functional.mse_loss(predicts * max_value, label_datas * max_value).item() # 模型保存
if loss < min_loss:
min_loss = loss
best_step = step
paddle.s*e(net.state_dict(), best_model) print('s*ing best model, loss: %f step: %d' % (loss, step))
net.train()
if (step - best_step) > keep_iter: break/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/tensor/creation.py:130: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any beh*ior and is safe. Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations if data.dtype == np.object:
s*ing best model, loss: 276994.156250 step: 0 s*ing best model, loss: 230093.750000 step: 20 s*ing best model, loss: 193405.031250 step: 40 s*ing best model, loss: 157615.359375 step: 60 s*ing best model, loss: 115932.000000 step: 80 s*ing best model, loss: 82303.750000 step: 100 s*ing best model, loss: 67326.789062 step: 120 s*ing best model, loss: 58744.937500 step: 140 s*ing best model, loss: 49890.906250 step: 160 s*ing best model, loss: 44489.367188 step: 180 s*ing best model, loss: 41577.460938 step: 200 s*ing best model, loss: 39550.421875 step: 220 s*ing best model, loss: 36614.867188 step: 240 s*ing best model, loss: 35523.441406 step: 260 s*ing best model, loss: 35439.527344 step: 280 s*ing best model, loss: 35354.671875 step: 300 s*ing best model, loss: 34999.957031 step: 320 s*ing best model, loss: 34962.304688 step: 1380 s*ing best model, loss: 34935.687500 step: 2380 s*ing best model, loss: 34919.925781 step: 2420 s*ing best model, loss: 34893.078125 step: 6960 s*ing best model, loss: 34886.433594 step: 11300 s*ing best model, loss: 34796.238281 step: 11460 s*ing best model, loss: 34639.136719 step: 12000 s*ing best model, loss: 34360.699219 step: 15960 s*ing best model, loss: 34348.332031 step: 16180 s*ing best model, loss: 34245.355469 step: 17780
5.6 模型加载和预测
In [6]net.set_state_dict(paddle.load(best_model))
net.eval()with paddle.no_grad():
input_datas = paddle.to_tensor([val_dataset[-days:,: ]], dtype='float32')
predicts = [] for _ in range(7):
h = net(input_datas)[1][0][-1].clip(0)
predicts.append(h)
input_datas = paddle.concat([input_datas[:, 1:, :], h[None,...]], 1)
predicts = paddle.concat(predicts, 0)
predicts = (predicts * max_value).numpy().transpose(1, 0)
net.train()
5.7 数据重构
将根节点的日期重设并清除所有数据
将传感器的预测能耗数据重新添加回各个传感器节点
就能够通过根节点来计算所需要的各个区域的预测能耗数据
dates = [ str(date.fromordinal(i).strftime("%Y%m%d000000")) for i in range(date(2025, 4, 1).toordinal(), date(2025, 4, 7).toordinal() + 1)
]
root.reset_dates(dates)
meters = root.meters()for (meter, predict) in zip(meters, predicts):
meter.set_values(predict.tolist())
5.8 导出预测数据
In [8]publics = []
business = []for node in root.nodes(): if node.order in [2, 31, 72]:
publics.append(node.get_values()) elif node.order in [29, 58, 60, 124]:
business.append(node.get_values())
publics = np.asarray(publics).sum(0).tolist()
business = np.asarray(business).sum(0).tolist()with open(submit_csv, 'w', encoding='UTF-8') as f:
f.write('c_order,c_logic_id,c_name,c_parent,2025/4/1,2025/4/2,2025/4/3,2025/4/4,2025/4/5,2025/4/6,2025/4/7\n')
f.write('998,998,公共用电,998,'+','.join([str(_) for _ in publics])+'\n')
f.write('999,999,商户用电,999,'+','.join([str(_) for _ in business])+'\n')
6. 提交答案
前往 比赛页面 的提交结果选项卡进行答案提交
上传完结果文件即可在下方看到你的得分
基线的得分为:0 / 10.84%(高情商:差一点就 75 分),由于训练的随机性,分数会有变动,优化空间极大
基于此基线稍微优化一下即可达到:84 / 6.57%
当然这里就只提供了初始版本的代码和模型参数文件
使用如下代码复现上述结果(0 / 10.84%):
net.set_state_dict(paddle.load('baseline.pdparams'))
net.eval()with paddle.no_grad():
input_datas = paddle.to_tensor([val_dataset[-days:,: ]], dtype='float32')
predicts = [] for _ in range(7):
h = net(input_datas)[1][0][-1].clip(0)
predicts.append(h)
input_datas = paddle.concat([input_datas[:, 1:, :], h[None,...]], 1)
predicts = paddle.concat(predicts, 0)
predicts = (predicts * max_value).numpy().transpose(1, 0)
net.train()
dates = [ str(date.fromordinal(i).strftime("%Y%m%d000000")) for i in range(date(2025, 4, 1).toordinal(), date(2025, 4, 7).toordinal() + 1)
]
root.reset_dates(dates)
meters = root.meters()for (meter, predict) in zip(meters, predicts):
meter.set_values(predict.tolist())
publics = []
business = []for node in root.nodes(): if node.order in [2, 31, 72]:
publics.append(node.get_values()) elif node.order in [29, 58, 60, 124]:
business.append(node.get_values())
publics = np.asarray(publics).sum(0).tolist()
business = np.asarray(business).sum(0).tolist()with open('baseline.csv', 'w', encoding='UTF-8') as f:
f.write('c_order,c_logic_id,c_name,c_parent,2025/4/1,2025/4/2,2025/4/3,2025/4/4,2025/4/5,2025/4/6,2025/4/7\n')
f.write('998,998,公共用电,998,'+','.join([str(_) for _ in publics])+'\n')
f.write('999,999,商户用电,999,'+','.join([str(_) for _ in business])+'\n')
7. 优化指南
- 模型调参:更换时间窗口大小、调整学习率等
- 更换模型:更换模型为 GRU、Transformer 等
- 训练配置:更换损失函数、优化器等
- 更多数据:加入天气、人流量信息等
以上就是香港置地2025年置慧杯:商业综合体能耗预测基线的详细内容,更多请关注其它相关文章!
# 加载
# 服务营销推广战略规划方案
# 青海商城网站建设
# seo工作状况
# 企业网站优化制作方案
# seo博客怎么养
# 抚州市百度网站优化排名
# 谷歌seo推广公司朔州
# 定西市知名的网站推广
# angular seo 如何发布
# 如何整体优化网站
# 估值
# python
# 相关信息
# 美图
# 一言
# 万元
# 数据结构
# 中文网
# 商户
# 香港
# type
# red
# ai
相关栏目:
【
行业资讯67740 】
【
技术百科0 】
【
网络运营39195 】
相关推荐:
单片机怎么控制内功率
360n7锁屏壁纸怎么固定
空调主板单片机怎么拆开
固态硬盘装完如何使用
如何提高固态硬盘速度
固态硬盘如何测试好坏
固态硬盘损坏如何修复
如何安装tree命令
sqlite中datediff函数怎么用 SQLite中DATEDIFF()函数的用法分享
市盈率为负数是什么意思
固态硬盘内存如何查找
域名批量查询工具有哪些
华为的type-c接口是什么接口
为什么夸克运行不了
typescript文件怎么打开
命令行如何运行c
市盈率3.2是什么意思
typescript如何遍历map
typescript全局配置放哪里
如何用命令行连接本地数据库
固态硬盘质量如何
linux下如何重定位命令
春运提前抢票攻略
万能表上的power是什么意思
春运抢票哪里最火热
市盈率百分位roe是什么意思
夸克还原排版是什么意思
华为5g手机怎么选择
固态硬盘如何外接
什么是域名解析 域名解析中采用了什么
如何学习typescript
nosql数据库的应用场景有哪些
焊机上power指示灯亮是什么意思
苹果16有哪些自带配件
怎么用typescript 写js
如何区别固态硬盘
单片机怎么连接电路图
如何辨别固态硬盘坏块
企业征信不好如何恢复 企业征信不好怎么恢复步骤
如何查询固态硬盘寿命
固态硬盘如何打开软件
access中如何使用常用宏命令
微信最多可以加多少好友
市盈率高是什么意思
网络光刻机是干什么用的
固态硬盘如何区分好坏
typescript卸载不掉怎么办
春运辅助抢票怎么抢
苹果16更新了哪些软件
video是什么意思


2025-07-16
浏览次数:次
返回列表
lf.mode=='meter'
self.values[self.dates.index(date)] += value def set_values(self, values):
'''
设置 meter 节点能耗数据
参数:
values:能耗数据
'''
assert self.mode=='meter'
assert len(values) == len(self.dates)
self.values = values
def reset_dates(self, dates):
'''
重设日期
参数:
dates:日期
'''
self.dates = dates
self.values = [0] * len(dates) for child in self.children:
child.reset_dates(dates) def meters(self):
'''
获取所有 meter
返回:
所有 meter
'''
if self.mode == 'meter': return [self] else:
meters = [] for child in self.children:
meters += child.meters() return meters def nodes(self):
'''
获取所有 node
返回:
所有 node
'''
if self.mode == 'meter': return [] else:
nodes = [self] for child in self.children:
nodes += child.nodes() return nodes
def __repr__(self):
'''
获取节点信息
返回:
节点信息
'''
if self.mode == 'meter': return json.dumps({ 'mode': 'meter', 'meter_id': self._id, 'logic_id': self.parent_id, 'values': self.values,
}, indent=4, ensure_ascii=False) else: return json.dumps({ 'mode': 'node', 'logic_id': self._id, 'parent_id': self.parent_id, 'name': self.name, 'order': self.order, 'values': self.get_values(), 'children': {child._id: json.loads(child.__repr__()) for child in self.children}
}, indent=4, ensure_ascii=False) def dump(self, json_file):
'''
保存节点
参数:
json_file:json 文件
'''
with open(json_file, 'w', encoding='UTF-8') as f:
f.write(self.__repr__())
@staticmethod
def load(json_file, dates):
'''
加载节点
参数:
json_file:json 文件
dates:日期
返回:
节点
'''
with open(json_file, 'r', encoding='UTF-8') as f:
node_info = json.load(f) return Node.create_node(node_info, dates) @staticmethod
def create_node(node_info, dates):
'''
创建节点
参数:
node_info:节点信息
dates:日期
返回:
节点
'''
if node_info['mode'] == 'node':
node = Node(node_info['logic_id'], node_info['parent_id'], dates, 'node', node_info['name'], node_info['order']) for child_info in node_info['children'].values():
node.add_child(Node.create_node(child_info, dates)) else:
node = Node(node_info['meter_id'], node_info['logic_id'], dates, 'meter')
node.values = node_info['values'] return node