across()
可以輕鬆地將相同的轉換應用於多個列,允許您在 "data-masking" 函數(如 summarise()
和 mutate()
)中使用 select()
語義。有關更多詳細信息,請參閱vignette("colwise")
。
if_any()
和 if_all()
對選定的列應用相同的謂詞函數,並將結果合並到單個邏輯向量中:當任何選定列的謂詞為 TRUE
時,if_any()
為 TRUE
;當所有選定列的謂詞為 TRUE
時,if_all()
為 TRUE
。
如果您隻需要選擇列而不對每個列應用轉換,那麽您可能需要使用pick()
。
across()
取代 "scoped variants" 係列,例如 summarise_at()
、 summarise_if()
和 summarise_all()
。
用法
across(.cols, .fns, ..., .names = NULL, .unpack = FALSE)
if_any(.cols, .fns, ..., .names = NULL)
if_all(.cols, .fns, ..., .names = NULL)
參數
- .cols
-
<
tidy-select
> 要轉換的列。您無法選擇分組列,因為它們已由動詞自動處理(即summarise()
或mutate()
)。 - .fns
-
應用於每個選定列的函數。可能的值為:
-
一個函數,例如
mean
。 -
purrr-style lambda,例如
~ mean(.x, na.rm = TRUE)
-
函數或 lambda 的命名列表,例如
list(mean = mean, n_miss = ~ sum(is.na(.x))
。每個函數都應用於每一列,並通過使用.names
中的粘合規範將函數名稱和列名稱組合起來來命名輸出。
在這些函數中,您可以使用
cur_column()
和cur_group()
分別訪問當前列和分組鍵。 -
- ...
-
.fns
中函數調用的附加參數在...
中不再接受,因為不清楚何時應計算它們:每個across()
一次還是每個組一次?相反,使用 lambda 直接在.fns
中提供附加參數。例如,不要寫across(a:b, mean, na.rm = TRUE)
,而是寫across(a:b, ~ mean(.x, na.rm = TRUE))
。 - .names
-
說明如何命名輸出列的粘合規範。這可以使用
{.col}
代表所選的列名稱,並使用{.fn}
代表正在應用的函數的名稱。默認值 (NULL
) 相當於單函數情況下的"{.col}"
和.fns
使用列表的情況下的"{.col}_{.fn}"
。 - .unpack
-
可選地,
.fns
中的函數返回 unpack 數據幀,它將 df-columns 擴展為單獨的列,保留數據幀中的行數。-
如果是
FALSE
,默認情況下,不進行解包。 -
如果
TRUE
,則使用默認膠合規範"{outer}_{inner}"
完成解包。 -
否則,可以提供單個粘合規範來說明如何命名未填充的列。這可以使用
{outer}
來引用.names
最初生成的名稱,並使用{inner}
來引用要解包的數據幀的名稱。
-
值
across()
通常為 .cols
中的每一列和 .fns
中的每個函數返回一個包含一列的 tibble。如果使用 .unpack
,則可能會返回更多列,具體取決於 .fns
結果的解包方式。
if_any()
和 if_all()
返回邏輯向量。
評估時間
dplyr 動詞中的 R 代碼通常每組評估一次。然而,在 across()
內部,對於每個列和組的組合,代碼都會計算一次。如果評估時間很重要,例如,如果您要生成隨機變量,請考慮它應該何時發生並將代碼放在結果中。
gdf <-
tibble(g = c(1, 1, 2, 3), v1 = 10:13, v2 = 20:23) %>%
group_by(g)
set.seed(1)
# Outside: 1 normal variate
n <- rnorm(1)
gdf %>% mutate(across(v1:v2, ~ .x + n))
#> # A tibble: 4 x 3
#> # Groups: g [3]
#> g v1 v2
#> <dbl> <dbl> <dbl>
#> 1 1 9.37 19.4
#> 2 1 10.4 20.4
#> 3 2 11.4 21.4
#> 4 3 12.4 22.4
# Inside a verb: 3 normal variates (ngroup)
gdf %>% mutate(n = rnorm(1), across(v1:v2, ~ .x + n))
#> # A tibble: 4 x 4
#> # Groups: g [3]
#> g v1 v2 n
#> <dbl> <dbl> <dbl> <dbl>
#> 1 1 10.2 20.2 0.184
#> 2 1 11.2 21.2 0.184
#> 3 2 11.2 21.2 -0.836
#> 4 3 14.6 24.6 1.60
# Inside `across()`: 6 normal variates (ncol * ngroup)
gdf %>% mutate(across(v1:v2, ~ .x + rnorm(1)))
#> # A tibble: 4 x 3
#> # Groups: g [3]
#> g v1 v2
#> <dbl> <dbl> <dbl>
#> 1 1 10.3 20.7
#> 2 1 11.3 21.7
#> 3 2 11.2 22.6
#> 4 3 13.5 22.7
也可以看看
c_across()
用於返回向量的函數
例子
# For better printing
iris <- as_tibble(iris)
# across() -----------------------------------------------------------------
# Different ways to select the same set of columns
# See <https://tidyselect.r-lib.org/articles/syntax.html> for details
iris %>%
mutate(across(c(Sepal.Length, Sepal.Width), round))
#> # A tibble: 150 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5 4 1.4 0.2 setosa
#> 2 5 3 1.4 0.2 setosa
#> 3 5 3 1.3 0.2 setosa
#> 4 5 3 1.5 0.2 setosa
#> 5 5 4 1.4 0.2 setosa
#> 6 5 4 1.7 0.4 setosa
#> 7 5 3 1.4 0.3 setosa
#> 8 5 3 1.5 0.2 setosa
#> 9 4 3 1.4 0.2 setosa
#> 10 5 3 1.5 0.1 setosa
#> # ℹ 140 more rows
iris %>%
mutate(across(c(1, 2), round))
#> # A tibble: 150 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5 4 1.4 0.2 setosa
#> 2 5 3 1.4 0.2 setosa
#> 3 5 3 1.3 0.2 setosa
#> 4 5 3 1.5 0.2 setosa
#> 5 5 4 1.4 0.2 setosa
#> 6 5 4 1.7 0.4 setosa
#> 7 5 3 1.4 0.3 setosa
#> 8 5 3 1.5 0.2 setosa
#> 9 4 3 1.4 0.2 setosa
#> 10 5 3 1.5 0.1 setosa
#> # ℹ 140 more rows
iris %>%
mutate(across(1:Sepal.Width, round))
#> # A tibble: 150 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5 4 1.4 0.2 setosa
#> 2 5 3 1.4 0.2 setosa
#> 3 5 3 1.3 0.2 setosa
#> 4 5 3 1.5 0.2 setosa
#> 5 5 4 1.4 0.2 setosa
#> 6 5 4 1.7 0.4 setosa
#> 7 5 3 1.4 0.3 setosa
#> 8 5 3 1.5 0.2 setosa
#> 9 4 3 1.4 0.2 setosa
#> 10 5 3 1.5 0.1 setosa
#> # ℹ 140 more rows
iris %>%
mutate(across(where(is.double) & !c(Petal.Length, Petal.Width), round))
#> # A tibble: 150 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5 4 1.4 0.2 setosa
#> 2 5 3 1.4 0.2 setosa
#> 3 5 3 1.3 0.2 setosa
#> 4 5 3 1.5 0.2 setosa
#> 5 5 4 1.4 0.2 setosa
#> 6 5 4 1.7 0.4 setosa
#> 7 5 3 1.4 0.3 setosa
#> 8 5 3 1.5 0.2 setosa
#> 9 4 3 1.4 0.2 setosa
#> 10 5 3 1.5 0.1 setosa
#> # ℹ 140 more rows
# Using an external vector of names
cols <- c("Sepal.Length", "Petal.Width")
iris %>%
mutate(across(all_of(cols), round))
#> # A tibble: 150 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5 3.5 1.4 0 setosa
#> 2 5 3 1.4 0 setosa
#> 3 5 3.2 1.3 0 setosa
#> 4 5 3.1 1.5 0 setosa
#> 5 5 3.6 1.4 0 setosa
#> 6 5 3.9 1.7 0 setosa
#> 7 5 3.4 1.4 0 setosa
#> 8 5 3.4 1.5 0 setosa
#> 9 4 2.9 1.4 0 setosa
#> 10 5 3.1 1.5 0 setosa
#> # ℹ 140 more rows
# If the external vector is named, the output columns will be named according
# to those names
names(cols) <- tolower(cols)
iris %>%
mutate(across(all_of(cols), round))
#> # A tibble: 150 × 7
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species sepal.length
#> <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
#> 1 5.1 3.5 1.4 0.2 setosa 5
#> 2 4.9 3 1.4 0.2 setosa 5
#> 3 4.7 3.2 1.3 0.2 setosa 5
#> 4 4.6 3.1 1.5 0.2 setosa 5
#> 5 5 3.6 1.4 0.2 setosa 5
#> 6 5.4 3.9 1.7 0.4 setosa 5
#> 7 4.6 3.4 1.4 0.3 setosa 5
#> 8 5 3.4 1.5 0.2 setosa 5
#> 9 4.4 2.9 1.4 0.2 setosa 4
#> 10 4.9 3.1 1.5 0.1 setosa 5
#> # ℹ 140 more rows
#> # ℹ 1 more variable: petal.width <dbl>
# A purrr-style formula
iris %>%
group_by(Species) %>%
summarise(across(starts_with("Sepal"), ~ mean(.x, na.rm = TRUE)))
#> # A tibble: 3 × 3
#> Species Sepal.Length Sepal.Width
#> <fct> <dbl> <dbl>
#> 1 setosa 5.01 3.43
#> 2 versicolor 5.94 2.77
#> 3 virginica 6.59 2.97
# A named list of functions
iris %>%
group_by(Species) %>%
summarise(across(starts_with("Sepal"), list(mean = mean, sd = sd)))
#> # A tibble: 3 × 5
#> Species Sepal.Length_mean Sepal.Length_sd Sepal.Width_mean
#> <fct> <dbl> <dbl> <dbl>
#> 1 setosa 5.01 0.352 3.43
#> 2 versicolor 5.94 0.516 2.77
#> 3 virginica 6.59 0.636 2.97
#> # ℹ 1 more variable: Sepal.Width_sd <dbl>
# Use the .names argument to control the output names
iris %>%
group_by(Species) %>%
summarise(across(starts_with("Sepal"), mean, .names = "mean_{.col}"))
#> # A tibble: 3 × 3
#> Species mean_Sepal.Length mean_Sepal.Width
#> <fct> <dbl> <dbl>
#> 1 setosa 5.01 3.43
#> 2 versicolor 5.94 2.77
#> 3 virginica 6.59 2.97
iris %>%
group_by(Species) %>%
summarise(across(starts_with("Sepal"), list(mean = mean, sd = sd), .names = "{.col}.{.fn}"))
#> # A tibble: 3 × 5
#> Species Sepal.Length.mean Sepal.Length.sd Sepal.Width.mean
#> <fct> <dbl> <dbl> <dbl>
#> 1 setosa 5.01 0.352 3.43
#> 2 versicolor 5.94 0.516 2.77
#> 3 virginica 6.59 0.636 2.97
#> # ℹ 1 more variable: Sepal.Width.sd <dbl>
# If a named external vector is used for column selection, .names will use
# those names when constructing the output names
iris %>%
group_by(Species) %>%
summarise(across(all_of(cols), mean, .names = "mean_{.col}"))
#> # A tibble: 3 × 3
#> Species mean_sepal.length mean_petal.width
#> <fct> <dbl> <dbl>
#> 1 setosa 5.01 0.246
#> 2 versicolor 5.94 1.33
#> 3 virginica 6.59 2.03
# When the list is not named, .fn is replaced by the function's position
iris %>%
group_by(Species) %>%
summarise(across(starts_with("Sepal"), list(mean, sd), .names = "{.col}.fn{.fn}"))
#> # A tibble: 3 × 5
#> Species Sepal.Length.fn1 Sepal.Length.fn2 Sepal.Width.fn1
#> <fct> <dbl> <dbl> <dbl>
#> 1 setosa 5.01 0.352 3.43
#> 2 versicolor 5.94 0.516 2.77
#> 3 virginica 6.59 0.636 2.97
#> # ℹ 1 more variable: Sepal.Width.fn2 <dbl>
# When the functions in .fns return a data frame, you typically get a
# "packed" data frame back
quantile_df <- function(x, probs = c(0.25, 0.5, 0.75)) {
tibble(quantile = probs, value = quantile(x, probs))
}
iris %>%
reframe(across(starts_with("Sepal"), quantile_df))
#> # A tibble: 3 × 2
#> Sepal.Length$quantile $value Sepal.Width$quantile $value
#> <dbl> <dbl> <dbl> <dbl>
#> 1 0.25 5.1 0.25 2.8
#> 2 0.5 5.8 0.5 3
#> 3 0.75 6.4 0.75 3.3
# Use .unpack to automatically expand these packed data frames into their
# individual columns
iris %>%
reframe(across(starts_with("Sepal"), quantile_df, .unpack = TRUE))
#> # A tibble: 3 × 4
#> Sepal.Length_quantile Sepal.Length_value Sepal.Width_quantile
#> <dbl> <dbl> <dbl>
#> 1 0.25 5.1 0.25
#> 2 0.5 5.8 0.5
#> 3 0.75 6.4 0.75
#> # ℹ 1 more variable: Sepal.Width_value <dbl>
# .unpack can utilize a glue specification if you don't like the defaults
iris %>%
reframe(across(starts_with("Sepal"), quantile_df, .unpack = "{outer}.{inner}"))
#> # A tibble: 3 × 4
#> Sepal.Length.quantile Sepal.Length.value Sepal.Width.quantile
#> <dbl> <dbl> <dbl>
#> 1 0.25 5.1 0.25
#> 2 0.5 5.8 0.5
#> 3 0.75 6.4 0.75
#> # ℹ 1 more variable: Sepal.Width.value <dbl>
# This is also useful inside mutate(), for example, with a multi-lag helper
multilag <- function(x, lags = 1:3) {
names(lags) <- as.character(lags)
purrr::map_dfr(lags, lag, x = x)
}
iris %>%
group_by(Species) %>%
mutate(across(starts_with("Sepal"), multilag, .unpack = TRUE)) %>%
select(Species, starts_with("Sepal"))
#> # A tibble: 150 × 9
#> # Groups: Species [3]
#> Species Sepal.Length Sepal.Width Sepal.Length_1 Sepal.Length_2
#> <fct> <dbl> <dbl> <dbl> <dbl>
#> 1 setosa 5.1 3.5 NA NA
#> 2 setosa 4.9 3 5.1 NA
#> 3 setosa 4.7 3.2 4.9 5.1
#> 4 setosa 4.6 3.1 4.7 4.9
#> 5 setosa 5 3.6 4.6 4.7
#> 6 setosa 5.4 3.9 5 4.6
#> 7 setosa 4.6 3.4 5.4 5
#> 8 setosa 5 3.4 4.6 5.4
#> 9 setosa 4.4 2.9 5 4.6
#> 10 setosa 4.9 3.1 4.4 5
#> # ℹ 140 more rows
#> # ℹ 4 more variables: Sepal.Length_3 <dbl>, Sepal.Width_1 <dbl>,
#> # Sepal.Width_2 <dbl>, Sepal.Width_3 <dbl>
# if_any() and if_all() ----------------------------------------------------
iris %>%
filter(if_any(ends_with("Width"), ~ . > 4))
#> # A tibble: 3 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5.7 4.4 1.5 0.4 setosa
#> 2 5.2 4.1 1.5 0.1 setosa
#> 3 5.5 4.2 1.4 0.2 setosa
iris %>%
filter(if_all(ends_with("Width"), ~ . > 2))
#> # A tibble: 23 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 6.3 3.3 6 2.5 virginica
#> 2 7.1 3 5.9 2.1 virginica
#> 3 6.5 3 5.8 2.2 virginica
#> 4 7.6 3 6.6 2.1 virginica
#> 5 7.2 3.6 6.1 2.5 virginica
#> 6 6.8 3 5.5 2.1 virginica
#> 7 5.8 2.8 5.1 2.4 virginica
#> 8 6.4 3.2 5.3 2.3 virginica
#> 9 7.7 3.8 6.7 2.2 virginica
#> 10 7.7 2.6 6.9 2.3 virginica
#> # ℹ 13 more rows
相關用法
- R dplyr arrange_all 通過選擇的變量排列行
- R dplyr arrange 使用列值對行進行排序
- R dplyr group_trim 修剪分組結構
- R dplyr slice 使用行的位置對行進行子集化
- R dplyr copy_to 將本地數據幀複製到遠程src
- R dplyr sample_n 從表中采樣 n 行
- R dplyr consecutive_id 為連續組合生成唯一標識符
- R dplyr row_number 整數排名函數
- R dplyr band_members 樂隊成員
- R dplyr mutate-joins 變異連接
- R dplyr nth 從向量中提取第一個、最後一個或第 n 個值
- R dplyr coalesce 找到第一個非缺失元素
- R dplyr group_split 按組分割 DataFrame
- R dplyr mutate 創建、修改和刪除列
- R dplyr order_by 用於排序窗口函數輸出的輔助函數
- R dplyr context 有關“當前”組或變量的信息
- R dplyr percent_rank 比例排名函數
- R dplyr recode 重新編碼值
- R dplyr starwars 星球大戰人物
- R dplyr desc 降序
- R dplyr between 檢測值落在指定範圍內的位置
- R dplyr cumall 任何、全部和平均值的累積版本
- R dplyr group_map 對每個組應用一個函數
- R dplyr do 做任何事情
- R dplyr nest_join 嵌套連接
注:本文由純淨天空篩選整理自Hadley Wickham等大神的英文原創作品 Apply a function (or functions) across multiple columns。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。