برنامه‌نویسی با dplyr

تابع فوق‌العاده ما!
تابع فوق‌العاده ما!
منتشر شده در towardsdatascience به تاریخ ۹ نوامبر ۲۰۲۱
لینک منبع Programming with dplyr

برنامه‌نویسی با dplyr vignette با docs بهترین مرجع است اگر در R تازه‌کار هستید ... اما اگر نیستید، بیایید ببینیم چگونه برنامه‌نویسی خود را از روش‌های قدیمی ارتقا دهید.

اگر با استفاده از sym و تبدیل از فرم استاندارد به فرم غیر استاندارد آشنا هستید، روند زیر باید به شما نشان دهد که چگونه کد خود را جایگزین کنید (و گسترش دهید). آن باید عمدتا پیدا-جایگزین شود! اگر تابعی دارید که بردار ویژگی را می‌گیرد و از یک فعل _ at استفاده می‌کند، تفاوت بین گزینه قدیمی متناظر (در اینجا، گزینه ۱ با _ at) را ببینید و ببینید که چگونه این برای «سوپر ورژن» در پایین تغییر می‌کند.

گزینه قدیمی ۱: استفاده از افعال *_at

این روش قدیمی برای نوشتن تابع dplyr است:

max_by_at <- function(data, var, by="") {
data %>%
group_by_at(by) %>%
summarise_at(var, max, na.rm = TRUE)
}

بیایید آن را امتحان کنیم:

starwars %>% max_by_at("height", by="gender")
starwars %>% max_by_at(c("height", "mass"), by="gender")
starwars %>% max_by_at(c("height", "mass"), by=c("sex", "gender"))

این کار خوب جواب داد، اما برای متغیرهای env جواب نمی‌دهد:

testthat::expect_error(starwars %>% max_by_at(height, by=gender))
testthat::expect_error(starwars %>% max_by_at("height", by=gender))
testthat::expect_error(starwars %>% max_by_at(height, by="gender"))

گزینه قدیمی ۲: استفاده از across

این برای کاراکترها و بردارهای کاراکتر کار می‌کند، اما برای متغیرهای env کار نمی‌کند. استفاده از across یک جایگزین برای استفاده از *_at است، و همان کارکرد را دارد:

max_by_across <- function(data, var, by="") {
data %>%
group_by(across(by)) %>%
summarise(across(var, max, na.rm = TRUE), .groups='keep')
}

نحوه کار آن به این شکل است:

starwars %>% max_by_across("height", by="gender")
starwars %>% max_by_across(c("height", "mass"), by="gender")
starwars %>% max_by_across(c("height", "mass"), by=c("sex", "gender"))

این هم برای بردارها و هم برای رشته‌ها کار می‌کرد (به یاد داشته باشید، هر چیزی در R در واقع یک بردار است). اما نمی‌توانیم از متغیرهای env استفاده کنیم:

testthat::expect_error(starwars %>% max_by_across(height, by=gender))
testthat::expect_error(starwars %>% max_by_across("height", by=gender))
testthat::expect_error(starwars %>% max_by_across(height, by="gender"))

گزینه قدیمی ۳: تبدیل از کاراکتر به env var با sym

max_by_1 <- function(data, var, by="") {
data %>%
group_by(!!sym(by)) %>%
summarise(maximum = max(!!sym(var), na.rm = TRUE))
}

برای انتقال متغیرهای env کار نمی‌کند:

testthat::expect_error(starwars %>% max_by_1(height))
testthat::expect_error(starwars %>% max_by_1(height, by=gender))

برای رشته‌ها کار می‌کند:

starwars %>% max_by_1("height")
starwars %>% max_by_1("height", by="gender")

اما، برای لیست‌ها مناسب نیست (بنابراین، کم‌تر از across همه‌جانبه است) :

testthat::expect_error(starwars %>% max_by_1(c("height", "weight")))
testthat::expect_error(starwars %>% max_by_1("height", by=c("gender", "sex")))

با مهارها بهتر است

این نسخه سوپر ورژن را بررسی کنید!

این روش برای env vars کار می‌کند، بنابراین ما می‌توانیم از آن مانند یک تابع dplyr با حالت غیر استاندارد و همچنین عبور در متغیرهای sym استفاده کنیم.

max_by_2 <- function(data, var, by) {
data %>%
group_by({{ by }}) %>%
summarise(maximum = max({{ var }}, na.rm = TRUE))
}

این روش برای متغیرهای env جواب می‌دهد!

که بسیار جالب است:

starwars %>% max_by_2(height)
starwars %>% max_by_2(height, by=gender)

این کار برای رشته‌های آماده جواب نمی‌دهد:

starwars %>% max_by_2("height")
starwars %>% max_by_2("height", by="gender")

ما می‌توانیم با sym این مورد را حل کنیم:

starwars %>% max_by_2(!!sym("height"))

برای لیست‌های متغیرهای env کار نمی‌کند:

starwars %>% max_by_2(c(height, mass))testthat::expect_error(starwars %>% max_by_2(height, by=c(gender, sex)))

سوپر ورژن

برای اجازه دادن به رشته‌ها، فهرست‌های env vars، و حتی فهرست‌های رشته‌ها از cross() استفاده می‌کنیم. پیش‌فرض by=() تبدیل به یک لیست خالی می‌شود و ما {{}} را با across() ساده می‌کنیم:

max_by_3 <- function(data, var, by=c()) {
data %>%
group_by(across({{ by }})) %>%
summarise(across({{ var }}, max, .names = "max_{.col}", na.rm = TRUE), .groups='keep')
}

این روش برای متغیرهای env جواب می‌دهد:

starwars %>% max_by_3(height)
starwars %>% max_by_3(height, by=gender)

این برای رشته‌ها کار می‌کند:

starwars %>% max_by_3("height")
starwars %>% max_by_3("height", by="gender")

این روش برای فهرستی از متغیرهای env کار می‌کند:

starwars %>% max_by_3(c(height, mass))
starwars %>% max_by_3(height, by=c(gender, sex))
starwars %>% max_by_3(c(height, mass), by=c(gender, sex))

برای فهرست کاراکترها کار می‌کند:

starwars %>% max_by_3(c("height", "mass"))
starwars %>% max_by_3("height", by=c(gender, sex))
starwars %>% max_by_3(c("height", "mass"), by=c("gender", "sex"))

حالا شما یاد گرفتید که چگونه برخی توابع بسیار انعطاف‌پذیر را با استفاده از قدرت‌های جدید برنامه‌نویسی dplyr بنویسید. لذت ببرید!

این متن با استفاده از ربات ترجمه مقالات علمی ترجمه شده و به صورت محدود مورد بازبینی انسانی قرار گرفته است.در نتیجه می‌تواند دارای برخی اشکالات ترجمه باشد.
مقالات لینک‌شده در این متن می‌توانند به صورت رایگان با استفاده از مقاله‌خوان ترجمیار به فارسی مطالعه شوند.