基坑预测插件是一个比较典型的功能性插件,基本涵盖了上述的大部分知识点,如果您更愿意跟随实际项目来快速上手,建议您阅读此章节。
首先点击【插件开发】
-【新建插件】
,在该文件夹中中编写所有所需主要功能代码:
代码解读
基坑支护数据-训练.py
脚本通过pandas库加载了训练集和测试集数据。这些数据一般存储在CSV文件中,通过指定文件路径,脚本能够准确地找到并读取这些文件。在读取数据后,脚本将标准输出重定向到一个文本文件,这样所有后续的输出信息都会被记录在这个新的文件中,便于查看和分析。
import sys
savedStdout = sys.stdout # 保存标准输出流
file = open(os.path.dirname(sys.argv[0]) +
"\\训练结果集\\"+"训练数据结果.txt", 'w+', encoding="utf-8")
sys.stdout = file # 标准输出重定向至文件
train_data = pd.read_csv(os.path.dirname(
sys.argv[0]) + "\\训练样本集\\"+"train.csv") # 训练集
test_data = pd.read_csv(
os.path.dirname(
sys.argv[0]) + "\\训练样本集\\"+"test.csv") # 测试集
接下来,脚本进行了数据探索。它打印了训练集和测试集的整体信息,包括每一列的数据类型、非空值数量等,这些信息有助于了解数据的基本结构和质量。同时,脚本还输出了数据集的统计信息,如均值、标准差、最小值、最大值等,这些数据提供了对数据分布和范围的直观认识。此外,脚本还打印了数据集的前五行和后五行,这些样本数据能够直观地展示数据的实际内容和格式。
# 数据探索
# 查看数据集的整体情况
print(train_data.info())
print('-'*100)
print(test_data.info())
print('-'*100)
# 了解数据集的统计情况
print(train_data.describe())
print('-'*100)
print(test_data.describe())
print('-'*100)
# 数据集的前5行
print(train_data.head())
print('-'*100)
print(test_data.head())
print('-'*100)
# 数据集的后5行
print(train_data.tail())
print('-'*100)
print(test_data.tail())
在完成数据探索后,脚本进行了数据清洗。针对数据中可能存在的缺失值,脚本使用了不同的填充策略。对于“ShearModulus/Mpa”列中的空值,脚本使用了该列的平均值进行填充;而对于“SoilDensity/(g/cm^3)”列中的空值,脚本则使用了众数进行填充。这样的处理保证了数据集的完整性,避免了由于缺失值而导致的模型训练问题。
# 数据清洗
# ShearModulus/Mpa中的空值可用平均剪切模量来填充
# inplace=True不创建新的对象,直接对原始对象进行修改
train_data['ShearModulus/Mpa'].fillna(
train_data['ShearModulus/Mpa'].mean(), inplace=True)
test_data['ShearModulus/Mpa'].fillna(
test_data['ShearModulus/Mpa'].mean(), inplace=True)
# 计数函数
# print(train_data['SoilDensity/(g/cm^3)'].value_counts())
# 使用土体密度的众数来填充土体密度的 nan 值
train_data['SoilDensity/(g/cm^3)'].fillna(1900, inplace=True)
test_data['SoilDensity/(g/cm^3)'].fillna(1900, inplace=True)
然后,我们进行了特征选择。脚本定义了两组特征变量features1和features2,分别对应不同的预测目标(桩顶水平位移和基坑周边沉降)。这些特征是从原始数据集中选取的,对于分类任务来说,选取合适的特征可以提高模型的预测性能和准确性。
# 特征选择:选择对分类结果有关键作用的特征
features = ['BulkModulus/Mpa', 'ShearModulus/Mpa', 'Cohesion/kpa', 'InternalFrictionAngle/(degree)',
'SoilDensity/(g/cm^3)', 'LengthInclinedPile/m', 'AngleFoundationPit/(degree)']
test_features = test_data[features]
# HorizontalPileTop/mm 桩顶水平位移/mm
features1 = ['ShearModulus/Mpa',
'SoilDensity/(g/cm^3)', 'LengthInclinedPile/m', 'AngleFoundationPit/(degree)']
train_features1 = train_data[features1]
train_labels1 = train_data['HorizontalPileTop/mm']
test_features1 = test_data[features1]
# Settlement/mm 基坑周边沉降/mm
features2 = ['BulkModulus/Mpa', 'Cohesion/kpa', 'InternalFrictionAngle/(degree)', 'SoilDensity/(g/cm^3)',
'LengthInclinedPile/m']
train_features2 = train_data[features2]
train_labels2 = train_data['Settlement/mm']
# print('--------------------')
test_features2 = test_data[features2]
# print(test_features2)
脚本使用了DictVectorizer类将特征向量转化为特征矩阵。DictVectorizer可以将符号化的对象转化为数字0或1进行表示,这对于机器学习模型来说是必要的一步操作,因为大多数模型只能处理数值型数据。
dvec1 = DictVectorizer(sparse=False)
dvec2 = DictVectorizer(sparse=False)
# 将特征向量转化为特征矩阵
train_features1 = dvec1.fit_transform(
train_features1.to_dict(orient='records'))
# 查看转化后的属性
print(dvec1.feature_names_)
print('-'*100)
train_features2 = dvec2.fit_transform(
train_features2.to_dict(orient='records'))
print(dvec2.feature_names_)
print('-'*100)
脚本构造了两个基于熵判据的决策树分类器clf1和clf2,并使用训练集的特征值矩阵和分类结果对它们进行训练。决策树是一种常用的机器学习分类算法,它通过构建树状结构来对数据进行分类,该算法鲁棒性强、可以处理多分类问题。
# 构造 ID3 决策树
clf1 = DecisionTreeClassifier(criterion='entropy') # 熵判据
clf2 = DecisionTreeClassifier(criterion='entropy') # 熵判据
# 决策树训练:将特征值矩阵和分类结果作为参数传入,得到决策树分类器
clf1.fit(train_features1, train_labels1)
clf2.fit(train_features2, train_labels2)
训练完成后,脚本将测试集的特征值转化为特征矩阵,并使用训练好的决策树分类器进行预测。预测结果pred_labels1和pred_labels2分别对应两组特征变量的预测结果。
# 得到测试集的特征值矩阵
test_features1 = dvec1.transform(test_features1.to_dict(orient='records'))
test_features2 = dvec2.transform(test_features2.to_dict(orient='records'))
# print(test_features1)
# print('-'*100)
# print(test_features2)
# print('-'*100)
# 决策树保存
# 两个决策树模型
joblib.dump(clf1, os.path.dirname(sys.argv[0])+'\\训练结果集\\DecisionTree1.pkl')
joblib.dump(clf2, os.path.dirname(sys.argv[0])+'\\训练结果集\\DecisionTree2.pkl')
# 两个特征数据集
joblib.dump(dvec1, os.path.dirname(sys.argv[0])+'\\训练结果集\\DictVectorizer1.pkl')
joblib.dump(dvec2, os.path.dirname(sys.argv[0])+'\\训练结果集\\DictVectorizer2.pkl')
# 决策树预测
pred_labels1 = clf1.predict(test_features1)
pred_labels2 = clf2.predict(test_features2)
print(pred_labels1)
print('-'*100)
print(pred_labels2)
脚本将预测结果和测试集的其他信息组合成一个新的数据框temp,并将其保存为CSV文件。同时,脚本还使用joblib库将训练好的决策树模型和特征转换器保存为pickle文件,以便后续使用。并对CSV文件进行了处理。
# 将预测后的结果导出到文件中
pred_labels = [[*x, y, z]
for x, y, z in zip(test_data._values, pred_labels1, pred_labels2)]
temp = pd.DataFrame(pred_labels)
# 设置对列索引
temp.index = temp.index+1
temp = temp.drop(columns=0)
temp.to_csv(os.path.dirname(sys.argv[0])+'\\训练结果集\\re.csv')
# csv文件第一行插入一行文字
text = 'Num, BulkModulus/Mpa, ShearModulus/Mpa, Cohesion/kpa, InternalFrictionAngle/(degree), SoilDensity/(g/cm^3), LengthInclinedPile/m, AngleFoundationPit/(degree), HorizontalPileTop/mm, Settlement/mm'
with open(os.path.dirname(sys.argv[0])+'\\训练结果集\\re.csv', 'r+', encoding='utf-8') as f:
content = f.read()
delnum = content.find('\n')
for i in range(delnum):
content = content[1:]
f.seek(0, 0)
f.write(text + content)
接下来,脚本对训练好的决策树模型进行了准确率评估。这里使用了模型的score方法,该方法通过计算模型在训练集上的准确率来评估模型的性能。并支持导出“训练数据结果.txt”来展示训练结果及保存准确率评估结果,方便用户处理。
# 用训练集做训练,再用训练集自身做准确率评估,得到决策树准确率
acc_decision_tree1 = round(clf1.score(train_features1, train_labels1), 6)*100
print('由桩顶水平位移得到的支护等级 准确率为 %.4lf' % acc_decision_tree1+"%")
acc_decision_tree2 = round(clf2.score(train_features2, train_labels2), 6)*100
print('由基坑周边沉降得到的支护等级 准确率为 %.4lf' % acc_decision_tree2+"%")
# 打开数据结果&准确率文件
sys.stdout = savedStdout # 恢复标准输出流
file.close()
os.startfile(os.path.dirname(sys.argv[0])+'\\训练结果集\\')
os.startfile(os.path.dirname(sys.argv[0])+'\\训练结果集\\训练数据结果.txt')
打开训练样本集.py
打开训练样本集主要是通过os库打开对应的csv文件
import os
import sys
os.startfile(os.path.dirname(sys.argv[0])+"\\训练样本集")
os.startfile(os.path.dirname(sys.argv[0])+"\\训练样本集\\train.csv")
基坑支护实时预测模型.py
此脚本主要是根据训练好的数据进行生成模型,主要建模步骤可以参考第3大章的造型函数的使用
from pyp3d import *
import joblib
import pandas as pd
class 基坑支护(Component):
def __init__(self):
Component.__init__(self)
self['坑外土体长'] = Attr(70000.0, obvious=True, group='土方尺寸')
self['开挖土层长'] = Attr(20000.0, obvious=True, group='土方尺寸')
self['坑外土体高'] = Attr(40000.0, obvious=True, group='土方尺寸')
self['土层宽'] = Attr(9000.0, obvious=True, group='土方尺寸')
self['基坑深'] = Attr(10000.0, obvious=True, group='基坑尺寸')
self['直立排桩直径'] = Attr(800.0, obvious=True, group='支护尺寸')
self['与基坑侧壁夹角'] = Attr(45, obvious=True, group='(机器学习)支护尺寸')
self['斜桩长度'] = Attr(11000.0, obvious=True, group='(机器学习)支护尺寸')
self['体积模量'] = Attr(0.7, obvious=True, group='(机器学习)土体属性')
self['剪切模量'] = Attr(0.65, obvious=True, group='(机器学习)土体属性')
self['黏聚力'] = Attr(3.0, obvious=True, group='(机器学习)土体属性')
self['内摩擦角'] = Attr(15, obvious=True, group='(机器学习)土体属性')
self['土体密度'] = Attr(1700, obvious=True, group='(机器学习)土体属性')
self['桩顶水平位移'] = Attr(1, combo=[1, 2, 3, 4],
obvious=True, group='(机器学习-预测)变形指标及支护等级')
self['基坑周边沉降'] = Attr(1, combo=[1, 2, 3, 4],
obvious=True, group='(机器学习-预测)变形指标及支护等级')
self['基坑支护'] = Attr(None, show=True)
self.replace()
@export
def replace(self):
dir = os.path.dirname(__file__)+ "\\训练结果集\\"
print(dir)
clf1 = joblib.load(f'{dir}DecisionTree1.pkl')
clf2 = joblib.load(f'{dir}DecisionTree2.pkl')
dvec1 = joblib.load(f'{dir}DictVectorizer1.pkl')
dvec2 = joblib.load(f'{dir}DictVectorizer2.pkl')
scores1 = {
'ShearModulus/Mpa': [self['剪切模量']],
'SoilDensity/(g/cm^3)': [self['土体密度']],
'LengthInclinedPile/m': [self['斜桩长度']/1000],
'AngleFoundationPit/(degree)': [self['与基坑侧壁夹角']]
}
scores2 = {
'BulkModulus/Mpa': [self['体积模量']],
'Cohesion/kpa': [self['黏聚力']],
'InternalFrictionAngle/(degree)': [self['内摩擦角']],
'SoilDensity/(g/cm^3)': [self['土体密度']],
'LengthInclinedPile/m': [self['斜桩长度']/1000]
}
# 将特征向量转化为特征矩阵
df1 = pd.DataFrame(scores1)
df1 = dvec1.transform(df1.to_dict(orient='records'))
df2 = pd.DataFrame(scores2)
df2 = dvec2.transform(df2.to_dict(orient='records'))
pred_labels1 = clf1.predict(df1)
pred_labels2 = clf2.predict(df2)
# 变量赋值
earthwork_L1 = self['坑外土体长']
earthwork_L2 = self['开挖土层长']
earthwork_H = self['坑外土体高']
earthwork_W = self['土层宽']
foundationpit_H = self['基坑深']
vertical_D = self['直立排桩直径']
angle = self['与基坑侧壁夹角']
batter_L = self['斜桩长度']
self['桩顶水平位移'] = int(pred_labels1[0])
self['基坑周边沉降'] = int(pred_labels2[0])
piletop_D = self['桩顶水平位移']
settlement = self['基坑周边沉降']
if piletop_D == 1:
piletop_D = -0.0025*foundationpit_H
elif piletop_D == 2:
piletop_D = -0.01*foundationpit_H
elif piletop_D == 3:
piletop_D = -0.02*foundationpit_H
elif piletop_D == 4:
piletop_D = -0.1*foundationpit_H
if settlement == 1:
settlement = -10
elif settlement == 2:
settlement = -30
elif settlement == 3:
settlement = -50
elif settlement == 4:
settlement = -100
color1 = (200/255, 167/255, 100/255, 0.7) # 土黄
color2 = (235/255, 230/255, 202/255, 0.7) # 浅黄
color3 = (150/255, 160/255, 170/255, 1) # 深灰
color4 = (210/255, 210/255, 217/255, 1) # 浅灰
color5 = (120/255, 147/255, 162/255, 1) # 蓝
mag1 = 100
mag2 = 20
# 土方
h1 = earthwork_H-foundationpit_H # 坑底土体深度
# 坑外土体
points = [Vec2(mag2*piletop_D, earthwork_H),
Vec2(1/4*(earthwork_L1-piletop_D),
earthwork_H+mag1*settlement),
Vec2(2/4*(earthwork_L1-piletop_D),
earthwork_H-mag1*settlement),
Vec2(3/4*(earthwork_L1-piletop_D), earthwork_H+settlement),
Vec2(earthwork_L1-piletop_D, earthwork_H+settlement)]
# 使用spline_curve_quasi函数可以获取quasi类型样条曲线离散点的列表
soilLine = spline_curve_quasi(points, 100)
soilPath = Line(Vec3(0, 0, 0), Vec3(0, 0, earthwork_W))
earthwork_1 = translate(0, earthwork_W, -h1)*rotx(pi/2) *\
Sweep(Section(Line(soilLine, Vec2(earthwork_L1-piletop_D, 0),
Vec2(0, 0))), soilPath).color(color2)
# 坑底土体
earthwork_2 = translate(0, earthwork_W, -h1)*rotx(pi/2) *\
Sweep(Section(Line(Vec2(0, 0), Vec2(-earthwork_L2, 0),
Vec2(-earthwork_L2, h1), Vec2(mag2*piletop_D/earthwork_H*h1, h1))), soilPath).color(color1)
earthwork = Combine(earthwork_1, earthwork_2)
# 止水帷
Curtain_H = batter_L*cos(angle/180*pi)+5000
Curtain_L = 1/30*Curtain_H
curtain = translate(piletop_D+0.1, -0.1, foundationpit_H-Curtain_H+0.1) * \
scale(Curtain_L, earthwork_W+0.2, Curtain_H)*Cube().color(color5)
curtain = translate(-0.1, earthwork_W, -h1+0.1)*rotx(pi/2) *\
Sweep(Section(Line(Vec2(mag2*piletop_D, earthwork_H), Vec2(mag2*piletop_D+Curtain_L, earthwork_H),
Vec2(mag2*piletop_D+Curtain_L-mag2*piletop_D /
earthwork_H*Curtain_H, earthwork_H-Curtain_H),
Vec2(mag2*piletop_D-mag2*piletop_D/earthwork_H*Curtain_H, earthwork_H-Curtain_H))),
Line(Vec3(0, 0, 0), Vec3(0, 0, earthwork_W+0.2))).color(color5)
# 支护
# 直立排桩
n = earthwork_W/1600 # 桩间距1600
single_vert = Cone(Vec3(0, 0, 0), Vec3(mag2*piletop_D/earthwork_H *
(Curtain_H-0.6*vertical_D), 0, Curtain_H-0.6*vertical_D), vertical_D/2)
verticalpile_0 = Array(single_vert)
for j in range(0, int(n)+1):
verticalpile_0.append(translate(0, 1600*j))
verticalpile = translate(-0.6*vertical_D+mag2*piletop_D/earthwork_H*(
earthwork_H-Curtain_H), vertical_D/2, foundationpit_H-Curtain_H)*verticalpile_0.color(color3)
# 冠梁
Cbeam_L = 1.2*vertical_D
Cbeam_H = 1/2*Cbeam_L+100
cappingbeam = translate(-0.1, earthwork_W, -h1+0.1)*rotx(pi/2) *\
Sweep(Section(Line(Vec2(mag2*piletop_D, earthwork_H), Vec2(mag2*piletop_D-Cbeam_L, earthwork_H),
Vec2(mag2*piletop_D-Cbeam_L-mag2*piletop_D /
earthwork_H*Cbeam_H, earthwork_H-Cbeam_H),
Vec2(mag2*piletop_D-mag2*piletop_D/earthwork_H*Cbeam_H, earthwork_H-Cbeam_H))),
soilPath).color(color4)
# 斜桩
single_batter = translate(-1.1*vertical_D, 0, foundationpit_H/2)*roty(angle/180*pi) *\
translate(-vertical_D/2, vertical_D/2) * \
Cone(Vec3(0, 0, 0), Vec3(0, 0, -batter_L), vertical_D/2)
batterpile_0 = Array(single_batter)
for i in range(0, int(n+1)):
batterpile_0.append(translate(0, 1600*i))
batterpile = translate(
mag2*piletop_D/earthwork_H*(h1+foundationpit_H/2), 0)*batterpile_0.color(color3)
# 腰梁
Wale_sec = Section(Vec2(0, 0),
Vec2(0.4*vertical_D, 0),
Vec2(0.4*vertical_D+vertical_D*cos(angle /
180*pi), vertical_D*sin(angle/180*pi)),
Vec2(0.4*vertical_D+vertical_D *
cos(angle/180*pi), vertical_D),
Vec2(0, vertical_D))
Wale = translate(0.7*vertical_D, 0, foundationpit_H/2) *\
Sweep(rotx(0.5*pi)*Wale_sec,
Line(Vec3(0, 0, 0), Vec3(0, earthwork_W, 0)))
Wale = translate(mag2*piletop_D/earthwork_H*(h1+foundationpit_H/2), 0)*translate(
0, earthwork_W/2)*rotz(pi)*translate(0, -earthwork_W/2)*Wale.color(color4)
# 最终组合
基坑支护 = Combine(
earthwork,
curtain,
verticalpile,
cappingbeam,
batterpile,
Wale)
self['基坑支护'] = 基坑支护
# import time
# createGeometry(earthwork)
# time.sleep(0.5)
# createGeometry(curtain)
# time.sleep(0.5)
# createGeometry(verticalpile)
# time.sleep(0.5)
# createGeometry(cappingbeam)
# time.sleep(0.5)
# createGeometry(Wale)
# time.sleep(0.5)
# createGeometry(batterpile)
if __name__ == "__main__":
FinalGeometry = 基坑支护()
place(FinalGeometry)
自动配置环境
自动配置环境分为两部分,py脚本主要是为了驱动bat文件
import os
os.startfile(os.path.dirname(__file__)+"\\自动配置环境.bat")
bat文件包含了自动配置环境的代码,详细内容可参照第1大章
@echo off
echo Starting automatic deployment of the environment...
echo.
cd %~dp0
cd ..
cd ..
cd ..
set pyPath=%CD%\PythonScript\python-3.7.9-embed-amd64\
set pipPath=%CD%\PythonScript\python-3.7.9-embed-amd64\Scripts\
echo Python interpreter path: %pyPath%
echo.
echo Pip3 path: %pipPath%
echo.
echo Pip3 installing
echo.
"%pyPath%\python.exe" "%pyPath%\get-pip.py" -i https://pypi.tuna.tsinghua.edu.cn/simple/
echo.
echo pandas installing
echo.
"%pipPath%\pip3.exe" install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple/
echo.
echo sklearn installing
echo.
"%pipPath%\pip3.exe" install scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple/
echo.
echo joblib installing
echo.
"%pipPath%\pip3.exe" install joblib -i https://pypi.tuna.tsinghua.edu.cn/simple/
@PAUSE
编写bat文件安装第三方库,和配套的Python脚本
配置xml文件
绑定图标文件,此处py脚本的路径为相对路径可参照此xml的文件结构写法
选择打包路径,生成exe可执行文件
至此,一个Python插件就完成打包了,需要注意的是如果在本机测试安装exe文件是否可用,一定要先把【\BIMBase建模软件 2024\App】
文件夹下对应插件文件夹备份后删除,否侧存在覆盖安装原代码导致安装失败。