《python for data analysis》第五章,pandas的基本使用

《利用python进行数据分析》一书的第五章源码与读书笔记python

直接上代码数组

# -*- coding:utf-8 -*-# 《python for data analysis》第五章, pandas基础# 高级数据结构与操做工具import pandas as pdimport numpy as npimport timestart = time.time()# pandas的数据结构, series and dataframe# 一、series,相似一维数据, 一个字典,创建了从索引值(index)到数据值(values)的映射# 组成:一组数据(numpy的各类数据类型,称为values)+数据标签(索引,称为index)+名称(称为name,values和index均有name属性,该属性可空缺)# index缺省值为0~N-1的整数型索引,N为数据个数# 建立一个seriesnp.random.seed(10)series1 = pd.Series(np.arange(1, 6) + np.random.random(5))print(series1)  # 打印seriesprint('')print(series1.values)  # 打印series的values属性print(series1.index)  # 打印series的index属性# 修改该series的index属性,也可在一开始建立series的时候就指定index,# 即series1 = pd.Series(np.random.random(5), index=['a','aa','b','bb','z'])# 也可经过字典建立series实现相同效果# dict = {'a':1, 'aa':2, 'b':3, 'bb':4, 'z':5}# series1 = pd.Series(dict)series1.index = ['a', 'aa', 'b', 'bb', 'z']  # 三种方式效果一致print('')print(series1)print('')print(series1['aa'])  # 可经过index索引的方式选择series中的值print(series1[['a', 'aa']])  # 可一次性选取一组值,注意双括号print('')dict = {'a': 1, 'aa': 2, 'b': 3, 'bb': 4, 'z': 5}series2 = pd.Series(dict, index=['a', 'aa', 'aaa'])print(series2)  # 'a'与'aa'在dict中均有对应值,直接写入到series中,'aaa'无对应值,故用NaN表示(NaN——缺失值或NA值)# 对于多个series的运算,series在运算过程当中会自动对齐,即同一个index的数据进行运算,不是全部series都有的index的结果用NaN表示print('')print(series1 + series2)# series对象的values属性和index属性均有一个name属性,上面的series1和series2的name均缺省,可对该属性进行赋值series1.name = 'distance'  # values的name属性series1.index.name = 'city'  # index的name属性print('')print(series1)# 二、dataframe,表格型数据结构,是一组有序的列# dataframe的每一个列可视为一个series,全部列共用一个行索引(index),每一个series的name就是列索引(columns)# index和columns可经过转置进行交换# 建立一个dataframedata = {    'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],    'year': [2000, 2001, 2002, 2001, 2002],    'pop': [1.5, 1.7, 3.6, 2.4, 2.9],}dataframe = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five'])# 对于找不到的列(如'debt'),dataframe中以NaN表示该列元素,行不能够多print('')print(dataframe)# 赋值(广义的广播)dataframe['debt'] = 10.2# 经过标记方式(dataframe[])或属性方式(dataframe.)可将dataframe的某个列转换为一个series, 返回的series和dataframe有相同的行索引(index)print('')series3 = dataframe.year  # 等价于 series3 = dataframe['year']print(series3)# dataframe经过索引返回的series是原dataframe的引用,而非复制,使用.copy()方法返回的就是原数据的复制# series3[0]=20# print(dataframe)del dataframe['debt']  # 删除dataframe的某一列,只能按照列索引删除某列print(dataframe)dataframe = dataframe.T  # dataframe能够进行转置,即行索引与列索引进行互换,dataframe.T不改变原dataframe,须要赋值操做print(dataframe)# 上述的dataframe是从字典(非嵌套),配以指定行索引,获得的# 经过对嵌套字典进行dataframe()操做能够获得带有列索引与行索引的dataframe(无需指定行索引index)# 2.一、二重嵌套字典,默认之外层字典的键为列索引columns,内层字典的键为行索引indexdict = {    'cityA': {2001: 2.1, 2002: 2.5},    'cityB': {2000: 1.5, 2001: 2.9, 2002: 3.0}}dataframe2 = pd.DataFrame(dict)print(dataframe2)# 2.二、三重及以上的嵌套字典,第一层字典的键为列索引columns,第二层字典的键为index,更内层的字典保留字典形式做为dataframe的valuedict = {    'cityA': {2001: {'pop': 1.2, 'debt': 2.1}, 2002: {'pop': 1.5, 'debt': 2.5}},    'cityB': {2001: {'pop': 1.8, 'debt': 2.9}, 2002: {'pop': 1.9, 'debt': 3.0}}}dataframe3 = pd.DataFrame(dict)print(dataframe3)print('')# 三、索引对象print(series1)  # 选一个以前用过的Seriesprint(series1.index)  # 打印该Series的索引对象,包括轴标签(a\aa\b\bb\z)、轴名称、dtype等print('')print(dataframe)print(dataframe.index)print(dataframe.columns)print('')print(series1.index)print(series2.index)print(series1.index.append(series2.index))# index有不少方法,如.append能够把两个index接到一块儿。append还能够拼接Series、dataframe等print('↑----------class1----------')# pandas的基本功能# 一、从新索引, reindex# 1.一、series的reindexseries1 = pd.Series(range(5), index=['d', 'a', 'c', 'b', 'e'])print(series1)series11 = series1.reindex(['a', 'b', 'c', 'd', 'e', 'blank'])print(series11)  # 行索引按照a、b、c、d、e、blank的顺序从新排列,其中blank在原series中无value,故以NaN计入,series11 = series1.reindex(['a', 'b', 'c', 'd', 'e', 'blank'], fill_value=0)  # 用0填充NaN值print(series11)# 对于单调(monotonic)变化的index(对原index而言),还可以使用插值方法来对NaN值进行填充series1 = pd.Series(np.random.randn(3), index=[1, 3, 5])series11 = series1.reindex(range(1, 7), method='bfill')  # 取后一个值填充NaNseries111 = series1.reindex(range(1, 7), method='ffill')  # 取前一个值填充NaNprint(series11)print(series111)# 1.二、dataframe的reindex# 建立一个dataframedataframe1 = pd.DataFrame(np.arange(1, 10).reshape(3, 3), index=['one', 'three', 'two'], columns=['b', 'a', 'c'])print(dataframe1)# 只传入一个index则默认是行index的修改,对于原dataframe中没有的值以NaN写入dataframe11 = dataframe1.reindex(['one', 'two', 'three', 'four'])# 上一行等价于dataframe11 = dataframe1.reindex(index = ['one','two','three','four'])print(dataframe11)# 修改列columns须要显式指定dataframe11 = dataframe1.reindex(columns=['a', 'b', 'c'])print(dataframe11)# 也可同时修改行index和列columnsdataframe11 = dataframe1.reindex(index=['one', 'two', 'three'], columns=['a', 'b', 'c'])print(dataframe11)print('\n')# dataframe的reindex也能够指定缺失值的填充值、插值方式等# 二、丢弃指定轴(或该轴上的一些项)# 2.一、series的drop,直接向drop()函数中送入要删的元素的indexseries1 = pd.Series(range(3), index=['a', 'b', 'c'])print(series1)series2 = series1.drop('c')print(series2)# 2.二、dataframe的drop,送入的索引值须要指定轴号,0表示行索引,index;1表示列索引,columns;缺省值为0dataframe1 = dataframe1.reindex(index=['one', 'two', 'three'], columns=['a', 'b', 'c'])print(dataframe1)dataframe2 = dataframe1.drop('three')  # 等价于dataframe1.drop('three', axis = 0)print(dataframe2)dataframe2 = dataframe1.drop('c', axis=1)  # 删除columns中某项须要显示指定第二条轴print(dataframe2)print('\n')# 三、series/dataframe中values的索引、选取与过滤# 3.一、series的索引、选取与过滤print(series1)print(series1[1])  # 相似numpy的array的索引,0表示第一个元素,类推得print(series1[['a', 'b']])  # 用索引的标签值进行索引print(series1['a':'b'])  # 用索引的标签值进行切片是闭区间,而相似numpy的array索引方式是左闭右开区间print(series1[0:1])print(series1[series1 < 1])  # 布尔型索引# 3.二、dataframe的索引、选取与过滤# 3.2.1 输入dataframe的列名进行选列print(dataframe1)print(dataframe1['a'])  # 该方式(输入列名columns)只能选列,等价于print(dataframe1.a)# 3.2.2 dataframe切片选行print(dataframe1[1:2])  # 选出第2行,即左闭右开,注意!!该方式只能切片索引,不能直接输入行号或者行的位置进行索引# 3.2.3 dataframe布尔型数组选行!行print(dataframe1[dataframe1['a'] > 2])  # 选出‘a'这一列中元素大于2的行# 3.2.4 布尔型dataframe选元素print(dataframe1[dataframe1 > 3])  # 打印dataframe1中大于3的元素,打印时整张表格会输出,小于等于3的元素以NaN表示# dataframe直接索引的方式就这几种,能够看到没法经过行标签(one、two、three)进行索引# 为解决该问题,引入.ix字段,能够直接根据行标签进行选行,注意!直接输入列标签选列是不行的,毕竟已经有3.2.1了print(dataframe1.ix['one'])# .ix[]同时输入行标签、列标签进行子表的选取print(dataframe1.ix[['one', 'two'], ['a', 'b']])  # 注意顺序!!!先给出行标签再给出列标签print(dataframe1.ix[2])  # 还能够给出行的位置序号选行print('\n')# 特别对于整数索引的状况,上面这句话就会有歧义,目前规则是.ix面向标签,.irow和.icol面向位置,本章最后进行介绍# 四、算术运算与数据对齐# 两个不一样索引的对象(Series or Dataframe)进行算术运算(直接的+-*/号),结果的索引为二者的并集,但仅交集有数据,其他为NaNdataframe1 = pd.DataFrame(np.arange(1, 10).reshape(3, 3), index=['one', 'two', 'three'], columns=['a', 'b', 'c'])dataframe2 = pd.DataFrame(np.arange(-10, -1).reshape(3, 3), index=['one', 'next', 'near'], columns=['a', 'd', 'e'])print(dataframe1)print(dataframe2)print(dataframe1 + dataframe2)# 用add、sub、div、mul来替代+、-、*、/,这样能够指定一个填充值来替代缺失值print(dataframe1.add(dataframe2, fill_value=0))  # 某对标签若在两个对象中均无数值则仍未NaN# Dataframe与Series之间的运算采用广播机制# 行上广播直接采用+-*/便可series1 = dataframe1.ix['one']print(dataframe1)print(series1)print(dataframe1 - series1)# 若在列上广播则须要用add、sub、mul、div,并指定轴为0!注意,是显示指定,不能缺省。series1 = dataframe1['a']print(dataframe1)print(series1)print(dataframe1 - series1)  # 全为NaN,缘由同上,无交集print(dataframe1.sub(series1, axis=0))print('\n')# 五、函数应用与映射# numpy有一些元素级数组方法,好比abs,可直接用于pandas对象print(dataframe2)print(dataframe2.abs())# 也能够自定义一些函数,经过.apply方法应用于pandas对象的行或者列(经过axis=0 or 1进行指定)function = lambda x: x.min() - x.max()print(dataframe1)print(dataframe1.apply(function, axis=0))print(dataframe1.apply(function, axis=1))# 也能够自定义一些元素级函数,经过.applymap()方法应用于dataframe对象,经过.map()方法应用于series对象function = lambda x: x / 2print(dataframe1.applymap(function))# 六、排序与排名# 6.一、list和array的排序,对前一章的回顾np.random.seed(10)list = list(np.random.random(5))  # array方法相同print(list)list.sort()  # 也能够用list = np.sort(list)print(list)print('\n')# 6.2 pandas对象的排序,经过.sort_index()方法进行实现,按索引进行排序# 默认均为升序,降序须要显式指定ascending=Falseseries = pd.Series(np.random.random(5), index=['d', 'b', 'c', 'e', 'a'])print(series)print(series.sort_index())  # series不须要指定轴号dataframe = pd.DataFrame(np.arange(9).reshape(3, 3), columns=['b', 'c', 'a'], index=[3, 1, 2])print(dataframe)print(dataframe.sort_index())  # 缺省axis=0print(dataframe.sort_index(axis=1, ascending=False))print('\n')# 若要按照value进行排序,则series用np.sort进行,索引会被抹去,dataframe仍是用sort_index,并加入参数by指定排序的列print(series)print(np.sort(series))print(dataframe)print(dataframe.sort_index(by='a', ascending=0))  # 该方法只能进行列上的排序# by传入一个list时进行多列上的排序,list中越靠前的列排序优先级越高print('\n')# 6.三、排名,即在排序的基础上增设一个从0到数据量的排名值# 该排名值可按照必定关系改变平级关系series = pd.Series([2, 1, 2, -1, -2])print(series.rank())  # 默认给出平均排名,如2,3并列则都给出2.5print(series.rank(method='first'))  # 先出现者排名高print(series.rank(method='min'))  # 统一给出小排名,如2,3并列都给2print(series.rank(method='max'))  # 统一给出大排名,如2,3并列都给3print('\n\n')# 七、重复值的轴索引# pandas对象容许轴索引重复,不过实际使用中最好仍是避免重复,不少pandas函数是要求index不重复的# Series为例,dataframe就是行索引series = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])print(series)print(series.index.is_unique)  # pandas对象的index对象有一个is_unique属性,用于判断索引惟一与否print(series['a'])  # 会打印出全部该轴标签的valueprint('↑----------class2----------\n\n')# 汇总与计算描述统计# pandas有不少数学统计方法,如.sum()、.cumsum()、.mean()等,默认对每一列进行运算# 相较numpy中的同功能函数,numpy不容许存在数据缺失而pandas容许,并能够对缺失值进行一些基本的处理dataframe = pd.DataFrame([[1, 2, np.nan], [4, 5, 6], [7, 8, 9]], columns=['a', 'b', 'c'], index=['one', 'two', 'three'])print(dataframe)print(dataframe.sum(axis=1, skipna=True))  # 每行求和,并跳过缺失值,axis缺省0,skipna缺省Trueprint(dataframe.sum(axis=1, skipna=0))  # 不调过NaN,则全部涉及到NaN的运算结果均为NaN,同numpy的原则ar1 = np.array([1, np.nan, np.nan, np.nan, 5])print(ar1)print(ar1.sum())# dataframe的describe方法可返回一个表的汇总统计结果print(dataframe1)print(dataframe1.describe())print('')# 相关系数与协方差的计算# 补充数据拼接series1 = pd.Series(range(5), index=['day1', 'day2', 'day3', 'day4', 'day5'], name='companyA')series2 = pd.Series(sorted(range(5), reverse=True), index=['day1', 'day2', 'day3', 'day4', 'day5'], name='companyB')print(series1)print(series2)dataframe = pd.concat([series1, series2], axis=1)print(dataframe)# 用.cov()方法计算协方差,用.corr()方法计算相关系数。要求:重叠、非NA、按索引对齐# series之间的计算cov和corrprint(dataframe.companyA.cov(dataframe.companyB))print(dataframe.companyA.corr(dataframe.companyB))print('')# 单个dataframe中计算cov和corrprint(dataframe.cov())print(dataframe.corr())print('')# dataframe与series之间,dataframe与dataframe之间,用.corrwith()方法计算相关系数print(dataframe.corrwith(dataframe.companyA))  # 传入的series与dataframe的各列计算相关系数print(dataframe.corrwith(dataframe))  # 两个dataframe的列按列名进行相关系数的计算print('')# 惟一值、值计数及成员资格# 从series中抽取信息# 一、.unique()方法,获得惟一值数组,功能相似set()series = pd.Series([9, 10, 1, 1, 1, 2, 3, 2, 3, 4, 5, 6, 7, 8])print(series.unique())  # 结果是未排序的# 二、.value_counts()方法,计算series中各值出现的次数print(series.value_counts())# 补充,list相应有.count()方法计算元素出现次数list1 = [1, 2, 2, 3, 3, 3]print(list1.count(1))print(list1.count(2))# 三、.isin()方法可用于判断series中各值是否位于另外一个矢量化集合中print(series.isin([1, 2, 3]))print('↑----------class3----------\n\n')# 处理缺失数据# pandas中,python内置的None和numpy的np.nan都识别为NaN# 一、滤除缺失数据# 1.一、对于series,直接经过.dropna()方法丢弃缺失值及其索引series = pd.Series([1, 2, None, None, 3, 4, 5])print(series)print(series.dropna())# 1.二、对于dataframe,dropna()缺失为丢弃全部含有NaN的行dataframe = pd.DataFrame(np.arange(1, 10).reshape(3, 3), columns=['a', 'b', 'c'], index=['one', 'two', 'three'])dataframe.ix[1:, 1] = Nonedataframe.ix[1, :] = Noneprint(dataframe)print(dataframe.dropna())  # 有NaN就丢print(dataframe.dropna(how="all"))  # 全为NaN就丢print(dataframe.dropna(axis=1))  # 指定列上操做print(dataframe.dropna(thresh=2))  # 给定丢弃阈值,每行有2个及以上的非NaN值时保留该行# 二、填充缺失数据print(dataframe)print(dataframe.fillna(0))  # 直接用常数填充,可传入一个函数值,如dataframe.fillna(dataframe.mean()),每列平均值print(dataframe.fillna({'a': -1, 'b': -2}))  # 传入字典,按照列名进行填充,没有的则保持为NaNprint(dataframe.fillna(method='ffill'))  # 插值方法仍然有效,ffill和bfillprint('↑----------calss4-----------')# 层次化索引,用低维数据形式表示高维数据# 一、层次化索引的series,至关于一张dataframeseries = pd.Series(np.arange(9), index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c'], [1, 2, 3, 1, 2, 3, 1, 2, 3]])print(series)  # 该series的索引是层次化的(两层)print(series['a'])  # 外层索引选取的数据仍是seriesprint(series['a', 2])  # 双层索引# 经过.stack()和.unstack()能够实现层次化索引的series和dataframe之间的转换dataframe = series.unstack()print(dataframe)print(dataframe.stack())  # 又变回层次化索引的series# 二、层次化索引的dataframe,表示更高维数据,其行索引与列索引都可以层次化dataframe = pd.DataFrame(np.arange(12).reshape(-1, 3),                         columns=[['countrya', 'countrya', 'countryb'], ['citya', 'cityb', 'cityc']],                         index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]])print(dataframe)print(dataframe['countrya']['citya'].ix['a'][1])  # 先选列再选行print(dataframe.stack().stack())  # 一次.stack()把一层列索引打包到行索引上# 三、经过.swaplevel()能够交换层次化轴索引的顺序,传入轴索引namedataframe.columns.names = ['country', 'city']dataframe.index.names = ['one', 'two']print(dataframe)print(dataframe.swaplevel('city', 'country', axis=1))print('')# 四、经过.sortlevel()能够对某一个级别索引进行排序print(dataframe)print(dataframe.swaplevel().sortlevel(level=0, axis=1, ascending=False))  # 对列索引的第一级索引进行排序print('\n')# 五、对于层次化索引的pandas对象,以前提到的统计函数如sum、mean等都可指定level进行计算print(dataframe)print(dataframe.mean(axis=1, level=0))  # 对每一行在第一层索引上进行取平均# 六、用dataframe的列来看成行索引# 以前用.stack()和.unstack()方法进行了行索引与列索引之间的转换# 还能够用.set_index()和.reset_index()进行列的value与行索引标签之间的转换,相应地,列索引标签与行索引name进行转换dataframe = pd.DataFrame(np.arange(25).reshape(5, 5), columns=['a', 'b', 'c', 'd', 'e'])print(dataframe)print(dataframe.set_index(['a', 'b']))print(dataframe.set_index(['a', 'b']).reset_index(['a', 'b']))print('↑----------class5---------\n\n')# pandas的其余话题 —— 整数索引 与 panel(面板)数据# 一、整数索引,有时候会有意外状况出现dataframe = pd.DataFrame(np.arange(9).reshape(3, 3), index=[-1, 0, 1], columns=['a', 'b', 'c'])print(dataframe)print(dataframe.ix[-1])  # 或许会有疑问,这里的-1是指索引为-1呢仍是位置为-1呢?# 在pandas中,直接索引([])和.ix()方法索引,给出的值都是按照标签去进行索引# 用.irow()和.icol()方法则是按照位置去进行索引(dataframe),发现高版本pandas中已经没有.irow().icol()方法了# 这一个曾经有过教训# 事情是这样的,有一个不少行(好比1000行)的csv,我用read_csv(‘’,chunksize=100)分块读取# 想用抽样的方法对其减少体积,取100个中的前5个保存到新的csv文件中# 写为# slices = pd.read_csv('filename.csv',chunksize=100),此时索引为缺省的整数索引# for slice in slices:#       slice.ix[:5,:].to_csv('newfilename.csv',method='a') , 追加写入方式# 原本应该要看到50行,可是打开csv只看到了5行数据# 这是由于.ix[]进行索引是按照标签进行的,:5是选择了索引为0、一、二、三、4这5行,以后的切片中都没有索引为0~4的了,因此# 追加写入的都是空集# 应该修改成# for slice in slices:#       slice[:5].to_csv('newfilename.csv',method='a')# 切片选行是基于位置进行索引的# 二、panel,面板数据类型,三维版的dataframe# 一个panel由不少张dataframe组成,panel和层次化索引的dataframe之间能够经过.to_dataframe()和.to_panel()方法进行转换# 前提——dataframe的层次化索引是行索引dataframe = pd.DataFrame(np.arange(12).reshape(-1, 3),                         columns=['countrya', 'countryb', 'countryc'],                         index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]])panel = dataframe.to_panel()print(dataframe)print(panel)print(panel.ix['countrya', 'a', :])  # 索引轴依次是item、major、minor。可切片。print('\n')print("-------------that's all------------------")print('Total time is %.5f s' % (time.time() - start))