如何将含mutate与case_when的R代码封装为可复用函数?
Great question! Handling multi-option flag columns can get repetitive fast, so wrapping this logic into a reusable function is a smart move. Let's break down how to simplify those repeated case_when calls and build a flexible function that fits your needs.
Step 1: Understand the Repetitive Pattern
First, let's recap the kind of code you're probably working with. For example, if you have a dataset with comma-separated interests, you might be writing code like this to create flag columns:
library(dplyr) library(stringr) sample_data <- tibble( id = 1:5, interests = c("读书,运动", "运动,音乐", "读书", "音乐,旅行", "读书,旅行,运动") ) # Repetitive code you want to replace sample_data %>% mutate( 读书 = case_when(str_detect(interests, "读书") ~ 1, TRUE ~ 0), 运动 = case_when(str_detect(interests, "运动") ~ 1, TRUE ~ 0), 音乐 = case_when(str_detect(interests, "音乐") ~ 1, TRUE ~ 0), 旅行 = case_when(str_detect(interests, "旅行") ~ 1, TRUE ~ 0) )
The core issue is repeating the same case_when(str_detect(...)) logic for every pattern. We can eliminate this repetition using purrr to batch-generate the flag columns.
Step 2: Build the Reusable Function
Here's a flexible function that handles all your requirements: it accepts custom input data, target column, match patterns, option count (handled automatically by the length of your patterns), and output column names.
library(dplyr) library(stringr) library(purrr) create_multi_flags <- function(data, target_col, patterns, output_names = NULL) { # Default to using patterns as output column names if none are provided if (is.null(output_names)) { output_names <- patterns } # Ensure pattern count matches output name count (prevents mismatches) stopifnot(length(patterns) == length(output_names), "Number of patterns must match number of output column names") # Batch-generate flag columns using map_dfc flag_columns <- map_dfc(patterns, ~ { # For each pattern, detect presence in target column and convert to 1/0 data %>% pull({{target_col}}) %>% str_detect(.x) %>% as.integer() }) %>% set_names(output_names) # Combine original data with new flag columns bind_cols(data, flag_columns) }
Step 3: Use the Function
Let's test this with your sample data. You can customize the output column names or let them default to the pattern strings:
# Sample data sample_data <- tibble( id = 1:5, interests = c("读书,运动", "运动,音乐", "读书", "音乐,旅行", "读书,旅行,运动") ) # Example 1: Custom output column names result_with_custom_names <- create_multi_flags( data = sample_data, target_col = interests, patterns = c("读书", "运动", "音乐", "旅行"), output_names = c("flag_read", "flag_sport", "flag_music", "flag_travel") ) # Example 2: Default output names (uses pattern strings) result_with_default_names <- create_multi_flags( data = sample_data, target_col = interests, patterns = c("读书", "运动", "音乐", "旅行") )
Expected Output
For the first example with custom names, you'll get this clean output:
# A tibble: 5 × 6 id interests flag_read flag_sport flag_music flag_travel <int> <chr> <int> <int> <int> <int> 1 1 读书,运动 1 1 0 0 2 2 运动,音乐 0 1 1 0 3 3 读书 1 0 0 0 4 4 音乐,旅行 0 0 1 1 5 5 读书,旅行,运动 1 1 0 1
Why This Works
- No more repeated
case_when:map_dfciterates over each pattern and applies the same detection logic, so you only write the core logic once. - Flexibility: You can pass any dataset, target column (using tidy evaluation with
{{}}), patterns, and output names. - Safety: The
stopifnotcheck ensures you don't accidentally pass mismatched numbers of patterns and output names.
内容的提问来源于stack exchange,提问作者gofraidh

