使用Python「秒開」100GB+數據

如果你50GB甚至500GB的數據集,打開他們都很困難了,更別說分析了。

在處理這樣的數據集時,我們通常採用3種方法。

第一種對數據進抽樣:這裡的缺點是顯而易見的,樣本數據能否代表整個數據。

第二種使用分佈式計算:雖然在某些情況下這是一種有效的方法,但是它帶來了管理和維護集群的巨大開銷。想象一下,必須為一個剛好超出RAM範圍的數據集設置一個集群,比如在30-50GB範圍內。這有點過分了。

第三種租用一個強大的雲服務:例如,AWS提供了具有TB內存的實例。在這種情況下,你仍然需要管理雲數據,每次啟動時都要等待一個個的數據傳輸。處理將數據放到雲上所帶來的遵從性問題,以及處理在遠程機器上工作所帶來的所有不便。更不用說成本了,儘管開始時成本很低,但隨著時間的推移,成本往往會越來越高。

在本文中,我們將向你展示一種新的方法: 一種更快、更安全、總體上更方便的方法,可以使用幾乎任意大小的數據進行數據研究分析 ,只要它能夠適用於筆記本電腦、臺式機或服務器的硬盤驅動器。

使用Python「秒開」100GB+數據

Vaex是一個開源的DataFrame庫,它可以對錶格數據集進行可視化、探索、分析,甚至機器學習,這些數據集和你的硬盤驅動器一樣大。 它可以在一個n維網格上每秒計算超過10億(10^9)個對象的平均值、和、計數、標準差等統計信息 。可視化使用直方圖、使用直方圖、密度圖和3D立體渲染進行可視化。為此, Vaex採用了內存映射、高效的外核算法和延遲計算等概念來獲得最佳性能(不浪費內存) 。所有這些都封裝在一個類似Pandas的API中。

GitHub: https://github.com/vaexio/vaex

使用Python「秒開」100GB+數據

為了說明Vaex的性能,我們為大家舉個例子。

數據準備

我們使用紐約市出租車的數據集,該數據集包含了出租車在2009年至2015年間超過10億次出租車出行的信息。數據可從下面的網站下載,並以 CSV 格式提供:

https://www1.nyc.gov/site/tlc/about/tlc-trip-record-data.page

使用Python「秒開」100GB+數據

數據清洗

第一步將數據轉換為內存映射文件格式,如Apache Arrow、Apache Parque 或HDF5。一旦數據成為內存映射格式,使用Vaex打開它是瞬間的(數據的磁盤大小超過100GB)。有多塊?

0.052秒!

將CSV數據轉換為HDF5的代碼如下:

使用Python「秒開」100GB+數據

為什麼這麼快?

當你使用Vaex打開內存映射文件時, 實際上沒有數據讀取。Vaex只讀取文件元數據,比如磁盤上數據的位置、數據結構(行數、列數、列名和類型)、文件描述等等 。那麼,如果我們想要檢查或與數據交互呢?打開一個數據集會得到一個標準的DataFrame:

使用Python「秒開」100GB+數據

再次注意,單元執行時間非常短。這是因為顯示Vaex DataFrame或列只需要從磁盤讀取前5行和後5行。這就引出了另一個重要的問題: V aex只會在必要時遍歷整個數據集,而且它會盡可能少地遍歷數據。

現在開始清理數據集。一個好的開始方法是使用 describe 方法獲得數據的概覽:

使用Python「秒開」100GB+數據

describe 方法很好地說明了Vaex的性能和效率:所有這些統計數據都是在MacBook Pro(15英寸,2018年,2.6GHz Intel Core i7,32GB RAM)上用 不到3分鐘 計算出來的。其他庫或方法需要分佈式計算或超過100GB的雲才能預先相同的計算。 有了Vaex,你所需要的只是數據,以及只有幾GB內存的筆記本電腦。

查看description的輸出,很容易注意到數據包含一些嚴重的異常值。由於我們使用的是如此龐大的數據集,直方圖是最有效的可視化方法。用Vaex創建和顯示柱狀圖和熱圖是如此的快,這樣的圖可又是交互式的!

<code>df.plot_widget(df.pickup_longitude,               df.pickup_latitude,               shape=512,               limits='minmax',               f='log1p',               colormap='plasma')/<code>
使用Python「秒開」100GB+數據

一旦我們決定了想要關注紐約的哪個區域,我們就可以簡單地創建一個過濾後的 DataFrame:

使用Python「秒開」100GB+數據

上面的代碼塊的優點在於: 它所需要的內存可以忽略不計 !在過濾Vaex DataFrame時,不會生成數據副本。相反,只創建對原始對象的引用,並在其上應用二進制掩碼。掩碼選擇顯示哪些行並用於將來的計算。這為我們節省了100GB的RAM,如果要複製數據,就需要這樣做,就像現在許多標準的數據分析所做的那樣。

現在,讓我們檢查一下 passenger_count 列。單次乘坐出租車的最高記錄是255人,這似乎有點極端。讓我們數一數每一名乘客的出行次數。使用 value_counts 方法很容易做到這一點:

使用Python「秒開」100GB+數據

應用10億行的“value_counts”方法只需要20秒!

從上圖中我們可以看出,乘客超過6人的出行很可能是罕見的異常值,或者是數據輸入錯誤。也有大量的出現,沒有(0名)乘客。既然現在我們還不知道這些旅行是否合法,那就讓我們把它們過濾掉吧。

讓我們做一個關於類似出行距離的操作。由於這是一個連續的變量,我們可以畫出出行距離的分佈。看看最小和最大的距離,讓我們用一個更合理的範圍來繪製直方圖。

使用Python「秒開」100GB+數據

從上圖中我們可以看到,出行次數隨著距離的增加而減少。在大約100英里的距離上,分佈有很大的下降。現在,我們用這個作為分界點,來消除基於行程距離的極端異常值:

出行距離列中存在的極端離群值是調查出租車出行時間和平均速度的原因。這些特徵在數據集中是不容易獲得的,但是計算起來很簡單:

使用Python「秒開」100GB+數據

上面的代碼塊需要零內存,不需要執行時間! 這是因為代碼會創建虛擬列。 這些列只包含數學表達式,僅在需要時才計算它們。 否則,虛列的行為與任何其他常規列一樣。注意,其他標準庫需要10s的GB內存來完成相同的操作。

讓我們畫出行程時間的分佈圖:

使用Python「秒開」100GB+數據

從上圖我們可以看到,95% 的出租車行程花費不到30分鐘到達目的地,儘管有些行程花費了4-5個小時。你能想象在紐約被困在出租車裡超過3個小時的情景嗎?考慮所有總共不超過3小時的行程:

現在讓我們看一下出租車的平均速度,同時為數據限制選擇一個合理的範圍:

使用Python「秒開」100GB+數據

根據分佈趨平的地方,我們可以推斷出合理的出租車平均速度在每小時1到60英里之間,因此我們可以更新過濾後的dataframe:

讓我們把焦點轉移到出租車的費用上。從describe方法的輸出中,我們可以看到在fare_amount、total_amount和tip_amount列中存在一些異常值。對於初學者來說,這些列中的任何值都不應該是負值。讓我們看看這些數據的分佈在一個相對合理的範圍內:

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

我們看到上面的三個分佈都有相當長的尾部。尾部的一些值可能是正確的,而其他值可能是錯誤的數據輸入。無論如何,讓我們現在保守一點,只考慮票價為fare_amount、total_amount和tip_amount低於200美元的乘客。我們還要求fare_amount、total_amount的值大於0。

最後,在所有初始數據清理之後,讓我們看看還剩下多少出租車次數供我們分析:

超過11億次的出行!

具體分析

假設我們使用這個數據集來學習 如何最大化利潤,最小化成本

讓我們從找出從平均值而言,能帶來較好收入的載客地點開始。我們只需繪製一張熱點地區接送地點的熱圖,對平均票價進行顏色編碼,然後查看熱點地區。然而,出租車司機也有自己的成本。例如,燃料費用。因此,把乘客帶到很遠的地方可能會導致更高的票價,但這也意味著更大的燃料消耗和時間損失。此外,從偏遠的地方載一個乘客去市中心可能不那麼容易,因此在沒有乘客的情況下開車回去可能會很貴。一種解釋的方法是,用票價金額與出行距離之比的平均值來表示熱圖的顏色。讓我們考慮一下這兩種方法:

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

出租車司機是一份相當靈活的工作。除了知道應該去哪裡,如果讓他們知道什麼時候開車最賺錢也是很有用的。為了回答這個問題,讓我們製作一個圖表,顯示每天和每小時的平均票價與行程的比率:

使用Python「秒開」100GB+數據

上面的數字是合理的,最好的收入發生在高峰時間, 特別是中午 ,在工作日。作為一名出租車司機,我們收入的一部分給了出租車公司,所以我們可能會對哪一天、哪段時間顧客給的小費最多感興趣。讓我們製作一個類似的圖,這次顯示的是平均小費的比例:

使用Python「秒開」100GB+數據

上面的結論很有趣。它告訴我們, 乘客在早上7點到10點之間給出租車司機的小費最多 ,如果你在凌晨3點或4點接乘客,不要指望會有大額小費。

更深入的分析

在本文的前一部分中,我們簡要地集中討論了trip_distance列,在去除異常值時,我們保留了所有值小於100英里的行程。但這仍然是一個相當大的臨界值,尤其是考慮到Yellow Taxi公司主要在曼哈頓運營。trip_distance列描述出租車從上客點到下客點的距離。然而,人們經常可以選擇不同的路線,在兩個確切的上落地點之間有不同的距離,例如為了避免交通堵塞或道路工程。因此,作為trip_distance列的一個對應項,讓我們計算接送位置之間可能的最短距離,我們稱之為arc_distance:

使用Python「秒開」100GB+數據

對於用Numpy編寫的複雜表達式,vaex可以在Numba、Pythran甚至CUDA(如果你有NVIDIA GPU的話)的幫助下使用即時編譯來極大地提高你的計算速度。

arc_distance的計算公式非常複雜,它包含了大量的三角函數和算術知識,特別是在處理大數據集的情況下,計算量很大。如果表達式或函數僅使用來自Numpy包的Python操作和方法編寫,Vaex將使用計算機的所有核心並行地計算它。除此之外,Vaex通過Numba(使用LLVM)或Pythran(通過C++加速)支持即時編譯,從而提供更好的性能。如果你有NVIDIA顯卡,你可以通過jit_cuda方法使用CUDA來獲得更快的性能。

無論如何,我們來畫一下trip_distance和arc_distance的分佈:

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

有趣的是,arc_distance從未超過21英里,但出租車實際行駛的距離可能是它的5倍。事實上,在數百萬次的出租車行程中,落客點距離接客點只有100米(0.06英里)。

我們這次試用的數據集跨越了7年。我們可以看看在這段時間裡,人們對某些東西的興趣是如何演變的,可能會很有趣。使用Vaex,我們可以進行out-of-core group-by和aggregation操作。讓我們來看看這7年中票價和旅行距離的變化:

使用Python「秒開」100GB+數據

在擁有四核處理器的筆記本電腦上,對一個擁有超過10億個樣本的Vaex DataFrame進行8個聚合的分組操作只需不到2分鐘。

在上面的單元格格中,我們執行groupby操作,然後執行8個聚合,其中2個位於虛擬列上。上面的單元格在我們的筆記本電腦上執行不到2分鐘。考慮到我們使用的數據包含超過10億個樣本,這是相當令人印象深刻的。不管怎樣,讓我們看看結果。以下是多年來乘坐出租車的費用是如何演變的:

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

我們看到,隨著時間的流逝,出租車費和小費都在上漲。現在讓我們看看出租車的trip_distance 和arc_distance作為年的函數:

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

上圖顯示,trip_distance和arc_distance都有一個小的增長,這意味著,平均而言,人們傾向於每年走得更遠一點。

讓我們再調查一下乘客是如何支付他們的車費的:payment_type列,讓我們看看它包含的值:

使用Python「秒開」100GB+數據

從數據集中,我們可以看到只有6個有效的條目:

1=信用卡支付

2=現金支付

3=不收費

4=糾紛

5=未知

6=無效行程

因此,我們可以簡單地將payment_type列中的條目映射到整數:

使用Python「秒開」100GB+數據

現在我們可以根據每年的數據進行分組,看看紐約人在支付打車費用方面的習慣是如何改變的:

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

我們發現,隨著時間的推移,信用卡支付慢慢變得比現金支付更頻繁。在上面的代碼塊中,一旦我們聚合了數據,小型的Vaex dataframe就可以很容易地轉換為Pandas DataFrame,將其傳遞給Seaborn。

最後,讓我們通過繪製現金支付與信用卡支付之間的比率來查看付款方法是否取決於當天的時間或星期幾。為此,我們將首先創建一個過濾器,它只選擇用現金或信用卡支付。下一步是具有Vaex特色功能的操作:帶有選擇的聚合。其他庫要求對每個支付方法進行聚合,然後將這些支付方法後來合併為一個支付方法。 另一方面,我們可以通過在聚合函數中提供的參數,一步完成這個操作。 這非常方便,只需要傳遞一次數據,就可以獲得更好的性能。 然後,我們可以用標準的方式繪製出最終的DataFrame:

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

從上面的圖可以看出,顯示的小費百分比可以作為一週的某天或一天的某時段的函數。從這兩個圖中表明,用信用卡支付的乘客比用現金支付的乘客更傾向於給小費。看看分佈:

使用Python「秒開」100GB+數據

乘客多久付一次小費?

使用Python「秒開」100GB+數據

但是讓我們看看_fareamount和_totalamount的分佈,這取決於支付方式是刷卡還是現金。

使用Python「秒開」100GB+數據

使用Python「秒開」100GB+數據

有了Vaex,你可以在短短几秒鐘內瀏覽超過10億行數據,計算各種統計數據、聚合信息,並生成信息圖表,而這一切都是在你自己的筆記本電腦上完成的。 而且它是免費和開源的!


分享到:


相關文章: