数据预处理

一.数据预处理概述

   常遇到的数据存在噪声、冗余、关联性、不完整性等。

数据预处理常见处理方法:

(1)数据清理:补充缺失值、消除噪声数据、识别或删除离群点(异常值)并解决不一致性。

    目标:数据格式标准化、异常数据清除、重复数据清除、错误纠正

(2)数据集成:将多个数据数据源中的数据进行整合并统一存储

(3)数据变换:通过平滑狙击、数据概化、规范化等方式将数据转换成适用数据挖掘的形式

(4)数据归约:针对在数据挖掘时,数据量非常大。数据归约技术指对数据集进行归约or简化,不仅保持原数据的完整性,且数据归约后的结果与归约前的结果相同或几乎相同。

二.数据清理

1.异常数据处理

  异常数据也称离群点,指采集的数据中,个别数据值明显偏离其余观测值。对这些数据需采用一定的方法消除,否则对结果产生影响。

(1)异常数据分析

  a.统计量判断:max,min,均值,检查数据是否超出合理范围

  b.3σ原则:根据正态分布定义,出现距离均值3σ以上数值属于小概率事件,此时,数据和均值的偏差超过3倍标准差的视为异常值。操作参考https://www.cnblogs.com/wd19/p/11195897.html

  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())

out:
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())

out:
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))

out:
          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))

out:
          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}))

out:
          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()}))

out:
          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)拉格朗日插值法

图片来源:https://blog.csdn.net/sinat_22510827/article/details/80972389

  此处着重介绍算法的实现。

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)

out:
       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) out: [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)

out:
       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函数保存文件
out: ,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)

out:
               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())

out:
    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'))

out:
--删除重复的内容后---
    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])

out:
原始数据为: 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())#对数据统计量进行描述

out:
          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()) #计算百分数变化

out:
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

  

 

posted @ 2019-07-16 14:09  可乐5266  阅读(2163)  评论(0编辑  收藏  举报