700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Pandas简明教程(一):Series数据类型 DataFrame数据类型

Pandas简明教程(一):Series数据类型 DataFrame数据类型

时间:2020-06-08 16:10:50

相关推荐

Pandas简明教程(一):Series数据类型 DataFrame数据类型

一、Pandas概述

1.1 简介

Pandas是Python生态中非常重要的数据分析包,它是一个开源的库,采用BSD开源协议。

Pandas是基于NumPy构建的数据分析包,但它含有比ndarray更为高级的数据结构和操作工具,如Series类型、DataFrame类型等。

Pandas的便捷功能离不开高效的底层数据结构的支持。

Pandas主要有三种数据结构:

Series(类似于一维数组)DataFrame(类似于二维数组)Panel(类似于三维数组)。由于Panel并不常用,因此,新版本的Pandas已经将其列为废弃(Deprecated)的数据结构。

此外,Pandas还是数据读取“小能手”,支持从多种数据存储文件(如CSV、TXT、Excel、HDF5等)中读取数据,支持从数据库(如SQL)中读取数据,还支持从Web(如JSON、HTML等)中读取数据。

1.2 安装

# pip install pandas

1.3 导入

import numpy as npimport pandas as pdpd.__version__

二、Series类型数据

SeriesPandas的核心数据结构之一,也是理解高阶数据结构DataFrame的基础。

Series(有中文译为“系列”)是一种类似于一维数组的数据结构,是由一组数据及与之对应的标签(即索引)构成的。

2.1 创建Series

语法:pd.Series(data, index=index)

其中data就是数据源,其类型可以是一系列的整数、字符串,也可是浮点数或某类Python对象。默认索引就是数据的标签(label)。

In [1]: a = pd.Series([-1,2,5,7])In [2]: aOut[2]:0 -11 22 53 7dtype: int64In [3]: a.indexOut[3]: RangeIndex(start=0, stop=4, step=1)In [4]: a.valuesOut[4]: array([-1, 2, 5, 7], dtype=int64)

由上述代码可知,Series数据有两列,第一列是数据对应的索引,第二列就是常见的数组元素。由此可见,Series是一种自带标签的一维数组(one-dimensional labeled array)

我们可以通过Seriesindexvalues属性,分别获取索引和数组元素值。

2.1.1Series与列表

Series的数据源可以用列表来填充。

二者有相似之处,它们内部都包括一系列的数据。

不同之处在于,列表内的元素可以是相同类型的,也可以是不同类型的,也就是说列表中的元素是“大杂烩”。而Series则不同,它依赖于NumPy中的N维数组(ndarray)而构建,因此,其内部的数据要整齐划一,数据类型必须相同。

此外,Series增加对应的标签(label)作为索引。如果没有显式添加索引,Python会自动添加一个[0, n-1]内的索引值(n为Series对象内含元素的个数)。通常的视图是索引在左,数值在右。

2.1.2 Series与字典

创建Series对象时,其标签并不必然是0~n-1内的数字,它也可以被显式指定为其他类型,甚至可在创建索引后被二次修改。

In [1]: a=pd.Series([-1,2,5,7],['a','b','c','d'])In [2]: aOut[2]:a -1b 2c 5d 7dtype: int64In [3]: a.valuesOut[3]: array([-1, 2, 5, 7], dtype=int64)In [4]: a.indexOut[4]: Index(['a', 'b', 'c', 'd'], dtype='object')#修改标签In [5]: a.index=['a', 'b', 'c', 'e']In [6]: aOut[6]:a -1b 2c 5e 7dtype: int64

乍一看,Series与Python中的字典颇有相似之处。的确如此,Series中的index可对应字典中的keySeries中的value与字典中的value相同。因此,Series也可以由现有的字典数据类型通过“打包”来创建。

由于字典中的key可以“对标”Series中的index,两者都起到快速定位数据的作用,所以无须单独设置Series所需的index参数。

In [1]: d=pd.Series({'a':1, 'b':2, 'c':3, 'e':4})In [2]: dOut[2]:a 1b 2c 3e 4dtype: int64

如果Pandas中的Series与Python中的字典完全一样,那么Series就没有存在的必要了。言外之意就是,它与字典还是有不同之处的。我们知道,字典是一种无序的数据类型(python3.6之前),而Series却是有序的,并且Seriesindexvalue之间是相互独立的。此外,两者的索引也是有区别的,Seriesindex是可变的,而字典的key是不可变的。

2.2Series的统计功能

Series还提供了简单的统计方法(如describe())供我们使用。describe()方法为以列为单位进行统计分析。默认情况下,describe()只对数值型的列进行统计分析。其统计参数的意义简述如下。

count:一列数据的个数。mean:一列数据的均值。std:一列数据的均方差。min:一列数据中的最小值。max:一列数据中的最大值。25%:一列数据中前25%的数据的分位数。50%:一列数据中前50%的数据的分位数。75%:一列数据中前75%的数据的分位数。

In [1]: d=pd.Series({'a':1, 'b':2, 'c':3, 'e':4})In [2]: d.describe()Out[2]:count 4.000000mean2.500000std1.290994min1.00000025%1.75000050%2.50000075%3.250000max4.000000dtype: float64

2.3 Series中的数据访问

一旦指定Series的标签,就可以通过特定标签,访问、修改索引位置对应的数值。

Series对象在本质上就是一个带有标签的NumPy数组,因此,NumPy中的一些概念和操作方法,可直接用于Series对象。

比如:

通过索引访问数组元素

通过切片访问数组元素

花式索引:列表作为索引

布尔索引:比较表达式作为索引

In [1]: d=pd.Series({'a':1, 'b':2, 'c':3, 'e':4})# 按标签访问In [2]: d['a']Out[2]: 1# 按索引访问In [3]: d[0]Out[3]: 1# 按切片访问In [4]: d[1:3]Out[4]:b 2c 3dtype: int64# 按花式索引访问In [5]: d[[1,2,3]]Out[5]:b 2c 3e 4dtype: int64# 按布尔索引访问In [6]: d[d>2]Out[6]:c 3e 4dtype: int64

特别需要注意的是,与基于数字的切片不同,基于标签的切片访问,其访问区间是左闭右也闭的,也就是说访问是“指哪打哪”的,不留余地。因此,索引为’a’、'b’和’c’的这三个元素的值,都被读取到了。

In [1]: d=pd.Series({'a':1, 'b':2, 'c':3, 'e':4})In [2]: d['a':'c']Out[2]:a 1b 2c 3dtype: int64

2.4Series的元素操作

2.4.1 添加元素

两个Series对象还可以通过append()方法实施叠加操作,以达到Series对象合并的目的。

In 1]: a=pd.Series([1,2,3])In [2: b=pd.Series([4,5,6])In [3]: a.append(b)Out[3]:0 11 22 30 41 52 6dtype: int64In [4]: a.append(b,ignore_index=True)Out[4]:0 11 22 33 44 55 6dtype: int64

通过append()方法的确可以将参数中的对象“追加”到目标对象之后,但这会产生一些小问题,因为ab的索引都是012,叠加到一起就会产生重复的索引,不利于通过索引来访问Series中的元素。为了解决这个问题,我们可以在append()方法中添加参数ignore_index=True,这样原始Series对象中的索引都会被忽略,而由Pandas统一给数值添加索引。

2.4.2 删除元素

当我们想要删除Series中的一条或者多条数据时,可以使用Pandas提供的drop()方法。

In [1]: a =pd.Series([1,2,3,4])In [2]: aOut[2]:0 11 22 33 4dtype: int64# 删除索引为0的元素,相当于a.drop(labels=0)In [3]: a.drop(0)Out[3]:1 22 33 4dtype: int64# a数据并没有改变In [4]: aOut[4]:0 11 22 33 4dtype: int64

Series进行删除操作并不会“惊扰”原有Series中的数值。虽然使用drop()方法删掉了索引值为0的数据,但原有Series中的数据依然安然无恙。这是因为,drop()操作的流程是这样的:先将原始的Series数据复制到一个新的内存空间(即所谓的深拷贝),再在新的Series对象基础上,删除指定索引值,这时,新旧两个Series分处不同的内存空间,自然操作起来互不干涉。你可以理解为,drop()操作仅仅返回原有Series对象的一个视图而已。

如果想一次性删除多个索引值对应的数据,就需要把这多个索引值打包为一个列表。

In [5]: a.drop([0,1])Out[5]:2 33 4dtype: int64

如果的确想删除原始Series对象中的数据,可以在drop()方法中多启用一个参数inplace,它是一个布尔类型变量,默认值为False,如果设置为Truedrop()操作就会在“本地”完成,最终的删除效果便会体现在原始Series对象上。

In [6]: a.drop([0,1],inplace=True)In [7]: aOut[7]:2 33 4dtype: int64

2.5Series中的向量化操作

类似于NumPyPandas中的数据结构也支持广播操作。比如说,某个向量乘以某个标量,那么这个标量会自我复制,并拉伸至维度尺寸与向量相同,然后即可进行逐元素(element-wise)操作。

In [1]: a=pd.Series([1,2,3])In [2]: a*3Out[2]:0 31 62 9dtype: int64

需要说明的是,任何NaN(Not a Number,即空置)参与的计算,返回的结果依然是NaN

在代码层面,向量化通常是消除代码中显式for循环语句的“艺术”。在底层实现上,Pandas的很多操作都是基于NumPy实现的,而在NumPy中,向量化操作通常意味着并行处理。

另外,Series对象也可以作为NumPy函数的一个参数。顾名思义,在本质上,Series就是“一系列”的数据,类似数组向量。这样一来,它就可以在NumPy函数的操作下,达到“向量进,向量出”的目的,而不像C或Java等编程语言一样使用for循环来完成类似的操作。

In [1]: s=pd.Series(np.random.randn(5))In [2]: sOut[2]:0 1.9021401 -0.7585702 1.0265713 2.3613294 -1.087620dtype: float64In [3]: a=np.abs(s)In [4]: aOut[4]:0 1.9021401 0.7585702 1.0265713 2.3613294 1.087620dtype: float64

2.6Seriesname属性

关于Series的属性,除了我们在前面讨论过的indexvalues,还有两个很有用的需要说明,那就是nameindex.namename可以理解为数值列的名称。如果把index也理解为一个特殊索引列的话,那么index.name就是这个索引列的名称。

name属性多用在Pandas另外一个常见的数据结构DataFrame中,DataFrame可视为多个Series对象的组合。

默认情况下,nameindex.name都被设置为None

在特定场合下,我们也可以通过如下代码进行修改。

三、DataFrame类型数据

如果把Series看作Excel表中的一列,那么DataFrame就是Excel中的一张表。从数据结构的角度来看,Series好比一个带标签的一维数组,而DataFrame就是一个带标签的二维数组,它可以由若干个一维数组(Series)构成

3.1 构建DataFrame

为了方便访问数据,DataFrame中不仅有行索引(好比Excel表中最左侧的索引编号),还有列索引(好比Excel表中各个列的列名)。

我们可以通过字典、Series等基本数据结构来构建DataFrame

最常用的方法之一是,先构建一个由列表或NumPy数组组成的字典,然后再将字典作为DataFrame中的参数。

In [1]: df=pd.DataFrame({'test':[1,2,3,4]})In [2]: dfOut[2]:test01122334

DataFrame是一种表格型数据结构,它含有一组有序的列,每列的值可以不同。充当DataFrame数据源的字典中有两部分:keyvalue。其角色各不相同,字典的key变成了DataFrame的列名称,而字典的value是一个列表,列表的长度就是行数。

为每一行打一个标签,得到的就是索引,位于DataFrame对象的最左侧。从上面的输出可以看出,与Series类似的是,在默认情况下,DataFrame的索引也是从0开始的自然数序列。

如果充当数据源的字典中有多个key/value对,那么每个key都对应一列。

In [1]: df=pd.DataFrame({'one':[1,2,3,4],'two':[5,6,7,8]})In [2]: dfOut[2]:one two0 1 51 2 62 3 73 4 8

由输出可以看出,字典的key对应DataFrame中的column(列)。每个key对应的value变成了不同的列数据。因此,在某种程度上,DataFrame可以看作由Series组成的大字典。

除了可以将字典当作构造DataFrame的数据源,我们也可以将NumPy中的二维数组转化为DataFrame对象。二维数组比较“纯粹”,只能提供必要的数据,DataFrame的索引名称和列名称均无法从数组对象中获取。因此,通过二维数组创建的DataFrame列名及行名都是默认的自然数序列。

In [1]: import numpy as npIn [2]: a=np.arange(1,10).reshape(3,3)In [3]: aOut[3]:array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])In [4]: df=pd.DataFrame(a)In [5]: dfOut[5]:0 1 20 1 2 31 4 5 62 7 8 9

当然,也可以在创建时显式指定列名及index行名。

In [6]: df=pd.DataFrame(a,columns=['a','b','c'],index=['one','two','three'])In [7]: dfOut[7]:a b cone 1 2 3two 4 5 6three 7 8 9

3.2 访问DataFrame中的列与行

3.2.1 访问列

访问DataFrame中的列很方便,因为DataFrame提供了特殊属性——columns,通过具体的列名称,我们就可以轻松获取一列或多列数据。

Pandas中,DataFrame还有一个“神奇”特性,就是可以将列的名称作为DataFrame对象的属性来访问数据。例如,对于df而言,它有三列,其列名分别为abc。事实上,df这个对象同时拥有这三个属性。我们知道,访问一个对象属性的方法是“对象名.属性名”。

In [8]: df['a']Out[8]:one1two4three 7Name: a, dtype: int32In [9]: df.aOut[9]:one1two4three 7Name: a, dtype: int32

df.adf2['a']是等价的,但有一点需要注意,如果列名的字符串包含空格,或存在其他不符合Python变量命名规范的情况,则不能通过访问对象属性的方式来访问某个特定的列。此外,上述方法仅仅对单个列是有效的。如果想要同时访问多个列,还是得“规规矩矩”地将多个列的名称打包进一个列表之中,例如,df[['a','b']就是一个包含两个列名的列表。

In [10]: df.columnsOut[10]: Index(['a', 'b', 'c'], dtype='object')In [11]: df.columns.valuesOut[11]: array(['a', 'b', 'c'], dtype=object)In [12]: df.columns.values[0]Out[12]: 'a'

df.columns返回的是一个Index对象,如果想读取这个对象的值,还需要进一步读取这个Indexvalues属性。df.columns.values返回的是一个数组对象,我们可以直接用访问数组的方式(如下标)来访问它。

3.2.2 访问行

倘若想获取DataFrame中一行或多行数据,最简单的方法莫过于使用切片技术,DataFrame的切片方法和列表及NumPy是类似的。

注意:只能是切片,不能是单个索引。

In [13]: df[1:3]Out[13]:a b ctwo 4 5 6three 7 8 9

以数字切片的方法来获取DataFrame的行数据,有时也有局限性。DataFrame提供了备用方案,即使用loc(index)方法,这里的loc是location(位置)的简写,其参数index是行的索引标签。

In [14]: dfOut[14]:a b cone 1 2 3two 4 5 6three 7 8 9In [15]: df.loc[['one','two']]Out[15]:a b cone 1 2 3two 4 5 6

此外,还有一个方法iloc值得关注,它完全是基于位置的索引,其中的参数都是数字(该方法开头的“i”是指index,特指数字索引)。iloc的用法与NumPy的切片用法完全一样,可以把它视作DataFrame版本的切片操作。

也正因如此,iloc虽为DataFrame对象的一个方法,但这个方法并不像其他方法一样有一对圆括号紧跟其后,而是如同NumPy一样,使用一对方括号[]来协助完成切片操作,这显然是为了和NumPy的用法“接轨”,降低用户的学习门槛。

In [16]: df.iloc[:,1:]Out[16]:b cone 2 3two 5 6three 8 9

iloc方法中,行和列的索引用逗号隔开,逗号前是行索引,逗号后是列索引

方括号中没有逗号时,表示的是行索引。如果仅仅给出一个数字,则返回这个行索引代表的一行数据,单行数据就是一个Series对象。

In [17]: df.iloc[1]Out[17]:a 4b 5c 6Name: two, dtype: int32

我们也可以利用iloc方法返回DataFrame的多行数据。如果这些行数据是连续的,可以用行索引的切片操作来获取。如果这些行数据是不连续的,可以把这些间断的行索引编号汇集起来,赋值给一个列表,然后将这个列表当作iloc方法的参数。

In [18]: df.iloc[1:2]Out[18]:a b ctwo 4 5 6In [19]: df.iloc[[0,2]]Out[19]:a b cone 1 2 3three 7 8 9

iloc方法的优势并不体现在对行粒度的访问上,而是体现在它精确的区域定位上,方括号内每增加一个逗号,就增加一个维度的控制权。

In [20]: df.iloc[0,2]Out[20]: 3

索引基础用法如下:

3.3DataFrame中的删除操作

有了行或列的索引,就可以对DataFrame中的数据进行修改。类似于Series,在DataFrame中同样可以使用drop()方法删除一行或者一列。

In [21]: df=pd.DataFrame({'one':[1,2,3],'two':[4,5,6,],'three':[7,8,9]})In [22]: dfOut[22]:one two three0 1 471 2 582 3 69In [23]: df.drop('three',axis='columns')Out[23]:one two0 1 41 2 52 3 6In [24]: dfOut[24]:one two three0 1 471 2 582 3 69In [25]: df.drop(0,axis=0)Out[25]:one two three1 2 582 3 69

删除列时,轴值还可以设置为axis=1,这与axis='columns'是等价的。

如果我们把drop()函数的删除轴方向设置为行方向(axis=0),这样就可达到删除行的目的。

同时“删除”多行数据,这时需要把多个行号用列表的方括号括起来。

如:df.drop([0,1],axis=0)

类似于Series中的drop()方法,上述的删除操作仅仅是假象。输出结果仅仅是原有DataFrame的一个视图,原始DataFrame的数据并没有发生变化。

如果删除DataFrame原始数据就是要借助drop()中的另外一个参数inplace(本地),其默认值为False,此时我们将其设置为True

我们还可以利用全局内置函数del,在原始DataFrame对象中删除某一列。

参考

《Python极简讲义》

/docs/

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。