Python数据分析 | (14)Pandas的数据结构

本篇博客所有示例使用Jupyter NoteBook演示。

Python数据分析系列笔记基于:利用Python进行数据分析(第2版)  

目录

1.pandas简介

2.pandas数据结构介绍


1.pandas简介

Python数据分析系列博客剩余的大部分内容是用pandas处理数据,不过还是会用到相似的基于数组的计算。

pandas含有使数据清洗和分析工作变得更快更简单的数据结构和操作工具,pandas经常和其他工具一同使用,如数值计算工具NumPy和SciPy,分析库statsmodels和scikit-learn,和数据可视化库matplotlib。pandas是基于NumPy数组构建的,特别是基于数组的函数和不使用for循环的数据处理。

虽然pandas采用了大量的NumPy编码风格,但2者最大的不同是pandas是专门为处理表格数据和混杂数据设计的。而NumPy更适合处理统一的数值数组数据。

自从2010年Pandas开源以来,pandas逐渐成长为一个非常大的库,应用于许多真实案例。开发者社区已经有了800个独立的贡献者,他们在解决日常数据问题的同时为这个项目提供贡献。

pandas引入约定:

import pandas as pd

代码中的pd就代表pandas。因为Series和DataFrame使用的次数非常多,下面这种引入方式会更方便:

from pandas import Series,DataFrame

2.pandas数据结构介绍

要使用pandas,首先得熟悉两个主要的数据结构:Series和DataFrame。虽然他们并不能解决所有问题,但他们为大多数应用提供了一种可靠的、易用的基础。

  • Series

Series是一种类似于一维数组的对象,他由一组数据(可以是各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成。仅由一组数据即可产生最简单的Series:

import pandas as pd
obj = pd.Series([4,7,-5,3])
print(obj)

Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0-N-1(N为数据长度)的整数型索引。Series的values属性获取数据的数组表现形式,index属性获取索引对象:

print(obj.values)
print(obj.index) #类似于 range(4)

通常为所创建的Series带有一个可以对各数据点进行标记的索引:

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

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

print(obj2['a'])
obj2['d'] = 100
print(obj2[['c','a','d']])

['c','a','d']是索引列表,即使它包含的是字符串而不是整数。

 

使用NumPy函数或类似NumPy的运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等)都会保留索引值的链接:

print(obj2[obj2>0])
print(obj2*2)
print(np.exp(obj2))

还可以将Series看作一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中:

print('b' in obj2)
print('e' not in obj2)

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

sdata = {'beijing':10000,'shanghai':8000,'guangzhou':9000,'shenzhen':5000,'jinan':2000}
obj3 = pd.Series(sdata)
print(obj3)

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

citys = ['aiqing','guangzhou','jinan','shanghai','shenzhen']
obj4 = pd.Series(sdata,index=citys)
print(obj4)

在上例中,sdata和citys中索引相匹配的那三个值会被找出并放到相应位置上,由于'anqing'所对应的sdata找不到,结果为NaN(非数字 not a number,在Pandas中,用于表示缺失或NA值). 因为'beijing'不在citys中,他被从结果中移除。

使用缺失(missing)或NA表示缺失数据,pandas中的isnull和notnull函数可用于检测缺失数据:

print(pd.isnull(obj4))
print(pd.notnull(obj4))

Series也有类似的实例方法:

print(obj4.isnull())

后续会详细讲解如何处理缺失数据。

对于许多应用而言,Series的一个重要功能是,他会根据运算的索引标签自动对齐数据:

print(obj3)
print(obj4)
print(obj3+obj4)

数据对齐功能之后会详细讲解。可以看作是数据库中的join操作。

Series对象本身及其索引都有一个name属性,该属性和pandas其他关键功能关系非常密切:

obj4.name = 'population'
obj4.index.name = 'city'
print(obj4)

Series的索引可以通过赋值的方式就地修改:

print(obj)
obj.index = ['alice','bob','dancy','mike']
print(obj)

 

  • DataFrame

DataFrame是一个表格型数据结构,它含有一组有序的列,每列可以是不同数据类型(数值、字符串、布尔值等).DataFrame既有行索引也有列索引,它可以被看作由Series组成的字典(共用同一个索引)。DataFrame中的数据是以一个或多个2维块存放的(而不是列表、字典或别的一维数据结构)。有关DataFrame的内部技术细节不再继续谈论。

虽然DataFrame是以2维结构保存数据的,但仍然可以轻松的将其表示为更高维度的数据(层次化索引的表格型结构,这是pandas中许多高级数据处理功能的关键要素,之后会学习).

 

创建DataFrame的方式有很多,最常用的是直接传入一个由等长列表或NumPy数组组成的字典:

data = {'city':['beijing','beijing','beijing','shanghai','shanghai','shanghai']
        ,'year':[2000,2001,2002,2001,2002,2003],'pop':[1.5,1.6,1.7,2.5,2.6,2.7]
       }
frame = pd.DataFrame(data)
print(frame)  #创建是不指定行索引 会自动添加0-N-1,全部列有序排列

对于特别大的DataFrame,head方法默认取前5行:

print(frame.head())

如果指定列序列,则DataFrame的列会按照指定顺序排列:

print(pd.DataFrame(data,columns=['year','city','pop']))

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

frame2 = pd.DataFrame(data,columns=['year','city','pop','debt'],index=['one','two','three','four','five','six'])
print(frame2)
print(frame2.columns)

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

print(frame2['city'])
print(frame2.year)

注意返回的Series拥有原DataFrame相同的索引,且其name属性也被相应的设置好了。IPython提供了类似属性的访问(即frame2.year)和tab补全。frame2[column]适用于任何列名,但是frame2.column只有在列名是一个合理的Python变量名时才适用(与Series的属性或方法名不冲突)。

行也可以通过位置或名称的方式进行获取,比如用loc属性(之后会详细学习):

print(frame2.loc['three'])

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

frame2['debt'] = 16.5
print(frame2)
frame2['debt'] = np.arange(6.)
print(frame2)

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

val = pd.Series([-1,-2,-3],index=['two','four','five'])
frame2['debt'] = val
print(frame2)

为不存在的列赋值会创建出一个新列,关键字del 可以删除列:

#添加一个布尔型 列
frame2['North'] = frame2.city=='beijing'  #不能用frame2.North创建新列
print(frame2)
del frame2['North']
print(frame2.columns)

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

 

另一种常见的创建形式就是嵌套字典,如果把嵌套字典传给DataFrame,pandas就会把外层字典的键作为列,内层键作为行索引:

pop = {'beijing':{2001:1.7,2002:1.8},'shanghai':{2000:2.2,2001:2.2,2002:2.3}}
frame3 = pd.DataFrame(pop)
print(frame3)

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

print(frame3.T)

内层字典的键会被合并、排序以形成最后的索引。如果明确指定了索引,则不会这样:

 

也可以通过Series组成的字典进行创建:

pdata = {'beijing':frame3['beijing'][:-1],'shanghai':frame3['shanghai'][:2]}
print(pd.DataFrame(pdata))

obj1 = pd.Series([1,2,3],index=['one','two','three'])
obj2 = pd.Series([1.1,2.2,3.3],index=['one','two','three'])
print(pd.DataFrame({'b':obj1,'c':obj2}))

下表列出了DataFrame构造函数所能接受的各种数据:

直接读入一个表格型数据文件,也可以转化为DataFrame。

 

如果设置了DataFrame的index和columns的name属性,则这些信息也会被显示出来:

frame3.index.name = 'year'
frame3.columns.name = 'city'
print(frame3)

和Series一样,values属性会以二维数组的形式返回DataFrame中的数据:

print(frame3.values)
print(frame2.values) #如果DataFrame各列数据类型不同,值数组的dtype会兼容所有列的数据类型
print(frame2.values.dtype)

 

  • 索引对象

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

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

Index对象不可变,因此用户不能对其进行修改:

index[1] = 'd'  #TypeError

不可变可以使Index对象在多个数据结构间安全共享:

labels = pd.Index(np.arange(3))
print(labels)
obj2 = pd.Series([1.3,3.3,0],index=labels)
print(obj2)
print(obj2.index is labels)

虽然用户不常使用Index功能,但是因为一些操作会生成包含被索引化的数据,理解他们的工作原理很重要。

 

除了类似于数组,Index的功能也类似于一个固定大小的集合:

print(frame3)
print(frame3.columns)
print('beijing' in frame3.columns)
print(2003 in frame3.index)

与Python集合不同,pandas的Index可以包含重复的标签:

dup_labels = pd.Index(['foo','foo','bar','bar'])
print(dup_labels)

选择重复的标签,会显示所有的结果。

每个索引都有一些方法和属性,他们可用于设置逻辑并回答有关该索引所包含的数据的常见问题。下表列出了这些函数:

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/sdu_hao/article/details/86523299