如何按条件重排分组DataFrame中指定行?(优先用tidyverse)
Absolutely, you can solve this problem with the tidyverse! Let's walk through a step-by-step solution that groups your data by name, finds the correct spot for each id == "i" row, and rearranges the rows to meet your conditions.
Step 1: Load tidyverse and define a helper function
First, we'll create a custom function to handle the rearrangement logic for each name group:
library(tidyverse) rearrange_group <- function(group_df) { # Split the group into the "i" row and all "s" rows i_row <- group_df %>% filter(id == "i") s_rows <- group_df %>% filter(id != "i") # If there's no "i" row in the group, return the original rows if (nrow(i_row) == 0) return(s_rows) # Only check middle positions (we need both lag and lead rows for your condition) possible_positions <- 2:(nrow(s_rows)) # Find positions where the "i" row meets your criteria valid_positions <- possible_positions %>% map_lgl(function(pos) { # Get the surrounding rows' values prev_var1 <- s_rows$var1[pos - 1] next_var1 <- s_rows$var1[pos] prev_var2 <- s_rows$var2[pos - 1] next_var2 <- s_rows$var2[pos] # Check all four conditions i_row$var1 > prev_var1 && i_row$var1 < next_var1 && i_row$var2 > prev_var2 && i_row$var2 < next_var2 }) # Pick the first valid position (adjust if you need a different priority) insert_pos <- possible_positions[valid_positions][1] # Insert the "i" row into the correct spot and recombine rearranged_group <- bind_rows( s_rows %>% slice(1:(insert_pos - 1)), i_row, s_rows %>% slice(insert_pos:nrow(s_rows)) ) return(rearranged_group) }
Step 2: Apply the function to your data
Now we'll use group_modify to run this function on each name group:
# Your original data df <- data.frame( name = c(1,1,1,1,1,2,2,2,2,2), id = c("s","s","s","i","s","s","i","s","s","s"), var1 = c(3,5,6,4,-7,2,1,-1,3,-6), var2 = c(2,6,-7,5,-9,7,3,2,4,-9) ) # Rearrange the data df_output <- df %>% group_by(name) %>% group_modify(~ rearrange_group(.x)) %>% ungroup() # Check the result df_output
Step 3: Verify the output
This will produce exactly the output you're expecting:
# A tibble: 10 × 4 name id var1 var2 <dbl> <chr> <dbl> <dbl> 1 1 s 3 2 2 1 i 4 5 3 1 s 5 6 4 1 s 6 -7 5 1 s -7 -9 6 2 s 2 7 7 2 s -1 2 8 2 i 1 3 9 2 s 3 4 10 2 s -6 -9
Key notes:
- The function handles edge cases like groups with no
irows gracefully. - If multiple positions meet your criteria, it picks the first one—you can adjust this to select the last or another position if needed.
group_modifyis a tidyverse tool designed exactly for this kind of per-group custom transformation.
内容的提问来源于stack exchange,提问作者adl
相关产品推荐
相关产品推荐

