在入門教程中,咱們已經使用過訪問數據的方法。這裏咱們再集中看一下。html
注:這裏的數據訪問方法既適用於Series,也適用於DataFrame。python
這是兩種最直觀的方法,任何有面向對象編程經驗的人應該都很容易理解。下面是一個代碼示例:git
# select_data.py import pandas **as** pd import numpy **as** np series1= pd.Series([1, 2, 3, 4, 5, 6, 7], index=["C", "D", "E", "F", "G", "A", "B"]) print("series1['E'] = {} \n".format(series1['E'])); print("series1.E = {} \n".format(series1.E));
這段代碼輸出以下:github
series1['E']= 3 series1.E= 3
注1:對於相似屬性的訪問方式.來講,要求索引元素必須是有效的Python標識符的時候才能夠,而對於series1.1這樣的索引是不行的。編程
注2:[]和.提供了簡單和快速訪問pands數據結構的方法。這種方法很是的直觀。然而,因爲要訪問的數據類型並非事先知道的,所以使用這兩種方法方式存在一些優化限制。所以對於產品級的代碼來講,pandas官方建議使用pandas庫中提供的數據訪問方法。數組
在入門教程中,咱們已經提到了這兩個操做符:數據結構
loc:經過行和列的索引來訪問數據app
iloc:經過行和列的下標來訪問數據dom
注意:索引的類型多是整數。機器學習
實際上,當DataFrame經過這兩個操做符訪問數據,能夠只指定一個索引來訪問一行的數據,例如:
# select_data.py df1= pd.DataFrame({"note": ["C", "D", "E", "F", "G", "A", "B"], "weekday": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]}, index=['1', '2', '3', '4', '5', '6', '7']) print("df1.loc['2']:\n{}\n".format(df1.loc['2']))
這裏經過索引'2'能夠方法到第2行的全部數據,所以它的輸出以下:
df1.loc['2']: note D weekday Tue Name: 2, dtype: **object**
除此以外,經過這兩個操做符咱們還能夠訪問某個範圍以內的數據,例如這樣:
# select_data.py print("series1.loc['E':'A']=\n{}\n".format(series1.loc['E':'A'])); print("df1.iloc[2:4]=\n{}\n".format(df1.iloc[2:4]))
這段代碼輸出以下:
series1.loc['E':'A']= E 3 F 4 G 5 A 6 dtype: int64 df1.iloc[2:3]= note weekday 3 E Wed 4 F Thu
這兩個操做符用來訪問單個的元素值(Scalar Value)。相似的:
· at:經過行和列的索引來訪問數據
· iat:經過行和列的下標來訪問數據
# select_data.py print("series1.at['E']={}\n".format(series1.at['E'])); print("df1.iloc[4,1]={}\n".format(df1.iloc[4,1]))
這兩行代碼輸出以下:
series1.at['E']=3 df1.iloc[4,1]=Fri
在入門教程咱們也已經簡單介紹過Index,Index提供了查找,數據對齊和從新索引所需的基礎數據結構。 最直接的,咱們能夠經過一個數組來建立Index對象。在建立的同時咱們還能夠經過name指定索引的名稱:
# index.py index= pd.Index(['C','D','E','F','G','A','B'], name='note')
Index類提供了不少的方法進行各類操做,這個建議讀者直接查詢API說明便可,這裏很少作說明。稍微提一下的是,Index對象能夠互相之間作集合操做,例如:
# index.py a= pd.Index([1,2,3,4,5]) b= pd.Index([3,4,5,6,7]) print("a|b = {}\n".format(a|b)) print("a&b = {}\n".format(a&b)) print("a.difference(b) = {}\n".format(a.difference(b)))
這幾個運算的結果以下:
a|b= Int64Index([1, 2, 3, 4, 5, 6, 7], dtype='int64') a&b= Int64Index([3, 4, 5], dtype='int64') a.difference(b)= Int64Index([1, 2], dtype='int64')
Index類有不少的子類,下面是最多見的一些:
MultiIndex,或者稱之爲Hierarchical Index是指數據的行或者列經過多層次的標籤來進行索引。 例如,咱們要經過一個MultiIndex描述三個公司在三年內每一個季度的營業額,能夠這樣:
# multiindex.py import pandas **as** pd import numpy **as** np multiIndex= pd.MultiIndex.from_arrays([ ['Geagle', 'Geagle', 'Geagle', 'Geagle', 'Epple', 'Epple', 'Epple', 'Epple', 'Macrosoft', 'Macrosoft', 'Macrosoft', 'Macrosoft', ], ['S1', 'S2', 'S3', 'S4', 'S1', 'S2', 'S3', 'S4', 'S1', 'S2', 'S3', 'S4']], names=('Company', 'Turnover'))
這段代碼輸出以下:
multiIndex = MultiIndex(levels=[['Epple', 'Geagle', 'Macrosoft'], ['S1', 'S2', 'S3', 'S4']], labels=[[1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2], [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]], names=['Company', 'Turnover'])
從這個輸出能夠看出,MultiIndex中的levels數組數量對應了索引的級別數量,labels對應了levels中元素的下標。 下面咱們用一個隨機數來構造一個DataFrame:
# multiindex.py df= pd.DataFrame(data=np.random.randint(0, 1000, 36).reshape(-1, 12), index=[2016, 2017, 2018], columns=multiIndex) print("df = \n{}\n".format(df))
這裏建立出了36個[0, 1000)之間的隨機數,而後組裝成3行12列的矩陣(若是你對NumPy不熟悉能夠訪問NumPy官網學習,或者看一下我以前寫過的:Python 機器學習庫 NumPy 教程)。 上面這段代碼輸出以下:
df = Company Geagle Epple Macrosoft Turnover S1 S2 S3 S4 S1 S2 S3 S4 S1 S2 S3 S4 2016 329 25 553 852 833 710 247 990 215 991 535 846 2017 734 368 28 161 187 444 901 858 244 915 261 485 2018 769 707 458 782 948 169 927 237 279 438 738 708
這個輸出很直觀的能夠看出三個公司在三年內每一個季度的營業額。 有了多級索引,咱們能夠方便的進行數據的篩選,例如:
經過df.loc[2017, (['Geagle', 'Epple', 'Macrosoft'] ,'S1')])篩選出三個公司2017年第一季度的營業額
經過df.loc[2018, 'Geagle']篩選出Geagle公司2018年每一個季度的營業額
它們輸出以下:
2017 S1: Company Turnover Geagle S1 734 Epple S1 187 Macrosoft S1 244 Name: 2017, dtype: int64 Geagle 2018: Turnover S1 769 S2 707 S3 458 S4 782 Name: 2018, dtype: int64
Concat(enate):串聯,鏈接,級連
Append:附加,增補
Merge:融合,歸併,合併
Join:合併,接合,交接
concat函數的做用是將多個數據串聯到一塊兒。例如,某個多條數據分散在3個地方記錄,最後咱們將三個數據添加到一塊兒。下面是一個代碼示例:
# concat_append.py import pandas **as** pd import numpy **as** np df1= pd.DataFrame({'Note': ['C', 'D'], 'Weekday': ['Mon', 'Tue']}, index=[1, 2]) df2= pd.DataFrame({'Note': ['E', 'F'], 'Weekday': ['Wed', 'Thu']}, index=[3, 4]) df3= pd.DataFrame({'Note': ['G', 'A', 'B'], 'Weekday': ['Fri', 'Sat', 'Sun']}, index=[5, 6, 7]) df_concat= pd.concat([df1, df2, df3], keys=['df1', 'df2', 'df3']) print("df_concat=\n{}\n".format(df_concat))
這裏咱們經過keys指定了三個數據的索引劃分,最後的數據中會由此存在MultiIndex。這段代碼輸出以下:
df_concat= Note Weekday df1 1 C Mon 2 D Tue df2 3 E Wed 4 F Thu df3 5 G Fri 6 A Sat 7 B Sun
請仔細思考一下df_concat結構與原先三個數據結構的關係:其實它就是將原先三個數據縱向串聯起來了。另外,請關注一下MultiIndex結構。 concat函數默認是以axis=0(行)爲主進行串聯。若是須要,咱們能夠指定axis=1(列)爲主進行串聯:
# concat_append.py df_concat_column= pd.concat([df1, df2, df3], axis=1) print("df_concat_column=\n{}\n".format(df_concat_column))
這個結構輸出以下:
df_concat_column= Note Weekday Note Weekday Note Weekday 1 C Mon NaN NaN NaN NaN 2 D Tue NaN NaN NaN NaN 3 NaN NaN E Wed NaN NaN 4 NaN NaN F Thu NaN NaN 5 NaN NaN NaN NaN G Fri 6 NaN NaN NaN NaN A Sat 7 NaN NaN NaN NaN B Sun
請再次觀察一下這裏的結果和原先三個數據結構之間的關係。 concat是將多個數據串聯在一塊兒。相似的,對於某個具體的數據來講,咱們能夠在其數據基礎上添加(append)其餘數據來進行串聯:
# concat_append.py df_append= df1.append([df2, df3]) print("df_append=\n{}\n".format(df_append))
這個操做的結果和以前的concat是同樣的:
df_append= Note Weekday 1 C Mon 2 D Tue 3 E Wed 4 F Thu 5 G Fri 6 A Sat 7 B Sun
pandas中的Merge操做和SQL語句中的Join操做是相似的。Join操做能夠分爲下面幾種:
· INNER
· LEFT OUTER
· RIGHT OUTER
· FULL OUTER
· CROSS
關於這幾種的Join操做的含義請參閱其餘資料,例如維基百科:Join (SQL)。 使用pandas進行Merge操做很簡單,下面是一段代碼示例:
# merge_join.py import pandas **as** pd import numpy **as** np df1= pd.DataFrame({'key': ['K1', 'K2', 'K3', 'K4'], 'A': ['A1', 'A2', 'A3', 'A8'], 'B': ['B1', 'B2', 'B3', 'B8']}) df2= pd.DataFrame({'key': ['K3', 'K4', 'K5', 'K6'], 'A': ['A3', 'A4', 'A5', 'A6'], 'B': ['B3', 'B4', 'B5', 'B6']}) print("df1=n{}n".format(df1)) print("df2=n{}n".format(df2)) merge_df= pd.merge(df1, df2) merge_inner= pd.merge(df1, df2, how='inner', on=['key']) merge_left= pd.merge(df1, df2, how='left') merge_left_on_key= pd.merge(df1, df2, how='left', on=['key']) merge_right_on_key= pd.merge(df1, df2, how='right', on=['key']) merge_outer= pd.merge(df1, df2, how='outer', on=['key']) print("merge_df=\n{}\n".format(merge_df)) print("merge_inner=\n{}\n".format(merge_inner)) print("merge_left=\n{}\n".format(merge_left)) print("merge_left_on_key=\n{}\n".format(merge_left_on_key)) print("merge_right_on_key=\n{}\n".format(merge_right_on_key)) print("merge_outer=\n{}\n".format(merge_outer))
這段代碼說明以下:
merge函數的join參數的默認值是「inner」,所以merge_df是兩個數據的inner join的結果。另外,在不指明的狀況下,merge函數使用全部同名的列名做爲key來進行運算。
merge_inner是指定了列的名稱進行inner join。
merge_left是left outer join的結果
merge_left_on_key是指定了列名進行left outer join的結果
merge_right_on_key是指定了列名進行right outer join的結果
merge_outer是full outer join的結果
這裏的結果以下,請觀察一下結果與你的預算是否一致:
df1= A B key 0 A1 B1 K1 1 A2 B2 K2 2 A3 B3 K3 3 A8 B8 K4 df2= A B key 0 A3 B3 K3 1 A4 B4 K4 2 A5 B5 K5 3 A6 B6 K6 merge_df= A B key 0 A3 B3 K3 merge_inner= A_x B_x key A_y B_y 0 A3 B3 K3 A3 B3 1 A8 B8 K4 A4 B4 merge_left= A B key 0 A1 B1 K1 1 A2 B2 K2 2 A3 B3 K3 3 A8 B8 K4 merge_left_on_key= A_x B_x key A_y B_y 0 A1 B1 K1 NaN NaN 1 A2 B2 K2 NaN NaN 2 A3 B3 K3 A3 B3 3 A8 B8 K4 A4 B4 merge_right_on_key= A_x B_x key A_y B_y 0 A3 B3 K3 A3 B3 1 A8 B8 K4 A4 B4 2 NaN NaN K5 A5 B5 3 NaN NaN K6 A6 B6 merge_outer= A_x B_x key A_y B_y 0 A1 B1 K1 NaN NaN 1 A2 B2 K2 NaN NaN 2 A3 B3 K3 A3 B3 3 A8 B8 K4 A4 B4 4 NaN NaN K5 A5 B5 5 NaN NaN K6 A6 B6
DataFrame也提供了join函數來根據索引進行數據合併。它能夠被用於合併多個DataFrame,這些DataFrame有相同的或者相似的索引,可是沒有重複的列名。默認狀況下,join函數執行left join。另外,假設兩個數據有相同的列名,咱們能夠經過lsuffix和rsuffix來指定結果中列名的前綴。下面是一段代碼示例:
# merge_join.py df3= pd.DataFrame({'key': ['K1', 'K2', 'K3', 'K4'], 'A': ['A1', 'A2', 'A3', 'A8'], 'B': ['B1', 'B2', 'B3', 'B8']}, index=[0, 1, 2, 3]) df4= pd.DataFrame({'key': ['K3', 'K4', 'K5', 'K6'], 'C': ['A3', 'A4', 'A5', 'A6'], 'D': ['B3', 'B4', 'B5', 'B6']}, index=[1, 2, 3, 4]) print("df3=\n{}\n".format(df3)) print("df4=\n{}\n".format(df4)) join_df= df3.join(df4, lsuffix='_self', rsuffix='_other') join_left= df3.join(df4, how='left', lsuffix='_self', rsuffix='_other') join_right= df1.join(df4, how='outer', lsuffix='_self', rsuffix='_other') print("join_df=\n{}\n".format(join_df)) print("join_left=\n{}\n".format(join_left)) print("join_right=\n{}\n".format(join_right))
這段代碼輸出以下:
df3= A B key 0 A1 B1 K1 1 A2 B2 K2 2 A3 B3 K3 3 A8 B8 K4 df4= C D key 1 A3 B3 K3 2 A4 B4 K4 3 A5 B5 K5 4 A6 B6 K6 join_df= A B key_self C D key_other 0 A1 B1 K1 NaN NaN NaN 1 A2 B2 K2 A3 B3 K3 2 A3 B3 K3 A4 B4 K4 3 A8 B8 K4 A5 B5 K5 join_left= A B key_self C D key_other 0 A1 B1 K1 NaN NaN NaN 1 A2 B2 K2 A3 B3 K3 2 A3 B3 K3 A4 B4 K4 3 A8 B8 K4 A5 B5 K5 join_right= A B key_self C D key_other 0 A1 B1 K1 NaN NaN NaN 1 A2 B2 K2 A3 B3 K3 2 A3 B3 K3 A4 B4 K4 3 A8 B8 K4 A5 B5 K5 4 NaN NaN NaN A6 B6 K6
不少時候,咱們會須要對批量的數據進行分組統計或者再處理,groupby,agg,apply就是用來作這件事的。
groupby將數據分組,分組後獲得pandas.core.groupby.DataFrameGroupBy類型的數據。
agg用來進行合計操做,agg是aggregate的別名。
apply用來將函數func分組化並將結果組合在一塊兒。
這些概念都很抽象,咱們仍是經過代碼來進行說明。
# groupby.py import pandas **as** pd import numpy **as** np df= pd.DataFrame({ 'Name': ['A','A','A','B','B','B','C','C','C'], 'Data': np.random.randint(0, 100, 9)}) print('df=\n{}\n'.format(df)) groupby= df.groupby('Name') print("Print GroupBy:") **for** name, group **in** groupby: print("Name: {}\nGroup:\n{}\n".format(name, group))
在這段代碼中,咱們生成了9個[0, 100)之間的隨機數,數據的第一列是['A','A','A','B','B','B','C','C','C']。而後咱們以Name列進行groupby,獲得的結果會根據將Name列值同樣的分組在一塊兒,咱們將獲得的結果進行了打印。這段代碼的輸出以下:
df= Data Name 0 34 A 1 44 A 2 57 A 3 81 B 4 78 B 5 65 B 6 73 C 7 16 C 8 1 C Print GroupBy: Name: A Group: Data Name 0 34 A 1 44 A 2 57 A Name: B Group: Data Name 3 81 B 4 78 B 5 65 B Name: C Group: Data Name 6 73 C 7 16 C 8 1 C
groupby並非咱們的最終目的,咱們的目的是但願分組後還要對這些數據進行進一步的統計或者處理。pandas庫自己就提供了不少進行操做的函數,例如:count,sum,mean,median,std,var,min,max,prod,first,last。這些函數的名稱很容易明白它的做用。 例如:groupby.sum()就是對結果進行求和運行。 除了直接調用這些函數以外,咱們也能夠經過agg函數來達到這個目的,這個函數接收其餘函數的名稱,例如這樣:groupby.agg(['sum'])。 經過agg函數,能夠一次性調用多個函數,而且能夠爲結果列指定名稱。 像這樣:groupby.agg([('Total', 'sum'), ('Min', 'min')])。 這裏的三個調用輸出結果以下:
# groupby.py Sum: Data Name A 135 B 224 C 90 Agg Sum: Data sum Name A 135 B 224 C 90 Agg Map: Data Total Min Name A 135 34 B 224 65 C 90 1
除了對數據集合進行統計,咱們也能夠經過apply函數進行分組數據的處理。像這樣:
# groupby.py def sort(df): **return** df.sort_values(by='Data', ascending=**False**) print("Sort Group: \n{}\n".format(groupby.apply(sort)))
在這段代碼中,咱們定義了一個排序函數,並應用在分組數據上,這裏最終的輸出以下:
Sort Group: Data Name A 2 57 1 44 0 34 B 3 81 4 78 5 65 C 6 73 7 16 8 1
時間是應用程序中很頻繁須要處理的邏輯,尤爲是對於金融,科技,商業等領域。 當咱們在討論時間,咱們討論的多是下面三種狀況中的一種:
某個具體的時間點(Timestamp),例如:今天下午一點整
某個時間範圍(Period),例如:整個這個月
某個時間間隔(Interval),例如:每週二上午七點整
Python語言提供了時間日期相關的基本API,它們位於datetime, time, calendar幾個模塊中。下面是一個代碼示例:
# time.py import datetime **as** dt import numpy **as** np import pandas **as** pd now= dt.datetime.now(); print("Now is {}".format(now)) yesterday= now- dt.timedelta(1); print("Yesterday is {}\n".format(yesterday.strftime('%Y-%m-%d')))
在這段代碼中,咱們打印了今天的日期,並經過timedelta進行了日期的減法運算。這段代碼輸出以下: 藉助pandas提供的接口,咱們能夠很方便的得到以某個時間間隔的時間序列,例如這樣:
# time.py this_year= pd.date_range(dt.datetime(2018, 1, 1), dt.datetime(2018, 12, 31), freq='5D') print("Selected days in 2018: \n{}\n".format(this_year))
這段代碼獲取了整個2018年中從元旦開始,每隔5天的日期序列。 date_range函數的詳細說明見這裏:pandas.date_range 這段代碼的輸出以下:
Selected days **in** 2018: DatetimeIndex(['2018-01-01', '2018-01-06', '2018-01-11', '2018-01-16', '2018-01-21', '2018-01-26', '2018-01-31', '2018-02-05', '2018-02-10', '2018-02-15', '2018-02-20', '2018-02-25', '2018-03-02', '2018-03-07', '2018-03-12', '2018-03-17', '2018-03-22', '2018-03-27', '2018-04-01', '2018-04-06', '2018-04-11', '2018-04-16', '2018-04-21', '2018-04-26', '2018-05-01', '2018-05-06', '2018-05-11', '2018-05-16', '2018-05-21', '2018-05-26', '2018-05-31', '2018-06-05', '2018-06-10', '2018-06-15', '2018-06-20', '2018-06-25', '2018-06-30', '2018-07-05', '2018-07-10', '2018-07-15', '2018-07-20', '2018-07-25', '2018-07-30', '2018-08-04', '2018-08-09', '2018-08-14', '2018-08-19', '2018-08-24', '2018-08-29', '2018-09-03', '2018-09-08', '2018-09-13', '2018-09-18', '2018-09-23', '2018-09-28', '2018-10-03', '2018-10-08', '2018-10-13', '2018-10-18', '2018-10-23', '2018-10-28', '2018-11-02', '2018-11-07', '2018-11-12', '2018-11-17', '2018-11-22', '2018-11-27', '2018-12-02', '2018-12-07', '2018-12-12', '2018-12-17', '2018-12-22', '2018-12-27'], dtype='datetime64[ns]', freq='5D')
咱們獲得的返回值是DatetimeIndex類型的,咱們能夠建立一個DataFrame並以此做爲索引:
# time.py df= pd.DataFrame(np.random.randint(0, 100, this_year.size), index=this_year) print("Jan: \n{}\n".format(df['2018-01']))
在這段代碼中,咱們建立了與索引數量同樣多的[0, 100)間的隨機整數,並用this_year做爲索引。用DatetimeIndex做索引的好處是,咱們能夠直接指定某個範圍來選擇數據,例如,經過df['2018-01']選出全部1月份的數據。 這段代碼輸出以下:
Jan: 0 2018-01-01 61 2018-01-06 85 2018-01-11 66 2018-01-16 11 2018-01-21 34 2018-01-26 2 2018-01-31 97
pandas的圖形展現依賴於matplotlib庫。對於這個庫,咱們在後面會專門講解,由於這裏僅僅提供一個簡單的代碼示例,讓你們感覺一下圖形展現的樣子。 代碼示例以下:
# plot.py import matplotlib.pyplot **as** plt import pandas **as** pd data= pd.read_csv("data/housing.csv") data.hist(bins=50, figsize=(15, 12)) plt.show()
這段代碼讀取了一個CSV文件,這個文件中包含了一些關於房價的信息。在讀取完以後,經過直方圖(hist)將其展現了出來。 該CSV文件的內容見這裏:pandas_tutorial/data/housing.csv 直方圖結果以下所示:
更多的內容在從此的時候,有機會咱們再來一塊兒探討。 讀者朋友也能夠根據官網上的文檔進行更深刻的學習。
更多Python技術文章請關注2019年,Python技術持續更新(附教程)