基于R语言优化单列CSV转三列数据的分组逻辑实现咨询
Optimized R Script to Transform input.csv to output.csv
Let's refine your draft code to fully implement the required transformation. Here's a complete, clean solution that handles grouping, value extraction, and formatting exactly as your expected output:
Step-by-Step Explanation & Code
First, we'll use tidyverse packages for smoother, more readable syntax (a base R alternative is included too). Below is the full script with comments:
# Load tidyverse for easier data manipulation library(tidyverse) # Read the input file - preserve raw text since we need to parse semicolon-containing rows input_df <- read_csv("input.csv", col_names = TRUE, show_col_types = FALSE) # 1. Flag header rows and extract LAYER/DATATYPE values input_df <- input_df %>% mutate( # Mark rows that contain LAYER/DATATYPE headers is_header = grepl("LAYER:", V1), # Pull the numeric LAYER value using regex layer = ifelse(is_header, str_extract(V1, "(?<=LAYER: )\\d+"), NA), # Pull the numeric DATATYPE value using regex datatype = ifelse(is_header, str_extract(V1, "(?<=DATATYPE: )\\d+"), NA), # Generate sequential group IDs: increment each time a new header is found group = cumsum(is_header) ) # 2. Propagate header values down to all rows in their group input_df <- input_df %>% fill(layer, datatype, .direction = "down") # 3. Clean up the data to match your expected output output_df <- input_df %>% # Remove the original header rows filter(!is_header) %>% # Combine layer and datatype into the "L;D" column mutate(`L;D` = paste(layer, datatype, sep = ";")) %>% # Reorder columns to match the desired output structure select(V1, group, `L;D`) # 4. Write the final result to output.csv write_csv(output_df, "output.csv", na = "")
Key Improvements Over Your Draft:
- Automatic Grouping: Uses
cumsum(is_header)to generate sequential group numbers for each block of data under a header row, no manual labeling needed. - Precise Value Extraction: Regex (
str_extract) pulls exactly the numeric values for LAYER and DATATYPE from header rows, avoiding messy string splitting. - Value Propagation: The
fillfunction ensures every data row inherits the correct LAYER/DATATYPE pair from its parent header. - Clean Output: Filters out redundant header rows and aligns columns perfectly with your expected output.
Base R Alternative (No Tidyverse):
If you prefer sticking to base R, here's an equivalent version:
# Read input data input_df <- read.csv("input.csv", stringsAsFactors = FALSE) # Flag headers and extract LAYER/DATATYPE values input_df$is_header <- grepl("LAYER:", input_df$V1) input_df$layer <- ifelse(input_df$is_header, regmatches(input_df$V1, regexpr("(?<=LAYER: )\\d+", input_df$V1, perl = TRUE)), NA) input_df$datatype <- ifelse(input_df$is_header, regmatches(input_df$V1, regexpr("(?<=DATATYPE: )\\d+", input_df$V1, perl = TRUE)), NA) input_df$group <- cumsum(input_df$is_header) # Custom function to fill down NA values (base R alternative to fill()) fill_down <- function(x) { na_pos <- which(is.na(x)) non_na_pos <- which(!is.na(x)) x[na_pos] <- x[findInterval(na_pos, non_na_pos)] x } input_df$layer <- fill_down(input_df$layer) input_df$datatype <- fill_down(input_df$datatype) # Clean up and export output_df <- input_df[!input_df$is_header, ] output_df$`L;D` <- paste(output_df$layer, output_df$datatype, sep = ";") output_df <- output_df[, c("V1", "group", "L;D")] write.csv(output_df, "output.csv", row.names = FALSE, quote = FALSE)
Both scripts will produce exactly the output.csv you specified in your example.
内容的提问来源于stack exchange,提问作者SeanH
相关产品推荐
相关产品推荐

