在数据进行建模分析,无法直接把类别变量放入模型中去分析,因此,需要对类别变量进行处理。最常见的方法是对类别变量做因子化处理、哑变量编码或one-hot编码、目标编码。
还有将连续性变量变成离散型的。在机器学习问题中,我们通过训练数据集学习得到的其实就是一组模型的参数,然后通过学习得到的参数确定模型的表示,最后用这个模型再去进行我们后续的预测分类等工作。在模型训练过程中,我们会对训练数据集进行抽象、抽取大量特征,这些特征中有离散型特征也有连续型特征。若此时你使用的模型是简单模型(如LR),那么通常我们会对连续型特征进行离散化操作,然后再对离散的特征,进行one-hot编码或哑变量编码。这样的操作通常会使得我们模型具有较强的非线性能力。

一、因子化处理

因子分析(Factor Analysis)是指研究从变量群中提取共性因子的统计技术,这里的共性因子指的是不同变量之间内在的隐藏因子。例如,一个学生的英语、数学、语文成绩都很好,那么潜在的共性因子可能是智力水平高。因此,因子分析的过程其实是寻找共性因子个性因子并得到最优解释的过程。

因子分析有两个核心问题:一是如何构造因子变量,二是如何对因子变量进行命名解释。因子分析有下面4个基本步骤过程:

1、确定原有若干变量是否适合于因子分析。因子分析的基本逻辑是从原始变量中构造出少数几个具有代表意义的因子变量,这就要求原有变量之间要具有比较强的相关性,否则,因子分析将无法提取变量间的“共性特征”(变量间没有共性还如何提取共性?)。实际应用时,可以使用相关性矩阵进行验证,如果相关系数小于0.3,那么变量间的共性较小,不适合使用因子分析(查看变量间的相关性,也就是共有特征是否有必要提取共性)。

mport pandas as pd
mydata = pd.read_csv(r'D:\PythonDDD\datafiles\data.csv')
mydata.describe()
 
 
import math
df = pd.DataFrame(mydata)
df['行驶里程1'] = df['行驶里程'].apply(lambda x: math.log(x))
df.boxplot(column = '行驶里程1', by='车号')#查看车号的行驶里程
df.boxplot(column = '平均时速', by='车号')#查看车号的平均时速
 
 
 
#样本离差矩阵
import numpy as np
mydata = mydata.drop('车号', 1)
mydata = mydata.drop('行驶里程1', 1)
mydata_mean = mydata.mean()
E = np.mat(np.zeros((14, 14)))
for i in range(len(mydata)):
    E += (mydata.iloc[i, :].reshape(14, 1) - mydata_mean.reshape(14, 1)) * (mydata.iloc[i, :].reshape(1, 14) - mydata_mean.reshape(1, 14))
 
 
#样本相关性矩阵
R = np.mat(np.zeros((14, 14)))
for i in range(14):
    for j in range(14):
        R[i, j] = E[i, j]/math.sqrt(E[i, i] * E[j, j])

或者

R1 = mydata.corr()       #样本相关性矩阵

2、 构造因子变量。因子分析中有多种确定因子变量的方法,如基于主成分模型的主成分分析法和基于因子分析模型的主轴因子法、极大似然法、最小二乘法等。其中基于主成分模型的主成分分析法是使用最多的因子分析方法之一。( 不同方法不同效果 )

import numpy.linalg as nlg
eig_value, eigvector = nlg.eig(R)#求矩阵R的全部特征值,构成向量E。
print(eig_value, eigvector)
eig = pd.DataFrame()
eig['names'] = mydata.columns
eig['eig_value'] = eig_value
eig.sort_values('eig_value', ascending=False, inplace=True)
 
 
#求因子模型的因子载荷阵,寻找公共因子个数m
for m in range(1, 14):
    if eig['eig_value'][:m].sum()/eig['eig_value'].sum() >= 0.8:
        print(m)
        break
 
#因子载荷矩阵,只是因子,
A  = np.mat(np.zeros((14, 6)))
A[:,0]=math.sqrt(eig_value[0])*eigvector[:,0]
A[:,1]=math.sqrt(eig_value[1])*eigvector[:,1]
A[:,2]=math.sqrt(eig_value[2])*eigvector[:,2]
A[:,3]=math.sqrt(eig_value[3])*eigvector[:,3]
A[:,4]=math.sqrt(eig_value[4])*eigvector[:,4]
A[:,5]=math.sqrt(eig_value[5])*eigvector[:,5]
 
a=pd.DataFrame(A)
a.columns=['factor1','factor2','factor3','factor4','factor5','factor6']

3、利用旋转使得因子变量更具有可解释性。在实际分析工作中,主要是因子分析得到因子和原变量的关系,从而对新的因子能够进行命名和解释,否则其不具有可解释性的前提下对比PCA就没有明显的可解释价值。

4、计算因子变量的得分。计算因子得分是因子分析的最后一步,因子变量确定以后,对每一样本数据,希望得到它们在不同因子上的具体数据值,这些数值就是因子得分,它和原变量的得分相对应。(生成新的数据)

from sklearn.cluster import KMeans
 
for i in range(2, 10):
    clf = KMeans(n_clusters=i)
    clf.fit(train_data)
#    print(clf.cluster_centers_)#类中心
    print(i, clf.inertia_)#用来评估簇的个数是否合适,距离越小说明簇分的越好,选取临界点的簇个数

二、One-Hot编码

在我们数据分析、建模的时候,首先要处理的就是各种数据,数据的类型也不仅仅局限于连续型数值。比如,性别、城市名等等此类的指标也是很多的。这种类型, 它是不具备序列性、也不能比较大小的,如果这个时候简单的用数字来替换,那么就给这种赋予了大小的属性,这就会影响权重矩阵的计算。这个时候,就可以用One-Hot编码(也有人称独热编码)这种特殊的编码方式了。

举例解释下为什么直接转变为数值型数据会有问题:对于分类型数据,如果种类较多,转变为分类1,2,3,4等来表示,带入到模型中,就被认为连续变量,并且如果同样的数据,一个分类被1代表,另一个分类被1000代表,1000和1对模型的影响明显不同,会影响统一特征在样本中的权重。

One-Hot编码是用N位状态寄存器来对N个状态进行编码。一个变量,共有3个分类值(ABC),那么N为3,对应的One-Hot编码可以表示为100,010,001。

one-hot的基本思想:将离散型特征的每一种取值都看成一种状态,若你的这一特征中有N个不相同的取值,那么我们就可以将该特征抽象成N种不同的状态,one-hot编码保证了每一个取值只会使得一种状态处于“激活态”,也就是说这N种状态中只有一个状态位值为1,其他状态位都是0。举个例子,假设我们以学历为例,我们想要研究的类别为小学、中学、大学、硕士、博士五种类别,我们使用one-hot对其编码就会得到:

Python时域离散数据转频域 python离散化_机器学习


对于连续型数据,有时候我们也需要做特征转换,比如说人的年龄,这个分布可能会从0一直到100,但其实他们的分布可能集中在10-40之间,那么我们可以将这种连续型的数据处理为分类变量。比如:0-18:1;19-30:2;30-40:3,40-60:4,60+:5,这样做的好处是提高模型运算的效率。比如用LR算法做模型,在数据处理过程中,可以先对连续变量进行离散化处理,然后对离散化后数据进行One-Hot编码,最后放入LR模型中。这样可以增强模型的非线性能力。

优缺点
(1)通过One-Hot编码,可以对特征进行了扩充。
(2)连续变量经过编码后,从一个权重变为多个权重,提升了模型的非线性能力。
(3)不需要多参数进行归一化处理。
(4)随着将大权重拆分成几个小权重管理特征,降低了异常值对模型的影响,增加了模型稳定性。
(5)生成了较大的稀疏矩阵。

接下来就是在Python中实现此方法:

from sklearn.preprocessing import OneHotEncoder#导入One-Hot编码
import pandas as pd
 
#创建一个数据集,放入dataframe中
data = [['语文',125],
        ['数学',140],
        ['英语',130],
       ['地理',80],
       ['历史',90],
       ['物理',80],
       ['化学',90]]
data = pd.DataFrame(data,columns=['titile','分数'])
#把带title这一列转换为数值型,因为one-hot编码也需要先转换成数值型
list = data.ix[:,'titile'].unique()#取出唯一的列的值
#用简单的数字直接代表即可
for j in range(len(list )):
    data.ix[:,'titile'] = data.ix[:,'titile'].apply(lambda x:j if x==list [j] else x)
print(data)

这里先看一下转化的结果:

titile   分数
0       0  125
1       1  140
2       2  130
3       3   80
4       4   90
5       5   80
6       6   90

然后用One-Hot编码来处理:

#进行one-hot编码
#先取出title这一列的值
tempdata = data[['titile']]
 
#使用One-Hot编码
enc = OneHotEncoder()
enc.fit(tempdata)
 
#one-hot编码的结果是比较奇怪的,最好是先转换成二维数组
tempdata = enc.transform(tempdata).toarray()
print(tempdata)
print('取值范围整数个数:',enc.n_values_)

先看下直接One-Hot的结果:

[[1. 0. 0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 0. 0. 1.]]
取值范围整数个数: [7]

将这个结果转成dataframe中的列:

#再将二维数组转换为DataFrame,这里多列用一样的列名
tempdata = pd.DataFrame(tempdata,columns=['titile']*len(tempdata[0]))
print(tempdata)
titile  titile  titile  titile  titile  titile  titile
0     1.0     0.0     0.0     0.0     0.0     0.0     0.0
1     0.0     1.0     0.0     0.0     0.0     0.0     0.0
2     0.0     0.0     1.0     0.0     0.0     0.0     0.0
3     0.0     0.0     0.0     1.0     0.0     0.0     0.0
4     0.0     0.0     0.0     0.0     1.0     0.0     0.0
5     0.0     0.0     0.0     0.0     0.0     1.0     0.0
6     0.0     0.0     0.0     0.0     0.0     0.0     1.0

以上就是一个简单的独热编码的过程了。

三、哑变量处理

哑变量(Dummy Variable),也叫虚拟变量,引入哑变量的目的是,将不能够定量处理的变量量化,如职业、性别对收入的影响,战争、自然灾害对GDP的影响,季节对某些产品(如冷饮)销售的影响等等。 这种“量化”通常是通过引入“哑变量”来完成的。根据这些因素的属性类型,构造只取“0”或“1”的人工变量,通常称为哑变量(dummy variables),记为D。

举一个例子,假设变量“职业”的取值分别为:工人、农民、学生、企业职员、其他,5种选项,我们可以增加4个哑变量来代替“职业”这个变量,分别为D1(1=工人/0=非工人)、D2(1=农民/0=非农民)、D3(1=学生/0=非学生)、D4(1=企业职员/0=非企业职员),最后一个选项“其他”的信息已经包含在这4个变量中了,所以不需要再增加一个D5(1=其他/0=非其他)了。这个过程就是引入哑变量的过程,其实在结合分析(conjoint analysis)中,就是利用哑变量来分析各个属性的效用值的。

哑变量编码直观的解释就是任意的将一个状态位去除。还是拿第二节中的例子来说,我们用4个状态位就足够反应上述5个类别的信息,也就是我们仅仅使用前四个状态位 [0,0,0,0] 就可以表达博士了。只是因为对于一个我们研究的样本,他已不是小学生、也不是中学生、也不是大学生、又不是研究生,那么我们就可以默认他是博士,是不是。(额,当然他现实生活也可能上幼儿园,但是我们统计的样本中他并不是,-)。所以,我们用哑变量编码可以将上述5类表示成:

Python时域离散数据转频域 python离散化_Python时域离散数据转频域_02


one-hot编码和dummy编码:区别与联系

  通过上面的例子,我们可以看出它们的“思想路线”是相同的,只是哑变量编码觉得one-hot编码太罗嗦了(一些很明显的事实还说的这么清楚),所以它就很那么很明显的东西省去了。这种简化不能说到底好不好,这要看使用的场景

选择建议

我感觉最好是选择正则化 + one-hot编码;哑变量编码也可以使用,不过最好选择前者。虽然哑变量可以去除one-hot编码的冗余信息,但是因为每个离散型特征各个取值的地位都是对等的,随意取舍未免来的太随意。

1.pandas进行哑变量编码
pandas中提供了get_dummies()函数:
pandas.get_dummies(prefix=) prefix参数设置编码后的变量名,也可以选择默认

# 导入数据
import pandas as pd
file = open('C:/Users/Dell/Documents/LTDSJ/example1data/data.csv',encoding='utf-8')
factory = pd.read_csv(file,engine='python')

数据如下:

0    C10235
1    C10135
2    C10035
3    C10135
4    C10385
5    C14534
6        **
7        **
8    C10129
9    C10150

四、其他问题

连续值的离散化为什么会提升模型的非线性能力?

  简单的说,使用连续变量的LR模型,模型表示为公式(1),而使用了one-hot或哑变量编码后的模型表示为公式(2)

Python时域离散数据转频域 python离散化_python_03


式中表示连续型特征,、、分别是离散化后在使用one-hot或哑变量编码后的若干个特征表示。这时我们发现使用连续值的LR模型用一个权值去管理该特征,而one-hot后有三个权值管理了这个特征,这样使得参数管理的更加精细,所以这样拓展了LR模型的非线性能力。

这样做除了增强了模型的非线性能力外,还有什么好处呢?这样做了我们至少不用再去对变量进行归一化,也可以加速参数的更新速度;再者使得一个很大权值管理一个特征,拆分成了许多小的权值管理这个特征多个表示,这样做降低了特征值扰动对模型为稳定性影响,也降低了异常数据对模型的影响,进而使得模型具有更好的鲁棒性。