dataframe 如何选中某列的一行_如何用 Python 在笔记本上分析 100GB 数据?
許多組織都想盡可能多地收集和利用數(shù)據(jù),從而改進(jìn)業(yè)務(wù)、增加收入和提升影響力。因此,數(shù)據(jù)科學(xué)家們要面對(duì) 50GB,甚至 500GB 數(shù)據(jù)集的場(chǎng)景變得越來(lái)越普遍。
目前,這些數(shù)據(jù)集處理起來(lái)有點(diǎn)麻煩。就大小而言,它們可以放進(jìn)你筆記本電腦的硬盤里,但卻無(wú)法裝入內(nèi)存。所以,僅僅打開和查看它們就很困難,更何況進(jìn)一步探索和分析。
處理這樣的數(shù)據(jù)集時(shí),一般有 3 種策略。
第 1 種是對(duì)數(shù)據(jù)進(jìn)行子抽樣,但它有一個(gè)明顯缺點(diǎn):可能因忽略部分?jǐn)?shù)據(jù)而錯(cuò)失關(guān)鍵信息,甚至誤解數(shù)據(jù)表達(dá)的含義。
第 2 種是使用分布式計(jì)算。雖然在某些情況下這是一種有效的方法,但是管理和維護(hù)集群會(huì)帶來(lái)巨大開銷。想象一下,要為一個(gè)剛超出內(nèi)存大小、大概 30-50GB 的數(shù)據(jù)集就建立一套集群,對(duì)我來(lái)說(shuō),這似乎有點(diǎn)“用力過(guò)猛”。
第 3 種是租用一個(gè)內(nèi)存大小等同于數(shù)據(jù)集大小的強(qiáng)大云服務(wù)實(shí)例,例如,AWS 提供了 TB 級(jí)內(nèi)存的云服務(wù)實(shí)例。但這種情況還需要管理云數(shù)據(jù)存儲(chǔ)空間,并且在每次實(shí)例啟動(dòng)時(shí)都要等待數(shù)據(jù)從存儲(chǔ)空間傳輸?shù)綄?shí)例。另外還需要應(yīng)對(duì)數(shù)據(jù)上云的合規(guī)性問(wèn)題,以及忍受在遠(yuǎn)程機(jī)器上工作帶來(lái)的不便。更別提成本,雖然開始會(huì)比較低,但隨著時(shí)間推移會(huì)快速上漲。
本文向你展示一種全新方法,它更快、更安全,可以更方便、全面地對(duì)幾乎任意大小的數(shù)據(jù)集進(jìn)行數(shù)據(jù)科學(xué)研究,只要這個(gè)數(shù)據(jù)集能裝進(jìn)你的筆記本電腦、臺(tái)式機(jī)或者服務(wù)器的硬盤里就行。
Vaex
Vaex 是一個(gè)開源的 DataFrame 庫(kù),對(duì)于和你硬盤空間一樣大小的表格數(shù)據(jù)集,它可以有效進(jìn)行可視化、探索、分析乃至實(shí)踐機(jī)器學(xué)習(xí)。
為實(shí)現(xiàn)這些功能,Vaex 采用內(nèi)存映射、高效的核外算法和延遲計(jì)算等概念。所有這些都封裝為類 Pandas 的 API,因此,任何人都能快速上手。
10 億級(jí)出租車的數(shù)據(jù)分析
為闡述這些概念,我們對(duì)一個(gè)遠(yuǎn)超出一般筆記本電腦內(nèi)存大小的數(shù)據(jù)集進(jìn)行簡(jiǎn)單地探索分析。
這里,我們使用 New York City(NYC) Taxi 數(shù)據(jù)集,它包含了標(biāo)志性的黃色出租車 2009 年到 2015 年間超過(guò)十億次的出租車行程信息。
數(shù)據(jù)從網(wǎng)站下載,提供 CSV 格式。完整分析可以單獨(dú)查看這個(gè) Jupyter notebook 。
0.052 秒打開 100G 的數(shù)據(jù)集
第一步是將數(shù)據(jù)轉(zhuǎn)換為內(nèi)存映射文件格式,如 Apache Arrow 、 Apache Parquet 或 HDF5 。關(guān)于如何把 CSV 數(shù)據(jù)轉(zhuǎn)為 HDF5 的例子請(qǐng)看這里。一旦數(shù)據(jù)存為內(nèi)存映射格式,即便它的磁盤大小超過(guò) 100GB,用 Vaex 也可以在瞬間打開它(0.052 秒):
Vaex 瞬間打開內(nèi)存映射文件(0.052 秒)
為什么這么快?在用 Vaex 打開內(nèi)存映射文件時(shí),實(shí)際上并沒有讀取數(shù)據(jù)。Vaex 只讀取了文件元數(shù)據(jù),比如數(shù)據(jù)在磁盤上的位置、數(shù)據(jù)結(jié)構(gòu)(行數(shù)、列數(shù)、列名和類型)、文件描述等等。那如果想查看或者操作數(shù)據(jù)呢?
將數(shù)據(jù)結(jié)果展示在一個(gè)標(biāo)準(zhǔn)的 DataFrame 中進(jìn)行預(yù)覽,速度一樣非常快。
預(yù)覽 New York City Yellow Taxi 數(shù)據(jù)
代碼單元執(zhí)行時(shí)間還是非常短。這是因?yàn)檎故?Vaex DataFrame 或者某列,只需要從硬盤中讀取前 5 行和后 5 行數(shù)據(jù)。這里引出另一個(gè)要點(diǎn):Vaex 只會(huì)在必要的時(shí)候遍歷整個(gè)數(shù)據(jù)集,而且它會(huì)盡可能遍歷更少的數(shù)據(jù)。
不管怎樣,我們先從異常值和錯(cuò)誤的輸入值開始清理這個(gè)數(shù)據(jù)集。一種好的方式是用describe方法獲取數(shù)據(jù)的高級(jí)概覽,它可以展示樣本數(shù)量、缺失值的數(shù)量和每列的數(shù)據(jù)類型。
如果某列的數(shù)據(jù)類型是數(shù)值,它還將展示其平均值、標(biāo)準(zhǔn)差、最小值及最大值。而所有的這些數(shù)據(jù)都是通過(guò)一次數(shù)據(jù)遍歷計(jì)算的。
使用describe方法獲得 DataFrame 的高級(jí)概覽,注意這個(gè) DataFrame 包含 18 列數(shù)據(jù),不過(guò)截圖只展示了前 7 列。
describe方法很好地體現(xiàn)了 Vaex 的能力和效率:所有這些數(shù)據(jù)都是在我的 MacBook Pro(15 英寸、2018 款、2.6GHz Intel Core i7 和 32G 內(nèi)存)上在 3 分鐘內(nèi)計(jì)算出來(lái)的。其他庫(kù)或方法則需要分布式計(jì)算或超過(guò) 100GB 的云服務(wù)實(shí)例才能完成相同的計(jì)算,而有了 Vaex 你需要的只是數(shù)據(jù)以及擁有幾 GB 內(nèi)存的筆記本電腦。
查看describe的輸出很容易發(fā)現(xiàn)這個(gè)數(shù)據(jù)包含了一些明顯的異常值。
首先從檢查上車點(diǎn)開始,去除異常值最簡(jiǎn)單的方法就是繪制出上車點(diǎn)和下車點(diǎn)位置,并且直觀地確定紐約哪些地區(qū)是要分析關(guān)注的。由于要處理的數(shù)據(jù)集如此龐大,直方圖是最有效的可視化方法。用 Vaex 創(chuàng)建和展示直方圖及熱力圖相當(dāng)快,而且圖表還是可交互的!
df.plot_widget(df.pickup_longitude, df.pickup_latitude, shape=512, limits='minmax', f='log1p', colormap='plasma')一旦通過(guò)交互確定紐約哪些區(qū)域是要關(guān)注的區(qū)域后,我們就可以創(chuàng)建一個(gè)篩選后的 DataFrame:
上述代碼很酷的一點(diǎn)是,它只需很少內(nèi)存就可以執(zhí)行!在篩選 Vaex DataFrame 時(shí)并不會(huì)復(fù)制數(shù)據(jù)。而是只創(chuàng)建對(duì)原始對(duì)象的引用,并在其上應(yīng)用二進(jìn)制掩碼。用掩碼來(lái)選擇哪些行將被顯示以及將來(lái)用于計(jì)算。這為我們節(jié)省了 100GB 的內(nèi)存,而像現(xiàn)在許多標(biāo)準(zhǔn)數(shù)據(jù)科學(xué)工具則必須得復(fù)制數(shù)據(jù)才行。
現(xiàn)在,來(lái)看下passenger_count這一列。單次出租車行程乘坐人數(shù)的最大值是 255,這似乎有點(diǎn)夸張。我們來(lái)數(shù)數(shù)每次行程的乘客人數(shù),這里用value_counts方法很容易實(shí)現(xiàn):
在 10 億行數(shù)據(jù)上使用 value_counts 方法只需要 20 秒!
從上圖可以看出,乘客超出 6 人可能是少見的異常值或者是錯(cuò)誤的數(shù)據(jù)輸入。同時(shí)還有大量乘客數(shù)為 0 的行程。既然不知道這些行程是否合理,就先把它們過(guò)濾掉。
再用行程距離做一個(gè)類似的練習(xí)。由于它是一個(gè)連續(xù)的變量,我們可以繪制出行程距離的分布情況。行程距離的最小值是負(fù)值,而最大值比火星都遠(yuǎn),所以還是限制在一個(gè)合理的區(qū)間內(nèi)繪制直方圖。
紐約出租車數(shù)據(jù)行程距離直方圖
從上圖中可以看到,行程數(shù)量隨著距離的增加而減少。在距離大約為 100 英里處,分布有明顯下降。現(xiàn)在,我們用這個(gè)作為分界點(diǎn)來(lái)消除行程距離的異常值。
在行程距離這一列中存在異常值,也因此有了動(dòng)機(jī)查看行程耗費(fèi)時(shí)間和平均速度。數(shù)據(jù)集中并沒有提供這兩個(gè)特征數(shù)據(jù),但是很容易計(jì)算得出:
上面的代碼塊不需要內(nèi)存也不消耗執(zhí)行時(shí)間!是因?yàn)榇a只會(huì)創(chuàng)建虛擬列(virtual columns),這些虛擬列只包含數(shù)學(xué)表達(dá)式,僅在需要時(shí)才進(jìn)行計(jì)算。除此之外,虛擬列和其他常規(guī)列是一樣的。注意,其他的標(biāo)準(zhǔn)庫(kù)可能需要數(shù)十 GB 的內(nèi)存才能實(shí)現(xiàn)相同操作。
好了,我們來(lái)繪制行程耗費(fèi)時(shí)間的分布:
紐約超過(guò) 10 億次出租車行程耗費(fèi)時(shí)間的直方圖
從上圖可以看到,95% 的出租車行程不到 30 分鐘就可以到達(dá)目的地,但有些行程可能花費(fèi)超過(guò) 4-5 個(gè)小時(shí)。你能想象在紐約市被困在出租車?yán)?3 個(gè)多小時(shí)的情景么?不管怎樣,我們豁達(dá)點(diǎn)只考慮少于 3 小時(shí)的行程:
對(duì)于出租車的平均速度,也選擇一個(gè)合理的范圍來(lái)查看:
出租車平均速度分布
根據(jù)分布趨平的位置,可以推斷出租車合理的平均速度在每小時(shí) 1 到 60 英里之間,由此可以更新篩選后的 DataFrame:
把關(guān)注點(diǎn)切換到出租車行程的費(fèi)用上,從describe方法的輸出可以看到 fare_amount、total_amount 和 tip_amount 列都有一些夸張的異常值。首先,這幾列都不應(yīng)該出現(xiàn)負(fù)值。
另一方面,有些數(shù)字表示一些幸運(yùn)的司機(jī)只開一次出租車就快要成為百萬(wàn)富翁了。讓我們?cè)诤侠淼姆秶鷥?nèi)查看這些數(shù)量的分布:
紐約超過(guò) 10 億次出租車行程的車費(fèi)、總額和小費(fèi)的分布。在筆記本上繪制這些圖表只用了 31 秒!
以上三個(gè)分布都有相當(dāng)長(zhǎng)的尾部。尾部可能有一些正確的值,而其他可能都是錯(cuò)誤的輸入。不管怎樣,我們保守一點(diǎn)只考慮 fare_amount、total_amount 和 tip_amount 低于 200 美元的行程。另外 fare_amount、total_amount 的值還要大于 0。
最終,在初步清理之后,看看還剩下多少出租車行程數(shù)據(jù)可供分析:
還剩下 11 億的行程!這些數(shù)據(jù)足以讓我們從出租車出行中獲得一些有價(jià)值的見解。
坐上駕駛座
假設(shè)我們是一名出租車司機(jī)或者一家出租車公司的經(jīng)理,有興趣使用這些數(shù)據(jù)來(lái)了解如何最大化利潤(rùn)、最小化成本或者僅僅是改善我們的工作生活。
首先,我們找出可以帶來(lái)平均最高收益的接客地點(diǎn)。簡(jiǎn)單講,只需要繪制出接客地點(diǎn)的熱力圖,并用顏色標(biāo)記平均價(jià)格,然后查看熱點(diǎn)地區(qū)。但是由于出租車司機(jī)需要自行承擔(dān)費(fèi)用,例如燃料費(fèi)。
因此,雖然將乘客載到較遠(yuǎn)的地方可能帶來(lái)更高車費(fèi),但同時(shí)也意味著更多的燃料消耗和時(shí)間損失。
另外,在偏遠(yuǎn)地區(qū)找一個(gè)回市中心某地的乘客可不是那么容易,而在沒有乘客的情況下回程就會(huì)很浪費(fèi)。一種解決方法是用車費(fèi)和行程距離之比的平均值對(duì)熱力圖進(jìn)行顏色編碼。我們來(lái)嘗試一下這兩種方法:
紐約熱力圖,顏色編碼:平均車費(fèi)(左),車費(fèi)與行程距離的平均比值
簡(jiǎn)單情況下,只關(guān)心所提供服務(wù)的最高車費(fèi)時(shí),紐約機(jī)場(chǎng)以及像范懷克高速公路(Van Wyck Expressway)和長(zhǎng)島高速公路(Long Island Expressway)這樣的主干道是最佳的載客區(qū)。
當(dāng)考慮行程距離時(shí),會(huì)得到一張不同的圖像。范懷克高速公路、長(zhǎng)島高速公路以及機(jī)場(chǎng)仍然是搭載乘客的好地方,但它們?cè)诘貓D上的重要性要低得多。而在哈德遜河(Hudson river)的西側(cè)出現(xiàn)了一些新的熱點(diǎn)地區(qū),看起來(lái)利潤(rùn)頗豐。
作為出租車司機(jī),實(shí)踐中可以做得很靈活。要想更好地利用這種靈活性,除了知道要在哪里載客之外,了解什么時(shí)候出車最賺錢也很有用。為回答這個(gè)問(wèn)題,我們繪制一個(gè)圖表來(lái)展示每天和每小時(shí)的平均車費(fèi)與行程距離之比。
一周中每天以及一天中每小時(shí)的車費(fèi)與行程的平均比值
上面的圖很符合常識(shí):高峰時(shí)段最掙錢,特別是工作日的中午。作為出租車司機(jī),收入的一部分要交給出租車公司,所以我們可能會(huì)對(duì)哪天、哪個(gè)時(shí)段顧客給的小費(fèi)最多感興趣。繪制一個(gè)類似的圖展示平均小費(fèi)比例:
一周中每天以及一天中每小時(shí)的小費(fèi)比例平均值
上圖很有意思,它告訴我們?cè)谝恢苤星皫滋斓脑缟?7-10 點(diǎn)和晚上 7-10 點(diǎn)乘客給司機(jī)的小費(fèi)最多。如果在凌晨 3-4 點(diǎn)接乘客,不要指望會(huì)有大額小費(fèi)。
結(jié)合最后兩張圖的經(jīng)驗(yàn),早上 8 點(diǎn)到 10 點(diǎn)是最好的工作時(shí)間,司機(jī)可以得到較多的車費(fèi)(每英里)和小費(fèi)。
發(fā)動(dòng)引擎
在本文的前半部分,我們簡(jiǎn)要地關(guān)注了trip_distance列,在給它清理異常值時(shí),只保留了低于 100 英里的行程。但這個(gè)邊界值仍然很大,尤其是考慮到 Yellow Taxi 公司主要在曼哈頓運(yùn)營(yíng)。
trip_distance描述出租車從上車點(diǎn)到下車點(diǎn)的行駛距離,但是在確切的兩個(gè)上車點(diǎn)和下車點(diǎn)之間,通常有多條不同距離的路線可以選擇,比如為了避開交通堵塞和道路施工的情況。
所以,相對(duì)于trip_distance列,我們計(jì)算一項(xiàng)接送位置之間可能的最短距離,命名為arc_distance:
對(duì)于用 numpy 編寫的復(fù)雜表達(dá)式,vaex 可以借助 Numba、Pythran 甚至 CUDA(需要 NVIDIA GPU)通過(guò)即時(shí)編譯來(lái)極大提高運(yùn)算速度。
arc_distance的計(jì)算公式非常復(fù)雜,它包含了大量的三角函數(shù)和數(shù)學(xué)運(yùn)算,在處理大型數(shù)據(jù)集時(shí)計(jì)算代價(jià)非常高。如果表達(dá)式或函數(shù)只用到了 Python 運(yùn)算符和 Numpy 庫(kù)的方法,Vaex 會(huì)使用計(jì)算機(jī)的所有核心來(lái)并行計(jì)算。
除此之外,Vaex 通過(guò) Numba (使用 LLVM)和 Pythran (通過(guò) C++ 加速)支持即時(shí)編譯從而提供更好性能。如果你碰巧有 NVIDIA 顯卡,就可以通過(guò)jit_cuda方法來(lái)運(yùn)用 CUDA 以獲取更快的性能。
我們來(lái)繪制 trip_distance 和 arc_distance 的分布:
左:trip_distance 和 arc_distance 的比較;右:arc_distance<100 米時(shí) trip_distance 的分布。
有意思的是,arc_distance從來(lái)沒有超過(guò) 21 英里,但出租車實(shí)際行駛距離可能是它的 5 倍。事實(shí)上,有數(shù)百萬(wàn)次的行程下客點(diǎn)距離上客點(diǎn)只有 100 米(0.06 英里)!
過(guò)去幾年的 Yellow Taxis
我們今天使用數(shù)據(jù)集時(shí)間上跨越了 7 年。隨著時(shí)間流逝,人們的興趣如何演變可能是件有趣的事。使用 Vaex 可以進(jìn)行快速的核外分組和聚合操作。
我們來(lái)看看 7 年間車費(fèi)和行程距離都有什么變化:
在四核處理器的筆記本電腦上,對(duì)擁有超過(guò) 10 億樣本的 Vaex DataFrame 進(jìn)行 8 個(gè)聚合的分組操作只需不到 2 分鐘。
在上面的代碼塊中,我們執(zhí)行分組操作,然后執(zhí)行 8 個(gè)聚合,其中有 2 個(gè)位于虛擬列上。上面的代碼塊在我的筆記本電腦上執(zhí)行耗時(shí)不到 2 分鐘。鑒于我們使用的數(shù)據(jù)包含超過(guò) 10 億條樣本,這是相當(dāng)驚人的。
總之,我們來(lái)看看結(jié)果,以下是多年來(lái)乘坐出租車的費(fèi)用的變化情況:
每年的平均車費(fèi)和總金額以及乘客所付的小費(fèi)比例
可以看出隨著時(shí)間流逝,出租車費(fèi)和小費(fèi)都在上漲。再來(lái)看看出租車每年的平均trip_disrance和arc_distance:
出租車每年的行程和弧距
上圖顯示,trip_distance和arc_distance都有一個(gè)小的增長(zhǎng),這意味著,平均而言,人們傾向于每年走得更遠(yuǎn)一點(diǎn)。
給錢吧
在旅程結(jié)束之前,我們?cè)偻R徽?#xff0c;調(diào)查一下乘客是如何支付乘車費(fèi)用的。數(shù)據(jù)集中包含了payment_type,來(lái)看看它都包含什么值:
從數(shù)據(jù)集文檔中,可以看出只有 6 個(gè)有效條目:
- 1 = 信用卡支付
- 2 = 現(xiàn)金付款
- 3 = 免費(fèi)
- 4 = 爭(zhēng)議
- 5 = 未知
- 6 = 無(wú)效行程
由此,可以簡(jiǎn)單地把payment_type映射到整數(shù):
現(xiàn)在可以根據(jù)每年的數(shù)據(jù)進(jìn)行分組,看看紐約人在支付打車費(fèi)用方面的習(xí)慣是如何變化的:
每年的支付方式
可以發(fā)現(xiàn)隨著時(shí)間的推移,信用卡支付逐漸變得比現(xiàn)金支付更加頻繁。我們果然是生活在數(shù)字時(shí)代!在上面的代碼塊中,一旦完成數(shù)據(jù)聚合,小型的 Vaex DataFrame 可以輕易地轉(zhuǎn)換為 Pandas DataFrame,從而傳遞給 Seaborn 。不用費(fèi)勁在這重新發(fā)明輪子。
最后通過(guò)繪制現(xiàn)金支付和信用卡支付之間的比例,來(lái)查看付款方法是否取決于當(dāng)天的時(shí)間或者星期幾。為此,先創(chuàng)建一個(gè)過(guò)濾器,篩出用現(xiàn)金或者信用卡的行程。
下一步是我最喜歡的 Vaex 的特性之一:帶選擇的聚合。其他庫(kù)要求對(duì)每個(gè)支付方法篩選出單獨(dú)的 DataFrame 進(jìn)行聚合,然后再合并為一個(gè)。
而使用 Vaex,可以在聚合函數(shù)中提供多個(gè)選擇從而一步到位。這非常方便,只需進(jìn)行一次數(shù)據(jù)傳遞,能提供更好性能。之后就可以用標(biāo)準(zhǔn)方式繪制 DataFrame:
在給定的時(shí)間和星期中某一天,現(xiàn)金和信用卡支付的比例
從上圖可以發(fā)現(xiàn)其模式非常類似于之前的一周中每天以及一天中每小時(shí)的小費(fèi)比例。從這兩個(gè)圖推測(cè),信用卡支付的乘客傾向于比現(xiàn)金支付的乘客給更多的小費(fèi)。
要想知道這是不是真的,我希望你去嘗試把它弄清楚,因?yàn)楝F(xiàn)在你已經(jīng)擁有了知識(shí)、工具和數(shù)據(jù)!你可以從這個(gè) Jupyter notebook 獲取更到額外提示。
抵達(dá)目的地
我希望這篇文章是對(duì) Vaex 一個(gè)有用的介紹,它會(huì)幫你緩解可能面臨的一些“麻煩數(shù)據(jù)”的問(wèn)題,至少在涉及表數(shù)據(jù)集時(shí)是這樣的。如果你對(duì)探索本文中用到的數(shù)據(jù)集感興趣,可以直接在 S3 中配合 Vaex 使用它,請(qǐng)參閱完整的 Jupyter notebook 了解如何實(shí)現(xiàn)。
有了 Vaex,你可以在短短幾秒內(nèi)遍歷超過(guò) 10 億行數(shù)據(jù),計(jì)算各種統(tǒng)計(jì)、聚合并產(chǎn)出信息圖表,這一切都能在你的筆記本電腦上完成。它免費(fèi)且開源,你可以嘗試一下!
數(shù)據(jù)科學(xué)快樂(lè)!
總結(jié)
以上是生活随笔為你收集整理的dataframe 如何选中某列的一行_如何用 Python 在笔记本上分析 100GB 数据?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 最小表达式_C# 09.找最大和最小的数
- 下一篇: python获取字符串首字母_[Pyth