0Pricing
R Academy · Урок

Аккуратное вычисление: {{ }} и .data

Безопасно пишите функции dplyr, принимающие имена столбцов в качестве аргументов.

«Аккуратное вычисление: {{ }} и .data» — бесплатный урок R Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения R Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс R Academy содержит 4 уроков всего.

Проблема: программирование с dplyr

dplyr использует нестандартное вычисление (NSE) — имена столбцов передаются без кавычек. Это удобно при интерактивной работе, но усложняет написание функций. Как передать имя столбца в функцию dplyr в виде переменной?

library(dplyr)

df <- data.frame(x=1:5, y=c(2,4,6,8,10))

# Works fine interactively:
df %>% summarize(mean_x = mean(x))

# But what if 'x' is a variable?
col_name <- 'x'
# df %>% summarize(result = mean(col_name))  # WRONG! treats 'col_name' as column
cat('Need tidy evaluation to solve this!')

Оператор {{ }} для передачи выражений

Внутри функции используйте {{ col_var }} (его называют «двойными фигурными скобками» или оператором передачи) для передачи имени столбца, которое будет вычислено в контексте кадра данных. Это рекомендуемый подход для большинства функций dplyr.

library(dplyr)

df <- data.frame(
  group = c('A','A','B','B'),
  sales = c(100, 120, 200, 180),
  costs = c(60, 70, 110, 90)
)

# Function using {{ }}
group_mean <- function(data, group_col, value_col) {
  data %>%
    group_by({{ group_col }}) %>%
    summarize(mean_val = mean({{ value_col }}), .groups = 'drop')
}

group_mean(df, group, sales)
group_mean(df, group, costs)

{{ }} для имён столбцов в результате

Оператор {{ }} можно также использовать слева от :=, чтобы динамически задавать имена выходных столбцов. Оператор := (оператор моржа) разрешает использовать имена переменных слева от присваиваний внутри глаголов dplyr.

library(dplyr)

df <- data.frame(a=1:4, b=c(2,4,6,8))

# Dynamic output column name
compute_mean <- function(data, col) {
  col_name <- paste0('mean_', deparse(substitute(col)))
  data %>% summarize('{col_name}' := mean({{ col }}))
}

compute_mean(df, a)
compute_mean(df, b)

Указатель .data

.data[['col_name']] позволяет выбрать столбец с помощью строковой переменной. Он явно указывает dplyr искать столбец в текущем кадре данных. Это полезно, когда имена столбцов хранятся в виде строк.

library(dplyr)

df <- data.frame(
  name = c('Alice','Bob','Carol'),
  score = c(85, 92, 78),
  grade = c('B','A','C')
)

# Using .data with a string variable
get_summary <- function(data, col_name) {
  data %>%
    summarize(
      n = n(),
      mean_val = mean(.data[[col_name]])
    )
}

get_summary(df, 'score')

across() — применить к нескольким столбцам

across(cols, fns) внутри mutate() или summarize() применяет функцию сразу к нескольким столбцам. Выбирайте столбцы с помощью вспомогательных функций tidyselect: starts_with(), where(is.numeric), everything() и других.

library(dplyr)

df <- data.frame(
  id = 1:3,
  sales_q1 = c(100, 200, 150),
  sales_q2 = c(120, 180, 160),
  cost_q1 = c(60, 110, 80),
  cost_q2 = c(70, 100, 85)
)

# Summarize all numeric columns except 'id'
df %>%
  summarize(across(where(is.numeric) & !id, mean))

across() с именованными функциями

Передайте в across() именованный список функций, чтобы вычислить несколько статистик для каждого столбца. Выходные столбцы получают имена в формате col_fn. Используйте .names, чтобы настроить шаблон именования.

library(dplyr)

df <- data.frame(
  x = c(10, 20, 30, 40),
  y = c(5, 15, 25, 35)
)

# Compute mean and sd for both columns
df %>%
  summarize(across(
    c(x, y),
    list(mean = mean, sd = sd),
    .names = '{.col}_{.fn}'
  ))

across() в mutate()

Использование across() внутри mutate() одновременно преобразует несколько столбцов. Это избавляет от необходимости повторять одно и то же преобразование для каждого столбца.

library(dplyr)

df <- data.frame(
  id = 1:3,
  revenue = c(1000, 2000, 1500),
  cost = c(600, 1100, 800),
  tax = c(100, 200, 150)
)

# Round all numeric columns except id to nearest 10
df %>%
  mutate(across(where(is.numeric) & !id,
                ~round(., -2)))

pick() — выбрать столбцы для операций

pick() (в dplyr 1.1 и новее) выбирает подмножество столбцов в виде небольшого кадра данных. Это удобно для передачи данных в функции, ожидающие кадр данных. Функция работает внутри mutate() и summarize().

library(dplyr)

df <- data.frame(
  id = 1:3,
  a = c(1, 2, 3),
  b = c(4, 5, 6),
  c_val = c(7, 8, 9)
)

# Use pick() to compute row-wise mean across selected columns
df %>%
  mutate(
    row_mean = rowMeans(pick(a, b, c_val)),
    row_max = do.call(pmax, pick(a, b, c_val))
  )

Написание повторно используемых функций dplyr

Сочетание {{ }}, .data[[]] и across() позволяет писать мощные повторно используемые функции анализа. Основной принцип: принимайте имена столбцов как аргументы без кавычек (используя {{ }}) или как строки (используя .data[[]]).

library(dplyr)

df <- data.frame(
  region = c('East','East','West','West'),
  product = c('A','B','A','B'),
  revenue = c(100, 200, 150, 250),
  units = c(10, 15, 12, 20)
)

# Flexible grouped summary function
group_stats <- function(data, ..., metric) {
  data %>%
    group_by(...) %>%
    summarize(
      total = sum({{ metric }}),
      average = mean({{ metric }}),
      .groups = 'drop'
    )
}

group_stats(df, region, metric = revenue)
group_stats(df, region, product, metric = units)

Вспомогательные функции упорядоченного выбора

Вспомогательные функции tidyselect работают внутри across(), select() и pick(): starts_with(), ends_with(), contains(), matches(), num_range(), where(predicate) и everything().

library(dplyr)

df <- data.frame(
  id = 1:3,
  score_2022 = c(80,85,90),
  score_2023 = c(82,88,91),
  score_2024 = c(85,90,93),
  category = c('A','B','A')
)

# Select all score columns and compute their means
df %>%
  summarize(
    across(starts_with('score'), mean),
    n = n()
  )

Сочетание шаблонов tidy evaluation

В реальных функциях dplyr часто сочетаются {{ }} для группирующих переменных, across() для нескольких показателей и .data[[]] для имён столбцов в виде строк. Понимание того, когда применять каждый шаблон, делает код гибким и корректным.

library(dplyr)

df <- data.frame(
  dept = c('HR','HR','Eng','Eng'),
  salary = c(60000, 65000, 100000, 110000),
  bonus = c(5000, 6000, 15000, 18000)
)

# String-based column selection with .data
summarize_column <- function(data, group_col, value_col_name) {
  data %>%
    group_by(.data[[group_col]]) %>%
    summarize(
      mean = mean(.data[[value_col_name]]),
      total = sum(.data[[value_col_name]]),
      .groups = 'drop'
    )
}

summarize_column(df, 'dept', 'salary')
summarize_column(df, 'dept', 'bonus')

Быстрая проверка

Как правильно передать имя столбца в функцию dplyr в качестве аргумента без кавычек внутри пользовательской функции?

Итоги: tidy evaluation

Главное о программировании с dplyr:

  • {{ col }} — передавать в функциях имена столбцов без кавычек
  • .data[['col_name']] — обращаться к столбцам по имени строковой переменной
  • := — оператор моржа; используется с {{ }} или строками glue для динамических имён результатов
  • across(cols, fns) — применять функцию или функции сразу к нескольким столбцам
  • pick(cols) — выбирать столбцы как вложенный кадр данных для построчных операций
  • Вспомогательные функции tidyselect: starts_with(), where(), contains(), everything()
library(dplyr)

df <- data.frame(
  group = c('A','A','B','B'),
  v1 = c(10, 20, 30, 40),
  v2 = c(5, 15, 25, 35)
)

# Reusable function using {{ }} + across
group_summary <- function(data, grp) {
  data %>%
    group_by({{ grp }}) %>%
    summarize(across(where(is.numeric), list(mean=mean, sum=sum)), .groups='drop')
}

group_summary(df, group)

Часто задаваемые вопросы

Урок «Аккуратное вычисление: {{ }} и .data» бесплатный?

Да — полный текст урока «Аккуратное вычисление: {{ }} и .data» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс R Academy, подпишись на CoddyKit PRO. Курс R Academy содержит 4 уроков всего.

Чему я научусь в уроке «Аккуратное вычисление: {{ }} и .data»?

Безопасно пишите функции dplyr, принимающие имена столбцов в качестве аргументов. Ты практикуешь R Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать R Academy?

Предыдущий опыт не требуется. R Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Аккуратное вычисление: {{ }} и .data»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке R Academy?

Да. Каждый урок R Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Сгруппированные сводки и group_by()
  2. Оконные функции: lag, lead, cumsum
  3. Объединение нескольких таблиц в dplyr
  4. Аккуратное вычисление: {{ }} и .data
← Назад к R Academy