《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))
相關文章
相關標籤/搜索