你的第一个Python机器学习项目
你想使用Python进行机器学习,但在开始时遇到问题吗?
在这篇文章中,你将使用Python完成你的第一个机器学习项目。
在本分步教程中,你将:
- 下载并安装Python SciPy,获取最有用的Python机器学习包。
- 使用统计摘要和数据可视化加载数据集并了解其结构。
- 创建6个机器学习模型,挑选最好的,并建立准确性可靠的信心。
如果你是机器学习的初学者,并且希望最终开始使用Python,那么本教程就是为你设计的。
我们开始吧!
如何在Python中启动机器学习?
学习机器学习的最好方法是设计和完成小项目。
Python在入门时可能会让人望而生畏。
Python是一种流行且功能强大的解释型语言。与R不同,Python是一种完整的语言和平台,你可以将其用于研发和开发生产系统。
还有很多模块和库可供选择,为每项任务提供了多种方式。它可能会让人感觉不堪重负。
开始使用Python进行机器学习的最佳方式是完成一个项目。
- 它将强制你安装并启动Python解释器(至少)。
- 它会让你鸟瞰如何完成一个小项目。
- 它会给你信心,也许会让你继续做你自己的小项目。
- 初学者需要一个端到端的小项目。
书籍和课程令人沮丧。他们给了你很多食谱和片段,但你永远看不到它们是如何组合在一起的。
当你将机器学习应用于你自己的数据集时,你正在处理一个项目。
机器学习项目可能不是线性的,但它有许多众所周知的步骤:
- 定义问题。
- 准备数据。
- 评估算法。
- 提高成绩。
- 展示结果。
真正与新平台或工具达成协议的最好方法是端到端地完成机器学习项目,并涵盖关键步骤。即从数据加载、数据汇总、算法评估和预测四个方面进行。
如果你能做到这一点,你就有了一个模板,你可以在一个接一个的数据集上使用它。一旦你有了更多的信心,你可以在以后填补空白,例如进一步的数据准备和改进结果任务。
机器学习的“你好,世界”
在一个新工具上开始的最好的小项目是鸢尾花的分类(例如鸢尾数据集)。
这是一个很好的项目,因为它被很好地理解了。
- 属性是数字的,所以你必须弄清楚如何加载和处理数据。
- 这是一个分类问题,允许你使用可能更简单类型的监督学习算法进行练习。
- 这是一个多类别分类问题(多名义),可能需要一些专门的处理。
- 它只有4个属性和150行,这意味着它很小,很容易放入内存(以及一个屏幕或A4页)。
- 所有数字属性都使用相同的单位和相同的比例,不需要任何特殊的缩放或变换即可开始。
让我们开始Python中的hello world机器学习项目。
Python中的机器学习:分步教程
在本节中,我们将端到端地完成一个小型机器学习项目。
以下是我们将要介绍的内容的概述:
- 安装Python和SciPy平台。
- 正在加载数据集。
- 汇总数据集。
- 可视化数据集。
- 对一些算法进行了评测。
- 做一些预测。
花点时间完成每一步。
尝试自己键入命令或复制粘贴命令以加快速度。
如果你有任何问题,请在文章评论区留言。
1.下载、安装并启动Python SciPy
如果尚未在你的系统上安装Python和SciPy平台,请将其安装到你的系统上。
我不想详细报道这一点,因为其他人已经这样做了。这已经相当简单了,特别是如果你是开发人员的话。如果你确实需要帮助,可以在评论中提问。
或者,你可以看这篇文章:如何用Anaconda构建机器学习和深度学习的Python环境
1.1安装SciPy库
本教程假定Python版本为2.7或3.6以上。
你需要安装5个关键库。以下是本教程所需的Python SciPy库的列表:
- scipy
- numpy
- matplotlib
- pandas
- sklearn
安装这些库的方法有很多种。我最好的建议是选择一种方法,然后在安装每个库时保持一致。
Scipy安装页面提供了在多个不同平台(如Linux、MacOSX和Windows)上安装上述库的出色说明。如果你有任何疑问或疑问,请参考本指南,它已经被成千上万的人关注。
- 在MacOSX上,你可以使用Macports安装Python3.6和这些库。有关macports的更多信息,请参见主页。
- 在Linux上,你可以使用包管理器(如Fedora上的yum)安装RPM。
如果你使用的是Windows或者你没有信心,我建议你安装免费版本的Anaconda,它包含了你需要的一切。
注意:本教程假设你已经安装了scikit-learn版本0.20或更高版本。
需要更多帮助吗?请参阅以下教程之一:
1.2启动Python并检查版本
最好确保你的Python环境已成功安装并按预期工作。
下面的脚本将帮助你测试你的环境。它导入本教程中所需的每个库并打印版本。
打开命令行并启动python解释器:
python
我建议直接在解释器中工作,或者编写脚本并在命令行上运行它们,而不是使用大型编辑器和IDE。保持简单,把重点放在机器学习上,而不是工具链上。
键入或复制并粘贴以下脚本:
# Check the versions of libraries # Python version import sys print('Python: {}'.format(sys.version)) # scipy import scipy print('scipy: {}'.format(scipy.__version__)) # numpy import numpy print('numpy: {}'.format(numpy.__version__)) # matplotlib import matplotlib print('matplotlib: {}'.format(matplotlib.__version__)) # pandas import pandas print('pandas: {}'.format(pandas.__version__)) # scikit-learn import sklearn print('sklearn: {}'.format(sklearn.__version__))
以下是我在OS X工作站上获得的输出:
Python: 3.6.9 (default, Oct 19 2019, 05:21:45) [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)] scipy: 1.3.1 numpy: 1.17.3 matplotlib: 3.1.1 pandas: 0.25.1 sklearn: 0.21.3
将上面的输出与你的版本进行比较。
理想情况下,你的版本应该匹配或更新。API变化不快,所以如果你落后几个版本,请不要太担心,本教程中的所有内容很可能仍然适用于你。
如果你收到错误,请停止。现在应该修复它。
如果你不能顺利地运行上面的脚本,你将无法完成本教程。
我最好的建议是在谷歌上搜索你的错误信息,或者在Stack Exchange上发布一个问题。
2.加载数据
我们将使用鸢尾花数据集。这个数据集非常有名,因为几乎每个人都将它用作机器学习和统计中的“hello world”数据集。
该数据集包含150个对鸢尾花的观测。有四列花的尺寸,单位是厘米。第五列是观察到的花的种类。所有观察到的花都属于三种中的一种。
你可以在维基百科上了解更多关于这个数据集的信息。
在此步骤中,我们将从CSV文件URL加载鸢尾数据。
2.1导入库
首先,让我们导入本教程中要使用的所有模块、函数和对象。
# Load libraries from pandas import read_csv from pandas.plotting import scatter_matrix from matplotlib import pyplot from sklearn.model_selection import train_test_split from sklearn.model_selection import cross_val_score from sklearn.model_selection import StratifiedKFold from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.naive_bayes import GaussianNB from sklearn.svm import SVC
所有内容都应该正确加载。如果出现错误,请停止。在继续之前,你需要一个工作的SciPy环境。有关设置环境的信息,请参阅上面的建议。
2.2加载数据集
我们可以直接从UCI机器学习储存库加载数据。
我们正在使用pandas来加载数据。接下来,我们还将使用pandas来探索数据,包括描述性统计和数据可视化。
请注意,我们在加载数据时指定了每列的名称。这将在稍后我们研究数据时提供帮助。
# Load dataset url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names)
数据集加载时应不会出现意外情况。
如果你确实有网络问题,可以将iris.csv文件下载到你的工作目录中,并使用相同的方法加载它,将URL更改为本地文件名。
3.汇总数据集
现在是时候来看看数据了。
在本步骤中,我们将通过几种不同的方式查看数据:
- 数据集的维度。
- 看看数据本身。
- 所有属性的统计汇总。
- 按类变量细分数据。
别担心,每次查看数据都是一个命令。这些命令非常有用,你可以在将来的项目中反复使用。
3.1数据集的维度
通过Shape属性,我们可以快速了解数据包含多少个实例(行)和多少个属性(列)。
# shape print(dataset.shape)
你应该会看到150个实例和5个属性:
(150, 5)
3.2查看数据
实际查看你的数据也总是一个好主意。
# head print(dataset.head(20))
你应该会看到数据的前20行:
sepal-length sepal-width petal-length petal-width class 0 5.1 3.5 1.4 0.2 Iris-setosa 1 4.9 3.0 1.4 0.2 Iris-setosa 2 4.7 3.2 1.3 0.2 Iris-setosa 3 4.6 3.1 1.5 0.2 Iris-setosa 4 5.0 3.6 1.4 0.2 Iris-setosa 5 5.4 3.9 1.7 0.4 Iris-setosa 6 4.6 3.4 1.4 0.3 Iris-setosa 7 5.0 3.4 1.5 0.2 Iris-setosa 8 4.4 2.9 1.4 0.2 Iris-setosa 9 4.9 3.1 1.5 0.1 Iris-setosa 10 5.4 3.7 1.5 0.2 Iris-setosa 11 4.8 3.4 1.6 0.2 Iris-setosa 12 4.8 3.0 1.4 0.1 Iris-setosa 13 4.3 3.0 1.1 0.1 Iris-setosa 14 5.8 4.0 1.2 0.2 Iris-setosa 15 5.7 4.4 1.5 0.4 Iris-setosa 16 5.4 3.9 1.3 0.4 Iris-setosa 17 5.1 3.5 1.4 0.3 Iris-setosa 18 5.7 3.8 1.7 0.3 Iris-setosa 19 5.1 3.8 1.5 0.3 Iris-setosa
3.3统计汇总
现在我们可以看一下每个属性的摘要。
这包括计数、平均值、最小值和最大值以及一些百分位数。
# descriptions print(dataset.describe())
我们可以看到,所有数值都具有相同的刻度(厘米)和0到8厘米之间的相似范围。
sepal-length sepal-width petal-length petal-width count 150.000000 150.000000 150.000000 150.000000 mean 5.843333 3.054000 3.758667 1.198667 std 0.828066 0.433594 1.764420 0.763161 min 4.300000 2.000000 1.000000 0.100000 25% 5.100000 2.800000 1.600000 0.300000 50% 5.800000 3.000000 4.350000 1.300000 75% 6.400000 3.300000 5.100000 1.800000 max 7.900000 4.400000 6.900000 2.500000
3.4类分布
现在让我们看一下属于每个类的实例(行)的数量。我们可以把这看作是绝对的统计。
# class distribution print(dataset.groupby('class').size())
我们可以看到,每个类都有相同数量的实例(占数据集的50%或33%)。
class Iris-setosa 50 Iris-versicolor 50 Iris-virginica 50
3.5完整示例
作为参考,我们可以将前面的所有元素绑定到单个脚本中。
下面列出了完整的示例。
# summarize the data from pandas import read_csv # Load dataset url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # shape print(dataset.shape) # head print(dataset.head(20)) # descriptions print(dataset.describe()) # class distribution print(dataset.groupby('class').size())
4.数据可视化
现在我们对数据有了一个基本的了解。我们需要用一些可视化的方式来扩展这一点。
我们将查看两种类型的绘图:
- 单变量曲线图,以更好地理解每个属性。
- 多变量曲线图,以更好地理解属性之间的关系。
4.1单变量曲线图
我们从一些单变量曲线图开始,也就是每个独立变量的曲线图。
假设输入变量是数值变量,我们可以创建每个变量的箱线图。
# box and whisker plots dataset.plot(kind='box', subplots=True, layout=(2,2), sharex=False, sharey=False) pyplot.show()
这使我们对输入属性的分布有了更清晰的了解:
我们还可以创建每个输入变量的直方图,以了解分布情况。
# histograms dataset.hist() pyplot.show()
看起来可能有两个输入变量具有高斯分布。这一点值得注意,因为我们可以使用可以利用此假设的算法。
4.2多元曲线图
现在我们可以看看变量之间的相互作用。
首先,让我们看一下所有属性对的散点图。这有助于发现输入变量之间的结构化关系。
# scatter plot matrix scatter_matrix(dataset) pyplot.show()
请注意某些属性对的对角分组。这表明了一种高度的相关性和一种可预测的关系。
4.3完整示例
作为参考,我们可以将前面的所有元素汇总到单个脚本中。
下面列出了完整的示例。
# visualize the data from pandas import read_csv from pandas.plotting import scatter_matrix from matplotlib import pyplot # Load dataset url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # box and whisker plots dataset.plot(kind='box', subplots=True, layout=(2,2), sharex=False, sharey=False) pyplot.show() # histograms dataset.hist() pyplot.show() # scatter plot matrix scatter_matrix(dataset) pyplot.show()
5.对一些算法进行评估
现在是时候为数据创建一些模型,并在看不见的数据上估计它们的准确性了。
以下是我们在此步骤中要介绍的内容:
- 分离出验证数据集。
- 将测试线束设置为使用10折交叉验证。
- 建立多个不同的模型来根据花的测量来预测物种。
- 选择最佳型号。
5.1创建验证数据集
我们需要知道我们创建的模型是好的。
稍后,我们将使用统计方法来估计我们在看不见的数据上创建的模型的准确性。我们还希望通过对实际未见数据进行评估来更具体地估计最佳模型在未见数据上的准确性。
也就是说,我们将保留一些算法无法看到的数据,我们将使用这些数据来获得第二个独立的想法,即最好的模型实际上可能有多精确。
我们将把加载的数据集分成两部分,其中80%将用于训练、评估和选择我们的模型,20%将保留为验证数据集。
# Split-out validation dataset array = dataset.values X = array[:,0:4] y = array[:,4] X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1)
现在,你在X_train和Y_train中有用于准备模型的训练数据,以及我们稍后可以使用的X_validation和Y_validation集。
请注意,我们使用了Python切片来选择NumPy数组中的列。如果这对你来说是新的,你可能想看看这篇文章:
5.2测试线束
我们将使用分层10-fold交叉验证来估计模型的准确性。
这将把我们的数据集分成10个部分,在9上训练,在1上测试,并对所有的训练-测试分割组合重复。
分层意味着数据集的每个折叠或拆分将旨在具有与整个训练数据集中存在的相同的按类别的示例分布。
有关k-fold交叉验证技术的更多信息,请参阅教程:
我们通过random_state参数将随机种子设置为固定数字,以确保在训练数据集的相同拆分上评估每个算法。
特定的随机种子无关紧要,请在此处了解有关伪随机数生成器的更多信息:
我们正在使用“准确性”的度量来评估模型。
这是正确预测的实例数除以数据集中的实例总数乘以100得出的百分比(例如,95%的准确率)。当我们接下来运行构建和评估每个模型时,我们将使用评分变量。
5.3构建模型
我们不知道哪种算法可以很好地解决这个问题,也不知道应该使用什么配置。
我们从曲线图中得到一个想法,即一些类在某些维度上是部分线性可分的,所以我们期待总体上有好的结果。
让我们测试6种不同的算法:
- 逻辑回归(LR)。
- 线性判别分析(LDA)。
- K-近邻(KNN)。
- 分类和回归树(CART)。
- 高斯朴素贝叶斯(NB)。
- 支持向量机(SVM)。
这是简单线性(LR和LDA)、非线性(KNN、CART、NB和SVM)算法的很好混合。
让我们构建并评估我们的模型:
# Spot Check Algorithms models = [] models.append(('LR', LogisticRegression(solver='liblinear', multi_class='ovr'))) models.append(('LDA', LinearDiscriminantAnalysis())) models.append(('KNN', KNeighborsClassifier())) models.append(('CART', DecisionTreeClassifier())) models.append(('NB', GaussianNB())) models.append(('SVM', SVC(gamma='auto'))) # evaluate each model in turn results = [] names = [] for name, model in models: kfold = StratifiedKFold(n_splits=10, random_state=1, shuffle=True) cv_results = cross_val_score(model, X_train, Y_train, cv=kfold, scoring='accuracy') results.append(cv_results) names.append(name) print('%s: %f (%f)' % (name, cv_results.mean(), cv_results.std()))
5.4选择最佳模型
我们现在有6个模型和每个模型的精确度估计。我们需要将这些模型相互比较,选择最准确的。
运行上面的示例,我们将获得以下原始结果:
LR: 0.960897 (0.052113) LDA: 0.973974 (0.040110) KNN: 0.957191 (0.043263) CART: 0.957191 (0.043263) NB: 0.948858 (0.056322) SVM: 0.983974 (0.032083)
注意,考虑到学习算法的随机性,你的结果可能会有所不同。有关这方面的更多信息,请参见帖子:
你得了几分?
在下面的评论中发布你的结果。
在这种情况下,我们可以看到,支持向量机(SVM)的估计准确率得分最高,约为0.98或98%。
我们还可以创建模型评估结果的曲线图,并比较每个模型的分布和平均精度。由于每个算法都经过了10次评估(通过10次折叠交叉验证),因此每个算法都有一组准确性度量。
比较每个算法的结果样本的一种有用的方法是为每个分布创建一个箱线图,并比较分布。
# Compare Algorithms pyplot.boxplot(results, labels=names) pyplot.title('Algorithm Comparison') pyplot.show()
我们可以看到,箱线图被压在了范围的顶部,许多评估达到了100%的准确率,有些评估下推到了高达80%的准确率。
5.5完整示例
作为参考,我们可以将前面的所有元素汇总到单个脚本中。
下面列出了完整的示例。
# compare algorithms from pandas import read_csv from matplotlib import pyplot from sklearn.model_selection import train_test_split from sklearn.model_selection import cross_val_score from sklearn.model_selection import StratifiedKFold from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.naive_bayes import GaussianNB from sklearn.svm import SVC # Load dataset url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # Split-out validation dataset array = dataset.values X = array[:,0:4] y = array[:,4] X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1, shuffle=True) # Spot Check Algorithms models = [] models.append(('LR', LogisticRegression(solver='liblinear', multi_class='ovr'))) models.append(('LDA', LinearDiscriminantAnalysis())) models.append(('KNN', KNeighborsClassifier())) models.append(('CART', DecisionTreeClassifier())) models.append(('NB', GaussianNB())) models.append(('SVM', SVC(gamma='auto'))) # evaluate each model in turn results = [] names = [] for name, model in models: kfold = StratifiedKFold(n_splits=10, random_state=1) cv_results = cross_val_score(model, X_train, Y_train, cv=kfold, scoring='accuracy') results.append(cv_results) names.append(name) print('%s: %f (%f)' % (name, cv_results.mean(), cv_results.std())) # Compare Algorithms pyplot.boxplot(results, labels=names) pyplot.title('Algorithm Comparison') pyplot.show()
6.作出预测
我们必须选择一种算法来进行预测。
上一节的结果表明,支持向量机可能是最准确的模型。我们将使用这个模型作为我们的最终模型。
现在,我们希望了解验证集上模型的准确性。
这将使我们对最佳模型的准确性进行独立的最终检查。保留验证集非常有价值,以防你在训练过程中出现失误,例如过度适应训练集或数据泄露。这两个问题都会导致过于乐观的结果。
6.1做出预测
我们可以将模型拟合到整个训练数据集上,并对验证数据集进行预测。
# Make predictions on validation dataset model = SVC(gamma='auto') model.fit(X_train, Y_train) predictions = model.predict(X_validation)
你可能还想对单行数据进行预测。有关如何执行此操作的示例,请参阅教程:
你可能还希望将模型保存到文件中,并在以后加载它,以便对新数据进行预测。有关如何执行此操作的示例,请参阅教程:
6.2评估预测
我们可以通过将预测与验证集中的预期结果进行比较来评估预测,然后计算分类准确率,以及混淆矩阵和分类报告。
# Evaluate predictions print(accuracy_score(Y_validation, predictions)) print(confusion_matrix(Y_validation, predictions)) print(classification_report(Y_validation, predictions))
我们可以看到,在保持数据集上的准确率为0.966,约为96%。
混淆矩阵提供了所犯的三个错误的指示。
最后,分类报告按精确度、召回率、F1分数和支持度提供了每个类别的细分,显示了出色的结果(假设验证数据集很小)。
0.9666666666666667 [[11 0 0] [ 0 12 1] [ 0 0 6]] precision recall f1-score support Iris-setosa 1.00 1.00 1.00 11 Iris-versicolor 1.00 0.92 0.96 13 Iris-virginica 0.86 1.00 0.92 6 accuracy 0.97 30 macro avg 0.95 0.97 0.96 30 weighted avg 0.97 0.97 0.97 30
6.3完整示例
作为参考,我们可以将前面的所有元素汇总到单个脚本中。
下面列出了完整的示例。
# make predictions from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score from sklearn.svm import SVC # Load dataset url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # Split-out validation dataset array = dataset.values X = array[:,0:4] y = array[:,4] X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1) # Make predictions on validation dataset model = SVC(gamma='auto') model.fit(X_train, Y_train) predictions = model.predict(X_validation) # Evaluate predictions print(accuracy_score(Y_validation, predictions)) print(confusion_matrix(Y_validation, predictions)) print(classification_report(Y_validation, predictions))
你可以在Python中进行机器学习
完成上面的教程。最多需要5到10分钟!
你不需要了解所有的事情。(至少现在不是)你的目标是端到端地浏览教程并获得结果。你不需要第一遍就什么都懂。边走边把你的问题列出来。大量使用Python中的help(“FunctionName”) 帮助语法来了解你正在使用的所有函数。
你不需要知道算法是如何工作的。了解这些限制以及如何配置机器学习算法非常重要。但是关于算法的学习可以在以后进行。你需要在很长一段时间内慢慢积累此算法知识。今天,我们先从熟悉平台开始。
你不需要是Python程序员。如果你是新手,Python语言的语法可能会很直观。就像其他语言一样,关注函数调用(例如function())和赋值(例如a=“b”)。这会让你走完大半条路。你是一名开发人员,你知道如何快速掌握一门语言的基础知识。只需开始,稍后再深入研究细节即可。
你不需要成为机器学习专家。你稍后可以了解各种算法的优点和局限性,并且有大量的帖子可以供你稍后阅读,以温习机器学习项目的步骤以及使用交叉验证评估准确性的重要性。
机器学习项目中的其他步骤呢?我们没有涵盖机器学习项目中的所有步骤,因为这是你的第一个项目,我们需要将重点放在关键步骤上。也就是说,加载数据、查看数据、评估一些算法并做出一些预测。在后面的教程中,我们可以查看其他数据准备和结果改进任务。
摘要
在这篇文章中,你逐步了解了如何用Python完成你的第一个机器学习项目。
你发现,完成一个从加载数据到进行预测的端到端小项目是熟悉新平台的最佳方式。
你的下一步
你完成教程了吗?
- 完成上面的教程。
- 列出你有任何问题。
- 搜索-寻找或研究答案。
- 请记住,你可以使用Python中的help(“FunctionName”)来获取有关任何函数的帮助。
你有什么问题吗?
把它贴在下面的评论里。