Python數(shù)據(jù)科學系列:Pandas 入門詳細教程
導讀
本文自然是要對pandas進行入門詳細介紹,通過本文你將系統(tǒng)性了解pandas為何會有數(shù)據(jù)分析界"瑞士軍刀"的盛譽。

行文二級目錄

pandas,python+data+analysis的組合縮寫,是python中基于numpy和matplotlib的第三方數(shù)據(jù)分析庫,與后兩者共同構(gòu)成了python數(shù)據(jù)分析的基礎工具包,享有數(shù)分三劍客之名。
從數(shù)據(jù)結(jié)構(gòu)上看:
numpy的核心數(shù)據(jù)結(jié)構(gòu)是ndarray,支持任意維數(shù)的數(shù)組,但要求單個數(shù)組內(nèi)所有數(shù)據(jù)是同質(zhì)的,即類型必須相同;而pandas的核心數(shù)據(jù)結(jié)構(gòu)是series和dataframe,僅支持一維和二維數(shù)據(jù),但數(shù)據(jù)內(nèi)部可以是異構(gòu)數(shù)據(jù),僅要求同列數(shù)據(jù)類型一致即可
numpy的數(shù)據(jù)結(jié)構(gòu)僅支持數(shù)字索引,而pandas數(shù)據(jù)結(jié)構(gòu)則同時支持數(shù)字索引和標簽索引 從功能定位上看:
numpy雖然也支持字符串等其他數(shù)據(jù)類型,但仍然主要是用于數(shù)值計算,尤其是內(nèi)部集成了大量矩陣計算模塊,例如基本的矩陣運算、線性代數(shù)、fft、生成隨機數(shù)等,支持靈活的廣播機制
pandas主要用于數(shù)據(jù)處理與分析,支持包括數(shù)據(jù)讀寫、數(shù)值計算、數(shù)據(jù)處理、數(shù)據(jù)分析和數(shù)據(jù)可視化全套流程操作
按索引匹配的廣播機制,這里的廣播機制與numpy廣播機制還有很大不同 便捷的數(shù)據(jù)讀寫操作,相比于numpy僅支持數(shù)字索引,pandas的兩種數(shù)據(jù)結(jié)構(gòu)均支持標簽索引,包括bool索引也是支持的 類比SQL的join和groupby功能,pandas可以很容易實現(xiàn)SQL這兩個核心功能,實際上,SQL的絕大部分DQL和DML操作在pandas中都可以實現(xiàn) 類比Excel的數(shù)據(jù)透視表功能,Excel中最為強大的數(shù)據(jù)分析工具之一是數(shù)據(jù)透視表,這在pandas中也可輕松實現(xiàn) 自帶正則表達式的字符串向量化操作,對pandas中的一列字符串進行通函數(shù)操作,而且自帶正則表達式的大部分接口 豐富的時間序列向量化處理接口 常用的數(shù)據(jù)分析與統(tǒng)計功能,包括基本統(tǒng)計量、分組統(tǒng)計分析等 集成matplotlib的常用可視化接口,無論是series還是dataframe,均支持面向?qū)ο蟮睦L圖接口

series和dataframe分別是一維和二維數(shù)組,因為是數(shù)組,所以numpy中關(guān)于數(shù)組的用法基本可以直接應用到這兩個數(shù)據(jù)結(jié)構(gòu),包括數(shù)據(jù)創(chuàng)建、切片訪問、通函數(shù)、廣播機制等
series是帶標簽的一維數(shù)組,所以還可以看做是類字典結(jié)構(gòu):標簽是key,取值是value;而dataframe則可以看做是嵌套字典結(jié)構(gòu),其中列名是key,每一列的series是value。所以從這個角度講,pandas數(shù)據(jù)創(chuàng)建的一種靈活方式就是通過字典或者嵌套字典,同時也自然衍生出了適用于series和dataframe的類似字典訪問的接口,即通過loc索引訪問。
注意,這里強調(diào)series和dataframe是一個類字典結(jié)構(gòu)而非真正意義上的字典,原因在于series中允許標簽名重復、dataframe中則允許列名和標簽名均有重復,而這是一個真正字典所不允許的。
ndim/shape/dtypes/size/T,分別表示了數(shù)據(jù)的維數(shù)、形狀、數(shù)據(jù)類型和元素個數(shù)以及轉(zhuǎn)置結(jié)果。其中,由于pandas允許數(shù)據(jù)類型是異構(gòu)的,各列之間可能含有多種不同的數(shù)據(jù)類型,所以dtype取其復數(shù)形式dtypes。與此同時,series因為只有一列,所以數(shù)據(jù)類型自然也就只有一種,pandas為了兼容二者,series的數(shù)據(jù)類型屬性既可以用dtype也可以用dtypes獲取;而dataframe則只能用dtypes。
index/columns/values,分別對應了行標簽、列標簽和數(shù)據(jù),其中數(shù)據(jù)就是一個格式向上兼容所有列數(shù)據(jù)類型的array。為了沿襲字典中的訪問習慣,還可以用keys()訪問標簽信息,在series返回index標簽,在dataframe中則返回columns列名;可以用items()訪問鍵值對,但一般用處不大。

關(guān)于series和dataframe數(shù)據(jù)結(jié)構(gòu)本身,有大量的方法可用于重構(gòu)結(jié)構(gòu)信息:
rename,可以對標簽名重命名,也可以重置index和columns的部分標簽列信息,接收標量(用于對標簽名重命名)或字典(用于重命名行標簽和列標簽)
reindex,接收一個新的序列與已有標簽列匹配,當原標簽列中不存在相應信息時,填充NAN或者可選的填充值
set_index/reset_index,互為逆操作,前者是將已有的一列信息設置為標簽列,而后者是將原標簽列歸為數(shù)據(jù),并重置為默認數(shù)字標簽
set_axis,設置標簽列,一次只能設置一列信息,與rename功能相近,但接收參數(shù)為一個序列更改全部標簽列信息(rename中是接收字典,允許只更改部分信息)
rename_axis,重命名標簽名,rename中也可實現(xiàn)相同功能

在pandas早些版本中,除一維數(shù)據(jù)結(jié)構(gòu)series和二維數(shù)據(jù)結(jié)構(gòu)dataframe外,還支持三維數(shù)據(jù)結(jié)構(gòu)panel。這三者是構(gòu)成遞進包容關(guān)系,panel即是dataframe的容器,用于存儲多個dataframe。2019年7月,隨著pandas 0.25版本的推出,pandas團隊宣布正式棄用panel數(shù)據(jù)結(jié)構(gòu),而相應功能建議由多層索引實現(xiàn)。
也正因為pandas這3種獨特的數(shù)據(jù)結(jié)構(gòu),個人一度認為pandas包名解釋為:pandas = panel + dataframe + series,根據(jù)維數(shù)取相應的首字母個數(shù),從而構(gòu)成pandas,這是個人非常喜歡的一種關(guān)于pandas縮寫的解釋。

文本文件,主要包括csv和txt兩種等,相應接口為read_csv()和to_csv(),分別用于讀寫數(shù)據(jù)
Excel文件,包括xls和xlsx兩種格式均得到支持,底層是調(diào)用了xlwt和xlrd進行excel文件操作,相應接口為read_excel()和to_excel()
SQL文件,支持大部分主流關(guān)系型數(shù)據(jù)庫,例如MySQL,需要相應的數(shù)據(jù)庫模塊支持,相應接口為read_sql()和to_sql()
此外,pandas還支持html、json等文件格式的讀寫操作。

series和dataframe兼具numpy數(shù)組和字典的結(jié)構(gòu)特性,所以數(shù)據(jù)訪問都是從這兩方面入手。同時,也支持bool索引進行數(shù)據(jù)訪問和篩選。
[ ],這是一個非常便捷的訪問方式,不過需區(qū)分series和dataframe兩種數(shù)據(jù)結(jié)構(gòu)理解:
series:既可以用標簽也可以用數(shù)字索引訪問單個元素,還可以用相應的切片訪問多個值,因為只有一維信息,自然毫無懸念
dataframe:無法訪問單個元素,只能返回一列、多列或多行:單值或多值(多個列名組成的列表)訪問時按列進行查詢,單值訪問不存在列名歧義時還可直接用屬性符號" . "訪問。切片形式訪問時按行進行查詢,又區(qū)分數(shù)字切片和標簽切片兩種情況:當輸入數(shù)字索引切片時,類似于普通列表切片;當輸入標簽切片時,執(zhí)行范圍查詢(即無需切片首末值存在于標簽列中),包含兩端標簽結(jié)果,無匹配行時返回為空,但要求標簽切片類型與索引類型一致。例如,當標簽列類型(可通過df.index.dtype查看)為時間類型時,若使用無法隱式轉(zhuǎn)換為時間的字符串作為索引切片,則引發(fā)報錯

切片形式返回行查詢,且為范圍查詢

切片類型與索引列類型不一致時,引發(fā)報錯
loc/iloc,最為常用的兩種數(shù)據(jù)訪問方法,其中l(wèi)oc按標簽值訪問、iloc按數(shù)字索引訪問,均支持單值訪問或切片查詢。與[ ]訪問類似,loc按標簽訪問時也是執(zhí)行范圍查詢,包含兩端結(jié)果 at/iat,loc和iloc的特殊形式,不支持切片訪問,僅可以用單個標簽值或單個索引值進行訪問,一般返回標量結(jié)果,除非標簽值存在重復 isin/notin,條件范圍查詢,即根據(jù)特定列值是否存在于指定列表返回相應的結(jié)果 where,仍然是執(zhí)行條件查詢,但會返回全部結(jié)果,只是將不滿足匹配條件的結(jié)果賦值為NaN或其他指定值,可用于篩選或屏蔽值

query,按列對dataframe執(zhí)行條件查詢,一般可用常規(guī)的條件查詢替代

get,由于series和dataframe均可以看做是類字典結(jié)構(gòu),所以也可使用字典中的get()方法,主要適用于不確定數(shù)據(jù)結(jié)構(gòu)中是否包含該標簽時,與字典的get方法完全一致

lookup,loc的一種特殊形式,分別傳入一組行標簽和列標簽,lookup解析成一組行列坐標,返回相應結(jié)果:

pandas中支持大量的數(shù)據(jù)訪問接口,但萬變不離其宗:只要聯(lián)想兩種數(shù)據(jù)結(jié)構(gòu)兼具numpy數(shù)組和字典的雙重特性,就不難理解這些數(shù)據(jù)訪問的邏輯原理。當然,重點還是掌握[]、loc和iloc三種方法。
loc和iloc應該理解為是series和dataframe的屬性而非函數(shù),應用loc和iloc進行數(shù)據(jù)訪問就是根據(jù)屬性值訪問的過程
另外,在pandas早些版本中,還存在loc和iloc的兼容結(jié)構(gòu),即ix,可混合使用標簽和數(shù)字索引,但往往容易混亂,所以現(xiàn)已棄用

pandas最為強大的功能當然是數(shù)據(jù)處理和分析,可獨立完成數(shù)據(jù)分析前的絕大部分數(shù)據(jù)預處理需求。簡單歸納來看,主要可分為以下幾個方面:
1
數(shù)據(jù)清洗
空值 判斷空值,isna或isnull,二者等價,用于判斷一個series或dataframe各元素值是否為空的bool結(jié)果。需注意對空值的界定:即None或numpy.nan才算空值,而空字符串、空列表等則不屬于空值;類似地,notna和notnull則用于判斷是否非空 填充空值,fillna,按一定策略對空值進行填充,如常數(shù)填充、向前/向后填充等,也可通過inplace參數(shù)確定是否本地更改 刪除空值,dropna,刪除存在空值的整行或整列,可通過axis設置,也包括inplace參數(shù)
重復值 檢測重復值,duplicated,檢測各行是否重復,返回一個行索引的bool結(jié)果,可通過keep參數(shù)設置保留第一行/最后一行/無保留,例如keep=first意味著在存在重復的多行時,首行被認為是合法的而可以保留 刪除重復值,drop_duplicates,按行檢測并刪除重復的記錄,也可通過keep參數(shù)設置保留項。由于該方法默認是按行進行檢測,如果存在某個需要需要按列刪除,則可以先轉(zhuǎn)置再執(zhí)行該方法
異常值,判斷異常值的標準依賴具體分析數(shù)據(jù),所以這里僅給出兩種處理異常值的可選方法 刪除,drop,接受參數(shù)在特定軸線執(zhí)行刪除一條或多條記錄,可通過axis參數(shù)設置是按行刪除還是按列刪除 替換,replace,非常強大的功能,對series或dataframe中每個元素執(zhí)行按條件替換操作,還可開啟正則表達式功能
2
數(shù)值計算
由于pandas是在numpy的基礎上實現(xiàn)的,所以numpy的常用數(shù)值計算操作在pandas中也適用:
通函數(shù)ufunc,即可以像操作標量一樣對series或dataframe中的所有元素執(zhí)行同一操作,這與numpy的特性是一致的,例如前文提到的replace函數(shù),本質(zhì)上可算作是通函數(shù)。如下實現(xiàn)對數(shù)據(jù)表中逐元素求平方

廣播機制,即當維度或形狀不匹配時,會按一定條件廣播后計算。由于pandas是帶標簽的數(shù)組,所以在廣播過程中會自動按標簽匹配進行廣播,而非類似numpy那種純粹按順序進行廣播。例如,如下示例中執(zhí)行一個dataframe和series相乘,雖然二者維度不等、大小不等、標簽順序也不一致,但仍能按標簽匹配得到預期結(jié)果

字符串向量化,即對于數(shù)據(jù)類型為字符串格式的一列執(zhí)行向量化的字符串操作,本質(zhì)上是調(diào)用series.str屬性的系列接口,完成相應的字符串操作。尤為強大的是,除了常用的字符串操作方法,str屬性接口中還集成了正則表達式的大部分功能,這使得pandas在處理字符串列時,兼具高效和強力。例如如下代碼可用于統(tǒng)計每個句子中單詞的個數(shù)

需注意的是,這里的字符串接口與python中普通字符串的接口形式上很是相近,但二者是不一樣的。
時間類型向量化操作,如字符串一樣,在pandas中另一個得到"優(yōu)待"的數(shù)據(jù)類型是時間類型,正如字符串列可用str屬性調(diào)用字符串接口一樣,時間類型列可用dt屬性調(diào)用相應接口,這在處理時間類型時會十分有效。

3
數(shù)據(jù)轉(zhuǎn)換
前文提到,在處理特定值時可用replace對每個元素執(zhí)行相同的操作,然而replace一般僅能用于簡單的替換操作,所以pandas還提供了更為強大的數(shù)據(jù)轉(zhuǎn)換方法
map,適用于series對象,功能與python中的普通map函數(shù)類似,即對給定序列中的每個值執(zhí)行相同的映射操作,不同的是series中的map接口的映射方式既可以是一個函數(shù),也可以是一個字典

apply,既適用于series對象也適用于dataframe對象,但對二者處理的粒度是不一樣的:apply應用于series時是逐元素執(zhí)行函數(shù)操作;apply應用于dataframe時是逐行或者逐列執(zhí)行函數(shù)操作(通過axis參數(shù)設置對行還是對列,默認是行),僅接收函數(shù)作為參數(shù)

applymap,僅適用于dataframe對象,且是對dataframe中的每個元素執(zhí)行函數(shù)操作,從這個角度講,與replace類似,applymap可看作是dataframe對象的通函數(shù)。

4
合并與拼接
pandas中又一個重量級數(shù)據(jù)處理功能是對多個dataframe進行合并與拼接,對應SQL中兩個非常重要的操作:union和join。pandas完成這兩個功能主要依賴以下函數(shù):
concat,與numpy中的concatenate類似,但功能更為強大,可通過一個axis參數(shù)設置是橫向或者拼接,要求非拼接軸向標簽唯一(例如沿著行進行拼接時,要求每個df內(nèi)部列名是唯一的,但兩個df間可以重復,畢竟有相同列才有拼接的實際意義)
merge,完全類似于SQL中的join語法,僅支持橫向拼接,通過設置連接字段,實現(xiàn)對同一記錄的不同列信息連接,支持inner、left、right和outer4種連接方式,但只能實現(xiàn)SQL中的等值連接
join,語法和功能與merge一致,不同的是merge既可以用pandas接口調(diào)用,也可以用dataframe對象接口調(diào)用,而join則只適用于dataframe對象接口
append,concat執(zhí)行axis=0時的一個簡化接口,類似列表的append函數(shù)一樣

建表語句

通過設置參數(shù),concat和merge實現(xiàn)相同效果

pandas中的另一大類功能是數(shù)據(jù)分析,通過豐富的接口,可實現(xiàn)大量的統(tǒng)計需求,包括Excel和SQL中的大部分分析過程,在pandas中均可以實現(xiàn)。
1
基本統(tǒng)計量
pandas內(nèi)置了豐富的統(tǒng)計接口,這是與numpy是一致的,同時又包括一些常用統(tǒng)計信息的集成接口。
info,展示行標簽、列標簽、以及各列基本信息,包括元素個數(shù)和非空個數(shù)及數(shù)據(jù)類型等
head/tail,從頭/尾抽樣指定條數(shù)記錄
describe,展示數(shù)據(jù)的基本統(tǒng)計指標,包括計數(shù)、均值、方差、4分位數(shù)等,還可接收一個百分位參數(shù)列表展示更多信息

count、value_counts,前者既適用于series也適用于dataframe,用于按列統(tǒng)計個數(shù),實現(xiàn)忽略空值后的計數(shù);而value_counts則僅適用于series,執(zhí)行分組統(tǒng)計,并默認按頻數(shù)高低執(zhí)行降序排列,在統(tǒng)計分析中很有用

unique、nunique,也是僅適用于series對象,統(tǒng)計唯一值信息,前者返回唯一值結(jié)果列表,后者返回唯一值個數(shù)(number of unique)

sort_index、sort_values,既適用于series也適用于dataframe,sort_index是對標簽列執(zhí)行排序,如果是dataframe可通過axis參數(shù)設置是對行標簽還是列標簽執(zhí)行排序;sort_values是按值排序,如果是dataframe對象,也可通過axis參數(shù)設置排序方向是行還是列,同時根據(jù)by參數(shù)傳入指定的行或者列,可傳入多行或多列并分別設置升序降序參數(shù),非常靈活。另外,在標簽列已經(jīng)命名的情況下,sort_values可通過by標簽名實現(xiàn)與sort_index相同的效果。

2
分組聚合
groupby,類比SQL中的group by功能,即按某一列或多列執(zhí)行分組。一般而言,分組的目的是為了后續(xù)的聚合統(tǒng)計,所有g(shù)roupby函數(shù)一般不單獨使用,而需要級聯(lián)其他聚合函數(shù)共同完成特定需求,例如分組求和、分組求均值等。

pandas官網(wǎng)關(guān)于groupby過程的解釋

兩種分組聚合形式
pivot,pivot英文有"支點"或者"旋轉(zhuǎn)"的意思,排序算法中經(jīng)典的快速排序就是不斷根據(jù)pivot不斷將數(shù)據(jù)二分,從而加速排序過程。用在這里,實際上就是執(zhí)行行列重整。例如,以某列取值為重整后行標簽,以另一列取值作為重整后的列標簽,以其他列取值作為填充value,即實現(xiàn)了數(shù)據(jù)表的行列重整。以SQL中經(jīng)典的學生成績表為例,給定原始學生—課程—成績表,需重整為學生vs課程的成績表,則可應用pivot實現(xiàn):

另外,還有一對函數(shù)也常用于數(shù)據(jù)重整,即stack和unstack,其中unstack執(zhí)行效果與pivot非常類似,而stack則是unstack的逆過程。
pivot_table,有了pivot就不難理解pivot_table,實際上它是在前者的基礎上增加了聚合的過程,類似于Excel中的數(shù)據(jù)透視表功能。仍然考慮前述學生成績表的例子,但是再增加一列班級信息,需求是統(tǒng)計各班級每門課程的平均分。由于此時各班的每門課成績信息不唯一,所以直接用pivot進行重整會報錯,此時即需要對各班各門課程成績進行聚合后重整,比如取平均分。


pandas集成了matplotlib中的常用可視化圖形接口,可通過series和dataframe兩種數(shù)據(jù)結(jié)構(gòu)面向?qū)ο蟮慕涌诜绞胶唵握{(diào)用。關(guān)于面向?qū)ο蠼涌诤蚿lt接口繪圖方式的區(qū)別,可參考python數(shù)據(jù)科學系列:matplotlib入門詳細教程。
plot屬性+相應繪圖接口,如plot.bar()用于繪制條形圖 plot()方法并通過傳入kind參數(shù)選擇相應繪圖類型,如plot(kind='bar')

不過,pandas繪圖中僅集成了常用的圖表接口,更多復雜的繪圖需求往往還需依賴matplotlib或者其他可視化庫。

