我的Python分析成长之路11
数据预处理
如何对数据进行预处理,提高数据质量,是数据分析中重要的问题。
1.数据合并
堆叠合并数据,堆叠就是简单地把两个表拼在一起,也被称为轴向链接,绑定或连接。依照轴的方向,数据堆叠可分为横向堆叠和纵向堆叠。
1.横向堆叠,即将两个表在x轴向拼接在一起。可以使用concat函数完成。
pandas.concat(obj,axis=0,join="outer",join_axes=None,ignore_index=False,keys=None,levels=None,names=None)
obj:需要拼接党的pandas对象
axis:连接的轴,axis=0为纵向,axis=1为横向
join: inner(交集)或outer(并集)
ignore_index:表示是否不保留连接轴上的索引
当axis=1是表示横向连接,当两张表索引不完全一样时,可以使用参数选择内连接和外连接。在内连接情况下,仅仅返回索引重叠部分,在外连接情 况下,则显示索引的并集部分数据,不足部分就使用空值填补。
2.纵向堆叠,是将两个数据表在y轴方向上拼接。concat函数和append方法两者都可以纵向堆叠。即axis=0 当数据表的列名不完全相同时,可以使用 join参数,inner 取的是列名交集的列,outer返回的是两者列名并集所代表的的列。
1 import numpy as np 2 s1 = pd.Series([1,2],index=["a","b"]) 3 s2 = pd.Series([3,4,5],index=["c",'d',"e"]) 4 s3 = pd.Series([6,7],index=["f","g"]) 5 s4 = pd.concat([s1,s2,s3]) #默认按列连接 6 print(s4) 7 s5 = pd.concat([s1,s2,s3],axis=1) #按横向连接 8 print(s5) #没有重叠部分用缺失值填充 9 print(pd.concat([s1,s4],axis=1,join="inner")) #值保留重叠部分 10 df1= pd.DataFrame(np.arange(6).reshape(3,2),index=["a","b","c"],columns=["one","two"]) 11 df2 = pd.DataFrame(5+np.arange(4).reshape(2,2),index=["a","c"],columns=["three","four"]) 12 print(pd.concat([df1,df2],axis=1,keys=["level1","level2"])) 13 print(pd.concat({"level1":df1,"level2":df2},axis=1))
3.除了concat函数,append方法也可以纵向合并两张表,使用append的前提是两张表的列名一定要一样。
pandas.DataFrame.append(self,other,ignore_index=False,verify_integrity=False)
other:接受其他dataframe
ignore_index:接受boolean,如果为True,就会对DataFrame使用新的索引
1 df1= pd.DataFrame(np.arange(6).reshape(3,2),index=["a","b","c"],columns=["one","two"]) 2 df2 = pd.DataFrame(5+np.arange(4).reshape(2,2),index=["a","c"],columns=["one","two"]) 3 print(df1.append(df2))
2.主键合并数据
主键合并,即通过一个或多个键将两个数据集的行连接起来,针对两张不同字段的表,将其根据某几个字段一一对应拼接起来,结果集的列数为两个 原数据的列数和减去连接数的数量。
1.merge函数
pandas.merge(left,right,how="inner",no=None,left_on=None,right_on=None,left_index=False,right_index=False,sort=False)
left:添加的新数据1
right:添加的新数据2
how:连接方式inner,outer,left,right
on :表示两个连接的主键(必须一致)
left_on:表示left参数接受数据用于合并的主键
right_on:表示right参数接受数据用于合并的主键
left_index:是否将left参数接受数据的Index作为连接主键
right_index:是否将right参数接受数据的index作为连接主键
sort:表示是否根据连接键对合并后的数据进行排序
suffixes:接受tuple表示用于追加到left和right参数接收数据列名相同的后缀
1 pd.DataFrame({"key":["b",'b',"a","c"],"data1":np.arange(4)}) 2 df2 = pd.DataFrame({"key":["a","b","d"],"data2":np.arange(3)}) 3 print(pd.merge(df1,df2,on="key")) #主键必须相同,且保留公共部分 4 print(pd.merge(df1,df2,how='outer')) #用nan填充 5 df3 = pd.DataFrame({"key1":["b",'b',"a","c"],"data1":np.arange(4)}) 6 df4 = pd.DataFrame({"key2":["a","b","d"],"data2":np.arange(3)}) 7 print(pd.merge(df3,df4,left_on="key1",right_on="key2")) #如果两个主键不同就分别接受主键 8 print(pd.merge(df3,df4,left_on="key1",right_on="key2",how="outer"))
2.join函数
join函数也可以实现主键合并,但是两个主键的名字必须相同.pd.DataFrame.join(self,other,on=None,how="left",lsuffix=",rsuffix=",sort=False)
other:接受另一个dataFrame
on:连接的键
how:left:左连接,right:右连接,inner:内连接,outer:外连接
sort:键对合并后是否排序
3.重叠合并数据
数据分析和处理中偶尔会出现两份数据的内容几乎一致的情况,但在某些特征在一张表的数据是完整的,在另一张的数据是缺失的。
combine_first进行重叠数据合并
pandas.DataFrame.combine_first(other) 接受另外一个dataframe
1 df3 = pd.DataFrame({"key1":[np.nan,'b',"a","c"],"data1":[1,np.nan,2,np.nan]}) 2 df4 = pd.DataFrame({"key1":["a",np.nan,"d",np.nan],"data1":[np.nan,1,np.nan,3]}) 3 print(df3.combine_first(df4)) #用df4中的值重叠填充df3中的缺失值
3.清洗数据
数据重复会导致方差减小,数据分布发生较大变化。缺失会导致样本信息减少,不仅增加了分析的难度,而且会导致数据分析的结果产生偏差。异常 值则会产生“伪回归”,因此需要对数据进行检测,查询是否有重复值、缺失值和异常值,并且对这些数据进行适当的处理。
1.检测和处理重复值
对重复数据进行处理前,需要分析重复数据产生的原因和去除这部分数据后可能造成的不良影响。常见的数据重复分为两种:记录重复,即一个或多 个特征的某几条记录的值完全相同,特征重复:存在一个或多个特征名称不同,但数据完全相同。
一、记录重复
1.利用list去重 2.利用set的特性去重 3.利用drop_duplicates()去重 pd.DateFrame.drop_duplicates(subset=None,keep="frist",inplace=False) subset: 接受要去重的列,keep:去重后保留哪一个,“first”:保留第一个,“last”:保留最后一个,“false”:只要有重复都不保留, inplace:表示是否在原表上操作
1 import pandas as pd 2 lists=[1,2,3,2,5] 3 print(pd.Series(lists).drop_duplicates()) #利用pandas.drop_duplicates()去重 4 print(set(lists)) #利用set去重 5 6 def req(lists): 7 #定义去重函数,利用list去重 8 new_lists =[] 9 for i in lists: 10 if i not in new_lists: 11 new_lists.append(i) 12 return new_lists 13 print(req(lists))
二、特征重复
对于数值型数据,我们可以使用相似度矩阵去重
data.corr(method="") method: spearman kendall
对于类别型数据: dataFrame.equals()
def FeatureEqual(df): dfequal = pd.DataFrame([],index=df.columns,columns=df.columns) for i in df.columns: for j in df.columns: dfequal.loc[i:j]=dfequal[:,i].equals(dfequal[:,j]) return dfequal dfequal = FeatureEqual() #调用函数得特征重复的值 l = dfequal.shape[0] list2 =[] #记录需要去重的列 for m in range(l): for n in range(m+1,l): if dfequal.iloc[m:n] and (dfequal.columns[n] not in list2): list2.append(dfequal.columns[n]) print("需要去重的列:",list2) df.drop(list2,axis=1,inplace=True) #然后去重
2.检测与处理缺失值
数据中的某个或某些特征不是完整的,这些值称为缺失值。pandas中isnull和notnull分别判断是否缺失值
对于缺失值处理方法:
一.删除法:df.dropna(axis=0,how="any",thresh=None,subset=None,inplace=False) axis=0删除行 axis=1 删除列
1 import pandas as pd 2 import numpy as np 3 df = pd.DataFrame({"one":[1,2,3,np.nan],"two":[np.nan,4,5,6],"three":[10,9,7,8]}) 4 print(df) 5 print(df.dropna(axis=0))#删除缺失行 6 print(df.dropna(axis=1)) #删除缺失列 7 print(df.dropna(axis=0,how="all")) #删除全为缺失值的行 8 print(df.dropna(axis=0,thresh=2)) #保留含有2个即以上非缺失值的行
二、替换法
用一个特定的值替换缺失值,当缺失值为数值型时,利用其均值、众数、中位数等描述其集中趋势的统计量来代替缺失值;当缺失值为类别型数据时, 利用其众数来替换。
df.fillna(value=None,method=None,axis=None,inplace=False,limit=None)
value:替换缺失值的值,
method:backfill或biff使用下一个非缺失值来填充,ffill或firstfill 使用上一个非缺失值来填充
axis :轴线
inplace:是否在原表上进行
limit:表示填充缺失值的上限
·
print(df.fillna(method="ffill",axis=0)) #利用上一个非缺失值填充缺失值 print(df.fillna(df.mean(),axis=0)) #利用列向的均值来填充缺失值 from sklearn.preprocessing import Imputer #利用Impute类来实现 imr = Imputer(strategy="median",axis=1) df = imr.fit_transform(df.values) print(df) print(type(df))
3.插值法
删除法简单易行,但是会引起数据结构变动,样本减少。替换法使用难度低,但是会影响数据的标准差,导致信息量变动。利用插值法
插值法:1.线性插值2.多项式插值3.样条插值
1 import numpy as np 2 import scipy.interpolate as sci 3 x = np.array([1,2,3,4,7,8,9]) 4 y1 = np.array([2,8,18,32,50,128,162]) 5 y2 = np.array([3,5,7,9,11,17,19]) 6 linearvalue1 = sci.interp1d(x,y1,kind="linear") 7 linearvalue2 = sci.interp1d(x,y2,kind="linear") 8 print("当x为6、7时,使用线性插值y1为:",linearvalue1([5,6])) 9 print("当x为6、7时,使用线性插值y2为:",linearvalue2([5,6])) 10 linearvalue3 = sci.lagrange(x,y1) 11 linearvalue4 = sci.lagrange(x,y2) 12 print("当x为6、7时,使用拉格朗日插值y1为:",linearvalue3([5,6])) 13 print("当x为6、7时,使用拉格朗日插值y2为:",linearvalue4([5,6])) 14 linearvalue5 = sci.spline(x,y1,xnew=np.array([5,6])) 15 linearvalue6 = sci.spline(x,y2,xnew=np.array([5,6])) 16 print("当x为5、6时,使用样条插值",linearvalue5) 17 print("当x为5、5时,使用样条插值",linearvalue6)
检测异常值方法:
1.3δ原则
3δ原则又称拉依达准则.先假设一组检测数据只含有随机误差,对原始数据进行计算处理得到标准差,然后按一定的概率确定一个区间,认为误差超过 这个区间就属于异常。不过,这种处理方法仅适用于对正态或近视正态分布的样本数据进行处理。几乎处于(μ-3δ,μ+3δ)
2.使用箱型图分析
异常值被定义为QL-1.5QR或大于QL+1.5QR的值,QL为下四分位,QR为上四分位,IQR为上四分数QR与下四分位QL的差
1 def Outrange(serl): 2 outbool = (serl.mean()-3*serl.std()>serl)|(serl.mean()+3*serl.std()<serl) 3 index = np.arange(serl.shape[0]) 4 outrange = serl.iloc[index][outbool] 5 return outrange 6 Outrange(serl) #调用 获得异常 7 import matplotlib.pyplot as plt 8 plt.figure(figsize=(10,8)) 9 p = plt.boxplot(x) #使用箱型图来检测异常值 10 outrange = p['fliers'][0].get_ydata() #获得异常值
4.标准化数据
1.离差标准化数据
将数据缩放到[0,1]
2.标准差标准化
将数据变化为均值为0,方差为1,
3.小数定标标准化
通过移动小数位数,将数据缩放到[-1,1],移动的小数位数取决于数据绝对值的最大值。
1 def MinMaxScale(x): #离差标准化 2 x = (x-x.min())/(x.max()-x.min()) 3 return x 4 from sklearn.preprocessing import MinMaxScaler #机器学习库中调用 但是为 5 mms = MinMaxScaler() 6 mms.fit_transform(X) 7 def Standscale(x): 8 x = (x-x.mean())/x.std() 9 return x 10 std = Standscale(x) 11 from sklearn.preprocessing import StandardScaler 12 std = StandardScaler() 13 std.fit_transform(x) 14 def decimalscale(x): #小数位标准化数据 15 x = x/10**np.ceil(np.log(x.abs().max())) 16 return x 17 decimalscale(x)
5.转化数据
对于类别型数据,可以用机器学习库类标编码的技术、独热编码,指的是创建一个新的虚拟特征,虚拟特征的每一各代表类别型数据的一个值。还有使用pandas.get_dummies()
pandas.get_dummies(data,prefix=None,prefix_sep="_",dummy_na=False,columns=None,sparse=False,drop_first=False)
import pandas as pd from sklearn.preprocessing import LabelEncoder le = LabelEncoder() x = le.fit_transform(x) from sklearn.preprocessing import OneHotEncoder ohe = OneHotEncoder() ohe.fit_transform(x) pd.get_dummies(x)
离散化连续型数据方法
1.等宽法 将数据的值域分成相同宽度的区间,区间个数由数据本身或用户来确定
pandas.cut(x,bins) bins:离散化后类别的数目
2.等频法
def SamRateCut(data,k): #自定义等频法 w = data.quantile(0.1+1/k,1/k) data = pd.cut(data,w) return data SamRateCut(data,k) #调用