政安晨:【Keras机器学习示例演绎】(四十九)—— 利用 KerasNLP 实现语义相似性

news2025/1/15 23:22:55

目录

简介

数据集

设置

准备数据

配置特征空间

进一步自定义特征空间

根据训练数据调整特征空间

制作模型

训练模型

使用端到端模型对新数据进行推理


政安晨的个人主页政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏: TensorFlow与Keras机器学习实战

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正!

本文目标 :只需几行代码就能对表格数据进行分类。

简介


本例演示了如何从原始 CSV 文件开始进行结构化数据分类(也称为表格数据分类)。

我们的数据包括数字特征、整数分类特征和字符串分类特征。

我们将使用实用程序 keras.utils.FeatureSpace 对特征进行索引、预处理和编码。

代码改编自从零开始的结构化数据分类示例。那一个示例使用 Keras 预处理层管理自己的底层特征预处理和编码,而在本示例中,我们将一切委托给 FeatureSpace,使工作流程变得极其快速和简单。

数据集


我们的数据集由克利夫兰诊所心脏病基金会提供。这是一个有 303 行的 CSV 文件。每一行包含一名患者的信息(样本),每一列描述患者的一个属性(特征)。我们使用这些特征来预测患者是否患有心脏病(二元分类)。

以下是各项功能的说明:

ColumnDescriptionFeature Type
AgeAge in yearsNumerical
Sex(1 = male; 0 = female)Categorical
CPChest pain type (0, 1, 2, 3, 4)Categorical
TrestbpdResting blood pressure (in mm Hg on admission)Numerical
CholSerum cholesterol in mg/dlNumerical
FBSfasting blood sugar in 120 mg/dl (1 = true; 0 = false)Categorical
RestECGResting electrocardiogram results (0, 1, 2)Categorical
ThalachMaximum heart rate achievedNumerical
ExangExercise induced angina (1 = yes; 0 = no)Categorical
OldpeakST depression induced by exercise relative to restNumerical
SlopeSlope of the peak exercise ST segmentNumerical
CANumber of major vessels (0-3) colored by fluoroscopyBoth numerical & categorical
Thal3 = normal; 6 = fixed defect; 7 = reversible defectCategorical
TargetDiagnosis of heart disease (1 = true; 0 = false)Target

设置

import os

os.environ["KERAS_BACKEND"] = "tensorflow"

import tensorflow as tf
import pandas as pd
import keras
from keras.utils import FeatureSpace

准备数据


让我们下载数据并将其加载到 Pandas 数据框中:

file_url = "http://storage.googleapis.com/download.tensorflow.org/data/heart.csv"
dataframe = pd.read_csv(file_url)

数据集包括 303 个样本,每个样本有 14 列(13 个特征,加上目标标签):

print(dataframe.shape)
(303, 14)

下面是几个样本的预览:

dataframe.head()
agesexcptrestbpscholfbsrestecgthalachexangoldpeakslopecathaltarget
063111452331215002.330fixed0
167141602860210811.523normal1
267141202290212912.622reversible0
337131302500018703.530normal0
441021302040217201.410normal0

最后一栏 "目标 "表示患者是否患有心脏病(1)。

让我们把数据分成训练集和验证集:

val_dataframe = dataframe.sample(frac=0.2, random_state=1337)
train_dataframe = dataframe.drop(val_dataframe.index)

print(
    "Using %d samples for training and %d for validation"
    % (len(train_dataframe), len(val_dataframe))
)
Using 242 samples for training and 61 for validation

让我们为每个数据帧生成 tf.data.Dataset 对象:

def dataframe_to_dataset(dataframe):
    dataframe = dataframe.copy()
    labels = dataframe.pop("target")
    ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
    ds = ds.shuffle(buffer_size=len(dataframe))
    return ds


train_ds = dataframe_to_dataset(train_dataframe)
val_ds = dataframe_to_dataset(val_dataframe)

每个数据集都会产生一个元组(输入、目标),其中输入是一个特征字典,目标是 0 或 1 的值:

for x, y in train_ds.take(1):
    print("Input:", x)
    print("Target:", y)
Input: {'age': <tf.Tensor: shape=(), dtype=int64, numpy=65>, 'sex': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'cp': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'trestbps': <tf.Tensor: shape=(), dtype=int64, numpy=138>, 'chol': <tf.Tensor: shape=(), dtype=int64, numpy=282>, 'fbs': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'restecg': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'thalach': <tf.Tensor: shape=(), dtype=int64, numpy=174>, 'exang': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'oldpeak': <tf.Tensor: shape=(), dtype=float64, numpy=1.4>, 'slope': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'ca': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'thal': <tf.Tensor: shape=(), dtype=string, numpy=b'normal'>}
Target: tf.Tensor(0, shape=(), dtype=int64)

让我们对数据集进行批处理:

train_ds = train_ds.batch(32)
val_ds = val_ds.batch(32)

配置特征空间


要配置如何预处理每个特征,我们需要实例化 keras.utils.FeatureSpace,并向其传递一个将特征名称映射到描述特征类型的字符串的字典。

我们有一些 "整数分类 "特征,如 "FBS",一个 "字符串分类 "特征("thal"),以及一些数字特征,我们希望对这些特征进行归一化处理,但 "年龄 "除外,我们希望将其离散化为若干个分区。

我们还使用交叉参数来捕捉某些分类特征的特征交互,也就是说,创建额外的特征来表示这些分类特征的值共存。您可以计算任意分类特征集的交叉特征,而不仅仅是两个特征的元组。由于生成的共现值会散列到一个固定大小的向量中,因此您无需担心共现值空间是否过大。

feature_space = FeatureSpace(
    features={
        # Categorical features encoded as integers
        "sex": "integer_categorical",
        "cp": "integer_categorical",
        "fbs": "integer_categorical",
        "restecg": "integer_categorical",
        "exang": "integer_categorical",
        "ca": "integer_categorical",
        # Categorical feature encoded as string
        "thal": "string_categorical",
        # Numerical features to discretize
        "age": "float_discretized",
        # Numerical features to normalize
        "trestbps": "float_normalized",
        "chol": "float_normalized",
        "thalach": "float_normalized",
        "oldpeak": "float_normalized",
        "slope": "float_normalized",
    },
    # We create additional features by hashing
    # value co-occurrences for the
    # following groups of categorical features.
    crosses=[("sex", "age"), ("thal", "ca")],
    # The hashing space for these co-occurrences
    # wil be 32-dimensional.
    crossing_dim=32,
    # Our utility will one-hot encode all categorical
    # features and concat all features into a single
    # vector (one vector per sample).
    output_mode="concat",
)

进一步自定义特征空间

通过字符串名称指定特征类型简单快捷,但有时您可能需要进一步配置每个特征的预处理。例如,在我们的案例中,我们的分类特征并没有大量的可能值--每个特征只有少数几个值(例如,特征 "FBS "的值为 1 和 0),而且所有可能的值都在训练集中有所体现。因此,我们不需要为这些特征预留一个索引来表示 "词汇表之外 "的值--这本来是默认行为。下面,我们只需在每个特征中指定 num_oov_indices=0,告诉特征预处理器跳过 "超出词汇量 "索引。

您还可以进行其他自定义设置,包括指定用于离散化 "float_discretized "类型特征的分段数,或用于特征交叉的散列空间维度。

feature_space = FeatureSpace(
    features={
        # Categorical features encoded as integers
        "sex": FeatureSpace.integer_categorical(num_oov_indices=0),
        "cp": FeatureSpace.integer_categorical(num_oov_indices=0),
        "fbs": FeatureSpace.integer_categorical(num_oov_indices=0),
        "restecg": FeatureSpace.integer_categorical(num_oov_indices=0),
        "exang": FeatureSpace.integer_categorical(num_oov_indices=0),
        "ca": FeatureSpace.integer_categorical(num_oov_indices=0),
        # Categorical feature encoded as string
        "thal": FeatureSpace.string_categorical(num_oov_indices=0),
        # Numerical features to discretize
        "age": FeatureSpace.float_discretized(num_bins=30),
        # Numerical features to normalize
        "trestbps": FeatureSpace.float_normalized(),
        "chol": FeatureSpace.float_normalized(),
        "thalach": FeatureSpace.float_normalized(),
        "oldpeak": FeatureSpace.float_normalized(),
        "slope": FeatureSpace.float_normalized(),
    },
    # Specify feature cross with a custom crossing dim.
    crosses=[
        FeatureSpace.cross(feature_names=("sex", "age"), crossing_dim=64),
        FeatureSpace.cross(
            feature_names=("thal", "ca"),
            crossing_dim=16,
        ),
    ],
    output_mode="concat",
)

根据训练数据调整特征空间

在开始使用特征空间构建模型之前,我们必须使其适应训练数据。在 adapt() 过程中,特征空间将:

—— 为分类特征的可能值集建立索引。
——计算数值特征的均值和方差,以进行归一化处理。
——为数值特征计算不同分区的值边界,以实现离散化。


请注意,adapt() 应在 tf.data.Dataset 上调用,因为该数据集会生成特征值的二进制数(无标签)。

train_ds_with_no_labels = train_ds.map(lambda x, _: x)
feature_space.adapt(train_ds_with_no_labels)

此时,可以调用原始特征值的特征空间,它将为每个样本返回一个单一的串联向量,将编码特征和特征交叉结合起来。

for x, _ in train_ds.take(1):
    preprocessed_x = feature_space(x)
    print("preprocessed_x.shape:", preprocessed_x.shape)
    print("preprocessed_x.dtype:", preprocessed_x.dtype)
preprocessed_x.shape: (32, 138)
preprocessed_x.dtype: <dtype: 'float32'>

管理预处理的两种方法:作为 tf.data 管道的一部分,或在模型本身中进行预处理

您可以通过两种方式利用您的 "特色空间":

tf.data 中的异步预处理

您可以将其作为数据管道的一部分,置于模型之前。这样就能在数据进入模型之前,在 CPU 上对数据进行异步并行预处理。如果您在 GPU 或 TPU 上进行训练,或者您想加快预处理速度,可以这样做。通常,在训练过程中这样做总是正确的。

模型中的同步预处理

您可以将其作为模型的一部分。这意味着模型将期待原始特征值的字典,并且预处理批处理将在前向传递的其余部分之前同步(以阻塞方式)完成。如果你想拥有一个可以处理原始特征值的端到端模型,可以这样做,但请记住,你的模型只能在 CPU 上运行,因为大多数类型的特征预处理(如字符串预处理)都与 GPU 或 TPU 不兼容。

请勿在 GPU / TPU 或对性能敏感的设置中执行此操作。一般来说,在 CPU 上进行推理时,应在模型内进行预处理。

在我们的例子中,我们将在训练过程中在 tf.data 管道中应用特征空间,但我们将使用包含特征空间的端到端模型进行推理。

让我们创建一个预处理批次的训练和验证数据集:

preprocessed_train_ds = train_ds.map(
    lambda x, y: (feature_space(x), y), num_parallel_calls=tf.data.AUTOTUNE
)
preprocessed_train_ds = preprocessed_train_ds.prefetch(tf.data.AUTOTUNE)

preprocessed_val_ds = val_ds.map(
    lambda x, y: (feature_space(x), y), num_parallel_calls=tf.data.AUTOTUNE
)
preprocessed_val_ds = preprocessed_val_ds.prefetch(tf.data.AUTOTUNE)

制作模型


是时候建一个模型了,或者说建两个模型:

一个训练模型,需要预处理特征(一个样本 = 一个向量)
一个推理模型,需要原始特征(一个样本 = 原始特征值的二进制数)

dict_inputs = feature_space.get_inputs()
encoded_features = feature_space.get_encoded_features()

x = keras.layers.Dense(32, activation="relu")(encoded_features)
x = keras.layers.Dropout(0.5)(x)
predictions = keras.layers.Dense(1, activation="sigmoid")(x)

training_model = keras.Model(inputs=encoded_features, outputs=predictions)
training_model.compile(
    optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"]
)

inference_model = keras.Model(inputs=dict_inputs, outputs=predictions)

训练模型


让我们对模型进行 50 次历时训练。请注意,特征预处理是 tf.data 管道的一部分,而不是模型的一部分。

training_model.fit(
    preprocessed_train_ds,
    epochs=20,
    validation_data=preprocessed_val_ds,
    verbose=2,
)
Epoch 1/20
8/8 - 3s - 352ms/step - accuracy: 0.5200 - loss: 0.7407 - val_accuracy: 0.6196 - val_loss: 0.6663
Epoch 2/20
8/8 - 0s - 20ms/step - accuracy: 0.5881 - loss: 0.6874 - val_accuracy: 0.7732 - val_loss: 0.6015
Epoch 3/20
8/8 - 0s - 19ms/step - accuracy: 0.6580 - loss: 0.6192 - val_accuracy: 0.7839 - val_loss: 0.5577
Epoch 4/20
8/8 - 0s - 19ms/step - accuracy: 0.7096 - loss: 0.5721 - val_accuracy: 0.7856 - val_loss: 0.5200
Epoch 5/20
8/8 - 0s - 18ms/step - accuracy: 0.7292 - loss: 0.5553 - val_accuracy: 0.7764 - val_loss: 0.4853
Epoch 6/20
8/8 - 0s - 19ms/step - accuracy: 0.7561 - loss: 0.5103 - val_accuracy: 0.7732 - val_loss: 0.4627
Epoch 7/20
8/8 - 0s - 19ms/step - accuracy: 0.7231 - loss: 0.5374 - val_accuracy: 0.7764 - val_loss: 0.4413
Epoch 8/20
8/8 - 0s - 19ms/step - accuracy: 0.7769 - loss: 0.4564 - val_accuracy: 0.7683 - val_loss: 0.4320
Epoch 9/20
8/8 - 0s - 18ms/step - accuracy: 0.7769 - loss: 0.4324 - val_accuracy: 0.7856 - val_loss: 0.4191
Epoch 10/20
8/8 - 0s - 19ms/step - accuracy: 0.7778 - loss: 0.4340 - val_accuracy: 0.7888 - val_loss: 0.4084
Epoch 11/20
8/8 - 0s - 19ms/step - accuracy: 0.7760 - loss: 0.4124 - val_accuracy: 0.7716 - val_loss: 0.3977
Epoch 12/20
8/8 - 0s - 19ms/step - accuracy: 0.7964 - loss: 0.4125 - val_accuracy: 0.7667 - val_loss: 0.3959
Epoch 13/20
8/8 - 0s - 18ms/step - accuracy: 0.8051 - loss: 0.3979 - val_accuracy: 0.7856 - val_loss: 0.3891
Epoch 14/20
8/8 - 0s - 19ms/step - accuracy: 0.8043 - loss: 0.3891 - val_accuracy: 0.7856 - val_loss: 0.3840
Epoch 15/20
8/8 - 0s - 18ms/step - accuracy: 0.8633 - loss: 0.3571 - val_accuracy: 0.7872 - val_loss: 0.3764
Epoch 16/20
8/8 - 0s - 19ms/step - accuracy: 0.8728 - loss: 0.3548 - val_accuracy: 0.7888 - val_loss: 0.3699
Epoch 17/20
8/8 - 0s - 19ms/step - accuracy: 0.8698 - loss: 0.3171 - val_accuracy: 0.7872 - val_loss: 0.3727
Epoch 18/20
8/8 - 0s - 18ms/step - accuracy: 0.8529 - loss: 0.3454 - val_accuracy: 0.7904 - val_loss: 0.3669
Epoch 19/20
8/8 - 0s - 17ms/step - accuracy: 0.8589 - loss: 0.3359 - val_accuracy: 0.7980 - val_loss: 0.3770
Epoch 20/20
8/8 - 0s - 17ms/step - accuracy: 0.8455 - loss: 0.3113 - val_accuracy: 0.8044 - val_loss: 0.3684

<keras.src.callbacks.history.History at 0x7f139bb4ed10>

我们很快就能达到 80% 的验证准确率。

使用端到端模型对新数据进行推理


现在,我们可以使用推理模型(其中包括特征空间),根据原始特征值的字典进行预测,如下所示:

sample = {
    "age": 60,
    "sex": 1,
    "cp": 1,
    "trestbps": 145,
    "chol": 233,
    "fbs": 1,
    "restecg": 2,
    "thalach": 150,
    "exang": 0,
    "oldpeak": 2.3,
    "slope": 3,
    "ca": 0,
    "thal": "fixed",
}

input_dict = {name: tf.convert_to_tensor([value]) for name, value in sample.items()}
predictions = inference_model.predict(input_dict)

print(
    f"This particular patient had a {100 * predictions[0][0]:.2f}% probability "
    "of having a heart disease, as evaluated by our model."
)
 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 273ms/step
This particular patient had a 43.13% probability of having a heart disease, as evaluated by our model.

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1691104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis服务启动以及连接redis客户端(可配置密码)

1.Redis解压后目录 启动服务器&#xff1a; 1. 输入&#xff1a;redis-server.exe redis.windows.conf回车 ctrlC退出 连接客户端&#xff1a; 同样先打开命令窗口&#xff1a; 输入redis-cli.exe或者redis-cli.exe -h localhost -p 6379 exit退出 注意&#xff1a;想添加密…

DSPy - prompt 优化

文章目录 一、关于 DSPy与神经网络的类比常见问题解答**DSPy 优化器可以调整什么&#xff1f;****我应该如何使用 DSPy 完成我的任务&#xff1f;****如果我对提示或合成数据生成有更好的想法怎么办&#xff1f;**DSPy 代表什么&#xff1f; 二、安装三、文档A) 教程B) 指南C) …

LuatOS-iRTU

DTU 英文全称为Data Transfer Unit&#xff0c;表示数据传输单元。 是专门用于将串口数据转为IP数据或将I[数据转换为串口数据&#xff0c;通过无线通信网络进行传送的无线终端设备。 业务逻辑包括数据采集上报&#xff1a; 传感器采集数据发送给单片机&#xff0c;单片机由串…

干货 | 什么是单相感应电机控制器?一文带你看感应交流电机解决方案KP86202

单相感应电机控制器是一种用于控制单相感应电机运行的电子设备。单相感应电机是一种常见的电动机类型&#xff0c;广泛应用于家用电器、商业设备以及轻工制造等领域。 单相感应电机控制器通常包括电源模块、控制逻辑模块和功率输出模块。其主要功能是对单相感应电机进行启停、…

推荐网站(13)plantumlb自动帮我们创建 UML 图表

今天推荐一个网站plantumlb&#xff0c;它可以自动帮我们创建 UML 图表。 plantumlb网站中的PlantUML是一个开源工具&#xff0c;它允许用户使用简单的文本描述来创建UML&#xff08;统一建模语言&#xff09;图表。PlantUML支持多种类型的UML图表&#xff0c;包括用例图、类图…

等保建设:打造MySQL数据库审计系统

1、建设目标 在等级保护三级->应用安全->安全审计中强制需要有审计平台(满足对操作系统、数据库、网络设备的审计&#xff0c;在条件不允许的情况下&#xff0c;至少要使用数据库审计) 数据库审计服务符合等级保护三级标准&#xff0c;帮助您满足合规性要求&#xff0c;…

解决LabVIEW通过OPC Server读取PLC地址时的错误180121602

在使用LabVIEW通过OPC Server读取PLC地址时&#xff0c;若遇到错误代码180121602&#xff0c;建议检查网络连接、OPC Server和PLC配置、用户权限及LabVIEW设置。确保网络畅通&#xff0c;正确配置OPC变量&#xff0c;取消缓冲设置以实时读取数据&#xff0c;并使用诊断工具验证…

vue contextPath的思考

先说我这边的情况&#xff0c;目前项目都是前后端分离开发的&#xff0c;上线有种部署方式&#xff0c;常见的就是前后端分开部署&#xff0c;这是比较常见的&#xff0c;我这边因客户原因&#xff0c;打包一起进行部署比较简单&#xff0c;交付技术运维部方便后期其他现场部署…

DHT11获取数据传输到PC端

1.DHT11的时序数据 a : dht 1 b &#xff1a;dht 0延时30ms c&#xff1a; dht 1 卡d点&#xff1b;while(dht1); 卡e点 while(!dht) 卡f点&#xff1a;while(dht) 卡g点&#xff1a;while(!dht) 有效数据都是高电平&#xff0c;持续时间不一样&#xff0c;50us读&#…

首发!飞凌嵌入式FETMX6ULL-S核心板已适配OpenHarmony 4.1

近日&#xff0c;飞凌嵌入式在FETMX6ULL-S核心板上率先适配了OpenHarmony 4.1&#xff0c;这也是业内的首个应用案例&#xff0c;嵌入式核心板与OpenHarmony操作系统的结合与应用&#xff0c;将进一步推动千行百业的数智化进程。 飞凌嵌入式FETMX6ULL-S核心板基于NXP i.MX 6ULL…

水电集中抄表是什么?

1.定义分析&#xff1a;水电集中抄表 水电集中抄表是一种现代化能源管理体系方法&#xff0c;它利用先进的信息科技&#xff0c;如物联网技术、云计算等&#xff0c;完成对水电表数据的远程智能采集与处理。这种方法改变了传统的人工上门服务抄表方式&#xff0c;提高了效率&a…

为什么 buffer 越大传输效率越低

先看 从边际效益递减看 buffer 中挤占带宽 中的两个模型&#xff1a; E1 inflight_prop - inflight_buff&#xff1a; y 2 t x − b x a − x y2tx-\dfrac{bx}{a-x} y2tx−a−xbx​E2 bw / delay&#xff1a; y a x − x 2 b t a − t x y\dfrac{ax-x^2}{bta-tx} ybta−…

光环P3O不错的一个讲座

光环P3O不错的一个讲座&#xff0c;地址&#xff1a;https://apphfuydjku5721.h5.xiaoeknow.com/v2/course/alive/l_663dc840e4b0694c62c32d1d?app_idapphfuydJkU5721&share_fromu_5c987304d8515_wH2E5HgCgx&share_type5&share_user_idu_5c987304d8515_wH2E5HgCgx…

STL--set和multiset集合

set和multiset会根据特定的排序准则&#xff0c;自动将元素排序。两者不同之处在于multiset 允许元素重复而 set 不允许。如下图: 使用set或multiset&#xff0c;必须先包含头文件: #include <set>上述两个类型都被定义为命名空间std内的class template: namespace std…

Platformer Project

Platformer项目适合那些寻找坚实基础来构建你梦想中的3D平台游戏的人,提供受该类型最具影响力游戏启发的核心机制。 一般功能 移动支持; 自定义运动学角色控制器; Humanoid Rig支持(共享动画); 保存/加载(二进制、JSON或Playerprefs); 支持多个存储槽; 三星、硬币和最…

React-JSX基础

什么是JSX 概念&#xff1a;JSX是JavaScript和XML&#xff08;HTML&#xff09;的缩写&#xff0c;表示在JS代码中编写HTML模板结构&#xff0c;它是React中编写UI模板的方式 优势&#xff1a;1.HTML的声明式模板写法 2.JS的可编程能力 JSX的本质 JSX并不是标准的JS语法&…

高集成IP摄像SOC处理方案简介以及芯片介绍SSC336D

时至今日&#xff0c;随着科技越来越快的发展&#xff0c;视频监控领域目前已经向新型 IP 网络进行技术过渡。而 IP 网络摄像系统的初始定义为&#xff1a;网络与视频处理技术相统一的摄像单元。 网络摄像系统拥有自己的 IP 地址和计算功能&#xff0c;能处理网络通信任务。其…

Qt下使用QImage和OpenCV实现图像的拼接与融合

文章目录 前言一、使用QImage进行水平拼接二、使用OpenCV进行水平拼接三、使用OpenCV进行图像融合四、示例完整代码总结 前言 本文主要讲述了在Qt下使用QImage和OpenCV实现图像的拼接与融合&#xff0c;并结合相应的示例进行讲解&#xff0c;以便大家学习&#xff0c;如有错误…

Linux基础(二):环境搭建

本文准备从0开始&#xff0c;一步步搭建一套属于自己的Linux系统环境&#xff0c;这将是后续学Linux、用Linux、Linux环境编程、应用和项目部署、工具实验等一系列学习和实践的基石&#xff0c;希望对小伙伴们有帮助。提前备好Linux编程实验环境非常重要&#xff0c;建议人手一…