Python数据分析实战笔记—深入pandas:数据处理(1)

xiaoxiao2021-02-28  13

《Python数据分析实战》

上一章讲解了从数据库或文件等数据源获取数据的方法。

将数据转换为DataFrame格式后,你就可以对其进行处理了。数据处理的目的时准备数据,便于分析。数据处理很大程度上取决于必须进行数据分析的人员的目的,数据处理可以使要寻找的信息以更清晰的方式呈现出来。

这一章,我们深入讲解pandas库在数据处理阶段的功能。

数据处理又可以细分为三个阶段,数据处理的三个阶段为:数据准备、数据转换和数据聚合。

1.数据准备

数据准备阶段包括以下步骤:

加载组装(合并、拼接、组合)变形(轴向旋转)删除

在本章,尤其是这一节,你将会学到数据转换为统一的数据结构所需的各种操作。

对于存储在pandas对象中的各种数据,其组装方法有以下几种。

合并—pandas.merge()函数根据一个或多个键连接多行。拼接—pandas.concat()函数按照轴把多个对象拼接起来。组合—pandas.DataFrame.combine_first()函数从另一个数据结构获取数据,连接重合的数据,以填充缺失值。

此外,数据准备过程还可能涉及变换行、列位置的变形操作。

2.合并

合并:它使用一个或多个键把多行数据结合在一起。

合并类似SQL的JOIN查询,用几个表共有的引用值(键)从不同的表获取数据。以这些键为基础,我们能够获取到列表形式的新数据,这些数据是对几个表中的数据进行组合得到的。

pandas库中这类操作叫作合并,执行合并操作的函数为merge()。

frame1 >> id price 0 ball 12.33 1 pencil 11.44 2 pen 33.21 3 mug 13.23 4 ashtray 33.62 frame2 >> color id 0 white pencil 1 red pencil 2 red ball 3 black pen #merge()函数,执行合并操作。 pd.merge(frame1,frame2) >> id price color 0 ball 12.33 red 1 pencil 11.44 white 2 pencil 11.44 red 3 pen 33.21 black

由结果可见,返回的DataFrame对象由原来两个DataFrame对象中ID相同的行组成。

这个例子中,我们没有为merge()指定基于哪一列进行合并。实际应用中,绝大部分情况下需要指定基于哪一列进行合并。

具体做法是增加on选项,把列的名称作为用于合并的键赋给它。

frame1 =pd.DataFrame({ 'id':['ball','pencil','pen','mug','ashtray'], 'color':['white','red','red','black','green'], 'brand':['OMG','ABC','ABC','POD','POD'] }) frame2 =pd.DataFrame({ 'id':['pencil','pencil','ball','pen'], 'brand':['OMG','POD','ABC','POD'] }) #1.因为一个对象的列名称完全在另一个对象中也存在,所以对它们执行合并操作将得到一个空DataFrame对象 pd.merge(frame1,frame2) >> Empty DataFrame Columns:[barnds,color,id] Index:[] #2.我们使用on选项指定合并操作所依据的基准列 pd.merge(frame1,frame2,on='id') >> brand_x color id brand_y 0 OMG white ball ABC 1 ABC red pencil OMG 2 ABC red pencil POD 3 ABC red pen POD pd.merge(frame1,frame2,on='brand') >> brand color id_x id_y 0 OMG white ball pencil 1 ABC red pencil ball 2 ABC red pen ball 3 POD black mug pencil 4 POD black mug pen 5 POD green ashtray pencil 6 POD green ashtray pen

如你所料,合并标准不同,结果差异很大。

然而,问题随之就来了。假如两个DataFrame基准列的名称不一致,该怎样进行合并呢?为了解决这个问题,你可以用left_on和right_on选项指定第一个和第二个DataFrame的基准列。

pd.merge(frame1,frame2,left_on='id',right_on='sid') >> brand_x color id brand_y sid 0 OMG white ball ABC ball 1 ABC red pencil OMG pencil 2 ABC red pencil POD pencil 3 ABC red pen POD pen

merge()函数默认执行的是内连接操作;上述结果中的键是由交叉操作得到的。

其他选项由左连接、右连接和外连接。外连接把所有的键整合到一起,其效果相当于左连接和右连接的效果之和。连接类型用how选项指定。

frame2.columns['brand','id'] #1.默认内连接 pd.merge(frame1,frame2,on='id') >> brand_x color id brand_y 0 OMG white ball ABC 1 ABC red pencil OMG 2 ABC red pencil POD 3 ABC red pen POD #2.外连接 pd.merge(frame1,frame2,on='id',how='outer') >> brand_x color id brand_y 0 OMG white ball ABC 1 ABC red pencil OMG 2 ABC red pencil POD 3 ABC red pen POD 4 POD black mug NaN 5 POD green ashtray NaN #3.左连接 pd.merge(frame1,frame2,on='id',how='left') >> brand_x color id brand_y 0 OMG white ball ABC 1 ABC red pencil OMG 2 ABC red pencil POD 3 ABC red pen POD 4 POD black mug NaN 5 POD green ashtray NaN #4.右连接 pd.merge(frame1,frame2,on='id',how='right') >> brand_x color id brand_y 0 OMG white ball ABC 1 ABC red pencil OMG 2 ABC red pencil POD 3 ABC red pen POD #5.要合并多个键,则把多个键赋给on选项 pd.merge(frame1,frame2,on=['id','brand'],how='outer') >> brand color id 0 OMG white ball 1 ABC red pencil 2 ABC red pen 3 POD black mug 4 POD green ashtray 5 OMG NaN pencil 6 POD NaN pencil 7 ABC NaN ball 8 POD NaN pen

根据索引合并:

有时,合并操作不是用DataFrame的列而是用索引作为键。

把left_index和right_index选项的值置为True,将其激活,就可以将其作为合并DataFrame的基准。

pd.merge(frame1,frame2,right_index=True,left_index=True) >> brand_x color id_x brand_y id_y 0 OMG white ball OMG pencil 1 ABC red pencil POD pencil 2 ABC red pen ABC ball 3 POD black mug POD pen

但是DataFrame对象的join()函数更适合于根据索引进行合并。我们还可以用它合并多个索引相同或索引相同但列却不一致的DataFrame对象。

fram1.join(frame2)

pandas将会给出错误信息,因为frame1的列名称与frame2有重合。因此在使用join()函数之前,要重命名frame2的列。

frame2.columns = ['brand2','id2'] frame1.join(frame2) >> brand color id brand2 id2 0 OMG white ball OMG pencil 1 ABC red pencil POD pencil 2 ABC red pen ABC ball 3 POD black mug POD pen 4 POD green ashtray NaN NaN

上述合并操作是以索引而不是列为基准。

合并后得到的DataFrame对象包含只存在于frame1中的索引4,但是整合自frame2、索引号为4的各元素均为NaN。

3.拼接

另外一种数据整合操作叫作拼接。Numpy的concatenate()函数就是用于数组的拼接操作。Pandas的concat()函数实现了按轴拼接的功能。

array1 >> array([ [0,1,2], [3,4,5], [6,7,8] ]) array2 >> array([ [6,7,8], [9.10.11], [12,13,14] ]) #Numpy的concatenate()函数 np.concatenate([array1,array2],axis=0) >> array([ [0,1,2], [3,4,5], [6,7,8], [6,7,8], [9.10.11], [12,13,14] ]) np.concatenate([array1,array2],axis=1) >> array([ [0,1,2,6,7,8], [3,4,5,9,10,11], [6,7,8,12,13,14] ]) #Pandas的concat()函数 ser1 >> 1 0.636 2 0.345 3 0.157 4 0.070 ser2 >> 5 0.411 6 0.359 7 0.987 8 0.329 pd.concat([ser1,ser2]) >> 1 0.636 2 0.345 3 0.157 4 0.070 5 0.411 6 0.359 7 0.987 8 0.329 #concat()函数默认按照axis=0这条轴拼接数据,返回series对象。如果指定axis=1,返回结果将是DataFrame对象。 pd.concat([ser1,ser2],axis=1) >> 0 1 1 0.636 NaN 2 0.345 NaN 3 0.157 NaN 4 0.070 NaN 5 NaN 0.411 6 NaN 0.359 7 NaN 0.987 8 NaN 0.329

结果中无重合数据,因而刚执行的其实是外连接操作。把join选项设置为‘inner’,可执行内连接操作。

pd.concat([ser1,ser3],axis=1,join='inner') >> 0 0 1 1 0.636 0.636 NaN 2 0.345 0.345 NaN 3 0.157 0.157 NaN 4 0.070 0.070 NaN

这种操作的问题是,从结果中无法识别被拼接的部分。如果你想在用于拼接的轴上创建等级索引,就需要借助key选项来完成。

pd.concat([ser1,ser2],key=[1,2]) >> 1 1 0.636 2 0.345 3 0.157 4 0.070 2 5 0.411 6 0.359 7 0.987 8 0.329

按照axis=1拼接拼接Series对象,所指定的键变为拼接后得到的DataFrame对象各列的名称。

pd.concat([ser1,ser2],axis=1,key=[1,2]) >> 1 2 1 0.636 NaN 2 0.345 NaN 3 0.157 NaN 4 0.070 NaN 5 NaN 0.411 6 NaN 0.359 7 NaN 0.987 8 NaN 0.329

到目前为止,我们拼接的是Series对象,而DataFrame对象的拼接方法与之相同。

4.组合

还有另外一种情况,我们无法通过合并或拼接方法组合数据。例如,两个数据集的索引完全或部分重合。

combine_first()函数可以用来组合Series对象,同时对齐数据。

ser1 >> 1 0.942 2 0.035 3 0.886 4 0.809 5 0.800 ser2 >> 2 0.739 4 0.225 5 0.709 6 0.214 ser1.combine_fisrt(ser2) >> 1 0.942 2 0.033 3 0.886 4 0.809 5 0.800 6 0.214 ser2.combine_first(ser1) >> 1 0.942 2 0.739 3 0.886 4 0.225 5 0.709 6 0.214

反之,如果你想进行部分合并,仅指定要合并的部分即可。

ser1[:3].combine(ser2[:3]) >> 1 0.942 2 0.033 3 0.886 4 0.225 5 0.709

5.轴向旋转:

除了整合统一来自不同数据源的数据,另外一种常用操作为轴向旋转。 实际应用中,按行或列调整元素并不总能满足目标。 有时,需要按照行重新调整列的元素或是按列调整行。

按等级索引旋转:

轴向旋转有两个基础操作:

入栈:旋转数据结构,把列转换为行出栈:把行转换为列 frame1 >> ball pen pencil white 0 1 2 black 3 4 5 red 6 7 8 #对DataFrame对象应用stack()函数,会把列转换为行,从而得到一个Series对象 frame1.stack() >> white ball 0 pen 1 pencil 2 black ball 3 pen 4 pencil 5 red ball 6 pen 7 pencil 8

在这个具有等级索引结构的Series对象上执行unstack()操作,可以重建之前的DataFrame对象,从而可以以数据透视表的形式来展示Series对象中的等级索引结构。

ser5 >> white ball 0 pen 1 pencil 2 black ball 3 pen 4 pencil 5 red ball 6 pen 7 pencil 8 ser5.unstack() >> ball pen pencil white 0 1 2 black 3 4 5 red 6 7 8

出栈操作可以应用于不同的层级,为unstack()函数传入表示层级的编号或名称,即可对相应层级进行操作。

ser5.unstack(0) >> ball pen pencil white 0 1 2 black 3 4 5 red 6 7 8

从“长”格式向“宽”格式旋转:

longframe >> color item value 0 white ball 0.091 1 white pen 0.495 2 white mug 0.956 3 red ball 0.394 4 red pen 0.501 5 red mug 0.561 6 black ball 0.879 7 black pen 0.610 8 black mug 0.093

这种记录数据的一个缺点是,因为一些字段具有多样性和重复性特点,是以选取列作为键时,这种格式的数据可读性差,尤其时无法理解基准列和其他列之间的关系。

pandas提供了能够把长格式DataFrame格式转换为宽格式的pivot()函数,它以用作键的一列或多列作为参数。

#选择color列作为主键,item列作为第二主键 wideframe = longframe.pivot('color','item') wideframe >> value item ball mug pen color balck 0.879 0.093 0.610 red 0.394 0.561 0.501 white 0.091 0.956 0.495

6.删除:

del命令和drop()函数

frame1 >> ball pen pencil white 0 1 2 balck 3 4 5 red 6 7 8 #要删除一列,对DataFrame对象应用del命令,指定列名。 del frame1['ball'] frame1 >> pen pencil white 1 2 balck 4 5 red 7 8 #要删除多余的行,使用drop()函数,将索引的名作为参数 frame1.drop('white') frame1 >> ball pen pencil balck 3 4 5 red 6 7 8
转载请注明原文地址: https://www.6miu.com/read-1650298.html

最新回复(0)