2024年最全机器学习算法(1)—— K-近邻算法_k近邻算法k的取值(1),金九银十怎么从中小企业挤进一线大厂

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

注意:邻居的数量不能大于样本的数量

问:为什么x是二维,y是一维
答:可以这样理解,x是特征值,是dataframe形式,理解为二维的[[]],y表示的目标值,可以表示为series,表示为一维数组[]

在这里插入图片描述

3 距离度量

3.1 基本性质

在这里插入图片描述

3.2 常见距离公式

(1)欧式距离

欧氏距离是最容易直观理解的距离度量方法,我们小学、初中和高中接触到的两个点在空间中的距离一般都是指欧氏距离。
在这里插入图片描述
(2)曼哈顿距离

在曼哈顿街区要从一个十字路口开车到另一个十字路口,驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是“曼哈顿距离”。曼哈顿距离也称为“城市街区距离”(City Block distance)。
在这里插入图片描述
在这里插入图片描述
(3)切比雪夫距离

国际象棋中,国王可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?这个距离就叫切比雪夫距离。
在这里插入图片描述
在这里插入图片描述
(4)闵可夫斯基距离

闵氏距离不是一种距离,而是一组距离的定义,是对多个距离度量公式的概括性的表述。
两个n维变量a(x11,x12,…,x1n)与b(x21,x22,…,x2n)间的闵可夫斯基距离定义为:
在这里插入图片描述
其中p是一个变参数:

  • 当p=1时,就是曼哈顿距离;
  • 当p=2时,就是欧氏距离;
  • 当p→∞时,就是切比雪夫距离。

根据p的不同,闵氏距离可以表示某一类/种的距离。

二维样本(身高[单位:cm],体重[单位:kg]),现有三个样本:a(180,50),b(190,50),c(180,60)。a与b的闵氏距离(无论是曼哈顿距离、欧氏距离或切比雪夫距离)等于a与c的闵氏距离。但实际上身高的10cm并不能和体重的10kg划等号。

闵氏距离的缺点:

  • 将各个分量的量纲(scale),也就是“单位”相同的看待了;
  • 未考虑各个分量的分布(期望,方差等)可能是不同的。

3.3 距离属性

我们常将属性划分为"连续属性" (continuous attribute)和"离散属性" (categorical attribute),前者在定义域上有无穷多个可能的取值,后者在定义域上是有限个取值.

  • 若属性值之间存在序关系,则可以将其转化为连续值,例如:身高属性“高”“中等”“矮”,可转化为{1, 0.5, 0}。
    • 闵可夫斯基距离可以用于有序属性。
  • 若属性值之间不存在序关系,则通常将其转化为向量的形式,例如:性别属性“男”“女”,可转化为{(1,0),(0,1)}。

4 k值选择

  • 近似误差:
    • 对现有训练集的训练误差,关注训练集
    • 如果近似误差过小可能会出现过拟合的现象,对现有的训练集能有很好的预测,但是对未知的测试样本将会出现较大偏差的预测,模型本身不是最接近最佳模型。
  • 估计误差:
    • 可以理解为对测试集的测试误差,关注测试集
    • 估计误差小说明对未知数据的预测能力好,模型本身最接近最佳模型。
  1. 选择较小的K值,就相当于用较小的领域中的训练实例进行预测,“学习”近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习”的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
  2. 选择较大的K值,就相当于用较大领域中的训练实例进行预测,
    其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误。且K值的增大就意味着整体的模型变得简单。
  3. K=N(N为训练样本个数),则完全不足取,因为此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单,忽略了训练实例中大量有用信息。

在实际应用中,K值一般取一个比较小的数值,例如采用交叉验证法(简单来说,就是把训练数据再分成两组:训练集和验证集)来选择最优的K值。

由此可得,KNN中K值大小选择对模型的影响:

  • K值过小:
    • 容易受到异常点的影响
    • 容易过拟合
  • K值过大:
    • 受到样本均衡的问题
    • 容易欠拟合

5 KNN优化—kd树

实现k近邻算法时,主要考虑的问题是如何对训练数据进行快速k近邻搜索。这在特征空间的维数大及训练数据容量大时尤其必要。

k近邻法最简单的实现是线性扫描(穷举搜索),即要计算输入实例与每一个训练实例的距离。计算并存储好以后,再查找K近邻。当训练集很大时,计算非常耗时。

为了提高KNN搜索的效率,可以考虑使用特殊的结构存储——kd树来训练数据,以减小计算距离的次数。

5.1 kd树简介

根据KNN每次需要预测一个点时,我们都需要计算训练数据集里每个点到这个点的距离,然后选出距离最近的k个点进行投票。当数据集很大时,这个计算成本非常高,针对N个样本,D个特征的数据集,其算法复杂度为O(DN^2​​)

kd树:为了避免每次都重新计算一遍距离,算法会把距离信息保存在一棵树里,这样在计算之前从树里查询距离信息,尽量避免重新计算。其基本原理是,如果A和B距离很远,B和C距离很近,那么A和C的距离也很远。有了这个信息,就可以在合适的时候跳过距离远的点。这样优化后的算法复杂度可降低到O(DNlogN)

在这里插入图片描述

黄色的点作为根节点,上面的点归左子树,下面的点归右子树,接下来再不断地划分,分割的那条线叫做分割超平面(splitting hyperplane),在一维中是一个点,二维中是线,三维的是面。

在这里插入图片描述
类比“二分查找”:给出一组数据:[9 1 4 7 2 5 0 3 8],要查找8。如果挨个查找(线性扫描),那么将会把数据集都遍历一遍。而如果排一下序那数据集就变成了:[0 1 2 3 4 5 6 7 8 9],按前一种方式我们进行了很多没有必要的查找,现在如果我们以5为分界点,那么数据集就被划分为了左右两个“簇” [0 1 2 3 4][6 7 8 9]

因此,根本就没有必要进入第一个簇,可以直接进入第二个簇进行查找。把二分查找中的数据点换成k维数据点,这样的划分就变成了用超平面对k维空间的划分。空间划分就是对数据点进行分类,“挨得近”的数据点就在一个空间里面。

5.2 构造方法

kd树(K-dimension tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。

  1. 构造根结点,使根结点对应于K维空间中包含所有实例点的超矩形区域;
  2. 通过递归的方法,不断地对k维空间进行切分,生成子结点。在超矩形区域上选择一个坐标轴和在此坐标轴上的一个切分点,确定一个超平面,这个超平面通过选定的切分点并垂直于选定的坐标轴,将当前超矩形区域切分为左右两个子区域(子结点);这时,实例被分到两个子区域。
  3. 上述过程直到子区域内没有实例时终止(终止时的结点为叶结点)。在此过程中,将实例保存在相应的结点上。
  4. 通常,循环的选择坐标轴对空间切分,选择训练实例点在坐标轴上的中位数为切分点,这样得到的kd树是平衡的(平衡二叉树:它是一棵空树,或其左子树和右子树的深度之差的绝对值不超过1,且它的左子树和右子树都是平衡二叉树)。

KD树中每个节点是一个向量,和二叉树按照数的大小划分不同的是,KD树每层需要选定向量中的某一维,然后根据这一维按左小右大的方式划分数据。在构建KD树时,关键需要解决2个问题:

  • 选择向量的哪一维进行划分;

    • 解决方法:可以是随机选择某一维或按顺序选择,但是更好的方法应该是在数据比较分散的那一维进行划分(分散的程度可以根据方差来衡量,方差越大越分散图像越矮胖)
  • 如何划分数据;

    • 解决方法:好的划分方法可以使构建的树比较平衡,可以每次选择中位数来进行划分。

5.3 案例分析

(1)树的建立

给定一个二维空间数据集:T={(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构造一个平衡kd树。
在这里插入图片描述

第一维度X:2,4,5,7,8,9 中位数:(5+7)/2=6
第二维度Y:1,2,3,4,6,7
显而易见,在选取根结点时,第一维度X更分散,方差更大,因此选择X维进行划分

根结点对应包含数据集T的矩形,选择X轴,6个数据点的X坐标中位数是6,这里选最接近的(7,2)点,【选择(5,4)也可以】以平面X=7将空间分为左、右两个子矩形(子结点);接着左矩形以Y=4分为两个子矩形【左矩形中{(2,3),(5,4),(4,7)}点的Y坐标中位数正好为4),Y轴的方差更大,选择Y划分】,右矩形以Y=6分为两个子矩形,如此递归,最后得到如下图所示的特征空间划分和kd树。
在这里插入图片描述
(2)最近邻域的搜索

假设标记为星星的点是 test point, 绿色的点是找到的近似点,在回溯过程中,需要用到一个队列,存储需要回溯的点,在判断其他子节点空间中是否有可能有距离查询点更近的数据点时,做法是以查询点为圆心,以当前的最近距离为半径画圆,这个圆称为 候选超球(candidate hypersphere),如果圆与回溯点的轴相交,则需要将轴另一边的节点都放到回溯队列里面来。
在这里插入图片描述
(3)查找点(2.1,3.1)
在这里插入图片描述
在(7,2)点测试到达(5,4),在(5,4)点测试到达(2,3),然后search_path中的结点为<(7,2),(5,4), (2,3)>,从search_path中取出(2,3)作为当前最佳结点nearest, dist为0.141;

然后回溯至(5,4),以(2.1,3.1)为圆心,以dist=0.141为半径画一个圆,并不和超平面y=4相交,如上图,所以不必跳到结点(5,4)的右子空间去搜索,因为右子空间中不可能有更近样本点了。

于是再回溯至(7,2),同理,以(2.1,3.1)为圆心,以dist=0.141为半径画一个圆并不和超平面x=7相交,所以也不用跳到结点(7,2)的右子空间去搜索。

至此,search_path为空,结束整个搜索,返回nearest(2,3)作为(2.1,3.1)的最近邻点,最近距离为0.141。

(4)查找点(2,4.5)
在这里插入图片描述

在(7,2)处测试到达(5,4),在(5,4)处测试到达(4,7)【优先选择在本域搜索】,然后search_path中的结点为<(7,2),(5,4), (4,7)>,从search_path中取出(4,7)作为当前最佳结点nearest, dist为3.202;

然后回溯至(5,4),以(2,4.5)为圆心,以dist=3.202为半径画一个圆与超平面y=4相交,所以需要跳到(5,4)的左子空间去搜索。所以要将(2,3)加入到search_path中,现在search_path中的结点为<(7,2),(2, 3)>;另外,(5,4)与(2,4.5)的距离为3.04 < dist = 3.202,所以将(5,4)赋给nearest,并且dist=3.04。

回溯至(2,3),(2,3)是叶子节点直接判断(2,3)是否离(2,4.5)更近,计算得到距离为1.5,所以nearest更新为(2,3),dist更新为(1.5)

回溯至(7,2),同理,以(2,4.5)为圆心,以dist=1.5为半径画一个圆并不和超平面x=7相交, 所以不用跳到结点(7,2)的右子空间去搜索。

至此,search_path为空,结束整个搜索,返回nearest(2,3)作为(2,4.5)的最近邻点,最近距离为1.5。

kd树的搜索过程

  • 二叉树搜索比较待查询节点和分裂节点的分裂维的值,(小于等于就进入左子树分支,大于就进入右子树分支直到叶子结点)
  • 顺着“搜索路径”找到最近邻的近似点
  • 回溯搜索路径,并判断搜索路径上的结点的其他子结点空间中是否可能有距离查询点更近的数据点,如果有可能,则需要跳到其他子结点空间中去搜索
  • 重复这个过程直到搜索路径为空

6 数据集

6.1 获取数据集

在这里插入图片描述

(1)数据集API介绍

sklearn.datasets加载获取流行数据集

  • datasets.load_*()
    • 获取小规模数据集,数据包含在datasets里,例如:加载并返回鸢尾花数据集sklearn.datasets.load_iris()
  • datasets.fetch_*(data_home=None)
    • 获取大规模数据集,需要从网络上下载,函数的第一个参数是data_home,表示数据集下载的目录,默认是 ~/scikit_learn_data/。例如:sklearn.datasets.fetch_20newsgroups(data_home=None,subset=‘train’),subset:‘train’或者’test’,‘all’,可选,选择要加载的数据集。

(2)数据集返回值介绍

load和fetch返回的数据类型datasets.base.Bunch(字典格式)

  • data:特征数据数组,是 [n_samples * n_features] 的二维 numpy.ndarray 数组
  • target:标签数组,是 n_samples 的一维 numpy.ndarray 数组
  • DESCR:数据描述
  • feature_names:特征名,新闻数据,手写数字、回归数据集没有
  • target_names:标签名
from sklearn.datasets import load_iris
# 获取鸢尾花数据集
iris = load_iris()
print("鸢尾花数据集的返回值:\n", iris)
# 返回值是一个继承自字典的Bench
print("鸢尾花的特征值:\n", iris["data"])
print("鸢尾花的目标值:\n", iris.target)
print("鸢尾花特征的名字:\n", iris.feature_names)
print("鸢尾花目标值的名字:\n", iris.target_names)
print("鸢尾花的描述:\n", iris.DESCR)

6.2 查看数据分布

通过创建一些图,以查看不同类别是如何通过特征来区分的。 在理想情况下,标签类将由一个或多个特征对完美分隔。 在现实世界中,这种理想情况很少会发生。

from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from pylab import mpl
import seaborn as sns
import pandas as pd

# 设置显示中文字体
mpl.rcParams["font.sans-serif"] = ["SimHei"]

iris = load_iris()
iris_data = pd.DataFrame(data=iris.data, columns=['Sepal\_Length', 'Sepal\_Width', 'Petal\_Length', 'Petal\_Width'])
iris_data["Species"] = iris.target


def plot\_iris(iris, feature_1, feature_2):
    sns.lmplot(x=feature_1, y=feature_2, data=iris, hue="Species", fit_reg=False)
    plt.xlabel(feature_1)
    plt.ylabel(feature_2)
    plt.title('鸢尾花种类分布图')
    plt.show()

plot_iris(iris_data, 'Petal\_Width', 'Sepal\_Length')

在这里插入图片描述

6.3 划分数据集

机器学习一般的数据集会划分为两个部分:

  • 训练数据:用于训练,构建模型
  • 测试数据:在模型检验时使用,用于评估模型是否有效

划分比例:

  • 训练集:70% 80% 75%
  • 测试集:30% 20% 25%

sklearn.model_selection.train_test_split(arrays, *options)

  • 参数:
    • x 数据集的特征值
    • y 数据集的标签值
    • test_size 测试集的大小,一般为float
    • random_state 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。类似于np.random.seed()
  • 返回值
    • x_train, x_test, y_train, y_test
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 1、获取鸢尾花数据集
iris = load_iris()
# 对鸢尾花数据集进行分割
# 训练集的特征值x\_train 测试集的特征值x\_test 训练集的目标值y\_train 测试集的目标值y\_test
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
print("x\_train:\n", x_train.shape)
# 随机数种子
x_train1, x_test1, y_train1, y_test1 = train_test_split(iris.data, iris.target, random_state=6)
x_train2, x_test2, y_train2, y_test2 = train_test_split(iris.data, iris.target, random_state=6)
print("如果随机数种子不一致:\n", x_train == x_train1)
print("如果随机数种子一致:\n", x_train1 == x_train2)

7 特征工程—特征预处理

特征预处理是特征工程的内容之一,即通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程。
在这里插入图片描述

为什么我们要进行归一化/标准化?
特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级,容易影响(支配)目标结果,使得一些算法无法学习到其它的特征。要保证每一个特征同等重要。

特征预处理APIsklearn.preprocessing

我们需要用到一些方法进行无量纲化,使不同规格的数据转换到同一规格

  • 归一化
  • 标准化

7.1 归一化

通过对原始数据进行变换把数据映射到(默认为[0,1])之间。
在这里插入图片描述

作用于每一列,max为一列的最大值,min为一列的最小值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0

sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )

  • MinMaxScalar.fit_transform(X)
    • X:numpy array格式的数据[n_samples,n_features]
  • 返回值:转换后的形状相同的array

归一化案例

dating.txt数据有三个特征值:milage,Liters,Consumtime,一个目标值target

data.txt 数据集分享:https://pan.baidu.com/s/1NzzqTk2lZtpAh7cdvFoYSg?pwd=dx7t

在这里插入图片描述

import pandas as pd
from sklearn.preprocessing import MinMaxScaler

def minmax\_demo():
    """
 归一化演示
 :return: None
 """
    data = pd.read_csv("./dating.txt")
    print(data)
    # 1、实例化一个转换器类MinMaxScaler
    transfer = MinMaxScaler(feature_range=(2, 3))
    # 2、通过调用fit\_transform转换
    data = transfer.fit_transform(data[['milage','Liters','Consumtime']]) 
    # 注意是二维且仅转换特征值
    
    print("最小值最大值归一化处理的结果:\n", data)

    return None

minmax_demo()

"""
 milage Liters Consumtime target
0 40920 8.326976 0.953952 3
1 14488 7.153469 1.673904 2
2 26052 1.441871 0.805124 1
3 75136 13.147394 0.428964 1
4 38344 1.669788 0.134296 1
.. ... ... ... ...
995 11145 3.410627 0.631838 2
996 68846 9.974715 0.669787 1
997 26575 10.650102 0.866627 3
998 48111 9.134528 0.728045 3
999 43757 7.882601 1.332446 3

[1000 rows x 4 columns]
最小值最大值归一化处理的结果:
 [[2.44832535 2.39805139 2.56233353]
 [2.15873259 2.34195467 2.98724416]
 [2.28542943 2.06892523 2.47449629]
 ...
 [2.29115949 2.50910294 2.51079493]
 [2.52711097 2.43665451 2.4290048 ]
 [2.47940793 2.3768091 2.78571804]]
"""

在这里插入图片描述

注意:最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性(确定性、稳定性)较差,只适合传统精确小数据场景。

7.2 标准化

通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内
在这里插入图片描述

作用于每一列,mean为平均值,σ为标准差

在这里插入图片描述

  • 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
  • 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。

标椎化案例

sklearn.preprocessing.StandardScaler( )

  • 处理之后每列来说所有数据都聚集在均值0附近标准差差为1
  • StandardScaler.fit_transform(X)
    • X:numpy array格式的数据[n_samples,n_features]
  • 返回值:转换后的形状相同的array
import pandas as pd
from sklearn.preprocessing import StandardScaler

def stand\_demo():
    """
 标准化演示
 :return: None
 """
    data = pd.read_csv("dating.txt")
    print(data)
    # 1、实例化一个转换器类
    transfer = StandardScaler()
    # 2、调用fit\_transform
    data = transfer.fit_transform(data[['milage','Liters','Consumtime']])
    print("标准化的结果:\n", data)
    print("每一列特征的平均值:\n", transfer.mean_)
    print("每一列特征的方差:\n", transfer.var_)

    return None

stand_demo()

"""
 milage Liters Consumtime target
0 40920 8.326976 0.953952 3
1 14488 7.153469 1.673904 2
2 26052 1.441871 0.805124 1
3 75136 13.147394 0.428964 1
4 38344 1.669788 0.134296 1
.. ... ... ... ...
995 11145 3.410627 0.631838 2
996 68846 9.974715 0.669787 1
997 26575 10.650102 0.866627 3
998 48111 9.134528 0.728045 3
999 43757 7.882601 1.332446 3

[1000 rows x 4 columns]
标准化的结果:
 [[ 0.33193158 0.41660188 0.24523407]
 [-0.87247784 0.13992897 1.69385734]
 [-0.34554872 -1.20667094 -0.05422437]
 ...
 [-0.32171752 0.96431572 0.06952649]
 [ 0.65959911 0.60699509 -0.20931587]
 [ 0.46120328 0.31183342 1.00680598]]
每一列特征的平均值:
 [3.36354210e+04 6.55996083e+00 8.32072997e-01]
每一列特征的方差:
 [4.81628039e+08 1.79902874e+01 2.46999554e-01]

"""

在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。

7.3 案例分析

K-近邻算法API进阶使用

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm='auto')

  • n_neighbors:

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

6354210e+04 6.55996083e+00 8.32072997e-01]
每一列特征的方差:
[4.81628039e+08 1.79902874e+01 2.46999554e-01]

“”"



> 
> 在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。
> 
> 
> 


### 7.3 案例分析


**K-近邻算法API进阶使用**


`sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm='auto')`


* n\_neighbors:


[外链图片转存中...(img-V5IMc24p-1714904989322)]
[外链图片转存中...(img-uwVcYldm-1714904989322)]
[外链图片转存中...(img-JQULOiQt-1714904989322)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值