Pandas與SQL對(duì)比

Pandas與SQL對(duì)比

作為一名數(shù)據(jù)分析師叭首,平常用的最多的工具是SQL(包括MySQL和Hive SQL等)。對(duì)于存儲(chǔ)在數(shù)據(jù)庫(kù)中的數(shù)據(jù)堡掏,自然用SQL提取會(huì)比較方便宋梧,但有時(shí)我們會(huì)處理一些文本數(shù)據(jù)(txt,csv),這個(gè)時(shí)候就不太好用SQL了专缠。Python也是分析師常用的工具之一雷酪,尤其pandas更是一個(gè)數(shù)據(jù)分析的利器。雖然二者的語(yǔ)法涝婉,原理可能有很大差別哥力,但在實(shí)現(xiàn)的功能上,他們有很多相通的地方墩弯,這里特進(jìn)行一個(gè)總結(jié)吩跋,方便大家對(duì)比學(xué)習(xí)~

什么是 Pandas?

Pandas渔工,即 Python 數(shù)據(jù)分析庫(kù)(Python Data Analysis Library)锌钮,是一個(gè)用于數(shù)據(jù)分析和處理的 Python 庫(kù)。它是開源的引矩,被 Anaconda 所支持梁丘。它特別適合結(jié)構(gòu)化(表格化)數(shù)據(jù)。有關(guān)更多信息,請(qǐng)參考 pandas.pydata.org/pandas-docs脓魏。

使用它可以做什么兰吟?

之前您在 SQL 里面進(jìn)行的查詢數(shù)據(jù)以及其他各種操作,都可以由 Pandas 完成茂翔!

太好了混蔼!我要從哪里開始呢?

對(duì)于已經(jīng)習(xí)慣于用 SQL 語(yǔ)句來(lái)處理數(shù)據(jù)問(wèn)題的人來(lái)說(shuō)珊燎,這是一個(gè)令人生畏的部分惭嚣。

SQL 是一種 聲明式編程語(yǔ)言en.wikipedia.org/wiki/List_o…

使用 SQL悔政,你通過(guò)聲明語(yǔ)句來(lái)聲明想要的內(nèi)容晚吞,這些聲明讀起來(lái)幾乎就如同普通英文短句一樣順暢。

而 Pandas 的語(yǔ)法與 SQL 完全不同谋国。在 Pandas 中槽地,您對(duì)數(shù)據(jù)集進(jìn)行處理,并將它們鏈在一起,以便按照您希望的方式進(jìn)行轉(zhuǎn)換和重構(gòu)捌蚊。

我們需要一本 phrasebook(常用語(yǔ)手冊(cè))集畅!

剖析 SQL 查詢

SQL 查詢由幾個(gè)重要的關(guān)鍵字組成。在這些關(guān)鍵字之間缅糟,添加您想要看到的具體數(shù)據(jù)挺智。下面是一些沒(méi)有具體數(shù)據(jù)的查詢語(yǔ)句的框架:

SELECT… FROM… WHERE…

GROUP BY… HAVING…

ORDER BY…

LIMIT… OFFSET…

當(dāng)然還有其他命令,但上面這些是最重要的窗宦。那么我們?nèi)绾螌⑦@些命令在 Pandas 實(shí)現(xiàn)呢赦颇?

首先,我們需要向 Pandas 里面加載一些數(shù)據(jù)赴涵,因?yàn)樗鼈冞€沒(méi)有在數(shù)據(jù)庫(kù)中媒怯。如下所示:

import pandas as pd

airports = pd.read_csv('data/airports.csv')
airport_freq = pd.read_csv('data/airport-frequencies.csv')
runways = pd.read_csv('data/runways.csv')

我的數(shù)據(jù)來(lái)自 ourairports.com/data/

SELECT, WHERE, DISTINCT, LIMIT

這是一些 SELECT 語(yǔ)句句占。我們使用 LIMIT 來(lái)截取結(jié)果沪摄,使用 WHERE 來(lái)進(jìn)行過(guò)濾篩選躯嫉,使用 DISTINCT 去除重復(fù)的結(jié)果纱烘。

SQL Pandas
select * from airports airports
select * from airports limit 3 airports.head(3)
select id from airports where ident = 'KLAX' airports[airports.ident == 'KLAX'].id
select distinct type from airport airports.type.unique()

使用多個(gè)條件進(jìn)行 SELECT 操作

我們將多個(gè)條件通過(guò)符號(hào)&組合在一起。如果我們只想要表格列中條件的子集條件祈餐,那么可以通過(guò)添加另外一對(duì)方括號(hào)來(lái)表示擂啥。

SQL Pandas
select * from airports where iso_region = 'US-CA' and type = 'seaplane_base' airports[(airports.iso_region == 'US-CA') & (airports.type == 'seaplane_base')]
select ident, name, municipality from airports where iso_region = 'US-CA' and type = 'large_airport' airports[(airports.iso_region == 'US-CA') & (airports.type == 'large_airport')][['ident', 'name', 'municipality']]

ORDER BY(排序)

默認(rèn)情況下,Pandas 會(huì)使用升序排序帆阳。如果要使用降序哺壶,請(qǐng)?jiān)O(shè)置 asending=False

SQL Pandas
select * from airport_freq where airport_ident = 'KLAX' order by type airport_freq[airport_freq.airport_ident == 'KLAX'].sort_values('type')
select * from airport_freq where airport_ident = 'KLAX' order by type desc airport_freq[airport_freq.airport_ident == 'KLAX'].sort_values('type', ascending=False)

IN… NOT IN(包含……不包含)

我們知道了如何對(duì)值進(jìn)行篩選蜒谤,但如何對(duì)一個(gè)列表進(jìn)行篩選呢山宾,如同 SQL 的IN 語(yǔ)句那樣?在 Pandas 中鳍徽,.isin() 操作符的工作方式與 SQL 的IN相同资锰。要使用否定條件,請(qǐng)使用 ~阶祭。

SQL Pandas
select * from airports where type in ('heliport', 'balloonport') airports[airports.type.isin(['heliport', 'balloonport'])]
select * from airports where type not in ('heliport', 'balloonport') airports[~airports.type.isin(['heliport', 'balloonport'])]

GROUP BY, COUNT, ORDER BY(分組)

分組操作很簡(jiǎn)單:使用 .groupby() 操作符绷杜。SQL 和 pandas 中的 COUNT 語(yǔ)句存在微妙的差異。在 Pandas 中濒募,.count() 將返回非空/非 NaN 的值鞭盟。要獲得與 SQL COUNT相同的結(jié)果,請(qǐng)使用 .size()瑰剃。

SQL Pandas
select iso_country, type, count(*) from airports group by iso_country, type order by iso_country, type airports.groupby(['iso_country', 'type']).size()
select iso_country, type, count() from airports group by iso_country, type order by iso_country, count() desc airports.groupby(['iso_country', 'type']).size().to_frame('size').reset_index().sort_values(['iso_country', 'size'], ascending=[True, False])

下面齿诉,我們對(duì)多個(gè)字段進(jìn)行分組。Pandas 默認(rèn)情況下將對(duì)列表中相同字段上的內(nèi)容進(jìn)行排序,因此在第一個(gè)示例中不需要 .sort_values()粤剧。如果我們想使用不同的字段進(jìn)行排序遗座,或者想使用 DESC 而不是 ASC,就像第二個(gè)例子那樣俊扳,那我們就必須明確使用 .sort_values()

SQL Pandas
select iso_country, type, count(*) from airports group by iso_country, type order by iso_country, type airports.groupby(['iso_country', 'type']).size()
select iso_country, type, count() from airports group by iso_country, type order by iso_country, count() desc airports.groupby(['iso_country', 'type']).size().to_frame('size').reset_index().sort_values(['iso_country', 'size'], ascending=[True, False])

其中使用.to_frame()reset_index() 是為什么呢途蒋?因?yàn)槲覀兿Mㄟ^(guò)計(jì)算出的字段(size)進(jìn)行排序,所以這個(gè)字段需要成為 DataFrame 的一部分馋记。在 Pandas 中進(jìn)行分組之后号坡,我們得到了一個(gè)名為 GroupByObject 的新類型。所以我們需要使用 .to_frame() 把它轉(zhuǎn)換回 DataFrame類型梯醒。再使用 .reset_index()宽堆,我們重新進(jìn)行數(shù)據(jù)幀的行編號(hào)。

HAVING(包含)

在 SQL 中茸习,您可以使用 HAVING 條件語(yǔ)句對(duì)分組數(shù)據(jù)進(jìn)行追加過(guò)濾畜隶。在 Pandas 中,您可以使用 .filter() 号胚,并給它提供一個(gè) Python 函數(shù)(或 lambda 函數(shù))籽慢,如果結(jié)果中包含這個(gè)組,該函數(shù)將返回 True猫胁。

SQL Pandas
select type, count() from airports where iso_country = 'US' group by type having count() > 1000 order by count(*) desc airports[airports.iso_country == 'US'].groupby('type').filter(lambda g: len(g) > 1000).groupby('type').size().sort_values(ascending=False)

前 N 個(gè)記錄

假設(shè)我們做了一些初步查詢箱亿,現(xiàn)在有一個(gè)名為by_country 的 dataframe,它包含每個(gè)國(guó)家的機(jī)場(chǎng)數(shù)量:

在接下來(lái)的第一個(gè)示例中弃秆,我們通過(guò) airport_count 來(lái)進(jìn)行排序届惋,只選擇數(shù)量最多的 10 個(gè)國(guó)家。第二個(gè)例子比較復(fù)雜菠赚,我們想要“前 10 名之后的另外 10 名脑豹,即 11 到 20 名”:

SQL Pandas
select iso_country from by_country order by size desc limit 10 by_country.nlargest(10, columns='airport_count')
select iso_country from by_country order by size desc limit 10 offset 10 by_country.nlargest(20, columns='airport_count').tail(10)

聚合函數(shù)(MIN,MAX衡查,MEAN)

現(xiàn)在給定一組 dataframe瘩欺,或者一組跑道數(shù)據(jù):

計(jì)算跑道長(zhǎng)度的最小值,最大值峡捡,平均值和中值:

SQL Pandas
select max(length_ft), min(length_ft), avg(length_ft), median(length_ft) from runways runways.agg({'length_ft': ['min', 'max', 'mean', 'median']})

SQL沒(méi)有median函數(shù)击碗。假設(shè)您編寫了一個(gè)用戶定義的函數(shù)來(lái)計(jì)算該統(tǒng)計(jì)信息(因?yàn)檫@里的重要部分是SQL和Pandas之間的語(yǔ)法差異)。

您會(huì)注意到们拙,使用 SQL 查詢稍途,每個(gè)統(tǒng)計(jì)結(jié)果都是一列數(shù)據(jù)。但是使用 Pandas 的聚集方法砚婆,每個(gè)統(tǒng)計(jì)結(jié)果都是一行數(shù)據(jù):

不用擔(dān)心 — 只需將 dataframe 通過(guò) .T 進(jìn)行轉(zhuǎn)換就可以得到成列的數(shù)據(jù):

JOIN(連接)

使用 .merge() 來(lái)連接 Pandas 的 dataframes械拍。您需要提供要連接哪些列(left_onright_on)和連接類型:inner(默認(rèn))突勇,left(對(duì)應(yīng) SQL 中的 LEFT OUTER),rightRIGHT OUTER)坷虑,或 OUTERFULL OUTER)甲馋。

SQL Pandas
select airport_ident, type, description, frequency_mhz from airport_freq join airports on airport_freq.airport_ref = airports.id where airports.ident = 'KLAX' airport_freq.merge(airports[airports.ident == 'KLAX'][['id']], left_on='airport_ref', right_on='id', how='inner')[['airport_ident', 'type', 'description', 'frequency_mhz']]

UNION ALL and UNION(合并)

使用 pd.concat() 替代 UNION ALL 來(lái)合并兩個(gè) dataframes:

SQL Pandas
select name, municipality from airports where ident = 'KLAX' union all select name, municipality from airports where ident = 'KLGB' pd.concat([airports[airports.ident == 'KLAX'][['name', 'municipality']], airports[airports.ident == 'KLGB'][['name', 'municipality']]])

合并過(guò)程中想要?jiǎng)h除重復(fù)數(shù)據(jù)(等價(jià)于 UNION),你還需要添加 .drop_duplicates()迄损。

INSERT(插入)

到目前為止定躏,我們一直在講篩選,但是在您的探索性分析過(guò)程中芹敌,您可能也需要修改痊远。如果您想添加一些遺漏的記錄你該怎么辦?

Pandas 里面沒(méi)有形同 INSERT 語(yǔ)句的方法。相反氏捞,您只能創(chuàng)建一個(gè)包含新記錄的新 dataframe碧聪,然后合并兩個(gè) dataframe:

SQL Pandas
create table heroes (id integer, name text); df1 = pd.DataFrame({'id': [1, 2], 'name': ['Harry Potter', 'Ron Weasley']})
insert into heroes values (1, 'Harry Potter'); df2 = pd.DataFrame({'id': [3], 'name': ['Hermione Granger']})
insert into heroes values (2, 'Ron Weasley');
insert into heroes values (3, 'Hermione Granger'); pd.concat([df1, df2]).reset_index(drop=True)

UPDATE(更新)

現(xiàn)在我們需要修改原始 dataframe 中的一些錯(cuò)誤數(shù)據(jù):

SQL Pandas
update airports set home_link = 'http://www.lawa.org/welcomelax.aspx' where ident == 'KLAX' airports.loc[airports['ident'] == 'KLAX', 'home_link'] = 'http://www.lawa.org/welcomelax.aspx'

DELETE(刪除)

從 Pandas dataframe 中刪除數(shù)據(jù)的最簡(jiǎn)單(也是最易讀的)方法是將 dataframe 提取包含您希望保留的行數(shù)據(jù)的子集∫壕ィ或者逞姿,您可以通過(guò)獲取行索引來(lái)進(jìn)行刪除,使用 .drop() 方法刪除這些索引的行:

SQL Pandas
delete from lax_freq where type = 'MISC' lax_freq = lax_freq[lax_freq.type != 'MISC']
lax_freq.drop(lax_freq[lax_freq.type == 'MISC'].index)
Pandas與SQL對(duì)比

Immutability(不變性)

我需要提及一件重要的事情 — 不可變性捆等。默認(rèn)情況下滞造,大部分應(yīng)用于 Pandas dataframe 的操作符都會(huì)返回一個(gè)新對(duì)象。有些操作符可以接收 inplace=True參數(shù)楚里,這樣您可以繼續(xù)使用原始的 dataframe断部。例如猎贴,以下是一個(gè)就地重置索引的方法:

df.reset_index(drop=True, inplace=True)

然而,上面的 UPDATE 示例中的 .loc 操作符僅定位需要更新記錄的索引班缎,并且這些值會(huì)就地更改。此外她渴,如果您更新了一列的所有值:

df['url'] = 'http://google.com'

或者添加一個(gè)計(jì)算得出的新列:

df['total_cost'] = df['price'] * df['quantity']

這些都會(huì)就地發(fā)生變化达址。

更多!

Pandas 的好處在于它不僅僅是一個(gè)查詢引擎趁耗。你可以用你的數(shù)據(jù)做更多事情沉唠,例如:

  • 以多種格式輸出:
df.to_csv(...)  # csv file
df.to_hdf(...)  # HDF5 file
df.to_pickle(...)  # serialized object
df.to_sql(...)  # to SQL database
df.to_excel(...)  # to Excel sheet
df.to_json(...)  # to JSON string
df.to_html(...)  # render as HTML table
df.to_feather(...)  # binary feather-format
df.to_latex(...)  # tabular environment table
df.to_stata(...)  # Stata binary data files
df.to_msgpack(...)  # msgpack (serialize) object
df.to_gbq(...)  # to a Google BigQuery table.
df.to_string(...)  # console-friendly tabular output.
df.to_clipboard(...) # clipboard that can be pasted into Excel
  • 繪制圖表:
top_10.plot(
    x='iso_country', 
    y='airport_count',
    kind='barh',
    figsize=(10, 7),
    title='Top 10 countries with most airports')

去看看一些很不錯(cuò)的圖表!

  • 共享:

共享 Pandas 查詢結(jié)果苛败、繪圖和相關(guān)內(nèi)容的最佳媒介是 Jupyter notebooks(jupyter.org)满葛。事實(shí)上,有些人(比如杰克·范德普拉斯(Jake Vanderplas)罢屈,他太棒了)會(huì)把整本書都發(fā)布在 Jupyter notebooks 上:github.com/jakevdp/Pyt…嘀韧。

很簡(jiǎn)單就可以創(chuàng)建一個(gè)新的筆記本:

pip install jupyter
jupyter notebook

之后:

  • 打開 localhost:8888
  • 點(diǎn)擊新建,并給筆記本起個(gè)名字
  • 查詢并顯示數(shù)據(jù)
  • 創(chuàng)建一個(gè) GitHub 倉(cāng)庫(kù)缠捌,并添加您的筆記本到倉(cāng)庫(kù)中(后綴為 .ipynb 的文件)锄贷。

GitHub 有一個(gè)很棒的內(nèi)置查看器,可以以 Markdown 的格式顯示 Jupyter notebooks 的內(nèi)容。

現(xiàn)在谊却,你可以開始你的 Pandas 之旅了柔昼!

我希望您現(xiàn)在確信,Pandas 庫(kù)可以像您的老朋友 SQL 一樣幫助您進(jìn)行探索性數(shù)據(jù)分析炎辨,在某些情況下甚至?xí)龅酶貌锻浮J菚r(shí)候你自己動(dòng)手開始在 Pandas 里查詢數(shù)據(jù)了!

學(xué)習(xí)來(lái)源

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碴萧,一起剝皮案震驚了整個(gè)濱河市激率,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌勿决,老刑警劉巖乒躺,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異低缩,居然都是意外死亡嘉冒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門咆繁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)讳推,“玉大人,你說(shuō)我怎么就攤上這事玩般∫伲” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵坏为,是天一觀的道長(zhǎng)究驴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)匀伏,這世上最難降的妖魔是什么洒忧? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮够颠,結(jié)果婚禮上熙侍,老公的妹妹穿的比我還像新娘。我一直安慰自己履磨,他們只是感情好蛉抓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著剃诅,像睡著了一般巷送。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上综苔,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天惩系,我揣著相機(jī)與錄音位岔,去河邊找鬼。 笑死堡牡,一個(gè)胖子當(dāng)著我的面吹牛抒抬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播晤柄,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼擦剑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了芥颈?” 一聲冷哼從身側(cè)響起惠勒,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爬坑,沒(méi)想到半個(gè)月后纠屋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盾计,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年售担,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片署辉。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡族铆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哭尝,到底是詐尸還是另有隱情哥攘,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布材鹦,位于F島的核電站逝淹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏侠姑。R本人自食惡果不足惜创橄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望莽红。 院中可真熱鬧,春花似錦邦邦、人聲如沸安吁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鬼店。三九已至,卻和暖如春黔龟,著一層夾襖步出監(jiān)牢的瞬間妇智,已是汗流浹背滥玷。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巍棱,地道東北人惑畴。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像航徙,于是被迫代替她去往敵國(guó)和親如贷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353