讨论和总结 树模型 的三种序列化 方式的区别(模型存储大小、序列化所用内存、序列化速度)...

news2024/9/25 1:24:56

一、前言

本文总结常用树模型: rf,xgboost,catboost和lightgbm等模型的保存和加载(序列化和反序列化)的多种方式,并对多种方式从运行内存的使用和存储大小做对比

二、模型

2.1 安装环境

pip install xgboost
pip install lightgbm
pip install catboost
pip install scikit-learn

可以指定版本也可以不指定,直接下载可获取最新的pkg

2.2 模型运行例子

针对iris数据集的多分类任务

import xgboost as xgb
from catboost import CatBoostClassifier
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

import lightgbm as lgb
from sklearn.ensemble import RandomForestClassifier


iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

# xgb
xgb_train = xgb.DMatrix(X_train, y_train)
xgb_test = xgb.DMatrix(X_test, y_test)
xgb_params = {'objective': 'multi:softmax', 'eval_metric': 'mlogloss', 'num_class': 3, 'verbosity': 0}
xgb_model = xgb.train(xgb_params, xgb_train)
y_pred = xgb_model.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)

# lgb
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
params = {
    'boosting_type': 'gbdt',
    'objective': 'multiclass',
    'num_class': 3,
    'metric': 'multi_logloss',
    'num_leaves': 31,
    'learning_rate': 0.05,
    'feature_fraction': 0.9
}
gbm = lgb.train(params, lgb_train, num_boost_round=100, valid_sets=[lgb_eval], early_stopping_rounds=5)
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
y_pred = [list(x).index(max(x)) for x in y_pred]
lgb_acc = accuracy_score(y_test, y_pred)

# rf
rf = RandomForestClassifier()
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
rf_acc = accuracy_score(y_test, y_pred)

# catboost
cat_boost_model = CatBoostClassifier(depth=9, learning_rate=0.01,
                                     loss_function='MultiClass', custom_metric=['AUC'],
                                     eval_metric='MultiClass', random_seed=1996)

cat_boost_model.fit(X_train, y_train, eval_set=(X_test, y_test), use_best_model=True, early_stopping_rounds=1000)
y_pred = cat_boost_model.predict(X_test)
cat_acc = accuracy_score(y_test, y_pred)

print(xgb_acc, lgb_acc, rf_acc, cat_acc)

2.3 运行内存计算

def cal_current_memory():
    # 获取当前进程内存占用。
    pid = os.getpid()
    p = psutil.Process(pid)
    info = p.memory_full_info()
    memory_used = info.uss / 1024. / 1024. / 1024.
    return {
        'memoryUsed': memory_used
    }

获取当前进程的pid,通过pid来定向查询memory的使用

三、保存和加载

主要有三种方法:

  1. jsonpickle

  2. pickle

  3. 模型api

3.1 jsonpickle

jsonpickle 是一个 Python 序列化和反序列化库,它可以将 Python 对象转换为 JSON 格式的字符串,或将 JSON 格式的字符串转换为 Python 对象。

调用jsonpickle.encode即可序列化,decode进行反序列化

以xgb为例

保存:

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

# xgb
xgb_train = xgb.DMatrix(X_train, y_train)
xgb_test = xgb.DMatrix(X_test, y_test)
xgb_params = {'objective': 'multi:softmax', 'eval_metric': 'mlogloss', 'num_class': 3, 'verbosity': 0}
xgb_model = xgb.train(xgb_params, xgb_train)
y_pred = xgb_model.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)

xgb_str = jsonpickle.encode(xgb_model)
with open(f'{save_dir}/xgb_model_jsonpickle.json', 'w') as f:
    f.write(xgb_str)

加载:

save_dir = './models'

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

xgb_test = xgb.DMatrix(X_test, y_test)

with open(f'{save_dir}/xgb_model_jsonpickle.json', 'r') as f:
    xgb_model_jsonpickle = f.read()
xgb_model_jsonpickle = jsonpickle.decode(xgb_model_jsonpickle)
y_pred = xgb_model_jsonpickle.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)
print(xgb_acc)

这样就完成了模型的保存和加载

优势

  1. 模型加载过程不需要重新实例化,直接jsonpickle.decode模型文件即可直接获得模型

  2. 获得的模型文件是json格式,便于各种编程语言和平台之间的数据交换,方便实现不同系统之间的数据传输和共享

劣势

  1. 在处理大型或者复杂的模型时,序列化过程可能会出现性能问题(占用更多的memory)

  2. 模型文件存储空间比较大

3.2 pickle

pickle 是 Python 的一种序列化和反序列化模块,可以将 Python 对象转换为字节流,也可以将字节流转换为 Python 对象,进而实现 Python 对象的持久化存储和恢复。(模型也是个对象)

调用pickle.dump/dumps即可序列化,pickle.load/loads进行反序列化(其中dump直接将序列化文件保存,二dumps则是返回序列化后的bytes文件,load和loads亦然)

这里可以查看和其他python方法的对比:https://docs.python.org/zh-cn/3/library/pickle.html

以xgb为例

保存:

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

# xgb
xgb_train = xgb.DMatrix(X_train, y_train)
xgb_test = xgb.DMatrix(X_test, y_test)
xgb_params = {'objective': 'multi:softmax', 'eval_metric': 'mlogloss', 'num_class': 3, 'verbosity': 0}
xgb_model = xgb.train(xgb_params, xgb_train)
y_pred = xgb_model.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)

with open(f'{save_dir}/xgb_model_pickle.pkl', 'wb') as f:
    pickle.dump(xgb_model, f)

加载:

save_dir = './models'

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

xgb_test = xgb.DMatrix(X_test, y_test)

with open(f'{save_dir}/xgb_model_pickle.pkl', 'rb') as f:
    xgb_model_pickle = pickle.load(f)
y_pred = xgb_model_pickle.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)
print(xgb_acc)

优势

  1. 模型加载过程同样不需要重新实例化,这点和jsonpickle一样

  2. 序列化文件相比于jsonpickle小非常的多,且读取和保存都会更快

劣势

  1. 在处理大型或者复杂的对象时,可能会出现性能问题(占用更多的memory)

  2. 不是json格式,很难跨平台和语言使用

3.3 模型自带

以xgb为例

保存

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

# xgb
xgb_train = xgb.DMatrix(X_train, y_train)
xgb_test = xgb.DMatrix(X_test, y_test)
xgb_params = {'objective': 'multi:softmax', 'eval_metric': 'mlogloss', 'num_class': 3, 'verbosity': 0}
xgb_model = xgb.train(xgb_params, xgb_train)
y_pred = xgb_model.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)

model_path = f'{save_dir}/xgb_model_self.bin' #也可以是json格式,但最终文件大小有区别 
xgb_model.save_model(model_path)

加载

save_dir = './models'

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

xgb_test = xgb.DMatrix(X_test, y_test)

xgb_model_self = xgb.Booster()
xgb_model_self.load_model(f'{save_dir}/xgb_model_self.bin')
y_pred = xgb_model_self.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)
print(xgb_acc)

更多文档参考:https://xgboost.readthedocs.io/en/stable/tutorials/saving_model.html

优势

  1. 只保存了模型的参数文件(包含树结构和需要模型参数比如 the objective function等), 模型文件较小

  2. 序列化过程中的运行内存所占不多

  3. 也可以保存json的形式(在XGBoost 1.0.0之后推荐以json的方式保存)

劣势

  1. 需要在加载模型之前创建模型的实例。

四、实验

以下主要还是针对较小的模型来做的实验

4.1 模型存储大小对比实验

28dac749994c9c45614a4aeeaa59d6ec.png
  1. _jsonpickle就是用jsonpickle方法序列化的模型文件

  2. _pickle是用pickle方法序列化的模型文件

  3. _self就是利用自身的save model的方法保存的模型文件

可以看出来是 jsonpickle> pickle > self 的关系

4.2 运行的memory对比实验

通过对序列化前后的memory做监控,例如xgb(只考虑序列化,去掉文件写入所需要的memory):

print("before:", cal_current_memory())
model_path = f'{save_dir}/xgb_model_self.bin'
xgb_model.save_model(model_path)
print("after:", cal_current_memory())

运行得到:

before: {'memoryUsed': 0.1490936279296875}
after: {'memoryUsed': 0.14911270141601562}
print("before:", cal_current_memory())
pickle.dumps(xgb_model)
print("after:", cal_current_memory())

运行得到:

before: {'memoryUsed': 0.1498260498046875}
after: {'memoryUsed': 0.14990234375}
print("before:", cal_current_memory())
xgb_str = jsonpickle.encode(xgb_model)
print("after:", cal_current_memory())

运行得到:

before: {'memoryUsed': 0.14917755126953125}
after: {'memoryUsed': 0.15140914916992188}

可以看出来对于xgb模型,picklejson所需要的memory是其他两种方法的几十倍,而其余两种方法很相似

lgb的结果:

对应上述顺序:

self:
before: {'memoryUsed': 0.14953994750976562}
after {'memoryUsed': 0.14959716796875}
pickle:
before: {'memoryUsed': 0.14938735961914062}
after {'memoryUsed': 0.14946746826171875}
jsonpickle:
before: {'memoryUsed': 0.14945602416992188}
after {'memoryUsed': 0.14974594116210938}

这里依然是jsonpickle大一些,但倍数小一些

catboost的结果:

self:
before: {'memoryUsed': 0.24615478515625}
after {'memoryUsed': 0.25492095947265625}
pickle:
before: {'memoryUsed': 0.2300567626953125}
after {'memoryUsed': 0.25820159912109375}
jsonpickle:
before: {'memoryUsed': 0.2452239990234375}
after {'memoryUsed': 0.272674560546875}

4.3 序列化时间对比

因为catboost总体模型大小大一些,所以通过catboost才能更好的反应序列化的速度

self:
0.02413797378540039 s
pickle:
0.04681825637817383 s
jsonpickle:
0.3211638927459717  s

jsonpickle的花费的时间会多一些

五、 总体代码

训练:

import base64
import json
import os
import pickle
import time
import jsonpickle
import psutil
import xgboost as xgb
from catboost import CatBoostClassifier
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

import lightgbm as lgb
from sklearn.ensemble import RandomForestClassifier

save_dir = "./models"


def cal_current_memory():
    # 获取当前进程内存占用。
    pid = os.getpid()
    p = psutil.Process(pid)
    info = p.memory_full_info()
    memory_used = info.uss / 1024. / 1024. / 1024.
    return {
        'memoryUsed': memory_used
    }


iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

# xgb
xgb_train = xgb.DMatrix(X_train, y_train)
xgb_test = xgb.DMatrix(X_test, y_test)
xgb_params = {'objective': 'multi:softmax', 'eval_metric': 'mlogloss', 'num_class': 3, 'verbosity': 0}
xgb_model = xgb.train(xgb_params, xgb_train)
y_pred = xgb_model.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)
#
# print("before:", cal_current_memory())
# model_path = f'{save_dir}/xgb_model_self.bin'
# xgb_model.save_model(model_path)
# print("after", cal_current_memory())
with open(f'{save_dir}/xgb_model_pickle.pkl', 'wb') as f:
    pickle.dump(xgb_model, f)
print(cal_current_memory())
xgb_str = jsonpickle.encode(xgb_model)
with open(f'{save_dir}/xgb_model_jsonpickle.json', 'w') as f:
    f.write(xgb_str)
print(cal_current_memory())


# lgb
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
params = {
    'boosting_type': 'gbdt',
    'objective': 'multiclass',
    'num_class': 3,
    'metric': 'multi_logloss',
    'num_leaves': 31,
    'learning_rate': 0.05,
    'feature_fraction': 0.9
}
gbm = lgb.train(params, lgb_train, num_boost_round=100, valid_sets=[lgb_eval], early_stopping_rounds=5)
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
y_pred = [list(x).index(max(x)) for x in y_pred]
lgb_acc = accuracy_score(y_test, y_pred)
#
# print("before:", cal_current_memory())
# model_path = f'{save_dir}/lgb_model_self.bin'
# gbm.save_model(model_path)
# print("after", cal_current_memory())

with open(f'{save_dir}/lgb_model_pickle.pkl', 'wb') as f:
    pickle.dump(gbm, f)

lgb_str = jsonpickle.encode(gbm)
with open(f'{save_dir}/lgb_model_jsonpickle.json', 'w') as f:
    f.write(lgb_str)


# rf
rf = RandomForestClassifier()
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
rf_acc = accuracy_score(y_test, y_pred)


with open(f'{save_dir}/rf_model_pickle.pkl', 'wb') as f:
    pickle.dump(rf, f)

rf_str = jsonpickle.encode(rf)
with open(f'{save_dir}/rf_model_jsonpickle.json', 'w') as f:
    f.write(rf_str)



# catboost
cat_boost_model = CatBoostClassifier(depth=9, learning_rate=0.01,
                                     loss_function='MultiClass', custom_metric=['AUC'],
                                     eval_metric='MultiClass', random_seed=1996)

cat_boost_model.fit(X_train, y_train, eval_set=(X_test, y_test), use_best_model=True, early_stopping_rounds=1000)
y_pred = cat_boost_model.predict(X_test)
cat_acc = accuracy_score(y_test, y_pred)

# t = time.time()
# model_path = f'{save_dir}/cat_boost_model_self.bin'
# cat_boost_model.save_model(model_path)
# print("after", time.time() - t)

# print("before:", cal_current_memory())
# model_path = f'{save_dir}/cat_boost_model_self.bin'
# cat_boost_model.save_model(model_path)
# print("after", cal_current_memory())
with open(f'{save_dir}/cat_boost_model_pickle.pkl', 'wb') as f:
    pickle.dump(cat_boost_model, f)

cat_boost_model_str = jsonpickle.encode(cat_boost_model)
with open(f'{save_dir}/cat_boost_model_jsonpickle.json', 'w') as f:
    f.write(cat_boost_model_str)

print(xgb_acc, lgb_acc, rf_acc, cat_acc)

测试

import pickle

import jsonpickle
import psutil
import xgboost as xgb
from catboost import CatBoostClassifier
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
import lightgbm as lgb
from sklearn.ensemble import RandomForestClassifier

save_dir = './models'

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1996)

xgb_test = xgb.DMatrix(X_test, y_test)

xgb_model_self = xgb.Booster()
xgb_model_self.load_model(f'{save_dir}/xgb_model_self.bin')
y_pred = xgb_model_self.predict(xgb_test)
xgb_acc = accuracy_score(y_test, y_pred)
print(xgb_acc)

# with open(f'{save_dir}/xgb_model_pickle.pkl', 'rb') as f:
#     xgb_model_pickle = pickle.load(f)
# y_pred = xgb_model_pickle.predict(xgb_test)
# xgb_acc = accuracy_score(y_test, y_pred)
# print(xgb_acc)

#
# with open(f'{save_dir}/xgb_model_jsonpickle.json', 'r') as f:
#     xgb_model_jsonpickle = f.read()
# xgb_model_jsonpickle = jsonpickle.decode(xgb_model_jsonpickle)
# y_pred = xgb_model_jsonpickle.predict(xgb_test)
# xgb_acc = accuracy_score(y_test, y_pred)
# print(xgb_acc)

ps:这里给出所有的代码,代码不多,但都写在一起了,比较粗糙,每个实验要记得把其他的对应代码注释掉。

六、总结

以上实验都是几次实验运行的结果的平均,如果想更有说服力,可以更多次实验取平均值来参考,整体的结果基本上没有差异。(还可以从更大的模型入手来讨论)

1. 对于图省事,并且想跨平台语言的话可以选择picklejson,但一定要有一定的memory预估,如果模型比较复杂比较大(可能一个模型class包含多种其他模型的对象),会占用非常大的memory,且模型文件也会非常大,但不需要对于每个单独的子模型做序列化,直接decode即可。

2. 对于要求省空间且运行内存的话,可以选择模型自身的保存方式(主要只保存模型参数文件),但对于这种方式,可能需要在模型的总class去实现序列化和反序列化方法(子模型都要实现,且每个都调用该模型的savemodel和loadmodel方法)

3. python下不考虑跨平台语言序列化和反序列可以直接考虑pickle的序列化方式,也比较省事。

推荐阅读:

我的2022届互联网校招分享

我的2021总结

浅谈算法岗和开发岗的区别

互联网校招研发薪资汇总
2022届互联网求职现状,金9银10快变成铜9铁10!!

公众号:AI蜗牛车

保持谦逊、保持自律、保持进步

发送【蜗牛】获取一份《手把手AI项目》(AI蜗牛车著)
发送【1222】获取一份不错的leetcode刷题笔记

发送【AI四大名著】获取四本经典AI电子书

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

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

相关文章

「车型分析」移动机器人控制系统典型应用车型 ——叉式移动机器人(AGV/AMR)

叉式移动机器人(AGV/AMR)是一种常见的移动机器人类型,它摆脱传统的人车操作,自动导航行驶,具有强大的柔性和智能性。叉式移动机器人(AGV/AMR)不同于传统叉车,它无需人工驾驶运行。具…

Spring纯注解开发模式让开发简化更简化

目录 一.注解开发二.注解定义Bean三.衍生注解四.纯注解开发模式五.注解实现注入 1.自动装配2.按名称注入3.简单数据注入4.读取properties配置文件六.Spring整合MyBatis 一.注解开发 以前跟老韩学习SE时他就说: 注解本质是一个继承了Annotation 的特殊接口,其具体…

龙华商业中心片区旧改:总建面161万平,分5个片区进行建设。

龙华商业旧改:总建面约161万平分5个片区进行建设 据了解,整个龙华商业旧改整体包含北、中、东、南一、南二五个片区,各个片区均整体实施。 更新单元南一片区项目(金地宸峯府),拆除用地面积30836.8平方米&…

前4月同比增长超50%,这条座舱智能化赛道国产化率逼近50%

车市行情的低迷,并没有影响智能化人机交互功能的需求增长。 根据高工智能汽车研究院监测数据显示,2023年1-4月中国市场(不含进出口)乘用车标配HUD(W/AR)搭载交付55.36万辆,同比增长54.98%&…

附录2-小程序常用API

API有三大类,事件监听API,同步API,异步API 事件监听API都以on开头,比如wx.onWindowResize()监听窗口尺寸变化事件 同步API都以Sync结尾,同步API可以通过函数返回值直接获取,执行出错会抛出异常。比如 wx.…

健康管理系统开发笔记

健康管理系统 项目介绍功能架构项目结构maven项目搭建 项目介绍 健康管理系统是一款应用于健康管理机构的业务系统,实现健康管理机构工作内容 可视化、会员管理专业化、健康评估数字化、健康干预流程化、知识库集成化,从而提 高健康管理师的工作效率&a…

12.页面导航

页面导航 是 页面之间的相互跳转,我们在浏览器中可以使用 a链接 与 location.href 进行跳转 在小程序中可以使用 声明式导航(navigator标签,类似于a标签) 与 编程式导航(使用小程序导航API,类似于location.href) 来跳转页面 目录 1 声明式…

软考A计划-电子商务设计师-电商设计师重点

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分享&am…

VS2019社区版和QT安装记录

下载 VS2019: Visual Studio 2019 版本 16.11 发行说明 | Microsoft Learnhttps://learn.microsoft.com/zh-cn/visualstudio/releases/2019/release-notes选择第一个,下载社区版。或者这里下载。 比较简单的方式就是直接打开,网络安装。但微…

camunda如何清理或归档历史数据

一、camunda如何清理历史数据 Camunda 提供了多种方式可以清理历史数据。以下是一些常见的方式: 1、使用 HistoryService#deleteHistoricProcessInstance 方法:该方法用于删除指定的历史流程实例以及与之关联的所有历史数据,包括历史任务、…

【微波实验1】 T形波导的内场分析及优化设计

实验目的 熟悉并掌握HFSS的工作界面、操作步骤及工作流程。掌握T型波导功分器的设计方法、优化设计方法和工作原理。 实验仪器 1、 装有windows 系统的PC 一台 2、 HFSS15.0 或更高版本软件 实验原理 本实验所要分析的器件是下图所示的一个带有隔片的T形波导。其中&#…

SpringBoot 设置动态定时任务,千万别再写死了~

怎么在SpringBoot项目中简单使用定时任务,不过由于要借助cron表达式且都提前定义好放在配置文件里,不能在项目运行中动态修改任务执行时间,实在不太灵活。 经过网上搜索学习后,特此记录如何在SpringBoot项目中实现动态定时任务。…

MySQL查询序号带小数点问题

案例: SELECT (num:num1) AS index, name, age FROM sys_user, (SELECT num:0) AS a order by age,name; 查询结果: datagrip和dbeaver查询结果不一样,使用cmd查询,默认也是无小数点的 但实际返回结果,其实是带点的 D…

CocosCreator制作地图外物品位置向导(指引/地图标点)

演示 图解 code goldTips:指引节点,更改位置使用 goldTipRotate:指引节点的子节点中具有指向性的节点,一般为带箭头,尖角等。 protected lateUpdate(dt: number): void {//可以不在lateUpdate中操作,…

【020】C++的动态内存申请new和delete

C的动态内存申请new和delete 引言一、动态分配内存的概述二、静态分配和动态分配三、new和delete3.1、new和delete操作基本类型空间3.2、new和delete操作数组空间 四、new和delete的重载五、动态分配内存的优缺点总结 引言 💡 作者简介:专注于C/C高性能程…

【算法系列 | 2】深入解析排序算法之插入排序

序言 你只管努力,其他交给时间,时间会证明一切。 文章标记颜色说明: 黄色:重要标题红色:用来标记结论绿色:用来标记一级论点蓝色:用来标记二级论点 决定开一个算法专栏,希望能帮助大…

看这篇文章能让你健康多活若干年

这个世界值得你多活几十年,即便你对现在的生活不满意,你也会对几十年后的生活倾慕不已。 毕竟: 到2029年,区块链就出来第二十年了,Web3会让我们生活得更容易。 到2042年,chatGPT就出来第二十年了&#xff0…

SpringCloudAlibaba

Spring Cloud Alibaba 是 Spring Cloud 的一个子项目,它是由阿里巴巴开发的一套微服务解决方案,旨在为微服务架构提供一站式解决方案,包括服务注册与发现、配置中心、消息总线、负载均衡、熔断器、限流器、分布式事务等组件。 Spring Cloud A…

阿里、字节大佬共创的Netty核心原理手册,必须是全网No.1

讲到这里,你可能要问了:如果我的工作中涉及网络编程的内容并不多,那我是否还有必要花精力学习 Netty 呢?其实在互联网大厂(阿里、腾讯、美团等)的中高级 Java 开发面试中,经常会问到涉及到 Nett…

将一个数组分为多个数组按其元素总数尽量均分的numpy.array_split()方法

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将一个数组s分为多个数组 按s中元素总数尽量均分 numpy.array_split() [太阳]选择题 关于以下代码说法错误的一项是? import numpy as np a np.array([1,2,3,4]) print("【显示】a &quo…