程序員用於機器學習編程的Python 數據處理庫 pandas 進階教程

數據訪問

在入門教程中,咱們已經使用過訪問數據的方法。這裏咱們再集中看一下。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與iloc

在入門教程中,咱們已經提到了這兩個操做符:數據結構

  • 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

at與iat

這兩個操做符用來訪問單個的元素值(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提供了查找,數據對齊和從新索引所需的基礎數據結構。 最直接的,咱們能夠經過一個數組來建立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

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與Append

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

Merge與Join

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技術持續更新(附教程)

相關文章
相關標籤/搜索