特征工程之数据预处理(笔记)

特征工程:对原始数据进行一系列工程处理,将其提炼为特征,作为输入供算法和模型使用。

特征工程的目的:去除原数据中的杂项和冗余,设计更高效的特征以刻画要求解的问题和预测模型之间的关系。

特征工程的重要性:

1.特征越好,灵活性越强。好的特征的灵活性在于它允许你选择不复杂的模型,同时运行速度也更快,也更容易和维护。
2.特征越好,构建的模型越简单。好的特征可以在参数不是最优的情况,依然得到很好的性能,减少调参的工作量和时间,也就可以大大降低模型复杂度。
3.特征越好,模型的性能越出色。特征工程的目的本来就是为了提升模型的性能。

数据预处理

一般常用的数据类型分为结构化数据非结构化数据。结构化数据可以看做是关系型数据库的一张表,每列都有清晰的定义,每一行数据表示一个样本信息;非结构化数据主要是文本、图像、音频、视频数据,其包含的信息无法用一个简单的数值表示,也没有清晰的类别定义,并且每个数据的大小互不相同。

这里主要学习结构化数据的预处理方法。

缺失值处理

由于各种原因,现实中许多数据包含缺失值,通常其编码为空白,NaN或其他占位符,缺失值会使建模过程混乱,导致不可靠的输出。

缺失值产生的原因

  • 信息暂时无法获取或获取信息的代价太大。
  • 信息被遗漏,人为的输入遗漏或数据采集设备的遗漏。
  • 对一些对象来说属性值本身不存在。

缺失值的处理方法

1.直接使用含有缺失值得特征:当仅有少量样本缺失该特征时可以尝试使用。
2.删除含有缺失值的特征:大多数样本都缺失改特征,且该特征效用很小。
3.插值补全缺失值

插值补全缺失值的方法
1.均值/中位数/众数补全

分类变量:通常分类水平出现的次数多,出现概率就高,众数填充。
数值型变量:样本属性的距离是可度量的,用有效值的均值填充。

import numpy as np
from sklearn.impute import SimpleImputer#填充缺失值的包
imp=SimpleImputer(missing_values=np.nan,strategy='mean').fit(X)
X=[[np.nan,2],[6,np.nan],[7,6]]
print(imp.transform(X))
#填充稀疏矩阵
import scipy.sparse as sp
imp=SimpleImputer(missing_values=np.nan,strategy='mean').fit(X)
X=sp.csc_matrix([[-1,2],[6,-1],[7,6]])
print(imp.transform(X).toarray())
#填充pandas类别数据
import pandas as pd
df=pd.DataFrame([["a","x"],[np.nan,"y"],["a",np.nan],["b","y"]])
imp=SimpleImputer(strategy='most_frequent').fit(df)
print(imp.transform(df))
2.同类均值/中位数/众数补全

对样本进行分类后,根据同类其他数据该属性的均值补全,均值不可行,尝试用众数(most_frequent)或中位数(median)补全。

3.固定值补全

用固定值补全缺失的属性值

4.建模预测

利用机器学习的方法,将缺失属性作为预测目标进行预测,将样本是否缺少该属性划分训练集和测试集,采用回归,决策树等机器学习算法训练模型,再利用训练得到的模型预测测试集中样本该属性的数值。
这个方法的缺陷是如果其他属性与缺失属性无关,则预测结果毫无意义,如果预测结果非常准确,则说明这个缺失属性没有必要纳入数据集中。

5.高维映射

通常特征不是连续值,而是分类值,这样的特征可以有效的编码为整数。将属性映射到高维空间,采用**独热编码(one-hot)**技术。将包含K个离散取值范围的属性值扩展为K+1个属性值,若该属性值缺失,则扩展后的第K+1个属性值置为1。

X_train= [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
from sklearn.preprocessing import OneHotEncoder
enc=preprocessing.OneHotEncoder()
enc.fit(X_train)
X_test=[['female', 'from US', 'uses Safari'],['male', 'from Europe', 'uses Safari']]
print(enc.transform(X_test).toarray())
print(enc.categories_)#查看编码规则的接口
#如果测试集中出现了训练集中没有的数值属性,需要单独手动编码
import pandas as pd
df=pd.DataFrame([['A'],['B']])
dic={'A':0,'B':1}
df[0]=df[0].map(dic)
print(df)

这种方法是最精确的做法,完整保留了原数据的全部信息,不用考虑缺失值,缺点是增加了数据的维度,计算量大大增加,且只有在样本量非常大时效果才好。

6.多重插补

多重插补认为待插补的值是随机的,实际上通常是估计出待插补的值,再加上不同的噪声,形成多组可选插补值,根据某种选择依据,选出最合适的插补值。

7.压缩感知和矩阵补全

压缩感知通过利用信号本身所具有的稀疏性,从部分观测样本中回复原信号。压缩感知分为感知测量和重构恢复两个阶段。

  • 感知测量:此阶段对原始信号处理以获得稀疏样本表示。常用的手段是傅里叶变换、小波变换、字典学习、稀疏编码等。
  • 重构恢复:此阶段基于稀疏性从少量观测中恢复原信号。这是压缩感知和核心。
8.手动补全

结合业务手动对缺失值插补,这种方法需要对问题领域有很高的认识和理解,如果确实数据较多,会比较费时费力。

9.最近邻补全

寻找与该样本最接近的样本,使用其该属性数值来补全。

处理异常值

异常值分析是检验数据是否有录入错误以及含有不和常理的数据。忽视异常值是非常危险的,不加剔除把异常值包括近数据的计算分析过程中,对结果会产生不良影响。
异常值是指观测中的个别值,其数值明显偏离其余的观测值。异常值也称为离群点,异常值分析也称为离群点分析。

异常值检测

1. 简单统计

用pandas库的descirbe()方法观察数据的描述性统计。

data.describe([0.01,0.03,0.1,0.25,0.5,0.75,0.9,0.97,0.99]).T

或者使用散点图观察异常值。
在这里插入图片描述

2. 3∂原则

3∂原则的前提假设:数据服从正态分布。在3∂原则下,数值如超过3倍标准差,则将其视为异常值。正负3∂的概率是99.7%,那么距离平均值3∂之外的值出现的概率为P(|x-u| > 3∂) <= 0.003,属于极个别的小概率时间。如果数据不服从正太分布,也可以用远离平均值多少倍标准差来描述。
在这里插入图片描述

#提取出测试集的所有异常值的索引
deltest = []
for i in col:
    bool_ = np.abs((Xtest.loc[:,i] - Xtrain.loc[:,i].mean())/Xtrain.loc[:,i].std())>3
    ind = Xtest[bool_].index
    deltest.extend(list(ind))
#去重之后有异常值的行索引
deltest1 = list(set(deltest)) 
#删除训练集特征的异常值
Xtrain = Xtrain.drop(index=deltrain1)
3. 箱线图

这种方法是利用箱线图的四分位距(IQR)对异常值进行检测。箱线图的定义如下:
在这里插入图片描述
四分位距(IQR)就是上四分位与下四分位的差值。而我们通过IQR的1.5倍为标准,规定:超过上四分位+1.5倍IQR,或者下四分位-1.5倍IQR的点为异常值。python代码实现:

Percentile = np.percentile(df['length'],[0,25,50,75,100])
IQR = Percentile[3] - Percentile[1]
UpLimit = Percentile[3]+ageIQR*1.5
DownLimit = Percentile[1]-ageIQR*1.5

也可以用seaborn的可视化方法boxplot来实现:

f,ax=plt.subplots(figsize=(10,8))
sns.boxplot(y='length',data=df,ax=ax)
plt.show()

以上三种方法是比较简单的异常值检测方法,接下来是一些较复杂的异常值检测方法。

4. 基于模型预测

顾名思义,该方法会构建一个概率分布模型,并计算对象符合该模型的概率,将低概率对象视为异常点。
如果模型是簇的组合,则异常点是不在任何簇的对象;如果模型是回归,异常点是远离预测值的对象。
优缺点:

  • 有坚实的统计学理论基础,当存在充分的数据和所用的检验类型的知识时,这些检验可能非常有效;
  • 对于多元数据,可用的选择少一些,并且对于高维数据,这些检测可能性很差。
5.基于近邻度的离群点检测

**一个对象的离群点得分由它的KNN距离给定。**k的取值会影响离群点的得分,如果k太小,则少量的临近离群点会导致较低的离群点得分;如果k太大,则点数小于k的簇中所有的对象可能都成了离群点。为了增强鲁棒性,可以采用k个最近邻的平均距离。
优缺点:

  • 简单;
  • 基于近邻的方法需要O(m^2)的时间,大数据集不适用;
  • k的取值导致该方法对参数选择敏感;
  • 不能处理具有不同密度区域的数据集,因为它使用全局阈值,不能考虑这种密度的变化。
6.基于密度的离群点检测

一种常用的定义密度的方法是:定义密度为到k个最近邻的平均距离的倒数。如果该距离小,则密度高,反之亦然。
另一种密度定义是使用DBSCAN聚类算法使用的密度定义,即一个对象的密度等于该对象指定距离d内对象的个数。
优缺点:

  • 给出了对象是离群点的定量度量,并且即使数据具有不同的区域也能很好的处理;
  • 与基于距离的方法一样,这些方法必然具有O(m^2)的时间复杂度。对于低维数据使用特定的数据结构可以达到O(mlogm);
  • 参数选择困难,虽然LOF算法通过观察不同的k值取得最大离群点得分来处理该问题,但仍要选择这些值得上下界。
7.基于聚类的离群点检测

一个对象是基于聚类的离群点,如果该对对象不属于任何簇,那么该对象属于离群点。
离群点对初始聚类的影响:如果通过聚类检测离群点,由于离群点影响聚类,存在一个问题:聚类结果是否有效。这也是K-means算法的缺点,对离群值敏感。为了解决这个问题,可以使用对象聚类;删除离群点;再次对象聚类(这个不能保证是最优的结果)。
优缺点:

  • 基于线性和接近线性复杂度(k均值)的聚类技术来发现离群点可能是高度有效的;
  • 簇的定义可以认为是离群点的补集,因此可以同时发现簇和离群点;
  • 产生的离群点集和它们的得分可能非常依赖所用的簇的个数和数据中离群点的存在性;
  • 聚类算法产生的簇的质量对该算法产生的离群点的质量影响大。
8.专门的离群点检测

除了以上提及的方法,还有两个专门用于检测异常点的方法比较常用:One Class SVM和Isolation Forest。

异常值处理

  • 删除含有异常值的记录:直接将含有异常值的记录删除;
  • 视为缺失值:用缺失值的处理方法处理异常值;
  • 平均值修正:用前后两个观测值的平均值修正异常值;
  • 不处理:直接在具有异常值的数据集上进行数据挖掘。
    将含有异常值的记录直接删除的方法简单易行,但缺点也很明显,在观测值很少的情况下,这种删除会造成样本量不足,可能会改变变量的原有分布,从而造成分析结果的不准确。视为缺失值处理的好处是可以利用现有变量的信息,对异常值(缺失值)进行填补
    在很多情况下,要先分析异常值出现的可能原因,在判断异常值是否应该舍弃,如果是正确的数据,可以直接在具有异常值的数据集上进行挖掘建模。

处理数据不平衡问题

1.扩充数据集

首先应该考虑数据集的扩充,在刚刚图片数据集扩充一节介绍了多种数据扩充的办法,而且数据越多,给模型提供的信息也越大,更有利于训练出一个性能更好的模型。
如果在增加小类样本数量的同时,又增加了大类样本数据,可以考虑放弃部分大类数据(通过对其进行欠采样方法)。

2.尝试其他评价指标

一般分类任务最常使用的评价指标就是准确度了,但它在类别不平衡的分类任务中并不能反映实际情况,原因就是即便分类器将所有类别都分为大类,准确度也不会差,因为大类包含的数量远远多于小类的数量,所以这个评价指标会偏向于大类类别的数据。
其他可以推荐的评价指标有以下几种

  • 混淆矩阵:实际上这个也是在分类任务会采用的一个指标,可以查看分类器对每个类别预测的情况,其对角线数值表示预测正确的数量;
  • 精确度(Precision):表示实际预测正确的结果占所有被预测正确的结果的比例,P=TP / (TP+FP)
  • 召回率(Recall):表示实际预测正确的结果占所有真正正确的结果的例,R = TP / (TP+FN)
  • F1 得分(F1 Score):精确度和召回率的加权平均,F1=2PR / (P+R)
  • Kappa (Cohen kappa)
  • ROC 曲线(ROC Curves):常被用于评价一个二值分类器的优劣,而且对于正负样本分布变化的时候,ROC曲线可以保持不变,即不受类别不平衡的影响。

其中 TP、FP、TN、FN 分别表示正确预测的正类、错误预测的正类、预测正确的负类以及错误预测的负类。图例如下:
在这里插入图片描述

3.对数据集进行重采样

可以使用一些策略该减轻数据的不平衡程度。该策略便是采样(sampling),主要有两种采样方法来降低数据的不平衡性。

  • 对小类的数据样本进行采样来增加小类的数据样本个数,即过采样(over-sampling ,采样的个数大于该类样本的个数)。
  • 对大类的数据样本进行采样来减少该类数据样本的个数,即欠采样(under-sampling,采样的次数少于该类样本的个素)。
    采样算法往往很容易实现,并且其运行速度快,并且效果也不错。 一些经验法则:
  • 考虑对大类下的样本(超过 1 万、十万甚至更多)进行欠采样,即删除部分样本;
  • 考虑对小类下的样本(不足 1万甚至更少)进行过采样,即添加部分样本的副本;
  • 考虑尝试随机采样与非随机采样两种采样方法;
  • 考虑对各类别尝试不同的采样比例,比一定是 1:1,有时候 1:1 反而不好,因为与现实情况相差甚远;
  • 考虑同时使用过采样与欠采样。

4.尝试人工生成数据样本

一种简单的人工样本数据产生的方法便是,对该类下的所有样本每个属性特征的取值空间中随机选取一个组成新的样本,即属性值随机采样
你可以使用基于经验对属性值进行随机采样而构造新的人工样本,或者使用类似朴素贝叶斯方法假设各属性之间互相独立进行采样,这样便可得到更多的数据,但是无法保证属性之前的线性关系(如果本身是存在的)。
有一个系统的构造人工数据样本的方法 SMOTE(Synthetic Minority Over-sampling Technique)。SMOTE 是一种过采样算法,它构造新的小类样本而不是产生小类中已有的样本的副本,即该算法构造的数据是新样本,原数据集中不存在的。
它基于距离度量选择小类别下两个或者更多的相似样本,然后选择其中一个样本,并随机选择一定数量的邻居样本,然后对选择的那个样本的一个属性增加噪声,每次处理一个属性。这样就构造了更多的新生数据。

5.尝试不同分类算法

强烈建议不要对待每一个分类都使用自己喜欢而熟悉的分类算法。应该使用不同的算法对其进行比较,因为不同的算法适用于不同的任务与数据。
决策树往往在类别不均衡数据上表现不错。它使用基于类变量的划分规则去创建分类树,因此可以强制地将不同类别的样本分开。目前流行的决策树算法有:C4.5、C5.0、CART和Random Forest等。

6.尝试对模型进行惩罚

你可以使用相同的分类算法,但使用一个不同的角度,比如你的分类任务是识别那些小类,那么可以对分类器的小类样本数据增加权值,降低大类样本的权值(这种方法其实是产生了新的数据分布,即产生了新的数据集),从而使得分类器将重点集中在小类样本身上。
一个具体做法就是,在训练分类器时,若分类器将小类样本分错时额外增加分类器一个小类样本分错代价,这个额外的代价可以使得分类器更加“关心”小类样本。如 penalized-SVM 和 penalized-LDA 算法。
如果你锁定一个具体的算法时,并且无法通过使用重采样来解决不均衡性问题而得到较差的分类结果。这样你便可以使用惩罚模型来解决不平衡性问题。但是,设置惩罚矩阵是一个复杂的事,因此你需要根据你的任务尝试不同的惩罚矩阵,并选取一个较好的惩罚矩阵。

7.尝试一个新的角度理解问题

从一个新的角度来理解问题,比如我们可以将小类的样本作为异常点,那么问题就变成异常点检测与变化趋势检测问题。

  • 异常点检测:即是对那些罕见事件进行识别。如通过机器的部件的振动识别机器故障,又如通过系统调用序列识别恶意程序。这些事件相对于正常情况是很少见的。
  • 变化趋势检测:类似于异常点检测,不同在于其通过检测不寻常的变化趋势来识别。如通过观察用户模式或银行交易来检测用户行为的不寻常改变。
    将小类样本作为异常点这种思维的转变,可以帮助考虑新的方法去分离或分类样本。这两种方法从不同的角度去思考,让你尝试新的方法去解决问题。

8.尝试创新

仔细对问题进行分析和挖掘,是否可以将问题划分为多个更小的问题,可以尝试如下方法:

  • 将你的大类压缩成小类;
  • 使用 One Class 分类器(将小类作为异常点);
  • 使用集成方式,训练多个分类器,然后联合这些分类器进行分类;
    对于类别不平衡问题,还是需要具体问题具体分析,如果有先验知识可以快速挑选合适的方法来解决,否则最好就是逐一测试每一种方法,然后挑选最好的算法。最重要的还是多做项目,多积累经验,这样遇到一个新的问题,也可以快速找到合适的解决方法。

特征缩放

特征缩放主要分为两种方法,归一化和正则化。

归一化

1.归一化:也称为标准化,这里不仅仅是对特征,实际上对于原始数据也可以进行归一化处理,它是将特征(或者数据)都缩放到一个指定的,大致相同的数据区间内。
2.归一化的原因:

  • 某些算法要求样本数据或特征的数值具有零均值和单位方差

  • 为了消除样本数据或者特征之间的量纲影响。如下图所示是包含两个属性的目标函数的等高线。
    数量级的差异将导致量级较大的属性占主导地位,从左图可以看到量级较大的属性会让椭圆的等高线压缩为直线,使得目标函数仅依赖于该属性。
    数量级的差异会导致迭代收敛速度减慢。原始的特征进行梯度下降时,每一步梯度的方向会偏离最小值(等高线中心点)的方向,迭代次数较多且学习率必须非常小,否则非常容易引起宽幅震荡。但经过标准化后,每一步梯度的方向都几乎指向最小值方向,迭代次数较少。
    所有依赖于样本距离的算法对数据的数量级都非常敏感。
    在这里插入图片描述
    3.常用的两种归一化方法:

  • 线性函数归一化(Min-Max Scaling)。它对原始数据进行线性变换,使得结果映射到[0,1]范围内,实现对原始数据的等比缩放,公式: x’ = (x - X_min) / (X_max - X_min)

  • 零均值归一化(Z-Score Normalization)。将原始数据映射到均值为零,标准差为1的分布上,公式:x’ = (x - μ)/σ

data_std=(data-data.mean(axis = 0))/(data.std(axis = 0))

4.如果数据分成训练集、验证集、测试集,那三个数据集都要用相同的归一化参数,数值都是通过训练集计算得到的,即上述两种方法中的最大值、最小值、均值和方差都是训练集的,可以理解为验证集测试集都是未知数据。

5.归一化不是万能的,在实际应用中,通过梯度下降法求解的模型是需要归一化的,这包括线性回归、逻辑回归、支持向量机、神经网络等模型。但决策树模型不需要,以C4.5为例,决策树在分裂节点的时候主要依据数据集D关于特征X的信息增益比,而信息增益比和特征是否归一化无关,归一化不会改变样本在特征X上的信息增益。

正则化

1.正则化是将样本或者特征的某个范数(L1或L2)缩放到单位1
假设数据集为:
在这里插入图片描述
对样本首先计算Lp范数,得到:
在这里插入图片描述
正则化后的结果是:每个属性值除以其Lp范数
在这里插入图片描述

from sklearn import preprocessing
X = [[ 1., -1.,  2.],[ 2.,  0.,  0.],[ 0.,  1., -1.]]
x_normalized_l1=preprocessing.normalize(X,norm='l1',axis=0)
x_normalized_l2=preprocessing.normalize(X,norm='l2',axis=0)

2.正则化的过程是针对单个样本的,对每个样本将它缩放到单位范数。
归一化是针对单个属性的,需要用到所有样本在该属性上的值。

3.通常如果使用二次型(如点积)或者其他核方法计算两个样本之间的相似性时,该方法很有用。

特征编码

序号编码(Ordinal Encoding)

定义:序号编码一般用于处理类别间有大小关系的数据,转换后依然保留大小关系。

独热编码(One-hot Encoding)

定义:独热编码通常用于处理类别间不具有大小关系的特征。

优点:

  • 能够处理非数值属性。如:血型、性别等
  • 一定程度上扩充了特征。
  • 编码后的向量是稀疏向量,只有1位是1,其余都是0,可以利用向量的稀疏来节省存储空间。
  • 能处理缺失值。所有位都是零,表明缺失。这时可以采用高维映射的方法,用N+1位来表示缺失值。

缺点:
1.高维特征带来的问题:

  • KNN算法中,高维空间中两点之间的距离很难得到有效的衡量;
  • 逻辑回归中,参数的数量会随维度的增高而增加,导致模型复杂,出现过拟合问题;
  • 通常只有部分维度是对分类、预测有帮助的,需要借助特征选择来降低维度;

2.决策树模型不推荐对离散特征进行独热编码:

  • 产生样本切分不平衡问题,此时切分增益会非常小。
    比如对血型做独热编码操作,那么对每个特征是否 A 型、是否 B 型、是否 AB 型、是否 O 型,会有少量样本是 1 ,大量样本是 0。这种划分的增益非常小,因为拆分之后:
    较小的那个拆分样本集,它占总样本的比例太小。无论增益多大,乘以该比例之后几乎可以忽略。
    较大的那个拆分样本集,它几乎就是原始的样本集,增益几乎为零。

  • 影响决策树的学习。
    决策树依赖的是数据的统计信息。而独热码编码会把数据切分到零散的小空间上。在这些零散的小空间上,统计信息是不准确的,学习效果变差。
    本质是因为独热编码之后的特征的表达能力较差。该特征的预测能力被人为的拆分成多份,每一份与其他特征竞争最优划分点都失败。最终该特征得到的重要性会比实际值低。

二进制编码(Binary Encoding)

二进制编码主要分为两步:
1.先采用序号编码给每个类别赋予一个类别ID;
2.接着将类别ID对应的二进制编码作为结果。
二进制本质上是利用二进制对类别ID进行哈希映射,最终得到0/1特征向量,并且特征维度小于独热编码,更加节省存储空间。

二元化

将数值型的属性转化为布尔型的属性。通常用于假设属性取值分布是伯努利分布的情形。
指定一个阈值m,>=m,二元化后取1,否则取0。m是一个关键的超参数,它的取值需要根据模型和具体业务来确定。

离散化

离散化就是将连续的数值属性转化为连续的数值属性。

  • 线性模型
    海量离散特征+简单模型
    优点:模型简单
    缺点:特征工程困难,但一旦有成功经验就可以推广,可以并行研究

  • 非线性模型
    少量连续特征+复杂模型
    优点:不需要复杂的特征工程
    缺点:模型负责

分箱

分箱是离散化的常用方法。
1.将所有样本在连续的数值属性j的取值从小到大排列。
2.从小到大依次选择分箱边界。分箱的数量以及每个箱子的大小都是超参数,需要指定。
3.给定属性j的取值a,判断a在哪个箱子中,将其划分到对应编号的箱子中,属性值取编号。

确定分箱数量和边界的方法

根据业务经验指定。
根据模型指定:根据具体任务来训练分箱之后的数据集,通过超参数搜索来确定最优的分箱数量和分箱边界。

import numpy as np
from sklearn import preprocessing
X=np.array([[-1,5,15,28],[0,6,14,3.],[6.,3,11.8,6]])
est=preprocessing.KBinsDiscretizer(n_bins=[2,2,2,2],encode='ordinal',strategy='kmeans').fit(X)
est.transform(X)
print(est)
print(est.bin_edges_)#返回每个箱子的边缘

选择分箱大小的经验:

  • 箱子必须足够小,使得箱内属性取值的变化对样本标记的影响基本在一个不大的范围内。
  • 箱子大小必须足够大,使每个箱子里都有足够多的样本。如果箱内样本太少,随机性太大,不具有统计意义。
  • 每个桶内样本尽量分布均匀。

数据离散化的特性:

  • 离散化之后得到稀疏矩阵,内积运算更快,方便存储。
  • 离散化之后的特征对于异常数据更具鲁棒性。
  • 逻辑回归属于广义线性模型,表达能力受限,只能描述线性关系。数据离散化后,相当于引入了非线性,提升了模型的表达能力。
  • 离散化之后可以进行特征交叉。
  • 离散化之后,模型更稳定,但要注意区间连接处值的处理。
  • 特征离散化简化了逻辑回归模型,降低了过拟合风险。
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值