天天看點

Python資料分析之路(一)查詢和統計

關注沙漠之鷹的同學一定看過沙漠君寫得很多篇資料分析文章,比如分析房價,車價,預測機動車搖号這些話題。其實文章中所有的分析都使用了Python和它非常強大的資料分析庫Pandas。一些機器學習和預測的功能則用到了sklearn庫。掌握了這些工具,就能應對絕大多數的分析需求。

紙上得來終覺淺,即使你看了很多書和代碼,也未必比得上多接觸例子多敲一些代碼,三四個中等規模(約一兩百行代碼的)的案例就能讓你有整體的把握。至于資料采集,沙漠之鷹有開源的資料抓取工具Hawk,網上也有衆多如何擷取資料的教程,是以本文不再詳述。

系列文章分為三個部分:

1) 查詢與統計

2) 可視化和進階用法

3) 分類和預測(估計會分為幾篇文章)

好了,廢話不多說,進入正題。

好的問題其實比答案更重要。人認識問題,分為四種級别:

我們知道自己知道的(房價在漲)

知道自己不知道的(可度量的資訊,如房價平均漲幅)

不知道自己知道的(如證明搖号系統漏洞)

不知道自己不知道的(最有價值,蘊含着最大的機會)

沙漠君期待于尋找3-4層級的問題,可是多數情況隻能在第1和第2檔上徘徊。當你發現一個問題之後,還需要思考3個問題:

我是否找到了一個值得解決的問題?

我是否提出了一個足夠好的解決方案

我真的想去解決這個問題嗎?

最後的動機往往反映了你能解決該問題的最大極限,很多人也許僅僅是完成任務,是以有了一點成果便停滞不前,錯過了最大的金礦。資料的品質比數量更重要,如果不知道什麼樣的資料更重要,即使擁有更多的資料也隻會造成嘔吐。資料分析需要專注,需要從紛繁的圖表和資訊中找到問題核心。

通常來說,人們對變化的名額更感興趣,是以比率和增長幅度比靜态的資料更有說服力。而變化又分長短期,不同次元得出的結論往往全然不同。相關性很好,因果性更佳。有了因果性,便有了改變未來的能力。

下圖展示了資料分析的一般流程(圖檔來自網絡):

Python資料分析之路(一)查詢和統計

統計的三大核心:分組(map),聚合(reduce),排序(sort)。它們用的是如此普遍,是以MapReduce管道架構成了資料分析的标準,也非常适合做多機并行化。分組和排序很好了解,聚合指的是對各組内容做求和,分組等。

絕大部分資料分析操作,都可以通過查詢,分組,聚合,排序四個元素進行級聯組合進行。是以掌握這四大天王,應付一般的場景就都無問題了。 (這應該是這篇文章最重要的一句話了)

DataFrame是pandas的核心資料結構,可以了解為Excel裡的二維矩陣,它更進階,能表達3維或更高維的資料,支援多索引。在記憶體中存取,效率極高,絕大多數操作都和DataFrame相關。次元為2的DataFrame,行(column)和列(row)的axis分别為0和1。可以針對某些列做索引(index),高維DataFrame是相當少見的。

下面的表展示了Pandas對索引的介紹:

符号

說明

例子

[]

列值索引

df['房價'] ,df[['房價','車價']]

loc

行值索引

df.loc[0], df['2013':'2015']

iloc

行号索引

df.iloc[0], df.iloc[2:10]

ix

行索引

df.ix[0], df.ix[2:10]

時間也是比較重要的index,比較好用的是Timestamp,接受<code>2016-12-24</code>這種字元串,字元串到時間轉換代碼如下:

<code>weather.index= weather[u'日期'].map(lambda x:Timestamp(x))</code>

Pandas的索引功能非常強大,補充如下:

1) <code>loc</code>也能支援先行後列的查詢:<code>df.loc['20130101':'20130103' , ['A','B']]</code>,類似的如<code>iloc</code>

2) 個人感覺ix的有些備援,和<code>ix</code>和<code>iloc</code>類似

所有索引都支援字元串和數組,以及切片(slice)用于指定範圍,索引還能傳遞一個bool類型的lambda表達式,或傳回和其shape一緻的bool數組

這種用法可以用在過濾上,這非常重要,我們再給幾個例子:

過濾有兩方面需求:找出特定資料進行針對性分析,或

針對特定資料做分析,

過濾異常值。

異常值非常重要,應該細緻分析導緻它們産生的原因,如果真是異常值,應該提早過濾,否則做聚合時會嚴重影響結果,如天價的房價。

先讨論按行過濾:非空過濾,過濾掉<code>col</code>列為空的内容:

<code>df=df[!data.col.isnull()]</code>

字元串過濾:

<code>db[db.city.str.contains(u'市')]</code>

若需要對df對某個鍵去重:

<code>qq['id'].unique()</code>

<code>isin</code>能判斷單元格中的值是否在給定的數組内,若希望對多個列做過濾,Pandas提供了現成的方法df.filter,還支援正則。還能進行邏輯操作,實作更複雜的需求。

有了索引和列操作,為何還要有周遊?因為周遊更加靈活,當然性能相對會差一些:

函數

周遊目标

lambda參數

map

一列的cell

cell

最為常見

apply

列/行

列或行的Series

axis:不填寫cell,1:行,2:列

applymap

element-wise最為靈活

iterrows

行周遊

提供行号

見備注

iteritems

列周遊

提供列名

itertuples

提供index

map, apply,applymap是隻傳回單元格或行列本身的,參數都是lambda,本節假設讀者對python的lambda表達式有足夠的了解。

但這樣不能實作如“奇數偶數行做分别作不同處理的需求,則這三個函數就無能為力。是以就有後面iterrows等三個函數。如iterrows,它會将行号和行疊代出來,進而友善自定義邏輯,示例如下:

一張表可能很難包含所有的資訊,是以需要計算新值(求值)或join其他表(合并),但Pandas本身的Join并不好用,經常出錯。

如果某個屬性可以通過計算獲得,可對各個列當做變量來處理,由于内部使用了C++和numpy加速,效率遠比for循環更高,下面是處理房價的一個例子:<code>總價/單價</code>,并做小數點截取:

numpy提供了絕大多數常見的函數算子,能滿足大部分需求。下面是合并:

橫向合并(需保證行數一緻)- 橫向合并 <code>df = pd.concat([data_train, dummies_Cabin])</code>

删除列 <code>df.drop(['Pclass', 'Name', 'Sex')]</code>

縱向合并(join操作)

如果不加參數,則可以自動通過列名合并。join的參數比較複雜,建議直接參考Pandas官方文檔。

排序,分組和聚合的組合都有無數種,這在技術層面不難。但如果要寫報告,避免大而全,因為客戶的注意力很容易浪費在沒有意義的圖表上。将客戶真正關心的搞出來,行業背景分析,使用者畫像,競品監測,銷售行為分析...如果是寫通俗文章,多問幾個人,你想要知道什麼。

由于分組是基礎,我們先介紹分組:

分組就是按照一個或多個鍵,将資料分為幾個組的過程。你可以直接傳列名做分組,<code>df.groupby('column_name')</code>

也可以傳遞相同行數的Series甚至DataFrame。下面的例子是按日期裡的年做分組:

<code>df2.groupby(df2.日期.map(lambda x:x.year))</code>

Pandas也能支援傳遞多個列的數組,除了切片以外,能在索引上使用的基本都能在group,sort上使用,一緻性的API上手非常容易。

值得注意的是,由于時間索引分組比較困難,例如每五個月一組,可以用針對TimeStamp特定優化的方案,如resample:

下面計算了北京按年平均的AQI:

<code>db[db.city==u'北京'][u'平均值'].resample('12M').aqi.mean()</code>

Pandas的排序非常之快,大部分操作都能在瞬間完成。排序分為兩類:

一般排序,直接用<code>sort</code>即可,傳遞lambda,列名或多個列,或長度一緻的Series,這與groupby等其他API一緻,此處從略。

可指定<code>ascending=True|False</code>來指定升序,降序。

groupby之後的資料,和一般的DataFrame不同,而像個字典(dict)。對鍵排序,需使用sort_index,值排序,需使用sort_values。

聚合可将分組後的資料按需求重新打平。如求每個分組的最大值(max),最小值(min),或數量等,例如:

<code>df2.groupby(df2.日期.map(lambda x:x.year)).size()</code>

我們來寫幾個例子大家說說是什麼意思:

<code>car.groupby(car.年月.map(lambda x:x.month)).銷量.sum().plot(kind='bar',title='汽車市場月度銷量彙總')</code>

将汽車資料按照月份分組,按銷量求和。然後繪制直方圖:

Python資料分析之路(一)查詢和統計

Pandas支援直接将聚合結果繪圖輸出(雖然醜但是友善啊),下一節我們将詳細介紹它的使用細節。

這條語句統計了廣西省東風MPV的各車型總體銷量情況,并按數量降序:

<code>df[(df.省=='廣西') &amp; (df.車型分類=='MPV') &amp; (df.品牌=='東風')].groupby('車型').size().sort_values(ascending=False)</code>

如果我想一次性地針對多種分組方式實行多種聚合政策,有沒有更友善的API? 答案是資料透視表(pivot_table)。Excel也有該功能,異常強大,有了它,一般需求幾乎都能實作。

有篇文章講的非常詳細,此處就不班門弄斧了,參考:

<a href="http://python.jobbole.com/81212/">http://python.jobbole.com/81212/</a>

下面是同時按<code>Name rep manager</code>分組,按價格分别以總價和數量聚合,并将空值填為0.

Python資料分析之路(一)查詢和統計

pivot之後,生成的DataFrame是multiindex的,處理起來稍顯繁瑣,用xs可将某個子index的資料“提升”出來,例如:

<code>df_pivot.xs(('12AM新坐标',2011))</code>

至于更複雜的通路和采樣,可配合loc和PD.IndexSlice, 可自行檢視官方文檔。

Pandas本身異常強大,功能非常繁雜,筆者僅僅掌握了其中非常小的一部分。但是對于一般的需求都能通過簡單的操作組合出來。API的一緻性非常重要,Pandas(包括numpy等)都繼承了Python的優良特性,是以隻要能舉一反三,就能進步神速。

文章不能太長,否則就沒人看得完了。不過相信我,掌握文中說的用法,基本上就足夠混口飯吃了。因為寫SQL的速度和靈活性是遠遠不及Pandas文法的。下一篇是資料可視化,我們來讨論如何做可視化,還有對應的Python庫。

有任何問題,歡迎交流。

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

 本文轉自FerventDesert部落格園部落格,原文連結:http://www.cnblogs.com/buptzym/p/7144122.html,如需轉載請自行聯系原作者