pandas是基于numpy构建的,使得数据分析工作变得更快更简单的高级数据结构和操作工具。
一、pandas数据结构
两个主要的数据结构:Series和DataFrame。
1.1 Series
Series是一种类似于一维数组的对象,它由一维数组(各种numpy数据类型)以及一组与之相关的数据标签(即索引)组成,仅由一组数据即可产生最简单的Series.
Series的字符串表现形式为:索引在左边,值在右边。如果没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。可以通过Series的values和index属性获取其数组表现形式和索引对象:
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
#**********************************Series*************************************
obj=Series([2,4,7,8,9,3])
'''obj=
0 2
1 4
2 7
3 8
4 9
5 3
dtype: int64
'''
obj.values #return:array([2, 4, 7, 8, 9, 3], dtype=int64)
obj.index #return: RangeIndex(start=0, stop=6, step=1)
#创建对数据点进行标记的索引
obj2=Series([2,4,7,8,9,3],index=['a','b','c','d','e','f'])
'''obj2=
a 2
b 4
c 7
d 8
e 9
f 3
dtype: int64
'''
obj2.index #return:Index(['a', 'b', 'c', 'd', 'e', 'f'], dtype='object')
#利用索引的方式选取Series的单个或一组值
obj2['c'] #return:7
obj2[['a','c','f']]
'''out:
a 2
c 7
f 3
dtype: int64
'''
#numpy数组运算(布尔型数组进行过滤、标量乘法、应用数学函数等)都会保留索引和值之间的链接
obj2[obj2>5]
obj2*2
np.exp(obj2)
'''
obj2[obj2>5]: obj2*2: np.exp(obj2):
c 7 a 4 a 7.389056
d 8 b 8 b 54.598150
e 9 c 14 c 1096.633158
dtype: int64 d 16 d 2980.957987
e 18 e 8103.083928
f 6 f 20.085537
dtype: int64 dtype: float64
'''
#可以将Series看成是一个有定长的有序字典,因为它是索引值到数据值的一个映射
#因此,一些字典函数也可以在这里使用:
'a' in obj2 #return:True
'h' in obj2 #return:False
2 in obj2.values #return:True
#利用字典创建Series
dic={'l':1,'z':2,'h':3}
obj3=Series(dic)
'''obj3=
h 3
l 1
z 2
dtype: int64
'''
#若索引比字典的索引多,则与字典索引相匹配的则会被找到,并放置到相应的位置中
#而对应字找不到的索引,其结果则为NaN(即非数字,Not a Number,在pandas中,用于表示缺失或NA值)
ind=['l','z','h','a']
obj4=Series(dic,index=ind)
'''obj4=
l 1.0
z 2.0
h 3.0
a NaN
dtype: float64
'''
#pandas中isnull和notnull函数用于检测缺失数据:
pd.isnull(obj4) #等效于: obj4.isnull()
pd.notnull(obj4)
'''
pd.isnull(obj4): pd.notnull(obj4)
l False l True
z False z True
h False h True
a True a False
dtype: bool dtype: bool
'''
#算术运算中自动对齐不同索引的数据
obj3+obj4
'''out:
a NaN
h 6.0
l 2.0
z 4.0
dtype: float64
'''
#Series对象本身及其索引都有一个name属性
obj4.name='myname'
obj4.index.name='letter'
'''obj4=
letter
l 1.0
z 2.0
h 3.0
a NaN
Name: myname, dtype: float64
'''
#索引可以通过赋值的方式进行改变
obj4.index=['li','zi','hua','a']
'''obj4=
li 1.0
zi 2.0
hua 3.0
a NaN
Name: myname, dtype: float64
'''
1.2 DataFrame
DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(公用同一个索引)。跟其他类似的数据结构相比,DataFrame中面向行和面向列的操作基本是平衡的。其实,DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或者别的一维数据结构)。
其中,可以输入给DataFrame构造器的数据类型及相关说明:
#*******************************DataFrame*************************************
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
#构建DataFrame
#最常用的一种是直接传入一个由等长列表或numpy数组组成的字典:
data={'names':['Bob','Jane','Jack','Ann'],
'sex':['M','F','M','F'],
'age':[21,30,26,28]}
frame=DataFrame(data)
'''没有指定索引,会自动加上索引,且全部列会被有序排列
frame=
age names sex
0 21 Bob M
1 30 Jane F
2 26 Jack M
3 28 Ann F
'''
#若指定列序列,则会按照指定顺序排列
frame=DataFrame(data,columns=['names','sex','age'])
'''frame=
names sex age
0 Bob M 21
1 Jane F 30
2 Jack M 26
3 Ann F 28
'''
#若传入列在数据中找不到,会返回NA值
frame1=DataFrame(data,columns=['names','sex','age','id'],index=['a','b','c','d'])
'''frame1=
names sex age id
a Bob M 21 NaN
b Jane F 30 NaN
c Jack M 26 NaN
d Ann F 28 NaN
'''
#通过类似字典标记或属性的方式,可以获取Series(列数据):
frame1['sex']
frame1.age
'''
frame1['sex']: frame1.age:
a M a 21
b F b 30
c M c 26
d F d 28
Name: sex, dtype: object Name: age, dtype: int64
'''
#行也可以通过位置或名称获取
#ix VS loc VS iloc
#loc——通过行标签索引行数据
frame1.loc('c')
#等效于
#iloc——通过行号获取行数据
frame1.iloc[2]
#ix--以上两种的混合,既可以用行号,也可以用行标签
frame1.ix[2]
frame1.ix['c']
'''result:
names Jack
sex M
age 26
id NaN
Name: c, dtype: object
'''
#获取多行
#注意:使用行标签时,:两边是全包括,使用行号时是左闭右开
frame1.loc['b':'c']
frame1.iloc[2:4]
frame1.ix['b':'c']
frame1.ix[2:4]
'''result:
names sex age id
c Jack M 26 NaN
d Ann F 28 NaN
'''
#利用ix、loc、iloc拓展获取列数据
#获取单列,如下所示,或将['sex']写成'sex',将不显示columns名
frame1.ix[:,['sex']] #等效于frame1['sex']
frame1.loc[:,['sex']]
frame1.ix[:,[1]]
'''
frame1.ix[:,['sex']]: VS frame1.ix[:,'sex'] :
sex
a M a M
b F b F
c M c M
d F d F
'''
#获取多列
frame1.ix[:,'sex':]
frame1.loc[:,'sex':]
frame1.iloc[:,1:4]
'''result:
sex age id
a M 21 NaN
b F 30 NaN
c M 26 NaN
d F 28 NaN
'''
#给列赋值,赋值是列表或数组时,长度必须相匹配
frame1['id']=np.arange(4)
'''frame1=
names sex age id
a Bob M 21 0
b Jane F 30 1
c Jack M 26 2
d Ann F 28 3
'''
#若赋值的是一个Series,将精确匹配DataFrame的索引,空位将补上缺失值
frame1['id']=Series([11,12],index=['a','c'])
'''frame1=
names sex age id
a Bob M 21 11.0
b Jane F 30 NaN
c Jack M 26 12.0
d Ann F 28 NaN
'''
#为不存在的列赋一个新列
frame1['Female']=frame1.sex=='F'
'''frame1=
names sex age id Female
a Bob M 21 11.0 False
b Jane F 30 NaN True
c Jack M 26 12.0 False
d Ann F 28 NaN True
'''
#删除列数据
del frame1['Female']
'''frame1=
names sex age id
a Bob M 21 11.0
b Jane F 30 NaN
c Jack M 26 12.0
d Ann F 28 NaN
'''
#嵌套字典(字典的字典)作为参数,传入DataFrame
#外层字典的键作为列(columns),内层键作为行索引(index)
pop={'Nevada':{2001:2.4,2002:2.9},'Ohio':{2000:1.5,2001:1.7,2002:3.6}}
frame2=DataFrame(pop)
'''frame2=
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
'''
#对结果进行转置
frame2.T
'''result:
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6
'''
#显示指定索引
DataFrame(pop,index=[2001,2002,2003])
'''result:
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2003 NaN NaN
'''
#跟Series一样,values属性也会以二维ndarray的形式返回DataFrame中的数据
frame2.values #result:array([[ nan, 1.5],[ 2.4, 1.7],[ 2.9, 3.6]])
二、基本功能
2.1 重新索引-------reindex:创建一个适合新索引的新对象
reindex函数的参数:
Series中reindex方法:
#Series中的reindex方法
obj=Series([1.2,3.4,-7.8,5.6],index=['d','a','c','b'])
#rreindex会根据新索引重新排列,若索引值不存在,则引入缺省值
obj.reindex(['a','b','c','d','e'])
#还可设置缺省项的值
obj.reindex(['a','b','c','d','e'],fill_value=0) #此时,上面结果中的NaN将变成0
'''
obj: obj.reindex(['a','b','c','d','e']):
d 1.2 a 3.4
a 3.4 b 5.6
c -7.8 c -7.8
b 5.6 d 1.2
dtype: float64 e NaN
dtype: float64
'''
#插值处理
#对于时间序列这样的有序序列,重新索引时需要做一些插值处理
obj1=Series(['yellow','pink','blue'],index=[0,2,4])
obj1.reindex(range(6),method='ffill')
'''obj1=
0 yellow
1 yellow
2 pink
3 pink
4 blue
5 blue
dtype: object
'''
DataFrame中reindex方法:
reindex可以修改(行)索引、列,或两个都修改。如果仅传入一个序列,则会重新索引行:frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=['US','UK','CN'])
'''frame=
US UK CN
a 0 1 2
b 3 4 5
c 6 7 8
'''
frame1=frame.reindex(['a','b','c','e'])
#使用columns关键字即可重新索引列
states=['US','HK','CN']
frame.reindex(columns=states)
'''result:
US HK CN
a 0 NaN 2
b 3 NaN 5
c 6 NaN 8
'''
#可以同时对行和列进行索引,但插值只能按照行(即轴0)应用
frame.reindex(index=['a','b','c','e'],method='ffill',columns=states)
'''
US HK CN
a 0 NaN 2
b 3 NaN 5
c 6 NaN 8
e 6 NaN 8
'''
#利用ix索引功能,重新索引任务变得更加简洁
frame.ix[['a','b','c','e'],states]
'''
US HK CN
a 0.0 NaN 2.0
b 3.0 NaN 5.0
c 6.0 NaN 8.0
e NaN NaN NaN
'''
2.2 丢弃指定轴上的项------drop方法
由于需要执行一些数据整理和集合逻辑,所以drop方法返回的是一个在指定轴上删除了指定值的新对象。
#对于Series对象
obj=Series([1.2,3.4,-7.8,5.6],index=['d','a','c','b'])
obj.drop('c') #返回的是新对象,obj没变
obj.drop(['a','d'])
'''
obj: obj.drop('c'): obj.drop(['a','d']):
d 1.2 d 1.2 c -7.8
a 3.4 a 3.4 b 5.6
c -7.8 b 5.6 dtype: float64
b 5.6 dtype: float64
dtype: float64
'''
#对于DataFrame,可以删除任意轴上的索引值:
frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=['US','UK','CN'])
frame.drop('a') #默认axis=0
frame.drop(['US','UK'],axis=1)
'''
frame: frame.drop('a'): frame.drop(['US','UK'],axis=1):
US UK CN US UK CN CN
a 0 1 2 b 3 4 5 a 2
b 3 4 5 c 6 7 8 b 5
c 6 7 8 c 8
'''
2.3 算术运算和数据对齐
pandas最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是索引对的并集。#对于Series对象
s1=Series([1.2,3.4,-7.8,5.6],index=['d','a','c','b'])
s2=Series([1.1,2.2,3.3,4.4.,5.5,6.6],index=['a','b','c','d','e','f'])
s1+s2 #在不重叠的地方引入了NA值,且缺失值会在算术运算过程中传播
'''result:
a 4.5
b 7.8
c -4.5
d 5.6
e NaN
f NaN
dtype: float64
'''
对于DataFrame对象,对齐操作会发生在列和行上,具体过程和Series一样。
2.4 DataFrame和Series之间的运算
跟Numpy数组一样,DataFrame和Series之间的算术运算也是有明确规定的,和不同形状的数组之间的运算类似,也具有广播效应。
默认情况下,DataFrame和Series之间的算术运算会将Series的索引匹配到DataFrame的列,然后沿着行已知向下传播(行传播):
frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=['US','UK','CN'])
s=frame.ix['a']
frame-s
'''
frame: s: frame-s:
US UK CN US 0 US UK CN
a 0 1 2 UK 1 a 0 0 0
b 3 4 5 CN 2 b 3 3 3
c 6 7 8 c 6 6 6
'''
如果你希望匹配行,且在列上广播(列传播),则必须使用算术运算方法:frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=['US','UK','CN'])
s1=frame['CN']
frame.sub(s1,axis=0) #axis=0不能少,否则运算时,默认沿着行向下传播
'''
frame: s1: frame.sub(s1,axis=0)
US UK CN CN US UK CN
a 0 1 2 a 2 a -2 -1 0
b 3 4 5 b 5 b -2 -1 0
c 6 7 8 c 8 c -2 -1 0
'''
frame-s1 #或frame.sub(s1)
'''result:
CN UK US a b c
a NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN
'''
算术方法:
2.5 函数应用和映射
numpy中ufuncs(元素级数组方法)也可以用于pandas对象,例:
np.exp(frame)
'''
US UK CN
a 1.000000 2.718282 7.389056
b 20.085537 54.598150 148.413159
c 403.428793 1096.633158 2980.957987
'''
另一个常见的操作是,将函数应用到由各列或行所形成的一维数组上,DataFrame的apply方法即可实现该功能:f=lambda x:x.max()-x.min()
frame.apply(f) #函数应用到每列所形成一维数组
frame.apply(f,axis=1) #函数应用到每行所形成一维数组
'''
frame:
US UK CN frame.apply(f): frame.apply(f,axis=1)
a 0 1 2 US 6 a 2
b 3 4 5 UK 6 b 2
c 6 7 8 CN 6 c 2
'''
2.6 排序和排名
根据条件对数据集排序,这是一个内置运算,要对行或列索引进行排序(按字典排序),可使用sort_index方法,它将返回一个已排序好的新对象。
2.6.1 排序
#排序
obj=Series([1.2,3.4,-7.8,5.6],index=['d','a','c','b'])
#索引排序
obj.sort_index()
#值排序
obj.sort_values()
'''
obj: obj.sort_index(): obj.sort_values():
d 1.2 a 3.4 c -7.8
a 3.4 b 5.6 d 1.2
c -7.8 c -7.8 a 3.4
b 5.6 d 1.2 b 5.6
'''
frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=['US','UK','CN'])
#索引排序,分轴0和轴1,若需要按照哪行排序,可利用by='',锁定某行
frame.sort_index(axis=1)
#值排序
#axis=0代表对列操作,by='CN'代表对name为'CN'的列处理,ascending默认为True,代表升序排
frame.sort_values(by='CN',axis=0,ascending=False)
'''
frame: frame.sort_index(axis=1): frame.sort_values(by='CN',axis=0,ascending=False):
US UK CN CN UK US US UK CN
a 0 1 2 a 2 1 0 c 6 7 8
b 3 4 5 b 5 4 3 b 3 4 5
c 6 7 8 c 8 7 6 a 0 1 2
'''
#在排序中,默认缺失值都会被放到最后
obj1=Series([4,np.nan,7,np.nan,-3,5])
'''result:
4 -3.0
0 4.0
5 5.0
2 7.0
1 NaN
3 NaN
dtype: float64
'''
2.6.2 排名
排名(ranking)跟排序关系密切,且它会增设一个排名值(从1开始,一直到数组中有效数据的数量)。它跟numpy.argsort产生的间接排序索引差不多,只不过它可以根据某种规则破坏平级关系。默认情况下,rank是通过”为各组分配一个平均排名“的方式破坏平级关系的。
rank()函数中,用于破坏平级关系的method选项:
#排名:
obj=Series([7,-5,7,4,2,0,4])
obj.rank()
obj.rank(method='first')
'''
obj: obj.rank(): obj.rank(method='first'):
0 7 0 6.5 0 6.0
1 -5 1 1.0 1 1.0
2 7 2 6.5 2 7.0
3 4 3 4.5 3 4.0
4 2 4 3.0 4 3.0
5 0 5 2.0 5 2.0
6 4 6 4.5 6 5.0
'''
frame=DataFrame({'b':[3,2,4,1],'a':[7,5,2,9],'c':[3,9,6,2]})
frame.rank(axis=1)
'''
frame: frame.rank(axis=1):
a b c a b c
0 7 3 3 0 3.0 1.5 1.5
1 5 2 9 1 2.0 1.0 3.0
2 2 4 6 2 1.0 2.0 3.0
3 9 1 2 3 3.0 1.0 2.0
'''
三、汇总和计算描述统计
pandas对象拥有一组常用的数学和统计方法。它们大部分都属于简约和汇总统计,用于从Series中提取单个值(如sum或mean)或从DataFrame的行或列中提取一个Series。更对应的numpy数组方法,它们都是基于没有缺失数据的假设而构建的。
3.1与描述统计相关的函数:
3.2 函数中常见的选项:
3.3部分代码示例:
#汇总和统计
df=DataFrame([[1.4,np.nan],[7.1,-4.5],[np.nan,np.nan],[0.75,-1.3]],columns=['one','two'])
#计算每列的和,默认排除NaN
df.sum()
#计算每行的和,默认排除NaN
df.sum(axis=1)
#计算每行的和,设置skipna=False,NaN参与计算,结果仍为NaN
df.sum(axis=1,skipna=False)
'''
df: df.sum(): df.sum(axis=1): df.sum(axis=1,skipna=False):
one two one 9.25 0 1.40 0 NaN
0 1.40 NaN two -5.80 1 2.60 1 2.60
1 7.10 -4.5 2 0.00 2 NaN
2 NaN NaN 3 -0.55 3 -0.55
3 0.75 -1.3
'''
obj=Series(['a','b','a','d']*4)
obj.describe()
'''
count 16
unique 3
top a
freq 8
dtype: object
'''
3.4、唯一值、值计数以及成员资格
常见方法:(对于Series对象)
相关代码:obj=Series(['a','d','a','b']*4)
unique=obj.unique() #结果未排序 return:array(['a', 'd', 'b'], dtype=object)
obj.value_counts() #结果按值频率降序排序
#等效于 pd.value_counts(obj,sort=True)
'''result:
a 8
d 4
b 4
dtype: int64
'''
obj1=Series(['a','b','c','d'])
#判断矢量化集合的成员资格
obj1.isin(['b','d'])
'''
0 False
1 True
2 False
3 True
dtype: bool
'''对于DataFrame对象,可以使用apply函数和以上函数联合使用。
frame=DataFrame({'b':[3,2,4,1],'a':[3,5,2,1],'c':[3,3,2,2]})
#fillna(0)将nan值的位置上填补0
frame.apply(pd.value_counts).fillna(0)
'''
a b c
1 1.0 1.0 0.0
2 1.0 1.0 2.0
3 1.0 1.0 2.0
4 0.0 1.0 0.0
5 1.0 0.0 0.0
'''
四、处理缺失数据
缺失数据是大部分数据分析应用中都很常见。pandas的设计目标之一就是让缺失数据的处理任务尽量轻松。pandas使用浮点值(NaN)表示浮点和非浮点数据中的缺失数据。它只是一个便于被检测出来的标记而已。python中的内置none也会被当做NA处理。
NA的处理方法: