Sklearn官方文档中文整理8——多类和多标签算法篇

1. 监督学习

1.12. 多类和多标签算法

scikit-learn中的所有分类器都可以开箱即用进行多类分类。除非您想尝试不同的多类策略,否则无需使用sklearn.multiclass模块。
sklearn.multiclass 模块采用了 元评估器 ,通过把多类多标签 分类问题分解为二元分类问题去解决。这同样适用于多目标回归问题。

  • Multiclass classification 多类分类 意味着一个分类任务需要对多于两个类的数据进行分类。比如,对一系列的橘子,苹果或者梨的图片进行分类。多类分类假设每一个样本有且仅有一个标签:一个水果可以被归类为苹果,也可以 是梨,但不能同时被归类为两类。

  • Multilabel classification 多标签分类 给每一个样本分配一系列标签。这可以被认为是预测不相互排斥的数据点的属性,例如与文档类型相关的主题。一个文本可以归类为任意类别,例如可以同时为政治、金融、 教育相关或者不属于以上任何类别。

  • Multioutput regression 多输出分类 为每个样本分配一组目标值。这可以认为是预测每一个样本的多个属性,比如说一个具体地点的风的方向和大小。

  • Multioutput-multiclass classification and multi-task classification 多输出-多类分类和多任务分类 意味着单个的评估器要解决多个联合的分类任务。这是只考虑二分类的 multi-label classification 和 multi-class classification 任务的推广。 此类问题输出的格式是一个二维数组或者一个稀疏矩阵

每个输出变量的标签集合可以是各不相同的。比如说,一个样本可以将“梨”作为一个输出变量的值,这个输出变 量在一个含有“梨”、“苹果”等水果种类的有限集合中取可能的值;将“蓝色”或者“绿色”作为第二个输出变量的值, 这个输出变量在一个含有“绿色”、“红色”、“蓝色”等颜色种类的有限集合中取可能的值…

这意味着任何处理 multi-output multiclass or multi-task classification 任务的分类器,在特殊的 情况下支持 multi-label classification 任务。Multi-task classification 与具有不同模型公式 的 multi-output classification 相似。详细情况请查阅相关的分类器的文档。

所有的 scikit-learn 分类器都能处理 multiclass classification 任务, 但是 sklearn.multiclass 提供的元评估器允许改变在处理超过两类数据时的方式,因为这会对分类器的性能产生影响 (无论是在泛化误差或者所需要的计算资源方面)

下面是按照 scikit-learn 策略分组的分类器的总结,如果你使用其中的一个,则不需要此类中的元评估器,除非你想要自定义的多分类方式。

固有的多类分类器:
sklearn.naive_bayes.BernoulliNB
sklearn.tree.DecisionTreeClassifier
sklearn.tree.ExtraTreeClassifier
sklearn.ensemble.ExtraTreesClassifier
sklearn.naive_bayes.GaussianNB
sklearn.neighbors.KNeighborsClassifier
sklearn.semi_supervised.LabelPropagation
sklearn.semi_supervised.LabelSpreading
sklearn.discriminant_analysis.LinearDiscriminantAnalysis
sklearn.svm.LinearSVC(setting multi_class=”crammer_singer”)
sklearn.linear_model.LogisticRegression (setting multi_class=”multinomial”)
sklearn.linear_model.LogisticRegressionCV(setting multi_class=”multinomial”)
sklearn.neural_network.MLPClassifier
sklearn.neighbors.NearestCentroid
sklearn.discriminant_analysis.QuadraticDiscriminantAnalysis
sklearn.neighbors.RadiusNeighborsClassifier
sklearn.ensemble.RandomForestClassifier
sklearn.linear_model.RidgeClassifier
sklearn.linear_model.RidgeClassifierCV

1对1的多类分类器:
sklearn.svm.NuSVC
sklearn.svm.SVC.
sklearn.gaussian_process.GaussianProcessClassifier (setting multi_class = “one_vs_one”)

1对多的多类分类器:
sklearn.ensemble.GradientBoostingClassifier
sklearn.gaussian_process.GaussianProcessClassifier (setting multi_class = “one_vs_rest”)
sklearn.svm.LinearSVC (setting multi_class=”ovr”)
sklearn.linear_model.LogisticRegression (setting multi_class=”ovr”)
sklearn.linear_model.LogisticRegressionCV (setting multi_class=”ovr”)
sklearn.linear_model.SGDClassifier
sklearn.linear_model.Perceptron
sklearn.linear_model.PassiveAggressiveClassifier

支持多标签分类的分类器:
sklearn.tree.DecisionTreeClassifier
sklearn.tree.ExtraTreeClassifier
sklearn.ensemble.ExtraTreesClassifier
sklearn.neighbors.KNeighborsClassifier
sklearn.neural_network.MLPClassifier
sklearn.neighbors.RadiusNeighborsClassifier
sklearn.ensemble.RandomForestClassifier
sklearn.linear_model.RidgeClassifierCV

支持多类-多输出分类的分类器:
sklearn.tree.DecisionTreeClassifier
sklearn.tree.ExtraTreeClassifier
sklearn.ensemble.ExtraTreesClassifier
sklearn.neighbors.KNeighborsClassifier
sklearn.neighbors.RadiusNeighborsClassifier
sklearn.ensemble.RandomForestClassifier

警告:目前,sklearn.metrics中没有评估方法能够支持多输出多类分类任务。

1.12.1. 多标签分类格式【preprocessing.MultiLabelBinarizer】

multilabel learning 中,二元分类任务的合集表示为二进制数组:每一个样本是大小为 (n_samples, n_classes) 的二维数组中的一行二进制值,比如非0元素,表示为对应标签的 子集。 一个数组 np.array([[1, 0, 0], [0, 1, 1], [0, 0, 0]]) 表示第一个样本属于第 0 个标签,第二个样本属于第一个和第二个标签,第三个样本不属于任何标签。

通过一系列的标签来产生多标签数据可能更为直观。 MultiLabelBinarizer转换器可以用来在标签接口和格式指示器接口之间进行转换。

>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> y = [[2, 3, 4], [2], [0, 1, 3], [0, 1, 2, 3, 4], [0, 1, 2]]
>>> MultiLabelBinarizer().fit_transform(y)
array([[0, 0, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [1, 1, 0, 1, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0]])

sklearn.preprocessing.MultiLabelBinarizer

参数解释
classes:array-like of shape (n_classes,), default=None指示类标签的顺序。所有条目都应该是唯一的(不能包含重复的类)。
sparse_output:bool, default=False如果需要CSR稀疏格式的输出二进制数组,则设置为True。
属性解释
classes_:ndarray of shape (n_classes,)classes参数的副本(如果提供)。否则,它对应于拟合时找到的已排序的类集。
方法解释
fit(y)拟合标签集,存储在classes_中
fit_transform(y)调整标签集二值化器并转换给定的标签集。
get_params([deep])获取此估计器的参数。
set_params(**params)设置此估计器的参数。
inverse_transform(yt)将给定的指标矩阵转换为标签集。
transform(y)变换给定的标签集。

例:

>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> mlb = MultiLabelBinarizer()
>>> mlb.fit_transform([(1, 2), (3,)])
array([[1, 1, 0],
       [0, 0, 1]])
>>> mlb.classes_
array([1, 2, 3])
>>>
>>> mlb.fit_transform([{'sci-fi', 'thriller'}, {'comedy'}])
array([[0, 1, 1],
       [1, 0, 0]])
>>> list(mlb.classes_)
['comedy', 'sci-fi', 'thriller']

一个常见的错误是传递列表,这会导致以下问题:

>>>
>>> mlb = MultiLabelBinarizer()
>>> mlb.fit(['sci-fi', 'thriller', 'comedy'])
MultiLabelBinarizer()
>>> mlb.classes_
array(['-', 'c', 'd', 'e', 'f', 'h', 'i', 'l', 'm', 'o', 'r', 's', 't',
    'y'], dtype=object)

要更正此问题,应将标签列表传递为:

>>>
>>> mlb = MultiLabelBinarizer()
>>> mlb.fit([['sci-fi', 'thriller', 'comedy']])
MultiLabelBinarizer()
>>> mlb.classes_
array(['comedy', 'sci-fi', 'thriller'], dtype=object)

1.12.2. 1对其余【multiclass.OneVsRestClassifier】

这个方法也被称为 1对多, 在OneVsRestClassifier 模块中执行。 这个方法在于每一个类都将用一个分类器进行拟合。 对于每一个分类器,该类将会和其他所有的类有所区别。除了它的计算效率之外 (只需要 n_classes 个分类器), 这种方法的优点是它具有可解释性。 因为每一个类都可以通过有且仅有一个分类器来代表,所以通过检查一个类相关的分类器就可以获得该类的信息。这是最常用的方法,也是一个合理的默认选择。

sklearn.multiclass.OneVsRestClassifier

参数解释
estimator:estimator object估计器实现的fit和 decision_function 或者 predict_proba
n_jobs:int, default=None线程数
属性解释
estimators_:list of n_classes estimators用于预测的估计器
coef_:ndarray of shape (1, n_features) or (n_classes, n_features)决策函数中特征的系数。
intercept_:ndarray of shape (1, 1) or (n_classes, 1)如果y是二进制的,则形状是(1,1)否则为(n_classes, 1)
classes_:array, shape = [n_classes]类标签
n_classes_:int类个数
label_binarizer_:LabelBinarizer object用于将多类标签转换为二进制标签的对象
multilabel_:boolean这是否是一个多标签分类器
方法解释
decision_function(X)返回每个类的每个样本到决策边界的距离。
fit(X, y)拟合基本估计器
get_params([deep])获取此估计器的参数。
set_params(**params)设置此估计器的参数。
partial_fit(X, y[, classes])部分拟合基本估计器
predict(X)利用基本估计器预测多类目标。
predict_proba(X)概率估计。
score(X, y[, sample_weight])返回给定测试数据和标签的平均精度。

例:

>>> import numpy as np
>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.svm import SVC
>>> X = np.array([
...     [10, 10],
...     [8, 10],
...     [-5, 5.5],
...     [-5.4, 5.5],
...     [-20, -20],
...     [-15, -20]
... ])
>>> y = np.array([0, 0, 1, 1, 2, 2])
>>> clf = OneVsRestClassifier(SVC()).fit(X, y)
>>> clf.predict([[-19, -20], [9, 9], [-5, 5]])
array([2, 0, 1])

1.12.2.1. 多类学习

下面是一个使用 OvR 的一个例子:

>>> from sklearn import datasets
>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.svm import LinearSVC
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> OneVsRestClassifier(LinearSVC(random_state=0)).fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
1.12.2.2. 多标签学习

OneVsRestClassifier 1对其余分类器 也支持 multilabel classification. 要使用该功能,给分类器提供一个指示矩阵,比如 [i,j] 表示第i个样本中的第j个标签。

1.12.3. 1对1【multiclass.OneVsOneClassifier】

OneVsOneClassifier 1对1分类器 将会为每一对类别构造出一个分类器,在预测阶段,收到最多投票的类别将会被挑选出来。 当存在结时(两个类具有同样的票数的时候), 1对1分类器会选择总分类置信度最高的类,其中总分类置信度是由下层的二元分类器 计算出的成对置信等级累加而成。

因为这需要训练出n_classes * (n_classes - 1) / 2个分类器, 由于复杂度为 O(n_classes^2),这个方法通常比 one-vs-the-rest 慢。然而,这个方法也有优点,比如说是在没有很好的缩放 n_samples 数据的核方法中。 这是由于每个单独的学习问题只涉及一小部分数据,而 one-vs-the-rest 将会使用 n_classes 次完整的数据。

sklearn.multiclass.OneVsOneClassifier

参数解释
estimator:estimator object估计器实现的fit和 decision_function 或者 predict_proba
n_jobs:int, default=None线程数
属性解释
estimators_:list of n_classes estimators用于预测的估计器
classes_:array, shape = [n_classes]类标签
n_classes_:int类个数
pairwise_indices_:list, length = len(estimators_), or None训练估计器时使用的样本的indices。
方法解释
decision_function(X)返回每个类的每个样本到决策边界的距离。
fit(X, y)拟合基本估计器
get_params([deep])获取此估计器的参数。
set_params(**params)设置此估计器的参数。
partial_fit(X, y[, classes])部分拟合基本估计器
predict(X)利用基本估计器预测多类目标。
score(X, y[, sample_weight])返回给定测试数据和标签的平均精度。

例:

>>> from sklearn.datasets import load_iris
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.multiclass import OneVsOneClassifier
>>> from sklearn.svm import LinearSVC
>>> X, y = load_iris(return_X_y=True)
>>> X_train, X_test, y_train, y_test = train_test_split(
...     X, y, test_size=0.33, shuffle=True, random_state=0)
>>> clf = OneVsOneClassifier(
...     LinearSVC(random_state=0)).fit(X_train, y_train)
>>> clf.predict(X_test[:10])
array([2, 1, 0, 2, 0, 2, 0, 1, 1, 1])

1.12.3.1. 多类别学习

下面是一个使用OvO进行多类别学习的例子:

>>> from sklearn import datasets
>>> from sklearn.multiclass import OneVsOneClassifier
>>> from sklearn.svm import LinearSVC
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> OneVsOneClassifier(LinearSVC(random_state=0)).fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

1.12.4. 误差校正输出代码【multiclass.OutputCodeClassifier】

基于Output-code的方法不同于 one-vs-the-restone-vs-one。使用这些方法,每一个类将会被映射到欧几里得空间,每一个维度上的值只能为0或者1。另一种解释它的方法是,每一个类被表示为二进制 码(一个 由0 和 1 组成的数组)。保存 location (位置)/ 每一个类的编码的矩阵被称为 code book。编码的大小是前面提到的欧几里得空间的纬度。直观上来说,每一个类应该使用一个唯一的编码,同时,好的 code book 应该能够优化分类的精度。 在实现上,我们使用随机产生的 code book,正如在 [3] 提倡的方式,即使更加详尽的方法可能会在未来被加入其中。

在训练时,code book 每一位的二分类器将会被训练。在预测时,分类器将映射到类空间中选中的点的附近。

OutputCodeClassifier, code_size 属性允许用户设置将会用到的分类器的数量。 它是类别总数的百分比。

在 0 或 1 之中的一个数字会比 one-vs-the-rest 使用更少的分类器。理论上log2(n_classes) / n_classes 足以明确表示每个类。然而在实际情况中,这也许会导致不太好的精确度,因为 log2(n_classes) 小于 n_classes.

比 1 大的数字比 one-vs-the-rest 需要更多的分类器。在这种情况下,一些分类器在理论上会纠正其他分类器的错误,因此命名为 “error-correcting” 。然而在实际上这通常不会发生,因为许多分类器的错误通常意义上来说是相关的。error-correcting output codesbagging有一个相似的作用效果。

sklearn.multiclass.OutputCodeClassifier

参数解释
estimator:estimator object估计器实现的fit和 decision_function 或者 predict_proba
code_size:float用于创建代码本的类数的百分比。
random_state:int, RandomState instance, default=None用于初始化代码本的生成器。
n_jobs:int, default=None线程数
属性解释
estimators_:list of n_classes estimators用于预测的估计器
classes_:array, shape = [n_classes]类标签
code_book_:numpy array of shape [n_classes, code_size]包含每个类的代码的二进制数组。
方法解释
fit(X, y)拟合基本估计器
get_params([deep])获取此估计器的参数。
set_params(**params)设置此估计器的参数。
predict(X)利用基本估计器预测多类目标。
score(X, y[, sample_weight])返回给定测试数据和标签的平均精度。

例:

>>> from sklearn.multiclass import OutputCodeClassifier
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.datasets import make_classification
>>> X, y = make_classification(n_samples=100, n_features=4,
...                            n_informative=2, n_redundant=0,
...                            random_state=0, shuffle=False)
>>> clf = OutputCodeClassifier(
...     estimator=RandomForestClassifier(random_state=0),
...     random_state=0).fit(X, y)
>>> clf.predict([[0, 0, 0, 0]])
array([1])

1.12.4.1. 多类别学习

下面是一个使用Output-Codes进行多类别学习的例子:

>>> from sklearn import datasets
>>> from sklearn.multiclass import OutputCodeClassifier
>>> from sklearn.svm import LinearSVC
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> clf = OutputCodeClassifier(LinearSVC(random_state=0),
...                            code_size=2, random_state=0)
>>> clf.fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2,
 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

1.12.5. 多输出回归【multioutput.MultiOutputRegressor】

多输出回归支持MultiOutputRegressor 可以被添加到任何回归器中。这个策略包括对每个目标拟合一个回归器。因为每一个目标可以被一个回归器精确地表示,通过检查对应的回归器,可以获取关于目标的信息。 因为 MultiOutputRegressor 对于每一个目标可以训练出一个回归器,所以它无法利用目标之间的相关度信息。

以下是 multioutput regression(多输出回归)的示例:

>>> from sklearn.datasets import make_regression
>>> from sklearn.multioutput import MultiOutputRegressor
>>> from sklearn.ensemble import GradientBoostingRegressor
>>> X, y = make_regression(n_samples=10, n_targets=3, random_state=1)
>>> MultiOutputRegressor(GradientBoostingRegressor(random_state=0)).fit(X, y).predict(X)
array([[-154.75474165, -147.03498585,  -50.03812219],
       [   7.12165031,    5.12914884,  -81.46081961],
       [-187.8948621 , -100.44373091,   13.88978285],
       [-141.62745778,   95.02891072, -191.48204257],
       [  97.03260883,  165.34867495,  139.52003279],
       [ 123.92529176,   21.25719016,   -7.84253   ],
       [-122.25193977,  -85.16443186, -107.12274212],
       [ -30.170388  ,  -94.80956739,   12.16979946],
       [ 140.72667194,  176.50941682,  -17.50447799],
       [ 149.37967282,  -81.15699552,   -5.72850319]])

1.12.6. 多输出分类

Multioutput classification 支持能够被添加到任何带有 MultiOutputClassifier 标志的分类器中. 这种方法为每一个目标训练一个分类器。 这就允许产生多目标变量分类器。这种类的目的是扩展评估器用于评估一系列目标函数 (f1,f2,f3…,fn) ,这些函数在一个单独的预测矩阵上进行训练以此来预测一系列的响应 (y1,y2,y3…,yn)。

下面是多输出分类的一个例子:

>>> from sklearn.datasets import make_classification
>>> from sklearn.multioutput import MultiOutputClassifier
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.utils import shuffle
>>> import numpy as np
>>> X, y1 = make_classification(n_samples=10, n_features=100, n_informative=30, n_classes=3, random_state=1)
>>> y2 = shuffle(y1, random_state=1)
>>> y3 = shuffle(y1, random_state=2)
>>> Y = np.vstack((y1, y2, y3)).T
>>> n_samples, n_features = X.shape # 10,100
>>> n_outputs = Y.shape[1] # 3
>>> n_classes = 3
>>> forest = RandomForestClassifier(n_estimators=100, random_state=1)
>>> multi_target_forest = MultiOutputClassifier(forest, n_jobs=-1)
>>> multi_target_forest.fit(X, Y).predict(X)
array([[2, 2, 0],
       [1, 2, 1],
       [2, 1, 0],
       [0, 0, 2],
       [0, 2, 1],
       [0, 0, 2],
       [1, 1, 0],
       [1, 1, 1],
       [0, 0, 2],
       [2, 0, 0]])

1.12.7. 链式分类器

Classifier chains (查看 ClassifierChain) 是一种集合多个二分类器为一个单独的多标签模型的方法,这种方法能够发掘目标之间的相关性信息

对于有 N 个类的多标签分类问题,为 N 个二元分类器分配 0 到 N-1 之间的一个整数。这些整数定义了模型在 chain 中的顺序。将每个分类器拟合可用的训练数据与真实的类别标签,标签数字相对较小。

当进行预测时,真正的标签将无法使用。相反,每一个模型的预测结果将会传递给链上的下一个模型作为特征来进行使用。

很明显,链的顺序是十分重要的。链上的第一个模型没有关于其他标签的信息,而链上的最后一个模型将会具有所有其他标签的信息。 在一般情况下,我们并不知道链上模型最优的顺序,因此通常会使用许多随机的顺序,将他们的预测求平均。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值