《利用python进行数据分析》读书笔记之pandas基础(二)

重建索引

考虑一个最简单的Series对象:

import pandas as pd
obj = pd.Series([4.5,7.2,-5.3,3.6],index = ['d','b','a','c'])
# d    4.5
# b    7.2
# a   -5.3
# c    3.6
# dtype: float64

我们可以使用reindex方法来改变其索引,数据会按照新索引来排序,若某个索引值之前不存在,则会引入缺失值:

obj2 = obj.reindex(['a','b','c','d','e'])
# a   -5.3
# b    7.2
# c    3.6
# d    4.5
# e    NaN
# dtype: float64

这里并不会改变原Series的索引
对于DataFrame,使用reindex可以同时改变行索引和列索引,在更改列索引的时候需要显示的指定:

frame2 = frame.reindex(['a','b','c','d'])
#默认更改行索引
#      O    T    C
# a  0.0  1.0  2.0
# b  NaN  NaN  NaN
# c  3.0  4.0  5.0
# d  6.0  7.0  8.0

states = ['T','U','C']
frame3 = frame.reindex(columns = states)
#更改列索引,发现之前有一列不见了
#    T   U  C
# a  1 NaN  2
# c  4 NaN  5
# d  7 NaN  8

轴向上删除条目

使用drop方法可以返回一个删除r若干行(列)后的新对象,首先是Series类型:

obj = pd.Series(np.arange(5.),index = ['a','b','c','d','e'])
new_obj = obj.drop('c')
# a    0.0
# b    1.0
# d    3.0
# e    4.0
# dtype: float64

对DataFrame对象使用drop:

data = pd.DataFrame(np.arange(16).reshape((4,4)),
                    index = ['O','C','U','NY'],
                    columns = [1,2,3,4])
#初始化一个DataFrame对象
#      1   2   3   4
# O    0   1   2   3
# C    4   5   6   7
# U    8   9  10  11
# NY  12  13  14  15
data_new = data.drop(['C','O'])
#根据行标签删除值(默认,axis = 0)
#      1   2   3   4
# U    8   9  10  11
# NY  12  13  14  15
data_new = data.drop([1,2],axis= 1 )
#根据列标签删除值
#      3   4
# O    2   3
# C    6   7
# U   10  11
# NY  14  15

我们在使用drop方法时,可以指定inplace参数,当其为真时则会直接在原对象上修改而不返回新对象:

new_data = data.drop([1,2],axis = 1,inplace = True)
print(new_data)
#None
print(data)
#      3   4
# O    2   3
# C    6   7
# U   10  11
# NY  14  15

索引、选择与过滤

Series的索引与Numpy的索引类似,但是Series的索引可以不仅仅是整数,也可以是字符。访问Series内部的元素即可以使用我们定义的标签,也可以使用默认标签:

obj = pd.Series(np.arange(4.),index = ['a','b','c','d'])
obj['b']
#1.0
obj[1]
#1.0
obj[['b','a','d']]
# b    1.0
# a    0.0
# d    3.0
# dtype: float64
obj[[1,3]]
# b    1.0
# d    3.0
# dtype: float64
obj[obj<2]
# a    0.0
# b    1.0
# dtype: float64

我们注意到,部分结果返回的是数值,而部分结果返回的是Series对象
使用默认的索引进行切片时是不包含尾部的,而使用自定义的索引切片时时包含尾部的:

obj[1:3]
# b    1.0
# c    2.0
# dtype: float64
obj['b':'d']
# b    1.0
# c    2.0
# d    3.0
# dtype: float64

使用以上方法修改值的时候原Series中的值也会发生改变,因为其返回的是数据的视图而不是拷贝
对于DataFrame可以根据以下方式选择若干列:

data = pd.DataFrame(np.arange(16).reshape((4,4)),
                    index = ['O','C','U','NY'],
                    columns = ['one','two','three','four'])
data['two']
# O      1
# C      5
# U      9
# NY    13
# Name: two, dtype: int32
data[['three','one']]
#     three  one
# O       2    0
# C       6    4
# U      10    8
# NY     14   12

可以使用以下方式方便的对DataFrame行进行选取:

data[:2]
#    one  two  three  four
# O    0    1      2     3
# C    4    5      6     7

DataFrame也支持布尔值切片与数据选择:

data[data['three']>5]
#删选出所有three大于5的行
#     one  two  three  four
# C     4    5      6     7
# U     8    9     10    11
# NY   12   13     14    15
data[data<5]=0
#让DataFrame中的所有<5的数值变为0
#     one  two  three  four
# O     0    0      0     0
# C     0    5      6     7
# U     8    9     10    11
# NY   12   13     14    15

以上方法是对DataFrame行选取或者列选取的方法,当需要选取DataFrame的特定行、特定列时,则需要用到loc和iloc方法。
loc方法可以使用我们自定义的标签来完成单行单列、单行多列、多行单列和多行多列的选择,单行多列的选择例子如下:

data = pd.DataFrame(np.arange(16).reshape((4,4)),
                    index = ['O','C','U','NY'],
                    columns = ['one','two','three','four'])
#     one  two  three  four
# O     0    1      2     3
# C     4    5      6     7
# U     8    9     10    11
# NY   12   13     14    15
data.loc['C',['two','three']]
# two      5
# three    6
# Name: C, dtype: int32

值得注意的是,当选取的是单行单列时返回的是一个值,当选取的是单行多列或者多行单列的时候返回的是一个Series对象,当选取的是多行多列时返回的是DataFrame对象
我们也可以使用整数标签(默认)配合iloc进行数据的选择:

data.iloc[2,[3,0,1]]
# four    11
# one      8
# two      9
# Name: U, dtype: int32
data.iloc[2]
# one       8
# two       9
# three    10
# four     11
# Name: U, dtype: int32
data.iloc[[1,2],[3,0,1]]
#      3   4
# O    2   3
# C    6   7
# U   10  11
# NY  14  15

loc和iloc还可以进行切片:

data.loc[:'U','two']
# O    1
# C    5
# U    9
# Name: two, dtype: int32
data.iloc[:,:3][data.three>5]
#     one  two  three
# C     4    5      6
# U     8    9     10
# NY   12   13     14

data索引选项

类型 描述
df[val] 从DataFrame中选择单列或者列序列;特殊情况的遍历:布尔数组(过滤行),切片(切片行)或布尔值DataFrame
df.loc[val] 根据标签选择DataFrtame的单行或者多行
df.loc[:,val] 根据标签选择单列或者多列
df.loc[vak1,val2] 同时选择行和列的一部分
df.iloc[where] 根据整数位置选择单行或者多行
df.iloc[:,where] 根据整数位置选择单列或者多列
df.iloc[where_i,where_j] 根据整数位置选择行和列
df.iat[I,j] 根据行列整数位置选择单个标量值
reindex 方法 通过标签选择行和列
get_value,set_value方法 根据行和列的标签设置单个值

算数和数据对齐

现在有两个不完全相同标签的Series对象:

ser1 = pd.Series([7.3,-2.5,3.5,1.5],index = ['a','b','c','d'])
# a    7.3
# b   -2.5
# c    3.5
# d    1.5
# dtype: float64
ser2 = pd.Series([-2.1,3.6,-1.5,4,3.1],index = ['a','c','e','f','g'])
# a   -2.1
# c    3.6
# e   -1.5
# f    4.0
# g    3.1
# dtype: float64

现在将这两个对象相加:

print(ser1+ser2)
# a    5.2
# b    NaN
# c    7.1
# d    NaN
# e    NaN
# f    NaN
# g    NaN
# dtype: float64

在没有交叠的标签位置上,内部数据对齐会产生缺失值,缺失值会在后续的算术操作上产生影响。在DataFrame情况中行和列上都会进行对其。如果将两个行或者列完全不同的DataFrame相加则会得到一个全空的结果。
在两个不同的索引化对象之间进行算术操作时,如果想要将确实的值替换为一个指定的数,可以在其中一个对象上使用add方法,并且将这个指定的数作为fill_value参数传入:

df1 = pd.DataFrame(np.arange(12.).reshape((3,4)),
                   columns = list('abcd'))
#      a    b     c     d
# 0  0.0  1.0   2.0   3.0
# 1  4.0  5.0   6.0   7.0
# 2  8.0  9.0  10.0  11.0
df2 = pd.DataFrame(np.arange(20.).reshape((4,5)),
                   columns=list('abcde'))
#       a     b     c     d     e
# 0   0.0   1.0   2.0   3.0   4.0
# 1   5.0   6.0   7.0   8.0   9.0
# 2  10.0  11.0  12.0  13.0  14.0
# 3  15.0  16.0  17.0  18.0  19.0
print(df1.add(df2,fill_value = 0))
#       a     b     c     d     e
# 0   0.0   2.0   4.0   6.0   4.0
# 1   9.0  11.0  13.0  15.0   9.0
# 2  18.0  20.0  22.0  24.0  14.0
# 3  15.0  16.0  17.0  18.0  19.0

灵活算数方法

方法 描述
add,radd 加法(+)
sub,rsub 减法(-)
div,rdiv 除法(/)
floordiv,rfloordiv 整除(//)
mul,rmul 乘法(*)
pow,rpow 幂乘方(**)

上面这些方法中每一个都有一个以r开头的副本,这些副本的方法参数是翻转的。因此以下语句是等价的:

1/df1
df1.rdiv(1)

现在考虑DataFrame和Series之间的操作:

frame = pd.DataFrame(np.arange(12.).reshape((4,3)),
                     columns = list('abc'),
                     index = ['U','O','T','Or'])
#       a     b     c
# U   0.0   1.0   2.0
# O   3.0   4.0   5.0
# T   6.0   7.0   8.0
# Or  9.0  10.0  11.0
series = frame.iloc[0]
# a    0.0
# b    1.0
# c    2.0
# Name: U, dtype: float64
print(frame - series)
#       a    b    c
# U   0.0  0.0  0.0
# O   3.0  3.0  3.0
# T   6.0  6.0  6.0
# Or  9.0  9.0  9.0

正常情况下,DataFrame和Series的数学操作中会将Series的索引和DataFrame的列进行匹配,并广播的各行。如果一个索引不在DataFrame中,也不再Series的索引中,则对象会重建索引并形成联合。
在列上进行广播的方法如下:

frame = pd.DataFrame(np.arange(12.).reshape((4,3)),
                     columns = list('abc'),
                     index = ['U','O','T','Or'])
#       a     b     c
# U   0.0   1.0   2.0
# O   3.0   4.0   5.0
# T   6.0   7.0   8.0
# Or  9.0  10.0  11.0
series = frame['a']
# U     0.0
# O     3.0
# T     6.0
# Or    9.0
# Name: a, dtype: float64
print(frame.sub(series,axis = 'index'))
# U   0.0  1.0  2.0
# O   0.0  1.0  2.0
# T   0.0  1.0  2.0
# Or  0.0  1.0  2.0

函数应用和映射

Numpy中的通用函数也可以对pandas中的对象使用:

frame = pd.DataFrame(np.random.randn(4,3),
                     columns = list('abc'),
                     index = ['U','O','T','Or'])
#            a         b         c
# U  -1.868928  0.952929  0.619027
# O  -0.752540  1.711835 -1.064560
# T   1.180530  0.507043 -0.633658
# Or  0.160631 -1.668812  0.027523
np.abs(frame)
#            a         b         c
# U   1.868928  0.952929  0.619027
# O   0.752540  1.711835  1.064560
# T   1.180530  0.507043  0.633658
# Or  0.160631  1.668812  0.027523

使用DataFrame的apply方法可以自定义一个函数,然后将这个函数应用到行或者列上,应用在列上的例子如下:

frame = pd.DataFrame(np.arange(12.).reshape((4,3)),
                     columns = list('abc'),
                     index = ['U','O','T','Or'])
#       a     b     c
# U   0.0   1.0   2.0
# O   3.0   4.0   5.0
# T   6.0   7.0   8.0
# Or  9.0  10.0  11.0
f = lambda x: x.max() - x.min()
#定义一个匿名函数,作用是返回每列的最大值与最小值之差
print(frame.apply(f))
# a    9.0
# b    9.0
# c    9.0

如果需要应用在行上,需要指定axis的参数:

print(frame.apply(f,axis = 'columns'))
# U     2.0
# O     2.0
# T     2.0
# Or    2.0
# dtype: float64

传递给apply的函数不一定需要返回一个标量,也可以返回一个Series:

def func(x):
    return pd.Series([x.min(),x.max()],index = ['max','min'])
print(frame.apply(func))
#        a     b     c
# max  0.0   1.0   2.0
# min  9.0  10.0  11.0

如果想对DataFrame进行逐元素运算,可以使用applymap方法:

f = lambda x: x+2
print(frame.applymap(f))
#        a     b     c
# U    2.0   3.0   4.0
# O    5.0   6.0   7.0
# T    8.0   9.0  10.0
# Or  11.0  12.0  13.0

对于Series,则使用map方法:

print(frame['c'].map(f))
# U      4.0
# O      7.0
# T     10.0
# Or    13.0
# Name: c, dtype: float64

排序和排名

对于Series和DataFrame可以使用sort_index方法按索引进行重新排序,对于Series:

series = pd.Series(np.arange(4),index = list('bcda'))
print(series)
# b    0
# c    1
# d    2
# a    3
# dtype: int32
print(series.sort_index())
# a    3
# b    0
# c    1
# d    2
# dtype: int32

对于DataFrame可以使用axis参数选择在行或者列上进行排序,并且可以指定ascending的值来改变升降序(默认为True,升序):

frame = pd.DataFrame(np.arange(8).reshape((2,4)),
                     index = ['three','one'],
                     columns= list('dcba'))
#        d  c  b  a
# three  0  1  2  3
# one    4  5  6  7
frame.sort_index(axis = 1)
#        a  b  c  d
# three  3  2  1  0
# one    7  6  5  4
frame.sort_index(ascending=True)
#        d  c  b  a
# one    4  5  6  7
# three  0  1  2  3

另外如果含有缺失值则会默认放至尾部。
也可以使用sort_values方法按列使用元素值进行排序,可以使用by指定列:

frame = pd.DataFrame({'b':[4,7,-3,2],'a':[0,1,0,1]})
#    b  a
# 0  4  0
# 1  7  1
# 2 -3  0
# 3  2  1
frame.sort_values(by = 'b')
#按b列中的值进行排序
#    b  a
# 2 -3  0
# 3  2  1
# 0  4  0
# 1  7  1
frame.sort_values(by = ['a','b'])
#x先使用b中的值排序,在使用a中的值进行排序
#    b  a
# 2 -3  0
# 0  4  0
# 3  2  1
# 1  7  1

另外使用Series和DataFrame对象的rank方法可以得到各元素按大小排列得到的名次(默认为最小的数名次为1):

obj = pd.Series([7,-5,7,4,2,0,4])
# 0    7
# 1   -5
# 2    7
# 3    4
# 4    2
# 5    0
# 6    4
# dtype: int64
obj.rank()
# 0    6.5
# 1    1.0
# 2    6.5
# 3    4.5
# 4    3.0
# 5    2.0
# 6    4.5
# dtype: float64

我们注意到第三个元素是第4小的,但是名次是4.5,这是由于还有一个元素也是4,即产生了平级关系,默认方法是取排名的平均值(一个第四名一个第五名,(4+5)/2 = 4.5,如果有3个4,那就是(4+5+6)/3 = 5)。若想要打破平级关系,则可以指定参数method:

print(obj.rank(method = 'first'))
# 0    6.0
# 1    1.0
# 2    7.0
# 3    4.0
# 4    3.0
# 5    2.0
# 6    5.0
# dtype: float64

first指的是如果有平级元素,则按最开始的索引大小排序,索引在前的排序在前。当然我们还可以指定ascending参数来让它从大到小排列。
对于DataFrame的rank方法和Series类似,但是需要使用axis选择行或者列。

排名中打破平级的方法 描述
'average 默认:在每个组中平均分配排名
‘min’ 对整个数组使用最小排名
‘max’ 对整个数组使用最大排名
‘first’ 按照值在数据中出现的次序排名
‘dense’ 类似于’min’,但是组间排名总是增加1,而不是一个组中相等的元素数量

含有重复标签的索引

对于一个含有重复索引的Series对象,选择重复的标签进行索引会返回一个序列,可以使用is_unique来判断索引是否唯一:

series = pd.Series(np.arange(4),index = list('aabb'))
# a    0
# a    1
# b    2
# b    3
# dtype: int32
print(series['a'])
# a    0
# a    1
# dtype: int32
print(series.index.is_unique)
# False

对于DataFrame类似:

df = pd.DataFrame(np.arange(12).reshape((4,3)),index = list('aabb'))
#    0   1   2
# a  0   1   2
# a  3   4   5
# b  6   7   8
# b  9  10  11
print(df.loc['b'])
#    0   1   2
# b  6   7   8
# b  9  10  11
print(df.index.is_unique)
# False
print(df.columns.is_unique)
# True
发布了14 篇原创文章 · 获赞 0 · 访问量 235

猜你喜欢

转载自blog.csdn.net/pnd237/article/details/104246598