想象一下,分析紐約市數百萬次的拼車旅程 — — 跟蹤各自治市的模式、比較服務定價或確定有利可圖的取車地點。公開發布的 New York City Taxi and Limousine Commission (TLC) 行程記錄數據包含有價值的信息,可以揭示具有劃時代意義的見解,但由于數據量龐大,分析師需要等待數小時才能得出結果。
這些延遲會中斷分析流程并限制業務響應能力。出租車公司、城市規劃部門和金融公司的數據科學家需要及時獲得見解,以便做出關鍵決策。等待 9 分鐘與 5 秒之間的區別不僅在于方便,還在于競爭優勢。
現代數據科學非常適合 GPU 并行。過濾和轉換大型數據集等操作需要在數百萬個獨立數據點中應用相同的功能。在處理 NYC 拼車數據集時,GPU 可以同時評估數千次拼車的計算,而不是按順序進行,從而大幅縮短計算時間。
盡管具有這些優勢,但獲取 GPU 的強大功能通常需要專門的編程模型和復雜的云配置。最近的發展使得任何具備基本 Python 技能的人都可以使用 GPU 加速的數據科學,從而無需專門的硬件投資。
本文將介紹如何將 NVIDIA RAPIDS (NVIDIA CUDA-X 庫的一部分) 和云 GPU 與云平臺 Coiled 結合使用,該平臺旨在簡化大規模運行 Python 工作負載的過程。
預備知識
NVIDIA RAPIDS:GPU 加速適用于 PyData 生態系統
NVIDIA RAPIDS 為數據科學工作負載提供 GPU 加速,無需更改代碼。cudf.pandas 加速器支持 GPU 即時執行 pandas 運算:
% load_ext cudf.pandas import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns |
詳細了解 NVIDIA cuDF 如何將 pandas 加速高達 150 倍。
云 GPU?
許多云平臺支持即時訪問最新的 NVIDIA GPU 架構,無需硬件刷新周期,可根據計算需求靈活擴展資源。這種可用性為各種規模的團隊普及了先進的 GPU 加速。
這些先進 GPU 的性能優勢改變了數據分析能力。借助 NYC 拼車數據集,以前在 CPU 上花費幾分鐘的操作現在只需幾秒鐘即可完成,從而實現從根本上改變分析工作流程的迭代探索。數據科學家可以測試更多假設,探索更多變量,并通過近乎即時的反饋完善模型,從而獲得更深入的見解和發現,否則這些見解和發現可能會被隱藏起來。
雖然云環境通常涉及配置挑戰,但 Coiled 等專用平臺可以簡化 GPU 工作流的此過程。通過抽象化資源配置和環境設置,這些解決方案使數據科學家能夠專注于分析而不是基礎設施管理,通過消除高級計算能力的技術障礙來加速創新。
連續筆記本?
使用以下命令啟動交互式 Jupyter notebook 會話: 連續筆記本 然后,通過 notebook 服務運行 RAPIDS notebook 容器。
coiled notebook start --gpu --container nvcr.io/nvidia/rapidsai/notebooks:25.02-cuda12.8-py3.12
請注意,--gpu
標志將自動選擇搭載 NVIDIA T4 GPU 的 g4dn.xlarge 實例。您可以添加 --vm-type
標志,以明確選擇具有不同 GPU 配置的其他機器類型。例如,要選擇配備四個 L4 GPU 的計算機,您需要運行以下命令。
coiled notebook start --gpu --vm-type g6.24xlarge --container nvcr.io/nvidia/rapidsai/notebooks:25.02-cuda12.8-py3.12
要訪問 Jupyter,請單擊終端中顯示的鏈接。


如上面的代碼片段所示,從本地開發過渡到云 GPU 執行是無縫的,并且使用 RAPIDS Notebook 鏡像提供了一種加速工作流程的便捷方法,從根本上改變了處理大規模問題的方式。
連續運行?
您還可以通過 Coiled Run 在臨時 VM 中運行 Python 腳本。此操作會從云端啟動 VM,使用 package sync 從本地環境復制所有必要的軟件包,運行腳本并關閉 VM。
coiled run python my_code.py # Boots a VM on the cloud, runs the scripts, then shuts down again
使用 RAPIDS 容器在遠程環境中運行 GPU 代碼。您可以將 coiled CLI 設置為在執行完成后將 VM 保留幾分鐘,以防您想再次運行它并重復使用相同的硬件。
$ coiled run --gpu --name rapids-demo --keepalive 5m --container nvcr.io/nvidia/rapidsai/base:25.02-cuda12.8-py3.12
與 cudf.pandas CLI 工具搭配使用時,效果非常好 。
$ coiled run --gpu --name rapids-demo --keepalive 5m --container nvcr.io/nvidia/rapidsai/base:25.02-cuda12.8-py3.12 -- python -m cudf.pandas cudf_pandas_coiled_demo.py
Output
------
This container image and its contents are governed by the NVIDIA Deep Learning Container License.
By pulling and using the container, you accept the terms and conditions of this license:
https://developer.download.nvidia.com/licenses/NVIDIA_Deep_Learning_Container_License.pdf
Calculate violations by state took: 3.470 seconds
Calculate violations by vehicle type took: 0.145 seconds
Calculate violations by day of week took: 1.238 seconds
在 NVIDIA RAPIDS 部署文檔中,您將找到本實驗中使用的 Jupyter Notebook 。您可以下載并運行它,以重現本文中提到的性能數字。
分析 ride-share 數據集
紐約市 TLC 行程記錄數據 可通過 S3 獲取。此數據也可以在 Coiled 的 S3 存儲桶 (用于本示例) 上以 parquet 格式提供,并被劃分為 100 MB 的文件。
我使用了 60 個分區,對應最新記錄的數據,并轉換為大約 64.8M 行數據。通過對這些數據執行不同的運算,可以了解使用 cudf.pandas 加速器與 vanilla Pandas 相比所實現的加速。
我使用了 g6.24xlarge EC2 實例,如上一部分中的代碼片段所示。這臺機器配備四個 NVIDIA L4 Tensor Core GPU、96 個 vCPU 和 384 GB 內存。
以下展示了無需更改代碼即可加速的一些可能操作。
加載數據并優化數據類型
從 S3 加載數據需結合使用 s3fs 和 Pandas 上的 read_parquet() 函數。
import pandas as pd path_files = [] for i in range ( 660 , 720 ): path_files.append(pd.read_parquet(f "s3://coiled-data/uber/part.{i}.parquet" , filesystem = fs)) data = pd.concat(path_files, ignore_index = True ) |
為了優化內存使用,我將所有字符串和對象類型轉換為分類值,并分別將 int32 和 float64 轉換為 int16 和 float32。
# Convert data types to save memory for col in data.columns: if data[col].dtype = = 'int32' : if data[col]. min () > = - 32768 and data[col]. max () < = 32767 : data[col] = data[col].astype( 'int16' ) if data[col].dtype = = 'float64' : data[col] = data[col].astype( 'float32' ) if data[col].dtype = = 'string' or data[col].dtype = = 'object' : data[col] = data[col].astype( 'category' ) |
使用 Pandas 時,此操作需要 15 秒,但使用 cudf.pandas 加速器時,僅需 1 秒。
按公司查找每月收入和利潤
接下來,我想了解數據中每個唯一月份各共享出行公司的收入和利潤。該數據集包含關于乘客支付的車費的幾列,包括基本乘客車費、過路費和銷售稅。* 為了計算公司的總收入,我匯總了與乘客支付的車費相關的所有列,并將其存儲在名為 total_fare 的列中。然后,我逐組執行操作,按公司和月份對這些數據進行分組。
data[ 'pickup_month' ] = data[ 'pickup_datetime' ].dt.month data[ 'total_fare' ] = data[ 'base_passenger_fare' ] + data[ 'tolls' ] + data[ 'bcf' ] + data[ 'sales_tax' ] + data[ 'congestion_surcharge' ] + data[ 'airport_fee' ] grouped = data.groupby([ 'company' , 'pickup_month' ]).agg({ 'company' : 'count' , 'total_fare' : [ 'sum' , 'mean' ], 'driver_pay' : 'sum' , 'tips' : 'sum' }).reset_index() grouped.columns = [ 'company' , 'pickup_month' , 'trip_count' , 'total_revenue' , 'avg_fare' , 'total_driver_pay' , 'total_tips' ] grouped[ 'total_driver_payout' ] = grouped[ 'total_driver_pay' ] + grouped[ 'total_tips' ] grouped = grouped[[ 'company' , 'pickup_month' , 'trip_count' , 'total_revenue' , 'avg_fare' , 'total_driver_payout' ]] grouped = grouped.sort_values([ 'company' , 'pickup_month' ]) grouped[ 'profit' ] = grouped[ 'total_revenue' ] - grouped[ 'total_driver_payout' ] grouped.head() |
在 Pandas 上,此操作大約需要 4.7 秒,但啟用 cudf.pandas 加速器后,僅需 2.67 秒即可完成。
根據持續時間對路線進行分類
為了了解用戶定義函數 (User-Defined Functions, UDF) 中的加速情況,我將數據中的所有行程分為以下三類:
- 短程 (在 trip_category 列中用 0 表示) 表示行程少于 10 分鐘。
- 中度 (在 trip_category 列中用 1 表示) 表示 10 到 20 分鐘的行程。
- 長途 (在 trip_category 列中用 2 表示) ,適用于 20 分鐘以上的行程。
然后,我使用這些類別來計算每個類別中的平均車費和出行次數。
def categorize_trip(row): if row[ 'trip_time' ] < 600 : # Less than 10 minutes return 0 elif row[ 'trip_time' ] < 1200 : # 10-20 minutes return 1 else : # More than 20 minutes return 2 # Apply UDF data[ 'trip_category' ] = data. apply (categorize_trip, axis = 1 ) # Create a mapping for trip categories trip_category_map = { 0 : 'short' , 1 : 'medium' , 2 : 'long' } # Group by trip category category_stats = data.groupby( 'trip_category' ).agg({ 'total_fare' : [ 'mean' , 'sum' ], 'trip_time' : 'count' }) # Rename the index with descriptive labels category_stats.index = category_stats.index. map ( lambda x: f "{trip_category_map[x]}" ) category_stats |
在 Pandas 上執行此操作需要 408 秒,但啟用 cudf.pandas 加速器后,只需 0.2 秒即可完成。這是因為需要對數據集中的每一行應用 categorize_trip 函數,但該函數本質上是一項可并行的任務,因此利用 GPU 可顯著提高性能。
查找常用路線
TLC 數據集包含列 PULocationID 和 DOLocationID,根據 NYC TLC 的出租車區域表示區域和自治市信息。您可以在以下位置找到信息并查找與索引對應的區域: CSV 格式 。
現在,我們可以將此數據集合并到 trips 數據幀中,找出十大常用路線。
taxi_zones = pd.read_csv( 'taxi_zones.csv' , usecols = [ 'LocationID' , 'zone' , 'borough' ]) #Convert PULocationID to pickup_location combining zone and borough information data = pd.merge(data, taxi_zones, left_on = 'PULocationID' , right_on = 'LocationID' , how = 'left' ) for col in [ 'zone' , 'borough' ]: data[col] = data[col].fillna( 'NA' ) data[ 'pickup_location' ] = data[ 'zone' ] + ',' + data[ 'borough' ] data.drop([ 'LocationID' , 'zone' , 'borough' ], axis = 1 , inplace = True ) #Doing the same for dropoff location location_group = data.groupby([ 'pickup_location' , 'dropoff_location' ]).size().reset_index(name = 'ride_count' ) location_group = location_group.sort_values( 'ride_count' , ascending = False ) # Identify top 10 hotspots top_hotspots = location_group.head( 10 ) print ( "Top 10 Pickup and Dropoff Hotspots:" ) print (top_hotspots) |
在 Pandas 上,每個合并操作大約需要 30 秒,但使用 cudf.pandas 加速器只需 1.3 秒。
總體時間比較?
我們來比較一下整個示例 Notebook 的運行時間 。在 CPU 上執行標準 Pandas 需要 18 分鐘 45 秒。相比之下,使用 cudf.pandas 的 GPU 加速版本僅在 2 分鐘 6 秒內執行了相同的操作,僅執行時間就提高了 8.9 倍。
考慮到基礎設施設置開銷 (在 Coiled 上使用 RAPIDS Docker 鏡像置備配備 GPU 的 EC2 實例需要 2 分鐘 45 秒) ,總運行時間為 4 分鐘 50 秒。與基于 CPU 的實施方案相比,這仍然代表著性能提升了 3.9 倍,只需很少的基礎設施設置即可實現。
這些指標清楚地表明,GPU 加速為涉及大數據的計算密集型操作帶來了巨大優勢,尤其是涉及元素級轉換和用戶定義函數的操作。
總結?
通過利用 cudf.pandas,我們實現了顯著的性能提升,從整體加速的 8.9 倍提升到 UDF 操作的 30 倍,并且無需更改代碼。Coiled 的平臺通過自動調配和自動擴展資源降低了 GPU 的云計算復雜性,通過在使用后關閉來確保資源設置的簡單性和成本效益。熟悉的語法與簡化的基礎架構管理相結合,為數據科學家創建了一個強大的工具包,以加速分析工作流程、縮短開發周期,并從大型數據集中提取更多價值,同時保持對見解而非基礎架構的關注。
了解詳情:
- 開始使用 RAPIDS
- 安裝 盤管
- cudf.pandas 的 API 參考
?