如何将RedCap多选问卷的未作答多行批量转为NA?
Let's break this down—you've got a RedCap dataset where your multi-select pet question is split into individual columns (like column_cat, column_dog), with "Yes" for selected options and "No" for unselected ones. The problem is respondents who skipped the question show up as all "No"s, which should actually be NA since they didn't answer at all. Here are a few clean, efficient ways to batch-process these variables:
Method 1: Use dplyr::across() (Most Efficient & Flexible)
This approach lets you target all your pet columns in one go, no helper columns needed. We'll check if a row has zero "Yes" values across all pet columns—if so, we replace that row's pet column values with NA; otherwise, we keep the original "Yes"/"No".
library(dplyr) # Define your pet columns (or use a pattern if they follow a naming rule) pet_columns <- c("column_cat", "column_dog", "column_rabbit", "column_guinea_pig", "column_mouse", "column_none") # Or, if all columns start with "column_", use this instead to avoid manual listing: # pet_columns <- starts_with("column_") df_cleaned <- df %>% mutate( across(all_of(pet_columns), ~ ifelse( # Check if the row has no "Yes" values in any pet column rowSums(select(., all_of(pet_columns)) == "Yes") == 0, NA, # Replace with NA if true .x # Keep original value if false )) )
Why this works:
rowSums(select(., all_of(pet_columns)) == "Yes")counts how many "Yes" entries are in each row for your pet columns.- If the count is 0, that means the respondent skipped the question (all "No"s), so we swap those values to
NA. - This correctly preserves cases where someone selected "无" (column_none = "Yes")—since that's a valid response, the row sum will be 1, so no replacement happens.
Method 2: Use naniar::replace_with_na()
If you prefer using the naniar package (great for missing data workflows), you can combine it with a row-level check:
library(dplyr) library(naniar) pet_columns <- c("column_cat", "column_dog", "column_rabbit", "column_guinea_pig", "column_mouse", "column_none") df_cleaned <- df %>% # Add a temporary flag for rows with all "No"s mutate(all_skipped = rowSums(select(., all_of(pet_columns)) == "Yes") == 0) %>% # Replace "No" with NA only where the row was skipped replace_with_na_if( .vars = all_of(pet_columns), .predicate = ~ .x == "No" & all_skipped ) %>% # Remove the temporary flag column select(-all_skipped)
Key Notes
- Always double-check a few rows after processing to confirm:
- Rows with at least one "Yes" (including "无") should retain their original "Yes"/"No" values.
- Rows with all "No"s should now have
NAin all pet columns.
- If your pet columns follow a consistent naming pattern (e.g., all start with
pet_instead ofcolumn_), adjust thepet_columnsdefinition to usestarts_with("pet_")for even less manual work.
内容的提问来源于stack exchange,提问作者ph_researcher

