数据预处理,特征选择方法整理

数据进入模型之前,通常都需要进行预处理和特征选择,在查看了一些资料,借鉴他人的一些经验总结后,我将这些方法整理好,并写成函数,方便以后调用,也是对自己的学习和工作做了一个小总结,如有错误还请留言指正!

'''
统计数据中的空值比例
'''
def cal_null_info( input_data, * null_threshold):
'''
输入:需要处理的数据(为一个dataframe),可以选择是否输入空值比例的阈值
输出:如输入阈值,则返回null_rate, thre_null_val两个值
没有输入阈值,则只返回null_rate
'''
data_column = pd.Series(input_data.columns)
null_rate = []
notnull_index = []
thre_null_index = []
for i in range(input_data.shape[ 1]):
col_data = input_data.iloc[:, i]
null_val = float( len(col_data[col_data.isnull()])) / float( len(col_data))
# 输出空值比例
null_rate.append(null_val)
null_rate = pd.DataFrame(null_rate, index=data_column, columns=[ 'null_rate_val'])
null_rate = null_rate.applymap( lambda x: round(x, 3))
# 如果有输入阈值则返回null_rate, thre_null_val两个值
if null_threshold:
thre_null_val = null_rate[null_rate[ 'null_rate_val']>=null_threshold]
return null_rate, thre_null_val
else: # 没有输入阈值,则只返回null_rate
return null_rate

# null_rate, thre_null_val = cal_null_info(data[features], 0.1)
# print null_rate
# print thre_null_val

'''
缺失值处理
'''
def imputer_null_val( input_data, missing_value, input_strategy):
'''
输入: 需要处理的数据(DataFrame格式)
missing_values:缺失值(NaN)
strategy:替换策略(字符串)可以使用‘mean’,‘median’,‘most_freequent’ 替换nan值
'''
imp = Imputer( missing_values=missing_value, strategy=input_strategy)
output_data = imp.fit_transform(input_data)
output_data = pd.DataFrame(output_data, columns=input_data.columns)
return output_data

# print imputer_null_val(input_data=data[features], missing_value='NaN', input_strategy='mean')

'''
计算各个特征的均值和方差
'''
def cal_variance( input_data):
'''
输入:需要处理的数据(dataframe格式)
输出:各个特征所对应的均值和方差(一个dataframe格式)
'''
# 计算均值
feature_mean = pd.DataFrame(np.mean(input_data, axis= 0), index=input_data.columns, columns=[ 'mean'])
# 计算方差
feature_var = pd.DataFrame(np.var(input_data, axis= 0), index=input_data.columns, columns=[ 'variance'])
# 按照左右的index合并集合
feature_mean_var = pd.merge(feature_mean, feature_var, left_index= True, right_index= True)
return feature_mean_var
# print cal_variance(data)

'''
z-score 标准化
需要计算每个特征的均值和标准差, X = (X-X')/S 减均值再除以标准差
其均值为每个特征的均值,标准差为所有样本的标准差, 按照列(axis=0)进行计算
https://www.cnblogs.com/chaosimple/archive/2013/07/31/3227271.html (网址可借鉴)
标准化之后的数据范围在[-1,1]之间
'''
def z_score_scaler( input_data):
'''
输入:需要处理的数据特征向量(为一个dataframe)
输出:经过标准化处理后的dataframe
'''
output_data = input_data
for i in range(output_data.shape[ 1]):
col_data = output_data.iloc[:, i]
mean_val = col_data.mean()
std_val = col_data.std()
if std_val != 0:
output_data.iloc[:, i] = (col_data - mean_val) / std_val
else:
output_data.iloc[i, :] = 0
return output_data

'''
min_max标准化
公式为:(x-x.min()) / (x.max()-x.min())
min-max为每一个特征的最小值和最大值,按照列(axis=0)
标准化之后的数据范围在[0,1]之间
http://blog.csdn.net/leiting_imecas/article/details/54986045
https://www.cnblogs.com/chaosimple/archive/2013/07/31/3227271.html 网址可借鉴
'''
def min_max_scaler( input_data):
'''
输入:需要处理的数据特征向量(为一个dataframe)
输出:经过标准化处理后的dataframe
'''
output_data = input_data
for i in range(output_data.shape[ 1]):
row_data = output_data.iloc[:, i]
min_val = row_data.min()
max_val = row_data.max()
if max_val - min_val != 0:
output_data.iloc[:, i] = (row_data - min_val) / (max_val - min_val)
else:
output_data.iloc[:, i] = 0

return output_data

# print min_max_scaler(data[features])

'''
正则化(normalization)
将每个样本缩放到单位范数(每个样本的范数为1),如果后面要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。
Normalization的主要思想是对每个样本计算其p-范数,然后对该样本中每个元素除以该范数,这样处理的结果是使得每个处理后样本的p-范数(l1-norm,l2-norm)等于1。
p-范数的计算公式:||X||p=(|x1|^p+|x2|^p+...+|xn|^p)^1/p
'''
def normalization_data( input_data, norm_strategy):
'''
输入:需要处理的数据特征向量(为一个dataframe),处理的策略(l1或l2范数)
输出:经过正则化处理后的dataframe
'''
output_data = input_data
for i in range(output_data.shape[ 0]):
row_data = output_data.iloc[i, :]
if norm_strategy == 'l1':
norm_val = np.sum(row_data.map( abs))
output_data.iloc[i, :] = row_data / norm_val
elif norm_strategy == 'l2':
norm_val = np.sqrt(np.sum(row_data.map( lambda x: pow(x, 2))))
output_data.iloc[i, :] = row_data / norm_val

return output_data

# print normalization_data(data[features], norm_strategy='l1')


'''
计算各个特征和目标变量皮尔森相关系数, 只能判断线性相关性, 范围[-1,1]
# •0.8-1.0 极强相关
# •0.6-0.8 强相关
# •0.4-0.6 中等程度相关
# •0.2-0.4 弱相关
# •0.0-0.2 极弱相关或无相关
'''
def cal_pearson( input_data, obj_data, sort_para):
'''
输入: 特征向量的矩阵
目标变量
是否对输出进行排序
输出: pearson相关系数的数组,数组第i项为第i个特征的评分
'''
def per( x, y, x_mean, y_mean):
sum_up = 0.0
x_down = 0.0
y_down = 0.0
sum_down = 0.0
for i in range( len(x)):
sum_up += (x[i] - x_mean)*(y[i] - y_mean)
x_down += math.pow(x[i] - x_mean, 2)
y_down += math.pow(y[i] - y_mean, 2)
sum_down = math.sqrt(x_down * y_down)
p = sum_up / sum_down
return round(p, 3)

# 计算y的平均值
y_mean = np.mean(obj_data)
# 计算各个特征的x_mean
x_mean_features = []
for i in range(input_data.shape[ 1]):
x = input_data.iloc[:, i]
x_mean_features.append(np.mean(x))

feature_p_coef = []
for i in range(input_data.shape[ 1]):
x_col = input_data.iloc[:, i]
y = pd.Series(obj_data)
x_mean = x_mean_features[i]
p = per(x_col, y, x_mean, y_mean)
feature_p_coef.append(p)
# 输出一个DataFrame,存储各个特征向量的相关系数
pearson_val = pd.DataFrame(feature_p_coef, index=input_data.columns, columns=[ 'pearson_coef'])
if sort_para == 'true':
pearson_val = pearson_val.sort_values( by=[ 'pearson_coef'], ascending= False)
return pearson_val
if sort_para == 'false':
return pearson_val
# print cal_pearson(input_data=data[features], obj_data=data['score'], sort_para='true')
# print cal_pearson(input_data=data[features], obj_data=data['score'], sort_para='flase')


'''
计算各个变量之间的线性相关性,使用pearson相关系数来评定
一般输出两个系数:相关系数和检验系数P值,相关系数在[-1,1]之间,P值用来检验样本的显著水平
如果不显著,相关系数再高也没用,可能只是因为偶然因素引起的,那么多少才算显著,一般p值小于0.05就是显著了
通常需要p值小于0.1,最好小于0.05设甚至0.01,才可得出结论:两组数据有明显关系,如果p=0.5,远大于0.1,只能说明相关程度不明显甚至不相关.起码不是线性相关.
相关系数,也就是Pearson Correlation(皮尔逊相关系数),通常也称为R值,在确认上面指标显著情况下,再来看这个指标,一般相关系数越高表明两者间关系越密切.
R>0 代表连个变量正相关,即一个变大另一个随之变大
'''
def cal_pearson_features( input_data):
'''
输入: 特征向量的矩阵
输出: pearsonr相关系数的数组,
P值
'''
pearson_val = []
p_val = []
for i in range(input_data.shape[ 1]):
for j in range(input_data.shape[ 1]):
tt = pearsonr(data[features].iloc[:, i], data[features].iloc[:, j])
pearson_val.append(tt[ 0])
p_val.append(tt[ 1])
pearson_val = np.array(pearson_val).reshape( len(input_data.columns), len(input_data.columns))
pearson_val = pd.DataFrame(np.round(pearson_val, 3), columns=input_data.columns, index=input_data.columns)
p_val = np.array(p_val).reshape( len(input_data.columns), len(input_data.columns))
p_val = pd.DataFrame(p_val, columns=input_data.columns, index=input_data.columns)
return pearson_val, p_val

# pearson_val, p_val = cal_pearson_features(data[features])


'''
画出皮尔森相关系数的“矩阵图”
'''
import matplotlib.pyplot as plt
import numpy as np
def plot_pearson_coef( input_data):
pearson_val, p_val = cal_pearson_features(input_data)
fig = plt.figure()
fig.set_size_inches( 9, 8)
ax = fig.add_subplot( 1, 1, 1)
cax = ax.matshow(pearson_val, vmin=- 1, vmax= 1) #绘制热力图,从-1到1
fig.colorbar(cax) #将matshow生成热力图设置为颜色渐变条
ticks = np.arange( 0, len(input_data.columns), 1) #生成0-9,步长为1
ax.set_xticks(ticks) #生成刻度
ax.set_yticks(ticks)
ax.set_xticklabels(data[features].columns, rotation= 90, fontsize= 'small') #生成x轴标签
ax.set_yticklabels(data[features].columns, fontsize= 'small')
plt.show()

# plot_pearson_coef(data[features])

'''
计算与变量有最大相关性的变量,以及他们的p值,(横向比较)
'''

def return_max_pearson( input_data, * val_thre):
'''
输入: 需要计算的特征向量数据(dataframe格式)
可选参数:相关系数的阈值
输出: 相关系数较大的向量
'''
pearson_val, p_val = cal_pearson_features(input_data)
max_x = []
for i in range( len(pearson_val)):
x = pearson_val.iloc[i,:]
x_sorted = x.sort_values( ascending= False)
max_x_val = x_sorted.values[ 1]
max_x_name = x_sorted.index[ 1]
max_x.append([x.index[i], max_x_name, max_x_val, p_val.loc[x.index[i], max_x_name]])

max_x = np.array(max_x).reshape( len(pearson_val), 4)
max_pearson = pd.DataFrame(max_x, columns=[ 'variable_1', 'variable_2', 'pearson_val', 'p_val'])
max_pearson[ 'pearson_val'] = max_pearson[ 'pearson_val'].astype( 'float')
if val_thre:
return max_pearson[max_pearson[ 'pearson_val'] >= val_thre]
else:
return max_pearson
# print return_max_pearson(data[features], 0.9)

'''
互信息法(Mutual Information),缩写为MI,表示变量X与Y是否有关系,以及关系的强弱,也可以用来衡量相关性,但有很多缺点,比如,非均一性
计算了每一个特征和目标变量的互信息系数,目标变量可以为离散型(mutual_info_classif)或者连续型(mutual_info_regression)
返回值为正,计算了变量之间的独立性,如果两个变量之间不独立时,则返回值为0,越大的值代表越高的独立性
互信息直接用于特征选择其实不是太方便:1、它不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较;
sklearn中的解释为:Mutual Information between two clusterings.The Mutual Information is a measure of the similarity between two labels of the same data.
参考链接:http://scikit-learn.org/stable/modules/generated/sklearn.metrics.mutual_info_score.html
'''
def cal_mutual_info( input_data, y, process_type):
if process_type == 'class':
coef = mutual_info_classif(input_data, y)
if process_type == 'regression':
coef = mutual_info_regression(input_data, y)
mutual_coef = pd.DataFrame(coef, columns=[ 'coef'])
mutual_coef[ 'feature_name'] = input_data.columns
mutual_coef = mutual_coef.sort_values( by=[ 'coef'])
return mutual_coef

# print cal_mutual_info(data[features], data['score'], 'class')

'''
最大信息系数MIC(Maximal information coefficient),不仅识别线性关系,还可以识别函数关系,比较general
参考文档地址:https://www.deeplearn.me/1466.html
因为其利用了蒙特卡洛的方法,所以在数据量越大时MIC越好,几百条数据不好。
其克服了MI的两个问题:
1、MI不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较
2、对于连续变量的计算不是很方便(X和Y都是集合,x,y都是离散的取值),通常变量需要先离散化,而互信息的结果对离散化的方式很敏感。
最大信息系数克服了这两个问题。它首先寻找一种最优的离散化方式,然后把互信息取值转换成一种度量方式,取值区间在[0,1]。 minepy 提供了MIC功能。
'''
# from minepy import MINE
# m = MINE()
# print m.computer_score(data[features], data['score']) #########会有错误:'minepy.mine.MINE' object has no attribute 'computer_score'

'''
卡方检验:拟合优度检验,独立性检验
用于计算"非负数"的特征(必须为非负数)和目标变量(必须为分类变量)之间的独立性
一般可以设原假设为 :观察频数与期望频数没有差异,或者两个变量相互独立不相关。
先假设原假设成立,计算卡方值,表示观察值与理论值之间的偏离程度。再根据自由度计算得到卡方值,再做出拒绝或接受原假设的结论,一般p=0.05
参考链接: http://blog.csdn.net/anneqiqi/article/details/62884632
值越大,越有相关性,特征越需要保留,值越小越说明不想关,需要去除
'''
def cal_chi2( input_data, y):
'''
输入:特征矩阵
目标变量
输出:chi2的值,p值
'''
negtive_index = []
# 计算存在负值的特征,需要在计算卡方值之前剔除
for i in range(input_data.shape[ 1]):
if len(input_data.iloc[:,i][input_data.iloc[:,i]< 0]) > 0:
negtive_index.append(i)
neg_name = [input_data.columns[x] for x in negtive_index]
pro_data = input_data.drop(neg_name, axis = 1)

# 计算卡方值
chi2_val = chi2(pro_data, y)
chi2_data = pd.DataFrame(chi2_val[ 0], columns=[ 'chi2_value'])
chi2_data[ 'p_val'] = chi2_val[ 1]
chi2_data[ 'feature_name'] = pro_data.columns
chi2_data = chi2_data.sort_values( by=[ 'chi2_value'], ascending= False)
return chi2_data
# tt = cal_chi2(data[['spanoutpaylast_count']], data['score'])

'''
基于模型的特征排序, 单独采用每个特征进行建模,并进行交叉验证
这种方法的思路是直接使用你要用的机器学习算法,针对 每个单独的特征和响应变量建立预测模型。
假如 特征 和 响应变量 之间的关系是非线性的,可以用基于树的方法(决策树、随机森林)、或者 扩展的线性模型 等。
基于树的方法比较易于使用,因为他们对非线性关系的建模比较好,并且不需要太多的调试。
但要注意过拟合问题,因此树的深度最好不要太大,再就是运用交叉验证。
'''
from sklearn.cross_validation import cross_val_score, ShuffleSplit
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from xgboost.sklearn import XGBClassifier

def cal_feature_model_based( input_data, y, model):
'''
输入:特征向量数据(注意:该方法是基于一个一个特征进入模型进行建模最终得到特征的重要性)
目标向量
输出:使用的模型
'''
row_num, col_num = input_data.shape
sfs = ShuffleSplit( n=row_num, n_iter= 3, test_size= 0.3, train_size= 0.7, random_state= 1)
scores=[]
for i in range(col_num):
score = cross_val_score(model, input_data.iloc[:, i:i+ 1], y, scoring= 'accuracy', cv=sfs)
scores.append(( format(np.mean(score), '.3f'), input_data.columns[i]))
sort_score = pd.DataFrame( sorted(scores, reverse= True), columns=[ 'score', 'feature'])
return sort_score

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值