前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Pandas 实践手册(一)

Pandas 实践手册(一)

作者头像
口仆
发布2020-11-06 13:33:50
2K0
发布2020-11-06 13:33:50
举报
文章被收录于专栏:用户2133719的专栏

本系列参考自「Python Data Science Handbook」第三章,旨在对 Pandas 库的使用方法进行归纳与总结。

1 安装和使用

关于 pandas 的安装可以参考官方教程[1],官方推荐直接基于 Anaconda 进行安装。安装完成后,我们可以导入 pandas 并查看其版本:

代码语言:javascript
复制
In[1]: import pandas
       pandas.__version__
Out[1]: '1.0.3'

与 Numpy 一样,为了使用方便我们会将 Pandas 以「别名」的形式导入:

代码语言:javascript
复制
In[2]: import pandas as pd

在接下来的介绍中我们都将使用该导入方式。值得一提的是,在 Jupyter lab 中我们可以通过 「Tab 键」来进行自动补全,使用「问号」来查看相关文档,如下所示:

代码语言:javascript
复制
In [3]: pd.<TAB> # 查看可以调用的方法
In [4]: pd? # 查看官方文档

2 Pandas 对象

本章节将介绍三种基本的 Pandas 对象(数据结构):SeriesDataFrameIndex。我们可以简单地将 Pandas 对象理解为 Numpy 数组的增强版本,其中行与列可以通过标签进行识别,而不仅是简单的数字索引。Pandas 为这些基本数据结构提供了一系列有用的工具与方法。为了小节之间的独立性,每节的最开始会先进行包导入(编号每节独立):

代码语言:javascript
复制
In[1]: import numpy as np
       import pandas as pd

2.1 Series 对象

Series 对象是一个可索引数据的「一维数组」,我们可以基于列表或数组来创建该对象:

代码语言:javascript
复制
In[2]: data = pd.Series([0.25, 0.5, 0.75, 1.0])
       data
Out[2]: 0 0.25
        1 0.50
        2 0.75
        3 1.00
        dtype: float64

如上所示,Series 对象包含了一个值序列和一个索引序列,我们可以分别通过 valuesindex 属性来进行访问。values 属性是一个 Numpy 数组:

代码语言:javascript
复制
In[3]: data.values
Out[3]: array([0.25, 0.5 , 0.75, 1.  ]) # 输出的缩进就是这样,还蛮怪的

index 属性则是一个类数组的对象,类型为 pd.Index,将在之后进行介绍:

代码语言:javascript
复制
In[4]: data.index
Out[4]: RangeIndex(start=0, stop=4, step=1)

和 Numpy 数组类似,我们可以通过方括号输入对应的索引来访问数据:

代码语言:javascript
复制
In[5]: data[1]
Out[5]: 0.5

In[6]: data[1:3] # 支持切片
Out[6]: 1 0.50
        2 0.75
        dtype: float64
2.1.1 Series 作为广义 Numpy 数组

虽然看起来和一维 Numpy 数组很像,但 Series 对象要比其更加通用和灵活。两者的关键区别在于:Numpy 数组使用「隐式定义」的数值索引来访问值,而 Series 对象则使用「明确」定义的索引来访问值。这一明确的索引定义赋予了 Series 对象额外的能力,例如索引不一定是整数,也可以是任意类型的值:

代码语言:javascript
复制
In[7]: data = pd.Series([0.25, 0.5, 0.75, 1.0],
                        index=['a', 'b', 'c', 'd'])
       data
Out[7]: a 0.25
        b 0.50
        c 0.75
        d 1.00
        dtype: float64

元素的访问也随之更改:

代码语言:javascript
复制
In[8]: data['b']
Out[8]: 0.5

我们甚至可以使用「非连续」的索引:

代码语言:javascript
复制
In[9]: data = pd.Series([0.25, 0.5, 0.75, 1.0],
                        index=[2, 5, 3, 7])
       data
Out[9]: 2 0.25
        5 0.50
        3 0.75
        7 1.00
        dtype: float64

In[10]: data[5]
Out[10]: 0.5
2.1.2 Series 作为特殊的字典

我们还可以将 Series 看作一种特殊的 Python 字典。字典是一种将任意的键映射到任意的值上的数据结构,而 Series 则是将包含类型信息的键映射到包含类型信息的值上的数据结构。「类型信息」可以为 Series 提供比普通字典更高效的操作。

我们可以直接基于字典来构建 Series 对象:

代码语言:javascript
复制
In[11]: population_dict = {'California': 38332521,
                           'Texas': 26448193,
                           'New York': 19651127,
                           'Florida': 19552860,
                           'Illinois': 12882135}
        population = pd.Series(population_dict)
        population
Out[11]: California    38332521
         Texas         26448193
         New York      19651127
         Florida       19552860
         Illinois      12882135
         dtype: int64

可以看到索引即为字典的键(新版 Pandas 中似乎不会对键进行排序以生成索引,而是保持原状)。我们可以像字典一样通过索引访问值,也可以使用字典不支持的切片操作(注意此处的切片会包含尾部):

代码语言:javascript
复制
In[12]: population['California']
Out[12]: 38332521

In[13]: population['California':'Texas']
Out[13]: California    38332521
         Texas         26448193
         dtype: int64
2.1.3 构建 Series 对象

如上所述,Series 对象的构建方式有很多种,其基本遵循如下形式:

代码语言:javascript
复制
>>> pd.Series(data, index=index)

其中 index 为可选参数,data 可以是很多数据结构之一,例如:

  • 「列表或 Numpy 数组」
代码语言:javascript
复制
In[14]: pd.Series([2, 4, 6])
Out[14]: 0    2
         1    4
         2    6
         dtype: int64
  • 「标量」(重复填充):
代码语言:javascript
复制
In[15]: pd.Series(5, index=[100, 200, 300])
Out[15]: 100    5
         200    5
         300    5
         dtype: int64
  • 「字典」(键即为索引):
代码语言:javascript
复制
In[16]: pd.Series({2:'a', 1:'b', 3:'c'})
Out[16]: 1    b
         2    a
         3    c
         dtype: object

索引还可以特别设置为子集的形式,例如:

代码语言:javascript
复制
In[17]: pd.Series({2:'a', 1:'b', 3:'c'}, index=[3, 2])
Out[17]: 3    c
         2    a
         dtype: object

2.2 DataFrame 对象

Series 对象一样,DataFrame 对象也可以被认为是 Numpy 数组的推广,或是一种特殊的 Python 字典。下面我们将分别从这两个角度进行介绍。

2.2.1 DataFrame 作为广义 Numpy 数组

我们可以将 DataFrame 看做一个拥有灵活的行索引与列名的「二维」 Numpy 数组,其本质上就是一系列对齐(共享相同的索引)的 Series 对象。为了说明这一点,我们首先构建一个包含五大洲面积数据的 Series

代码语言:javascript
复制
In[18]: area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297,
                     'Florida': 170312, 'Illinois': 149995}
        area = pd.Series(area_dict)
        area
Out[18]: California    423967
         Texas         695662
         New York      141297
         Florida       170312
         Illinois      149995
         dtype: int64

将该对象与之前的人口数据进行合并(使用字典),即可得到一个 DataFrame 对象:

代码语言:javascript
复制
In[19]: states = pd.DataFrame({'population': population,
                               'area': area})
        states
Out[19]:            population area
         California 38332521 423967
         Texas      26448193 695662
         New York   19651127 141297
         Florida    19552860 170312
         Illinois   12882135 149995

Series 对象类似,我们可以通过 index 属性来获取 DataFrame 对象的索引标签:

代码语言:javascript
复制
In[20]: states.index
Out[20]: Index(['California', 'Texas', 'New York', 'Florida', 'Illinois'], dtype='object')

此外,DataFrame 对象还有一个 columns 属性,其为一个包含列标签的 Index 对象:

代码语言:javascript
复制
In[21]: states.columns
Out[21]: Index(['population', 'area'], dtype='object')

因此,DataFrame 对象可以看做是二维 Numpy 数组的推广,其行与列都拥有广义的索引以方便进行数据查询。

2.2.2 DataFrame 作为特殊的字典

我们也可以将 DataFrame 对象看作一种特殊的字典,其将一个「列名」映射到一个 Series 对象上。例如:

代码语言:javascript
复制
In[22]: states['area']
Out[22]: California    423967
         Texas         695662
         New York      141297
         Florida       170312
         Illinois      149995
         Name: area, dtype: int64

注意如果直接访问行索引会报错,因此 DataFrame 对象需要首先通过列索引来找到列对象,再去通过行索引访问具体的值。而对于二维 Numpy 数组来说,data[0] 返回的是第一行,需要与 DataFrame 区分开来(其返回的是列)。

2.2.3 构建 DataFrame 对象

DataFrame 对象的构建方式同样有很多种,例如:

  • 「基于单个 Series 对象构建」
代码语言:javascript
复制
In[23]: pd.DataFrame(population, columns=['population'])
Out[23]:            population
         California 38332521
         Texas      26448193
         New York   19651127
         Florida    19552860
         Illinois   12882135
  • 「基于字典的列表构建」
代码语言:javascript
复制
In[24]: data = [{'a': i, 'b': 2 * i}
                for i in range(3)]
        pd.DataFrame(data)
Out[24]:   a b
         0 0 0
         1 1 2
         2 2 4

即使字典中缺少部分键,Pandas 也会自动填充为 NaN

代码语言:javascript
复制
In[25]: pd.DataFrame([{'a': 1, 'b': 2}, {'b': 3, 'c': 4}])
Out[25]:   a    b  c
         0 1.0  2  NaN
         1 NaN  3  4.0
  • 「基于 Series 对象的字典构建」
代码语言:javascript
复制
In[26]: pd.DataFrame({'population': population,
                      'area': area})
Out[26]:            population area
         California 38332521 423967
         Texas      26448193 695662
         New York   19651127 141297
         Florida    19552860 170312
         Illinois   12882135 149995
  • 「基于二维 Numpy 数组构建」(不指定则为整数索引):
代码语言:javascript
复制
In[27]: pd.DataFrame(np.random.rand(3, 2),
                     columns=['foo', 'bar'],
                     index=['a', 'b', 'c'])
Out[27]:   foo      bar
        a  0.165577 0.626570
        b  0.799517 0.376820
        c  0.614334 0.886437
  • 「基于 Numpy 结构化数组构建」(较为特殊):
代码语言:javascript
复制
In[28]: A = np.zeros(3, dtype=[('A', 'i8'), ('B', 'f8')])
        A
Out[28]: array([(0, 0.0), (0, 0.0), (0, 0.0)], dtype=[('A', '<i8'), ('B', '<f8')])
In[29]: pd.DataFrame(A)
Out[29]:   A B
         0 0 0.0
         1 0 0.0
         2 0 0.0

以上是书中列举的常用构建方法,这里补充一个在使用过程中遇到的构建案例:

  • 「基于嵌套列表(或元组)构建」(可以混用):
代码语言:javascript
复制
In[extra1]: pd.DataFrame([[1,2],[2,3],[3,4]], columns=['A', 'B'])
Out[extra2]:  A B
            0 1 2
            1 2 3
            2 3 4

对于这种构建方式,在实践过程中我们可以对于每组数据构建一个列表,然后通过 list(zip(a_list, b_list)) 创建嵌套列表,再基于上述方式创建 DataFrame 即可(行索引为默认整数索引)。

2.3 Index 对象

Series 对象与 DataFrame 对象中,都包含由于查找与修改数据的「索引」(index),其结构为一个 Index 对象。我们可以将 Index 对象看做一个「不可变数组」或是一个「有序集合」(多重集,因为可能包含重复值)。下面将分别从这两个角度进行介绍。首先我们基于一个整数列表创建一个简单的 Index 对象:

代码语言:javascript
复制
In[30]: ind = pd.Index([2, 3, 5, 7, 11])
        ind
Out[30]: Int64Index([2, 3, 5, 7, 11], dtype='int64')
2.3.1 Index 作为不可变数组

Index 对象可以执行很多与数组类似的操作,如通过索引访问:

代码语言:javascript
复制
In[31]: ind[1]
Out[31]: 3

In[32]: ind[::2]
Out[32]: Int64Index([2, 5, 11], dtype='int64')

其也拥有很多与 Numpy 数组相似的属性:

代码语言:javascript
复制
In[33]: print(ind.size, ind.shape, ind.ndim, ind.dtype)
Out[33]: 5 (5,) 1 int64

需要注意的是,Index 对象与 Numpy 数组的区别在于其是不可变的(类似列表与元组的区别),我们不能对索引进行修改:

代码语言:javascript
复制
In[34]: ind[1] = 0
TypeError: Index does not support mutable operations

这样可以保证在共享索引时更加安全。

2.3.2 Index 作为有序集合

Pandas 对象的设计初衷之一是便于执行数据集之间的连接这样的操作。Index 对象遵循 Python 内置的 set 数据结构的特性,可以方便地进行各种连接操作,例如:

代码语言:javascript
复制
In[35]: indA = pd.Index([1, 3, 5, 7, 9])
        indB = pd.Index([2, 3, 5, 7, 11])
In[36]: indA & indB # 交集
Out[36]: Int64Index([3, 5, 7], dtype='int64')

In[37]: indA | indB # 并集
Out[37]: Int64Index([1, 2, 3, 5, 7, 9, 11], dtype='int64')

In[38]: indA ^ indB # 对称差集
Out[38]: Int64Index([1, 2, 9, 11], dtype='int64')

上述操作也可以通过对象方法执行,如 indA.intersection(indB)

「未完待续」

参考资料

[1] Install pandas now: https://pandas.pydata.org/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 口仆 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 安装和使用
  • 2 Pandas 对象
    • 2.1 Series 对象
      • 2.1.1 Series 作为广义 Numpy 数组
      • 2.1.2 Series 作为特殊的字典
      • 2.1.3 构建 Series 对象
    • 2.2 DataFrame 对象
      • 2.2.1 DataFrame 作为广义 Numpy 数组
      • 2.2.2 DataFrame 作为特殊的字典
      • 2.2.3 构建 DataFrame 对象
    • 2.3 Index 对象
      • 2.3.1 Index 作为不可变数组
      • 2.3.2 Index 作为有序集合
    • 参考资料
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档