您的位置:

python中lightgbm(Python 中)

本文目录一览:

lightgbm怎么导入到python

Numpy是Python的一个科学计算的库,提供了矩阵运算的功能,一般与Scipy、matplotlib一起使用。导入numpy的范例如下:import numpy as npprint np.version.version1.6.2

LightGBM 如何确定最佳迭代次数?

LightGBM中实现了哪些梯度增强方法,它们有什么区别?一般来说,哪些参数是重要的?哪些正则化参数需要调整?如何调整lightGBM参数在python?梯度提升的方法

使用LightGBM,你可以运行不同类型的渐变增强提升方法。你有:GBDT、DART和GOSS,这些可以通过“boosting”参数指定。

在下一节中,我将对这些方法进行解释和比较。

梯度提升决策树(GBDT)

该方法是本文首先提出的传统梯度提升决策树,也是XGBoost和pGBRT等优秀库背后的算法。

由于其精度高、效率高、稳定性好,目前已得到广泛的应用。你可能知道gbdt是一个决策树的集合模型但是它到底是什么意思呢?

让我来告诉你要点。

它基于三个重要原则:

弱学习者(决策树)梯度优化提升技术所以在gbdt方法中,我们有很多决策树(弱学习者)。这些树是按顺序构建的:

首先,树学习如何适应目标变量第二棵树学习如何适合残差(差异)之间的预测,第一棵树和地面真相第三棵树学习如何匹配第二棵树的残差,以此类推。所有这些树都是通过传播整个系统的误差梯度来训练的。

gbdt的主要缺点是,在每个树节点中找到最佳分割点非常耗时,而且会消耗内存。其他的提升方法试图解决这个问题。

DART梯度提升

在这篇优秀的论文中(arxiv/1505.01866),你可以学习所有关于DART梯度提升的东西,这是一种使用dropout(神经网络中的标准)的方法,来改进模型正则化和处理一些其他不太明显的问题。

也就是说,gbdt存在过度专门化(over-specialization)的问题,这意味着在以后的迭代中添加的树往往只会影响对少数实例的预测,而对其余实例的贡献则可以忽略不计。添加dropout会使树在以后的迭代中更加难以专门化那些少数的示例,从而提高性能。

lgbm goss基于梯度的单边采样

事实上,将该方法命名为lightgbm的最重要原因就是使用了基于本文的Goss方法。Goss是较新的、较轻的gbdt实现(因此是“light”gbm)。

标准的gbdt是可靠的,但在大型数据集上速度不够快。因此goss提出了一种基于梯度的采样方法来避免搜索整个搜索空间。我们知道,对于每个数据实例,当梯度很小时,这意味着不用担心数据是经过良好训练的,而当梯度很大时,应该重新训练。这里我们有两个方面,数据实例有大的和小的渐变。因此,goss以一个大的梯度保存所有数据,并对一个小梯度的数据进行随机抽样(这就是为什么它被称为单边抽样)。这使得搜索空间更小,goss的收敛速度更快。

让我们把这些差异放在一个表格中:

注意:如果你将增强设置为RF,那么lightgbm算法表现为随机森林而不是增强树! 根据文档,要使用RF,必须使用baggingfraction和featurefraction小于1。

正则化

在这一节中,我将介绍lightgbm的一些重要的正则化参数。显然,这些是您需要调优以防止过拟合的参数。

您应该知道,对于较小的数据集(10000条记录),lightGBM可能不是最佳选择。在这里,调优lightgbm参数可能没有帮助。

此外,lightgbm使用叶向树生长算法,而xgboost使用深度树生长算法。叶向方法使树的收敛速度更快,但过拟合的几率增加。

注意:如果有人问您LightGBM和XGBoost之间的主要区别是什么?你可以很容易地说,它们的区别在于它们是如何实现的。

根据lightGBM文档,当面临过拟合时,您可能需要做以下参数调优:

使用更小的max_bin使用更小的num_leaves使用mindatainleaf和minsumhessianin_leaf通过设置baggingfraction和baggingfreq使用bagging_freq通过设置feature_fraction使用特征子采样使用更大的训练数据尝试lambdal1、lambdal2和mingainto_split进行正则化尝试max_depth以避免树的深度增长在下面的部分中,我将更详细地解释这些参数。

lambda_l1

Lambdal1(和lambdal2)控制l1/l2,以及mingainto_split用于防止过拟合。我强烈建议您使用参数调优(在后面的小节中讨论)来确定这些参数的最佳值。

num_leaves

numleaves无疑是控制模型复杂性的最重要参数之一。通过它,您可以设置每个弱学习者拥有的叶子的最大数量。较大的numleaves增加了训练集的精确度,也增加了因过度拟合而受伤的几率。根据文档,一个简单的方法是numleaves = 2^(maxdepth)但是,考虑到在lightgbm中叶状树比层次树更深,你需要小心过度拟合!因此,必须同时使用maxdepth调优numleaves。

子采样

通过子样例(或bagging_fraction),您可以指定每个树构建迭代使用的行数百分比。这意味着将随机选择一些行来匹配每个学习者(树)。这不仅提高了泛化能力,也提高了训练速度。

我建议对基线模型使用更小的子样本值,然后在完成其他实验(不同的特征选择,不同的树结构)时增加这个值。

feature_fraction

特征分数或子特征处理列采样,LightGBM将在每次迭代(树)上随机选择特征子集。例如,如果将其设置为0.6,LightGBM将在训练每棵树之前选择60%的特性。

这个功能有两种用法:

可以用来加速训练吗可以用来处理过拟合吗

max_depth

该参数控制每棵经过训练的树的最大深度,将对:

num_leaves参数的最佳值模型的性能训练时间注意,如果您使用较大的max_depth值,那么您的模型可能会对于训练集过拟合。

max_bin

装箱是一种用离散视图(直方图)表示数据的技术。Lightgbm在创建弱学习者时,使用基于直方图的算法来寻找最优分割点。因此,每个连续的数字特性(例如视频的视图数)应该被分割成离散的容器。

此外,在这个GitHub repo(huanzhang12/lightgbm-gpu)中,你可以找到一些全面的实验,完全解释了改变max_bin对CPU和GPU的影响。

如果你定义maxbin 255,这意味着我们可以有255个唯一的值每个特性。那么,较小的maxbin会导致更快的速度,较大的值会提高准确性。

训练参数

当你想用lightgbm训练你的模型时,一些典型的问题可能会出现:

训练是一个耗时的过程处理计算复杂度(CPU/GPU RAM约束)处理分类特征拥有不平衡的数据集定制度量的需要需要对分类或回归问题进行的调整在本节中,我们将尝试详细解释这些要点。

num_iterations

Num_iterations指定增强迭代的次数(要构建的树)。你建立的树越多,你的模型就越精确,代价是:

较长的训练时间过拟合的可能性更高从较少的树开始构建基线,然后当您想从模型中挤出最后的%时增加基线。

建议使用更小的learningrate和更大的numiteration。此外,如果您想要更高的numiteration,那么您应该使用earlystopping_rounds,以便在无法学习任何有用的内容时停止训练。

earlystoppingrounds

如果验证度量在最后一轮停止后没有改进,此参数将停止训练。这应该与一些迭代成对地进行定义。如果你把它设置得太大,你就增加了过拟合的变化(但你的模型可以更好)。

经验法则是让它占num_iterations的10%。

lightgbm categorical_feature

使用lightgbm的优势之一是它可以很好地处理分类特性。是的,这个算法非常强大,但是你必须小心如何使用它的参数。lightgbm使用一种特殊的整数编码方法(由Fisher提出)来处理分类特征

实验表明,该方法比常用的单热编码方法具有更好的性能。

它的默认值是“auto”,意思是:让lightgbm决定哪个表示lightgbm将推断哪些特性是绝对的。

它并不总是工作得很好,我强烈建议您简单地用这段代码手动设置分类特性

cat_col = dataset_name.select_dtypes(‘object’).columns.tolist()

但是在幕后发生了什么,lightgbm是如何处理分类特征的呢?

根据lightgbm的文档,我们知道树学习器不能很好地使用一种热编码方法,因为它们在树中深度生长。在提出的替代方法中,树形学习器被最优构造。例如,一个特征有k个不同的类别,有2^(k-1) -1个可能的划分,通过fisher方法,可以改进到k * log(k),通过找到分类特征中值排序直方图的最佳分割方式。

isunbalance vs scalepos_weight

其中一个问题,你可能面临的二分类问题是如何处理不平衡的数据集。显然,您需要平衡正/负样本,但如何在lightgbm中做到这一点呢?

lightgbm中有两个参数允许你处理这个问题,那就是isunbalance和scalepos_weight,但是它们之间有什么区别呢?

当您设置Is_unbalace: True时,算法将尝试自动平衡占主导地位的标签的权重(使用列集中的pos/neg分数)

如果您想改变scaleposweight(默认情况下是1,这意味着假设正负标签都是相等的),在不平衡数据集的情况下,您可以使用以下公式来正确地设置它

sample_pos_weight = number of negative samples / number of positive samples

lgbm函数宏指令(feaval)

有时你想定义一个自定义评估函数来测量你的模型的性能,你需要创建一个“feval”函数。

Feval函数应该接受两个参数:

preds 、train_data

并返回

evalname、evalresult、ishigherbetter

让我们一步一步地创建一个自定义度量函数。

定义一个单独的python函数

def feval_func(preds, train_data): # Define a formula that evaluates the results return ('feval_func_name', eval_result, False)

使用这个函数作为参数:

print('Start training...') lgb_train = lgb.train(..., metric=None, feval=feval_func)

注意:要使用feval函数代替度量,您应该设置度量参数 metric “None”。

分类参数与回归参数

我之前提到的大多数事情对于分类和回归都是正确的,但是有些事情需要调整。

具体你应该:

lightgbm最重要的参数

我们已经在前面的部分中回顾并了解了有关lightgbm参数的知识,但是如果不提及Laurae令人难以置信的基准测试,那么关于增强树的文章将是不完整的。

您可以了解用于lightGBM和XGBoost的许多问题的最佳默认参数。

你可以查看这里,但一些最重要的结论是:

注意:绝对不要理会任何参数值的默认值,并根据您的问题进行调整。 也就是说,这些参数是超参数调整算法的一个很好的起点。

Python中的Lightgbm参数调整示例

最后,在解释完所有重要参数之后,该进行一些实验了!

我将使用最受欢迎的Kaggle竞赛之一:Santander Customer Transaction Prediction. 交易预测

我将使用本文介绍如何在任何脚本中的Python中运行超参数调整。

在开始之前,一个重要的问题! 我们应该调整哪些参数?

请注意您要解决的问题,例如,Santander 数据集高度不平衡,在调整时应考虑到这一点!

一些参数是相互依赖的,必须一起调整。 例如,mindatainleaf取决于训练样本和numleaves的数量。

注意:为超参数创建两个字典是一个好主意,一个字典包含您不想调整的参数和值,另一个字典包含您想要调整的参数和值范围。

SEARCH_PARAMS = {'learning_rate': 0.4, 'max_depth': 15, 'num_leaves': 20, 'feature_fraction': 0.8, 'subsample': 0.2} FIXED_PARAMS={'objective': 'binary', 'metric': 'auc', 'is_unbalance':True, 'boosting':'gbdt', 'num_boost_round':300, 'early_stopping_rounds':30}

lightgbm算法的python实现是哪一年提出的

那是当然。python是一个通用语言。这一点难不倒它。除非算法是依赖特定的软硬件环境。否则全部都可以实现。现在大部分算法都集中在大数据与人工智能了。基础的算法基本上没有多少人研究了。python在大数据与人工智能上支撑的库很多。游刃有余。最近在研究语义学习的算法,用python来实现非常快。通常新算法先用python来写,验证完成后再转换成其它的语言。

如何看待微软新开源的LightGBM

作者:柯国霖

链接:

来源:知乎

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

10/19/2017 更新:

完整的更新列表可以参考: Microsoft/LightGBM/Key-Events.md

下面列出一些比较大的更新

R-package 已完成

缺失值(missing value)的自动处理

类别特征(Categorical Feature) 的进一步优化,不再使用类似one-hot coding的分割方式。对于类别数量很多的类别特征,使用one-vs-other的切分方式会长出很不平衡的树,不能实现较好的精度。这是树模型在支持类别特征的一个痛点。 LightGBM可以找出类别特征的最优切割,即many-vs-many的切分方式。并且最优分割的查找的时间复杂度可以在线性时间完成,和原来的one-vs-other的复杂度几乎一致。

cf: NIPS 2017 有什么值得关注的亮点?

12/17/2016 更新:

完成了python-package,欢迎使用。

直接支持类别特征(Categorical Feature),不需要进行0/1展开。相对0/1展开的解决方案,速度快非常多,且精度一致。

大多数机器学习工具都无法直接支持类别特征作为输入,一般需要转换成多维0/1特征,带来计算和内存上的额外消耗。LightGBM增加了针对于类别特征的决策规则,这在决策树上也很好实现。主要的思想是,在对类别特征计算分割增益的时候,不是按照数值特征那样由一个阈值进行切分,而是直接把其中一个类别当成一类,其他的类别当成另一类。这实际上与0/1展开的效果是一样的。

---------------------------------------

正好开源了一个月,强答一下。

GBDT 虽然是个强力的模型,但却有着一个致命的缺陷,不能用类似 mini batch 的方式来训练,需要对数据进行无数次的遍历。如果想要速度,就需要把数据都预加载在内存中,但这样数据就会受限于内存的大小;如果想要训练更多的数据,就要使用外存版本的决策树算法。虽然外存算法也有较多优化,SSD 也在普及,但在频繁的 IO 下,速度还是比较慢的。

为了能让 GBDT 高效地用上更多的数据,我们把思路转向了分布式 GBDT, 然后就有了 LightGBM。设计的思路主要是两点,1. 单个机器在不牺牲速度的情况下,尽可能多地用上更多的数据;2.

多机并行的时候,通信的代价尽可能地低,并且在计算上可以做到线性加速。

基于这两个需求,LightGBM 选择了基于 histogram 的决策树算法。相比于另一个主流的算法 pre-sorted(如 xgboost 中的 exact 算法),histogram 在内存消耗和计算代价上都有不少优势。

Pre-sorted 算法需要的内存约是训练数据的两倍(2 * #data * #features

* 4Bytes),它需要用32位浮点来保存 feature value,并且对每一列特征,都需要一个额外的排好序的索引,这也需要32位的存储空间。对于 histogram 算法,则只需要(#data

* #features * 1Bytes)的内存消耗,仅为 pre-sorted算法的1/8。因为 histogram 算法仅需要存储 feature

bin value (离散化后的数值),不需要原始的 feature value,也不用排序,而 bin

value 用 uint8_t (256

bins) 的类型一般也就足够了。

在计算上的优势则主要体现在“数据分割”。决策树算法有两个主要操作组成,一个是“寻找分割点”,另一个是“数据分割”。从算法时间复杂度来看,Histogram 算法和 pre-sorted 算法在“寻找分割点”的代价是一样的,都是O(#feature*#data)。而在“数据分割”时,pre-sorted 算法需要O(#feature*#data),而 histogram 算法是O(#data)。因为 pre-sorted 算法的每一列特征的顺序都不一样,分割的时候需要对每个特征单独进行一次分割。Histogram算法不需要排序,所有特征共享同一个索引表,分割的时候仅需对这个索引表操作一次就可以。(更新: 这一点不完全正确,pre-sorted 与 level-wise 结合的时候,其实可以共用一个索引表(row_idx_to_tree_node_idx)。然后在寻找分割点的时候,同时操作同一层的节点,省去分割的步骤。但这样做的问题是会有非常多随机访问,有很大的chche miss,速度依然很慢。)。

另一个计算上的优势则是大幅减少了计算分割点增益的次数。对于一个特征,pre-sorted 需要对每一个不同特征值都计算一次分割增益,而 histogram 只需要计算 #bin (histogram 的横轴的数量) 次。

最后,在数据并行的时候,用 histgoram 可以大幅降低通信代价。用 pre-sorted 算法的话,通信代价是非常大的(几乎是没办法用的)。所以 xgoobst 在并行的时候也使用 histogram 进行通信。

当然, histogram 算法也有缺点,它不能找到很精确的分割点,训练误差没有 pre-sorted 好。但从实验结果来看, histogram 算法在测试集的误差和 pre-sorted 算法差异并不是很大,甚至有时候效果更好。实际上可能决策树对于分割点的精确程度并不太敏感,而且较“粗”的分割点也自带正则化的效果。

在 histogram 算法之上, LightGBM 进行进一步的优化。首先它抛弃了大多数 GBDT 工具使用的按层生长

(level-wise) 的决策树生长策略,而使用了带有深度限制的按叶子生长 (leaf-wise) 算法。 level-wise 过一次数据可以同时分裂同一层的叶子,容易进行多线程优化,不容易过拟合。但实际上level-wise是一种低效的算法,因为它不加区分的对待同一层的叶子,带来了很多没必要的开销。因为实际上很多叶子的分裂增益较低,没必要进行搜索和分裂。leaf-wise则是一种更为高效的策略,每次从当前所有叶子中,找到分裂增益最大(一般也是数据量最大)的一个叶子,然后分裂,如此循环。因此同 level-wise 相比,在分裂次数相同的情况下,leaf-wise 可以降低更多的误差,得到更好的精度。leaf-wise 的缺点是可能会长出比较深的决策树,产生过拟合。因此 LightGBM 在leaf-wise 之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合。

另一个比较巧妙的优化是 histogram 做差加速。一个容易观察到的现象:一个叶子的直方图可以由它的父亲节点的直方图与它兄弟的直方图做差得到。通常构造直方图,需要遍历该叶子上的所有数据,但直方图做差仅需遍历直方图的 k 个桶。利用这个方法,LightGBM 可以在构造一个叶子的直方图后,可以用非常微小的代价得到它兄弟叶子的直方图,在速度上可以提升一倍。

如需要更多的细节,可以参考github上的文档:

比XGBOOST更快--LightGBM介绍

xgboost的出现,让数据民工们告别了传统的机器学习算法们:RF、GBM、SVM、LASSO........。现在,微软推出了一个新的boosting框架,想要挑战xgboost的江湖地位。笔者尝试了一下,下面请看来自第一线的报告。

包含以下几个部分:

一. 基本介绍

二.  XGBOOST原理及缺点

三. LightGBM的优化

四. 建模过程(python)

五. 调参

一. 基本介绍

LightGBM 是一个梯度 boosting 框架,使用基于学习算法的决策树。它可以说是分布式的,高效的,它有以下优势:

- 更快的训练效率

- 低内存使用

- 更好的准确率

- 支持并行学习

- 可处理大规模数据

与常用的机器学习算法进行比较:

· 速度飞起

二.  XGBOOST原理及缺点

1. 原理

1 ) 有监督学习

有监督学习的目标函数是下面这个东东:

其中,第一项称为误差函数,常见的误差函数有平方误差,logistic误差等等,第二项称为正则项,常见的有L1正则和L2正则,神经网络里面的dropout等等

2)Boosted Tree

i)基学习器:分类树和回归树(CART)

ii ) Tree Ensemble

一个CART往往过于简单无法有效地预测,因此一个更加强力的模型叫做tree ensemble。

简而言之,Boosted Tree 就是一种 Tree Ensemble的方法,和RF一样,只是构造(学习)模型参数的方法不同。

iii)模型学习:additive training

每一次保留原来的模型不变,加入一个新的函数f到我们的模型中。

f 的选择标准---最小化目标函数!

通过二阶泰勒展开,以及(中间省略N步),我们得到了最终的目标函数:

G、H:与数据点在误差函数上的一阶、二阶导数有关,T:叶子的个数

iv ) 枚举所有不同树结构的贪心算法

不断地枚举不同树的结构,根据目标函数来寻找出一个最优结构的树,加入到我们的模型中,再重复这样的操作。不过枚举所有树结构这个操作不太可行,所以常用的方法是贪心法,每一次尝试去对已有的叶子加入一个分割。对于一个具体的分割方案,我们可以获得的增益可以由如下公式计算。

对于每次扩展,我们还是要枚举所有可能的分割方案,如何高效地枚举所有的分割呢?我假设我们要枚举所有 x

我们可以发现对于所有的a,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和GL和GR。然后用上面的公式计算每个分割方案的分数就可以了。

详细的内容可以看陈天奇大神的文章【3】

2. 缺点

-- 在每一次迭代的时候,都需要遍历整个训练数据多次。如果把整个训练数据装进内存则会限制训练数据的大小;如果不装进内存,反复地读写训练数据又会消耗非常大的时间。

-- 预排序方法(pre-sorted):

首先,空间消耗大。这样的算法需要保存数据的特征值,还保存了特征排序的结果(例如排序后的索引,为了后续快速的计算分割点),这里需要消耗训练数据两倍的内存。

其次,时间上也有较大的开销,在遍历每一个分割点的时候,都需要进行分裂增益的计算,消耗的代价大。

最后,对cache优化不友好。在预排序后,特征对梯度的访问是一种随机访问,并且不同的特征访问的顺序不一样,无法对cache进行优化。同时,在每一层长树的时候,需要随机访问一个行索引到叶子索引的数组,并且不同特征访问的顺序也不一样,也会造成较大的cache miss。

三. LightGBM的优化

基于Histogram的决策树算法

带深度限制的Leaf-wise的叶子生长策略

直方图做差加速

直接支持类别特征(Categorical Feature)

Cache命中率优化

基于直方图的稀疏特征优化

多线程优化

下面主要介绍Histogram算法、带深度限制的Leaf-wise的叶子生长策略。

Histogram算法

直方图算法的基本思想是先把连续的浮点特征值离散化成k个整数,同时构造一个宽度为k的直方图。在遍历数据的时候,根据离散化后的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。

图:直方图算法

带深度限制的Leaf-wise的叶子生长策略

Level-wise过一次数据可以同时分裂同一层的叶子,容易进行多线程优化,也好控制模型复杂度,不容易过拟合。但实际上Level-wise是一种低效的算法,因为它不加区分的对待同一层的叶子,带来了很多没必要的开销,因为实际上很多叶子的分裂增益较低,没必要进行搜索和分裂。

Leaf-wise则是一种更为高效的策略,每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同Level-wise相比,在分裂次数相同的情况下,Leaf-wise可以降低更多的误差,得到更好的精度。Leaf-wise的缺点是可能会长出比较深的决策树,产生过拟合。因此LightGBM在Leaf-wise之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合。

四. 建模过程(python)

数据导入

# 接受:libsvm/tsv/csv 、Numpy 2D array、pandas object(dataframe)、LightGBM binary file

# 需要指定 feature names and categorical features

train_data = lgb.Dataset(dtrain[predictors],label=dtrain[target],feature_name=list(dtrain[predictors].columns), categorical_feature=dummies)

test_data = lgb.Dataset(dtest[predictors],label=dtest[target],feature_name=list(dtest[predictors].columns), categorical_feature=dummies)

设置参数

param = {'max_depth':6,'num_leaves':64,'learning_rate':0.03,'scale_pos_weight':1,'num_threads':40,'objective':'binary','bagging_fraction':0.7,'bagging_freq':1,'min_sum_hessian_in_leaf':100}

param['is_unbalance']='true'

param['metric'] = 'auc'

3. CV

bst=lgb.cv(param,train_data,num_boost_round=1000,nfold=3,early_stopping_rounds=30)

estimators = lgb.train(param,train_data,num_boost_round=len(bst['auc-mean']))

4. 预测

ypred = estimators.predict(dtest[predictors])

四. 实测效果

试了一下90W条记录*130维的样本,num_threads设置为40

时间:

2. 准确率:

五. 调参

1. 使用num_leaves

因为LightGBM使用的是leaf-wise的算法,因此在调节树的复杂程度时,使用的是num_leaves而不是max_depth

大致换算关系:num_leaves = 2^(max_depth)

2.对于非平衡数据集:可以param['is_unbalance']='true’

3. Bagging参数:bagging_fraction+bagging_freq(必须同时设置)、feature_fraction

4. min_data_in_leaf、min_sum_hessian_in_leaf

参考文献

关于LightGBM: ;mid=2650719786idx=3sn=ab1c5a77237dc4b2ee5ae12c7a68ff87chksm=871b0254b06c8b42d5a4fdf3327f7284c9ffbe72fe7911301d368b157024b32923d88401c2a8scene=0open_source=weibo_search

关于XGBOOST:

对数据感兴趣的小伙伴,欢迎交流,微信公共号:一白侃数