Pandas使用小结

一、引言

终于放假了,又可以抽出时间来写点博客,这一学期本来以为有数字图像处理的课程,可以在图像处理方面学点理论知识,没想到只是个入门科普性质的课程,虽然有点干货稍微把零散的知识点串了起来,但落实到具体的理论基础也只是一笔带过。阴差阳错的帮老师做了些数据处理和筛选的工作,算是Pandas的重度使用患者了,本篇博客就来记录一下Pandas的基本使用、 常用函数、和某些偏门的方法吧。

二、基本使用方法

i.pandas数据类型

  pandas里面常用的数据类型有SeriseDataFrame,二者在使用的时候还是有着大的差异,例如对前者可以使用argmax()的方法找到最大值的索引,而后者则没有这样的用法。自我感觉,DataFrame的用法更加的灵活,因为Pandas中有着一个十分灵活的函数apply(),它可以将DataFrame的所有行或者列作为Series输入一个给定函数,由此DataFrame就可以使用Series所特有的函数了,例如之前介绍的寻找最大值索引作用到DataFrame上就可以表示为df.apply(lambda x:x.argmax())(后续会进一步介绍apply()的用法).而很多DataFrame中的函数如merge()、concat()则无法移植到Series上,所以后续的介绍基本都是以DataFrame为默认数据类型,如用到Series会特意标注。

ii.DataFrame的创建

 DataFrame的创建分为从文件导入和直接创立两种方式。

a)从文件导入

范例如下:
df=pd.read_csv('test.csv',sep='\t',header='infer')
arg1为要导入的数据文件,虽然函数名为read_csv,实际上可以导入的数据格式并不只局限于.csv文件,txt文件也是可以导入的;
可选参数sep限定了文件的分隔符,默认分隔符为空格;
可选参数header限定了文件是否包含列名,如果包含列名的话,header=‘infer’,导入时将第一行作为DataFrame的列名;如果不含列名,header=None,导入时不考虑列名,列名默认按0、1、2…给出;

b)直接创立

范例如下:
df=pd.DataFrame({'a':[1,2,3,4],'b':[5,6,7,8],'c':[9,10,11,12]})
也可使用:
df=pd.DataFrame([[1,5,9],[2,6,10],[3,7,11],[4,8,12]],columns=['a','b','c'])
结果如下:

   a  b   c
0  1  5   9
1  2  6  10
2  3  7  11
3  4  8  12

iii.DataFrame的属性

DataFrame的常用属性包括了列名(columns)、行名(index)、大小(size)、形状(shape),使用df.columns类似形式即可访问,接下来重点介绍行名和列名的修改。
设使用的DataFrame为:

	a  b   c
0  1  5   9
1  2  6  10
2  3  7  11
3  4  8  12

行名:[0,1,2,3]
列名:[‘a’,‘b’,‘c’]
需要着重强调的是无论是列名还是行名都要着重注意数字的出现,索引‘1’(字符型)与1(整型)是完全不同的。

a)列修改

对某些特定的列名进行修改时可以使用如下所示方法:
df.rename({'a':'d','b':'e'},axis=1)
其中key即为要修改的列名,value为修改后的列名,axis=1表示为对列进行操作。结果如下所示

   d  e   c
0  1  5   9
1  2  6  10
2  3  7  11
3  4  8  12

如果列名的操作是针对于所有列,且所有列名修改都遵循某一规律,比如想在所有列后面加后缀‘_1’,就可以使用rename的改名函数用法,如下:
df.rename(lambda x:x+'_1',axis=1)
这里使用的函数是简单的匿名函数,如果是需要进行判断后的改名,也可以自定义函数后传入函数名。结果如下所示:

   a_1  b_1  c_1
0    1    5    9
1    2    6   10
2    3    7   11
3    4    8   12

需要注意的是rename()函数不是立即生效函数,这就是为什么第二次rename的结果第一列列名是‘a_1’而不是‘d_1’,如果想作用于当前DataFrame,可以使用df=df.rename()或者df.rename(inplace=True)。

如果列名的操作是针对所有列,但无同一规律,修改方法为:
df.columns=['d','e','f']

   d  e   f
0  1  5   9
1  2  6  10
2  3  7  11
3  4  8  12

如果是需要对列的顺序进行修改的话可以用:
df=df[['b','a','c']]
结果如下:

   b  a   c
0  5  1   9
1  6  2  10
2  7  3  11
3  8  4  12

b)行修改

行名修改的方式与列名修改的方式类似,不再赘述,只给出参考代码和结果:
df.rename({1:'d',2:'2'})

   a  b   c
0  1  5   9
d  2  6  10
2  3  7  11
3  4  8  12

df.rename(lambda x:x*2)

   a  b   c
0  1  5   9
2  2  6  10
4  3  7  11
6  4  8  12

df=df.loc[[3,2,0,1]]

   a  b   c
3  4  8  12
2  3  7  11
0  1  5   9
1  2  6  10

df.index=['d','e','f','g']

   a  b   c
d  1  5   9
e  2  6  10
f  3  7  11
g  4  8  12

需要注意两点:一是使用rename()函数的时候,axis默认为0即对行进行操作;二是如果对行顺序进行改变,不能直接用[]的方式进行访问,因为这种方式是对列进行的操作,而应该使用.loc[],这种方式默认对行进行操作。

如果需要自行设置行索引的话,可以使用set_index()函数,使用方式如下:
df.set_index('a',drop=False)
其中arg1为新行索引的列名,drop为选择是否要舍弃作为索引的列,默认为True即将要作为索引的列从DataFrame中移除。结果如下:

   a  b   c
a          
1  1  5   9
2  2  6  10
3  3  7  11
4  4  8  12

行索引还可进行重设,这一性质常用于当对行进行了drop()操作后保证了行索引的连续性,便于定位。假定drop后的DataFrame如下:

   a  b   c
0  1  5   9
1  2  6  10
3  4  8  12

重设行索引方式如下:
df.reset_index(drop=True)
其中drop设定是否在重设索引后,默认为False,即保留当前的索引列将其作为DataFrame中的一列,列名为’index’。结果如下:

   a  b   c
0  1  5   9
1  2  6  10
2  4  8  12

iv.DataFrame的访问方式

DataFrame的常用访问方式有三种:[].loc[].iloc[] ,其具体使用方式见下:
[]方式是直接选取列的操作,其使用范例为:
df['a']

0    1
1    2
2    3
3    4
Name: a, dtype: int64

为了说明.iloc[].ilo[]的区别,接下来使用的DataFrame为:

   a  b   c
d  1  5   9
e  2  6  10
f  3  7  11
g  4  8  12

.loc[]方式即可选取行、也可以选取某一个值,使用范例为:
df.loc['d']

a    1
b    5
c    9
Name: d, dtype: int64

选取行时给的参数为行名,返回值是一个Series
df.loc['d','a']

1

选取某一个值时,参数为行名列名,需要注意这里用的词是行名,如果行名不是行的顺序的话,就应该使用行名。这里也可使用[[1,2],'a']来访问多个数据。


.iloc[]也既可选取行和某些特定值,使用范例为:
df.iloc[0]

a    1
b    5
c    9
Name: d, dtype: int64

选某一行时,参数为行顺序
df.iloc[0,0]

1

选取某一个值时,参数为行顺序列顺序而非之前的行名列名

三、常用函数

i.merge()

  merge()函数通常是用于求得两个DataFrame的交集或者并集,具体来说就是以两个DataFrame中各自一列(或者行索引)作为键值在列的方向上进行拼接,其具体参数如下:
pd.merge( left, right, how: str = 'inner', on=None, left_on=None, right_on=None, left_index: bool = False, right_index: bool = False, sort: bool = False, suffixes=('_x', '_y'), copy: bool = True, indicator: bool = False, validate=None, )


常用参数介绍:
left:进行合并的左DataFrame;
right:进行合并的右DataFrame;
on:用于合并的键值,要求在左右DataFrame中都能找到该列,默认为None,即自动选取共同列作为合并的键值(可以用多列作为键值);

how:进行合并的方式,默认为’inner’方式,可选方式还有:‘outer’,‘left’,‘right’。

'inner’方式意味着取交集,即只取两个DataFame中键值列中相同的部分所在行作为合并后的新行;
‘outer’方式意味着取并集,即取两个DataFrame中键值列中所有值所在行作为合并后的新行,对于某个DataFrame不包含该键值行,则以Nan填充;
‘left’方式意味着按左DataFrame进行合并,即保留左DataFrame中所有行,舍弃右DataFrame中与之键值不同的行,对于右DataFrame中不包含的左键值行,以Nan填充;
‘right’方式与’left’方式类似,不再赘述;

假定左DataFrame(df1):

   a  b   c
0  1  5   9
1  2  6  10
2  3  7  11
3  4  8  12

右DataFrame(df2):

   a  b   e
0  1  6   9
1  3  7  11

若直接执行df1.merge(df2):则采用on=None、how=‘inner’的方式,首先寻找共同列‘a’、’b‘,再取两df中[a,b]的交集:3,7,保留两df中该行,结果为:

   a  b   c   e
0  3  7  11  11

若执行df1.merge(df2,on='a'):则只寻找共同列’a’,取两df中[a]的交集:1、3,保留两df中对应行,结果为:

   a  b_x   c  b_y   e
0  1    5   9    6   9
1  3    7  11    7  11

若执行df1.merge(df2,on='a',how='outer'):则寻找共同列‘a’,取两df中[a]的并集:1、2、3、4,结果为:

   a  b_x   c  b_y     e
0  1    5   9  6.0   9.0
1  2    6  10  NaN   NaN
2  3    7  11  7.0  11.0
3  4    8  12  NaN   NaN

若执行df1.merge(df2,on='a',how='right'):则保留df2的所有行,df1中多余行舍去,结果为:

   a  b_x   c  b_y   e
0  1    5   9    6   9
1  3    7  11    7  11

其余参数介绍:

left_onright_on:当左右DataFrame中不存在公共列的时候,使用left_on、right_on、分别指定两DataFrame中用于合并的键值列;
left_indexright_index:当需要以两DataFrame中的行索引作为键值列进行合并时,设定left_index、right_index为True即可实现;
suffixes:当左右DataFrame中存在不止一列公共列,而并未取其所有所有作为合并键值,结果中势必会出现两列名相同的列,suffixes为共同列设定后缀以区别,默认为’_x’、‘_y’。

merge()函数有个很好的特性,就是合并后所得到的DataFrame其行顺序是和左DataFrame的顺序一致的,也就是说如果我们已知所计算样本的某些性质、总体的另一些性质,只需将样本作为左DF和总体进行merge,就可以得到样本的所有性质,同时样本的顺序不会发生改变,如果后续有操作涉及到对应项的加减乘除,这一顺序不变性将十分有用。

ii.concat()

concat()函数也是用于对DataFrame进行拼接的,相较于merge(),它可用于多个DataFrame的合并拼接,且不只局限于列方向上的拼接,还可作用于行,但自我感觉灵活性方面较merge()略差,所以一般将其用于行列名完全相同的DF拼接。其具体参数如下:
pd.concat( objs: Union[Iterable[~FrameOrSeries], Mapping[Union[Hashable, NoneType], ~FrameOrSeries]], axis=0, join='outer', ignore_index: bool = False, keys=None, levels=None, names=None, verify_integrity: bool = False, sort: bool = False, copy: bool = True, )
常用参数:
obj:用于拼接的DF;
axis:选择在哪一方向上拼接,默认为axis=0,即在行方向上进行拼接(增加行),axis=1时为在列方向上拼接;
ignore_index:选择是否忽略当前拼接方向上已有的索引,按默认0、1、2重新赋予索引,常用于在行方向上拼接时避免索引重复;
假定用于拼接的两DF(df1,df2)如下:

   a  b   c
0  1  5   9
1  2  6  10
2  3  7  11
3  4  8  12
    a   b   c
0  13  15  17
1  14  16  18

则执行pd.concat([df1,df2],ignore_index=True)结果为:

    a   b   c
0   1   5   9
1   2   6  10
2   3   7  11
3   4   8  12
4  13  15  17
5  14  16  18

执行pd.concat([df1,df2],axis=1)结果为:

   a  b   c     a     b     c
0  1  5   9  13.0  15.0  17.0
1  2  6  10  14.0  16.0  18.0
2  3  7  11   NaN   NaN   NaN
3  4  8  12   NaN   NaN   NaN

iii.apply()

apply()函数用于将DF中的每一行(列)作为某一函数的输入,并收集所有的返回值合并为一个Series或者DataFrame输出。其使用方式为:
df1.apply(func, axis=0, raw=False, result_type=None, args=(), **kwds)


常用参数:

func : 要使用的函数名,可以使用匿名函数;
axis:传入的轴,默认为0,即将每一行作为单独的Series传入函数;
result_type:设定apply返回值的数据类型,可以为Series或者DataFrame,默认值为None,可选值:‘reduce’、‘broadcast’和
‘expand’。需要注意的是经过实验和查阅文档发现,该参数的调整只有当axis=1时才有效,若axis=0,则result为单个值时返回Series,多个值时返回DataFrame(即使result为数组的形式)。

‘expand’:当函数func的返回值是类似于数组的形式时,将Seriies传入func时会将所得result中的每一个值作为单独一列,每个Series的函数返回值拼接在一起形成DataFrame返回;
’reduce’:可能的情况下将函数func的返回值作为一个整体,将每个Series的返回值数组作为一个值,所有的返回值拼在一起构成Series;
‘broadcast’:返回值最终会经broadcast变成和输入DataFrame一样的shape,广播机制较为复杂,不推荐使用;
None:当func的返回值为数组形式时,最终返回Seies;当func的返回值为Series时,最终返回DataFrame;
另经实验发现,当func返回值为Series时,即使设置为‘reduce’,最终返回值仍是DataFrame,而非Series。

args=(),**kwds:当func具有多个输入值时,通过设置args或者kwds来给出,具体见之后的范例;
假定func为:

def test(df):
    return [df.max(),df.argmax()]

使用的DataFrame(df1)为:

   a  b   c
0  1  5   9
1  2  6  10
2  3  7  11
3  4  8  12

若执行df1.apply(test,axis=1):默认result_type为None,结果为:

0     [9, 2]
1    [10, 2]
2    [11, 2]
3    [12, 2]
dtype: object

若执行df1.apply(test,axis=1,result_type='expand'):则输出为DataFrame,结果为:

    0  1
0   9  2
1  10  2
2  11  2
3  12  2

若执行df1.apply(test,axis=1,result_type='reduce'):则此时结果和默认值一致;
将func变更为:

def test(df,adding):
    return pd.Series([df.max(),df.argmax()])+adding

若执行df1.apply(test,args=(2,),axis=1),则结果为:

    0  1
0  11  4
1  12  4
2  13  4
3  14  4

若执行df1.apply(test,axis=1,**{'adding':2}),则结果为:

    0  1
0  11  4
1  12  4
2  13  4
3  14  4

需要注意的是,如果以args=()的方式传入多个参数,括号中的逗号不能省略。

iv.groupby()

goupby()函数用于对DataFrame进行分类,通常是用于对总体中不同种类的样本进行聚合,之后按类求取特征或者进行后续处理(常用agg(),apply(),describe())。其函数范例如下:
df1.groupby( by=None, axis=0, level=None, as_index: bool = True, sort: bool = True, group_keys: bool = True, squeeze: bool = <object object at 0x000002696E5D2CC0>, observed: bool = False, dropna: bool = True, )


常用参数:
by:此参数用于指定如何分类,理论上来说是可以用不同方式,例如函数、dict、Series等等,但实际上并不常用,通常都是用列名或者列名list来进行分类;
as_indexgroup_keys:都是用于设置apply()应用于group之后所得DataFrame的索引,as_index、group_keys为True时返回DataFrame将使用键值同时作为索引(最终为多级索引),group_keys为False时返回DataFrame将使用原索引(单级索引),as_index为False时返回DataFrame将使用新的0、1、2等等同时作为索引(最终为多级索引),详见后续范例;
假定使用DataFrame为:

  name  v1  v2
0    a   1  10
1    a   2  11
2    b   3  12
3    a   4  13
4    b   5  14
5    c   6  15
6    c   7  16
7    a   8  17
8    a   9  18
9    b   0  19

执行df.groupby('name').apply(lambda x:print(x))
结果为

  name  v1  v2
0    a   1  10
1    a   2  11
3    a   4  13
7    a   8  17
8    a   9  18
  name  v1  v2
2    b   3  12
4    b   5  14
9    b   0  19
  name  v1  v2
5    c   6  15
6    c   7  16

执行df.groupby('name').apply(lambda x:x.iloc[[0,1]]):此时as_index、group_keys均为默认值True;
结果为

       name  v1  v2
name               
a    0    a   1  10
     1    a   2  11
b    2    b   3  12
     4    b   5  14
c    5    c   6  15
     6    c   7  16

执行df.groupby('name',as_index=False).apply(lambda x:x.iloc[[0,1]])
结果为

    name  v1  v2
0 0    a   1  10
  1    a   2  11
1 2    b   3  12
  4    b   5  14
2 5    c   6  15
  6    c   7  16

执行df.groupby('name',group_keys=False).apply(lambda x:x.iloc[[0,1]])
结果为

  name  v1  v2
0    a   1  10
1    a   2  11
2    b   3  12
4    b   5  14
5    c   6  15
6    c   7  16

四、零散知识

i.缺失值的处理

当我们从文件中读取数据时,很重要的一步是判断数据是否有缺失值、重复值,以及该如何处理这些缺失值、重复值,Pandas提供了一系列函数来干这件事情。
假定使用的DataFrame(df)为:

   a   b      c
0  1   6  111.0
1  2   7   12.0
2  3   8    NaN
3  1   9   13.0
4  1  10   14.0

执行df.duplicated('a',keep='last')获取存在重复值的行,arg1为用于判断重复值的列,如果不填的话则默认为所有列的组合(此处为[‘a’,‘b’,‘c’]);ag2用于设定如何标记重复值。

默认值’first’:除第一个重复值所在行之外所有存在重复值行标记为True,其余行为False;
可选值‘last’:除最后一个重复值所在行标记为True,其余行为False;
可选值‘False’:所有重复值均标记为True

结果为

0     True
1    False
2    False
3     True
4    False
dtype: bool

执行df.drop_duplicates('a',keep='last')以删除存在重复值的行,参数含义和前述一致,另有inplace(就地执行)、ignore_index(结果重编索引)可选;
结果为

   a   b     c
1  2   7  12.0
2  3   8   NaN
4  1  10  14.0

执行df.isna()df.isnull()以获取存在Nan值的布尔型DataFrame;

isna()和isnull()的用途完全一样,因为pandas的数据类型是基于numpy的,而numpy中并未对na和null进行区分,统一用nan表示,所以这两个函数没有区别,单纯是模仿R语言。
可通过df.isna().sum(0).sum()获取nan值的数目

结果为

       a      b      c
0  False  False  False
1  False  False  False
2  False  False   True
3  False  False  False
4  False  False  False

执行df.dropna(1,how='any')以删除存在Nan值的行或列,arg1为轴,arg2为删除依据

默认值‘any’:只要存在Nan就删除
可选值’all’:所有值都为Nan才删除
如果想自行设定存Nan阈值,可使用thresh参数:这一行去除nan值,剩余值数目大于thresh值,则保留该行;

ii.DataFrame特征值获取

常用DataFrame特征值有最小值,最大值,平均值等等,每一个都有其专用的求取函数,如果需要获取这所有的特征值则没有必要一个个求取,可以使用describe()函数获得这一系列的特征值。
假定使用DataFrame(df):

   a   b      c
0  1   6  111.0
1  2   7   12.0
2  3   8    NaN
3  1   9   13.0
4  1  10   14.0

执行df.describe(),默认只使用数字类型的数值;
结果为

              a          b           c
count  5.000000   5.000000    4.000000
mean   1.600000   8.000000   37.500000
std    0.894427   1.581139   49.006802
min    1.000000   6.000000   12.000000
25%    1.000000   7.000000   12.750000
50%    1.000000   8.000000   13.500000
75%    2.000000   9.000000   38.250000
max    3.000000  10.000000  111.000000

iii.DataFrmae类型获取及修改

DataFrame类型通过dtypes获取,重点不是dtype 。之后可以通过astypes来修改数据类型,通常来说会搭配numpy里的各种数据来使用,因为pandas允许选取的数据类型较为有限。这种修改一般是为了在大数据处理时,减少对内存的占用。
假定使用DataFrame(df):

   a   b      c
0  1   6  111.0
1  2   7   12.0
2  3   8    4.0
3  1   9   13.0
4  1  10   14.0

执行df.dtypes;
结果为

a      int64
b      int64
c    float64
dtype: object

执行df['c']=df['c'].astype('int32');
结果为

   a   b    c
0  1   6  111
1  2   7   12
2  3   8    4
3  1   9   13
4  1  10   14

iv. 删除特定行列

如果想要删除符合某些条件值所在行或者列,可以采用如下方法。
假定DataFrame(df)为:

   a   b    c
0  1   6  111
1  2   7   12
2  3   8    4
3  1   9   13
4  1  10   14

执行df.drop(df[df['a']==1].index);
结果为

   a  b   c
1  2  7  12
2  3  8   4

v.大文件的读取

普通文件的读取使用read_csv()即可达成目标,但是当文件过大时数据的读取速度会大大减慢,对电脑内存的要求也比较高。给出以下几种方法来读取大文件。

a)读取部分行

执行df=pd.read_csv(agefile,sep='\t',header=None,nrows=10),只读取文件中的前10行,通过nrows设定读取的行数;

b)读取特定列

执行df=pd.read_csv(agefile,sep='\t',header=None,names=['a','b','c'],usecols=['a'])或者df=pd.read_csv(agefile,sep='\t',header=None,usecols=[0])以获取数据中的第一列。

此处的usecols可以为实际的列名或者是位置顺序,如果为列名的话要求从文件本身可以推断出列名(自我理解是包含header)或者通过names显式给出;如果为位置顺序的话需要是列表的形式,即无法用切片[0:1]这一形式表达,且最终读取列的顺序与给出的位置顺序无关,即[1,0]的顺序实际仍为[0,1]。

c)分块读取

执行:

df=pd.read_csv(agefile,sep='\t',header=None,iterator=True)
temp=[]
while(True):
    try:
        temp.append(df.get_chunk(500))
    except:
        break
temp=pd.concat(temp)

设定文件为可迭代格式,循环从中读取一定数目的行加入list中,最后将所有DataFrame完成读取;

参考文献:

pandas数据合并之一文弄懂pd.merge()
python数据拼接: pd.concat
pandas中groupby函数中参数ax_index和group_keys的区别
pandas中多重索引multiIndex的使用
关于参数thresh的理解(pd.dropna(thresh=n))
使用Python Pandas处理亿级数据
Pandas分组运算(groupby)修炼

勘误:

i.DataFrame最大值寻址

在比较DataFrame和Series中,曾提到过DataFrame中无类似于argmax()的函数能找到最大值的索引,后发现通过df.idxmax()即可获取每一列最大值所在位置,df.idxmin()同理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值