在R语言中基于多条件为数据框分配新列值的实现方法
Got it, let's tackle this problem. You need to add a new column to your data frame based on multiple custom rules, and the solution should be flexible enough to adapt as you add more rules later. Here's a straightforward, scalable approach using base R or dplyr:
First, let's start with some sample data matching your a1-a9 column structure:
set.seed(123) # For reproducible results df <- data.frame( a1 = sample(1:9, 10, replace = TRUE), a2 = sample(1:9, 10, replace = TRUE), a3 = sample(1:9, 10, replace = TRUE), a4 = sample(1:9, 10, replace = TRUE), a5 = sample(1:9, 10, replace = TRUE), a6 = sample(1:9, 10, replace = TRUE), a7 = sample(1:9, 10, replace = TRUE), a8 = sample(1:9, 10, replace = TRUE), a9 = sample(1:9, 10, replace = TRUE) )
Step 1: Define Your Rules as a List
The key to scalability is storing rules in a structured list. Each rule includes a condition (what triggers it) and the value to assign to the new column when the condition is met. We'll also add a default value for rows that don't match any rule.
For your example rules, structure them like this (adjust the order to set rule priority—earlier rules get checked first):
rules <- list( # Rule 1: If any column has 1 or 2, assign 1 rule1 = list( condition = c(1, 2), value = 1 ), # Rule 2: If any column has 5 or 6, assign 6 (only checked if Rule 1 fails) rule2 = list( condition = c(5, 6), value = 6 ), # Default value if no rules are matched default = list( value = 3 ) )
Step 2: Create a Rule Application Function
Write a helper function that checks each row against your rules in order and returns the appropriate value:
apply_rules <- function(row, rules) { # Loop through all rules except the default for (rule in setNames(rules, NULL)[-length(rules)]) { # Check if any value in the row matches the rule's condition if (any(row %in% rule$condition)) { return(rule$value) } } # If no rules are triggered, return the default value return(rules$default$value) }
Step 3: Apply the Rules to Your Data Frame
You can use either base R or dplyr to apply this function to every row:
Option 1: Base R
df$NEW <- apply(df, 1, apply_rules, rules = rules)
Option 2: dplyr (tidyverse style)
If you prefer the tidyverse workflow:
library(dplyr) df <- df %>% rowwise() %>% # Check all columns from a1 to a9 mutate(NEW = apply_rules(c_across(a1:a9), rules)) %>% ungroup()
Step 4: View the Result
Print your updated data frame to see the new NEW column:
print(df)
Sample output:
a1 a2 a3 a4 a5 a6 a7 a8 a9 NEW 1 3 2 7 6 9 6 5 8 1 1 2 8 7 8 9 7 7 9 9 2 1 3 4 9 5 5 3 3 7 3 5 6 4 8 1 9 8 1 1 3 1 9 1 5 9 5 2 6 5 2 8 2 7 1 6 1 3 6 2 8 9 1 4 4 1 7 6 8 3 3 6 8 2 5 8 1 8 5 6 1 1 2 4 6 7 3 1 9 8 4 4 4 4 5 4 6 6 6 10 9 1 7 7 7 6 9 9 8 1
Scaling to More Complex Rules
This approach is super flexible. If you need more complex conditions (like checking if the mean of the row is above a threshold, or all columns meet a criteria), update your rules to use functions instead of value lists:
# Example with a mix of condition types rules <- list( rule_high_avg = list( condition = function(row) mean(row) > 6, # Custom function condition value = "high_average" ), rule_has_low_values = list( condition = c(1, 2), # Value match condition value = "has_1_or_2" ), default = list( value = "other" ) ) # Updated function to handle both condition types apply_rules <- function(row, rules) { for (rule in setNames(rules, NULL)[-length(rules)]) { if (is.function(rule$condition)) { # Evaluate the custom function if (rule$condition(row)) { return(rule$value) } } else { # Check for value matches if (any(row %in% rule$condition)) { return(rule$value) } } } return(rules$default$value) }
Now you can add, remove, or reorder rules in the rules list without changing the core application code—perfect for managing multiple custom conditions!
内容的提问来源于stack exchange,提问作者C_psy

