Pandas学习
(一).前言:
Pandas是建立在Numpy数据结构上的,尤其时它的Series 和Dataframe对象,为数据科学家们处理那些消耗大量时间的"数据清理"任务提供了捷径.
下面我将重点介绍Series ,Dataframe和其他数据结构的高效使用方法.
(二).Pandas的安装:
在安装Pandas之前首相要确保你已经安装了Numpy,详细的安装方法,请参考Pandas官方文档(http://pandas.pydata.org/).
(三).Pandas对象简介:
三个基本数据结构:Series,DataFrame,和Index.
1.Pandas的Series对象
1.1 Series是通用的Numpy数组
Series对象和一维Numpy数组基本可以等价交换,本质差异就是索引:
Numpy通过隐式定义的整数索引获取数值,而Series使用一种显式定义的索引与数值关联,意思就是索引不单单可以是整数,还可以是任意想要的类型,例如:字符串,浮点数等等.
data = pd.Series([0.25,0.5,0.75,1.0],index=['a','b','c','d'])
print(data)
输出结果:
a 0.25
b 0.50
c 0.75
d 1.00
dtype: float64
也可以使用不连续或者不按顺序的索引:
data = pd.Series([0.25,0.5,0.75,1.0],index=[2,5,3,7])
print(data)
输出结果:
2 0.25
5 0.50
3 0.75
7 1.00
dtype: float64
进程已结束,退出代码为 0
1.2. Series是特殊的字典
Series其实是一种将类型键映射到类型值的数据结构.
我们可以直接使用字典创建一个Series对象:
area_dict={'California':423967,'Texas':605662,'New York':141297,'Florida':170312,'Illinois':149995}
area=pd.Series(area_dict)
print(area)
输出结果:
California 423967
Texas 605662
New York 141297
Florida 170312
Illinois 149995
dtype: int64
用字典创建Series时,典型的字典数值获取方式仍然有效
print(population['California'])
1.3. 创建Series对象
上述几种创建方式都是这样的形式
pd.Series(data,index=index)
其中index是一个可选参数,data参数支持多种数据类型.
例如:data可以是一个Numpy数组
pd.Series([2,4,6])
输出结果:
0 2
1 4
2 6
dtype: int64
data也可以是一个标量,创建时会重复填充到每一个索引上:
pd.Series(5,index=[100,200,300])
输出结果:
100 5
200 5
300 5
dtype: int64
data还可以是一个字典,index默认是排序的字典键:
pd.Series({2:'a',1:'b',3:'c'})
输出结果:
2 a
1 b
3 c
dtype: object
每一种形式都可以通过显式指定索引:
pd.Series({2:'a',1:'b',3:'c'},index=[3,2])
输出结果:
3 c
2 a
dtype: object
需要注意的是,Series只会保留显式定义的键值对.
2. Pandas的DataFrame对象
Pandas的另一个基础数据结构就是Dataframe.也可以作为Numpy的一个通用类型数组,也可以看作特殊的字典.
2.1.DataFrame是通用的Numpy数组
前面我们了解到了,Series是有灵活的行索引的一维数组,那么DaraFrame就可以看做,是一种既具有灵活的行索引,还具有灵活的列名的二维数组.
population_dict={'California':38332521,'Texas':26448193,'New
York':19651127,'Florida':19552860,'Illinois':12882135}
population=pd.Series(population_dict)
area_dict={'California':423967,'Texas':605662,'New York':141297,'Florida':170312,'Illinois':149995}
area=pd.Series(area_dict)
states=pd.DataFrame({'population':population,'area':area})
print(states)
输出结果:
population area
California 38332521 423967
Texas 26448193 605662
New York 19651127 141297
Florida 19552860 170312
Illinois 12882135 149995
进程已结束,退出代码为 0
可以看到DataFrame类似于二维数组,具有列名的对象
和Series一样,DataFrame也有index属性可以获取索引标签:
print(states.index)
输出结果:
Index(['California', 'Texas', 'New York', 'Florida', 'Illinois'], dtype='object')
另外,DataFrame还有一个columns属性,是存放列标签的index对象:
print(states.columns)
输出结果:
Index(['population', 'area'], dtype='object')
2.2. DataFrame是特殊的字典
DataFrame是一种一列映射一个Series值的数据.例如:通过area可以返回包含列属性的Series对象:
print(states['area'])
输出结果:
California 423967
Texas 605662
New York 141297
Florida 170312
Illinois 149995
Name: area, dtype: int64
进程已结束,退出代码为 0
注意:在Numpy二维数组里面,data[0]是返回第一行,而DataFrame中data[‘col0’]是返回第一列
2.3.创建DataFrame对象
2.3.1通过单个Series创建.
DataFrame是多个Series对象的集合,可以用单个Series来创建一个单列的DataFrame:
population_dict={'California':38332521,'Texas':26448193,'New York':19651127,'Florida':19552860,'Illinois':12882135}
population=pd.Series(population_dict)
states=pd.DataFrame({'population':population,'area':area})
data=pd.DataFrame(population,columns=['population'])
print(data)
输出结果:
population
California 38332521
Texas 26448193
New York 19651127
Florida 19552860
Illinois 12882135
进程已结束,退出代码为 0
2.3.2 通过字典列表创建:
data=[{'a':i,'b':i*2}
for i in range(0,3)]
data01=pd.DataFrame(data)
print(data01)
输出结果:
a b
0 0 0
1 1 2
2 2 4
即使字典中的有些键不存在,Pandas也会用NaN来表示:
data=pd.DataFrame([{'a':1,'b':2},{'b':3,'c':4,'d':5}])
print(data)
输出结果:
a b c d
0 1.0 2 NaN NaN
1 NaN 3 4.0 5.0
2.3.3 还有一种就是上述2.1.所示例的创建方法.
通过Series对象构成的字典
2.3.4 通过Numpy二维数组创建.
假如有一个二维数组,就可以创建一个指定行索引的DataFrame对象,如果不指定,那么就默认是整数索引值.
data01=pd.DataFrame(np.random.rand(3,2),index=['a','b','c'],columns=['num1','num2'])
print(data01)
输出结果:
#这个是指定行索引
num1 num2
a 0.558924 0.558841
b 0.294003 0.305038
c 0.625494 0.760208
#这个是未指定行索引
num1 num2
0 0.065357 0.172990
1 0.831366 0.892077
2 0.726851 0.422833
进程已结束,退出代码为 0
2.3.5 通过Numpy结构化数组创建.
A=np.zeros(3,dtype=[('A','i8'),('B','f8')])
print(A)
a=pd.DataFrame(A)
print(a)
输出结果:
[(0, 0.) (0, 0.) (0, 0.)]
A B
0 0 0.0
1 0 0.0
2 0 0.0
进程已结束,退出代码为 0
3.Pandas的index对象
index是一个很有趣的数据结构,我们可将它看做成一个有序集合,或者不可变数组.
3.1.将index看做成一个不可变数组
index许多操作都很像数组.我们试着用一个简单的整数列表来创建一个index对象:
ind=pd.Index([2,3,5,7,11])
然后对其进行简单的数组操作:
#取值
print(ind[1])
#切片
print(ind[::2])
输出结果:
3
Int64Index([2, 5, 11], dtype='int64')
Index还有许多与数组相类似的属性:
print(ind.shape,ind.size,ind.ndim,ind.dtype)
输出结果:
(5,) 5 1 int64
Index对象与数组不同之处在于,Index对象的索引是不可变的
这个特点的好处就是,可以避免因粗心大意而修改索引值的副作用,多个DataFrame与数组之间进行索引共享时更加安全.
3.2.将Index看作有序集合
Index遵循python标准库集合用法,包括并集,交集,差集等
indA=pd.Index([1,2,3,4,5])
indB=pd.Index([3,4,5,6,7])
print(indA&indB)#交集
print(indA|indB)#并集
print(indA^indB)#差集
输出结果:
Int64Index([3, 4, 5], dtype='int64')#交集
Int64Index([1, 2, 3, 4, 5, 6, 7], dtype='int64')#并集
Int64Index([1, 2, 6, 7], dtype='int64')#差集
这些操作还可以用调用对象方法来实现例如:indA.intersection(intB)
(四)数据取值与选择
1 Series的数据选择方法
1.1把Series当作字典
和字典一样series提供了键值对的映射:
import pandas as pd
data=pd.Series([1,2,3,4],index=['a','b','c','d'])
print(data['a'])
输出结果:
1
还可以用字典的语法来调整Series
增添新的索引值来扩展Series
data['e']=5
print(data)
输出结果:
a 1
b 2
c 3
d 4
e 5
dtype: int64
进程已结束,退出代码为 0
1.2.同理也可以将Series当作一维数组
1.3. 使用索引器:loc,iloc和ix(不常用).
由于上述方法容易混淆显式索引和隐式索引,毕竟整数索引就很容易混淆
所以Pandas就提供了索引器属性.
1.3.1 第一种就是loc属性,表示取值和切片都是显式索引
import pandas as pd
data=pd.Series([1,2,3,4],index=['a','b','c','d'])
print(data.loc['a'])
print(data.loc['a':'d'])
输出结果:
1
a 1
b 2
c 3
d 4
dtype: int64
进程已结束,退出代码为 0
1.3.2第二种就是iloc属性表示都用的是隐式索引
data=pd.Series([1,2,3,4],index=['a','b','c','d'])
print(data.iloc[1])
print(data.iloc[0:3])
输出结果:
2
a 1
b 2
c 3
dtype: int64
1.3.3第三种属性就是ix
pandas版本0.20.0及其以后版本中,ix已经不被推荐使用
这个属性就是前两种属性的混合形式,我强烈建议使用前两种索引器,避免误用索引,也是自己的代码更容易理解.
2.DataFrame的数据选择方法
先用字典的形式创建一个DataFrame对象;
import pandas as pd
num01=pd.Series({'a':11,'b':22,'c':33})
num02=pd.Series({'a':1,'b':2,'c':3})
num=pd.DataFrame({'num01':num01,'num02':num02})
print(num)
输出:
num01 num02
a 11 1
b 22 2
c 33 3
2.1将DataFrame看作字典
这个和Series是一样的,不多做解释.
2.2将DataFrame理解为加强版的二维数组
这样我们就可以对它进行更多操作,例如:
转置: num.T
取单行:
print(num.values[0])
输出:
[11 1]
取单列:
print(num.num01)
输出:
a 11
b 22
c 33
Name: num01, dtype: int64
2.3使用loc,iloc
print(num.iloc[:3, :2])
print(num.loc[:'c',:'num02'])
输出:
num01 num02
a 11 1
b 22 2
c 33 3
num01 num02
a 11 1
b 22 2
c 33 3
任何一种方法都可调整数据,这一点和Numpy的常用方法是相同的:
num.iloc[0]=90
输出:
num01 num02
a 90 90
b 22 2
c 33 3
(五)Pandas数值运算方法
Pandas不仅继承了Numpy的基本运算方法,也实现了一些高效的技巧.
1.通用函数:保留索引
让我们创建一个简单的Series和DataFrame来演示:
import numpy as np
import pandas as pd
rng=np.random.RandomState(42)
ser=pd.Series(rng.randint(0,10,4))
df=pd.DataFrame(rng.randint(0,10,(3,4)),columns=['A','B','C','D'])
print(ser)
print(df)
输出;
0 6
1 3
2 7
3 4
dtype: int32
A B C D
0 6 9 2 6
1 7 4 3 7
2 7 2 5 4
进程已结束,退出代码为 0
对两个对象使用Numpy通用函数,生成的是另一个保留索引的Pandas对象:
print(np.exp(ser))
print(np.sin(df))
输出:
0 403.428793
1 20.085537
2 1096.633158
3 54.598150
dtype: float64
A B C D
0 -0.279415 0.412118 0.909297 -0.279415
1 0.656987 -0.756802 0.141120 0.656987
2 0.656987 0.909297 -0.958924 -0.756802
进程已结束,退出代码为 0
2.通用函数:索引对齐
2.1 Series索引对齐
看一个例子:假如你要整合两个数据源的数据,其中一个是美国面积最大的三个州的面积数据,另一个是美国人口最多的三个州的人口数据.
import pandas as pd
area=pd.Series({'Alasksa':1723337,'Texas':26448193,'California':21565132},name='area')
population=pd.Series({'California':3813515,'Texas':3215631,'New York':1565484},name='population')
我们试着用area除以population看看会得到什么结果:
print(area/population)
输出:
Alasksa NaN
California 5.654923
New York NaN
Texas 8.224884
dtype: float64
进程已结束,退出代码为 0
得到个两者的并集,缺失的索引Pandas会自己用NaN填充.
2.1 DataFrame索引对齐
我们先创建两个DataFrame对象:
rng=np.random.RandomState(42)
A=pd.DataFrame(rng.randint(0,20,(2,2)),columns=list('AB'))
B=pd.DataFrame(rng.randint(0,10,(3,3)),columns=list('BAC'))
print(A)
print(B)
输出:
A B
0 6 19
1 14 10
B A C
0 7 4 6
1 9 2 6
2 7 4 3
进程已结束,退出代码为 0
两者相加;
A B C
0 10.0 26.0 NaN
1 16.0 19.0 NaN
2 NaN NaN NaN
进程已结束,退出代码为 0
你会发现,即使两个对象的索引是不同顺序的,结果的索引是按照顺序排列
我们用fill_value参数自定义缺失值,这里我将用A的所有值的均值来填充缺失值:
#先将A用stack把二维压缩成一维数组再进行计算均值
fill=A.stack().mean()
C=A.add(B,fill_value=fill)
print(C)
输出:
A B C
0 10.00 26.00 18.25
1 16.00 19.00 18.25
2 16.25 19.25 15.25
进程已结束,退出代码为 0
表3-1列举了Pandas的运算方法:
3.DataFrame与Series的运算
我们经常需要对一个DataFrame和一个Series进行计算,行列式对齐方式与之前类似,也就是说,DataFrame和一个Series计算就是Numpy中的二维数组和一个一维数组进行计算.
import numpy as np
import pandas as pd
rng=np.random.RandomState(42)
A=rng.randint(10,size=(3,4))
df=pd.DataFrame(A,columns=list('QWER'))
fd=df.iloc[0,::2]
print("df:\n%s"%df)
print("fd:\n%s"%fd)
print(df-fd)
输出:
df:
Q W E R
0 6 3 7 4
1 6 9 2 6
2 7 4 3 7
fd:
Q 6
E 7
Name: 0, dtype: int32
E Q R W
0 0.0 0.0 NaN NaN
1 -5.0 0.0 NaN NaN
2 -4.0 1.0 NaN NaN
进程已结束,退出代码为 0
这些行列索引的自动对齐说明Pandas在运算时会保留这些数据内容,从而避免维度不一致时的运算错误.
(六)处理缺失值
本节涉及的处理方法有三种方式:‘null’,‘NaN’,‘NA’.
1.选择处理缺失值的方法
在数据表或者DataFrame中处理法一般分为两种:
第一种:通过覆盖全局的掩码表示缺失值
另一种:用一个标签值表示缺失值.
(一)掩码方法中:掩码可能是一个与原数组维度相同的完整布尔类型数组,也可能是用一个0或1来表示缺失值的局部状态.
(二)标签法中标签值可能是具体的数据,也可能是极少出现的形式.
使用者两种方法都先要综合考虑:
使用单独的掩码数组会额外出现一个布尔类型数组,从而增加储存于计算负担…
使用标签法缩小了可以被表示为有效值的范围可能需要在Gpu或Cpu算桉树逻辑单元中增加额外的计算逻辑,通常使用的NaN也不能表示所有数据类型.
2. Pandas的缺失值
2.1 None:Python对象类型的缺失值
由于None是Python的对象,所以它只能用作为’object’数组类型的缺失值
如果你用一个 包含None的数组进行累计运算,比如min(),sum()等,那么通常会出现类型错误.
2.2 NaN数值类型的缺失值
NaN全称为:“Not a Number”(不是一个数字),是一种按照IEEE浮点数标准射击,在任何系统中都兼容的特殊浮点数.
你可以把NaN看作是一种数据病毒,他将与它接触的数据同化,无论NaN进行何种运算,得到的结果都是NaN.
NaN是一种特殊的浮点数.
3.NaN与None的差异
虽然两者各有各的用处但是Pandas有时候会将他们看作是可以等价交换的
,在适当的时候将两者进行替换:
import numpy as np
import pandas as pd
A=pd.Series([1,np.nan,2,3,None])
print(A)
输出:
0 1.0
1 NaN
2 2.0
3 3.0
4 NaN
除了将整型数组的缺失值强制转换为浮点数,Pandas还会自动将None转换为NaN
4.处理缺失值
Pandas提供了一些方法来发现,剔除,替换数据结构中缺失值,主要包括以下几种:
isnull()创建一个布尔类型的掩码标签缺失值.
notnull()与isnull()操作相反.
dropna()返回一个剔除缺失值的数据.
fillna()返回一个填充了缺失值的数据副本.
5.层级索引
5.1多级索引Series
Pandas的MultiIndex类型提供了丰富的操作方法
我们先用元组创建一个数据-----漂亮国各个州在两个不同年份的数据:
import numpy as np
import pandas as pd
index=[('California',2000),('California',2010),
('New York',2000),('New York',2010),('Texas',2000),
('Texas',2010)]
populations=[132,12,554,234,127,232]
A=pd.Series(populations,index=index)
print(A)
输出:
(California, 2000) 132
(California, 2010) 12
(New York, 2000) 554
(New York, 2010) 234
(Texas, 2000) 127
(Texas, 2010) 232
dtype: int64
进程已结束,退出代码为 0
当我们用了多级索引后:
index=pd.MultiIndex.from_tuples(index)
A=A.reindex(index)#重置一下索引
print(A)
输出:
California 2000 132
2010 12
New York 2000 554
2010 234
Texas 2000 127
2010 232
dtype: int64
进程已结束,退出代码为 0
可以发现有些行没有了第一列数据,这个其实就是多级的表现形式,每个空格与上面的索引相同.
现在我们就可以直接使用第二列的索引来获取2010 年的所有数据,和之前的切片用法一样:
print(A[:,2010])
输出:
California 12
New York 234
Texas 232
dtype: int64
进程已结束,退出代码为 0
6.高维数据的多级索引
unstack()方法可以快速将一个多级索引的Series转化为一个普通索引的DataFrame
import numpy as np
import pandas as pd
index=[('California',2000),('California',2010),
('New York',2000),('New York',2010),('Texas',2000),
('Texas',2010)]
populations=[132,12,554,234,127,232]
A=pd.Series(populations,index=index)
index=pd.MultiIndex.from_tuples(index)
A=A.reindex(index)#重置一下索引
print(A)
A=A.unstack()
print(A)
输出:
California 2000 132
2010 12
New York 2000 554
2010 234
Texas 2000 127
2010 232
dtype: int64
2000 2010
California 132 12
New York 554 234
Texas 127 232
进程已结束,退出代码为 0
我们可以用一维的Series来表示二维的数据,那么我们就可以使用Series和DataFrame的组合来表示三维或者更高维的数据.
7,多级索引的创建方法
7.1显式地创建多级索引
你可以使用pd.Multiindex中的类方法更加灵活地构建多级索引.
例如:
B=pd.MultiIndex.from_arrays([['a','a','b','b'],[1,2,1,2]])
print(B)
输出:
MultiIndex([('a', 1),
('a', 2),
('b', 1),
('b', 2)],)
进程已结束,退出代码为 0
也可以用两个索引的笛卡尔积创建MulitiIndex:
B=pd.MultiIndex.from_product([['a','b'],[1,2]])
你也可以直接提供levels和labels.
在创建Series或者DataFrame时候可以将这些作为index参数,或通过reindex方法重置更新索引.
7.2多级索引的等级名称
你可以在前面任意一个MultiIndex构造器中通过names参数设置更改等级名称,也可以创建之后通过索引的names属性来修改名称:
import pandas as pd
index=[('California',2000),('California',2010),
('New York',2000),('New York',2010),('Texas',2000),
('Texas',2010)]
populations=[132,12,554,234,127,232]
A=pd.Series(populations,index=index)
index=pd.MultiIndex.from_tuples(index)
A=A.reindex(index)#重置一下索引
A.index.names=['pleace','age']
print(A)
输出:
pleace age
California 2000 132
2010 12
New York 2000 554
2010 234
Texas 2000 127
2010 232
在处理复杂数据的时候更改索引名字是个好办法.
7.3多级列索引
既然有多级行索引那就一定有多级列索引;
#多级行列索引
index=pd.MultiIndex.from_product([[2013,2014],[1,2]],names=['year','visit'])
columns=pd.MultiIndex.from_product([['Bob','Guido','Sue'],['HR','Temp']],names=['subject','type'])
#模拟数据
data=np.round(np.random.rand(4,6),1)
data[:,::2]*=10
data +=data
#创建DataFrame
health_data=pd.DataFrame(data,index=index,columns=columns)
print(health_data)
输出:
subject Bob Guido Sue
type HR Temp HR Temp HR Temp
year visit
2013 1 6.0 1.2 6.0 1.6 12.0 0.2
2 12.0 0.4 8.0 0.8 6.0 0.8
2014 1 8.0 0.4 8.0 0.2 6.0 1.0
2 16.0 1.4 8.0 0.4 2.0 1.0
进程已结束,退出代码为 0
上面创建了一个简易的四维数据,分别为被检查人的姓名,检查项目,检查年份,检查次数.可以在列索引第一级查询姓名,从而获取包含一个人的全部检查信息的DataFrame:
例:
print(health_data['Guido'])
输出:
type HR Temp
year visit
2013 1 18.0 0.2
2 18.0 1.2
2014 1 8.0 1.8
2 8.0 0.2
进程已结束,退出代码为 0
如果想获取包含多种标签的数据,需要通过多个维度的多次查询才能实现,这时使用多级行列索引进行查询会非常方便.