本篇內容爲整理《利用Python進行數據分析》,博主使用代碼爲 Python3,部份內容和書本有出入。python
在前幾篇中咱們介紹了 NumPy、pandas、matplotlib 三個庫的基本操做,本篇介紹對數據的一些操做。正則表達式
pandas.merge
:可根據一個或多個鍵將不一樣DataFrame
中的行連接起來。pandas.concat
:可沿着一條軸將多個對象堆疊到一塊兒。combine_first
:可將重複數據編接在一塊兒,用一個對象中的值填充另外一個對象中的缺失值。數據庫風格的 DataFrame 合併數據庫
數據集的合併或鏈接運算:經過一個或多個鍵將行連接起來。數組
多對一的合併:app
若沒有指定用哪一個列進行鏈接,merge
會將重疊列名當作鍵,指定以下:dom
若兩個對象的列名不一樣,可分別進行指定:函數
默認狀況下,merge
作inner
鏈接,結果中的鍵是交集。外鏈接求取的是鍵的並集:工具
多對多的合併操做:大數據
鏈接方式隻影響出如今結果中的鍵。優化
根據多個鍵進行合併,傳入一個由列名組成的列表:
在進行列-列鏈接時,DataFrame
對象中的索引會被丟棄。
suffixes
選項:指定附加到左右兩個DataFrame
對象的重疊列名上的字符串。
索引上的合併
當DataFrame
中的鏈接鍵位於其索引中時,傳入left_index=True
、 right_index=True
,以說明索引應該被用做鏈接鍵:
對於層次化索引的數據:
必須以列表的形式指明用做合併鍵的列(注意對重複索引值的處理):
使用合併雙方的索引:
DataFrame
的 join
實例方法:
更方便的實現按索引合併,無論有沒有重疊的列。在鏈接鍵上做左鏈接。
支持參數DataFrame
的索引跟調用者DataFrame
的某個列之間的鏈接:
對於簡單的索引合併,能夠向join
傳入一組DataFrame
(concat 函數也是這個功能):
軸向鏈接
數據合併運算:
NumPy
有一個用於合併原始NumPy
數組的concatenation
函數:
pandas
的concat
函數:
默認狀況下,concat
在 axis=0
上工做,產生一個新Series
。傳入 axis=1
,產生一個DataFrame
:
這種狀況下,另一條軸上沒有重疊,傳入 join = 'inner'
獲得它們的交集:
使用 key
參數,在鏈接軸上建立一個層次化索引:
沿着 axis=1
對Series
進行合併,keys
就會成爲DataFrame
的列頭:
對DataFrame
對象也是如此:
傳入一個字典,則字典的鍵會被當作keys
選項的值:
用於管理層次化索引建立方式的參數:
跟當前分析工做無關的DataFrame
行索引:
傳入 ignore_index = True
:
合併重疊數據
關於有索引所有或部分重疊的兩個數據集。
NumPy
的where
函數,用於表達一種矢量化的if-else
:
Series
的combine_first
方法,實現與上面同樣的功能,並會進行數據對齊:
對於DataFrame
同樣:
能夠看做用參數對象中的數據爲調用者對象的缺失數據「打補丁」。
用於從新排列表格型數據的基礎運算:重塑(reshape)或軸向旋轉(pivot)。
重塑層次化索引
stark
:將數據的列「旋轉」爲行unstark
:將數據的行「旋轉」爲列
用stack
方法將行轉爲列,獲得一個Series
:
對層次化索引的Series
,能夠用unstack
將其從新排爲一個DataFrame
:
默認狀況下,unstack
操做最內層。
傳入分層級別的編號或名稱可對其餘級別進行unstack
操做:
若是不是全部的級別值都能在各分組找到的話,unstack
操做可能會引入缺失數據:
stack
默認會濾除缺失數據,所以該運算是可逆的:
對DataFrame
進行unstack
操做時,做爲旋轉軸的級別將會成爲結果中的最低級別:
將「長格式」旋轉爲「寬格式」
時間序列數據一般以 「長格式(long)」或「堆疊格式(stacked)」存儲在數據庫和 CSV 中。
轉成DataFrame
,用 pivot
方法:
獲得的DataFrame
帶有層次化的列:
假設有兩個須要參與重塑的數據列:
pivot
其實只是一個快捷方式:用set_index
建立層次化索引,再用unstack
重塑。
以上是數據的重排,下面是過濾、清理及其餘轉換工做。
移除重複數據
DataFrame
中出現的重複行:
DataFrame
的duplicated
方法返回一個布爾型Series
,表示各行是不是重複行,drop_duplicates
方法返回一個移除了重複行的DataFrame
:
指定部分列進行重複項判斷,如只但願根據k1
列過濾重複項:
duplicated
和drop_duplicates
默認保留重複數值裏第一次出現的組合,傳入keep = last
則保留最後一個:
利用函數或映射進行數據轉換
根據數組、Series
或DataFrame
列中的值來實現轉換。
編寫一個肉類到動物的映射:
Series
的map
方法:能夠接受一個函數或含有映射關係的字典型對象,用於修改對象的數據子集。
也能夠傳入一個可以完成所有這些工做的函數:
替換值
replace
方法 :替換
利用fillna
方法填充缺失數據能夠看做替換的一種特殊狀況。
替換一個值和一次性替換多個值:
對不一樣的值進行不一樣的替換:
傳入的參數也能夠是字典:
重命名軸索引
軸標籤有一個map
方法:
對函數或映射進行轉換,從而獲得一個新對象。
將其值賦給index
,就能夠對DataFrame
進行就地修改了:
要建立數據集的轉換版,而不是修改原始數據,用rename
:
rename
結合字典型對象能夠實現對部分軸標籤的更新:
rename
實現了複製DataFrame
並對其索引和列標籤進行賦值,就地修改某個數據集,傳入inplace=True
:
離散化和麪元劃分
爲了便於分析,連續數據經常被離散化或拆分爲「面元(bin)」。
用pandas
的cut
函數:
pandas
返回的是一個特殊的Categorical
對象,它含有一個表示不一樣分類名稱的數組和一個爲年齡數據進行標號的屬性:
哪邊是閉端能夠經過right=False
進行修改:
設置本身的面元名稱:
將labels
選項設置爲一個列表或數組便可。
若是向cut
傳入的是面元的數量而不是確切的面元邊界,則它會根據數據的最小值和最大值計算等長面元:
將一些均勻分佈的數據分紅了四組。
qcut
函數:根據樣本分位數對數據進行面元劃分。
因爲qcut
使用的是樣本分位數,能夠獲得大小基本相等的面元(而 cut 根據數據的分佈狀況,可能沒法使各個面元中含有相同數量的數據點)。
設置自定義的分位數:
在聚合和分組運算時會再次用到cut
和 qcut
這兩個離散化函數。
檢測和過濾異常值
判斷是否存在異常值(outlier ):
找出某列中絕對值大小超過 3 的值:
選出所有含有「超過 3 或 -3 的值」的行:
將值限制在區間 -3 到 3 之內:
np.sign
這個ufunc
返回的是一個由 1 和 -1 組成的數組,表示原始值的符號。
排列和隨機採樣
numpy.random.permutation
函數:對Series
和DataFrame
的列排列。
Permutation(5)
:須要排列的軸的長度。
而後就能夠在基於ix
的索引操做或take
函數中使用該數組了:
選取隨機子集(非替換):
用替換的方式產生樣本:
計算指標/啞變量
將分類變量(Categorical)轉換爲「啞變量矩陣(dummy matrix)」或「指標矩陣(indicator matrix)」。
給DataFrame
的列加上一個前綴,以便可以跟其餘數據進行合併:
用get_dummies
的prefix
參數。
DataFrame
中的某行同屬於多個分類的狀況,舉個例子:
要爲每一個genre
添加指標變量就須要作一些數據規整操做,構建多成員指標變量:
對於很大的數據,這種方式會變得很是慢,須要編寫一個可以利用DataFrame
內部機制的更低級的函數:
用get_dummies
和cut
之類的離散化函數。
字符串對象方法
Python 字符串對象的內置方法:
find
找不到返回 -1,index
找不到引起一個異常
傳入空字符串經常用於刪除模式:
正則表達式(regex)
提供了一種靈活的在文本中搜索或匹配字符串模式的方式。python 內置的re
模塊負責對字符串應用正則表達式。
re
模塊的函數分爲三個大類:模式匹配、替換、拆分。
描述一個或多個空白符的regex
是 \s+
。
調用re.split('\s+', text)
時,正則表達式會先被編譯,而後再在text
上調用其split
方法。
能夠用re.compile
本身編譯一個regex
,以獲得一個可重用的regex
對象,如上所示。若是打算對許多字符串應用同一條正則表達式,強烈建議經過這種方法,能夠節省大量的 CPU 時間。
獲得匹配regex
的全部模式:
findall
:返回字符串中全部的匹配項。search
:只返回第一個匹配項。match
:只匹配字符串的首部。
sub
方法:將匹配到的模式替換爲指定字符串,並返回所獲得的新字符串。
不只想找出電子郵件地址,還想將各個地址分爲 3 個部分,只需將待分段的模式的各部分用圓括號包起來:
經過groups
方法返回一個由模式各段組成的元組。
對於帶有分組功能的模式,findall
會返回一個元組列表:
sub
還能經過諸如\1
, \2
之類的特殊符號訪問各匹配項中的分組:
爲各個匹配分組加上一個名稱,由這種正則表達式所產生的匹配對象能夠獲得一個簡單易用的帶有分組名稱的字典:
pandas 中矢量化的字符串函數
經過data.map
,全部字符串和正則表達式方法都能被應用於各個值,但如存在NA
就會報錯,爲了解決這個問題,Series
有一些可以跳過NA
值的字符串操做方法,經過Series
的str
屬性便可訪問這些方法:
也能夠用正則表達式:
實現矢量化的元素獲取操做,對str.get/str
屬性上使用索引:
對字符串進行子串截取:
對數據集進行分組並對各組應用一個函數。
在將數據集準備好以後,一般的任務就是計算分組統計或生成透視表。pandas
提供了一個靈活高效的gruopby
功能,對數據集進行切片、切塊、摘要等操做。
用 python
和pandas
強大的表達能力能夠執行復雜的多的分組運算:利用任何能夠接受pandas
對象或NumPy
數組的函數。
分組運算:split
(拆分)--apply
(應用)--combine
(合併)。
分組鍵的形式:
DataFrame
某個列名的值。Series
,給出待分組軸上的值與分組名之間的對應關係。
訪問data1
,並根據key1
調用groupby
。
變量grouped
是一個GroupBy對象
,它實際上尚未進行任何計算,只是含有一些有關分組鍵df['key1']
的中間數據。
例如,調用GroupBy
的mean
方法來計算分組平均值:
Series
根據分組鍵進行了聚合,產生了一個新的Series
,其索引爲key1
列中的惟一值。
經過兩個鍵對數據進行了分組後,獲得的Series
具備一個層次化索引:
分組鍵能夠是任何長度適當的數組:
將列名用做分組鍵:
GroupBy
的size
方法返回一個含有分組大小的Series
:
對分組進行迭代
GroupBy
對象支持迭代,能夠產生一組二元元組(由分組名和數據塊組成)。
對於多重鍵,元組的第一個元素將會是由鍵值組成的元組。
對數據片斷進行操做,如將這些數據片斷作成一個字典:
groupby
默認在axis=0
上進行分組,經過設置能夠在其它任何軸上進行分組,如能夠根據dtype
對列進行分組:
選取一個或一組列
對於由DataFrame
產生的GroupBy對象
,用一個或一組(單個字符串或字符串數組)列名對其進行索引,就能實現選取部分列進行聚合的目的:
例如,對部分列進行聚合:計算data2
列的平均值並以DataFrame
形式獲得結果:
返回一個已分組的DataFrame
(傳入的是列表或數組)或Series
(傳入的是標量形式的單個列名):
經過字典或 Series 進行分組
除數組之外,分組信息還能夠其餘形式存在
根據分組計算列的sum
:
將mapping
這個字典傳給groupby
便可。
用Series
做爲分組鍵:
這裏Series
能夠被看作一個固定大小的映射。pandas
會檢查Series
以確保其索引根分組軸是對齊的。
經過函數進行分組
任何被當作分組鍵的函數都會在各個索引值上被調用一次,其返回值就會被用做分組名稱。
將函數根數組、列表、字典、Series
混合使用(任何東西最終都會被轉換爲數組):
Key_list
和人名對應,再在相同長度的對應一列裏選min
的值。
根據索引級別分組
層次化索引數據集經過level
關鍵字傳入級別編號或名稱:
可使用通過優化的GroupBy
的方法,還可使用本身發明的聚合運算,還能夠調用分組對象上已經定義好的任何方法,如 quantile
能夠計算Series
或DataFrame
列的樣本分位數:
GroupBy
會高效地對Series
進行切片,而後對各片調用piece.quantile(0.9)
,最後將這些結果組裝成最終結果。
使用本身的聚合函數,傳入aggregate
或agg方法
便可:
有些方法如describe
也能夠用,但嚴格來說它們並不是聚合運算。
自定義聚合函數比表中的通過優化的函數慢得多,這是由於在構造中間分組數據塊時存在很是大的開銷(函數調用、數據重排等)。
面向列的多函數應用
根據 'smoker'
和 'size'
對 tips
進行分組:
傳入一組函數或函數名,獲得的DataFrame
的列就會以相應的函數命名:
傳入一個由(name, function )
元組組成的列表,各元組的第一個元素會被用做DataFrame
的列名:
對於DataFrame
,定義一組應用於所有列的函數,或不一樣的列應用不一樣的函數。
結果的DataFrame
擁有層次化的列。至關於分別對列['tip_pct']
和列['total_bill']
進行聚合,而後用concat
將結果組裝到一塊兒(列名用做 keys 參數)。
傳入帶有自定義名稱的元組列表:
對不一樣的列應用不一樣的函數:向agg
傳入一個從列名映射到函數的字典
只有將多個函數應用到至少一列時,DataFrame
纔會擁有層次化的列:
以「無索引」的形式返回聚合數據
向groupby
傳入as_index=False,禁用功能由惟一的分組鍵組成索引:
聚合只是分組運算的其中一種,它接受可以將一維數據簡化爲標量值的函數。
接下來介紹 transform
和 apply
方法,執行更多其餘的分組運算。
爲一個DataFrame
添加一個用於存放各索引分組平均值的列:先聚合再合併。
下面在GroupBy
上使用transform
方法:
transform
會將一個函數應用到各個分組,而後將結果放置到適當的位置上。
從各組中減去平均值:先建立一個距平化函數(demeaning function),而後將其傳給transform
。
檢查demeaned
如今的分組平均值是否爲 0:
跟aggregate
同樣,transform
也是一個有着嚴格條件的特殊函數,傳入的函數只能產生兩種結果,一個能夠廣播的標量值(如 np.mean) 或一個相同大小的結果數組。
apply:通常性的「拆分-應用-合併」
最通常化的GroupBy
方法是apply
:apply
會將待處理的對象拆分紅多個片斷,而後對各片斷調用傳入的函數,最後嘗試將各片斷組合到一塊兒。
根據分組選出最高的 5 個tip_pct
值:編寫一個函數,在指定列找出最大值,而後把這個值所在的行選取出來。
對smoker
分組並用該分組函數調用apply
,獲得:
top
函數在DataFrame
的各個片斷上調用,而後結果由pandas
.concat
組裝到一塊兒,並以分組名稱進行了標記。
最後結果就有了一個層次化索引,其內層索引值來自原DataFrame
。
若是傳給apply
的函數可以接受其餘參數或關鍵字,能夠將這些內容放在函數名後面一併傳入:
在GroupBy
對象上調用describe
:
在GroupBy
中,當調用如describe
之類的方法時,實際上只是應用了下面兩條代碼的快捷方式:
除這些基本用法以外,可否充分發揮apply
的威力很大程度上取決於你的創造力,傳入的哪一個函數能作什麼全由你說了算,它只需返回一個pandas 對象或標量值便可。
禁止分組鍵
分組鍵會跟原始對象的索引共同構成結果對象中的層次化索引,將group_keys=False
傳入groupby
便可禁止該效果:
分位數和桶分析
pandas
有一些能根據指定面元或樣本分位數將數據拆分紅多塊的工具(cut 和 qcut),將這些函數跟groupby
結合起來,就能很是輕鬆地實現對數據集的桶或分位數分析了。
「長度相等的桶」指的是「區間大小相等」,「大小相等的桶」指的是「數據點數量相等」。
利用cut
將其裝入長度相等的桶中:
由cut
返回的Factor
對象可直接用於groupby
,能夠對data2
作一些統計計算:
要根據樣本分位數獲得大小相等的桶,使用qcut
:
傳入labels=False
,便可只獲取分位數的編號。不然那段仍是區間而不是編號:
示例:用特定於分組的值填充缺失值
對於缺失數據的清理工做,有時用dropna
將其濾除,有時則但願用一個固定值或由數據集自己所衍生出來的值去填充NA值
,用fillna
這個工具。
如用平均值去填充NA值
:
對不一樣的分組填充不一樣的值:將數據分組,並使用apply
和一個可以對各數據塊調用fillna
的函數便可。
用這個分組平均值去填充NA值
:
也能夠在代碼中預約義各組的填充值,因爲分組具備一個name 屬性
:
示例:隨機採樣和排列
從一個大數據集中隨機抽取樣本以進行蒙特卡羅模擬(Monte Carlo simulation)或其餘分析工做。抽取的方式不少,其中的一些效率會比其餘的高不少
一個辦法是:選取np.random.permutation(N)
的前K
個元素,其中N
爲完整數據的大小,K
爲指望的樣本大小。
構造一副撲克牌:
從整副牌中抽出 5 張:
從每種花色中隨機抽取兩張牌,因爲花色是牌名的最後一個字符,能夠據此進行分組,並使用apply
:
另外一種方法:
示例:分組加權平均數和相關係數
例如對這個數據集利用category
計算分組加權平均數:
來自 Yahoo! Finance 的數據集:
計算一個由日收益率(經過百分數變化計算)與 SPX 之間的年度相關係數組成的DataFrame
:
計算列於列之間的相關係數:(蘋果和微軟的年度相關係數)
示例:面向分組的線性迴歸
仍是上個例子,定義下面這個regress
函數(利用 statsmodels 庫)對各數據塊執行普通最小二乘法迴歸(Ordinary Least Squares, OLS)。
按年計算 AAPL 對 SPX 收益率的線性迴歸:
透視表(pivot table)
是各類電子表格程序和其餘數據分析軟件中一種常見的數據彙總工具。它根據一個或多個鍵對數據進行聚合,並根據行和列上的分組鍵將數據分配到各個矩形區域中。
在小費數據集中,根據day
和smoker
計算分組平均數(pivot_table 的默認聚合類型):
只想聚合tip_pct
和size
,並根據day
進行分組:
傳入margins=True
添加分項小計,將會添加標籤爲All
的行和列,其值對應於單個等級中全部數據的分組統計。
這裏All
值爲平均數。
要使用其餘的聚合函數,將其傳給aggfunc
便可。例如使用count
或len
獲得有關分組大小的交叉表:
存在NA值
,就設置一個fill_value
:
交叉表(crosstab)
是一種用於計算分組頻率的特殊透視表。
用pandas.crosstab
函數(pivot_table 也能實現該功能:根據 Nationality 和 Handedness 對這段數據進行彙總):
crosstab
的前兩個參數能夠是數組、Series
、數組列表:
加載數據
抽取有關贊助人和贊助模式的統計信息。
經過unique
,能夠獲取所有的候選人名單:
利用字典說明黨派關係:
經過這個映射以及 Series
對象的map
方法,能夠根據候選人姓名獲得一組黨派信息:
注意,該數據集既包括贊助也包括退款(負的出資額),爲了簡化分析過程,限定該數據集只能有正的出資額:
因爲 Barack Obama 和 Mitt Romney 是最主要的兩名候選人,專門準備了一個子集,只包含針對他們兩人的競選活動的贊助信息:
根據職業和僱主統計贊助信息
首先,根據職業計算出資總額:
這裏只列出了前10個,注意到 許多職業都涉及相同的基本工做類型或同同樣東西有多種變體,清理一些這樣的數據:將一個職業信息映射到另外一個。
對僱主信息也進行了一樣的處理。
這裏利用了dict.get
,它容許沒有映射關係的職業也能「經過」。
如今,能夠經過pivot_table
根據黨派和職業對數據進行聚合,而後過濾掉總出資額不足 200 萬美圓對數據:
作成柱狀圖:
對 Obama 和 Romney 總出資額最高的職業和企業:先對候選人進行分組,而後求取最大值:
對出資額分組
利用cut
函數根據出資額的大小將數據離散化到多個面元中:
根據候選人姓名以及面元標籤對數據進行分組:
對出資額求和並在面元內規格化,以便圖形化顯示兩位候選人各類贊助額度的比例:
根據州統計贊助信息
首先,根據候選人和州對數據進行聚合:
對各行除以總贊助額,就獲得各候選人在各州的總贊助額比例:
不足之處,歡迎指正。