主要内容:
数据预处理的必要性
数据清洗
数据集成
数据标准化
数据规约
数据变换与离散化
利用sklearn进行数据预处理
小结
1.缺失值的处理
(1)忽略元组
(2)人工填写缺失值
(3)使用一个全局常量填充缺失值
(4)使用属性的中心度量(如均值或中位数)填充缺失值
(5)使用与给定元组属同一类的所有样本的属性均值或中位数
(6)使用最可能的值填充缺失值
2.噪声数据的处理
噪声(Noise)是被测量的变量的随机误差或方差。噪声的处理方法一般有分箱、回归和离群点分析等方法。
(1)分箱
(2)回归
(3)离群点分析
1.检测与处理缺失值
Pandas使用浮点值NaN表示缺失数据。
(1)缺失值的检测与统计
利用isnull()函数检测缺失值。
import pandas as pd
import numpy as np
string_data = pd.Series(['aardvark','artichoke',np.nan,'avocado'])
print(string_data)
string_data.isnull()
# 0 aardvark
# 1 artichoke
# 2 NaN
# 3 avocado
# dtype: object
# 0 False
# 1 False
# 2 True
# 3 False
# dtype: bool
Series中的None值处理
string_data = pd.Series(['aardvark','artichoke',np.nan,'avocado'])
string_data.isnull()
# 0 False
# 1 False
# 2 True
# 3 False
# dtype: bool
(2)缺失值的统计
利用isnull().sum()方法统计缺失值
df = pd.DataFrame(np.arange(12).reshape(3,4),columns = ['A','B','C','D'])
df.ix[2,:] = np.nan
df[3] = np.nan
print(df)
df.isnull().sum()
# A B C D 3
# 0 0.0 1.0 2.0 3.0 NaN
# 1 4.0 5.0 6.0 7.0 NaN
# 2 NaN NaN NaN NaN NaN
# A 1
# B 1
# C 1
# D 1
# 3 3
# dtype: int64
df.ix[] 既可以通过整数索引进行数据选取,也可以通过标签索引进行数据选取,换句话说,df.ix[]是df.loc[]和df.iloc[]的功能集合,且在同义词选取中,可以同时使用整数索引和标签索引。
利用info()方法查看DataFrame的缺失值
df.info()
#
# RangeIndex: 3 entries, 0 to 2
# Data columns (total 5 columns):
# A 2 non-null float64
# B 2 non-null float64
# C 2 non-null float64
# D 2 non-null float64
# 3 0 non-null float64
# dtypes: float64(5)
# memory usage: 200.0 bytes
2.缺失值的处理
(1)删除缺失值
dropna()函数:删除具有缺失值的行。
dropna(axis = 0,how = 'any', thresh = None, subset = None, inplace = False)
参数 | 说明 |
---|---|
axis | 默认为 axis=0,当某行出现缺失值时,将该行丢弃并返回;当axis=1时,为某列出现缺失值,将该列丢弃 |
how | 确定缺失值个数,默认how='any’表明,只要某行有缺失值就将该行丢弃;how='all’表明某行全部为缺失值才将其丢弃 |
thresh | 阈值设定,行列中非默认值的数量小于给定的值,就将该行丢弃 |
subset | 部分标签中删除某行列,如subset=[‘a’,‘d’],即丢弃子列a和d中含有缺失值的行 |
inplace | 布尔值,默认为False,当inplace = True时,即对原数据操作,无返回值 |
对于Series,dropna()函数返回一个仅含非空数据和索引值的Series。
from numpy import nan as NA
data = pd.Series([1,NA,3.5,NA,7])
print(data)
print(data.dropna())
# 0 1.0
# 1 NaN
# 2 3.5
# 3 NaN
# 4 7.0
# dtype: float64
# 0 1.0
# 2 3.5
# 4 7.0
# dtype: float64
布尔型索引选择过滤非缺失值。
not_null = data.notnull()
print(not_null)
print(data[not_null])
# 0 True
# 1 False
# 2 True
# 3 False
# 4 True
# dtype: bool
# 0 1.0
# 2 3.5
# 4 7.0
# dtype: float64
对于DataFrame对象,dropna()函数默认丢弃任何含有缺失值的行。
from numpy import nan as NA
data = pd.DataFrame([[1.,5.5,3.],[1.,NA,NA],[NA,NA,NA],[NA,5.5,3.]])
print(data)
cleaned = data.dropna()
print('删除缺失值后的:\n',cleaned)
# 0 1 2
# 0 1.0 5.5 3.0
# 1 1.0 NaN NaN
# 2 NaN NaN NaN
# 3 NaN 5.5 3.0
# 删除缺失值后的:
# 0 1 2
# 0 1.0 5.5 3.0
传入how=‘all’ 将只丢弃全为NA的那些行。
data = pd.DataFrame([[1.,5.5,3.],[1.,NA,NA],[NA,NA,NA],[NA,5.5,3.]])
print(data)
print(data.dropna(how='all'))
# 0 1 2
# 0 1.0 5.5 3.0
# 1 1.0 NaN NaN
# 2 NaN NaN NaN
# 3 NaN 5.5 3.0
# 0 1 2
# 0 1.0 5.5 3.0
# 1 1.0 NaN NaN
# 3 NaN 5.5 3.0
丢弃DataFrame的列。只须传入axis=1即可。
data = pd.DataFrame([[1.,5.5,NA],[1.,NA,NA],[NA,NA,NA],[NA,5.5,NA]])
print(data)
print(data.dropna(axis = 1,how='all'))
# 0 1 2
# 0 1.0 5.5 NaN
# 1 1.0 NaN NaN
# 2 NaN NaN NaN
# 3 NaN 5.5 NaN
# 0 1
# 0 1.0 5.5
# 1 1.0 NaN
# 2 NaN NaN
# 3 NaN 5.5
当thresh=N时,表示要求一行至少具有N个非NaN才能保留。
df = pd.DataFrame(np.random.randn(7,3))
df.iloc[:4,1] = NA
df.iloc[:2,2] = NA
print(df)
print(df.dropna(thresh=2))
# 0 1 2
# 0 -0.344574 NaN NaN
# 1 -1.036411 NaN NaN
# 2 1.350421 NaN -0.299612
# 3 1.801679 NaN -1.674728
# 4 0.072237 1.331576 -0.393538
# 5 -1.155418 -0.727690 -0.306949
# 6 0.537618 -1.820370 -0.118417
# 0 1 2
# 2 1.350421 NaN -0.299612
# 3 1.801679 NaN -1.674728
# 4 0.072237 1.331576 -0.393538
# 5 -1.155418 -0.727690 -0.306949
# 6 0.537618 -1.820370 -0.118417
(2)填充缺失值
缺失值替换方法fillna():
pandas.DataFrame.fillna(value=None,method=None,axsi=None,inplace=False,limit=None)
参数 | 说明 |
---|---|
value | 用于填充缺失值的标量值或字典对象 |
method | 插值方式 |
axis | 待填充的轴,默认axis=0 |
inplace | 修改调用者对象而不产生副本 |
limit | (对于前向和后向填充)可以连续填充的最大数量 |
通过字典形式填充缺失值。
df = pd.DataFrame(np.random.randn(5,3))
df.loc[:3,1] = NA
df.loc[:2,2] = NA
print(df)
print(df.fillna({1:0.88,2:0.66}))
# 0 1 2
# 0 1.487451 NaN NaN
# 1 -0.594379 NaN NaN
# 2 -0.125070 NaN NaN
# 3 0.905233 NaN -1.448934
# 4 -0.264390 -1.201126 -0.660528
# 0 1 2
# 0 1.487451 0.880000 0.660000
# 1 -0.594379 0.880000 0.660000
# 2 -0.125070 0.880000 0.660000
# 3 0.905233 0.880000 -1.448934
# 4 -0.264390 -1.201126 -0.660528
fillna()函数中参数method的应用。
df = pd.DataFrame(np.random.randn(6,3))
df.iloc[2:,1] = NA
df.iloc[4:,2] = NA
print(df)
print(df.fillna(method = 'ffill'))
# 0 1 2
# 0 0.140363 0.504090 -0.595635
# 1 0.451219 0.445143 -1.690518
# 2 -0.759913 NaN 2.837122
# 3 0.879716 NaN -1.009732
# 4 -1.656160 NaN NaN
# 5 -0.128482 NaN NaN
# 0 1 2
# 0 0.140363 0.504090 -0.595635
# 1 0.451219 0.445143 -1.690518
# 2 -0.759913 0.445143 2.837122
# 3 0.879716 0.445143 -1.009732
# 4 -1.656160 0.445143 -1.009732
# 5 -0.128482 0.445143 -1.009732
用Series的均值填充。
data = pd.Series([1.,NA,3.5,NA,7])
data.fillna(data.mean())
# 0 1.000000
# 1 3.833333
# 2 3.500000
# 3 3.833333
# 4 7.000000
# dtype: float64
DataFrame中用均值填充。
df = pd.DataFrame(np.random.randn(4,3))
df.iloc[2:,1] = NA
df.iloc[3:,2] = NA
print(df)
df[1] = df[1].fillna(df[1].mean())
print(df)
# 0 1 2
# 0 -0.651648 0.026439 1.933004
# 1 0.150372 -0.556725 0.365933
# 2 -0.231654 NaN -1.678729
# 3 1.563050 NaN NaN
# 0 1 2
# 0 -0.651648 0.026439 1.933004
# 1 0.150372 -0.556725 0.365933
# 2 -0.231654 -0.265143 -1.678729
# 3 1.563050 -0.265143 NaN
3.数据值替换
使用replace()方法替换数据值。
data = {'姓名':['张三','小明','马芳','国志'],'性别':['0','1','0','1'],'籍贯':['北京','甘肃','','上海']}
df = pd.DataFrame(data)
df = df.replace('','不详')
print(df)
# 姓名 性别 籍贯
# 0 张三 0 北京
# 1 小明 1 甘肃
# 2 马芳 0 不详
# 3 国志 1 上海
传入列表实现多值替换。
df = df.replace(['不详','甘肃'],['兰州','兰州'])
print(df)
# 姓名 性别 籍贯
# 0 张三 0 北京
# 1 小明 1 兰州
# 2 马芳 0 兰州
# 3 国志 1 上海
传入字典实现多值替换。
df = df.replace({'1':'男','0':'女'})
print(df)
# 姓名 性别 籍贯
# 0 张三 女 北京
# 1 小明 男 兰州
# 2 马芳 女 兰州
# 3 国志 男 上海
4.利用函数或映射进行数据转换
map()方法映射数据。
data = {'姓名':['张三','小明','马芳','国志'],'性别':['0','1','0','1'],'籍贯':['北京','兰州','兰州','上海']}
df = pd.DataFrame(data)
df['成绩'] = [58,86,91,78]
print(df)
def grade(x):
if x>=90:
return '优'
elif 70<=x<90:
return '良'
elif 60<=x<70:
return '中'
else:
return '差'
df['等级'] = df['成绩'].map(grade)
print(df)
# 姓名 性别 籍贯 成绩
# 0 张三 0 北京 58
# 1 小明 1 兰州 86
# 2 马芳 0 兰州 91
# 3 国志 1 上海 78
# 姓名 性别 籍贯 成绩 等级
# 0 张三 0 北京 58 差
# 1 小明 1 兰州 86 良
# 2 马芳 0 兰州 91 优
# 3 国志 1 上海 78 良
5.异常值检测
(1)散点图方法
import pandas as pd
wdf = pd.DataFrame(np.arange(20),columns = ['W'])
wdf['Y'] = wdf['W']*1.5+2
wdf.iloc[3,1] = 128
wdf.iloc[18,1] = 150
wdf.plot(kind = 'scatter',x = 'W',y = 'Y')
盒图:利用箱线图进行异常值检测时,根据经验,将最大(最小)值设置为与四分位数值间距为1.5个IQR(IQR=Q3-Q2)的值,即min=Q1-1.5IQR,max=Q3+1.5IQR,小于min和大于max的值被认为是异常值。
import matplotlib.pyplot as plt
plt.boxplot(wdf['Y'].values,notch = True)
若数据服从正态分布,在3σ原则下,异常值被定义为一组测定值中与平均值的偏差超过3倍标准差的值,因为在正态分布的假设下,距离平均值3σ之外的值出现的概率小于0.003。因此根据小概率事件,可以认为超出3σ之外的值为异常数据。
def outRange(S):
blidx = (S.mean()-3*S.std()>S)|(S.mean()+3*S.std()<S)
idx = np.arange(S.shape[0])[blidx]
outRange = S.iloc[idx]
return outRange
outier = outRange(wdf['Y'])
outier
# 18 150.0
# Name: Y, dtype: float64