Pandas入门(实战)
Python Data Analysis Library 或 pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Python Data Analysis Library 或 pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。你很快就会发现,它是使Python成为强大而高效的数据分析环境的重要因素之一。
同时pandas还具备以下的功能:
● 具备按轴自动或显式数据对齐功能的数据结构。这可以防止许多由于数据未对齐以及来自不同数据源的数据而导致的常见错误
● 集成时间序列功能
● 即能处理时间序列数据也能处理非时间序列数据的数据结构
● 数学运算和约简可以根据不同的元数据执行
● 灵活处理缺失数据
● 合并及其他出现在常见数据库中的关系型运算
Pandas的数据结构介绍
代码运行环境:Pycharm,py3.6,numpy,pandas
Pandas主要的两个数据结构:Series与DataFrame。接下来对Series与DataFrame进行介绍。
Series
Series是一种类似于一维数组的对象,它由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即索引)组成。仅由一组数据即可产生最简单的Series
in:
import pandas as pd
from pandas import Series,DataFrame
obj = Series([1,2,3,4,5])
print(obj)
out:
0 1
1 2
2 3
3 4
4 5
dtype: int64
通过pandas导入Series和DataFrame,且Series的字符串表现形式为:左边为索引,右边为值。由于索引没有进行定义,series会自动创建一个0到N-1的整型索引。可以通过Series的values和index属性获取其数组表示形式和索引对象:
in:
print('obj.values:',obj.values,'\nobj.index:',obj.index)
out:
obj.values: [1 2 3 4 5]
obj.index: RangeIndex(start=0, stop=5, step=1)
通常会通过所创建的Series对index进行赋值,以方便对每行进行标记。
in:
obj2 = Series([1,2,3,4,5],index = ['a','b','c','d','e'])
print(obj2)
out:
a 1
b 2
c 3
d 4
e 5
dtype: int64
与普通的Numpy的数组相比,可以通过索引的方式选取Series中的单个或一组值:
in:
obj2['d'] = 6 #令第4个元素的值为6
print("obj2['a']",obj2['a'],"\nobj2['d']",obj2['d'],"\nobj2['c','a','d']",obj2[['c','a','d']])
out:
obj2['a']: 1
obj2['d']: 6
obj2['c','a','d']: c 3
a 1
d 6
Numpy数组运算(如根据布尔型数据进行过滤、标量乘法、应用数学函数等)都会保留索引和值之间的链接:
in:
print('obj2[obj2>3]:',obj2[obj2>=3])
print('obj2*2:',obj2*2)
print('np.exp(obj2):',np.exp(obj2))
out:
obj2[obj2>3]: c 3
d 6
e 5
dtype: int64
obj2*2: a 2
b 4
c 6
d 12
e 10
dtype: int64
np.exp(obj2): a 2.718282
b 7.389056
c 20.085537
d 403.428793
e 148.413159
dtype: float64
还可以将Series看成是一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用于在许多原本需要字典参数的函数中
in:
print('b' in obj2)
print('z' in obj2)
out:
True
False
对于Python中的字典来说,Series可以支持直接通过字典来创建Series
in:
sdata = {'Eirc':520,'Rick':1314,'Morty':250}
obj3 = Series(sdata)
print('obj3:',obj3)
out:
obj3: Eirc 520
Morty 250
Rick 1314
dtype: int64
如果只传入一个字典的话在Series的值中索引为原字典的键值(有序排列)
对于找不到的值NAN,pandas的isnull和notnull函数可以用于检测缺失数据:
in:
obj4 = Series([1,2,3,3,4])
obj4[3] = np.nan#np.nan可以用来创造缺失值
print('obj4:',obj4)
print('缺失值查找:',pd.isnull(obj4))
out:
obj4: 0 1.0
1 2.0
2 3.0
3 NaN
4 4.0
dtype: float64
缺失值查找: 0 False
1 False
2 False
3 True
4 False
dtype: bool
Series对象本身及其索引都有一个name属性,该属性跟pandas其他的关键功能关系非常密切:
in:
obj4.name = 'Eric'
obj4.index.name = 'Rick'
print(obj4)
out:
Rick
0 1.0
1 2.0
2 3.0
3 NaN
4 4.0
Name: Eric, dtype: float64
Series的索引可以通过赋值的方式就地修改:
in:
obj4.index =['Eirc','Bob','Rick','Morty','Tom']
print(obj4)
out:
Eirc 1.0
Bob 2.0
Rick 3.0
Morty NaN
Tom 4.0
Name: Eric, dtype: float64
DataFrame
DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以使不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(共同用一个索引)。跟其他类似的数据结构相比(R中的data.frame),DataFrame中面向行和面向列的操作基本上是平衡的。在DataFrame中的数据时以一个或多个二维块进行存放的(而不是列表、字典或别的一维数据结构)。DataFrame是以二维结构保存数据的,但是可以仍然可以轻松地将其表示为更高维度的数据。构建DataFrame的办法有很多,最常用的是一种直接传入一个由等长列表或Numpy数组组成的字典:
in:
data = {'state':['Ohio','Ohio','China','Nevada','China'],
'year':[2000,2018,2014,2002,1995],
'pop':[1.5,6.7,4.6,1.7,1.1]}
frame = DataFrame(data)
print("DataFrame:",frame)
out:
DataFrame: pop state year
0 1.5 Ohio 2000
1 6.7 Ohio 2018
2 4.6 China 2014
3 1.7 Nevada 2002
4 1.1 China 1995
结果DataFrame会自动加上索引。如果指定了列序列,则DataFrame的列就会按照指定顺序进行排列。
in:
print(DataFrame(data,columns=['year','state','pop']))
out:
year state pop
0 2000 Ohio 1.5
1 2018 Ohio 6.7
2 2014 China 4.6
3 2002 Nevada 1.7
4 1995 China 1.1
跟Series一样,如果传入的列在数据中找不到,就会产生NaN值
in:
frame2 = DataFrame(data,columns=['year','state','pop','gdp'],index = ['a','b','c','d','e'])
print("frame2:",frame2)
out:
frame2: year state pop gdp
a 2000 Ohio 1.5 NaN
b 2018 Ohio 6.7 NaN
c 2014 China 4.6 NaN
d 2002 Nevada 1.7 NaN
e 1995 China 1.1 NaN
通过类似字典标记的方式或属性的方式,可以将DataFrame的列获取为一个Series:
in:
print("frame2['state']",frame2['state'],"\nframe2.year",frame2.year)
out:
frame2['state']: a Ohio
b Ohio
c China
d Nevada
e China
Name: state, dtype: object
frame2.year: a 2000
b 2018
c 2014
d 2002
e 1995
Name: year, dtype: int64
以上返回的Series拥有原DataFrame相同的索引,且其name属性也已经被相应的设置好了。行也可以通过位置或名称的方式进行获取,比如用索引字段ix:
in:
print(frame2.ix['d'])
out:
year 2002
state Nevada
pop 1.7
gdp NaN
Name: d, dtype: object
列值可以通过赋值的方式进行修改。比如给‘gdp’列赋值上一个标量值或一组值:
in:
frame2['gdp'] = 20
print(frame2)
out:
year state pop gdp
a 2000 Ohio 1.5 20
b 2018 Ohio 6.7 20
c 2014 China 4.6 20
d 2002 Nevada 1.7 20
e 1995 China 1.1 20
in:
frame2['gdp'] = np.arange(0,2.5,.5)#第一个是起始值,第二个是终止值,第三个是间隔值的大小可以用range(x1,x2)代替
print(frame2)
out:
year state pop gdp
a 2000 Ohio 1.5 0.0
b 2018 Ohio 6.7 0.5
c 2014 China 4.6 1.0
d 2002 Nevada 1.7 1.5
e 1995 China 1.1 2.0
将列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配。如果赋值的是一个Series,就会精确匹配DataFrame的索引,所有的空位都将被填上缺失值:
in:
values = Series([1.3,2,4],index = ['a','d','c'])
frame2.gdp = values#frame2.gdp = frame2['gdp']
print(frame2)
out:
year state pop gdp
a 2000 Ohio 1.5 1.3
b 2018 Ohio 6.7 NaN
c 2014 China 4.6 4.0
d 2002 Nevada 1.7 2.0
e 1995 China 1.1 NaN
为不存在的列赋值会创建出一个新列。关键字del可以用于删除列
in:
frame2['Feiyuqing'] = frame2.state == 'China'
print(frame2)
del frame2['Feiyuqing']
print(frame2)
out:
year state pop gdp Feiyuqing
a 2000 Ohio 1.5 1.3 False
b 2018 Ohio 6.7 NaN False
c 2014 China 4.6 4.0 True
d 2002 Nevada 1.7 2.0 False
e 1995 China 1.1 NaN True
year state pop gdp
a 2000 Ohio 1.5 1.3
b 2018 Ohio 6.7 NaN
c 2014 China 4.6 4.0
d 2002 Nevada 1.7 2.0
e 1995 China 1.1 NaN
类型 | 说明 |
二维ndarray | 数据矩阵,还可以传入行标和列标 |
由数组、列表或元组组成的字典 | 每个序列会变成DataFrame的一列,所有序列的长度必须相同 |
Numpy的结构化/记录数组 | 类似于"由数组组成的字典" |
由Serie组成的字典 | 每个Series会成为一列。如果没有显式指定索引,则各Series的索引会被合并成结果的行索引 |
由字典组成的字典 | 各内层字典会成为一列。键会合并成结果的行索引,跟‘由Series组成的字典’的情况一样 |
字典或Series的列表 | 各项将会成为DataFrame的一行。字典键或Series索引的并集将会成为DataFrame的列标 |
由列表或元组组成的列表 | 类似于二维Ndarray |
另一个DataFrame | 该DataFrame的索引将会被沿用,除非显示指定了其他索引 |
Numpy的MaskedArray | 类似于“二维Ndarray”的情况,掩码值在结果中DataFrame会变成NA/缺失值 |
索引对象
pandas的索引对象负责管理轴标签和其他元数据(比如轴名称等)。构建Series或DataFrame时,所用到的任何数据或其他序列的标签都会被转换成一个index:
in:
obj = Series(range(3),index = ['a','b','c'])
index = obj.index
print(index)
print(index[1:])
out:
Index(['a', 'b', 'c'], dtype='object')
Index(['b', 'c'], dtype='object')
tips:Index对象是不可修改的, e.g : index[1] = 'd'是错误的语法
类 | 说明 |
Index | 最泛化的index对象,将轴标签表示为一个由Python对象组成的Numpy数组 |
int64Index | 针对整数的特殊index |
MulitiIndex | ‘层次化’索引对象,表示单个轴上的多层索引,可以看做由元组组成的数组 |
DatatimeIndex | 存储纳秒级时间戳 |
PeriodIndex | 针对Period数据的特殊Index |
每个索引都有一些方法和属性,它们可以用于设置逻辑并回答有关该索引所包含的数据的常见问题。具体见下表
方法 | 说明 |
append | 连接另一个Index对象,产生一个新的Index |
diff | 计算差集,并得到一个index |
intersection | 计算交集 |
unicon | 计算并集 |
isin | 计算一个指示搁置是否都包含在参数集合中的布尔型函数 |
delete | 删除所有i处的元素,且得到新的index |
drop | 删除传入的值,且得到新的index |
insert | 将元素插入到索引i出,且得到新的index |
is_monotonic | 当各元素均大于等于前一个元素时,返回True |
is_unique | 当index没有重复值时,返回True |
unique | 计算index中的唯一值的数组 |
基本功能
重新索引
pandas对象的一个重要方法是reindex,其作用是是创建一个适应新索引的新对象。调用Series的reindex会根据新索引进行重排。如某个索引的值当前不存在于,则引入缺失值
in:
obj = Series([4.1,-2.1,3.5],index = ['d','a','c'])
obj2 = obj.reindex(['a','b','c','d','e'])
print('obj:',obj,'\nobj2:',obj2)
out:
obj: d 4.1
a -2.1
c 3.5
dtype: float64
obj2: a -2.1
b NaN
c 3.5
d 4.1
e NaN
dtype: float64
参数 | 说明 |
index | 用作索引的新序列。可以为index实例 ,也可以是其他序列型的Python数据结构。index会被完全使用 |
method | 插值(填充)方式,ffill/pad(前向填充值),bfill/backfill(后向填充值) |
fill_value | 在重新索引的过程中,需要引入缺失值时使用的替代值 |
limit | 前向或后向填充时的最多填充量 |
level | 在MultiIndex的指定级上匹配简单索引,否则选取其子集 |
copy | 默认为True,无论如何复制;False,则新旧相等就不复制 |
in:
obj = Series(range(3),index = ['a','b','c'])
obj2 = obj.reindex(['a','b','c','d','e','f','g'],fill_value=100)
print('obj2:',obj2)
out:
obj2: a -2.1
b 100.0
c 3.5
d 4.1
e 100.0
f 100.0
g 100.0
dtype: float64
丢弃指定轴上的项
丢弃某条轴上的一个或多个项很简单,只要有一个索引数组或列表即可。由于需要执行一些数据整理和集合逻辑,所以drop方法返回的是一个指定轴上删除了指定值的新对象。
in:
obj = Series(np.arange(4),index = ['a','b','c','d'])
print('obj:',obj)
obj = obj.drop(['a','c'])
print("obj:",obj)
out:
obj: a 0
b 1
c 2
d 3
dtype: int32
obj: b 1
d 3
dtype: int32
对于DataFrame一样的可以进行删除任意轴上的索引值
in:
data = DataFrame(np.arange(12).reshape((3,4)),index = ['a','b','c'],columns = ['one','two','three','four'])
print("data.drop(['a','c']):",data.drop(['a','c']),"\ndata.drop(['one','three'],axis = 1):",data.drop(['one','three'],axis = 1))
out:
data.drop(['a','c']): one two three four
b 4 5 6 7
data.drop(['one','three'],axis = 1): two four
a 1 3
b 5 7
c 9 11
索引、选取和过滤
对于Series索引的工作方式类似于NumPy数组的索引,且对于DataFrame进行索引其实就是获取一个或者多个列,在对数据的操作中最根本的就是对数据进行选取、过滤来获得你所需要的数据集。为了在DataFrame上进行标签索引,我们将会引入专门的索引字段ix。其作用可以通过Numpy式的标记法以及轴标签选取行和列的子集。
in:
data = DataFrame(np.arange(16).reshape((4,4)),index = ['a','b','c','e'],columns = ['one','two','three','four'])
print('data:',data)
print("data[['four','one']]:",data[['four','one']])
print("data[:2]:",data[:2])
print("data[data<5]:",data[data<5])
print("data[:,:2]:",data.ix[2:4,:3])
print("data.ix[data.two>5,:3]:",data.ix[data.two>5,:3])
print("data.ix['a',['one','four']]:",data.ix['a',['one','four']])
out:
data: one two three four
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
e 12 13 14 15
data[['four','one']]: four one
a 3 0
b 7 4
c 11 8
e 15 12
data[:2]: one two three four
a 0 1 2 3
b 4 5 6 7
data[data<5]: one two three four
a 0.0 1.0 2.0 3.0
b 4.0 NaN NaN NaN
c NaN NaN NaN NaN
e NaN NaN NaN NaN
data[:,:2]: one two three
c 8 9 10
e 12 13 14
data.ix[data.two>5,:3]: one two three
c 8 9 10
e 12 13 14
data.ix['a',['one','four']]: one 0
four 3
Name: a, dtype: int32
也就是说,对pandas对象中的数据的选取和重排的方式很多。下表会简单的总结了针对DataFrame数据的大部分选取和重排方式。在使用层次化索引时还能用到一些别的方法。
类型 | 说明 |
obj[val] | 选取DataFrame的单个列或一组列。在一些特殊情况下会比较便 利:布尔型数组,切片,布尔型DataFrame |
obj.ix[val] | 选取DataFrame的单个行或一组行 |
obj.ix[:,val] | 选取单个列或列子集 |
obj.ix[var1,var2] | 同时选取行和列 |
reindex方法 | 将一个或多个轴匹配到新索引 |
xs方法 | 根据标签选取单列或单行、且返回一个Series |
icol、irow方法 | 根据整数位置选取单列或单行,且返回一个Series |
get_value/set_value | 根据行标签和列标签选取单个值 |
函数应用和映射
在Pandas中的函数应用一般使用lambda的方式来建立简单的运算函数,也可以通过def的形式来定义函数,而要运用到DataFrame中则需要使用的apply方法,通过apply将函数应用到由各行或列所形成的一维数组上。
in:
data = DataFrame(np.arange(16).reshape((4,4)),index = ['a','b','c','e'],columns = ['one','two','three','four'])
f = lambda x:x.max() - x.min()
def f1(x):
return x.max()-x.min()
print("data:",data)
print("data.apply(f):",data.apply(f))
print("data.apply(f,axis = 1):",data.apply(f,axis = 1))
print("data.apply(f1):",data.apply(f1))
out:
data: one two three four
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
e 12 13 14 15
data.apply(f): one 12
two 12
three 12
four 12
dtype: int64
data.apply(f,axis = 1): a 3
b 3
c 3
e 3
dtype: int64
data.apply(f1): one 12
two 12
three 12
four 12
dtype: int64
在Series中有一个可以运用到元素级上的函数叫做map,map方法可以接受一个函数或含有映射关系的字典型对象。
in:
data['K'] = data['one'].map({0:'Eric',4:'Rick',8:'Morty'})
print("data:",data)
out:
data: one two three four K
a 0 1 2 3 Eric
b 4 5 6 7 Rick
c 8 9 10 11 Morty
e 12 13 14 15 NaN
排序和排名
根据条件对数据集排序是一种重要的内置运算,可用于处理需要获得排序数据的数据集问题。要对行或列索引进行排序(按字典排序),可使用sort_index的方法,它将返回一个已排序后的新对象,数据默认是按升序排序的,如果需要降序的可以通过在函数中使用ascending = False,若是Series按值排序的话可以使用order方法。在对值排序的时候也可使用sort_valuesd进行排序,但在多列数据框的情况下需要通过by来选取需要排序的列在排序的时候任何缺失值都会放在末尾。
in:
frame = DataFrame(np.arange(8).reshape((2,4)),index = ['two','one'],columns = ['d','a','c','b'])
print("frame.sort_index():",frame.sort_index())
print("frame.sort_index(axis = 1):",frame.sort_index(axis = 1) )
print("frame.sort_values(by = ['c']):",frame.sort_values(by = ['c']))
out:
frame.sort_index(): d a c b
one 4 5 6 7
two 0 1 2 3
frame.sort_index(axis = 1): a b c d
two 1 3 2 0
one 5 7 6 4
frame.sort_values(): d a c b
two 0 1 2 3
one 4 5 6 7
汇总和计算描述统计
pandas对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值(如sum和mean)或从DataFrame的行或列中提取一个Series。跟对应的Numpy的数组方法相比,它们都是基于没有缺失数据的假设而构建的。
in:
df = DataFrame([[1.4,np.nan],[7.5,-4.3],[np.nan,np.nan],[0.73,-0.113]],index = ['a','b','c','d'],columns = ['one','two'])
print("df:",df)
print("df.sum():",df.sum())
print("df.sum(axis =1):",df.sum(axis = 1))
print("df.mean(axis = 1):",df.mean(axis = 1))
out:
df: one two
a 1.40 NaN
b 7.50 -4.300
c NaN NaN
d 0.73 -0.113
df.sum(): one 9.630
two -4.413
dtype: float64
df.sum(axis =1): a 1.400
b 3.200
c NaN
d 0.617
dtype: float64
df.mean(axis = 1): a 1.4000
b 1.6000
c NaN
d 0.3085
dtype: float64
方法 | 说明 |
count | 非NA值的数量 |
describe | 针对Series或各DataFrame列计算汇总统计 |
min、max | 计算最小值和最大值 |
argmin、argmax | 计算能够获取的到最小值和最大值的索引位置 |
idxmin、idxmax | 计算能够获取到最小值和最大值的索引值 |
quantile | 计算样本的分位数(0到1) |
sum | 值的总和 |
mean | 值的平均数 |
median | 值的算术平均数 |
mad | 根据平均值计算平均绝对离差 |
var | 样本值的方差 |
std | 样本值的标准差 |
skew | 样本值的偏度(三阶矩) |
kurt | 样本值的峰度(四阶矩) |
cumsum | 样本值的累计和 |
cummin、cummax | 样本值的累计最大值和累计最小值 |
cumprod | 样本值的累计积 |
diff | 计算一阶差分(对时间序列很有用) |
pct_change | 计算百分数变化 |
处理缺失数据
缺失数据在大部分数据分析应用中都很常见。且pandas上所有的描述统计都排除了缺失数据。而且使用浮点值NaN表示浮点和非浮点数组中的缺失数据,是一种用于方便检测的标记。
in:
string_data = Series(['a','b',np.nan,'c','d'])
print("string_data.isnull():",string_data.isnull())
data = DataFrame(np.arange(16).reshape(4,4))
data.ix[2,3] = np.nan
print("data.isnull():",data.isnull())
out:
string_data.isnull(): 0 False
1 False
2 True
3 False
4 False
dtype: bool
data.isnull(): 0 1 2 3
0 False False False False
1 False False False False
2 False False False True
3 False False False False
方法 | 说明 |
dropna | 根据各标签的值中是否存在缺失数据对轴标签进行过滤,可通过调节阔值来决定缺失值的容忍度 |
fillna | 用指定值或插值方法(如ffill或bfill)填充缺失数据 |
isnull | 返回一个含有布尔值的对象,这些布尔值表示那些值是缺失值NA,该对象的类型与源类型一样 |
notnul | isnull的否定式 |
in:
print("data.fillna(0):",data.fillna(0))
print("data.fillna(data.mean()):",data.fillna(data.mean()))
print("data.dropna()",data.dropna())
out:
data.fillna(0): 0 1 2 3
0 0 1 2 3.0
1 4 5 6 7.0
2 8 9 10 0.0
3 12 13 14 15.0
data.fillna(data.mean()): 0 1 2 3
0 0 1 2 3.000000
1 4 5 6 7.000000
2 8 9 10 8.333333
3 12 13 14 15.000000
data.dropna() 0 1 2 3
0 0 1 2 3.0
1 4 5 6 7.0
3 12 13 14 15.0