一.数据预处理概述
常遇到的数据存在噪声、冗余、关联性、不完整性等。
数据预处理常见处理方法:
(1)数据清理:补充缺失值、消除噪声数据、识别或删除离群点(异常值)并解决不一致性。
目标:数据格式标准化、异常数据清除、重复数据清除、错误纠正
(2)数据集成:将多个数据数据源中的数据进行整合并统一存储
(3)数据变换:通过平滑狙击、数据概化、规范化等方式将数据转换成适用数据挖掘的形式
(4)数据归约:针对在数据挖掘时,数据量非常大。数据归约技术指对数据集进行归约or简化,不仅保持原数据的完整性,且数据归约后的结果与归约前的结果相同或几乎相同。
二.数据清理
1.异常数据处理
异常数据也称离群点,指采集的数据中,个别数据值明显偏离其余观测值。对这些数据需采用一定的方法消除,否则对结果产生影响。
(1)异常数据分析
a.统计量判断:max,min,均值,检查数据是否超出合理范围
b.3σ原则:根据正态分布定义,出现距离均值3σ以上数值属于小概率事件,此时,数据和均值的偏差超过3倍标准差的视为异常值。操作参考
c.箱型图判断:箱型图反应数据分布。如果数据超出箱型图上界or下界视为异常数据
(2)异常数据处理方法
a.删除:直接把存在的一场数据删除,不进行考虑
b.视为缺失值:按照缺失值处理方法进行操作。如2所示
c.不处理:看作正常数据处理
d.平均值修正:使用前后两个观测值的均值代替,or使用整个数据集的均值。参考spss工具
2.缺失值处理
经常使用数据补插方法代替缺失值,如以下几种:
(1)最近邻插补:使用缺失值附近样本or其他样本代替;or前后数据均值代替
(2)回归方法:建立拟合模型,用该模型预测缺失值
(3)插值法:类似回归法,利用已知数据建立插值函数,用该函数计算近似值代替缺失值。
常见插值函数:拉格朗日插值法、牛顿插值法、分段插值法、样条插值法、Hermite插值法
3.噪声数据处理
处理方法:分箱、聚类、回归
(1)分箱法
把待处理数据(某列属性值)按一定规则放进一些箱子(区间),考察每一个区间里的数据,then采用某方法分别对各个区间数据处理。需考虑2个问题:如何分箱,如何对每个箱子中数据进行平滑处理。
分箱方法如下几种:
a.等深分箱法(统一权重法):将数据集按记录(行数)分箱,每箱具有相同的记录数(元素个数)。每箱记录数称为箱子深度(权重)。
b.等宽分箱法(统一区间法):使数据集在整个属性值的区间上平均分布,即每个箱的区间范围(箱子宽度)是一个常量。
c.用户自定义区间:当用户明确希望观察某些区间范围内的数据时,可根据需要自定义区间。
eg.客户收入属性的数据排序后值如下:800,1000,1200,1500,1500,1800,2000,2300,2500,2800,3000,3500,4000,4500,4800,5000
等深分箱法:设定权重(箱子深度)为4
箱1:800,1000,1200,1500
箱2:1500,1800,2000,2300
箱3:2500,2800,3000,3500
箱4:4000,4500,4800,5000
等宽分箱法:设定区间范围(箱子宽度)为1000元
箱1:800,1000,1200,1500,1500,1800
箱2:2000,2300,2500,2800,3000
箱3:3500,4000,4500
箱4:4800,5000
用户自定义:将客户收入划分为1000元以下,1000-2000元,2000元以上
箱1:800,1000
箱2:1200,1500,1500,1800,2000,
箱3:2300,2500,2800,3000,3500,4000,4500,4800,5000
分箱后对每个箱子中数据进行平滑处理。常见数据平滑方法如下:
a.按均值平滑:对同一箱值中数据求均值,用均值代替该箱子中所有数据
b.按边界值平滑:用距离较小的边界值代替每一个数据
c.按中值平滑:取箱子中的中值,代替箱子中所有数据
(2)聚类法
将物理对的or抽象对象的集合分组为 由类似对象组成的多个类,then展出并清除那些落在簇之外的值(孤立点),这些孤立点称为噪声数据。
(3)回归法
试图发现两个变量之间的相关变化模式,找到这个函数来平滑数据。即通过建立一个数学模型来预测下一个数值,方法一般包括线性回归and非线性回归。
三.数据集成
将多文件or数据库中的异构数据进行合并,然后存放在一个统一数据库中存储。
需考虑的问题:
(1)实体识别:数据来源不同,其中概念定义不同
a.同名异义:数据源A某个数据特征名称 与 数据源B某个数据特征名称 相同,但 表示内容不同。
b.异名同义:数据源A某个数据特征名称 与 数据源B某个数据特征名称 不同,但表示内容相同。
c.单位不统一:不同的数据源记录单位不同。如身高,米?l厘米吗?
(2)冗余属性
a.同一属性多个数据源均有记录
b.同一属性命名不一致引起数据重复
(3)数据不一致:编码使用不一致、数据表示不一致。如日期
四.数据变换
将数据转换成适合机器学习的形式。
1.使用简单的数学函数对数据进行变换
数据较大:取对数、开方 使数据压缩变小
数据较小:平方 扩大数据
时间序列分析:对数变换or 差分运算 使非平稳序列转换为平稳序列
2.归一化(数据规范化)
如比较工资收入,有人每月工资上万元,有人每月才几百元,归一化可消除数据间这种量纲影响。
(1)最小--最大归一化(离散标准化)
对原始数据进行线性变换,使其映射到 [0,1]之间,转换函数如下:
(2) Z-score标准法(零-均值规范法)
使用原始数据均值和标准差,对数据标准化。经过处理的数据符合 标准正态分布,即均值为0,标准差为1。转化函数如下:
X-μ为离均差,σ表示总体标准偏差 。
要求:原始数据近似为高斯分布(正态分布),否则,归一效果不理想。(可简单做变量散点图观察)
(3) 小数定标规范化
通过移动数据的小数点位置进行规范化。
3.连续属性离散化
本质上是将连续属性空间划分为若干个区间,最后用不同的符号or整数值 代表每个子区间中的数据。
离散化涉及两个子任务:确定分类,将连续属性值映射到这些分类中
机器学习常用离散化方法:
(1)等宽法:将数据 划分为具有相同宽度的区间,将数据按照值分配到不同区间,每个区间用一个数值表示。
(2)等频法:把数据划分为若干个区间,按照其值分配到不同区间,每个区间内数据个数相等
(3)基于聚类分析的方法:典型算法K-means算法:
首先从数据集中随机找出k个数据作为k个聚类的中心;
其次,根据其他数据相对于这些中心的欧氏距离,对所有对象聚类。如果数据点x距某个中心近,则将x划归该中心所代表的聚类;
最后,重新计算各区间中心,利用新中心重新聚类所有样本。循环直至所有区间中心不再随算法循环而改变,
五.数据归约
在尽可能保持数据原貌前提下,最大限度精简数据量。与非归约数据相比,在归约的数据上进行挖掘,所需时间和内存资源更少,挖掘更有效,产生几乎相同分析结果。
常用维归约、数值归约等方法。
1.维归约(特征归约)
通过减少属性特征方式压缩数据量,移除不相关属性,提高模型效率。维归约方法很多:
AIC准则:通过选择最优模型来选择属性
LASSO:通过一定约束条件选择变量
分类树、随机森林:通过对分类效果的影响大小筛选属性
小波变换、主成分分析:通过把原数据变换or投影到较小空间来降低维数
2.数值归约(样本归约)
从数据集中选出一个有代表性的样本子集。
子集大小的确定需考虑:计算成本、存储要求、估计量精度、其他与算法有关因素
如:参数法中使用模型估计数据,可只存放模型参数代替存放实际数据:eg,回归模型、对数线性模型
非参数方法可使用直方图、聚类、抽样、数据立方体聚焦等。
六.Pyhton的主要数据预处理函数
1.Python的数据结构
pandas主要两种数据结构
(1)Series
类似一维的数组对象。Series对象主要有两个属性:index、values.
如果传递给构造器的是一个列表,index值是从0递增的整数;如果传递一个键值对结构,就会生成index-value对应的Series
from pandas import Series,DataFrame
s=Series([1,2,3,'abc','def']) #自动生成索引
#指定索引
s=Series(data=[1,2,3,'abc','def'],index=[10,20,30,40,50]) # s=Series([1,2,3,'abc','def'],index=[10,20,30,40,50])
(2)DataFrame
类似一个表格。有行和列索引。
from pandas import Series,DataFrame
data =DataFrame({'id':[100,101,102,103,104],'name':['aa','bb','cc','dd','ee'],'age':[18,19,20,19,18]})
#指定index or columns
data2 =DataFrame({'id':[100,101,102,103,104],'name':['aa','bb','cc','dd','ee'],'age':[18,19,20,19,18]},index=['one','two','three','four','five']) #or data2 =DataFrame(data,index=['one','two','three','four','five'])
print(data2)
2.数据缺失处理函数
Pandas使用浮点值NaN代表缺失数据,Numpy使用nan代表缺失值,Python内置的None也会被当做NA处理。
from pandas import Series,DataFrame
from numpy import nan as NA
data = Series([12,None,34,NA,58])
print(data)
out: 0 12.0
1 NaN
2 34.0
3 NaN
4 58.0
dtype: float64
可使用 isnull() 检测是否为缺失值,该函数返回一个布尔型数组,一般可用于布尔型索引。
print(data.isnull())
0 False
1 True
2 False
3 True
4 False
dtype: bool
当数据中存在缺失值时,常用以下方法处理。
(1)数据过滤(dropna)
直接将缺失值数据过滤掉,不再考虑。对Series结构没太大问题;对DataFrame结构,如果过滤掉,至少丢掉包含缺失值所在的一行or一列。
语法格式:dropna(axis=0,how='any',thresh=None)
axis=0表示行,axis=1表示列
how参数可选值为all/any,all表示丢掉全为NA的行
thresh为整数类型,表示删除条件,如thresh=3,表示一行中至少有3个非NA值才将其保留。
from pandas import Series,DataFrame
from numpy import nan as NA
data = Series([12,None,34,NA,58])
print(data.dropna())
0 12.0
2 34.0
4 58.0
dtype: float64
接下来看一个两维数据情况
from pandas import Series,DataFrame
from numpy import nan as NA
import numpy as np
data = DataFrame(np.random.randn(5,4))
data.ix[:2,1]=NA
data.ix[:3,2]=NA
print(data)
print('---删除后的结果是---')
print(data.dropna(thresh=2))
print(data.dropna(thresh=3))
0 1 2 3
0 0.223965 NaN NaN 0.572505
1 -0.310963 NaN NaN -0.085844
2 -0.174306 NaN NaN -0.160054
3 -0.570029 0.451696 NaN 1.168203
4 -0.918397 -1.249329 -0.61818 0.978389
---删除后的结果是---
0 1 2 3
0 0.223965 NaN NaN 0.572505
1 -0.310963 NaN NaN -0.085844
2 -0.174306 NaN NaN -0.160054
3 -0.570029 0.451696 NaN 1.168203
4 -0.918397 -1.249329 -0.61818 0.978389
0 1 2 3
3 -0.570029 0.451696 NaN 1.168203
4 -0.918397 -1.249329 -0.61818 0.978389
loc——通过行标签索引行数据
iloc——通过行号索引行数据
ix——通过行标签或者行号索引行数据(基于loc和iloc 的混合)
(2)数据填充(fillna)
语法格式:fillna(value,method,axis)
value:除了基本类型外,还可使用字典实现对不同列填充不同值。
method:采用填补数值的方法,默认None
eg.用0代替所有NaN.
print(data.fillna(0))
0 1 2 3
0 0.083377 0.000000 0.000000 0.147247
1 0.927662 0.000000 0.000000 0.156747
2 -0.054431 0.000000 0.000000 -1.118927
3 -0.237319 2.413680 0.000000 0.196252
4 -0.400624 -0.422343 1.136373 -0.370904
使用字典填充:第1列缺失值用11代替,第2列缺失值用22代替
print(data.fillna({1:11,2:22}))
0 1 2 3
0 0.731801 11.000000 22.000000 0.663891
1 0.617013 11.000000 22.000000 -0.067351
2 0.117183 11.000000 22.000000 -0.048441
3 -1.180875 -0.211674 22.000000 0.026497
4 0.271810 0.836722 0.125407 -0.510306
第一列缺失值用该列均值代替,同理第2列
print(data.fillna({1:data[1].mean(),2:data[2].mean()}))
0 1 2 3
0 1.440942 -0.550534 -0.40254 -0.238328
1 1.177531 -0.550534 -0.40254 0.184064
2 -0.568246 -0.550534 -0.40254 0.286022
3 0.709073 0.082285 -0.40254 -0.808424
4 0.599532 -1.183353 -0.40254 1.894830
(3)拉格朗日插值法
from scipy.interpolate import lagrange #导入拉格朗日插值函数
import pandas as pd
from pandas import DataFrame
import numpy as np
df = DataFrame(np.random.randn(20,2),columns=['first','second'])
df[(df['first']<-1.5)|(df['first']>1.5)] =None #将异常值变为空值
print(df)
first second
0 0.509865 0.223248
1 0.105383 -0.354727
2 NaN 0.720146
3 NaN 0.254254
4 -0.664651 1.752019
5 NaN 0.379110
6 0.154492 1.358823
7 -0.275848 -0.425088
8 -0.457922 0.653865
9 0.138629 0.215032
10 -0.563553 -0.121851
11 NaN 1.410582
12 -0.879194 0.297789
13 0.216112 -0.038785
14 0.567963 -1.438319
15 0.430648 1.843005
16 1.126694 -0.419329
17 NaN -0.230501
18 0.471433 -0.279679
19 0.960270 0.261889
自定义列向量插值函数。s为列向量,n为被插值位置,k为取前后的数据个数,默认为5
tips补充知识:
a=list(range(2,6))+list(range(0,4))
print(a)
[2, 3, 4, 5, 0, 1, 2, 3]
-------------------------------------------------------------------
from scipy.interpolate import lagrange #导入拉格朗日插值函数
import pandas as pd
from pandas import DataFrame
import numpy as np
df = DataFrame(np.random.randn(20,2),columns=['first','second'])
df[(df['first']<-1.5)|(df['first']>1.5)] =None #将异常值变为空值
print(df)
first second
0 -0.908670 -1.849173
1 -0.014963 -0.294497
2 0.229062 0.765329
3 NaN NaN
4 NaN NaN
5 -0.515293 -0.429553
6 0.109772 0.243534
7 -0.447363 0.827352
8 0.810052 0.960669
9 NaN NaN
10 NaN NaN
11 -0.495736 -0.823449
12 1.433098 0.810218
13 1.238232 -0.752660
14 -0.277956 -1.495663
15 1.367079 -0.653861
16 0.417049 -0.334369
17 0.328512 0.267598
18 0.671522 0.040041
19 0.292779 -1.500854
def ployinterp_column(s,n,k=5):
y=s[list(range(n-k,n)) + list(range(n+1,n+1+k))] #取数,n的前后5个,这里有可能取到不存在的下标,为空
y=y[y.notnull()] #剔除空值
return lagrange(y.index,list(y))(n) #插值并返回插值结果,最后的括号就是我们要插值的n
#逐个元素判断是否需要插值
for i in df.columns:
for j in range(len(df)): #逐个元素判断
if(df[i].isnull())[j]: #如果为空即插值
df[i][j]=ployinterp_column(df[i],j)
df.to_csv('C:/df2',sep=',') #使用DataFrame的to_csv函数保存文件
,first,second
0,-0.9086702668582811,-1.8491728913487913
1,-0.014963260074014563,-0.29449702937867106
2,0.22906199067439614,0.7653293525157804
3,-0.704082936914352,0.3723318613247397
4,-1.1624629170855587,-0.3757317510307674
5,-0.5152933370950362,-0.4295533360082923
6,0.10977175789757533,0.2435336905666214
7,-0.44736256388993095,0.8273521748276524
8,0.8100515665921939,0.9606688385148615
9,1.5460818472129176,-0.0779254312581088
10,-0.041597527502744924,-1.5356986975057225
11,-0.49573605078970445,-0.8234491527470889
12,1.4330980273017377,0.8102181255104398
13,1.2382321456144767,-0.752660056579277
14,-0.2779557239464442,-1.495663200350301
15,1.3670789841095052,-0.6538612478274082
16,0.417048532674513,-0.3343690769844107
17,0.32851231080966964,0.26759821504833575
18,0.6715223467868799,0.04004134652646034
19,0.292779439136057,-1.5008536999322502
(4)检测和过滤异常值(Outlier)
from pandas import Series,DataFrame,np
from numpy import nan as NA
data = DataFrame(np.random.randn(10,4))
print(data.describe())
print('n...找出某一列中绝对值大小超过1的项...n')
data1 = data[2] #data的第2列赋值给data1
print(data1[np.abs(data1)>1])
data1[np.abs(data1)>1]=100 #将绝对值大于1的数据修改为100
print(data1)
0 1 2 3
count 10.000000 10.000000 10.000000 10.000000
mean -0.063484 -0.173792 0.446723 0.211679
std 1.032054 1.079380 0.900736 0.863194
min -1.117239 -2.009955 -0.689243 -1.045505
25% -0.832113 -0.689701 -0.165707 -0.338501
50% -0.560831 -0.250178 0.317723 0.184269
75% 0.680691 0.536042 0.844509 0.668352
max 1.799798 1.495253 2.279650 1.703622
...找出某一列中绝对值大小超过1的项...
0 1.318452
8 2.279650
Name: 2, dtype: float64
0 100.000000
1 -0.499920
2 0.407870
3 -0.689243
4 0.861217
5 -0.017720
6 0.227575
7 -0.215036
8 100.000000
9 0.794384
Name: 2, dtype: float64
(5)移除重复数据
在Pandas中使用duplicated方法发现重复值(返回bool型数组,F非重复,T重复),drop_duplicates方法移除重复值
from pandas import Series,DataFrame,np
from numpy import nan as NA
import pandas as pd
import numpy as np
data = DataFrame({'name':['zhang']*3 + ['wang']*4,'age':[18,18,19,19,20,20,21]})
print(data)
print('...重复的内容是...n')
print(data.duplicated())
print('--删除重复的内容后---')
print(data.drop_duplicates())
name age
0 zhang 18
1 zhang 18
2 zhang 19
3 wang 19
4 wang 20
5 wang 20
6 wang 21
...重复的内容是...
0 False
1 True
2 False
3 False
4 False
5 True
6 False
dtype: bool
--删除重复的内容后---
name age
0 zhang 18
2 zhang 19
3 wang 19
4 wang 20
6 wang 21
duplicated 和drop_duplicates默认保留第一个出现值组合,可修改参数keep='last'保留最后一个
print('--删除重复的内容后---')
print(data.drop_duplicates(keep='last'))
--删除重复的内容后---
name age
1 zhang 18
2 zhang 19
3 wang 19
5 wang 20
6 wang 21
(6)数据规范化
为消除数据之间量纲影响,需对数据进行规范化处理,将数据落入一个有限范围。
常见归一化将数据范围调整到[0,1] or [-1,1]。一般使用方法:最小-最大规范化、零-均值规范化和小数规范化。
import pandas as pd
import numpy as np
data1 = pd.read_csv('C:/Users/Administrator.SC-201905211330/spx.csv') #header=None时,即指明原始文件数据没有列索引,这样read_csv为自动加上列索引,除非你给定列索引的名字。
data=data1['SPX'] # or data1.spx,选取spx列
print('原始数据为:',data[:5] )
min = (data-data.min())/(data.max()-data.min()) #最小-最大规范化
zero = (data-data.mean())/data.std() #零-均值规范化
float = data/10**np.ceil(np.log10(data.abs().max())) #小数定标规范化,np.ceil()向上(正无穷)取整函数
print('最小-最大规范化后数据:n',min[:5])
print('零-均值规范化后数据:n',zero[:5])
print('小数规范化后数据:n',float[:5])
原始数据为: 0 328.79
1 330.92
2 331.85
3 329.66
4 333.75
Name: SPX, dtype: float64
最小-最大规范化后数据:
0 0.026251
1 0.027928
2 0.028661
3 0.026936
4 0.030157
Name: SPX, dtype: float64
零-均值规范化后数据:
0 -1.667805
1 -1.662041
2 -1.659524
3 -1.665451
4 -1.654382
Name: SPX, dtype: float64
小数规范化后数据:
0 0.032879
1 0.033092
2 0.033185
3 0.032966
4 0.033375
Name: SPX, dtype: float64
其他的一些第三方库也有类似预处理函数,如机器学习库sklearn中:最小-最大规范化函数是MinMaxScaler,Z-Score规范化函数是StandardScaler()等
(7)汇总和描述等统计量的计算
max,min,方差,标准差(Standard Deviation)等统计量、
import pandas as pd
import numpy as np
from pandas import Series,DataFrame
df = DataFrame(np.random.randn(4,3),index=list('abcd'),columns =['first','second','third'])
print(df.describe())#对数据统计量进行描述
first second third
count 4.000000 4.000000 4.000000
mean 0.094635 -0.481173 0.239956
std 0.396495 0.379548 1.155269
min -0.408514 -0.914881 -1.393335
25% -0.116806 -0.732928 -0.152447
50% 0.148771 -0.459812 0.586063
75% 0.360212 -0.208057 0.978466
max 0.489511 -0.090186 1.181033
----------------------------------------------------------------------------------------------------------
print(df.sum())#统计每列数据的和
print(df.sum(axis=1)) #统计每行(从左到右)数据和
print(df.idxmin()) #统计每列最小数值所在的行
print(df.idxmin(axis=1)) #统计每行最小数值所在的列
print(df.cumsum()) #计算相对于上一行的累计和
print(df.var()) #计算方差
print(df.std())#计算标准差差
print(df.pct_change()) #计算百分数变化
first 0.378540
second -1.924692
third 0.959825
dtype: float64
a 0.151427
b -1.748500
c 0.525172
d 0.485573
dtype: float64
first c
second d
third b
dtype: object
a second
b third
c first
d second
dtype: object
first second third
a -0.019570 -0.090186 0.261183
b 0.297542 -0.762463 -1.132152
c -0.110971 -1.009810 0.048881
d 0.378540 -1.924692 0.959825
first 0.157208
second 0.144056
third 1.334646
dtype: float64
first 0.396495
second 0.379548
third 1.155269
dtype: float64
first second third
a NaN NaN NaN
b -17.204010 6.454375 -6.334713
c -2.288230 -0.632075 -1.847630
d -2.198273 2.698771 -0.228689