Pandas基础和应用
pandas在numpy的基础上,优化了数据结构,在数据的存储、读取、切割、转换等方面进行了改进,使操作更简单。
常用数据对象
pandas提供三种数据对象,分别是Series(保存一维类数据),DataFrame(保存二维类数据,表格)和Panel(保存三维类或可变维度数据)
Series对象
解决数组索引含义不明确的问题
Series对象有别于Numpy的ndarray对象,它显示的内容不仅包含元素,也包含索引,并且这个索引可以是有意义的
如果索引不传值,那就是位置索引,0,1,2,......
data可以是数组、列表等类数组对象,也可以数字,字符串,也可以是字典
当data是字典时,标签索引由key来充任
#index参数用来指定顺序 gdp=pd.Series({"wuhan":5225.6,"nanjing":5558.6,'hangzhou':5255.4}, index=['nanjing','hangzhou','wuhan']) print(gdp) """ nanjing 5558.6 hangzhou 5255.4 wuhan 5225.6 dtype: float64 """ #每一个series对象都有index和values两个基本属性,可以获得标签索引和值,也可以进行修改 """ Series对象具有name属性,可以对本对象进行描述 标签索引也是对象——index对象,具有name属性,可以进行描述 """ gdp.name="GDP DATA(bian de)" gdp.index.name='city' print(gdp) """ city nanjing 5558.6 hangzhou 5255.4 wuhan 5225.6 Name: GDP DATA(bian de), dtype: float64 """
DataFrame对象
使用二维数组存储表,就无法存储二维表的字段名称,所以引入DataFrame
pd.DataFrame()
主要3个参数,data,index(行索引标签),columns(列索引标签)
data可以是嵌套列表、二维数组、字典或者是DataFrame对象。字典的数据除字符串,数字等基本Python数据类型外,可以包含Series、数组等序列化类型的对象。
#data是嵌套列表 gp=pd.DataFrame([[2521.6,4222.5],[22552.5,5222.6],[53233.3,52522.6]], index=['Shanghai','nanjing','qidong'], columns=['GDP','population']) #和series一样可以给columns和index命名 gp.index.name='City' gp.columns.name='items' print(gp) """ items GDP population City Shanghai 2521.6 4222.5 nanjing 22552.5 5222.6 qidong 53233.3 52522.6 """ #data是字典,字典的key充当columns,字典的value充当具体的值 gdp=pd.DataFrame({'GDP':[2521.6,22552.5,53233.3],'Population':[4222.5,5222.6,52522.6]}, index=['Shanghai','nanjing','qidong']) #data也可以是自定义类型的数组 data=np.array([('beijing',100.00),('hubei',82.57),('shanghai',82.47)],dtype=[("city",'S30'),('marks',np.float_)]) test=pd.DataFrame(data,index=['PKU','WHU','Fudan']) print(test) """ city marks PKU b'beijing' 100.00 WHU b'hubei' 82.57 Fudan b'shanghai' 82.47 """
数据格式转换
使用pd.DataFrame.from_此类方法的作用:将某种格式的数据转换为DataFrame对象
比如:pd.DataFrame.from_dict(data,orient='columns',dtype=None) 把字典数据转换为DataFrame对象
参数orient默认为columns,意思是字典的key是列的标签索引,如果orient=‘index’,字典的key是行的标签索引
#创建的字典是{field:array_like}样式 dict_gdp={'GDP':[25522.5,52233.5,54555.3],'Population':[54423.1,55332.3,45656.7]} print(pd.DataFrame.from_dict(dict_gdp)) """ GDP Population 字典的key变为列的标签索引 0 25522.5 54423.1 1 52233.5 55332.3 2 54555.3 45656.7 """ #创建的字典是{field:dict}样式 dict_gdp1={'GDP':{'Beijing':5222.2,'Shanghai':4522.6,'chengdu':5344.6}, 'Population':{'Beijing':52354.6,'Shanghai':45633.2,'chengdu':4555.6}} print(pd.DataFrame.from_dict(dict_gdp1,orient='index')) #字典的key变为行的标签索引 """ Beijing Shanghai chengdu GDP 5222.2 4522.6 5344.6 Population 52354.6 45633.2 4555.6 """ items_gdp=dict_gdp.items() #dict_items([('GDP', [25522.5, 52233.5, 54555.3]), ('Population', [54423.1, 55332.3, 45656.7])])
逆过程:将DataFrame对象转换为其他类型的数据
dict_gdp1={'GDP':{'Beijing':5222.2,'Shanghai':4522.6,'chengdu':5344.6},
'Population':{'Beijing':52354.6,'Shanghai':45633.2,'chengdu':4555.6}}
gp=pd.DataFrame.from_dict(dict_gdp1)
"""
GDP Population
Beijing 5222.2 52354.6
Shanghai 4522.6 45633.2
chengdu 5344.6 4555.6
"""
pd.DataFrame.to_csv(gp,'D:/gp.csv')
Panel对象

上面是二维方式下展示的三维数据
三个参数
items:即axis=0,对应表格China,USA
major_axis:即axis=1,对应表格Beijing,Hong Kong,New York,Chicage
minor_axis:即axis=2,对应表格Average Temparature,Altitude
最新版本,已将Panel这个类移除
对于三维数据,我们也可以使用DataFrame对象的多级索引MultiIndex对象
索引对象
Index对象
Index对象是序列,可以看成是一维数组,跟一维数组最大的区别是不可变。Index对象是pd.Index()的实例。
ind=pd.Index(['chinese','math','english','physics']) print(pd.Series([100,98,97,95],index=ind)), """ chinese 100 math 98 english 97 physics 95 dtype: int64 """
MultiIndex对象

Nation作为第0级索引,City作为第1级索引
创建MultiIndex对象
(1)通过pd.MultiIndex.from_函数创建
#tuples接收一个列表或者类数组的方式表示的多级索引 cities_index=[('China','Beijing'),('China','HongKong'),('USA','New York'),('USA','Chicago')] cities=pd.MultiIndex.from_tuples(cities_index) """ MultiIndex([('China', 'Beijing'), ('China', 'HongKong'), ( 'USA', 'New York'), ( 'USA', 'Chicago')], ) """ city_array=[['China','China','USA','USA'],['Beijing','HongKong','New York','Chicago']] print(pd.MultiIndex.from_arrays(city_array)) #依据笛卡儿积计算MultiIndex对象 print(pd.MultiIndex.from_product([['a','b'],[100,200]])) """ MultiIndex([('a', 100), ('a', 200), ('b', 100), ('b', 200)], ) """
(2)通过pd.MultiIndex()实例化类来创建对象
注意:两个参数levels:以序列类数据表示标签索引 codes:以整数的方式表示每个标签索引的位置
mulind=pd.MultiIndex(levels=[['China','USA'],['Bejing','hongkong','new york','chincage']], codes=[[0,0,1,1],[0,1,2,3]]) """ MultiIndex([('China', 'Bejing'), ('China', 'hongkong'), ( 'USA', 'new york'), ( 'USA', 'chincage')], ) """ #通过实例化pd.Index()类创建MultiIndex对象 mulind1=pd.Index([('china','beijing'),('china','hongkong'),('USA','New York'), ('USA','Chincage')])
使用MultiIndex对象
Series对象转为DataFrame类对象:通过unstack()方法
逆过程stack()方法
gdp=pd.Series({('shanghai',2015):5452,('shanghai',2016):5423,('beijing',2015):5213,
('beijing',2016):5665,('jiangsu',2015):5432,('jiangsu',2016):5789})
"""
shanghai 2015 5452
2016 5423
beijing 2015 5213
2016 5665
jiangsu 2015 5432
2016 5789
dtype: int64
跟以往不同是字典的key,key作为Series对象的索引,它是由两个元素组成的元祖,pandas自动将两个元素处理为两级索引
"""
#pd.DataFrame()类创建多级索引,index通过嵌套列表表示多级索引
a=np.array([[20155,44212],[55234,42331],[11114,55233]
,[45522,42112],[42533,44755],[75542,45963]])
gbp1=pd.DataFrame(a,index=[['shanghai','shanghai','beijing','beijing','jiangsu','jiangsu'],
[2015,2016,2015,2016,2015,2016]],
columns=['gdp','population'])
"""
gdp population
shanghai 2015 20155 44212
2016 55234 42331
beijing 2015 11114 55233
2016 45522 42112
jiangsu 2015 42533 44755
2016 75542 45963
"""
#不用嵌套列表,直接传入MultiIndex对象
gh_mind=pd.MultiIndex.from_arrays([['shanghai','shanghai','beijing','beijing','jiangsu','jiangsu'],
[2015,2016,2015,2016,2015,2016]])
gdp2=pd.DataFrame(a,index=gh_mind,columns=['GDP','Population'])
print(gdp2)
数据索引和切片
Series对象
Series对象是类字典的对象,那么可以使用字典的一些方法进行操作
有几个注意点
①Series对象对于标签索引的切片是前包含后也包括,但数组切片是前包括后不包括
②切片切出来的是一个新的Series对象,与原来的不共用同一个视图,但数组的切片是公用同一视图
③Series对象拥有标签索引的同时,位置索引也没有失效,还是前包括,后不包括
g=np.array([1523.2,442.2,4426.6,4555.7,47563.7,789.8]) gdp=pd.Series(g,index=['shanghai','beijing','chengdu','tianjin','zhejiang','jiangsu']) """ shanghai 1523.2 beijing 442.2 chengdu 4426.6 tianjin 4555.7 zhejiang 47563.7 jiangsu 789.8 dtype: float64 """ gdp['shanghai'] #1523.2 Series对象是类字典对象 print(gdp[['shanghai','zhejiang','jiangsu']]) #还是返回一个新的Series对象,该对象与原来不共用一个视图 """ shanghai 1523.2 zhejiang 47563.7 jiangsu 789.8 dtype: float64 """ print(gdp['beijing':'tianjin']) #标签索引,前包括后也包括 """ beijing 442.2 chengdu 4426.6 tianjin 4555.7 dtype: float64 """ print(gdp[2]) #4426.6 位置索引并没有失效
为了避免标签索引和位置索引都是整数带来的混乱,采用iloc和loc
series.iloc[]只接收位置索引 series.loc[]只接收标签索引
使用在MultiIndex对象
gdp=pd.Series({('shanghai',2015):5452,('shanghai',2016):5423,('beijing',2015):5213,
('beijing',2016):5665,('jiangsu',2015):5432,('jiangsu',2016):5789})
"""
shanghai 2015 5452
2016 5423
beijing 2015 5213
2016 5665
jiangsu 2015 5432
2016 5789
dtype: int64
"""
gdp.loc['shanghai']
"""
2015 5452
2016 5423
dtype: int64
"""
gdp.iloc[0] # 5452 注意,返回的是第一个数值
#取2015年的数据
#print(gdp.iloc[2015]) #出错
print(gdp[:,2015])
"""
shanghai 5452
beijing 5213
jiangsu 5432
dtype: int64
"""
DataFrame对象
类比二维数组的索引和切片
iloc()和loc不仅适用于Series对象,也适用于DataFrame对象
#建立一个典型的DataFrame对象,它的行和列都是以MultiIndex对象为索引 mind=pd.MultiIndex.from_product([[2020,2021],[1,2]],names=['year','term']) columns=pd.MultiIndex.from_product([['zhangsan','lisi','wangwu'],['chinese','math']], names=['name','subject']) #开始生成数据 data=np.round(np.random.randn(4,6),1) #生成4行6列的二维数组,符合标准的正态分布 data=data*10+70 scores=pd.DataFrame(data,index=mind,columns=columns) """ name zhangsan lisi wangwu subject chinese math chinese math chinese math year term 2020 1 68.0 65.0 74.0 68.0 56.0 64.0 2 62.0 80.0 76.0 68.0 74.0 80.0 2021 1 75.0 67.0 88.0 57.0 81.0 70.0 2 55.0 85.0 67.0 61.0 64.0 72.0 """ #取李四的数学成绩 print(scores['lisi','math']) #使用切片,取李四的数学成绩 print(scores.loc[:,('lisi','math')]) #取两年中第一学期所有人的数学成绩 不会
文件读写操作
CSV文件
以纯文本形式保存表格数据(数字和文本)
读取csv文件:pd.read_csv()
参数解释
header:默认=0表示第一行作为列标签
names: 指定列标签内容
skiprows:忽略的行数
index_col:指定某一列或者多列作为索引
gdp=pd.read_csv('gdp-population.csv',names=['city','GDP','Pop'],skiprows=[0],index_col=0)
对于有缺失的数据,pandas会自动处理,以NaN表示
na_values 用于替换NA的值
nrows指定需要读取的行数
注:在Python中,None是一个对象,而NaN是缺失数据的标记
chunksize指定文件块的大小,返回一个TextFileReader对象
api_chunk=pd.read_csv('aqi.csv',chunksize=100,encoding='utf-8') #一次读100个记录,300多个数据共4次 tot=pd.Series([])# Series.add()方法,其中fill_value参数表示在添加前要在列表中用NaN替换的值 #city['级别']返回的是series对象,series.value_counts()计算不同值在该列中有多少数据,返回series对象 for city in api_chunk: tot=tot.add(city['级别'].value_counts(),fill_value=0) """ 中度污染 8.0 优 105.0 良 180.0 轻度污染 62.0 dtype: float64 """
HDF5文件
HDF是指一种为存储和处理大容量科学数据设计的文件格式及相应库文件。当前流行版本是HDF5
HDF5文件包含两种基本数据对象。
群组(group):类似文件夹,可以包含多个数据集或下级群组
数据集(dataset):数据内容
f=h5py.File('test.hdf5','w') #创建一个hdf5文件 d=f.create_dataset(name='/dataset1',shape=(99,99)) g=f.create_group('group1')
#在group中增加dataset d2=g.create_dataset(name='in_group1',shape=(20,)) d2.name #/group1/in_group1 #HDF5文件也是类字典对象,包括f.values() f.items() f.keys() 前面说到Series对象也可以看成类字典对象 d3=f['group1/in_group1'] # <HDF5 dataset "in_group1": shape (20,), type "<f4">
使用Pandas对此类文件进行读写
store=pd.HDFStore('data.h5') #通过HDFStore()类创建HDF5对象,安装tables包 gdp=pd.read_csv('gdp-population.csv',names=['city','GDP','Pop'],skiprows=[0],index_col=0) #读取csv数据 store['gdp']=gdp['GDP'] store['gdp_pop']=gdp print(store) print(store['gdp_pop'])
处理缺失数据
numpy中的缺失数据
a=np.array([1,2,3,None,5]) print(a.dtype) #判断其数组元素类型为object。也不能对数组a进行运算,会报错
b=np.array([1,2,3,np.nan,5]) print(b.dtype) #float64 np.nan是浮点数,这个浮点数用来标记缺失数据 print(0*np.nan) #nan,注意0*任意数不一定为0了 print(np.nansum(b)) # 11.0 numpy提供专门处理nan数据的函数
pandas处理缺失数据
s=pd.Series([1,np.nan,4,8,None,10]) """ 0 1.0 1 NaN 2 4.0 3 8.0 4 NaN 5 10.0 dtype: float64 """ s.isnull() #类似的s.notnull() """ 0 False 1 True 2 False 3 False 4 True 5 False dtype: bool """ s[s.notnull()] #用返回的对象作为下标,对原有对象进行筛选 """ 0 1.0 2 4.0 3 8.0 5 10.0 dtype: float64 """ #dropna()删除所有NaN数据,对于Series对象容易,对于DataFrame呢 df=pd.DataFrame([[1,2,np.nan,4],[5,None,7,8],[9,10,11,12]]) """ 参数讲解 axis默认=0,即删除行,如果axis=1,删除列 how默认=any,即删除有NaN的行或者列 how=all表示丢弃全为NaN的那些行或列 subset 指定删除哪几列的NaN """ df.dropna() """ 0 1 2 3 2 9 10.0 11.0 12 """ #fillna() 用某个值将数据NaN替换掉 df.fillna(-1) #与原来df不共用同一视图 """ 0 1 2 3 0 1 2.0 -1.0 4 1 5 -1.0 7.0 8 2 9 10.0 11.0 12 """ print(s.fillna(method='ffill')) #用前面的数据进行替换 method='bfill'表示用后面的数据进行替换 """ 0 1.0 1 1.0 2 4.0 3 8.0 4 8.0 5 10.0 """ #对于DataFrame对象要指定哪个轴进行前后对换 print(df.fillna(method='bfill',axis=1)) """ 0 1 2 3 0 1.0 2.0 4.0 4.0 1 5.0 7.0 7.0 8.0 2 9.0 10.0 11.0 12.0 """
规整数据
前面学习过规整数据的方法(数组的组合、分割操作),下面介绍pandas的一些方法
轴向连接
在numpy中,np.concatenate()通过axis参数实现沿所设置的轴方向连接数组。pandas提供类似的函数pd.concat()
参数介绍
objs:连接对象,必须
axis:默认为0,就是沿着0轴连接
keys:设置多级索引
join:join默认=‘outer’,取索引的并集连接 ,join='inner'表示取索引的交集
ignore_index:默认为False,如果=True,表示忽略原有索引,采用位置索引
s1=pd.Series([100,200,300],index=['a','b','c']) df1=pd.DataFrame([[110,120,130],[210,220,230],[310,320,330]]) #Series对象与DataFrame连接,自动补充NaN,并且做了类型转换 pd.concat([s1,df1]) """ 0 1 2 a 100 NaN NaN b 200 NaN NaN c 300 NaN NaN 0 110 120.0 130.0 #索引也是顺序连接的 1 210 220.0 230.0 2 310 320.0 330.0 """
df1=pd.DataFrame([[110,120,130],[210,220,230],[310,320,330]]) df1.index=['a','c','d'] df2=pd.DataFrame([[11,12,13],[21,22,23],[31,32,33]]) df2.index=['b','c','d'] pd.concat([df1,df2],axis=1) #取并集join='outer',缺失数据自动补NaN """ 0 1 2 0 1 2 a 110.0 120.0 130.0 NaN NaN NaN c 210.0 220.0 230.0 21.0 22.0 23.0 d 310.0 320.0 330.0 31.0 32.0 33.0 b NaN NaN NaN 11.0 12.0 13.0 """ pd.concat([df1,df2],axis=1,join='inner') #取交集 """ 0 1 2 0 1 2 c 210 220 230 21 22 23 d 310 320 330 31 32 33 """ #设置列的多级索引 df1.columns=['one','two','three'] df2.columns=['one','two','three'] pd.concat([df1,df2],axis=1,keys=['level1','level2'],names=['LEVEL','ROW']) pd.concat({'level1':df1,'level2':df2},names=['LEVEL',"ROW"],axis=1) #另外一种方式 """ LEVEL level1 level2 ROW one two three one two three a 110.0 120.0 130.0 NaN NaN NaN c 210.0 220.0 230.0 21.0 22.0 23.0 d 310.0 320.0 330.0 31.0 32.0 33.0 b NaN NaN NaN 11.0 12.0 13.0 """ #除了pd.concat()完成轴向连接, 还有append(),但该方法不能实现在axis=1轴上的连接 print(df1.append(df2,ignore_index=True)) # 和列表的append()的区别:这个是新生成DataFrame对象,df1的值没有变;列表中的append()是对其原地修改 """ one two three 0 110 120 130 1 210 220 230 2 310 320 330 3 11 12 13 4 21 22 23 5 31 32 33 """
合并数据
注意pd.merge()和pd.concat()区别
pd.merge()是两个对象取并集,pd.concat()是沿着某一轴将两者连接
pd.merge()是针对DataFrame而言,参数解释如下
how:默认为inner,取两个对象指定键的交集。how='outer'取并集 how='left/right'
on:指定要合并的键
left_on/right_on:从对象中选择列标签作为数据合并的键
left_index/right_index:默认为False,如果为True,则以left/right所引用对象的索引为键合并数据
indicator:默认为False,如果为True,增加_merge 列,注明每行数据的来源


除pd.merge()实现合并操作外,DataFrame实例对象的join()操作也可以
#读取数据 pop=pd.read_csv('state-population.csv') areas=pd.read_csv('state-areas.csv') abbrevs=pd.read_csv('state-abbrevs.csv') #将pop和abbrevs合并,使得每一个pop后面有国家全称 pop_merged=pd.merge(pop,abbrevs,how='left',left_on='state/region',right_on='abbreviation') #删掉重复的列 pop_merged=pop_merged.drop('abbreviation',axis=1) #检查数据是否有空的情况 pop_merged.isnull().any() """ state/region False ages False year False population True state True dtype: bool """ #看一下population记录为空的数据 pop_merged[pop_merged['population'].isnull()].head() """ state/region ages year population state 2448 PR under18 1990 NaN NaN 2449 PR total 1990 NaN NaN 2450 PR total 1991 NaN NaN 2451 PR under18 1991 NaN NaN 2452 PR total 1993 NaN NaN """ #寻找所有state为NaN的state/region的值 pop_merged.loc[pop_merged['state'].isnull(),'state/region'].unique() # ['PR' 'USA'] #说明PR和USA没有全称 pop_merged.loc[pop_merged['state/region']=='PR','state']='Puerto Rico' pop_merged.loc[pop_merged['state/region']=='USA','state']='United States' pop_merged.isnull().any() """ state/region False ages False year False population True state False dtype: bool """ #将areas也加入其中,共有的列 result=pd.merge(pop_merged,areas,on='state',how='outer') result.isnull().any() #发现area也有数据缺失 #看一下缺失的是哪些国家的面积 print(result.loc[result['area (sq. mi)'].isnull(),'state'].unique()) #['United States'] result.dropna(inplace=True) #inplace=True实现原地修改,就是不创建中间变量,将删完的数据重新分配给原始变量 result.isnull().any() #现在没有为空的记录了
组合数据
根据某个条件分别从不同的对象中选择数据,组成一个新的数据对象。
#Series对象 a=pd.Series([np.nan,2,4,np.nan,8,10]) b=pd.Series([1,2,np.nan,np.nan,5,np.nan]) b.combine_first(a) #b中缺失的数据由a来补充 """ 0 1.0 1 2.0 2 4.0 3 NaN 4 5.0 5 10.0 dtype: float64 """ #DataFrame类 df1=pd.DataFrame({'one':[11,12,np.nan,13,np.nan],'two':[np.nan,22,23,np.nan,24]}) df2=pd.DataFrame({'one':np.arange(6),'two':np.linspace(10,100,6),'three':np.logspace(2,3,6)}) print(df2.combine_first(df1)) #df1缺失的数据由df2补充,包括把缺失的行、列从df2取出来补充 """ one three two 0 0.0 100.000000 10.0 1 1.0 158.489319 28.0 2 2.0 251.188643 46.0 3 3.0 398.107171 64.0 4 4.0 630.957344 82.0 5 5.0 1000.000000 100.0 """
数据转换
行列转换
data=pd.DataFrame(np.arange(10).reshape(2,5),index=['one','two'],columns=['a','b','c','d','e']) data['e']=np.nan print(data.stack(dropna=False)) #列转为行,DataFrame对象转换为Series对象,默认dropna=True,即转换结果中没有NaN """ one a 0.0 b 1.0 c 2.0 d 3.0 e NaN two a 5.0 使用MultiIndex的Series对象 b 6.0 c 7.0 d 8.0 e NaN dtype: float64 """ print(data.stack().unstack()) #再由行转换成列 """ a b c d one 0.0 1.0 2.0 3.0 two 5.0 6.0 7.0 8.0 """
透视表
pivot()和pivot_table()区别:
pivot:无法聚合,只能重塑,如果存在重复数据将会报错;pivot_table()可以聚合,弥补了pivot的缺陷
students=pd.DataFrame({'class':['class1','class2','class1','class2'],
'subject':['physics','python','math','physics'],
'numbers':[28,30,20,80]})
#根据class数据再归类
students.pivot(index='class',columns='subject',values='numbers')
"""
subject math physics python
class
class1 20.0 28.0 NaN
class2 NaN 80.0 30.0
"""
students2=pd.DataFrame({'class':['class1','class2','class1','class2','class2'],
'subject':['physics','python','math','physics','python'],
'numbers':[28,30,20,80,99]})
#存在一个条件有两个数据的情况,所以不能使用pivot(),会报错
print(students2.pivot_table(index='class',columns='subject',values='numbers',aggfunc='sum'))
"""
subject math physics python
class
class1 20.0 28.0 NaN
class2 NaN 80.0 129.0
"""
综合运用
cnpop=pd.read_csv('cnpop.csv') #增加一个列标签,标记每行记录所处的年代 cnpop['decade']=cnpop['year']//10*10 #统计每一个年代出生率,死亡率,增长率的平均值 print(cnpop.pivot_table(index='decade',values=['birth_rate','death_rate','growth_rate'],aggfunc='mean'))
统计运算
gdp=pd.read_csv('gdp-population.csv') gdp=gdp.set_index('City_Name') gdp.mean() #pandas的实例方法,不是pandas的类方法 #默认沿着0轴方向对各列数据进行统计,参数skipna默认=True,即对于缺失的数据不计入统计范畴 """ GDP 19319.79875 Population 1828.25125 dtype: float64 """ #此对象的基本统计项目 print(gdp.describe()) """ GDP Population count 8.000000 8.000000 mean 19319.798750 1828.251250 std 4908.677545 645.654074 min 12170.200000 1137.870000 25% 17037.842500 1368.777500 50% 18688.995000 1576.940000 75% 20933.000000 2234.600000 max 27466.150000 3016.550000 """
分组运算
pandas分组(groupby)的运算过程:①split(分割) 得到分组对象 ②apply(应用) 应用分组对象的某个方法进行计算 ③combine(合并):对各组的计算结果合并
分组的键
参数by用来指明分组的键
df=pd.DataFrame({'subject':['math','physics','english','math','physics','english'],
'score':[90,80,70,95,85,75],
'teacher':['Netwon','Netwon','Pascal','Netwon','Pascal','Pascal'],
'rank':[4,5,2,9,7,5]})
df.groupby('subject').mean() #指定一列为键 数据为字符串的列不参与运算
"""
score rank
subject
english 72.5 3.5
math 92.5 6.5
physics 82.5 6.0
"""
df.groupby(['subject','teacher']).mean() #指定多列,返回具有多级索引的DataFrame对象
"""
score rank
subject teacher
english Pascal 72.5 3.5
math Netwon 92.5 6.5
physics Netwon 80.0 5.0
Pascal 85.0 7.0
"""
#分组的键可以不是数据的本身
data=pd.DataFrame(np.random.randn(6,6),columns=['a','b','c','d','e','f'],
index=['first','second','third','forth','fifth','sixth'])
lst=['one','one','one','two','two','two'] #分组的键,lst列表长度和data列标签个数一样
#lst元素和data。columns建立了一对一的对应关系,分组的键可以是上面的列表形式,也可以是字典,Series,主要是建立起映射关系
data.groupby(lst,axis=1).mean()
"""
one two
first -0.498949 -0.306100
second -0.013481 -0.886954
third 0.409185 -0.725453
forth 0.707199 0.627845
fifth 0.098086 0.672246
sixth 0.373017 -0.175056
"""
#分组的键可以是函数,自定义函数和Python内置函数
def is_t(name):
if "t" in name:
return True
else:
return False
data.groupby(is_t).mean() #注意,传递的是函数对象
"""
a b c d e f
False 0.821196 0.879802 -0.716091 0.223925 0.748068 -0.015562
True 0.440988 0.148169 0.190818 0.145825 0.404146 0.265538
"""
data.groupby(len).mean() #内置函数
"""
a b c d e f
5 -0.536603 0.064252 -0.691745 -0.166796 1.141152 -0.172374
6 -0.299885 -0.376578 -1.194604 -2.959855 1.103298 -0.398169
"""
分组对象的运算方法
下面介绍的都是分组对象的方法,他们都是以分组对象为单位进行计算
df=pd.DataFrame({'subject':['math','physics','english','math','physics','english'],
'score':[90,80,70,95,85,75],
'teacher':['Netwon','Netwon','Pascal','Netwon','Pascal','Pascal'],
'rank':[4,5,2,9,7,5]})
#1.aggregate():将若干个用于统计运算的函数聚合在一起
df.groupby('teacher').aggregate(['mean','std','max'])
"""
score rank
mean std max mean std max
teacher
Netwon 88.333333 7.637626 95 6.000000 2.645751 9
Pascal 76.666667 7.637626 85 4.666667 2.516611 7
"""
#对不同的列进行不同的运算,以字典形式建立列标签和函数的映射关系
df.groupby('teacher').aggregate({'score':['mean','max','min'],'rank':'std'})
"""
score rank
mean max min std
teacher
Netwon 88.333333 95 80 2.645751
Pascal 76.666667 85 70 2.516611
"""
#2.filter() 以分组对象为单位,若符合条件,将分组数据全部返回,不是逐条进行筛选
df.groupby('subject').filter(lambda x:x['rank'].mean()>5) #英语分组的平均值<5,所以不返回
"""
subject score teacher rank
0 math 90 Netwon 4
1 physics 80 Netwon 5
3 math 95 Netwon 9
4 physics 85 Pascal 7
"""
#3.transform() 改变原数据的值,返回值的长度和原数据相同,注意:以分组对象为单位
df.groupby('subject').transform(lambda x:x-x.mean())
"""
score rank
0 -2.5 -2.5
1 -2.5 -1.0
2 -2.5 -1.5
3 2.5 2.5
4 2.5 1.0
5 2.5 1.5
"""
#4.apply()
def rank_score(x):
x['rank_score']=x['score']*x['rank'].std() #乘的是每组rank的标准差
return x
print(df.groupby('subject').apply(rank_score)) #传入函数对象
pd.cut()方法返回category类型的对象——已经“装箱’’(划分了“类别”’)的对象
x=pd.Series([20,25,30,35,40]) bins=[10,30,40] print(pd.cut(x,bins)) """ 0 (10, 30] 1 (10, 30] 2 (10, 30] 3 (30, 40] 4 (30, 40] dtype: category Categories (2, interval[int64]): [(10, 30] < (30, 40]] """
矢量化字符串
names=['newton','hertz',None,'curie'] snames=pd.Series(names) #snames是矢量化字符串后的Series对象,和字符串有相同的方法,但功能要更强悍 snames.str.capitalize() #首字母大写 """ 0 Newton 1 Hertz 2 None 3 Curie dtype: object """ #包括进行正则表达式匹配,切片 snames.str[2] #snames.str.get(2)使用此方法同等作用 """ 0 w 1 r 2 None 3 r dtype: object """ snames.str[:4] #使用snames.str.slice(0,4)同等作用 """ 0 newt 1 hert 2 None 3 curi dtype: object """
与时间相关操作
时刻
python中提供datetime标准库来描述时刻,
pandas定义了名为Timestamp类型的对象描述时刻,并且Timestamp继承datetime
now=datetime.datetime.now() now #2021-05-20 20:50:26.034685 now.year #2021 ---------------------------------------------- now=pd.Timestamp.now() print(now) #2021-05-20 20:51:21.979260 print(now.dayofyear)#一年中的第几天 print(now.dayofweek)#本周中的第几天,周一为第0天 print(now.hour) #今天中的第几个小时 #通过以下实例化方式均可获得Timestamp对象 print(pd.Timestamp('1999.07.21')) print(pd.Timestamp(1999,7,21)) print(pd.Timestamp(datetime.datetime(1999,7,21)))
时间间隔
pandas使用Timedelta来描述时间间隔
start=pd.Timestamp('1999.07.21') now=pd.Timestamp.now() delta=now-start # 7974 days 21:04:10.931264 我已经生活了这么多天了 #一个时刻加上一个时间间隔,可以得到另外一个时刻 print(start+delta) #2021-05-20 21:06:14.506062 #通过以下实例化方式可获得Timedelta类型对象 print(pd.Timedelta(days=5,hours=6,minutes=7,seconds=8))#5 days 06:07:08 print(pd.Timedelta(seconds=123456567)) #1428 days 21:29:27
周期
pandas描述周期的对象是Period
重要参数freq,来确定周期的频率
#实例化Period对象 now_week=pd.Period.now(freq='W') #2021-05-17/2021-05-23 print(pd.Period('1999-07')) #1999-07 print(pd.Period('1999-07',freq='D')) #1999-07-01 #我们可以通过Timestamp来创建Period对象 t1=pd.Timestamp('1999.07.21') print(t1.to_period('W')) #1999-07-19/1999-07-25
比较相关模块
#datetime是python的标准库 datetime.datetime(year=1999,month=7,day=21) #1999-07-21 00:00:00 #dateutil是以datetime为基础,提供扩展功能,比如解析字符串时间 from dateutil import parser parser.parse("1999.07.21") #1999-07-21 00:00:00 #以上都是针对单个数据操作 #数据分析基础模块numpy,提供一种针对日期/时间的专有数据类型datetime64 m=np.datetime64('1999-07-21') m+np.arange(5) #体现出以datetime64为数据类型创建的数据的优势 #['1999-07-21' '1999-07-22' '1999-07-23' '1999-07-24' '1999-07-25'] #更加方便的是,pandas的Timestamp date_pd=pd.to_datetime('1999-07-21') print(date_pd) #1999-07-21 00:00:00 print(date_pd.strftime("%A")) #%A表示格式符,星期的全拼 Wednesday print(date_pd+pd.to_timedelta(np.arange(10),'D')) #'D'表示指定单位为日 """ DatetimeIndex(['1999-07-21', '1999-07-22', '1999-07-23', '1999-07-24', '1999-07-25', '1999-07-26', '1999-07-27', '1999-07-28', '1999-07-29', '1999-07-30'], dtype='datetime64[ns]', freq=None) """
时间索引
#pd.to_datetime() 如果传入一个时间对象,获得的是Timestamp对象,如果传入的是序列,则生成的是DatetimeIndex的索引对象 #同理,Period对象组成的序列就是PeriodIndex类型的索引对象 #也提供了将DatetimeIndex索引对象转换成PeriodIndex索引对象的方法 data_index=pd.to_datetime(['1999.07.21','1999.08.09','2002.06.08','2021.05.22']) #DatetimeIndex(['1999-07-21', '1999-08-09', '2002-06-08', '2021-05-22'], dtype='datetime64[ns]', freq=None) period_index=data_index.to_period('M') #参数以freq声明周期的单位 #PeriodIndex(['1999-07', '1999-08', '2002-06', '2021-05'], dtype='period[M]', freq='M') #Timedelta对应的索引对象是TimedeltaIndex delta_index=data_index-data_index[0] #TimedeltaIndex(['0 days', '19 days', '1053 days', '7976 days'], dtype='timedelta64[ns]', freq=None)
使用pd.date_range(),pd.period_range(),pd.timedelta_range()生成三种元素对象,且元素的物理量按一定规律排列
pd.date_range('1999-07','1999-09',freq='M') #freq默认为'D' #DatetimeIndex(['1999-07-31', '1999-08-31'], dtype='datetime64[ns]', freq='M') #参数periods表示生成的数量 freq可以取的值很多,用的时候去查 print(pd.timedelta_range(0,periods=6,freq='3H30T')) #3个半小时 """ TimedeltaIndex(['0 days 00:00:00', '0 days 03:30:00', '0 days 07:00:00', '0 days 10:30:00', '0 days 14:00:00', '0 days 17:30:00'], dtype='timedelta64[ns]', freq='210T') """
重采样
重采样的对象必须是DatetimeIndex,PeriodIndex或TimedeltaIndex为索引,重采样就是变更这些索引的频率
d_index=pd.date_range('2019.07.21',periods=50,freq='D') sdata=pd.Series(np.random.randn(len(d_index)),index=d_index) """ 2019-07-21 -0.287214 2019-07-22 0.564339 2019-07-23 -1.206455 ...... """ #频率从日改为月,频率降低,也叫降采样 print(sdata.resample('M',kind='period').mean()) #kind参数表示聚合的类型 """ 2019-07 -0.063128 2019-08 -0.225223 2019-09 -0.168393 Freq: M, dtype: float64 """ #直接使用下标也可以实现采用,sdate频率为日,下标为月,返回该月的全部数据 print(sdata['2019-09']) """ 2019-09-01 -1.806521 2019-09-02 -1.584223 2019-09-03 1.062668 2019-09-04 0.051151 2019-09-05 -0.653908 2019-09-06 -0.466127 2019-09-07 1.335732 2019-09-08 -0.770979 """

浙公网安备 33010602011771号