啃书:《利用python进行数据分析》第五章——pandas入门(一)

本文介绍了Pandas库的基础知识,包括Series和DataFrame数据结构。Series是一维数组,可以设置自定义索引;DataFrame是表格型数据结构,含有多列不同类型的数据,支持行和列的索引。文中展示了如何创建、操作和筛选这些数据结构,以及如何使用reindex方法进行数据重塑。此外,还介绍了DataFrame的loc和iloc属性用于行和列的选取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过前面几个章节的铺垫,我们对于数据处理也有了一点了解。后续主要首选是Pandas,它包含了使数据清洗和分析工作更快更简单的数据结构和操作工具。pandas经常会和其他工具一起并行使用,如上章学习到的numpy和scipy,分析库statsmodels和scikit-learn,和数据可视化库matplotlib。pandas是基于numpy建立的,特别是对基于数组的函数和不使用for循环的数据处理。

虽然pandas使用了很多的numpy编码风格,但是二者最大的不同是pandas专门为处理表格和混杂数据设计的框架。而numpy更加适合处理统一的数值数组数据。

本章中,我将使用以下约定引入pandas:

In [1]: import pandas as pd

因为Series和DataFrame用的次数非常多,所以将其引入本地命名空间中会更方便:

In [2]: from pandas import Series, DataFrame

5.1pandas的数据结构

要使用pandas,你首先就得熟悉它的两个主要数据结构:Series和DataFrame。这两个基本数可以解决大多数的处理问题了,所以我们要了解清楚他们的细节。

Series

Series是一种类似一维数组的对象,它是由一组数据(各种numpy的数据类型)以及一组与之相关的数据标签(索引)组成。

In [11]: obj = pd.Series([4, 7, -5, 3])

In [12]: obj
Out[12]: 
0    4
1    7
2   -5
3    3
dtype: int64

Series的表现形式是左边是索引,右边是数据值。这里我们并没有对数据进行特殊索引设置,所以是默认从0开始的索引标号。你也可以通过Series的values和index属性对数组内容进行访问:

In [13]: obj.values
Out[13]: array([ 4,  7, -5,  3])

In [14]: obj.index  # like range(4)
Out[14]: RangeIndex(start=0, stop=4, step=1)

通常来说,我们希望Series可以对各个数据进行标记:

In [15]: obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])

In [16]: obj2
Out[16]: 
d    4
b    7
a   -5
c    3
dtype: int64

In [17]: obj2.index
Out[17]: Index(['d', 'b', 'a', 'c'], dtype='object')

与普通NumPy数组相比,你可以通过索引的方式选取Series中的单个或一组值:

In [18]: obj2['a']
Out[18]: -5

In [19]: obj2['d'] = 6

In [20]: obj2[['c', 'a', 'd']]
Out[20]: 
c    3
a   -5
d    6
dtype: int64

当然你也可以通过上章节所学的numpy的相关知识对Series进行数据运算:

In [21]: obj2[obj2 > 0]
Out[21]: 
d    6
b    7
c    3
dtype: int64

In [22]: obj2 * 2
Out[22]:
d    12
b    14
a   -10
c     6
dtype: int64

In [23]: np.exp(obj2)
Out[23]: 
d     403.428793
b    1096.633158
a       0.006738
c      20.085537
dtype: float64

如果数据被存放在一个Python字典中,也可以直接通过这个字典来创建Series:

In [26]: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}

In [27]: obj3 = pd.Series(sdata)

In [28]: obj3
Out[28]: 
Ohio      35000
Oregon    16000
Texas     71000
Utah       5000
dtype: int64

如果只传入一个字典,则结果Series中的索引就是原字典的键(有序排列)。你可以传入排好序的字典的键以改变顺序:

In [29]: states = ['California', 'Ohio', 'Oregon', 'Texas']

In [30]: obj4 = pd.Series(sdata, index=states)

In [31]: obj4
Out[31]: 
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
dtype: float64

这个例子中,sdata和states索引相匹配的才会存入新生成的对象中,由于states中的California找不到对应值,所以为NaN。而Utah并不在states中,所以也不存在。

这种NaN在pandas中被称为损失值或NA值。pandas有函数isnull和notnull进行检测数组中是否含有损失值:

In [32]: pd.isnull(obj4)
Out[32]: 
California     True
Ohio          False
Oregon        False
Texas         False
dtype: bool

In [33]: pd.notnull(obj4)
Out[33]: 
California    False
Ohio           True
Oregon         True
Texas          True
dtype: bool

当然细心的同学可能发现了Series很重要的功能就是数据对齐,数据能够很整齐的排列,这对我们数据分析有很大帮助。Series对象本身和其索引都有一个属性name,该属性和pandas的其他功能密切相关:

In [38]: obj4.name = 'population'

In [39]: obj4.index.name = 'state'

In [40]: obj4
Out[40]: 
state
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
Name: population, dtype: float64

同时Series的索引可以通过赋值就地修改:

In [41]: obj
Out[41]: 
0    4
1    7
2   -5
3    3
dtype: int64

In [42]: obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']

In [43]: obj
Out[43]: 
Bob      4
Steve    7
Jeff    -5
Ryan     3
dtype: int64

DataFrame

DataFrame是一个表格型数据结构,它含有一组有序列,每列可以识不同类型值。DataFrame既有行索引,也有列索引,它可以被看成是Series组成的字典。DataFrame中的数据是以一个或多个二维块存放的,而不是列表,字典或者其他的一维数组的集合。关于其内部实现,这超出了本章的范围,所以有兴趣的小伙伴可以自行查阅了解细节。

学一个新的数据结构首先就是要学会它如何构造。有很多方式都可以构造DataFrame,最常用的方式就是利用包含等长度列表或Numpy数组的字典来形成DataFrame:

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002, 2003],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)

结果DataFrame会自动加上索引(跟Series一样):

In [24]:frame
Out[24]: 
    state  year  pop
0    Ohio  2000  1.5
1    Ohio  2001  1.7
2    Ohio  2002  3.6
3  Nevada  2001  2.4
4  Nevada  2002  2.9
5  Nevada  2003  3.2

如果你使用的是Jupyter notebook,pandas DataFrame对象会以对浏览器友好的HTML表格的方式呈现。
对于特别大的DataFrame,head方法会选取前五行:

In [26]:frame.head()
Out[27]: 
    state  year  pop
0    Ohio  2000  1.5
1    Ohio  2001  1.7
2    Ohio  2002  3.6
3  Nevada  2001  2.4
4  Nevada  2002  2.9

如果你想要自定义列序,你需要制定好序列顺序:

In [27]:pd.DataFrame(data, columns=['year', 'state', 'pop'])
Out[28]: 
   year   state  pop
0  2000    Ohio  1.5
1  2001    Ohio  1.7
2  2002    Ohio  3.6
3  2001  Nevada  2.4
4  2002  Nevada  2.9
5  2003  Nevada  3.2

如果传入的列在数据中找不到,就会在结果中产生缺失值:

In [28]:pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
   ....:                       index=['one', 'two', 'three', 'four',
   ....:                              'five', 'six'])
                             
Out[29]: 
       year   state  pop debt
one    2000    Ohio  1.5  NaN
two    2001    Ohio  1.7  NaN
three  2002    Ohio  3.6  NaN
four   2001  Nevada  2.4  NaN
five   2002  Nevada  2.9  NaN
six    2003  Nevada  3.2  NaN

通过类似字典标记的方式或属性的方式,可以将DataFrame的列获取为一个Series:

In [36]:frame2['year']
Out[33]: 
one      2000
two      2001
three    2002
four     2001
five     2002
six      2003
Name: year, dtype: int64

In [36]:frame2.state
Out[34]: 
one        Ohio
two        Ohio
three      Ohio
four     Nevada
five     Nevada
six      Nevada
Name: state, dtype: object

行也可以通过位置或名称方式进行获取,比如用到loc属性:

In [36]:frame2.loc['three']
Out[36]: 
year     2002
state    Ohio
pop       3.6
debt      NaN
Name: three, dtype: object

列可以通过赋值的方式进行修改。例如,我们可以给那个空的"debt"列赋上一个标量值或一组值:

In [37]: frame2['debt'] = 16

In [38]:frame2
Out[38]: 
       year   state  pop  debt
one    2000    Ohio  1.5    16
two    2001    Ohio  1.7    16
three  2002    Ohio  3.6    16
four   2001  Nevada  2.4    16
five   2002  Nevada  2.9    16
six    2003  Nevada  3.2    16

In [39]: import numpy as np

In [40]: frame2['debt'] = np.arange(6.)

In [41]: frame2
Out[41]: 
       year   state  pop  debt
one    2000    Ohio  1.5   0.0
two    2001    Ohio  1.7   1.0
three  2002    Ohio  3.6   2.0
four   2001  Nevada  2.4   3.0
five   2002  Nevada  2.9   4.0
six    2003  Nevada  3.2   5.0

将列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配。如果赋值的是一个Series,就会精确匹配DataFrame的索引,所有的空位都将被填上缺失值:

In [42]: val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])

In [43]: frame2['debt'] = val

In [44]: frame2
Out[44]: 
       year   state  pop  debt
one    2000    Ohio  1.5   NaN
two    2001    Ohio  1.7  -1.2
three  2002    Ohio  3.6   NaN
four   2001  Nevada  2.4  -1.5
five   2002  Nevada  2.9  -1.7
six    2003  Nevada  3.2   NaN

为不存在的列赋值会创建出一个新列。关键字del用于删除列。作为del的例子,我先添加一个新的布尔值的列,state是否为’Ohio’:

In [45]: frame2['ear'] = frame2.state == 'Ohio'

In [46]: frame2
Out[46]: 
       year   state  pop  debt    ear
one    2000    Ohio  1.5   NaN   True
two    2001    Ohio  1.7  -1.2   True
three  2002    Ohio  3.6   NaN   True
four   2001  Nevada  2.4  -1.5  False
five   2002  Nevada  2.9  -1.7  False
six    2003  Nevada  3.2   NaN  False

注意这里不能用frame2.eastern创建新的列。

del方法可以用来删除这列:

In [47]: del frame2['ear']

In [48]: frame2.columns
Out[48]: Index(['year', 'state', 'pop', 'debt'], dtype='object')

注意:通过索引方式返回的列只是相应数据的视图而已,并不是副本。因此,对返回的Series所做的任何就地修改全都会反映到源DataFrame上。通过Series的copy方法即可指定复制列。

另一种常见的数据形式是嵌套字典:

In [49]: pop = {'Nevada': {2001: 2.4, 2002: 2.9},
....:           'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}

如果嵌套字典传给DataFrame,pandas就会被解释为:外层字典的键作为列,内层键则作为行索引:

In [50]: frame3 = pd.DataFrame(pop)

In [51]: frame3

Out[52]: 
      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7
2002     2.9   3.6

你也可以使用类似NumPy数组的方法,对DataFrame进行转置(交换行和列):

In [53]: frame3.T
Out[53]: 
        2000  2001  2002
Nevada   NaN   2.4   2.9
Ohio     1.5   1.7   3.6

索引对象

pandas的索引对象负责管理轴标签和其他的元数据(例如轴名称)。构建Series或DataFrame时,所用到的任何数组或其他序列的标签都会被转换为Index:

In [76]: obj = pd.Series(range(3), index=['a', 'b', 'c'])

In [77]: index = obj.index

In [78]: index
Out[78]: Index(['a', 'b', 'c'], dtype='object')

In [79]: index[1:]
Out[79]: Index(['b', 'c'], dtype='object')

Index对象是不可变的,因此用户不能对其进行修改。不可变可以使Index对象在多个数据结构之间安全共享:

In [80]: labels = pd.Index(np.arange(3))

In [81]: labels
Out[81]: Int64Index([0, 1, 2], dtype='int64')

In [82]: obj2 = pd.Series([1.5, -2.5, 0], index=labels)

In [83]: obj2
Out[83]: 
0    1.5
1   -2.5
2    0.0
dtype: float64

In [84]: obj2.index is labels
Out[84]: True

下图表5-2列出了索引常见的方法和属性

在这里插入图片描述

5.2基本功能

基础概念介绍完毕了,接下来要对数据操作的基本手段进行一个解决,本文并不是罗列所有的pandas库,所以只展示一些常用函数,如果要深入学习,可以自己仔细阅读相关文档进一步学习。

重建索引

reindex是pandas对象的重要方法,该方法用于创建一个符合新索引的新对象:

In [91]: obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])

In [92]: obj
Out[92]: 
d    4.5
b    7.2
a   -5.3
c    3.6
dtype: float64

用该Series的reindex将会根据新索引进行重排。如果某个索引值当前不存在,就引入缺失值:

In [93]: obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])

In [94]: obj2
Out[94]: 
a   -5.3
b    7.2
c    3.6
d    4.5
e    NaN
dtype: float64

对于顺序结构的数据,比如递增函数,在重建索引的时候会需要进行插值和填充。method方法可以允许我们对其插入,例如ffill方法,会在值前插入:

In [95]: obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])

In [96]: obj3
Out[96]: 
0      blue
2    purple
4    yellow
dtype: object

In [97]: obj3.reindex(range(6), method='ffill')
Out[97]: 
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object

在DataFrame中,reindex仍然可以更改行与列的索引值。只需要传递一个序列,结果就会重置:

In [98]: frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
   ....:                      index=['a', 'c', 'd'],
   ....:                      columns=['Ohio', 'Texas', 'California'])

In [99]: frame
Out[99]: 
   Ohio  Texas  California
a     0      1           2
c     3      4           5
d     6      7           8

In [100]: frame2 = frame.reindex(['a', 'b', 'c', 'd'])

In [101]: frame2
Out[101]: 
   Ohio  Texas  California
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

列可以用columns关键字重新索引:

In [102]: states = ['Texas', 'Utah', 'California']

In [103]: frame.reindex(columns=states)
Out[103]: 
   Texas  Utah  California
a      1   NaN           2
c      4   NaN           5
d      7   NaN           8

轴向上删除条目

如果此时你已经拥有了索引数组或不含条目的列表,在轴向上删除一个或更多的条目就很容易,但这样需要一些数据操作和集合逻辑,drop方法会返回一个含有指示值或轴向上删除值的新对象:

In [105]: obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])

In [106]: obj
Out[106]: 
a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64

In [107]: new_obj = obj.drop('c')

In [108]: new_obj
Out[108]: 
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

In [109]: obj.drop(['d', 'c'])
Out[109]: 
a    0.0
b    1.0
e    4.0
dtype: float64

在DataFrame中,有类似的属性方法,具体就不再演示了,大家可以自己尝试。不过要小心使用drop函数中的inplace属性,小心使用inplace,它会销毁所有被删除的数据。‘

索引、选取和过滤

Series的索引工作方式类似于Numpy,只不过Series有更丰富的索引类型:

In [117]: obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])

In [118]: obj
Out[118]: 
a    0.0
b    1.0
c    2.0
d    3.0
dtype: float64

In [119]: obj['b']
Out[119]: 1.0

In [120]: obj[1]
Out[120]: 1.0

In [121]: obj[2:4]
Out[121]: 
c    2.0
d    3.0
dtype: float64

In [122]: obj[['b', 'a', 'd']]
Out[122]:
b    1.0
a    0.0
d    3.0
dtype: float64

In [123]: obj[[1, 3]]
Out[123]: 
b    1.0
d    3.0
dtype: float64

In [124]: obj[obj < 2]
Out[124]: 
a    0.0
b    1.0
dtype: float64

DataFrame的操作方法类似Series。同样可以通过上述方法进行选择。这使得DataFrame的语法与NumPy二维数组的语法很像。

用loc和iloc进行选取

对于DataFrame的行标签,pandas引入了loc和iloc,它们可以让使用者能够通过类似与numpy的标记方式,使用轴标签(loc)或整数标签(iloc),从DataFrame选择行和列的子集。以下作一个初步示例,我们来通过标签选择一行或多列:

In [137]: data.loc['Colorado', ['two', 'three']]
Out[137]: 
two      5
three    6
Name: Colorado, dtype: int64

然后用iloc和整数进行选取,数字就代表行与列:

In [138]: data.iloc[2, [3, 0, 1]]
Out[138]: 
four    11
one      8
two      9
Name: Utah, dtype: int64

In [139]: data.iloc[2]
Out[139]: 
one       8
two       9
three    10
four     11
Name: Utah, dtype: int64

In [140]: data.iloc[[1, 2], [3, 0, 1]]
Out[140]: 
          four  one  two
Colorado     7    0    5
Utah        11    8    9

这两个索引函数也适用于一个标签或多个标签的切片。所以,在pandas中,有多个方法可以选取和重新组合数据。对于DataFrame,图5-1进行了总结。后面会看到,还有更多的方法进行层级化索引。

在这里插入图片描述

图5-1 DataFrame的常用索引选项

由于内容太多这里分一篇!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值