第5章Pandas数据载入与预处理 对于数据分析而言,数据大部分来源于外部数据,如常用的CSV文件、Excel文件和数据库文件等。Pandas库将外部数据转换为DataFrame数据格式,处理完成后再存储到相应的外部文件中。 视频讲解 5.1数据载入 5.1.1读/写文本文件 1. 文本文件读取 文本文件是一种由若干行字符构成的计算机文件,它是一种典型的顺序文件。CSV是一种逗号分隔的文件格式,因为其分隔符不一定是逗号,又被称为字符分隔文件,文件以纯文本形式存储表格数据(数字和文本)。 在Pandas中使用read_table函数来读取文本文件: pandas.read_table(filepath_or_buffer, sep='\t', header='infer', names=None, index_col=None, dtype=None, engine=None, nrows=None) 在Pandas中使用read_csv函数来读取CSV文件: pandas.read_csv(filepath_or_buffer, sep=',', header='infer', names=None, index_col=None, dtype=None, engine=None, nrows=None) 两个文本文件读取方法中的常用参数及其说明见表51。 表51read_table和read_csv常用参数及其说明 参数说明 filepath接收string,代表文件路径,无默认 sep接收string,代表分隔符。read_csv默认为“,”,read_table默认为制表符“[Tab]”,如果分隔符指定错误,在读取数据的时候,每一行数据将连成一片 header接收int或sequence,表示将某行数据作为列名,默认为infer,表示自动识别 names接收array,表示列名,默认为None index_col接收int、sequence或False,表示索引列的位置,取值为sequence则代表多重索引,默认为None dtype接收dict,代表写入的数据类型(列名为key,数据格式为values),默认为None engine接收c或者python,代表数据解析引擎,默认为c nrows接收int,表示读取前n行,默认为None 【例51】使用read_csv函数读取CSV文件。 In[1]:df1 = pd. read_csv('文件路径文件名') #读取CSV文件到DataFrame中 df2 = pd. read_table('文件路径文件名', sep = ',') #使用read_table,并指定分隔符 df3 = pd. read_csv('文件路径文件名',names = ['a','b',---]) #文件不包含表头行,允许自动分配默认列名,也可以指定列名 2. 文本文件的存储 文本文件的存储和读取类似,结构化数据可以通过Pandas中的to_csv函数实现以CSV文件格式存储文件。 DataFrame.to_csv(path_or_buf = None, sep = ',', na_rep=", columns=None, header=True, index=True,index_label=None,mode='w',encoding=None) 5.1.2读/写Excel文件 1. Excel文件的读取 Pandas提供了read_excel函数读取xls和xlsx两种Excel文件,其格式为: pandas.read_excel(io,sheetname,header=0,index_col=None,names=None,dtype) read_excel函数和read_table函数的部分参数相同,其常用参数及其说明见表52。 表52Pandas读/写Excel文件 参数说明 io接收string,表示文件路径,无默认 sheetname接收string、int,代表Excel表内数据的分表位置,默认为0 续表 参数说明 header接收int或sequence,表示将某行数据作为列名,默认为infer,表示自动识别 names接收int、sequence或者False,表示索引列的位置,取值为sequence则代表多重索引,默认为None index_col接收int、sequence或者False,表示索引列的位置,取值为sequence则代表多重索引,默认为None dtype接收dict,代表写入的数据类型(列名为key,数据格式为values),默认为None 【例52】读取Excel文件。 In[2]:xlsx = pd.excelFile('example/ex1.xlsx') pd.read_excel(xlsx, 'Sheet1') #也可以直接使用 frame = pd.read_excel('example/ex1.xlsx', 'Sheet1') 2. Excel文件的存储 将文件存储为Excel文件,可以使用to_excel方法。其语法格式如下: DataFrame.to_excel(excel_writer=None, sheetname=None', na_rep=", header=True, index=True, index_label=None, mode='w', encoding=None) to_excel与to_csv方法的常用参数基本一致,区别之处在于to_excel指定存储文件的文件路径参数名称为excel_writer,并且没有sep参数,增加了一个sheetnames参数用来指定存储的Excel Sheet的名称,默认为sheet1。 5.1.3JSON数据的读取与存储 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,其简洁和清晰的层次结构使其成为理想的数据交换语言。JSON数据使用大括号来区分表示并存储。 1. Pandas读取JSON数据 Pandas通过read_json函数读取JSON数据,读取时会出现顺序错乱的问题,因此要对行索引进行排序。读取代码如下: import pandas as pd df=pd.read_json('FileName') df=df.sort_index 2. JSON数据的存储 Pandas使用pd.to_json实现将DataFrame数据存储为JSON文件。 5.1.4读取数据库文件 在许多应用中,很多文件来源于数据库。Pandas实现了便捷连接并存取数据库文件的方法。 1. Pandas读取MySQL数据 要读取MySQL中的数据,首先要安装MySQLdb包,然后进行数据文件读取。读取代码如下: import pandas as pd import MySQLdb conn = MySQLdb.connect(host = host,port = port,user = username,passwd = password,db = db_name) df = pd.read_sql('select * from table_name',con=conn) conn.close() 2. Pandas读取SQL Server中的数据 要读取SQL Server中的数据,首先要安装pymssql包,然后进行数据文件读取。读取代码如下: import pandas as pd import pymssql conn = pymssql.connect(host=host, port=port ,user=username, password=password, database=database) df = pd.read_sql("select * from table_name",con=conn) conn.close() 5.2合并数据 在实际的数据分析中,可能有不同的数据来源,因此需要对数据进行合并处理。 5.2.1merge数据合并 Python中的merge函数是通过一个或多个键将两个DataFrame按行合并起来,与SQL中的join用法类似,Pandas中的数据合并函数merge()格式如下: merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None) merge方法的主要参数及其说明见表53。 表53merge方法的主要参数及其说明 参数说明 left参与合并的左侧DataFrame right参与合并的右侧DataFrame how连接方法: inner,left,right,outer on用于连接的列名 left_on左侧DataFrame中用于连接键的列 right_on右侧DataFrame中用于连接键的列 left_index左侧DataFrame中行索引作为连接键 right_index右侧DataFrame中行索引作为连接键 sort合并后会对数据排序,默认为True suffixes修改重复名 【例53】merge的默认合并数据。 In[3]:price = pd.DataFrame({'fruit':['apple','grape','orange','orange'], 'price':[8,7,9,11]}) amount = pd.DataFrame({'fruit':['apple','grape','orange'],'amout':[5,11,8]}) display(price,amount,pd.merge(price,amount)) Out[3]: 由于两个DataFrame都有fruit列,所以默认按照该列进行合并,默认how='inner', 即pd.merge(amount,price,on='fruit',how='inner')。如果两个DataFrame的列名不相同,可以单独指定。 【例54】指定合并时的列名。 In[4]:display(pd.merge(price,amount,left_on = 'fruit',right_on = 'fruit')) Out[4]: merge合并时默认是内连接(inner),即返回交集。通过how参数可以选择连接方法: 左连接(left)、右连接(right)和外连接(outer)。 【例55】左连接。 In[5]:display(pd.merge(price,amount,how = 'left')) Out[5]: 【例56】右连接。 In[6]:display(pd.merge(price,amount,how = 'right')) Out[6]: 也可以通过多个键进行合并。 【例57】merge通过多个键合并。 In[7]:left = pd.DataFrame({'key1':['one','one','two'],'key2':['a','b','a'], 'value1':range(3)}) right = pd.DataFrame({'key1':['one','one','two','two'],'key2':['a','a','a','b'], 'value2':range(4)}) display(left,right,pd.merge(left,right,on = ['key1','key2'],how = 'left')) Out[7]: 在合并时会出现重复列名,虽然可以人为进行重复列名的修改,但merge函数提供了suffixes用于处理该问题。 【例58】merge函数中参数suffixes的应用。 In[8]:print(pd.merge(left,right,on = 'key1')) print(pd.merge(left,right,on = 'key1',suffixes = ('_left','_right'))) Out[8]: key1 key2_xvalue1 key2_yvalue2 0onea0a0 1onea0a1 2oneb1a0 3oneb1a1 4twoa2a2 5twoa2b3 key1 key2_leftvalue1 key2_rightvalue2 0onea0a0 1onea0a1 2oneb1a0 3oneb1a1 4twoa2a2 5twoa2b3 5.2.2concat数据连接 如果要合并的DataFrame之间没有连接键,就无法使用merge方法,可以使用Pandas中的concat方法。默认情况下会按行的方向堆叠数据; 如果在列向上连接,设置axis=1即可。 【例59】两个Series的数据连接。 In[9]:s1 = pd.Series([0,1],index = ['a','b']) s2 = pd.Series([2,3,4],index = ['a','d','e']) s3 = pd.Series([5,6],index = ['f','g']) print(pd.concat([s1,s2,s3])) #Series行合并 Out[9]:a0 b1 a2 d3 e4 f5 g6 dtype: int64 【例510】两个DataFrame的数据连接。 In[10]:data1 = pd.DataFrame(np.arange(6).reshape(2,3),columns = list('abc')) data2 = pd.DataFrame(np.arange(20,26).reshape(2,3),columns = list('ayz')) data = pd.concat([data1,data2],axis = 0) display(data1,data2,data) Out[10]: 通过结果可以看出,concat连接方式为外连接(并集),通过传入join='inner'可以实现内连接。 可以通过join_axis指定使用的索引顺序。 【例511】指定索引顺序。 In[11]:s1 = pd.Series([0,1],index = ['a','b']) s2 = pd.Series([2,3,4],index = ['a','d','e']) s3 = pd.Series([5,6],index = ['f','g']) s4 = pd.concat([s1*5,s3],sort=False) s5 = pd.concat([s1,s4],axis = 1,sort=False) s6 = pd.concat([s1,s4],axis = 1,join = 'inner',sort=False) s7 = pd.concat([s1,s4],axis = 1,join = 'inner',join_axis = [['b','a']], sort=False) display(s4,s5,s6,s7) Out[11]: 5.2.3combine_first合并数据 如果需要合并的两个DataFrame存在重复索引,则使用merge和concat都无法正确合并,此时需要使用combine_first方法。数据w1和w2分别如下所示: w1w2 【例512】使用combine_first合并。 In[12]:w1.combine_first(w2) Out[12]: 视频讲解 5.3数据清洗 数据一般是不完整、有噪声和不一致的。数据清洗试图填充缺失的数据值、光滑噪声、识别离群点并纠正数据中的不一致。 5.3.1检测与处理缺失值 在许多数据分析工作中,经常会有缺失数据的情况。 Pandas的目标之一就是尽量轻松地处理缺失数据。 1. 缺失值的处理 Pandas对象的所有描述性统计默认都不包括缺失数据。对于数值数据,Pandas使用浮点值NaN表示缺失数据。 1) 缺失值的检测与统计 函数isnull()可以直接判断该列中的哪个数据为NaN。 【例513】使用isnull检测缺失值。 In[13]:string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado']) print(string_data) string_data.isnull() Out[13]:0aardvark 1artichoke 2NaN 3avocado dtype: object 0False 1False 2True 3False dtype: bool 在Pandas中,缺失值表示为NA,它表示不可用(not available)。在统计应用中,NA数据可能是不存在的数据,或者存在却没有观察到的数据(例如数据采集中发生了问题)。当清洗数据用于分析时,最好直接对缺失数据进行分析,以判断数据采集问题或缺失数据可能导致的偏差。Python内置的None值也会被当作NA处理。 【例514】Series中的None值处理。 In[14]:string_data = pd.Series(['aardvark', 'artichoke',np.nan, 'avocado']) string_data.isnull() Out[14]:0False 1False 2True 3False dtype: bool 2) 缺失值的统计 【例515】使用isnull().sum()统计缺失值。 In[15]: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() Out[15]:ABCD3 00.01.02.03.0NaN 14.05.06.07.0NaN 2NaNNaNNaNNaNNaN A1 B1 C1 D1 33 dtype: int64 另外,通过info方法,也可以查看DataFrame每列数据的缺失情况。 【例516】用info方法查看DataFrame的缺失值。 In[16]:df.info() Out[16]:<class 'pandas.core.frame.DataFrame'> RangeIndex: 3 entries, 0 to 2 Data columns (total 5 columns): A2 non-null float64 B2 non-null float64 C2 non-null float64 D2 non-null float64 30 non-null float64 dtypes: float64(5) memory usage: 200.0 bytes 2. 缺失值的处理 1) 删除缺失值 在缺失值的处理方法中,删除缺失值是常用的方法之一。通过dropna方法可以删除具有缺失值的行。 dropna方法的格式: dropna(axis=0, how='any', thresh=None, subset=None, inplace=False) dropna的参数及其说明见表54。 表54dropna的参数及其说明 参数说明 axis 默认为axis=0,当某行出现缺失值时,将该行丢弃并返回; 当axis=1,且某列出现缺失值时,将该列丢弃 how确定缺失值个数,缺省时how='any',how='any'表明只要某行有缺失值就将该行丢弃,how='all'表明某行全部为缺失值才将其丢弃 thresh阈值设定,当行列中非缺失值的数量少于给定的值就将该行丢弃 subset部分标签中删除某行列,例如subset=[ 'a','d'], 即丢弃子列a d中含有缺失值的行 inplacebool取值,默认为False, 当inplace= True,即对原数据操作,无返回值 对于Series,dropna返回一个仅含非空数据和索引值的Series。 【例517】Series的dropna用法。 In[17]:from numpy import nan as NA data = pd.Series([1, NA, 3.5, NA, 7]) print(data) print(data.dropna()) Out[17]:01.0 1NaN 23.5 3NaN 47.0 dtype: float64 01.0 23.5 47.0 dtype: float64 当然,也可以通过布尔型索引达到这个目的。 【例518】布尔型索引选择过滤非缺失值。 In[18]:not_null = data.notnull() print(not_null) print(data[not_null]) Out[18]:0True 1False 2True 3False 4True dtype: bool 01.0 23.5 47.0 dtype: float64 对于DataFrame对象,dropna默认丢弃任何含有缺失值的行。 【例519】DataFrame对象的dropna默认参数使用。 In[19]: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) Out[19]:012 01.05.53.0 11.0NaNNaN 2NaNNaNNaN 3NaN5.53.0 删除缺失值后的: 012 01.05.53.0 传入how='all'将只丢弃全为NA的那些行。 【例520】传入参数all。 In[20]:data = pd.DataFrame([[1., 5.5, 3.], [1., NA, NA],[NA, NA, NA], [NA, 5.5, 3.]]) print(data) data.dropna(how='all') Out[20]: 如果用同样的方式丢弃DataFrame的列,只需传入axis = 1即可。 【例521】dropna中的axis参数应用。 In[21]:data = pd.DataFrame([[1., 5.5, NA], [1., NA, NA],[NA, NA, NA], [NA, 5.5, NA]]) print(data) data.dropna(axis = 1, how = 'all') Out[21]: 使用thresh参数,当传入thresh=N时,表示要求一行至少具有N个非NaN才能存活。例如df.dropna(thresh=len(df)*0.9, axis=1) 表示如果某列数据中的缺失值超过10%,则删除该列。 【例522】dropna中的thresh参数应用。 In[22]:df = pd.DataFrame(np.random.randn(7, 3)) df.iloc[:4, 1] = NA df.iloc[:2, 2] = NA print(df) df.dropna(thresh=2) Out[22]: 2) 填充缺失值 直接删除有缺失值的样本并不是一个很好的方法,因此可以用一个特定的值替换缺失值。缺失值所在的特征为数值型时,通常使用其均值、中位数和众数等描述其集中趋势的统计量来填充; 缺失值所在特征为类别型数据时,则选择众数来填充。Pandas库中提供了缺失值替换的方法fillna。 fillna的格式: pandas.DataFrame.fillna(value=None,method=None,axis=None,inplace=False, limit=None) fillna参数及其说明见表55。 表55fillna参数及其说明 参数说明 value用于填充缺失值的标量值或字典对象 method插值方式 axis待填充的轴,默认为axis=0 inplace修改调用者对象而不产生副本 limit(对于前向和后向填充)可以连续填充的最大数量 通过一个常数调用fillna就会将缺失值替换为那个常数值,例如df.fillna(0)用零代替缺失值; 也可以通过一个字典调用fillna,就可以实现对不同的列填充不同的值。 【例523】通过字典形式填充缺失值。 In[23]:df = pd.DataFrame(np.random.randn(5,3)) df.loc[:3,1] = NA df.loc[:2,2] = NA print(df) df.fillna({1:0.88,2:0.66}) Out[23]: fillna默认会返回新对象,但也可以通过参数inplace=True对现有对象进行就地修改。对reindex有效的那些插值方法也可用于fillna。 【例524】fillna中method的应用。 In[24]:df = pd.DataFrame(np.random.randn(6, 3)) df.iloc[2:, 1] = NA df.iloc[4:, 2] = NA print(df) df.fillna(method = 'ffill') Out[24]: 可以使用fillna实现许多别的功能,例如可以传入Series 的平均值或中位数。 【例525】用Series的均值填充。 In[25]:data = pd.Series([1., NA, 3.5, NA, 7]) data.fillna(data.mean()) Out[25]:01.000000 13.833333 23.500000 33.833333 47.000000 dtype: float64 【例526】在DataFrame中用均值填充。 In[26]: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) Out[26]:012 00.6561550.0084420.025324 10.1608450.8291271.065358 2-0.321155NaN-0.955008 30.953510NaNNaN 012 00.6561550.0084420.025324 10.1608450.8291271.065358 2-0.3211550.418785-0.955008 30.9535100.418785NaN 对于fillna的参数,可以通过“df.fillna?”进行帮助查看。 5.3.2检测与处理重复值 数据中存在重复样本时只需保留一份即可,其余的可以做删除处理。在DataFrame中使用duplicates方法判断各行是否有重复数据。duplicates方法返回一个布尔值的Series,反映每一行是否与之前的行重复。 【例527】判断DataFrame中的重复数据。 In[27]:data = pd.DataFrame({ 'k1':['one','two'] * 3 + ['two'],'k2':[1, 1, 2, 3, 1, 4, 4], 'k3':[1,1,5,2,1, 4, 4] }) print(data) data.duplicated() Out[27]:k1k2k3 0one11 1two11 2one25 3two32 4one11 5two44 6two44 0False 1False 2False 3False 4True 5False 6True dtype: bool Pandas通过drop_duplicates删除重复的行,drop_duplicates方法的格式为: pandas.DataFrame(Series). drop_duplicates(self, subset=None, keep='first',inplace=False) 该方法常用的参数及其说明见表56。 表56drop_duplicates的主要参数及其说明 参数说明 subset接收string或sequence,表示进行去重的列,默认全部列 keep接收特定string,表示重复时保留第几个数据,'first'保留第一个,'last'保留最后一个,'False'只要有重复都不保留,默认为first inplace接收布尔型数据,表示是否在原表上进行操作,默认为False 使用drop_duplicates方法去重时,当且仅当subset参数中的特征重复时才会执行去重操作,去重时可以选择保留哪一个或者不保留。 【例528】每行各个字段都相同时去重。 In[28]:data.drop_duplicates() Out[28]: 【例529】指定部分列重复时去重。 In[29]:data.drop_duplicates(['k2','k3']) Out[29]: 默认保留的数据为第一个出现的记录,通过传入keep='last'可以保留最后一个出现的记录。 【例530】去重时保留最后出现的记录。 In[30]:data.drop_duplicates(['k2','k3'],keep = 'last') Out[30]: 5.3.3检测与处理异常值 异常值是指数据中存在的个别数值明显偏离其余数据的值。异常值的存在会严重干扰数据分析的结果,因此经常要检验数据中是否有输入错误或含有不合理的数据。在数据统计方法中一般常用散点图、箱线图和3σ法则检测异常值。 1. 散点图方法 通过数据分布的散点图发现异常数据。 【例531】使用散点图检测异常值。 In[31]: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') Out[31]:<matplotlib.axes._subplots.AxesSubplot at Ox2680853ca20> 2. 箱线图分析 箱线图使用数据中的5个统计量(最小值、下四分位数Q1、中位数Q2、上四分位数Q3和最大值)来描述数据,它也可以粗略地看出数据是否具有对称性、分布的分散程度等信息。利用箱线图还可以进行异常值检测。在检测过程中,根据经验,将最大(最小)值设置为与四分位数值间距为1.5个IQR(IQR=Q3-Q2)的值,即min=Q1-1.5IQR,max=Q3+1.5IQR,小于min和大于max的值被认为是异常值。 【例532】使用箱线图分析异常值。 In[32]:import matplotlib.pyplot as plt plt.boxplot(wdf['Y'].values,notch = True) Out[32]: 3. 3σ法则 若数据服从正态分布,在3σ原则下,异常值被定义为一组测定值中与平均值的偏差超过3倍标准差的值,因为在正态分布的假设下,距离平均值3σ之外的值出现的概率小于0.003。因此根据小概率事件,可以认为超出3σ之外的值为异常数据。 【例533】使用3σ法则检测异常值。 In[33]: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 Out[33]:18150.0 Name: Y, dtype: float64 5.3.4数据转换 1. 数据值替换 数据值替换是将查询到的数据替换为指定数据。在Pandas中通过replace进行数据值的替换。 【例534】使用replace替换数据值。 In[34]:data = {'姓名':['李红','小明','马芳','国志'],'性别':['0','1','0','1'], '籍贯':['北京','甘肃','','上海']} df = pd.DataFrame(data) df = df.replace('','不详') print(df) Out[34]:姓名性别籍贯 0李红0北京 1小明1甘肃 2马芳0不详 3国志1上海 也可以同时对不同值进行多值替换,参数传入的方式可以是列表,也可以是字典格式。传入的列表中,第一个列表为被替换的值,第二个列表是对应替换的值。 【例535】使用replace传入列表实现多值替换。 In[35]:df = df.replace(['不详','甘肃'],['兰州','兰州']) print(df) Out[35]:姓名性别籍贯 0李红0北京 1小明1兰州 2马芳0兰州 3国志1上海 【例536】使用replace传入字典实现多值替换。 In[36]:df = df.replace({'1':'男','0':'女'}) print(df) Out[36]:姓名性别籍贯 0李红女北京 1小明男兰州 2马芳女兰州 3国志男上海 2. 使用函数或映射进行数据转换 在数据分析中,经常需要进行数据的映射或转换,在Pandas中可以自定义函数,然后通过map方法实现。 【例537】使用map方法映射数据。 In[37]: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) Out[37]:姓名性别籍贯成绩 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.4数据标准化 不同特征之间往往具有不同的量纲,由此造成数值之间的差异。为了消除特征之间量纲和取值范围的差异可能会造成的影响,需要对数据进行标准化处理。 5.4.1离差标准化数据 离差标准化是对原始数据所做的一种线性变换,将原始数据的数值映射到[0,1]。转换公式如下: x1=x-minmax-min(5.1) 【例538】数据的离差标准化。 In[38]:def MinMaxScale(data): data = (data-data.min())/(data.max()-data.min()) return data x = np.array([[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]]) print('原始数据为:\n',x) x_scaled = MinMaxScale(x) print('标准化后矩阵为:\n',x_scaled,end = '\n') Out[38]:原始数据为: [[1.-1.2.] [ 2.0. 0.] [ 0.1.-1.]] 标准化后矩阵为: [[0.666666670.1.] [1.0.333333330.33333333] [0.33333333 0.666666670.]] 5.4.2标准差标准化数据 标准差标准化又称为零均值标准化或z分数标准化,是当前使用最广泛的数据标准化方法。经过该方法处理的数据均值为0,标准差为1,转换公式如下: x1=x-meanstd(5.2) 【例539】数据的标准差标准化。 In[39]:def StandardScale(data): data = (data-data.mean())/data.std() return data x = np.array([[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]]) print('原始数据为:\n',x) x_scaled = StandardScale(x) print('标准化后矩阵为:\n',x_scaled,end = '\n') Out[39]:原始数据为: [[1.-1. 2.] [ 2.0.0.] [0.1.-1.]] 标准化后矩阵为: [[0.52128604-1.355343691.4596009] [1.4596009-0.41702883-0.41702883] [-0.41702883 0.52128604-1.35534369]] 视频讲解 5.5数据变换与数据离散化 数据分析的预处理除了数据清洗、数据合并和标准化之外,还包括数据变换的过程,如类别型数据变换和连续型数据的离散化。 5.5.1类别型数据的哑变量处理 类别型数据是数据分析中十分常见的特征变量,但是在进行建模时,Python不能像R那样去直接处理非数值型的变量,因此往往需要对这些类别变量进行一系列转换,如哑变量。 哑变量(Dummy Variables)又称为虚拟变量,是用以反映质的属性的一个人工变量,是量化了的质变量,通常取值为0或1。Python中使用Pandas库中的get_dummies函数对类别型特征进行哑变量处理。 【例540】数据的哑变量处理。 In[40]:df = pd.DataFrame([ ['green', 'M', 10.1, 'class1'], ['red', 'L', 13.5, 'class2'], ['blue', 'XL', 15.3, 'class1']]) df.columns = ['color', 'size', 'prize','class label'] print(df) pd.get_dummies(df) Out[40]:colorsizeprizeclasslabel 0greenM10.1class1 1redL13.5class2 2blueXL15.3class1 对于一个类别型特征,若取值有m个,则经过哑变量处理后就变成了m个二元互斥特征,每次只有一个激活,使得数据变得稀疏。 5.5.2连续型变量的离散化 数据分析和统计的预处理阶段,经常会碰到年龄、消费等连续型数值,而很多模型算法,尤其是分类算法,都要求数据是离散的,因此要将数值进行离散化分段统计以提高数据区分度。 常用的离散化方法主要有等宽法、等频法和聚类分析法。 1. 等宽法 将数据的值域划分成具有相同宽度的区间,区间个数由数据本身的特点决定或由用户指定。Pandas提供了cut函数,可以进行连续型数据的等宽离散化。cut函数的基本语法格式为: pandas.cut(x,bins,right=True,labels=None,retbins=False,precision=3) cut函数的主要参数及其说明见表57。 表57cut函数的主要参数及其说明 参数说明 x接收array或Series,待离散化的数据 bins接收int、list、array和tuple。若为int指离散化后的类别数目,若为序列型则表示进行切分的区间,每两个数的间隔为一个区间 right接收boolean,代表右侧是否为闭区间,默认为True labels接收list、array,表示离散化后各个类别的名称,默认为空 retbins接收boolean,代表是否返回区间标签,默认为False precision接收int,显示标签的精度,默认为3 【例541】cut函数应用。 In[41]:np.random.seed(666) score_list = np.random.randint(25, 100, size = 10) print('原始数据:\n',score_list) bins = [0, 59, 70, 80, 100] score_cut = pd.cut(score_list, bins) print(pd.value_counts(score_cut)) # 统计每个区间人数 Out[41]:原始数据: [27 70 55 87 95 98 55 61 86 76] (80, 100]4 (0, 59] 3 (59, 70] 2 (70, 80] 1 dtype: int64 【例542】将泰坦尼克数据集中的年龄字段按下面规则分组转换为分类特征: (≤12,儿童)、(≤18,青少年)、(≤60,成人)、(>60,老人) In[42]:import seaborn as sns import sys # 导入泰坦尼克数据集 df = sns.load_dataset('titanic') display(df.head()) df['ageGroup']=pd.cut( df['age'], bins=[0, 13, 19, 61, sys.maxsize], labels=['儿童', '青少年', '成人', '老人'] ) # sys.maxsize是指可以存储的最大值 display(df.head()) Out[42]: 使用等宽法离散化对数据分布具有较高要求,若数据分布不均匀,那么各个类的数目也会变得不均匀。 2. 等频法 cut函数虽然不能够直接实现等频离散化,但可以通过定义将相同数量的记录放进每个区间。 【例543】等频法离散化连续型数据。 In[43]:def SameRateCut(data,k): k = 2 w = data.quantile(np.arange(0,1+1.0/k,1.0/k)) data = pd.cut(data,w) return data result = SameRateCut(pd.Series(score_list),3) result.value_counts() Out[43]:(73.0, 98.0]5 (27.0, 73.0]4 dtype: int64 相比较于等宽法,等频法避免了类分布不均匀的问题,但同时也有可能将数值非常接近的两个值分到不同的区间以满足每个区间对数据个数的要求。 3. 聚类分析法 一维聚类的方法包括两步,首先将连续型数据用聚类算法(如KMeans算法等)进行聚类,然后处理聚类得到的簇,为合并到一个簇的连续型数据做同一标记。聚类分析的离散化需要用户指定簇的个数来决定产生的区间数。 5.6本章小结 本章主要针对数据预处理阶段的需求,介绍了使用Pandas数据载入、合并数据、数据清洗、数据标准化及数据转换的典型方法。 5.7本章习题 一、 单项选择题 1. 利用可视化绘图()可以发现数据的异常点。 A. 密度图 B. 直方图 C. 盒图 D. 概率图 2. 以下关于缺失值检测的说法中,正确的是()。 A. null和notnull可以对缺失值进行处理 B. dropna方法既可以删除观测记录,也可以删除特征 C. fillna方法中用来替换缺失值的值只能是数据框 D. Pandas库中的interpolate模块包含多种插值方法 二、 判断对错题 1. Pandas中利用merge函数合并数据表时默认的是内连接方式。 () 2. Pandas中的描述性统计一般会包括缺失数据。 () 3. 语句dataframe.dropna(thresh=len(df)*0.9,axis=1) 表示如果某列的缺失值超过90%则删除该列。() 4. 利用merge方法合并数据时允许合并的DataFrame之间没有连接键。 () 5. 哑变量(Dummy Variables)又称虚拟变量,是用以反映质的属性的一个人工变量。() 三、 简答题 1. 简述Pandas删除空缺值方法dropna中参数thresh的使用方法。 2. 简述Python中利用数据统计方法检测异常值的常用方法及其原理。 3. 简述数据分析中要进行数据标准化的主要原因。 4. 简述Pandas中利用cut方法进行数据离散化的用法。 5.8本章实训 本实训将第4章用到的小费数据集进行随机修改后(tips_mod.xls)进行预处理。 1. 导入模块 In[1]:import pandas as pd import numpy as np 2. 获取数据 导入待处理数据tips_mod.xls,并显示前5行。 In[2]:fdata = pd.read_excel('D:/dataset/tips_mod.xls') fdata.head() Out[2]: 3. 分析数据 (1) 查看数据的描述信息。 In[3]:print(fdata.shape) fdata.describe() Out[3]:(244.7) 通过结果可以看出,共有244条记录,通过每个字段的均值和方差,看不出数据有异常。 (2) 显示聚餐时间段time的不重复值。 In[4]:fdata['time'].unique() Out[4]:array(['Dinner', 'Diner', 'Dier', 'Lunch', nan], dtype = object) 从结果发现有两个拼写错误“Diner”和“Dier”。 (3) 修改拼写错误的字段值。 In[5]:fdata.ix[fdata['time']=='Diner','time'] = 'Dinner' fdata.ix[fdata['time']=='Dier','time'] = 'Dinner' fdata['time'].unique() Out[5]:array(['Dinner', 'Lunch', nan], dtype = object) (4) 检测数据中的缺失值。 In[6]:fdata.isnull().sum() Out[6]:total_bill3 tip3 sex 2 smoker 0 day 0 time 2 size 3 dtype: int64 (5) 删除一行内有两个缺失值的数据。 In[7]:fdata.dropna(thresh = 6,inplace = True) fdata.isnull().sum() Out[7]:total_bill2 tip 3 sex 2 smoker 0 day 0 time 2 size 3 dtype: int64 (6) 删除sex或time为空的行。 In[8]:fdata.dropna(subset = ['sex','time'],inplace = True) fdata.isnull().sum() Out[8]:total_bill2 tip 3 sex 0 smoker 0 day 0 time 0 size 3 dtype: int64 (7) 对剩余有空缺的数据用平均值替换。 In[9]:fdata.fillna(data.mean(),inplace = True) fdata.isnull().sum() Out[9]:total_bill0 tip 0 sex 0 smoker 0 day 0 time 0 size 0 dtype: int64