37、机器学习:从理论到医疗实践的应用

机器学习:从理论到医疗实践的应用

在机器学习的领域中,我们常常会遇到各种技术问题和挑战,同时也能收获令人惊喜的成果。本文将深入探讨机器学习的关键要点,并通过威斯康星诊断乳腺癌(WDBC)数据集的实例,展示如何运用机器学习解决实际问题。

机器学习的关键要点

在进行机器学习时,有几个关键要点需要我们特别关注:
1. 数据质量 :数据质量是机器学习成功的基础。由于数据通常具有多个维度,难以直观检查,因此需要特别注意。异常值可能会对结果产生负面影响,而适当的数据预处理对于机器学习的成功至关重要。在实际应用中,数据生成者和数据分析者应密切合作,以确保数据质量。
2. 线性方法 :尽管自然界本质上是非线性的,但线性机器学习方法通常速度极快,不受技术或结构问题的影响,也不易过拟合。线性方法可以帮助我们了解机器学习任务的非线性程度。在许多情况下,任务可能只是轻微非线性的,此时可以使用允许接近线性回归或决策表面的非线性方法。
3. 训练集和测试集的准备 :除非有已知输出误差的数据集用于评估机器学习结果的质量,否则数据必须划分为训练集和测试集。划分过程是一个关键步骤,不适当的划分可能会破坏后续的机器学习工作。目前没有理想的划分方法,需要结合启发式考虑和相关经验来解决这个挑战。
4. 方法选择 :机器学习有多种方法可供选择,没有一种方法适用于所有情况。通常,我们会根据个人偏好或经验选择方法。如果一种方法能够成功应用,就没有必要再研究其他方法。只有在方法失败时,才需要评估其他方法。
5. 参数设置 :几乎所有机器学习程序都从一些默认参数设置开始。首先调整技术参数是必不可少的,然后再处理结构问题。然而,技术和结构问题之间可能存在复杂的纠缠,因此可能需要通过简单的试错来找到解决方案。
6. 计算资源估计 :机器学习任务可能需要大量的计算资源和时间。因此,对计算需求进行适当的初始估计是必不可少的。在实际应用中,可以根据类似任务的经验或初步调查来进行估计。
7. 结果解释 :机器学习结果的范围从毫无价值到有价值的见解不等。由于机器学习有许多参数可以调整,问题可能会被巧妙地隐藏。因此,我们应该谨慎对待已发表的机器学习结果。在科学研究中,披露遇到的问题并进行充分的验证是非常重要的。

机器学习实践:WDBC数据集

为了更好地理解机器学习的应用,我们将使用威斯康星诊断乳腺癌(WDBC)数据集进行实践。该数据集将乳腺肿瘤组织中提取的细胞核特征与诊断后的肿瘤类型相关联,可以用于构建一个良性/恶性肿瘤分类预测器。
1. 数据准备 :首先,我们需要获取WDBC分类数据集,并了解其基本信息。

Clear["Global‘*"];
<<CIP‘Utility‘
<<CIP‘ExperimentalData‘
<<CIP‘DataTransformation‘
<<CIP‘Graphics‘
<<CIP‘Cluster‘
<<CIP‘MLR‘
<<CIP‘Perceptron‘
<<CIP‘SVM‘

classificationDataSet = CIP‘ExperimentalData‘GetWDBCClassificationDataSet[];
CIP‘Graphics‘ShowDataSetInfo[
  {"IoPairs", "InputComponents", "OutputComponents", "ClassCount"},
  classificationDataSet
]

运行上述代码后,我们可以得到数据集的基本信息:
| 信息 | 详情 |
| ---- | ---- |
| IO 对数量 | 569 |
| 输入组件数量 | 30 |
| 输出组件数量 | 2 |
| 类别 1(良性肿瘤)成员数量 | 357 |
| 类别 2(恶性肿瘤)成员数量 | 212 |

从这些信息可以看出,数据集是不对称的,良性肿瘤样本数量多于恶性肿瘤样本。
2. 无监督学习尝试 :我们首先尝试使用基于聚类的分类预测器进行无监督学习。

clusterInfo = CIP‘Cluster‘FitCluster[classificationDataSet];
CIP‘Cluster‘ShowClusterSingleClassification[
  {"CorrectClassification", "CorrectClassificationPerClass",
   "WrongClassificationDistribution"},
  classificationDataSet,
  clusterInfo
]

运行结果显示,整体预测成功率为 85.4%,其中良性肿瘤的预测成功率接近 99%,而恶性肿瘤的预测成功率仅为 61%。这表明无监督学习在解决良性/恶性肿瘤分类问题上效果不佳。
3. 算法问题分析 :在使用 ART - 2a 聚类算法时,我们遇到了错误。通过对输入数据的纯聚类分析,我们发现 ART - 2a 算法在该数据集上无法达到预期的结果,因此不适合用于构建基于聚类的分类预测器。

clusterMethod = "ART2a";
clusterInfo = CIP‘Cluster‘FitCluster[classificationDataSet,
  ClusterOptionMethod -> clusterMethod];
  1. 监督学习:线性方法 :接下来,我们使用线性方法(MLR)进行监督学习。
mlrInfo = CIP‘MLR‘FitMlr[classificationDataSet];
CIP‘MLR‘ShowMlrSingleClassification[
  {"CorrectClassification", "CorrectClassificationPerClass",
   "WrongClassificationDistribution"},
  classificationDataSet,
  mlrInfo
]

结果显示,整体预测成功率达到了 96.5%,良性肿瘤的预测成功率接近 99%,恶性肿瘤的预测成功率为 91%。与无监督学习相比,监督学习显著提高了恶性肿瘤的预测成功率。这表明该分类问题可以被描述为接近线性的,不需要高度非线性的决策表面。
5. 训练集和测试集划分 :为了避免过拟合问题,我们将数据集划分为训练集和测试集。使用聚类代表(CR)选择训练集通常优于随机选择。

trainingFractionList = Table[trainingFraction,
  {trainingFraction, 0.10, 0.60, 0.05}];
mlrClassificationScan =
  CIP‘MLR‘ScanClassTrainingWithMlr[
    classificationDataSet,
    trainingFractionList
  ];
CIP‘MLR‘ShowMlrClassificationScan[
  mlrClassificationScan
]

trainingFraction = 0.25;
trainingAndTestSet = CIP‘Cluster‘GetClusterBasedTrainingAndTestSet[
  classificationDataSet,
  trainingFraction
];
trainingSet = trainingAndTestSet[[1]];
testSet = trainingAndTestSet[[2]];

通过上述代码,我们选择了 25% 的数据作为训练集,75% 的数据作为测试集。划分后的训练集和测试集的类别分布与原始数据集相似,这表明划分过程是合理的。
6. 监督学习:非线性方法 - 感知器 :由于线性方法取得了较好的结果,我们可以推测该问题接近线性。因此,在使用非线性方法(如三层感知器神经网络)时,我们可以设置较少的隐藏神经元,以减少过拟合的风险。

numberOfHiddenNeurons = 2;
perceptronInfo = CIP‘Perceptron‘FitPerceptron[trainingSet,
  numberOfHiddenNeurons
];
CIP‘Perceptron‘ShowPerceptronClassificationResult[
  {"CorrectClassification", "CorrectClassificationPerClass"},
  trainingAndTestSet,
  perceptronInfo
]

结果显示,训练集和测试集的预测成功率都很高,表明感知器方法在该问题上表现良好。进一步优化训练集后,预测成功率可以进一步提高。

trainingFraction = 0.25;
numberOfTrainingSetOptimizationSteps = 20;
blackListLength = 5;
perceptronTrainOptimization =
  CIP‘Perceptron‘GetPerceptronTrainOptimization[
    classificationDataSet,
    numberOfHiddenNeurons,
    trainingFraction,
    numberOfTrainingSetOptimizationSteps,
    UtilityOptionBlackListLength -> blackListLength
  ];
CIP‘Perceptron‘ShowPerceptronTrainOptimization[
  perceptronTrainOptimization
]

index =
  CIP‘Perceptron‘GetBestPerceptronClassOptimization[
    perceptronTrainOptimization
  ];
optimizedTrainingAndTestSetList =
  perceptronTrainOptimization[[3]];
optimizedTrainingAndTestSet =
  optimizedTrainingAndTestSetList[[index]];
optimizedTrainingSet = optimizedTrainingAndTestSet[[1]];
optimizedTestSet = optimizedTrainingAndTestSet[[2]];
optimizedPerceptronInfoList =
  perceptronTrainOptimization[[4]];
optimizedPerceptronInfo = optimizedPerceptronInfoList[[index]];
CIP‘Perceptron‘ShowPerceptronClassificationResult[
  {"CorrectClassification", "CorrectClassificationPerClass"},
  optimizedTrainingAndTestSet,
  optimizedPerceptronInfo
]
  1. 输入组件相关性分析 :在得到成功的分类预测器后,我们可以分析每个输入组件的相关性。
perceptronInputRelevanceClass =
  CIP‘Perceptron‘GetPerceptronInputRelevanceClass[
    optimizedTrainingAndTestSet,
    numberOfHiddenNeurons
  ];
CIP‘Perceptron‘ShowPerceptronInputRelevanceClass[
  perceptronInputRelevanceClass
]

结果显示,约三分之二的输入组件可以省略,而不会显著影响预测性能。这表明描述细胞核的特征之间存在高度的冗余性,这一发现可以为进一步的研究提供启示。
8. 监督学习:非线性方法 - SVM :除了感知器方法,我们还可以使用支持向量机(SVM)进行非线性分类。

trainingFraction = 0.25;
trainingAndTestSet = CIP‘Cluster‘GetClusterBasedTrainingAndTestSet[
  classificationDataSet,
  trainingFraction
];
trainingSet = trainingAndTestSet[[1]];
testSet = trainingAndTestSet[[2]];

kernelFunctionList = Table[{"Wavelet", kernelParameter},
  {kernelParameter, 1.0, 3.0, 0.1}
];
svmInfoList = CIP‘SVM‘FitSvmSeries[trainingSet, kernelFunctionList];
svmSeriesClassificationResult =
  CIP‘SVM‘GetSvmSeriesClassificationResult[trainingAndTestSet,
    svmInfoList
  ];
CIP‘SVM‘ShowSvmSeriesClassificationResult[
  svmSeriesClassificationResult
]

kernelFunction = kernelFunctionList[[12]];
trainingFraction = 0.25;
numberOfTrainingSetOptimizationSteps = 20;
blackListLength = 5;
svmTrainOptimization =
  CIP‘SVM‘GetSvmTrainOptimization[classificationDataSet,
    kernelFunction,
    trainingFraction,
    numberOfTrainingSetOptimizationSteps,
    UtilityOptionBlackListLength -> blackListLength
  ];
CIP‘SVM‘ShowSvmTrainOptimization[
  svmTrainOptimization
]

index =
  CIP‘SVM‘GetBestSvmClassOptimization[
    svmTrainOptimization
  ];
optimizedTrainingAndTestSetList =
  svmTrainOptimization[[3]];
optimizedTrainingAndTestSet =
  optimizedTrainingAndTestSetList[[index]];
optimizedTrainingSet = optimizedTrainingAndTestSet[[1]];
optimizedTestSet = optimizedTrainingAndTestSet[[2]];
optimizedSvmInfoList = svmTrainOptimization[[4]];
optimizedSvmInfo = optimizedSvmInfoList[[index]];
CIP‘SVM‘ShowSvmClassificationResult[
  {"CorrectClassification", "CorrectClassificationPerClass"},
  optimizedTrainingAndTestSet,
  optimizedSvmInfo
]

SVM 方法在训练集和测试集上也取得了良好的预测结果,与感知器方法的性能相当。

总结

通过对 WDBC 数据集的实践,我们可以看到机器学习在解决实际问题中的强大能力。我们不仅成功构建了高质量的分类预测器,还获得了关于细胞核特征对于良性/恶性肿瘤分类的重要见解。在实际应用中,我们应该根据具体情况选择合适的方法和参数,并进行充分的验证和解释。同时,不断扩大我们的计算方法工具箱,以便在不同情况下选择最合适的方法。

以下是整个机器学习过程的 mermaid 流程图:

graph LR
    A[数据准备] --> B[无监督学习尝试]
    B --> C{无监督学习是否成功}
    C -- 否 --> D[监督学习:线性方法]
    D --> E[训练集和测试集划分]
    E --> F[监督学习:非线性方法 - 感知器]
    F --> G[输入组件相关性分析]
    E --> H[监督学习:非线性方法 - SVM]
    C -- 是 --> I[结束]
    F --> J[结果评估]
    H --> J
    G --> J
    J --> K[总结与应用]

通过这个流程图,我们可以清晰地看到整个机器学习过程的步骤和决策点。在实际应用中,我们可以根据具体情况进行调整和优化。

机器学习:从理论到医疗实践的应用

机器学习在医疗诊断中的优势与挑战

机器学习在医疗诊断领域展现出了巨大的潜力,但也面临着一些挑战。

优势
  1. 高效处理复杂数据 :医疗数据往往具有高维度、复杂性的特点,机器学习能够快速处理这些数据,挖掘其中隐藏的模式和信息。例如,在 WDBC 数据集中,有 30 个输入组件描述细胞核特征,机器学习方法可以对这些特征进行综合分析,为肿瘤的良性/恶性分类提供依据。
  2. 提供准确的预测 :通过构建有效的分类预测器,机器学习可以为医疗诊断提供准确的预测结果。如在 WDBC 数据集的实践中,线性方法(MLR)和非线性方法(感知器、SVM)都取得了较高的预测成功率,能够为医生的诊断决策提供有力支持。
  3. 发现特征相关性 :机器学习可以帮助分析每个输入组件的相关性,发现特征之间的冗余性。在 WDBC 数据集的分析中,发现约三分之二的输入组件可以省略而不显著影响预测性能,这有助于简化医疗诊断过程,减少不必要的检测项目。
挑战
  1. 数据质量问题 :数据质量是机器学习成功的关键,但医疗数据的收集和整理过程中可能存在各种问题,如数据缺失、异常值等。这些问题可能会影响机器学习模型的性能,因此需要对数据进行严格的预处理。
  2. 过拟合风险 :非线性机器学习方法容易出现过拟合问题,即模型在训练集上表现良好,但在测试集上的性能不佳。为了避免过拟合,需要合理划分训练集和测试集,并选择合适的模型结构和参数。
  3. 结果解释困难 :机器学习模型通常是复杂的黑盒模型,其结果的解释较为困难。在医疗领域,医生需要理解模型的预测结果,以便做出合理的诊断决策。因此,如何解释机器学习模型的结果是一个亟待解决的问题。
不同机器学习方法的比较

在处理 WDBC 数据集的良性/恶性肿瘤分类问题时,我们使用了多种机器学习方法,下面对这些方法进行比较。

方法 优点 缺点 预测成功率
无监督学习(聚类) 不需要输出诊断信息,不受过拟合影响 整体预测成功率较低,对恶性肿瘤预测效果差 85.4%
线性方法(MLR) 速度快,不易过拟合 受线性性质限制 96.5%
非线性方法 - 感知器 可以处理非线性问题,通过调整隐藏神经元数量可减少过拟合风险 结构参数设置较复杂 最高 99.6%(未验证),验证后最高 98.8%
非线性方法 - SVM 可以处理非线性问题,通过选择合适的核函数和参数可获得较好性能 核函数和参数选择较困难 最高 98.8%

从比较结果可以看出,线性方法和非线性方法在处理 WDBC 数据集时都取得了较好的效果,但非线性方法在某些情况下可以进一步提高预测成功率。在实际应用中,我们应该根据具体情况选择合适的方法。

机器学习在医疗诊断中的操作步骤总结

为了更好地在医疗诊断中应用机器学习,下面总结了具体的操作步骤:

  1. 数据准备
    • 收集相关的医疗数据,如 WDBC 数据集。
    • 对数据进行预处理,包括处理缺失值、异常值等。
    • 了解数据的基本信息,如输入组件数量、输出组件数量、类别分布等。
Clear["Global‘*"];
<<CIP‘Utility‘
<<CIP‘ExperimentalData‘
<<CIP‘DataTransformation‘
<<CIP‘Graphics‘
<<CIP‘Cluster‘
<<CIP‘MLR‘
<<CIP‘Perceptron‘
<<CIP‘SVM‘

classificationDataSet = CIP‘ExperimentalData‘GetWDBCClassificationDataSet[];
CIP‘Graphics‘ShowDataSetInfo[
  {"IoPairs", "InputComponents", "OutputComponents", "ClassCount"},
  classificationDataSet
]
  1. 无监督学习尝试
    • 使用聚类方法进行无监督学习,如 FitCluster 方法。
    • 评估无监督学习的结果,判断是否能够成功解决问题。
clusterInfo = CIP‘Cluster‘FitCluster[classificationDataSet];
CIP‘Cluster‘ShowClusterSingleClassification[
  {"CorrectClassification", "CorrectClassificationPerClass",
   "WrongClassificationDistribution"},
  classificationDataSet,
  clusterInfo
]
  1. 监督学习 - 线性方法
    • 如果无监督学习不成功,使用线性方法(如 MLR)进行监督学习。
    • 评估线性方法的预测结果,了解问题的非线性程度。
mlrInfo = CIP‘MLR‘FitMlr[classificationDataSet];
CIP‘MLR‘ShowMlrSingleClassification[
  {"CorrectClassification", "CorrectClassificationPerClass",
   "WrongClassificationDistribution"},
  classificationDataSet,
  mlrInfo
]
  1. 训练集和测试集划分
    • 将数据集划分为训练集和测试集,避免过拟合问题。
    • 可以使用聚类代表(CR)选择训练集,提高划分的合理性。
trainingFractionList = Table[trainingFraction,
  {trainingFraction, 0.10, 0.60, 0.05}];
mlrClassificationScan =
  CIP‘MLR‘ScanClassTrainingWithMlr[
    classificationDataSet,
    trainingFractionList
  ];
CIP‘MLR‘ShowMlrClassificationScan[
  mlrClassificationScan
]

trainingFraction = 0.25;
trainingAndTestSet = CIP‘Cluster‘GetClusterBasedTrainingAndTestSet[
  classificationDataSet,
  trainingFraction
];
trainingSet = trainingAndTestSet[[1]];
testSet = trainingAndTestSet[[2]];
  1. 监督学习 - 非线性方法
    • 根据线性方法的结果,选择合适的非线性方法(如感知器、SVM)。
    • 设置合适的结构参数,如感知器的隐藏神经元数量、SVM 的核函数和参数。
    • 对训练集进行优化,提高模型的性能。
numberOfHiddenNeurons = 2;
perceptronInfo = CIP‘Perceptron‘FitPerceptron[trainingSet,
  numberOfHiddenNeurons
];
CIP‘Perceptron‘ShowPerceptronClassificationResult[
  {"CorrectClassification", "CorrectClassificationPerClass"},
  trainingAndTestSet,
  perceptronInfo
]

trainingFraction = 0.25;
numberOfTrainingSetOptimizationSteps = 20;
blackListLength = 5;
perceptronTrainOptimization =
  CIP‘Perceptron‘GetPerceptronTrainOptimization[
    classificationDataSet,
    numberOfHiddenNeurons,
    trainingFraction,
    numberOfTrainingSetOptimizationSteps,
    UtilityOptionBlackListLength -> blackListLength
  ];
CIP‘Perceptron‘ShowPerceptronTrainOptimization[
  perceptronTrainOptimization
]

index =
  CIP‘Perceptron‘GetBestPerceptronClassOptimization[
    perceptronTrainOptimization
  ];
optimizedTrainingAndTestSetList =
  perceptronTrainOptimization[[3]];
optimizedTrainingAndTestSet =
  optimizedTrainingAndTestSetList[[index]];
optimizedTrainingSet = optimizedTrainingAndTestSet[[1]];
optimizedTestSet = optimizedTrainingAndTestSet[[2]];
optimizedPerceptronInfoList =
  perceptronTrainOptimization[[4]];
optimizedPerceptronInfo = optimizedPerceptronInfoList[[index]];
CIP‘Perceptron‘ShowPerceptronClassificationResult[
  {"CorrectClassification", "CorrectClassificationPerClass"},
  optimizedTrainingAndTestSet,
  optimizedPerceptronInfo
]

trainingFraction = 0.25;
trainingAndTestSet = CIP‘Cluster‘GetClusterBasedTrainingAndTestSet[
  classificationDataSet,
  trainingFraction
];
trainingSet = trainingAndTestSet[[1]];
testSet = trainingAndTestSet[[2]];

kernelFunctionList = Table[{"Wavelet", kernelParameter},
  {kernelParameter, 1.0, 3.0, 0.1}
];
svmInfoList = CIP‘SVM‘FitSvmSeries[trainingSet, kernelFunctionList];
svmSeriesClassificationResult =
  CIP‘SVM‘GetSvmSeriesClassificationResult[trainingAndTestSet,
    svmInfoList
  ];
CIP‘SVM‘ShowSvmSeriesClassificationResult[
  svmSeriesClassificationResult
]

kernelFunction = kernelFunctionList[[12]];
trainingFraction = 0.25;
numberOfTrainingSetOptimizationSteps = 20;
blackListLength = 5;
svmTrainOptimization =
  CIP‘SVM‘GetSvmTrainOptimization[classificationDataSet,
    kernelFunction,
    trainingFraction,
    numberOfTrainingSetOptimizationSteps,
    UtilityOptionBlackListLength -> blackListLength
  ];
CIP‘SVM‘ShowSvmTrainOptimization[
  svmTrainOptimization
]

index =
  CIP‘SVM‘GetBestSvmClassOptimization[
    svmTrainOptimization
  ];
optimizedTrainingAndTestSetList =
  svmTrainOptimization[[3]];
optimizedTrainingAndTestSet =
  optimizedTrainingAndTestSetList[[index]];
optimizedTrainingSet = optimizedTrainingAndTestSet[[1]];
optimizedTestSet = optimizedTrainingAndTestSet[[2]];
optimizedSvmInfoList = svmTrainOptimization[[4]];
optimizedSvmInfo = optimizedSvmInfoList[[index]];
CIP‘SVM‘ShowSvmClassificationResult[
  {"CorrectClassification", "CorrectClassificationPerClass"},
  optimizedTrainingAndTestSet,
  optimizedSvmInfo
]
  1. 输入组件相关性分析
    • 分析每个输入组件的相关性,发现特征之间的冗余性。
    • 根据分析结果,简化输入特征,提高模型的效率和可解释性。
perceptronInputRelevanceClass =
  CIP‘Perceptron‘GetPerceptronInputRelevanceClass[
    optimizedTrainingAndTestSet,
    numberOfHiddenNeurons
  ];
CIP‘Perceptron‘ShowPerceptronInputRelevanceClass[
  perceptronInputRelevanceClass
]
  1. 结果评估与应用
    • 对模型的预测结果进行评估,包括整体预测成功率、各类别的预测成功率等。
    • 将模型的预测结果应用于实际医疗诊断中,并不断进行验证和改进。
未来展望

随着技术的不断发展,机器学习在医疗诊断领域的应用前景十分广阔。

  1. 多模态数据融合 :未来可以将多种医疗数据(如影像数据、基因数据、临床数据等)进行融合,利用机器学习方法进行综合分析,提高诊断的准确性和可靠性。
  2. 可解释性机器学习 :研究更加可解释的机器学习模型,使医生能够更好地理解模型的预测结果,提高模型在医疗领域的可信度和应用范围。
  3. 个性化医疗 :根据患者的个体特征(如基因信息、生活习惯等),利用机器学习方法为患者提供个性化的医疗诊断和治疗方案,提高治疗效果。

总之,机器学习在医疗诊断领域具有巨大的潜力,但也需要我们不断地探索和研究,解决面临的挑战,以实现其在医疗领域的广泛应用和发展。

以下是不同机器学习方法在医疗诊断中的应用流程 mermaid 流程图:

graph LR
    A[数据收集与预处理] --> B[无监督学习]
    B --> C{无监督学习效果好?}
    C -- 否 --> D[线性监督学习]
    C -- 是 --> E[使用无监督学习结果]
    D --> F[训练集/测试集划分]
    F --> G[非线性监督学习 - 感知器]
    F --> H[非线性监督学习 - SVM]
    G --> I[特征相关性分析]
    H --> I
    I --> J[模型评估]
    E --> J
    J --> K[临床应用与改进]

这个流程图展示了不同机器学习方法在医疗诊断中的应用步骤和决策过程,有助于我们更好地理解和应用机器学习技术。在实际应用中,我们可以根据具体情况对流程进行调整和优化,以达到最佳的诊断效果。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值