#数据处理总结

1.异常值的处理

1.基于正态分布的方法

通过数据分布图,发现数据大致呈正态分布的情况下(68%的数据位于一个标准差内,95%的数据位于两个标准差内,99%的数据位于三个标准差内)可以使用正态分布的方法来去除异常值,我们一般认为大于三个标准差以外的数据为异常值(对于一些较严的可以用两个标准差)

import pandas as pd
from scipy import stats

# 加载你的数据到一个Pandas DataFrame
# dataframe = pd.read_csv('yourfile.csv')

# 假设我们已有一个DataFrame叫做dataframe,且包含我们需要分析的feature列
mean = dataframe['feature'].mean()
std = dataframe['feature'].std()

# 定义异常值的边界
k = 3  # 或者根据你的需求选择2
lower_bound = mean - k * std
upper_bound = mean + k * std

# 检测异常值
outliers = dataframe[(dataframe['feature'] < lower_bound) | (dataframe['feature'] > upper_bound)]
print("Outliers using Normal Distribution:")
print(outliers)

2.四分位间距法

当数据不符合正态分布时,可以考虑四分位间距法(IQR),IQR不要求数据符合正态分布,我们所采取的方法是将数据四等分后处理,处理步骤如下:Q1=0.25*DATA, Q3=0.75*DATA, IQR=Q3-Q1, lowerbound=DATA-1.5*IQR, upperbound=DATA+1.5*IQR

import pandas as pd

# 加载你的数据到一个Pandas DataFrame
# dataframe = pd.read_csv('yourfile.csv')

# 假设我们已有一个DataFrame叫做dataframe,且包含我们需要分析的feature列
Q1 = dataframe['feature'].quantile(0.25)
Q3 = dataframe['feature'].quantile(0.75)
IQR = Q3 - Q1

# 定义异常值的边界
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 检测异常值
outliers = dataframe[(dataframe['feature'] < lower_bound) | (dataframe['feature'] > upper_bound)]
print("Outliers using IQR:")
print(outliers)

3.z-score方法

z-score是指标准分数,一般也是在数据处于正态分布下会采取的方式,优势是可以将不同量级的数据变成同一数量级进行计算,坏处是会抹去数值原本的意义,且数据不处于正态分布的情况下会造成较大误差。一般我们规定|z|小于等于3为正常值,大于三则为异常值

z=(x-\mu )/\xi,其中\mu表示均值,\xi表示标准差

import pandas as pd
from scipy import stats

# 以某个CSV文件作为例子加载数据
# dataframe = pd.read_csv('data.csv')

# 计算每个数据点的Z-score
z_scores = stats.zscore(dataframe['feature'])

# 设置一个阈值(通常是3或者你选择的任何数)
z_score_threshold = 3

# 识别异常值
outliers = dataframe[(z_scores < -z_score_threshold) | (z_scores > z_score_threshold)]

# 查看异常值
print(outliers)

# 移除异常值后的数据
dataframe_clean = dataframe[(z_scores >= -z_score_threshold) & (z_scores <= z_score_threshold)]

4.孤立森林(isolation forest)

孤立森林和随机森林都是随机生成许多棵决策树,通过随机选取决策树来建立模型,但孤立森林的思想是在很大的数据集里,往往异常值出现在那些离群点(离高密度集较远的点),因此孤立森林往往用于较大的数据集或者高维数据里,过程是:

1.选择一个样本集中的特征,并随机选择一个特征值范围。
2.根据选择的特征和范围,将样本集中的数据点分割成左右两个子集。
3.重复步骤1和2,将每个子集继续分割,直到达到预定的停止条件,例如树的高度达到最大限制或子集中只剩下一个数据点。
4.构建一棵二叉树,其中每个数据点都是树节点。树的深度即为数据点的路径长度。
5.重复步骤1至4,构建多棵独立的随机树。
6.对于新的数据点,通过计算其在每棵树中的路径长度来判断其是否为异常点。如果路径长度较短,则该数据点被认为是异常点。

from sklearn.ensemble import IsolationForest

# 假设X是我们的输入数据
X = ... # 数据矩阵

# 初始化孤立森林对象
isof = IsolationForest(n_estimators=100, contamination='auto')

# 拟合并预测异常值:1表示正常,-1表示异常
preds = isof.fit_predict(X)

# 获取异常值的数据点
anomalies = X[preds == -1]

5.DBSCAN算法(比较复杂,不建议使用)

对于聚类算法,在scikit-learn中,DBSCAN算法类为sklearn.cluster.DBSCAN。要熟练的掌握用DBSCAN类来聚类,除了对DBSCAN本身的原理有较深的理解以外,还要对最近邻的思想有一定的理解。   DBSCAN重要参数也分为两类,一类是DBSCAN算法本身的参数,一类是最近邻度量的参数:   1)eps: DBSCAN算法参数,即我们的ϵ-邻域的距离阈值,和样本距离超过ϵ的样本点不在ϵ-邻域内。默认值是0.5.一般需要通过在多组值里面选择一个合适的阈值。eps过大,则更多的点会落在核心对象的ϵ-邻域,此时我们的类别数可能会减少, 本来不应该是一类的样本也会被划为一类。反之则类别数可能会增大,本来是一类的样本却被划分开。   2)min_samples: DBSCAN算法参数,即样本点要成为核心对象所需要的ϵ-邻域的样本数阈值。默认值是5. 一般需要通过在多组值里面选择一个合适的阈值。通常和eps一起调参。在eps一定的情况下,min_samples过大,则核心对象会过少,此时簇内部分本来是一类的样本可能会被标为噪音点,类别数也会变多。反之min_samples过小的话,则会产生大量的核心对象,可能会导致类别数过少。   3)metric:最近邻距离度量参数。可以使用的距离度量较多,一般来说DBSCAN使用默认的欧式距离(即p=2的闵可夫斯基距离)就可以满足我们的需求。可以使用的距离度量参数有:     a) 欧式距离 “euclidean”     b) 曼哈顿距离 “manhattan”     c) 切比雪夫距离“chebyshev”     d) 闵可夫斯基距离 “minkowski”     e) 带权重闵可夫斯基距离 “wminkowski”     f) 标准化欧式距离 “seuclidean”: 即对于各特征维度做了归一化以后的欧式距离。此时各样本特征维度的均值为0,方差为1.     g) 马氏距离“mahalanobis”:当样本分布独立时,马氏距离等同于欧式距离。  还有一些其他不是实数的距离度量,一般在DBSCAN算法用不上,这里也就不列了。      4)algorithm:最近邻搜索算法参数,算法一共有三种,第一种是蛮力实现,第二种是KD树实现,第三种是球树实现。对于这个参数,一共有4种可选输入,‘brute’对应第一种蛮力实现,‘kd_tree’对应第二种KD树实现,‘ball_tree’对应第三种的球树实现, ‘auto’则会在上面三种算法中做权衡,选择一个拟合最好的最优算法。需要注意的是,如果输入样本特征是稀疏的时候,无论我们选择哪种算法,最后scikit-learn都会去用蛮力实现‘brute’。个人的经验,一般情况使用默认的 ‘auto’就够了。 如果数据量很大或者特征也很多,用"auto"建树时间可能会很长,效率不高,建议选择KD树实现‘kd_tree’,此时如果发现‘kd_tree’速度比较慢或者已经知道样本分布不是很均匀时,可以尝试用‘ball_tree’。而如果输入样本是稀疏的,无论你选择哪个算法最后实际运行的都是‘brute’。   5)leaf_size:最近邻搜索算法参数,为使用KD树或者球树时, 停止建子树的叶子节点数量的阈值。这个值越小,则生成的KD树或者球树就越大,层数越深,建树时间越长,反之,则生成的KD树或者球树会小,层数较浅,建树时间较短。默认是30. 因为这个值一般只影响算法的运行速度和使用内存大小,因此一般情况下可以不管它。   6) p: 最近邻距离度量参数。只用于闵可夫斯基距离和带权重闵可夫斯基距离中p值的选择,p=1为曼哈顿距离, p=2为欧式距离。如果使用默认的欧式距离不需要管这个参数。   以上就是DBSCAN类的主要参数介绍,需要调参的两个参数eps和min_samples,这两个值的组合对最终的聚类效果有很大的影响。

from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler

# 假设X是我们的输入数据
X = ... # 数据矩阵

# 标准化数据
X = StandardScaler().fit_transform(X)

# 初始化DBSCAN对象
db = DBSCAN(eps=0.5, min_samples=5).fit(X)

# 聚类标签
labels = db.labels_

# 获取噪声点(异常值)
noise = X[labels == -1]

虽然DBSCAN算法在整个参数中求解比较复杂,但是他可以有效的找到噪音值(异常值)

2.建立模型前的数据处理方法

1.过滤法

通常在预处理的时候使用,独立于任何的机器学习模型,往往和特征自身的性质有关

1.方差过滤

在特征很多的时候,往往会采取将方差为0的特征过滤掉(方差为0或方差很小往往对模型的建立无法起决定性作用)

1.过滤方差为0的特征

from sklearn.feature_selection import VarianceThreshold
selector=VarianceThreshold()
X_var0=selector.fit_transform(X)
X_var0.shape

2.过滤方差为中位数的特征

from sklearn.feature_selection import VarianceThreshold
import numpy as np
X_fsvar=VarianceThreshold(np.median(X.var().value)).fit_transform(X)
x_fsvar

3.特征为二分类时的过滤

#若特征是伯努利随机变量,假设p=0.8,即二分类特征中某种分类占到80%以上的时候删除特征
x_bvar = VarianceThreshold(.8*(1-.8)).fit_transform(x)
x_bvar.shape
>(42000, 685)

注意:方差过滤一般对于随机森林这种不需要遍历特征的模型影响较小,而对于KNN,决策树等需要遍历特征的模型往往有显著提升速度的影响

2.相关性过滤

1.皮尔逊相关系数

用于度量两个连续变量之间的线性关系的强度和方向。其值范围从-1到1,1表示完全正线性关系,-1表示完全负线性关系,而0表示没有线性关系。

2.斯皮尔曼等级相关系数 

用于衡量两个变量之间的单调关系的强度和方向,无须假定数据是正态分布的或线性相关的。

3.肯德尔等级相关系数

也是一种衡量非参数关系(即变量的分布不遵循特定分布)强度的方法。

4.相关性矩阵

是一个表格,它显示了数据集中所有变量(或特征)之间的相关系数。每个单元格(i,j)的值表示变量i和变量j之间的相关系数值。当我们谈论数据集的相关性矩阵时,我们通常指的是皮尔逊相关系数

在相关性矩阵中:

  • 对角线上的值总是1,因为变量和自己的相关系数总是完全正相关。
  • 矩阵是对称的,因为变量A和变量B之间的相关性与变量B和变量A之间的相关性是一样的。
import pandas as pd

# 假设df是Pandas DataFrame
X = df.drop('target', axis=1)  # 去掉目标列

# 计算相关性矩阵
corr_matrix = X.corr()

# 设定相关性高的阈值
high_corr_var = set()
threshold = 0.8

for i in range(len(corr_matrix.columns)):
    for j in range(i+1, len(corr_matrix.columns)):
        if abs(corr_matrix.iloc[i, j]) > threshold:
            colname = corr_matrix.columns[i]  # 获取列名
            high_corr_var.add(colname)
            
# 从数据集中移除高相关变量
X_filtered = X.drop(columns=high_corr_var)

 注意:高相关的特征并不一定意味着对目标变量影响小。

3.卡方检验

卡方检验的原理是比较实际观察值和期望观察值之间的差异,就是将每个特征与目标特征进行相关性的比较。具体步骤如下:

  1. 计算每个特征与目标变量之间的卡方值。
  2. 根据卡方值的大小进行排序,选择具有最高卡方值的特征。
  3. 根据设定的阈值,选择卡方值大于阈值的特征。
import pandas as pd
from sklearn.feature_selection import SelectKBest, chi2

# 读取数据集
data = pd.read_csv('data.csv')

# 将特征和目标变量分开
X = data.drop('target_variable', axis=1)
y = data['target_variable']

# 使用SelectKBest和chi2进行特征选择
selector = SelectKBest(score_func=chi2, k=5)
X_new = selector.fit_transform(X, y)

# 输出选择的特征
features = X.columns[selector.get_support()]
print(features)
 

4.信息增益(一般用于决策树,SVM和k-means)

信息增益是一种经典的特征选择方法,用于在特征工程中选择最佳的特征。它衡量了一个特征对于分类任务的贡献程度,信息增益越大,意味着使用该特征进行分类能够获得更多的信息。

信息增益的计算基于熵的概念。熵是表示系统中不确定性的度量,可以理解为信息的混乱程度。在分类任务中,熵越大,表示样本的类别分布越均匀,即不确定性越大。

计算信息增益的步骤如下:
1. 计算原始数据集的熵(标签的熵)。
2. 针对每个特征,计算该特征的条件熵。
3. 用原始数据集的熵减去条件熵,即得到信息增益。

信息增益是一种用于决策树算法中的特征选择方法。它衡量了一个特征对于分类任务的贡献程度,即特征通过它的划分能够带来的信息增益。

优点:

  1. 信息增益简单直观,易于计算。它使用基于信息熵的方法,不需要假设任何概率分布,可以适用于各种类型的数据集。
  2. 信息增益能够考虑特征间的相互作用,通过评估每个特征的独立贡献,可以选择多个相关特征以提高分类性能。

缺点:

  1. 信息增益偏向于选择具有较多取值的特征。对于取值较多的特征,其划分可以带来更多的信息增益,但是对于其他特征而言可能并不具有更好的分类能力。
  2. 信息增益对于取值较多的特征也更容易产生过拟合,因为很容易在训练集上出现过多的划分,对于新的未知数据可能不具有泛化能力。

使用注意事项:

  1. 对于存在缺失值的数据,需要进行适当的处理,以避免对信息增益的计算产生偏差。
  2. 在特征选择时,信息增益只考虑了特征与分类之间的关系,而忽略了特征之间的相关性。因此,在实际应用中,需要综合考虑特征相关性等其他因素。
  3. 信息增益容易受到取值较多的特征的影响,为了平衡这种影响,可以使用其他特征选择方法,如增益率、卡方检验等来辅助判断
import numpy as np
from collections import Counter

def entropy(labels):
    """计算熵"""
    label_counts = Counter(labels)
    probs = [count / len(labels) for count in label_counts.values()]
    return -np.sum(probs * np.log2(probs))

def conditional_entropy(feature, labels):
    """计算条件熵"""
    feature_values = np.unique(feature)
    probs = [np.mean(labels[feature == value]) for value in feature_values]    
    return np.sum(probs * entropy(labels[feature == value]) for value in feature_values)

def information_gain(feature, labels):
    """计算信息增益"""
    base_entropy = entropy(labels)
    return base_entropy - conditional_entropy(feature, labels)

# 示例数据
X = np.array([[1, 0], [1, 1], [0, 0], [0, 1]])
y = np.array([0, 0, 1, 1])

# 计算信息增益
for i in range(X.shape[1]):
    gain = information_gain(X[:, i], y)
    print(f"特征{i}的信息增益为:{gain}")
 

5.F-统计量

 原理: 基于方差分析(ANOVA),测试每个特征和目标变量之间的线性关系强度。

优点:

  1. 可以通过比较组间方差与组内方差的大小,判断特征与目标变量之间的关系强度。
  2. 相对简单易理解,不依赖于特征之间的线性关系。
  3. 可以用于不同分布的数据。

缺点:

  1. 对异常值敏感。异常值可能会引起方差的增加,从而影响F值的计算结果。
  2. 只能衡量特征与目标变量的关系强度,无法提供特征之间的相关性信息。

ANOVA F-value适用于以下机器学习模型:

  1. 线性回归模型:可以使用ANOVA F-value来选择对目标变量影响显著的特征,建立线性回归模型。
  2. ANOVA分类器:可以使用ANOVA F-value来选择最具显著性的特征,提高分类器的性能。

在使用ANOVA F-value时,通常需要进行参数寻找,以确定最佳的处理方式(如方差分析类型、自由度等)。参数寻找的过程可以使用交叉验证、网格搜索等方法。

from sklearn.feature_selection import SelectKBest, f_classif

# 假设X为特征数据,y为目标变量
selector = SelectKBest(f_classif, k=5)  # 选择最重要的5个特征
X_new = selector.fit_transform(X, y)
 

2.包裹法

2.1.RFE(递归特征消除)

其实本质就是我们校赛的时候使用的那种先通过随机森林确立十一个特征值中谁是最重要的,谁是第二重要的....以此类推他的思想是这样的:

1.对最初始的数据集进行异常值,缺失值等处理

2.对于数据集进行建模

3.删除最不重要的一个或几个特征值,更新数据集

4.回到步骤2,直到精确率提升确实不是很大的时候

通常我们一般使用随机森林来进行RFE

from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier

# 创建随机森林分类器
rf = RandomForestClassifier()

# 创建RFE对象,设置评估器为随机森林,选择保留的特征数量为10
rfe = RFE(estimator=rf, n_features_to_select=10)

# 使用RFE进行特征选择
selected_features = rfe.fit_transform(X, y)
 

2.SFS顺序特征选择

与RFE相反,SFS的核心思想是先建立一个空的数据集,然后针对每一个特征值,通过交叉验证等方式来得到每一个特征值对模型构建的影响,将最重要的特征值加入到空的数据集中,将影响最大的特征加入数据集,在影响最大的这个特征固定的情况下,将其他特征再次建模,判断影响程度。以此类推,直到数据集达到一定要求,一般这个模型也是使用随机森林,但是也可以使用逻辑回归等其他模型

from mlxtend.feature_selection import SequentialFeatureSelector
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 创建随机森林分类器
rf = RandomForestClassifier()

# 创建SFS对象,设置评估器为随机森林,选择保留的特征数量为2
sfs = SequentialFeatureSelector(estimator=rf, k_features=2, forward=True, scoring='accuracy', cv=5)

# 使用SFS进行特征选择
selected_features = sfs.fit_transform(X, y)
 

 注意:在数据集确定的情况下,当特征值数量较小的时候,我们一般认为SFS比RFE较快,但是SFS会偏好冗余的特征值,最好在使用SFS前先通过相关系数矩阵判断特征间的相关性

3.嵌入法

1.Lasso回归

在建立机器学习模型的时候,我们判断数据的拟合程度一般使用的是最小二乘法,其中需要运用到最小均方误差(MSE),对于一般的线性回归模型,最小均方误差的计算公式为:

在普通的线性回归模型中,我们通常会最小化均方误差(Mean Squared Error,MSE):

minimize:(1\n)* Σ(y_i - Σβ_j*x_ij)^2

在Lasso回归中,目标函数变为:

minimize: (1/2n) * Σ(y_i - Σβ_j*x_ij)^2 + λ * Σ|β_j|

这个\lambda就是我们选定的惩罚函数,由于加入了惩罚项,所以L1会将很多不重要的特征压缩为0,从而实现了特征选择,与此同时由于Lasso生成的是稀疏解,大部分特征的权重值都会被降到0,也有利于理解模型但是也存在缺点:

  1. 选择合适的 λ 有挑战性:λ 需要通过交叉验证选择,这可能增加计算复杂度和计算时间。
  2. 不能用于组特征选择:Lasso回归会倾向于选出其中的一个变量,并将其他共线性变量的系数压缩到零,不适合组特征选择。
  3. 不稳定性:对于高度相关的变量,Lasso 回归可能不是非常稳定,可能需要使用其变体如 Elastic Net(结合了 L1 和 L2 正则化)来解决这个问题。
from sklearn.linear_model import Lasso

# 创建Lasso回归模型对象
lasso = Lasso(alpha=0.1)

# 训练模型
lasso.fit(X, y)

# 获取特征系数
coefficients = lasso.coef_
 

2.岭回归

 懒得写了,贴一下https://zhuanlan.zhihu.com/p/654825350

4.三种方法比较的优缺点 

过滤法、包裹法和嵌入法是常用的特征选择方法,它们各自具有不同的优缺点。

  1. 过滤法(Filter Method):
  • 优点:
    • 计算效率高,适用于大型数据集。
    • 独立于具体的机器学习算法,可以作为预处理步骤。
    • 简单易实现,不需要训练模型。
  • 缺点:
    • 仅考虑特征本身的相关性,忽略了特征与目标变量之间的关系。
    • 无法准确评估特征对模型性能的影响。
    • 只能考虑单个特征,无法捕捉特征之间的交互效应。
  1. 包裹法(Wrapper Method):
  • 优点:
    • 考虑了特征与目标变量之间的关系,可以更准确地评估特征的重要性。
    • 能够捕捉特征之间的交互效应。
  • 缺点:
    • 计算复杂度较高,对于大型数据集可能不适用。
    • 可能导致过拟合,因为在训练模型时使用了特定的特征子集。
    • 对于特征空间较大的问题,包裹法可能会受到维度灾难问题的影响。
  1. 嵌入法(Embedded Method):
  • 优点:
    • 同时考虑了特征本身的相关性和特征与目标变量之间的关系。
    • 可以自动选择最优的特征子集,不需要额外的特征评估和模型训练过程。
    • 通常能够产生更好的模型性能。
  • 缺点:
    • 计算复杂度较高,尤其对于复杂的嵌入算法。
    • 可能受到选择的嵌入算法的特定假设或限制的影响。
    • 对于特征空间较大的问题,可能会面临维度灾难和计算资源限制的问题。

综上所述,过滤法适用于快速筛选出具有较大相关性的特征。包裹法则考虑特征与目标变量之间的关系,适用于特征子集的搜索,但计算复杂度较高。嵌入法结合了过滤法和包裹法的优点,可以自动选择最优的特征子集,但计算复杂度也较高。在选择特定的特征选择方法时,需要根据具体的问题、数据集规模和计算资源等因素进行权衡和

  • 28
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值