• <xmp id="om0om">
  • <table id="om0om"><noscript id="om0om"></noscript></table>
  • 3 月 19 日下午 2 點,鎖定 NVIDIA AI 網絡中文專場。立即注冊觀看
    數據科學

    使用 NVIDIA cuDF API 中最新的 UDF 增強功能更快地原型制作

    在過去的幾個版本中, NVIDIA cuDF 團隊為用戶定義函數( UDF )添加了幾個新特性,這些特性可以簡化開發過程,同時提高總體性能。在本文中,我將介紹新的 UDF 增強功能,并展示如何在自己的應用程序中利用它們:

    • cuDF Series.apply API 及其使用方法
    • cuDF DataFrame.apply API 以及如何根據“行”編寫自定義項
    • 使用兩個 apply API 增強對缺失數據的支持
    • 帶有計時的真實用例示例
    • 實際考慮、限制和未來計劃

    為 cuDF 系列應用 API

    如果您不熟悉 pandas , series apply 是用于將任意 Python 函數映射到單個數據系列的主要入口點。例如,您可能希望使用已編寫為 Python 函數的公式將攝氏溫度轉換為華氏溫度。

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    下面是運行此代碼的輸出后的快速刷新:

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    從技術上講,您可以在函數f中編寫任何有效的 Python 代碼, pandas 在序列上循環運行函數。這使得apply在 pandas 環境中非常靈活,因為任何 UDF 都可以成功應用,只要它能夠成功處理所有輸入數據,甚至是依賴于外部庫或期望或返回任意 Python 對象的 UDF 。

    但是,這種靈活性是以性能為代價的。由于各種原因,在長循環中運行 Python 函數并不是一種有效的策略(例如,從一開始就對 Python 進行解釋)。因此,如果您的 UDF 更簡單,例如那些對標量值進行純數學運算的 UDF ,那么這種性能約束可能會令人沮喪。

    幸運的是,這些用例正是 cuDF 構建的目的。最近在 UDF 范圍內的 cuDF 改進促使引入等效的apply API :

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    如果您熟悉 pandas ,您可以生成與使用 pandas 處理數值相同的結果。唯一顯著的區別是,得到的數據總是 cuDF dtype,而不是object,這通常是熊貓的情況。

    函數f可以包含由純數學運算或 Python 運算組成的任何 Python UDF 。 cuDF 基于通過 Numba 對函數的檢查推斷出適當的返回dtype,并在 GPU 上編譯和運行等效函數。

    函數也可以編寫為接受任意

    雖然在 cuDF 中有其他方法可以使用自定義內核和其他方法實現相同的目標,但這種編寫 UDF 的方法有助于將 GPU 從過程中抽象出來,這可以縮短從事快節奏、真實項目的數據科學家的開發時間。

    到目前為止,我只討論了基于Series的數據的情況。也就是說,我已經向您展示了如何使用單個輸入和輸出編寫 UDF 。然而,許多用例需要多列輸入,這需要稍微不同的思考。

    數據框架 UDF 和按行思考

    期望多個列作為輸入并生成單個列作為輸出的 UDF 是 pandas DataFrame apply API 支持的函數集。

    在這些情況下,第一個函數參數表示一行數據,而不僅僅是單個輸入列中的一個值。我所說的 row 是指某種能夠通過鍵控獲取值的數據結構,其中鍵是列名,值是與該行中這些列的值相對應的標量。從概念上講,這是在熊貓中使用iloc時得到的結果:

    數量的標量參數。在以下代碼示例中,您可以看到支持args=

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    下面的代碼示例顯示了如何在 pandas 中編寫和使用使用此類行對象的 UDF :

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    cuDF 現在,您可以在不重寫自定義項的情況下完成確切的操作。

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    在應用這些函數時,需要注意的是,盡管 cuDF API 希望您以行的形式編寫函數,但在執行此函數時,實際上并不涉及任何行。

    cuDF 避免使用 for 循環,而是執行“假裝”存在數據行的 CUDA 內核。通過一點魔法, Numba 知道如何編寫一個合適的內核來獲得與 pandas 相同的結果。因為沒有循環,所以通過此 API 執行函數時應該會看到更高的性能。

    使用 series 和 DataFrame 應用對缺失值的支持

    從歷史上看, cuDF 中的 UDF 并沒有提供對缺失值的完全支持。這是由于 cuDF 內部的架構選擇與 cuDF 記錄哪些元素為空的方式有關,特別是它使用空掩碼來節省內存。

    pandas apply API 的循環設計僅在數據包含空值時有效。如果數據中遇到 null , UDF 將接收特殊值pd.NA.,如果特殊值未觸發錯誤,則執行將正常進行。然而, cuDF 不是這樣工作的,它需要一些額外的機器來支持相同的功能。如果使用 cuDF apply API ,您應該發現您的 UDF 以自然的方式處理空值:

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    您甚至可以在cudf.NA單例上設置條件并獲得預期的答案,或者直接從函數返回:

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.

    顯然,這里的情況與行的情況相同: cuDF 實際上并不像 pandas 那樣運行 Python 函數。相反,它使用了更多的 Numba 魔法將此類函數轉換為等效的 CUDA 內核,然后返回結果。

    在下一節中,我將查看一個真實的示例,并執行一些粗略的計時。

    使用 apply 的真實示例

    考慮一下這個場景:一個在線流媒體服務正在調查其訂閱者中哪些部分的訂閱時間最長。此外, leadership 還要求制定一個具體的細分方案,按年齡劃分訂閱者:

    • 18 – 19
    • 20 – 29
    • 30 – 39
    • 40 – 49
    • 50 – 59
    • 60 – 69
    • 69 +

    提供的數據只有兩個字段:agedays_subscribed

    以下是 UDF 如何解決這個問題。首先,編寫應用分組的按行自定義函數。接下來,獲取結果,按組 ID 分組,并平均續訂次數。

    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    ?

    在此代碼示例中,數據是隨機生成的,因此您的里程數可能與實際答案不同。然而,它展示了這個過程。對代碼的 UDF 部分進行計時涉及到創建一個變量pdfpdf = df.to_pandas,并使用 IPython 完成粗略比較:

    %timeit df.apply(f, axis=1) # 1.64 ms ± 34.2 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) %timeit pdf.apply(f, axis=1)
    # 19.2 s ± 63.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

    雖然這不是官方的基準測試, CUDA 內核在這個特定的情況下平均快了四個數量級以上,它是在 32 GB V100 GPU 上運行的。

    實際考慮、限制和未來

    雖然這些 cuDF 改進代表了比以前的迭代更廣泛的功能,但總有增長的空間。以下是為 cuDF 中的 apply 編寫自定義項時要考慮的關鍵項目列表:

    • JIT compilation. 第一次針對 cuDF 對象執行函數時,您會遇到編譯正確的 CUDA 內核的開銷影響。除非目標數據集的dtypes發生更改,否則該函數的后續使用不需要重新編譯。
    • dtype support. 到目前為止,apply中只支持數字dtypes。然而,對其他類型的支持已經在路線圖上,從字符串開始。
    • External libraries. 常見的模式是在 pandas 中執行數據準備,然后使用外部庫在 UDF 中為每一行進行處理。由于您無法將外部代碼任意映射到 GPU ,因此目前不支持此操作。

    總結

    UDF 是快速解決特定問題的簡單方法。在設計管道邏輯時,它們可以幫助您從單個數據的角度進行思考。通過這些新的 cuDF UDF 增強,目的是加快涉及 cuDF 的工作流的開發,并允許您快速原型化解決方案,以及重用現有業務邏輯。此外, null 支持允許您明確說明如何處理缺少的值,而不需要額外的處理步驟。

    值得注意的是, UDF 是 cuDF 中積極開發的一個領域,目前正在進行更新。如果您選擇像往常一樣嘗試這些新的 UDF 增強功能,我很樂意在評論部分了解您的體驗。

    ?

    0

    標簽

    人人超碰97caoporen国产