Pandas库回顾与分享(二)

Pandas库

Pandas库是一个专门用于数据分析的开源Python库,有Series(序列)和DataFrame(数据框)这两种数据结构。

6 索引对象的其他功能

与Python常用数据结构相比,pandas不仅利用了NumPy数组的高性能优势,还整合了索引机制。

6.1 更换索引

前面讲过,数据结构一旦声明,Index对象就不能改变。这么说一点也没错,但是执行更换索引操作就可以解决这个问题。

重新定义索引之后,就能够用现有的数据结构生成一个新的数据结构。

>>> ser = pd.Series([2,5,7,4], index=['one','two','three','four'])
>>> ser
one      2
two      5
three    7
four     4
dtype: int64

pandas的reindex()函数可更换Series对象的索引。它根据新标签序列,重新调整原Series的元素,生成一个新的Series对象。

更换索引时,可以调整索引序列中各标签的顺序,删除或增加新标签。如增加新标签,pandas会添加NaN作为其元素。

>>> ser.reindex(['three','four','five','one'])
three     7
four      4
five    NaN
one       2
dtype: float64

从返回结果可以看到,标签顺序全部调整过。删除了标签two及其元素,增加了新标签five。

然而,重新编制索引,定义所有的标签序列可能会很麻烦,对大型DataFrame来说更是如此。可以使用自动填充或插值方法。

为了更好地理解自动编制索引功能,先定义以下Series对象。

>>> ser3 = pd.Series([1,5,6,3],index=[0,3,5,6])
>>> ser3
0    1
3    5
5    6
6    3
dtype: int64

刚定义的Series对象,其索引列并不完整而是缺失了几个值(1、2和4)。常见的需求为插值,以得到一个完整的序列。方法是用reindex()函数,method选项的值为ffill。此外,还需要指定索引值的范围。要指定一列0~5的值,参数为range(6)。

>>> ser3.reindex(range(6),method='ffill')
0    1
1    1
2    1
3    5
4    5
5    6
dtype: int64

由结果可见,新Series对象添加了原Series对象缺失的索引项。新插入的索引项,其元素为前面索引编号比它小的那一项的元素。所以看到索引项1、2的值为1,也就是索引项0的值。

如果你想用新插入索引后面的元素,需要使用bfill方法。

>>> ser3.reindex(range(6),method='bfill')
0    1
1    5
2    5
3    5
4    6
5    6
dtype: int64

用这种方法,索引项1和2的元素则为5,也就是索引项3的元素。

更换索引的概念可以由Series扩展到DataFrame,不仅可以更换索引(行),还可以更换列,甚至更换两者。如前所述,可以增加行或列,但pandas用NaN弥补原数据结构中缺失的元素。

>>> frame.reindex(range(5), method='ffill',columns=['colors','price','new','object'])
   colors price  new  object
0    blue   1.2  NaN    ballpand
1   green   1.0  NaN     pen
2  yellow   0.6  NaN  pencil
3     red   0.9  NaN   paper
4   white   1.7  NaN     mug

6.2 删除

另外一种跟Index对象相关的操作是删除。因为索引和列名称有了标签作为标识,所以删除操作变得很简单。

pandas专门提供了一个用于删除操作的函数:drop(),它返回不包含已删除索引及其元素的新对象。

举例来说,从Series对象中删除一项。先来定义一个含有四个元素的Series对象,其中各元素标签均不相同。

>>> ser = Series(np.arange(4.), index=['red','blue','yellow','white'])
>>> ser
red       0
blue      1
yellow    2
white     3
dtype: float64

假如想删除标签为yellow的这一项。用标签作为drop()函数的参数,就可以删除这一项。

>>> ser.drop('yellow')
red      0
blue     1
white    3
dtype: float64

传入一个由多个标签组成的数组,可以删除多项。

>>> ser.drop(['blue','white'])
red       0
yellow    2
dtype: float64

要删除DataFrame中的元素,需要指定元素两个轴的轴标签。通过具体的例子来看一下,首先声明一个DataFrame对象。

>>> frame = pd.DataFrame(np.arange(16).reshape((4,4)),
...                   index=['red','blue','yellow','white'],
...                   columns=['ball','pen','pencil','paper'])
>>> frame
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15

传入行的索引可删除行。

>>> frame.drop(['blue','yellow'])
       ball  pen  pencil paper
red       0    1       2     3
white    12   13      14    15

要删除列,需要指定列的索引,但是还必须用axis选项指定从哪个轴删除元素。如按照列的方向删除,axis的值为1。

>>> frame.drop(['pen','pencil'],axis=1)
        Ball  paper
red        0      3
blue       4      7
yellow     8     11
white     12     15

6.3 算术和数据对齐

pandas能够将两个数据结构的索引对齐,这可能是与pandas数据结构索引对象有关的最强大的功能。这一点尤其体现在数据结构之间的算术运算上。参与运算的两个数据结构,其索引项顺序可能不一致,而且有的索引项可能只存在于一个数据结构中。

从下面几个例子中,就会发现做算术运算时,pandas很擅长对齐不同数据结构的索引项。举个例子,先来定义两个Series对象,分别指定两个不完全一致的标签数组。

>>> s1 = pd.Series([3,2,5,1],['white','yellow','green','blue'])
>>> s2 = pd.Series([1,4,7,2,1],['white','yellow','black','blue','brown'])

算术运算种类很多,考虑一下最简单的求和运算。刚定义的两个Series对象,有些标签两者都有,有些只属于其中一个对象。如果一个标签,两个Series对象都有,就把它们的元素相加,反之,标签也会显示在结果(新Series对象)中,只不过元素为NaN。

>>> s1 + s2
black    NaN
blue       3
brown    NaN
green    NaN
white      4
yellow     6
dtype: float64

DataFrame对象之间的运算,虽然看起来可能更复杂,但对齐规则相同,只不过行和列都要执行对齐操作。

>>> frame1 = pd.DataFrame(np.arange(16).reshape((4,4)),
...                   index=['red','blue','yellow','white'],
...                   columns=['ball','pen','pencil','paper'])
>>> frame2 = pd.DataFrame(np.arange(12).reshape((4,3)),
...                   index=['blue','green','white','yellow'],
...                   columns=['mug','pen','ball'])
>>> frame1
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15
>>> frame2
        mug  pen  ball
blue      0    1     2
green     3    4     5
white     6    7     8
yellow    9   10    11
>>> frame1 + frame2
        ball  mug  paper pen pencil
blue       6  NaN    NaN   6    NaN
green    NaN  NaN    NaN NaN    NaN
red      NaN  NaN    NaN NaN    NaN
white     20  NaN    NaN  20    NaN
yellow    19  NaN    NaN  19    NaN

7 数据结构之间的运算

接下来是两种及以上数据结构之间的运算。

上一节两个对象之间的算术运算。这一节,则对两种数据结构之间的运算进行深入探讨。

7.1 灵活的算术运算方法

前面可直接在pandas数据结构之间使用算术运算符。相同的运算还可以借助灵活的算术运算方法(flexible arithmetic methods)来完成。

add()
sub()
div()
mul()

这些函数的调用方法与数学运算符的使用方法不同。例如,两个DataFrame对象的求和运算,不再使用“frame1+frame2”这种格式,而是使用下面这种格式:

>>> frame1.add(frame2)
        ball  mug  paper  pen pencil
blue       6  NaN    NaN    6    NaN
green    NaN  NaN    NaN  NaN    NaN
red      NaN  NaN    NaN  NaN    NaN
white     20  NaN    NaN   20    NaN
yellow    19  NaN    NaN   19    NaN

如上所见,结果跟使用+运算符所得到的相同。如果两个DataFrame对象的索引和列名称差别很大,新得到的DataFrame对象将有很多元素为NaN。

7.2 DataFrame和Series对象之间的运算

再次回到算术运算符,pandas允许参与运算的对象为不同的数据结构,比如DataFrame和Series。举例之前,先来定义两个不同的数据结构。

>>> frame = pd.DataFrame(np.arange(16).reshape((4,4)),
...                   index=['red','blue','yellow','white'],
...                   columns=['ball','pen','pencil','paper'])
>>> frame
        ball  pen pencil paper
red        0    1      2     3
blue       4    5      6     7
yellow     8    9     10    11
white     12   13     14    15
>>> ser = pd.Series(np.arange(4), index=['ball','pen','pencil','paper'])
>>> ser
ball      0
pen       1
pencil    2
paper     3
dtype: int32

定义数据结构时,特意让Series对象的索引和DataFrame对象的列名称保持一致。这样就可以直接对它们进行运算。

>>> frame - ser
        ball  pen pencil paper
red        0    0      0     0
blue       4    4      4     4
yellow     8    8      8     8
white     12   12     12    12

如上所见,DataFrame对象各元素分别减去了Series对象中索引与之相同的元素。DataFrame对象每一列的所有元素,无论对应哪一个索引项,都执行了减法操作。

如果一个索引项只存在于其中一个数据结构之中,则运算结果中会为该索引项生成一列,只不过该列的所有元素都是NaN。

>>> ser['mug'] = 9
>>> ser
ball      0
pen       1
pencil    2
paper     3
mug       9
dtype: int64
>>> frame - ser
        ball  mug paper pen pencil
red        0  NaN     0   0      0
blue       4  NaN     4   4      4
yellow     8  NaN     8   8      8
white     12  NaN    12  12     12

8 函数应用和映射

pandas库函数。

8.1 操作元素的函数

pandas库以NumPy为基础,并对它的很多功能进行了扩展,以用来操作新数据结构Series和DataFrame。通用函数(ufunc,universal function)就是经过扩展得到的功能,这类函数能够对数据结构中的元素进行操作,因此特别有用。

>>> frame = pd.DataFrame(np.arange(16).reshape((4,4)),
...                   index=['red','blue','yellow','white'],
...                   columns=['ball','pen','pencil','paper'])
>>> frame
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15

例如,使用NumPy的np.sqrt()函数就能计算DataFrame对象每个元素的平方根。

>>> np.sqrt(frame)
            ball       pen    pencil     paper
red     0.000000  1.000000  1.414214  1.732051
blue    2.000000  2.236068  2.449490  2.645751
yellow  2.828427  3.000000  3.162278  3.316625
white   3.464102  3.605551  3.741657  3.872983

8.2 按行或列执行操作的函数

除了通用函数,用户还可以自己定义函数。需要注意的是这些函数对一维数组进行运算,返回结果为一个数值。可以定义一个计算数组元素取值范围的lambda函数。

>>> f = lambda x: x.max() - x.min()

还可以用下面这种形式定义函数:

>>> def f(x):
...    return x.max() - x.min()
...

用apply()函数可以在DataFrame对象上调用刚定义的函数。

>>> frame.apply(f)
ball      12
pen       12
pencil    12
paper     12
dtype: int64

每一列的运算结果为一个数值。如果你想用函数处理行而不是列,需将axis选项设置为1

>>> frame.apply(f, axis=1)
red       3
blue      3
yellow    3
white     3
dtype: int64

apply()函数并不是一定要返回一个标量,它还可以返回Series对象,因而可以借助它同时执行多个函数。每调用一次函数,就会有两个或两个以上的返回结果。可以像下面这样指定一个函数。

>>> def f(x):
...     return pd.Series([x.min(), x.max()], index=['min','max'])
...

像之前一样,应用这个函数,但是返回结果不再是Series而是DataFrame对象,并且DataFrame对象的行数跟函数返回值的数量相等。

>>> frame.apply(f)
     ball  pen  pencil  paper
min     0    1       2      3
max    12   13      14     15

8.3 统计函数

数组的大多数统计函数对DataFrame对象依旧有效,因此没有必要使用apply()函数。例如,sum()和mean()函数分别用来计算DataFrame对象元素之和及它们的均值。

>>> frame.sum()
ball      24
pen       28
pencil    32
paper     36
dtype: int64
>>> frame.mean()
ball      6
pen       7
pencil    8
paper     9
dtype: float64

describe()函数能够计算多个统计量。

>>> frame.describe()
            ball       pen      pencil      paper
count   4.000000  4.000000    4.000000   4.000000
mean    6.000000  7.000000    8.000000   9.000000
std     5.163978  5.163978    5.163978   5.163978
min     0.000000  1.000000    2.000000   3.000000
25%     3.000000  4.000000    5.000000   6.000000
50%     6.000000  7.000000    8.000000   9.000000
75%     9.000000  10.000000  11.000000  12.000000
max    12.000000  13.000000  14.000000  15.000000
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值