基坑预测插件是一个比较典型的功能性插件,基本涵盖了上述的大部分知识点,如果您更愿意跟随实际项目来快速上手,建议您阅读此章节。
首先点击【插件开发】-【新建插件】,在该文件夹中中编写所有所需主要功能代码:

代码解读

基坑支护数据-训练.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】文件夹下对应插件文件夹备份后删除,否侧存在覆盖安装原代码导致安装失败。